Dynamically Calling PHP Class Methods - php

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.

Related

PHP force class to have a certain method if class variable has been set

I have a simple requirement where I want to allow a Class (Laravel Model) to define whether a controller should check whether it's allowed to be deleted or not based on a class variable like so
public $verify_delete = true;
Currently if this variable is set I must add the following method;
public function deletable()
{
$deletable = true;
if ($this->has_children()) {
$deletable = false;
}
// ...
return $deletable;
}
The first variable is simply an indication the code running this class should also run the deletable() method.
So what I want is a way to force a developer to implement the deletable() method if they set the $verify_delete to true, and throw an error if they have not done so. I don't know much about traits and implements at this stage, so I'm not sure if they're the right route to go down.
If this is not the best method to achieve what I'm after I'm all ears.
You should create a trait called Deletable or Removeable or something along these lines and implement this delete method there and then each model that can be deleted will use this trait. Not exactly what you wanted but it is the right approach.
Or
You can create an interface which will have this method inside and then each class (model) which implements this interface will have to implement the method, the only difference is that implementation may vary depending on the model from others
You question is this: can I detect if a method is callable in a class, when a specific property is set...
Other (very wise) solutions are suggesting interfaces and traits... A perfectly fine idea and a really good way to look at things.
But you can think of something like this as well:
public function __construct() {
if (true === $this->verify_delete && !method_exists($this, 'deletable')) {
throw new \Exception('Hi developer! You forgot something...');
}
}
Explanation:
on the constructor you check if the property is true.
if the method does not exist, let's throw an exception
I think this does exactly as you ask: force the developer to implement the deletable method, when the property is set.
But to be honest, I really like those traits as well... I just wanted to give you an alternative that does the trick as well if you are not too comfortable with techniques likes interfaces, traits, etc.

Restrict method chaining on other method

Let say i have this class
class Test
{
method_a(){ return $this;}
method_b(){ return $this;}
method_c(){ return $this;}
}
$obj = new Test();
$obj->method_a()->method_b();
$obj->method_a()->method_c();
$obj->method_b()->method_c(); //i want to disallow this
How can i disallow method_b() chaining with method_c()
Edited:
Calling $obj->method_b() and follow by $obj->method_c() also disallow because i only want method_b chaining with method_a and method_c with other method
there are two possibilitys i can think of. the first is to not retun $this from method_b(). that would prevent chaining method_c() - but everything else, too, so this doesn't seem to be what you're looking for.
the second one is kind of ugly, but might work as intended: add another private variable $last_method to your class and set that in every called method (to the methods name or some kind of id). that way, when calling method_c(), you could check if the last called method was method_b() - and if so, throw an exception (or whatever you'd like to do in such a case). note that this solution would also prevent from calling method_b() and method_c() consecutive on the same object without chaining - so this might not be 100% what you're looking for.
You could use a State Pattern and introduce State objects for each possible state in Test. When someone calls Method B, you change the state of Test internally to the StateB class and when someone calls Method C then you can raise an Exception.
See http://sourcemaking.com/design_patterns/state

Using -> with a static function

Hi I'm a bit of a newbie to OOP, i just have a quick question: say I have a function in a class declared as
class House
{
public static function hasAlcohol()
{
// Do Something
}
}
I know i can call this as
House::hasAlcohol()
However, i would also like to know if its okay with coding standards and PHP and if it would be error free to call hasAlcohol() from an instance of house (i tried it and got no errors), for example
$house = new House();
$house->hasAlcohol();
As this has caused several problems for me in the past: Yes, it is valid code. Should you do it? No. It gives the impression that the call is non-static and will most likely cause grief for people working on your code later on. There is no reason to make your code ambiguous.
This used to be possible, but the latest versions of PHP will throw an error, if I remember correctly. You should call static functions statically. You can do $house::hasAlcohol() though.
This used to be possible, but the latest versions of PHP will throw an error, if I remember correctly. You should call static functions statically. You can do $house::hasAlcohol() though.
On a side note, should hasAlcohol really be static? From the name it appears it should be an instance method.
A more recommended pattern if you need constant access to a method is to use a static constructor and get an instance (even if it's a "blank" or "empty") instance to that class. So in the example you've shown, it might be better to have a method like this:
class House
{
public function instance()
{
return new House;
}
public function hasAlcohol()
{
// Do Something
}
}
Then if you ever needed to make a call to "hasAlcohol()" where you don't need an instance for any other purpose, you can do a one-off like so:
House::instance()->hasAlcohol();
or you can instantiate it like in your example:
$house = new House;
$house->hasAlcohol();
or, better yet, use your new factory method:
$house = House::instance();
$house->hasAlcohol();

is it possible to change method property from public to private and back on runtime from inside class?

like this:
if ($sth) make_private($this->method);
or maybe there's some other way to affect accessibility of methods ?
Problem is that I written a class where methods must be called once, so I need code to restrict access to given method from outside the class after this method was executed.
You've got several better options:
Handle the 'can only be called once' with some static state variable in the class itself, and throw legible exceptions.
Handle the 'can only be called once' with a decorator object if you cannot alter the class/object itself.
The very undesirable way you suggest is possible, see classkit_method_redefine or runkit_method_redefine, but on behalf of anyone possibly working on your code in future: please do not use it.
Simple way to do so within the mothod (restrict to one call):
public function fooBar() {
static $called;
if (isset($called)) throw new Exception('Called already once!');
$called = true;
// your code
}

Call a protected method from outside a class in PHP

I have a very special case in which I need to call a protected method from outside a class. I am very conscious about what I do programmingwise, but I would not be entirely opposed to doing so in this one special case I have. In all other cases, I need to continue disallowing access to the internal method, and so I would like to keep the method protected.
What are some elegant ways to access a protected method outside of a class? So far, I've found this.
I suppose it may be possible create some kind of double-agent instance of the target class that would sneakily provide access to the internals...
In PHP you can do this using Reflections.
To invoke protected or private methods use the setAccessible() method
http://php.net/reflectionmethod.setaccessible (just set it to TRUE)
I would think that in this case, refactoring so you don't require this sort of thing is probably the most elegant way to go. In saying that one option is to use __call and within that parse debug_backtrace to see which class called the method. Then check a friends whitelst
class ProtectedClass {
// Friend list
private $friends = array('secret' => array('FriendClass'));
protected function secret($arg1, $arg2) {
// ...
}
public function __call($method, $args) {
$trace = debug_backtrace();
$class = $trace[1]['class'];
if(in_array($class, $this->friends[$method]))
return $this->$method($args[0], $args[1]);
throw new Exception();
}
}
I think I need a shower.
This is a little kludgy, but might be an option.
Add a child class for the sake of accessing your protected function
public class Child extends Parent {
public function protectedFunc() {
return parent::protectedFunc();
}
}
Then, instantiate an instance of Child instead of Parent where you need to call that function.
I'm just throwing this out there since I haven't programmed in PHP in two years. Could you just add a function to the class that calls the protected method like so?
$obj->publicFunc = create_function('$arg', 'return $this->protectedFunc($arg);');
Edit:
I think Tom's correct in looking at the documentation for create_function. It looks like the scope of $this will be "wrong" when you try to call it with this example.
It looks like traditional anonymous functions are supported since PHP 5.3.0 as well (and my first solution probably won't work), so I'd probably write it like this instead:
$obj->publicFunc = function($arg) {
return $this->protectedFunc($arg);
};
Since I think it looks a little cleaner (and your IDE of choice will highlight it better of course).
Ugh, I tried using Reflection to call the method but PHP won't allow you to do that either. It seems that you're going to have to use some sort of child class like the other posters have suggested. If you find a method that works, the developers will likely classify it as a bug in the future and break your code when you upgrade to the next version.
I recommend extending the class.
I'd think about what is the matter with the program design if I have to call a private function?
It used to be the case when
your class is responsible for several things (it is really two or thre calsses wrapped together) or
the rules of encapsulation are broken (utility functions, for example)
By finding any way to walk around this questions, you'll be nowhere nearer to the real solution.
Suppose your method declaration goes like so:
protected function getTheFoo() {
...
}
protected function setTheFoo($val) {
...
}
Usage:
$obj->__get('the_foo');
$obj->__set('the_foo', 'myBar');
This bypasses the protected methods and goes directly straight to the instance variables.

Categories