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

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

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 ?

Laravel guzzle Get request to API , interaction

I'm trying to send get request to this API https://api.coinmarketcap.com/v1/ticker/bitcoin/ and it's working fine, i'm getting the object but when i try to call object properties it's giving me error:
Undefined property: GuzzleHttp\Psr7\Response::$id
This is my code:
$client = new GuzzleHttp\Client(['base_uri' => 'https://api.coinmarketcap.com/v1/ticker/']);
$response = $client->request('GET', 'bitcoin');
return $response->id;;
I don't really know how to interact with this object...
The Guzzle Response object doesn't work that way, it doesn't assume what the response content is and proxy your request for a property.
You used to be able to call $response->json(), but you can't do that anymore due to PSR-7. Instead do something like this:
$items = json_decode($response->getBody());
foreach ($items as $item) {
echo($item->id);
}
That endpoint returns an array of objects. So you would need to either get the first one or loop through them if there are multiple.
NOTE: If you are adding the namespace at the top of your controller like:
use \GuzzleHttp\Client;
You then in your code need only to refer to it as Client like:
$client = new Client(...);

how to deal with jsonp request in php using the Slim Framework?

when i send a jsonp GET request with jQuery, it usually sends something like:
http://website.com/test?callback=jQuery20309569547907449305_1386221743664&id=9&limit=10&_=1386221743665
in Zend Framework i will handle this like:
$request = $this->getRequest();
$callback = $request->getParam('callback');
$id = $request->getParam('id');
$limit = $request->getParam('limit');
// set $response var to something
$this->getResponse()->setBody($callback . '(' . json_encode($response) . ');');
in Slim Framework i have:
$callback = isset($_GET['callback']) ? $_GET['callback'] : '';
$app->get(
'/test',
function () {
$resp = array('This is a TEST route');
}
);
$app->response->setBody($callback . '(' . json_encode($resp) . ');');
but the route returns 404
any ideas how can i have this working?
For Slim 3.x Just add the middleware in the response chain
$app->add(function ($request, $response, $next) { // jsonp
$callback = $_GET['callback'] ?? false;
if($callback) $response->getBody()->write($callback."(");
$response = $next($request, $response);
if($callback) $response->getBody()->write(")");
return $response;
});
There are several things wrong here. First, you should not be getting a 404, you should be getting an error complaining that $resp is not defined.
I think you are probably missing a .htaccess (or web.config if you are on IIS) that is routing all requests to your front controller file (where you define your Slim object and routes). To see if this is the problem, try http://website.com/index.php/test?callback=whatever, where index.php is the name of your front controller file.
This is the .htaccess that I use:
RewriteEngine On
#Slim PHP routing
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_URI} !^/index.php
RewriteRule ^ index.php [QSA,NC,L]
As for trying to achieve what you want to achieve, you need something like this:
$app = new Slim\Slim();
$app->get('/test', function () use($app) {
//Request processing begins here...
//Get callback from query string
$callback = $app->request()->get('callback');
//Check for null here...
//Set content type to javascript
header('Content-type: text/javascript');
//Generate our JSONP output
echo "$callback(" . json_encode(array('This is a test.')) . ");";
//Request processing ends here...
});
$app->run();
I'm not 100% familiar with Zend, but I think it uses a more traditional MVC implementation where you have a Controller class that you extend and implement actions as methods. Slim is much more basic than that, instead you define routes on your app objects and map these to closures, which are executed when their route is hit.
In my example above, I define a closure for the route '/test'. Closures in PHP have no access by default to other variables in their scope. In order to access a variable outside of the closure scope we must explicitly specific the variables we want via the "use" keyword. In the example, I "use" the $app object, so that we can use the app object inside our closure. This is the basis for the majority of the functionality Slim provides. The $app object is the IOC object, the core where everything lives and should be used to expose service objects, etc. In this case, we are using the request() method that returns us a wrapper around the request related superglobals ($_GET, $_POST, etc).
Once we have our callback parameter, we can validate, and then generate and send our JSONP. Slim does not abstract (as far as I know) send data back down the response, you should just use echo as in vanilla PHP. You should also set the header type to javascript since that is what we are sending. Hope this helps.
Have you worked with zend before? I'm not quite sure if you know how zend works. You don't have any get() functions with callbacks, but rather you've got an controller (in your case: test) and this controller has several actions.
an example for your text-controller with an example action could look something like this:
class TestController extends Zend_Controller_Action
{
public function init()
{
//you might want to use here a contextSwitch
}
public function fooAction()
{
//get params
$limit = $this->_getParam('limit', 0);
[...]
//do stuff here
[...]
$this->_helper->json($response);
}
}
Your calls to this action now might look like this:
http://website.com/test/foo/limit/10
Note that there is no need for ugly ?param=value in zend. simply append it to you URI with param/value
Note (important):
There are several ways in zend to output json, therefore $this->_helper->json($response) might not be the best solution for you. Using a contextSwitch inside your init() function might be better.
I came across this answer while attempting to support JSONP responses in Slim v3.
The answer by #cardeol didn't quite support my needs as some of my earlier middleware calls made use of the "$response->withJson($data, $code);"
This call destroys and recreates the body object. Flushing any "BEFORE" writes.
class JSONPResponseMiddleware {
/**
* Wrap response with callback query parameter
*
* #param \Psr\Http\Message\ServerRequestInterface $request PSR7 request
* #param \Psr\Http\Message\ResponseInterface $response PSR7 response
* #param callable $next Next middleware
*
* #return \Psr\Http\Message\ResponseInterface
*/
public function __invoke(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, $next){
if(!$callback = $request->getQueryParam("callback", false)){
return $next($request, $response);
}
$response = $next($request, $response);
$data = $response->getBody();
// upstream controllers use "withJSON" which purges the existing body object.
$body = new Body(fopen('php://temp', 'r+'));
$body->write("{$callback}(");
$body->write($data);
$body->write(")");
$response = $response->withBody($body)->withHeader('Content-type', 'application/javascript');
return $response;
}
}
Then installed with:
$app->add(new JSONPResponseMiddleware());

Categories