Capture incoming request data - php

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

Related

Check if my GET request has Header: Token

I want to send a request with or without 'Token' as a header.
If request has 'Token' as a header: if the user already has that item, it will return the item with the proper item_id of a specific user (based on its token), otherwise it will return null.
If request doesn't have 'Token' as a header: it will return the item with that item_id
I'm working with Zend Framework and in ItemResource I have this method:
public function fetch($id)
{
}
How can I check if my request has Token as a header or not and implement both cases inside fetch()?
Using Laminas API Tools it depends on wether you 're using a RPC or a REST resource. I will explain which tools the Laminas API Tools give you to evaluate the received header data.
You don 't have to reinvent the wheel, because Laminas API Tools has the received headers already at hand, when you 're in your fetch method.
Representational State Transfer (REST)
Rest resources normally extend the \Laminas\ApiTools\Rest\AbstractResourceListener class. This class listens for \Laminas\ApiTools\Rest\ResourceEvent. Fortunately, this event provides you with a request object that also contains the received header data.
<?php
declare(strict_types=1);
namespace Marcel\V1\Rest\Example;
use Laminas\ApiTools\Rest\AbstractResourceListener;
class ExampleResource extends AbstractResourceListener
{
public function fetch($id)
{
// requesting for an authorization header
$token = $this->getEvent()->getRequest()->getHeader('Authorization', null);
if ($token === null) {
// header was not received
}
}
}
As you can see the ResourceEvent returns a \Laminas\Http\Request instance when calling getRequest(). The request instance already contains all request headers you 've received. Just call getHeader with the given name and as second parameter a default value, which should be returned, when the header was not set. If there is no http_token header, you 'll get null as a result.
Remote Procedure Calls (RPC)
Since RPC requests are handled with a MVC controller class, you can get the request as easy as in a rest resource. Controller classes extend from \Laminas\Mvc\Controller\AbstractActionController, which already contains a request instance.
<?php
declare(strict_types=1);
namespace Marcel\V1\Rpc\Example;
use Laminas\Mvc\Controller\AbstractActionController;
class ExampleController extends AbstractActionController
{
public function exampleAction()
{
$token = $this->getRequest()->getHeader('Authorization', null);
if ($token === null) {
// token was not set
}
}
}
As you can see getting header data in rpc requests is as easy as in resource listeners. The procedure is the same because a request instance is also used here.
Conclusion
There is absolutely no need for coding things, that are already there. Just get the request instance from the event or the abstract controller and retrieve the header you want. Always keep in mind, that there are security aspects like CRLF injections, when dealing with raw data. The Laminas framework handles all this for you already.
Additionally you can check for all received headers by calling ->getHeaders() instead of ->getHeader($name, $default). You 'll get a \Laminas\Http\Header instance with all received headers.
You can get all HTTP header values by getallheaders() or just get the specific value by $_SERVER['HTTP_XXX'], in your case, replace XXX with Token, $_SERVER['HTTP_Token'].
Manual: https://www.php.net/manual/en/reserved.variables.server.php
public function fetch($id)
{
$token = $_SERVER['HTTP_Token'];
// do your busniess code
}

Forwarding Slim HTTP requests to Guzzle client

I am using Slim on a REST API server. Some of the endpoints need to blindly be proxied to to another server, and I am using Guzzle for this part. It works most of the time to just use the Slim request as the Guzzle request (with some minor modification such as the host, etc).
<?php
use Psr\Http\Message\ServerRequestInterface as SlimRequest;
use Psr\Http\Message\ResponseInterface as SlimResponse;
use GuzzleHttp\Psr7\Request as GuzzleRequest;
use GuzzleHttp\Psr7\Response as GuzzleRequest;
$app->post('/bla/bla/bla', function (SlimRequest $slimRequest, SlimResponse $slimResponse) {
$slimRequest = $slimRequest->withUri($slimRequest->getUri()->withHost('https://example.com'));
$guzzleResponse=$this->httpClient->send($slimRequest);
});
One of my endpoints uses multipart content, and the files nor the POST content is being sent. As an alternative, I've tried the following but without success.
<?php
use Psr\Http\Message\ServerRequestInterface as SlimRequest;
use Psr\Http\Message\ResponseInterface as SlimResponse;
use GuzzleHttp\Psr7\Request as GuzzleRequest;
use GuzzleHttp\Psr7\Response as GuzzleRequest;
$app->post('/bla/bla/bla', function (SlimRequest $slimRequest, SlimResponse $slimResponse) {
$headers = array_intersect_key($slimRequest->getHeaders(), array_flip(["HTTP_CONNECTION", "CONTENT_LENGTH", "HTTP_ACCEPT", "HTTP_ACCEPT_ENCODING", "HTTP_ACCEPT_LANGUAGE", "CONTENT_TYPE"]));
$guzzleRequest = new \GuzzleHttp\Psr7\Request($slimRequest->getMethod(), $slimRequest->getUri()->getPath(), $headers, $slimRequest->getBody());
$guzzleResponse=$this->httpClient->send($guzzleRequest);
});
If necessary, I will resort to manually creating the multipart form, however, I expect there is a better way to do so since both are PSR-7 complient.
How should this best be accomplished?
PSR-7 Request objects are IMMUTABLE. That is, you cannot alter the values. Setting something new will return a new instance.
https://www.php-fig.org/psr/psr-7/
So, just change
$slimRequest->withUri($slimRequest->getUri()->withHost('https://example.com'));
to
$slimRequest = $slimRequest->withUri($slimRequest->getUri()->withHost('https://example.com'));
Also, $slimRequest->getUri()->withHost('https://example.com') returns a Request object too. What you need here is:
$slimRequest->getUri()->withHost('https://example.com')->getHost()
which will give you your string.

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

slim framework withHeader json it does not work

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.

Slim Framework 2.0.0 Unable to use ->params() with GET

I'm using SLIM 2.0.0
Is it possible to use ->params() with GET?
In the example below
if I call it by POST: curl -d "param1=hello&param2=world" http://localhost/foo it prints: helloworld CORRECT!!
if I call it by GET: http://localhost/foo/hello/world it prints: NOTHING!! <- WRONG!!
Why?
<?php
require 'Slim/Slim.php';
\Slim\Slim::registerAutoloader();
$app = new \Slim\Slim();
$app -> get('/foo/:param1/:param2', 'foo');
$app -> post('/foo', 'foo');
$app -> run();
function foo() {
$request = \Slim\Slim::getInstance() -> request();
echo $request -> params('param1');
echo $request -> params('param2');
}
?>
SOLVED!
In the documentation page Request Variables - Slim Framework Documentation I read this:
An HTTP request may have associated variables (not to be confused with route variables). The GET, POST, or PUT variables sent with the current HTTP request are exposed via the Slim application’s request object.
If you want to quickly fetch a request variable value without considering its type, use the request object’s params() method:
<?php
$req = $app->request();
$paramValue = $req->params('paramName');
The params() method will first search PUT variables, then POST variables, then GET variables. If no variables are found, null is returned. If you only want to search for a specific type of variable, you can use these methods instead:
<?php
// Get request object
$req = $app->request();
//GET variable
$paramValue = $req->get('paramName');
//POST variable
$paramValue = $req->post('paramName');
So:
The key line is "An HTTP request may have associated variables (not to be confused with route variables)."
http://domain.com/foo/hello/wold?name=brian
In the above URI the route variables/parameters are read from the '/foo/hello/world' portion. The request GET variables are read from the query string ('name=brian') and can be accessed by $app->request()->get('name') or $app->request()->params('name').
The request POST variables are parsed from the body of the request and can be accessed $app->request()->post('param1') or $app->request()->params('param1').
Thanks to Brian Nesbitt

Categories