slim framework withHeader json it does not work - php

Hello everyone, I'm using slim framework for JSON API all responses work but on headers show text / html, the documentation mentions the function whitHeader:
$app = new \Slim\App;
$app->get('/new/', function (Request $request, Response $response){
$response->getBody()->write(json_encode(['message'=>'ok']));
$response_h = $response->withHeader('Content-Type', 'application/json; charset=utf-8');
return json_decode($response_h);
});
$app->run();
When using $response_h-> getHeaders (); show json header(work) but when running takes another header, I tracked where it replaces the header and is in slim / slim / container.php exactly in current function registerDefaultServices i replace:
Headers $ headers = new (['Content-Type' => 'text / html; charset = UTF-8']);
to
Headers $ headers = new (['Content-Type' => 'application / json; charset = utf-8']);
but it is not the best way, how change the headers?
and try using:
$ app-> response () -> header ();
$ app-> response () -> setHeader ();
In all the return is that the response function () does not exist.

Using official documentation for Slim Framework v2:
The HTTP response returned to the HTTP client will have a header. The HTTP header is a list of keys and values that provide metadata about the HTTP response. You can use the Slim application’s response object to set the HTTP response’s header. The response object has a public property headers that is an instance of \Slim\Helper\Set; this provides a simple, standardized interface to manipulate the HTTP response headers.
<?php
$app = new \Slim\Slim();
$app->response->headers->set('Content-Type', 'application/json');
You may also fetch headers from the response object's headers property, too:
<?php
$contentType = $app->response->headers->get('Content-Type');
If a header with the given name does not exist, null is returned. You may specify header names with upper, lower, or mixed case with dashes or underscores. Use the naming convention with which you are most comfortable.
Using official documentation for Slim Framework v3:
An HTTP response typically has a body. Slim provides a PSR 7 Response object with which you can inspect and manipulate the eventual HTTP response’s body.
Just like the PSR 7 Request object, the PSR 7 Response object implements the body as an instance of \Psr\Http\Message\StreamInterface. You can get the HTTP response body StreamInterface instance with the PSR 7 Response object’s getBody() method. The getBody() method is preferable if the outgoing HTTP response length is unknown or too large for available memory.
Your code should looks like this:
<?php
$app = new \Slim\App();
$app->get('/new/', function(Request $requst, Response $response) {
$response->getBody()->write(json_encode(['YOUR_ARRAY']));
$newResponse = $response->withHeader(
'Content-type',
'application/json; charset=utf-8'
);
return $newResponse;
});
Tested on my environment with Postman. Content-type were changed.

Related

Capture incoming request data

I have been experimenting with the current version of the wonderful package for routing from thephpleague.
I have a simple index page to handle the routing and it works just fine.
<?php declare(strict_types=1);
use Laminas\Diactoros\ServerRequestFactory;
use Laminas\HttpHandlerRunner\Emitter\SapiEmitter;
use Laminas\Diactoros\ResponseFactory;
use League\Route\Router;
use League\Route\Strategy\JsonStrategy;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
$strategy = new JsonStrategy(new ResponseFactory());
$router = new Router;
$router->setStrategy($strategy);
$router->post(
'/hello',
function (ServerRequestInterface $request): ResponseInterface
{
var_dump($request->getParsedBody());
}
);
$request = ServerRequestFactory::fromGlobals(
$_SERVER,
$_GET,
$_POST,
$_COOKIE,
$_FILES
);
$response = $router->dispatch($request);
// send the response to the browser
(new SapiEmitter)->emit($response);
My problem is when I send a POST request with JSON data in it, I am unable to capture it in my code as indicated by the line var_dump($request->getParsedBody());.
At the moment, the only way I am able to capture the data sent with the request is by running json_decode(file_get_contents('php://input'), true);.
What I do need to do in order to get the payload sent with whatever request, be it GET, POST, PUT, PATCH, or otherwise?
Thank you.
I finally figured it out. After close examination, I think using dependency injection, ServerRequestInterface is mapped to Laminas\Diactoros\ServerRequest.
So, to illustrate
$router->post(
'/hello',
function (ServerRequestInterface $request): ResponseInterface {
var_dump(
$request->getHeaders(),
$request->getParsedBody(),
$request->getQueryParams(),
$request->getUploadedFiles(),
$request->getBody()->getContents(),
$request // Laminas\Diactoros\ServerRequest
);
}
);
where
$request->getHeaders() gives you the request headers
$request->getParsedBody() will return to all the data as an array sent through when the header Content-Type: multipart/form-data is set (at least as far as I have experimented)
$request->getQueryParams() gives all the query string params as an array just like $_GET
$request->getUploadedFiles() gives all the the uploaded files as an array of instances of Laminas\Diactoros\UploadedFile
$request->getBody()->getContents() will return to all data the as a string when the header Content-Type: application/json is set. You can then run json_decode($request->getBody()->getContents(), true) to get the actual contents an array

How to add HEADER in apache_request_headers in PHP

I want to add a header, to request headers, dynamically on the server side.
I am using slim 2 framework which supports middleware.
Here is my usecase:
Client initiates request to url "https://somedomain.com/login" with some Request Headers.
I have middleware say authenticate. Which should add say "UserAddress" to Request Header.
My callback function login() is called. And I need to access "UserAddress" from header.
So following is the code for this route:
function login() {
//Login related stuff
$allHeaders = apache_request_headers();
//Perform some operation on UserAdress from $allHeaders
}
function authenticate(\Slim\Route $route) {
//Perform authentication here
//I am using SUPERFICIAL method `set_apache_request_headers` as reference.
//Here I need to know how I can add new header to REQUEST HEADER
set_apache_request_headers('UserAdress', 'New York');
//Here is what I tried, which did not work when I called apache_request_headers()
//$_SERVER["UserAdress"] = "New York";
}
$app = getSlimInstance();
$app->post('/login', 'authenticate', login);
I tried using $_SERVER, but when I call apache_request_headers(), my header does not show up.
Side Note:
I am using "UserAddress" as my header for reference purpose. Actually I am using different name.
Also I know you guys will say pass that via request body. But due to legacy code I need this in request header.
I just need to know how can I modify the Request Header

Remove specific cookie in Guzzle response

I would like to remove a specific cookie in a Guzzle response object.
My application uses Slim framework and I make calls to an API with Guzzle. Both Slim and Guzzle implement the Request and Response Interface (Psr7) so I can easily return a Guzzle response in a Slim controller like this :
class APIController {
public function call($request, $response) {
// Do stuff with $request (check body and params, change url, etc)
$client = new \GuzzleHttp\Client();
$response = $client->send($request, []);
return $response;
}
}
Everything works fine but the API returns a cookie I want to remove. I can remove the whole header with :
$response = $response->withoutHeader('Set-Cookie');
Is there a native way in Guzzle to remove a specific cookie by name instead of removing the whole header ?

How to use a MVC 'View' in Slim?

$app->get('/', function () {
// Initial page load.
include 'body-index.php';
return $response;
});
I have the code above on my /index.php. How would I then call and modify functions within body-index.php? As I'm learning MVCs and frameworks right now on my own I'd rather do it this way, rather then breaking out of Slim and do a get('/body-index.php', with the page code. Is this possible?
Thanks.
From Slim Framework documentation:
Most often, you’ll need to write to the PSR 7 Response object. You can write content to the StreamInterface instance with its write() method like this:
$body = $response->getBody();
$body->write('Hello');
You can also replace the PSR 7 Response object’s body with an entirely new StreamInterface instance. This is particularly useful when you want to pipe content from a remote destination (e.g. the filesystem or a remote API) into the HTTP response. You can replace the PSR 7 Response object’s body with its withBody(StreamInterface $body) method. Its argument MUST be an instance of \Psr\Http\Message\StreamInterface.
$newStream = new \GuzzleHttp\Psr7\LazyOpenStream('/path/to/file', 'r');
$newResponse = $oldResponse->withBody($newStream);
Source: Response - Slim Framework

Bad request with Twitter Streaming API and ReactPHP

I am working on a project that needs realtime data from twitter streaming api.
To do that I am using ReactPHP.
When I make the request to the twitter streamintg API, I am getting BadRequest response.
The request (with the payload) is the following:
POST /1.1/statuses/filter.json HTTP/1.0
Host: stream.twitter.com
User-Agent: React/alpha
Authorization: OAuth oauth_nonce="0f1add32ee06141004ea4c02d892bdaf",oauth_timestamp="1405130866",oauth_consumer_key="72XsNwUvJjw0xaSinIk1mzHL0",oauth_token="366141931-Zxljl6Ycwgdh9a5IYPqImJT5zeat2EJOAJOarTq6",oauth_signature_method="HMAC-SHA1",oauth_signature="Rs57ywc26IRNQA1l9zQZwoRMV5Q%3D"
Content-Type: application/x-www-form-urlencoded
Content-Length: 11
track=arg
and to do that I am using:
"jacobkiers/oauth": "1.0." => for oauth
"react/http-client": "" => to connect to the streaming API
you can check the code here:
TwitterConnector.php
thanks
So the answer is really simple, you're making a HTTP 1.0 request while the Twitter API requires a HTTP 1.1 request.
The source of the problem resides in the Request object. In order to work around that I've quickly created two more classes. RequestData11:
<?php
use React\HttpClient\RequestData;
class RequestData11 extends RequestData
{
public function setProtocolVersion($version)
{
}
}
And Client11:
<?php
use React\EventLoop\LoopInterface;
use React\HttpClient\Request;
use React\SocketClient\ConnectorInterface;
class Client11
{
private $connectionManager;
private $secureConnectionManager;
public function __construct(ConnectorInterface $connector, ConnectorInterface $secureConnector)
{
$this->connector = $connector;
$this->secureConnector = $secureConnector;
}
public function request($method, $url, array $headers = array())
{
$requestData = new RequestData11($method, $url, $headers);
$connectionManager = $this->getConnectorForScheme($requestData->getScheme());
return new Request($connectionManager, $requestData);
}
private function getConnectorForScheme($scheme)
{
return ('https' === $scheme) ? $this->secureConnector : $this->connector;
}
}
You normally would create a new client like this:
<?php
$client = $httpClientFactory->create($loop, $dnsResolver);
Instead you'll have to create it this way:
<?php
$connector = new Connector($loop, $dnsResolver);
$secureConnector = new SecureConnector($connector, $loop);
$client = new Client11($connector, $secureConnector);
This forces the client to use HTTP 1.1, beware though, the http-client is a 1.0 client so forcing it to 1.1 should only be done when you know what you're doing.
Note that you didn't lock the react\http-client version in your composer file so I have no clue what version you're using and the bove code might not work because of that.
The previous comment fix the issue with the HTTP version.
But I had another issue.
Twitters kept answering Unauthorize.
Debugging a little, I find out that the issue was that Reacts uses STREAM_CRYPTO_METHOD_TLS_CLIENT encription method instead of STREAM_CRYPTO_METHOD_SSLv23_CLIENT in
React\SocketClient\StreamEncryption
I cant find an elegant way to fix, just rewrite StreamEncryption to use SSL and SecureConnector to use the rewrited StreamEncryption

Categories