The segments in a URI normally follow this pattern in Codeigniter:
XYZ.com/Class/Method/param1/param2
This works as expected when the called method is defined in the controller, but nothing works if I supply the URI with some undefined method to invoke the __call magic method that takes care of any undefined method.
__call is only invoked if its called from within the controller itself, not when I call some undefined method from the URI
Any explanation?
Thanks
In CodeIgniter, there is _remap. So if you go to
XYZ.com/Class/UndefinedMethod/param1/param2
then _remap will be called (actually _remap will always be called, so we need to make sure that methods that do exist are called correctly).
function _remap($method, $params=array()){
$funcs = get_class_methods($this);
if(in_array($method, $funcs)){ // We are trying to go to a method in this class
return call_user_func_array(array($this, $method), $params);
}
// else do something else
}
Look in the server (Apache?) log file. Undoubtedly you will see PHP errors which caused processing to abort. Unless you cover undefined functions by remapping them to an error page, random URLs will cause "nothing" to seem to happen.
Related
Guys I just came across the __call() PHP function. I tried to understand what this is used through the manual here http://php.net/manual/en/language.oop5.overloading.php#object.call
But all that is mentioned here is that
__call() is triggered when invoking inaccessible methods in an object context.
which is not really clear honestly. I tried looking for other examples online, but they all seem complicated. Can anyone explain using a simple example what is __call() and what is it good for?
Consider this:
class Foo
{
public function __call($name, $args)
{
echo "you tried to call method $name with these args:";
print_r($args);
}
}
$foo = new Foo();
$foo->bar($args);
Note there is no method named bar. Normally, calling it will produce an error. However, in this case, you've defined a __call() method. So, instead of generating an error, PHP will invoke this method, passing it the name of the method you tried to call, and the arguments you tried to call it with.
Hi I have a class which includes two methods.
One of which is to initialize session , another one is for redirect the web page
I ve written the class such that it can be called repeatedly.
$obj->setSession(key,value)->redirect(url);
In this mode , the session is firstly initialized and then it redirects to the next page.
But if it's written like this
$obj->redirect(url)->setSession(key,value);
It just redirects to the defined location qnd the session is not initialized anymore ..
It s cuz when the resirect method is called, the page changes promptly and it causes the second method not to be called ..
Is there any way to be able to call methods repeatedly without the need of considering their order ?
When I usually face that issue, I add a method in the $obj object called render() or done() or something to that effect that checks all the flags I might have defined previously. One of those flags might be a header flag, which is what a redirect method usually does header(Location: $yourDestUrl).
So you end up with something like:
$obj->redirect(url)->setSession(key,value)->render();
When you call a method such as redirect or setSession, put those actions in a "stack" as a property of you class.
Then, when all your methods are called, call a method called exec (for example) that will execute all the actions in the "stack".
Here is a base class based on this idea using magic methods:
class Stack {
private $_stack = array();
public function __call($method, $args) {
// Adding method to stack
$this->_stack[$method] = $args;
return $this;
}
public function __isset($name) {
// Checks if method is in stack
return isset($this->_stack[$name];
}
public function exec() {
// setSession is executed first
if (isset($this->setSession))
call_user_func_array('setSessionMethod', $this->_stack['setSession']);
// redirect is executed second
if (isset($this->redirect))
call_user_func_array('redirectMethod', $this->_stack['redirect']);
}
}
To use this class, you would do:
$stack = new Stack;
$stack->redirect('arg')
->setSession('arg1', 'arg2')
->exec();
Looking at Laravel code I found they are passing variable from 'routes' to 'views' using the following method:
$arraysan = ['mike','robert','john']; **//Variable to be passed**
return view('home')->withArraysan($arraysan); **//Variable passed with** name "withArraysan"
In that above syntax they call a function named withArraysan which doesn't exist.
Can somebody explain how its been handled in Laravel?
For a while now, PHP has had the concept of magic methods - these are special methods that can be added to a class to intercept method calls that do not exist.
It appears that Laravel Views implement __call - this then intercepts a call to an undefined method on the object, and is passed both the name of the method being called as well as the arguments. In this way, the View object can then see that the withArraysan call began with and call the concrete method with, passing the second part Arraysan as the first argument, and the argument to withArraysan as the second part.
If I've got your question then in Laravel they had a class View using magic method __call to handle the above function and the code for that function is like as follows
public function __call($method, $parameters)
{
if (Str::startsWith($method, 'with')) {
return $this->with(Str::snake(substr($method, 4)), $parameters[0]);
}
throw new BadMethodCallException("Method [$method] does not exist on view.");
}
And you can find this within
your_project_folder/vendor/laravel/framework/src/Illuminate/View/View.php
$arraysan = ['mike', 'robert', 'john']; // Variable to be passed
return view('home')->with('AnyVariable', $arraysan);
Try this! This will work.
Also check in home.blade.php,
<?php
print_r($AnyVariable);die;
?>
public function _remap($method)
{
if ($method == 'some_method')
{
$this->$method();
}
else
{
$this->default_method();
}
}
This is what i read from official site. As i understand _remap method is getting called before all actions. But this instruction $this->$method(); means that calling $method will call _remap again and it is being something like cycle. Isn't it?
No, _remap is called by the framework, during the init, but when you call some method directly, you only execute the function content...
Hope it's helpful!
Some explanation found here:
Important: If your controller contains a function named _remap(), it will always get called regardless of what your URI contains. It overrides the normal behavior in which the URI determines which function is called, allowing you to define your own function routing rules.
Is there any security problem with dynamically calling a method in a class from user input. For example:
<?php
class A {
public function foo() {
return true;
}
}
$obj = new A();
$method = $_GET['method'];
$obj->$method();
I am aware that the user will be able to call any method within A, and I am fine with that. I am just curious if there may be other possible security issues.
Your user will be able to try calling any possible method from your class -- even try to call non-existant methods (and get a Fatal Error).
If you're fine with this... well, I suppose this is OK.
It doesn't look nice, but I don't think one could inject any other kind of code.
Still, I would at least check if the method exists -- using method_exists()
Yes its probably a bad idea, maybe you should restrict allowed methods. Maybe define allowed methods in an array then throw an exception if $method is not in this whitelist.
Also you will need to use the magic __call($name, $args) method to allow these user defined methods to be called.