PHP FILTER_CALLBACK in OOP Class - php

Hi I've been playing around with phps filter class getting and have come across a snag with the filter_callback filter.
the following rough bit of code works but shows an error every time
Warning: filter_var() [function.filter-var]: First argument is expected to be a valid callback in /Users/Rob/sites/test_val.php on line 12
class test
{
public function callback($string)
{
$var = filter_var($string, FILTER_CALLBACK, array('options' => $this->foo($string)));
}
public function foo($string){
echo $string;
}
}
$test = new test();
$string = 'test';
$tested = $test->callback($string);
am i calling the function correctly or is there a different way?

$this->foo($string)
...should be...
array($this, 'foo')
When using a method as a callback, you need to provide the reference in this manner.
Documentation.

This code works for me :)
<?php
class myClass {
public function myFunc($var){
return filter_var($var, FILTER_CALLBACK, array('options'=> 'self::myCallback'));
}
public function myCallback(){
return true;
}
}
$obj = new myClass();
var_dump($obj->myFunc("myname#gmail.com"));
//output:- bool(true)
?>

echo filter_var('wo9w9w9', FILTER_CALLBACK, array('options' => array(new MyFilter(), 'filter1'))) . PHP_EOL;
options You can directly transfer object instance, like $this or new self ,

Related

Array to string conversion problem in PHP7 [duplicate]

Is there a way to dynamically invoke a method in the same class for PHP? I don't have the syntax right, but I'm looking to do something similar to this:
$this->{$methodName}($arg1, $arg2, $arg3);
There is more than one way to do that:
$this->{$methodName}($arg1, $arg2, $arg3);
$this->$methodName($arg1, $arg2, $arg3);
call_user_func_array(array($this, $methodName), array($arg1, $arg2, $arg3));
You may even use the reflection api http://php.net/manual/en/class.reflection.php
You can use the Overloading in PHP:
Overloading
class Test {
private $name;
public function __call($name, $arguments) {
echo 'Method Name:' . $name . ' Arguments:' . implode(',', $arguments);
//do a get
if (preg_match('/^get_(.+)/', $name, $matches)) {
$var_name = $matches[1];
return $this->$var_name ? $this->$var_name : $arguments[0];
}
//do a set
if (preg_match('/^set_(.+)/', $name, $matches)) {
$var_name = $matches[1];
$this->$var_name = $arguments[0];
}
}
}
$obj = new Test();
$obj->set_name('Any String'); //Echo:Method Name: set_name Arguments:Any String
echo $obj->get_name();//Echo:Method Name: get_name Arguments:
//return: Any String
Just omit the braces:
$this->$methodName($arg1, $arg2, $arg3);
You can also use call_user_func() and call_user_func_array()
If you're working within a class in PHP, then I would recommend using the overloaded __call function in PHP5. You can find the reference here.
Basically __call does for dynamic functions what __set and __get do for variables in OO PHP5.
In my case.
$response = $client->{$this->requestFunc}($this->requestMsg);
Using PHP SOAP.
You can store a method in a single variable using a closure:
class test{
function echo_this($text){
echo $text;
}
function get_method($method){
$object = $this;
return function() use($object, $method){
$args = func_get_args();
return call_user_func_array(array($object, $method), $args);
};
}
}
$test = new test();
$echo = $test->get_method('echo_this');
$echo('Hello'); //Output is "Hello"
EDIT: I've edited the code and now it's compatible with PHP 5.3. Another example here
Still valid after all these years! Make sure you trim $methodName if it is user defined content. I could not get $this->$methodName to work until I noticed it had a leading space.

PHP Nested call_user_func_array with classes

I have a complicated scenario based on an existing framework I'm using which is forcing me to deal with nested call_user_func_array calls. I've got a file with two functions:
function their_caller($options)
{
call_user_func_array('their_callback', $options);
}
function their_callback($options)
{
call_user_func_array($options[0], $options[1]);
}
Then I have another file with a class with and some public methods:
namespace FOO;
class MyClass
{
public function my_caller()
{
$operations = array(
array(
array($this, 'my_callback'),
'Hello World'
)
);
their_caller($operations);
}
public function my_callback($text)
{
print $text;
}
}
When I call my_caller() on a new instance of MyClass, it calls their_caller which then passes an array of arguments containing a reference to MyClass (as $this) as well as the method my_callback.
their_caller() then forwards the request to their_callback and passes $options along.
In their_callback I can debug $options[0] and see that it's an array containing a reference to MyClass and my_callback.
I call get_class_methods() on $options[0][0] in their_callback and it will show the list of methods, but for some reason, call_user_func_array($options[0], $options[1]); won't call my_callback on MyClass. I can even call $options[0][0]->my_callback('HELLO'); and it works.
Unfortunately, I can't modify their_caller or their_callback. They are part of the framework. Any ideas what's preventing it from working?
Note: Your function their_callback will receive two arguments.
Try this code snippet here
<?php
ini_set('display_errors', 1);
function their_caller($options)
{
call_user_func_array('their_callback', $options);
}
//first argument will receive callback
//second argument will receive the text which you want to send as argument.
function their_callback($callback,$option)
{
//call_user_func_array should expect second argument as array not string.
call_user_func_array($callback, array($option));
//here we have converted `$option` string(Hello World) to array.
}
class MyClass
{
public function my_caller()
{
$operations = array(
array(
array($this, 'my_callback'),
'Hello World'
)
);
call_user_func_array('their_caller', $operations);
}
public function my_callback($text)
{
print $text;
}
}
$object= new MyClass();
$object->my_caller();

Select custom class function

I have a custom PHP class with few methods in it. Is is possible to call class method this way:
<?php
class someClass{
function someMethod_somename_1(){
echo 'somename1';
}
function someMethod_somename_2(){
echo 'somename2';
}
}
$obj = new someClass();
$methodName = $_GET['method_name'];
$obj->someMethod_{$methodName}(); //calling method
?>
My real world application is more complex, but here I provide just this simple example to get the main idea. Maybe I can use eval function here?
Please don't use eval() because it's evil in most situations.
Simple string concatenation helps you:
$obj->{'someMethod_'.$methodName}();
You should also verify the user input!
$allowedMethodNames = array('someone_2', 'someone_1');
if (!in_array($methodName, $allowedMethodNames)) {
// ERROR!
}
// Unrestricted access but don't call a non-existing method!
$reflClass = new ReflectionClass($obj);
if (!in_array('someMethod_'.$methodName, $reflClass->getMethods())) {
// ERROR!
}
// You can also do this
$reflClass = new ReflectionClass($obj);
try {
$reflClass->getMethod('someMethod_'.$methodName);
}
catch (ReflectionException $e) {
// ERROR!
}
// You can also do this as others have mentioned
call_user_func(array($obj, 'someMethod_'.$methodName));
Of course, take this:
$obj = new someClass();
$_GET['method_name'] = "somename_2";
$methodName = "someMethod_" . $_GET['method_name'];
//syntax 1
$obj->$methodName();
//alternatively, syntax 2
call_user_func(array($obj, $methodName));
Concatenate the whole method name before you call it.
Update:
Directly calling methods based on user input is never a good idea. Consider doing some previous validation of the method name before.
You may also take advantage of php magic methods, namely __call() in combination with call_user_func_array() and method_exists():
class someClass{
public function __call($method, $args) {
$fullMethod = 'someMethod_' . $method;
$callback = array( $this, $fullMethod);
if( method_exists( $this, $fullMethod)){
return call_user_func_array( $callback, $args);
}
throw new Exception('Wrong method');
}
// ...
}
For safety purposes you may want to create a wrapper which would prohibit calling other methods, like this:
class CallWrapper {
protected $_object = null;
public function __construct($object){
$this->_object = $object;
}
public function __call($method, $args) {
$fullMethod = 'someMethod_' . $method;
$callback = array( $this->_object, $fullMethod);
if( method_exists( $this->_object, $fullMethod)){
return call_user_func_array( $callback, $args);
}
throw new Exception('Wrong method');
}
}
And use it as:
$call = new CallWrapper( $obj);
$call->{$_GET['method_name']}(...);
Or maybe create execute method and than add to someClass method GetCallWrapper().
This way you'll get functionality well encapsulated into objects (classes) and won't have to copy it every time (this may come in handy if you'll need to apply some restrictions, i.e. privileges checking).
It is possible to use variable as function.
For example if you have function foo() you can have some variable $func and call it. Here is example:
function foo() {
echo "foo";
}
$func = 'foo';
$func();
So it should work like $obj->$func();

Add method in an std object in php

Is it possible to add a method/function in this way, like
$arr = array(
"nid"=> 20,
"title" => "Something",
"value" => "Something else",
"my_method" => function($arg){....}
);
or maybe like this
$node = (object) $arr;
$node->my_method=function($arg){...};
and if it's possible then how can I use that function/method?
This is now possible to achieve in PHP 7.1 with anonymous classes
$node = new class {
public $property;
public function myMethod($arg) {
...
}
};
// and access them,
$node->property;
$node->myMethod('arg');
You cannot dynamically add a method to the stdClass and execute it in the normal fashion. However, there are a few things you can do.
In your first example, you're creating a closure. You can execute that closure by issuing the command:
$arr['my_method']('Argument')
You can create a stdClass object and assign a closure to one of its properties, but due to a syntax conflict, you cannot directly execute it. Instead, you would have to do something like:
$node = new stdClass();
$node->method = function($arg) { ... }
$func = $node->method;
$func('Argument');
Attempting
$node->method('Argument')
would generate an error, because no method "method" exists on a stdClass.
See this SO answer for some slick hackery using the magic method __call.
Since PHP 7 it is also possible to directly invoke an anonymous function property:
$obj = new stdClass;
$obj->printMessage = function($message) { echo $message . "\n"; };
echo ($obj->printMessage)('Hello World'); // Hello World
Here the expression $obj->printMessage results in the anonymous function which is then directly executed with the argument 'Hello World'. It is however necessary to put the function expression in paranetheses before invoking it so the following will still fail:
echo $obj->printMessage('Hello World');
// Fatal error: Uncaught Error: Call to undefined method stdClass::printMessage()
Another solution would be to create an anonymous class and proxy the call via the magic function __call, with arrow functions you can even keep reference to context variables:
new Class ((new ReflectionClass("MyClass"))->getProperty("myProperty")) {
public function __construct(ReflectionProperty $ref)
{
$this->setAccessible = fn($o) => $ref->setAccessible($o);
$this->isInitialized = fn($o) => $ref->isInitialized($o);
$this->getValue = fn($o) => $ref->getValue($o);
}
public function __call($name, $arguments)
{
$fn = $this->$name;
return $fn(...$arguments);
}
}
class myclass {
function __call($method, $args) {
if (isset($this->$method)) {
$func = $this->$method;
return call_user_func_array($func, $args);
}
}
}
$obj = new myclass();
$obj->method = function($var) { echo $var; };
$obj->method('a');
Or you can create defult class and use...

Call private methods and private properties from outside a class in PHP

I want to access private methods and variables from outside the classes in very rare specific cases.
I've seen that this is not be possible although introspection is used.
The specific case is the next one:
I would like to have something like this:
class Console
{
final public static function run() {
while (TRUE != FALSE) {
echo "\n> ";
$command = trim(fgets(STDIN));
switch ($command) {
case 'exit':
case 'q':
case 'quit':
echo "OK+\n";
return;
default:
ob_start();
eval($command);
$out = ob_get_contents();
ob_end_clean();
print("Command: $command");
print("Output:\n$out");
break;
}
}
}
}
This method should be able to be injected in the code like this:
Class Demo
{
private $a;
final public function myMethod()
{
// some code
Console::run();
// some other code
}
final public function myPublicMethod()
{
return "I can run through eval()";
}
private function myPrivateMethod()
{
return "I cannot run through eval()";
}
}
(this is just one simplification. the real one goes through a socket, and implement a bunch of more things...)
So...
If you instantiate the class Demo and you call $demo->myMethod(), you'll get a console: that console can access the first method writing a command like:
> $this->myPublicMethod();
But you cannot run successfully the second one:
> $this->myPrivateMethod();
Do any of you have any idea, or if there is any library for PHP that allows you to do this?
Thanks a lot!
Just make the method public. But if you want to get tricky you can try this (PHP 5.3):
class LockedGate
{
private function open()
{
return 'how did you get in here?!!';
}
}
$object = new LockedGate();
$reflector = new ReflectionObject($object);
$method = $reflector->getMethod('open');
$method->setAccessible(true);
echo $method->invoke($object);
EDIT:
Updated to include examples of private function calls with parameters.
As of PHP 5.4, you can use the predefined Closure class to bind a method/property of a class to a delta functions that has access even to private members.
The Closure class
For example we have a class with a private variable and we want to access it outside the class:
class Foo {
private $bar = "Foo::Bar";
private function add_ab($a, $b) {
return $a + $b;
}
}
PHP 5.4+
$foo = new Foo;
// Single variable example
$getFooBarCallback = function() {
return $this->bar;
};
$getFooBar = $getFooBarCallback->bindTo($foo, 'Foo');
echo $getFooBar(); // Prints Foo::Bar
// Function call with parameters example
$getFooAddABCallback = function() {
// As of PHP 5.6 we can use $this->fn(...func_get_args()) instead of call_user_func_array
return call_user_func_array(array($this, 'add_ab'), func_get_args());
};
$getFooAddAB = $getFooAddABCallback->bindTo($foo, 'Foo');
echo $getFooAddAB(33, 6); // Prints 39
As of PHP 7, you can use the new Closure::call method, to bind any method/property of an obect to a callback function, even for private members:
PHP 7+
$foo = new Foo;
// Single variable example
$getFooBar = function() {
return $this->bar;
};
echo $getFooBar->call($foo); // Prints Foo::Bar
// Function call with parameters example
$getFooAddAB = function() {
return $this->add_ab(...func_get_args());
};
echo $getFooAddAB->call($foo, 33, 6); // Prints 39
The first question you should ask is, if you need to access it from outside the class, why did you declare it private? If it's not your code, the originator probably had a good reason to declare it private, and accessing it directly is a very bad (and largely unmaintainable) practice.
EDIT: As Adam V. points out in the comments, you need to make the private method accessible before invoking it. Code sample updated to include this. I haven't tested it, though - just adding here to keep the answer updated.
That having been said, you can use Reflection to accomplish this. Instantiate ReflectionClass, call getMethod for the method you want to invoke, and then call invoke on the returned ReflectionMethod.
A code sample (though I haven't tested it, so there may be errors) might look like
$demo = new Demo();
$reflection_class = new ReflectionClass("Demo");
$reflection_method = $reflection_class->getMethod("myPrivateMethod");
$reflection_method->setAccessible(true);
$result = $reflection_method->invoke($demo, NULL);
Here's a variation of the other answers that can be used to make such calls one line:
public function callPrivateMethod($object, $methodName)
{
$reflectionClass = new \ReflectionClass($object);
$reflectionMethod = $reflectionClass->getMethod($methodName);
$reflectionMethod->setAccessible(true);
$params = array_slice(func_get_args(), 2); //get all the parameters after $methodName
return $reflectionMethod->invokeArgs($object, $params);
}
I have these problems too sometimes, however I get around it through my coding standards. Private or protected functions are denoted with a prefix underscore ie
private function _myPrivateMethod()
Then i simply make the function public.
public function _myPrivateMethod()
So although the function is public the naming convention gives the notification that whilst public is is private and shouldn't really be used.
If you are able to added a method in the class where the method is defined, you can add method which uses the call_user_method() internally. This works also with PHP 5.2.x
<?php
class SomeClass {
public function callprivate($methodName) {
call_user_method(array($this, $methodName));
}
private function somePrivateMethod() {
echo 'test';
}
}
$object = new SomeClass();
$object->callprivate('somePrivateMethod');
Answer is put public to the method. Whatever trick you are going to do it wouldn't be understandable to fellow developers. For example they do not know that at some other code this function has been accessed as public by looking at the Demo class.
One more thing. that console can access the first method writing a command like:. How can this even be possible? Console can not access demo class functions by using $this.
I guess the reflectionClass is the only alternative if you really want to execute some private methods. Anyhow, if you just need read access to privat or protected properties, you could use this code:
<?php
class Demo
{
private $foo = "bar";
}
$demo = new Demo();
// Will return an object with public, private and protected properties in public scope.
$properties = json_decode(preg_replace('/\\\\u([0-9a-f]{4})|'.get_class($demo).'/i', '', json_encode((array) $demo)));
?>
<?php
$request="email";
$data=[1,2,3,4,5];
$name=new Update($request,$data);
class Update{
private $request;
private $data;
function __construct($request,$data){
$this->request=$request;
$this->data=$data;
if($this->request=='email'){
$this->update_email();
}
else{
echo "Can't do anything";
}
}
private function update_email(){
echo $this->request;
echo '\n';
foreach($this->data as $x){
echo $x."\n";
}
}
}
?>

Categories