Hook into call_user_func_array - possible? [duplicate] - php

I want to hook before execution / or replace standart core functions, for example i im going to prevent both include and require accesa to any scripts. Is any way to make it without any extra .dll's? Or another case is_array($myarr); i would be to hook at array($myarr) === $myarr; (looks like it is faster) to avoid creating extra classes and functions.
Ps and one more question : how to prevent all php execution after some moment? I have html templates with php parts <?=$myvar?> i want to prevent short sintax and execution at all when my script ends work, what i have to try?

About hooks to standart functions: there is no way to do that without external modules. APD PECL module
will do the job.
rename_function('require', 'internal_require'); // saving reference to original function
override_function('require', '$filename',
'print "require called"; internal_require($filename);');
Second question is not very clear. Do you want to hook on standart is_array function, to array() lexical construct or (array) type casting?
About stopping php interpretation: have a look at __halt_compiler function. But keep in mind that succeeding blocks of php will be just embedded in HTML (thus visible to everybody).

If you want to disable functions, you can use safe mode, but it is deprecated and not recommended. And as madfriend says, __halt_compiler just sends everything below it as text. Bear in mind that it can only be called from the outermost scope - I.e. not inside curly braces (if, loops, functions etc.)

Related

is there a way to eval a piece of php code where die() or exit() is present and return to main code if it is called?

I do not have control over the code I'm executing. This is a third party function, but not user-entered. These are things that are versioned so it is impractical that I poke there and change all die()'s into something more sane. Because a new version is coming from time to time and then I could paradoxically make the code even more insecure by trying mess with it poor error handling.
so let's say we have a function:
fuction myfunc() {
// lot's of complicated code
if (!is_file('myfile.txt') exit('file not found');
// and so on
}
What I'm trying to do is to somewhat run that piece of code and return to my main thread and then act accordingly with that error.
I've tried die() or eval() but this returns the whole script.
Bummer ?
A Hail Mary approach is to use runkit's runkit_function_redefine or function_override to redefine the functions die and exit to throw an Exception instead.
A potential problem is that the 3rd party can catch those exceptions and might not deal with them correctly. It's also very likely that you can't properly deal with the exception either.
You can use register_shutdown_function to run code after exit has been called. You are somewhat limited in what you can do at this point as some services have already been shut down (such as autoloading). I think you can still output content, not sure about sessions and other headers.
Another approach would be to run the code in a seperate php process (or http request), for instance by calling php through exec.
A more solid approach can be to add predicitions to your own code, ensuring the bad states are never reached when calling the 3rd party code. It is possible that not all preconditions can be met.
Ideally only code that is an entry point (like a router script) may exit. Using exit anywhere else is just shoddy programming really.
If you have not read Halcyon's answer, you should have a look at it first.
Since you mention eval(), I assume you have the code as a string. I will refer to both die() and exit() by just the latter, but things should be relevant for both.
You can try and replace occurrences of die() and exit() with something, and then eval. It's simple but that can be very messy.
One thing to look out for, IF you decide to do this, is that you may end up replacing occurrences which are not really 'code'. For example, echo "Let him exit()";.
Also, when you consider possible equivalent syntax, like exit (); , exit; or exit(1);, it gets much more unpleasant. You'll have to handle those with a regex.
But if you can safely assume that
those two signatures (die() and exit()) are the only ones you need to worry about; and
that strings (or other content) are not going to contain those 'phrases'
then you can use this approach.

php hook core functions

I want to hook before execution / or replace standart core functions, for example i im going to prevent both include and require accesa to any scripts. Is any way to make it without any extra .dll's? Or another case is_array($myarr); i would be to hook at array($myarr) === $myarr; (looks like it is faster) to avoid creating extra classes and functions.
Ps and one more question : how to prevent all php execution after some moment? I have html templates with php parts <?=$myvar?> i want to prevent short sintax and execution at all when my script ends work, what i have to try?
About hooks to standart functions: there is no way to do that without external modules. APD PECL module
will do the job.
rename_function('require', 'internal_require'); // saving reference to original function
override_function('require', '$filename',
'print "require called"; internal_require($filename);');
Second question is not very clear. Do you want to hook on standart is_array function, to array() lexical construct or (array) type casting?
About stopping php interpretation: have a look at __halt_compiler function. But keep in mind that succeeding blocks of php will be just embedded in HTML (thus visible to everybody).
If you want to disable functions, you can use safe mode, but it is deprecated and not recommended. And as madfriend says, __halt_compiler just sends everything below it as text. Bear in mind that it can only be called from the outermost scope - I.e. not inside curly braces (if, loops, functions etc.)

Looking for functions with PHP tokenizer

Right now, I have a script which uses PHP's tokenizer to look for certain functions within a PHP source code file. The pattern I am currently looking for is:
T_STRING + T_WHITESPACE (optional) + "("
This seems to match all of my test cases so far except variable functions, which I am ignoring for the purposes of this question.
The obvious problem here is that this pattern produces a lot of false positives, like matching function definitions:
public function foo() { // foo() should not be matched
My question is, is there a more reliable/accurate method for looking at source code and plucking out all the function invocations? Maybe a better method than using the tokenizer at all?
Edit:
In particular, I'm looking to emulate the functionality of the disable_functions PHP directive within a class file. So, if exec() should be disallowed, I'm trying to find any uses of that function within the analyzed file. I do realize that variable functions make this terribly difficult, so I am detecting these and disallowing them as well.
You first run the tokenizer (available in PHP). Then you run a parser on top of the tokens. The parser needs to read the tokens and should be able to tell your what a specific token has been used for. It depends on the reliability of your parser how reliable the outcome is.
If your current parser (you have not shown any code) is not reliable enough, you need to write a better parser. That simple it is. Probably you're not doing much more than just tokenizing and then reading as it passes which just might not be enough.
Instead of using the tokenizer, consider instead using a higher-level parser to analyze your code. For example, PHP-Parser can explicitly identify function declarations, as well as variable function calls.

Why are dynamic constructs difficult for php compilers (HPHP)?

I was reading up on Paul Bigger's http://blog.paulbiggar.com/archive/a-rant-about-php-compilers-in-general-and-hiphop-in-particular/ and he mentions that HPHP doesn't fully support dynamic constructs. He then states, "Still, a naive approach is to just stick a switch statement in, and compile everything that makes sense." Is he saying that instead of a dynamic include, you could use switch statements to include the proper file? If so, why would this work and why is it "easier" for a compiler to compile? As always, thx for your time!
from my understanding, if you've got this
include "$foo.php";
the compiler would have no clue what you're going to include. On the other side, with this
switch($foo) {
case 'bar' : include "bar.php";
case 'quux' : include "quux.php";
}
they can simply compile "bar" and "quux" and wrap them in an if statement which checks $foo and executes whatever is appropriate.
A compiler expects to be able to identify all of the source and binary files that might be used by the program being compiled.
include($random_file);
If the file named in $random_file declares constants, classes, variables, the compiler will have no way knowing because the value of $random_file is not known at compile time. Your code using those constants, classes and variables will fail in difficult-to-debug ways. The switch statement would make known the list of possible files so the compiler can discover any relevant declarations.
Languages designed to be compiled have dynamic linkers and foreign function interfaces that combine to provide similar functionality to include($random_file) without needing the explicit switch.

What can I use instead of eval()?

I have a string that stores some variables that must be executed to produce a result, for example:
define('RUN_THIS', '\$something.",".$somethingElse');
Which is then eval()-uated:
$foo = eval("return ".RUN_THIS.";");
I understand that eval is unsafe if the string that gets evaluated is from user input. However, if for example I wanted to have everything run off Facebook's HipHop which doesn't support eval() I couldn't do this.
Apparently I can use call_user_func() - is this effectively the same result as eval()? How is deemed to be secure when eval() isn't, if that is indeed the case?
Edit:
In response to the comments, I didn't originally make it clear what the goal is. The constant is defined in advance in order that later code, be it inside a class that has access to the configuration constants, or procedural code, can use it in order to evaluate the given string of variables. The variables that need to be evaluated can vary (completely different names, order, formatting) depending on the situation but it's run for the same purpose in the same way, which is why I currently have the string of variables set in a constant in this way. Technically, eval() is not unsafe as long as the config.php that defines the constants is controlled but that wasn't the point of the question.
Kendall seems to have a simple solution, but I'll try to answer your other question:
Apparently I can use call_user_func() - is this effectively the same result as eval()? How is deemed to be secure when eval() isn't, if that is indeed the case?
call_user_func is actually safer than eval because of the fact that call_user_func can only call one user function. eval on the other hand executes the string as PHP code itself. You can append '; (close the string and start a new "line" of code) at the end of the string and then add some more code, add a ;' (end the line of code and start another string so that there is no syntax error), thus allowing the constant RUN_THIS to contain lots of PHP code that the user can run on the server (including deleting all your important files and retrieving information for databases, etc. NEVER LET THIS HAPPEN.
call_user_func doesn't let his happen. When you run call_user_func_array($func, $args) the user can only run a restricted set of functions because: (a) the function has to be user defined (b) you can manipulate $func to ensure the user isn't able to run any function he/she wants either by checking that $func is in a list of "allowed functions" or by prefixing something like user_ to the function names and the $func variable itself (This way the user can run only functions beginning with user_.
I can't see any reason why you can't just use double-quote string building.
$foo = "\$something,$somethingElse";

Categories