I am getting get parameters using this
$this->params()->fromQuery('KEY');
I found two way to get POST parameters
//first way
$this->params()->fromPost('KEY', null);
//second way
$this->getRequest()->getPost();
Both of this working in "POST" method but now in a "PUT" method if I pass values as a post parameters.
How I can get post parameters in "PUT" method?
I guess the right way of doing that is by using Zend_Controller_Plugin_PutHandler:
// you can put this code in your projects bootstrap
$front = Zend_Controller_Front::getInstance();
$front->registerPlugin(new Zend_Controller_Plugin_PutHandler());
and then you can get your params via getParams()
foreach($this->getRequest()->getParams() as $key => $value) {
...
}
or simply
$this->getRequest()->getParam("myvar");
You need to read the request body and parse it, something like this:
$putParams = array();
parse_str($this->getRequest()->getContent(), $putParams);
This will parse all params into the $putParams-array, so you can access it like you would access the super globals $_POST or $_GET. For instance:
// Get the parameter named 'id'
$id = $putParams['id'];
// Loop over all params
foreach($putParams as $key => $value) {
echo 'Put-param ' . $key . ' = ' . $value . PHP_EOL;
}
I had trouble using PUT data sent from AngularJS and found the best way was to use a custom Zend plugin
class Web_Mvc_Plugin_JsonPutHandler extends Zend_Controller_Plugin_Abstract {
public function preDispatch(Zend_Controller_Request_Abstract $request) {
if (!$request instanceof Zend_Controller_Request_Http) {
return;
}
if ($this->_request->isPut()) {
$putParams = json_decode($this->_request->getRawBody());
$request->setParam('data', $putParams);
}
}
}
Which can then be accesses via getParams as a PHP object
$data = $this->getRequest()->getParam('data');
$id = $data->id;
Related
I'm building a Laravel app, and I need to use an URL that looks like that :
/api/ads?page=Actuel&formatsQuery[]=side&formatsQuery[]=leaderboard&deviceQuery=mobile
I have 3 parameters (page, formatsQuery (as an array), and deviceQuery).
Do you now how to hold his in routing and controller in order to have the correct value inside the controller's fonction?
I tried this :
routes/api.php
//request to get ads for given parameters
Route::get('/ads', [MediaController::class, 'findAds']);
and this (MediaController.php) :
public function findAds($page, $formatsQuery, $deviceQuery) {
echo $page;
if(sizeof($formatsQuery) <= 0 || sizeof($formatsQuery) > 3){
return $this->unvalidParametersError();
}
//transform format to position depending on deviceQuery
$position = [];
$res = [];
foreach ($formatsQuery as $format) {
$res = Media::where('position', $format)->inRandomOrder()->first()->union($res);
}
echo $res;
return $res;
}
then I test it with this :
public function test_findAds()
{
$ads = Ad::factory()
->has(Media::factory()->count(3), 'medias')
->count(3)->create();
$response = $this->get('/api/ads?page=Actuel&formatsQuery[]=side&formatsQuery[]=leaderboard&deviceQuery=mobile');
$response->assertStatus(200);
}
You are using a GET request to fetch your data. GET request is a type of request that you send parameters in URL using ? after URL and separating parameters with &. You can find out more about HTTP methods here.
In laravel using request parameters is so simple. First of all you need to add Request $request to your method prototype like this:
use Illuminate\Http\Request;
public function findAds(Request $request)
Then you can simply use $request->parameter to get the values. So you need to change your code like this:
public function findAds(Request $request){
$page = $request->page;
$formatsQuery = $request->formatsQuery;
$deviceQuery = $request->deviceQuery;
// Your code
}
And as #matiaslauriti mentioned in the comments you don't need to put [] after formatsQuery[] to send an array in GET request. Using the same key more than one time automatically makes an array for you.
i'm developing an app and i'm trying to pass a variable from the controller to the form but without success. I need this variable for executing queries and populate fields of the form.
This is my code:
CONTROLLER:
$cod = $this->_getParam('cod');
$form = new Application_Form_MylacForm($cod);
FORM:
public $_codanagrafica;
protected $_codcircuito;
public function __construct($codanagrafica = null, $param)
{
$this->_codcircuito = $param;
echo $this->_codcircuito;
$this->_codanagrafica = $codanagrafica;
$this->init();
$this->loadDefaultDecorators();
}
With this code the variable _codcircuito is null.
How can i solve it?
Thank's
You are passing only one variable to form object:
$form = new Application_Form_MylacForm($cod);
And then you set _codcircuito with second argument, which is not passed:
$this->_codcircuito = $param;
$param is null in your case. Try:
$this->_codcircuito = $codanagrafica;
instead.
I'm not sure if I'm approaching this problem in the correct way
I need the same route pattern for 2 different actions, like this
/{category}
going to productAction and
/{brand}
going to brandAction (without prefix)
A query to DB will tell me which type of entity this parameter is and then I can assign the action/controller to handle it
I could create an Action to handle this pattern and redirect to another action accordingly
I could create a Listener in kernel.controller event and reassign the controller accordingly
I could use Symfony CMF but seems to me like overkill.
Thanks in advance
Got it working using Option 2, not sure if that is the best way to do it
/**
* #param FilterControllerEvent $event
*/
public function onKernelController(FilterControllerEvent $event)
{
$routeService = $this->getRouteService();
$params = $request->attributes->all();
$slugs = array();
foreach ($params as $key => $param) {
if (preg_match('/slug*/', $key)) {
$node = $routeService->findBySlug($param);
if ($node !== null) {
$slug['id'] = $node->getEntityId();
$slug['type'] = $node->getEntityType();
$slugs[] = $slug;
}
}
}
$request->request->set('slugs', $slugs);
}
Imagine I have a URL that loads a controller if the name matches (Ignoring any security issues with this at the moment hehe)
public function Load( $controller, $action = "Index" )
{
require_once( "Controllers/" . $controller . "Controller.php" );
$controllerName = $controller . "Controller";
$loadedController = new $controllerName();
$actionName = "ActionResult_" . $action;
$loadedController->$actionName();
}
Now imagine I want a log in form to send its $_POST details as parameters of the receiving controller launched above:
<?php
class ExcelUploadController extends Controller
{
public function ActionResult_Login( $username = NULL, $password = NULL )
{
// The parameters need to be mapped to the $_POST parameters names probably from the Load method somewhere and pumped in to the $loadedController->$actionName();
$post_username = $username;
$post_password = $password;
$this->ReturnView( "ExcelUpload/Index" );
}
}
?>
But also so that it does not matter what order the parameters are declared, it matches the parameter in the function based on the $_POST key.
How might I go about doing this, any ideas?
So to clarify if this doesn't make sense.. the method might look something like this:
public function Load( $controller, $action = "Index" )
{
require_once( "Controllers/" . $controller . "Controller.php" );
$controllerName = $controller . "Controller";
$loadedController = new $controllerName();
$actionName = "ActionResult_" . $action;
$checkIfPostData = $_POST;
if( isset( $checkIfPostData ) )
{
// Do some funky wang to map the following $loadedController->$actionName();
// with the username and password or any other $_POST keys so that in the calling method, I can grab hold of the $_POST values
}
$loadedController->$actionName();
}
What your are looking for is call_user_func_array()
EDIT, to reply to comment :
You have two options: rewrite all your function so that they accept only one array() as argument and you parse that array for values. A bit fastidious but it can be useful in some cases. Or you can request for the required argument of a function:
// This will create an object that is the definition of your object
$f = new ReflectionMethod($instance_of_object, $method_name);
$args = array();
// Loop trough params
foreach ($f->getParameters() as $param) {
// Check if parameters is sent through POST and if it is optional or not
if (!isset($_POST[$param->name]) && !$param->isOptional()) {
throw new Exception("You did not provide a value for all parameters");
}
if (isset($_POST[$param->name])) {
$args[] = $_POST[$param->name];
}
if ($param->name == 'args') {
$args[] = $_POST;
}
}
$result = call_user_func_array(array($instance_of_object, $method_name), $args);
That way your array will be properly constructed.
You can also add some specific treatment whether a parameter is optional or not (I guess you can understand how to do it from the code I gave you ;)
Since the data is being sent through POST you don't need to pass any parameters to your method:
class ExcelUploadController extends Controller {
private $userName;
private $login;
public function ActionResult_Login() {
$this->userName = $_POST['username'];
$this->login = $_POST['login'];
}
}
Don't forget to sanitize and validate the user input!
I have come up with the following bits of code to call a method via AJAX in my PHP classes:
PHP:
class Ajax extends Controller {
private $class;
private $method;
private $params;
function __construct()
{
$this->params = $_POST; // Call params
$call = explode('->', $this->params['call']);
$this->class = new $call[0]; // e.g. controller->method
$this->method = $call[1];
array_shift($this->params);
$this->parse();
}
public function index()
{
//Dummy
}
public function parse()
{
$r = '';
$r = call_user_func_array(array($this->class, $this->method), $this->params);
echo $r;
}
}
Client:
function creditCheck2(id)
{
$.post(ROOT + 'Ajax', {call: 'Record->creditState', id: id, enquiryid: enquiryId}, function(data) {
alert(data)
}, 'json')
}
It seems to work great, but is it secure and could it be better?
Just for reference, I have added my code with the changes suggested by the answers:
class Call extends Controller {
private $class;
private $method;
private $params;
private $authClasses = array(
'Gallery'
);
function __construct()
{
$this->params = $_POST; // Call params
$call = explode('->', $this->params['call']);
if(!in_array($call[0], $this->authClasses))
{
die();
}
$this->class = new $call[0]; // e.g. controller->method
$this->method = $call[1];
unset($this->params['call']);
$this->parse();
}
public function parse()
{
$r = '';
$param = array();
// Params in any order...
$mRef = new ReflectionMethod($this->class, $this->method);
foreach($mRef->getParameters() as $p) {
$param[$p->name] = $this->params[$p->name];
}
$this->params = $param;
if($r = #call_user_func_array(array($this->class, $this->method), $this->params))
{
echo $r;
}
else {
}
}
}
Small issues
It could be better in that array_shift($this->params) unnecessarily assumes that the first item in the params array will always be call. That's not true and it does not agree with the direct access $this->params['call'] you are doing a little earlier. The array_shift should be replaced with simply unset($this->params['call']).
Bigger issues
There is also the problem that the order of values in the params array must match the order of parameters in the signature of the method you are trying to call. I don't think there is a guarantee that the order will be the same as the order of the parameters in the AJAX request, so that's a theoretical problem.
VERY big problem
More importantly, this way of doing things forces the author of the AJAX code to match the order of parameters in the signature of the method you are trying to call. This introduces a horrible level of coupling and is a major problem. What's worse, changing the order of the parameters by mistake will not be apparent. Consider:
public function bankTransfer($fromAccount, $toAccount, $amount);
$.post(ROOT + 'Ajax', {
call: 'Bank->bankTransfer',
from: "sender",
to: "recipient",
amount: 42
}, function(data) { ... });
This would work. But if you do this
$.post(ROOT + 'Ajax', {
call: 'Bank->bankTransfer',
to: "recipient", // swapped the order of
from: "sender", // these two lines
amount: 42
}, function(data) { ... });
You will get the opposite result of what is expected. I believe it's immediately obvious that this is extremely bad.
To solve the problem you would have to use reflection to match the array keys in $this->params with the formal names of the parameters of the method being called.
Security
Finally, this code is insecure in that anyone can make a request that directs your code to call any method of any class with the appropriate parameters -- even methods that should not be accessible from a web environment.
This is another serious problem and cannot really be fixed unless you introduce some type of filtering to the dispatch logic.
It seems to work great, but is it secure and could it be better?
Are you using your own framework or using other framework? I believe that it isn't secure at all, if the attacker know what might be inside your framework. For example: there is database class in your framework, attacker can do the following:
{call: 'Database->execute', sql: 'SELECT * FROM information_schema.`tables`'}
Filtering
You can limit the number of class that you allow user to access. For example:
if (!in_array($this->class, array('Record', 'Hello'))) {
die();
}
Reflection
This is sample of reflection that I just learn (Thanks to #Jon for the reference). This solve the problem of passing argument in different order from the PHP function.
class Email
{
public function send($from, $to, $msg) {
return "Send $from to $to: $msg";
}
}
$rawParam = array('msg' => 'Hello World',
'to' => 'to#gmail.com',
'from' => 'from#gmail.com');
$param = array();
// Rearrange
$methodRef = new ReflectionMethod('Email', 'send');
foreach($methodRef->getParameters() as $p) {
$param[$p->name] = $rawParam[$p->name];
}
var_dump($rawParam);
var_dump($param);