I have a eval function like this
if(FALSE === #eval($code)) echo 'your code has php errors';
So if the code has synthax errors it will return that message.
The problem is that if within the code you have something like:
require_once('missing_file.php');
it will just break the page, without my nice error message :(
Is there any workaround for this?
Well, first I hope that $code comes from a trusted source and that you're executing arbitrary code sent by the users.
Second, the only way I see you can workaround that is to save $code into a file, run it with the command line PHP interpreter, and check the exit value. Note that passing this test doesn't make $code fatal error free, it just so happened that this particular execution of the script did not throw any fatal error; there may be other code paths that trigger such an error.
This is because once eval triggers a fatal error, it can't be recovered and the script dies. eval only returns FALSE if there is a parsing error.
Related
So my PHP file is meant to check if a variable is null, if so than echo and output, and stop there
Here is that code:
if(is_null($ip)){
echo "IP is not valid";
clean_all_processes();
}
So when I try to test this script using the insomnia rest client it outputs the "IP is not valid" but also gives a "500 internal server error"
In my error_log file it spits out this every time
Uncaught Error: Call to undefined function clean_all_processes()
Note: I am using php 7.3
There is no such function called clean_all_processes() in PHP. The answer you linked to used it as an example name of a function you could call.
If you want a hard stop of your script use die(). This is not recommended! You should structure your code in such a way that you should almost never need to use this approach.
There is no way to break out of if statement, because such thing makes no sense. An if statement is already a condition. You either execute the code or don't.
I am trying to implement Google+ login on my website and am running into an issue. Here is my code (after creating a Google_Client object):
try {
$client->authenticate($_GET['code']);
$plus = new \Google_Service_Plus($client);
$person = $plus->people->get('me');
$firstName = $person->modelData->name->givenName;
} catch (Google_Auth_Exception $e) {
$response = array(
'error' => 'Error: Authentication exception.'
);
} catch (Exception $e) {
$response = array(
'error' => 'Error: Uncaught exception.'
);
}
$client->authenticate() throws a Google_Auth_Exception if the code passed to it is invalid
If authentication failed, then reading properties from the $person object causes fatal errors
$responseis echo'd out as a JSON-encoded object
The problem is that the try/catch code does not seem to be working properly. When authentication fails due to the code in $_GET['code'] being invalid, the following response is returned from the script:
{"error":"Error: Authentication exception."}
So far so good -- the code in the first catch block was executed.
However, the code in the try block continues to execute in a weird fashion. I say "weird" because in the above form, a bunch of errors (culminating in a fatal error) occur, meaning this line:
$firstName = $person->modelData->name->givenName;
Is still executed! It should not be executed since an exception was thrown on a previous line. If I comment out the above line, the errors are not thrown (again indicating this line is executed, which it shouldn't be).
Here are the errors outputted due to the above line executing after the exception has been thrown:
Notice: Undefined index: modelData in [...]\google-api-php-client-master\src\Google\Model.php on line 78
Notice: Trying to get property of non-object in [...]\ajax_handler.php on line 720 [note: this is the line shown above, where the property is being accessed]
Notice: Trying to get property of non-object in [...]\ajax_handler.php on line 720
Another reason I said "weird" is that if I add this line:
die('dying before reading property');
Right before the above line (where I read a property), no errors occur, BUT the "dying before reading property" text is not output onto the page! This is weird because the script is clearly still executing code in the try block after the error is thrown (since without this die() line, the line reading the property is executed and results in lots of errors being output). As with before, the code in the catch block is still executed and the JSON is output onto the page.
What on earth is going on?
PHP is a compiled language. See this question and this answer for an explanation.
Basically, the code is parsed, assembled, and compiled into bytecode before it's executed; what's happening with your script is that the code is invalid. The syntax is correct, so PHP doesn't just outright fail. The issue arises after the object $person is constructed, when you try to access a dynamic property (modelData) that doesn't exist or is inaccessible due to its scope. So the errors you are seeing are because PHP can't find it.
The reason the code doesn't output 'dying before reading property' is because the code isn't actually being executed, so it can't "stop" execution; it's already stopped.
Change
$firstName = $person->modelData->name->givenName;
to
$firstName = $person->name->givenName;
and you should be good to go.
This question and its selected answer keep bothering me. It seems so unlikely that PHP would have executed/parsed/whatever, while an exception was already thrown.
I would rather suggest the code is being run twice. The first time giving the Exception message, and the second time producing the notices.
I suggest you try this:
put $testVar = uniqid(); just before try {
put echo $testVar; just after try {
When you run the code now you should see a unique ID just before the Exception message, and (my theory) another/different unique ID just before your notices. This would prove the code is being run twice.
About the die("..."); not appearing, I would ask if you really checked this looking in your HTML source, because it could be hidden for some reasong. (eg invisible div)
I'll give you the gist.
I'm trying to scrape certain URL's using a third party HTML tag stripper because I don't think the default strip_tags() does the job well. (I don't think you need to check that scraper)
Now sometimes, the HTML source code of some sites contains some weird code that is causing my HTML tag stripper to fail.
One such example is this site that contains the following piece of code :
<li>Photo Galleries</li>
that causes the above mentioned tag stripper to throw this error :
Parse error: syntax error, unexpected
T_ENCAPSED_AND_WHITESPACE, expecting T_STRING or T_VARIABLE or
T_NUM_STRING in /var/www/GET
Tweets/htdocs/tmhOAuth-master/examples/class.html2text.inc(429) :
regexp code on line 1 Fatal error:
preg_replace() [<a
href='function.preg-replace'>function.preg-replace</a>]:
Failed evaluating code:
$this->_build_link_list("<//?=$cnf[\'website\']?>girls/models-photo-gallery/?sType=6#top_menu",
"Photo Galleries") in /var/www/GET
Tweets/htdocs/tmhOAuth-master/examples/class.html2text.inc on line
429
Now what happens is, there is an array of many URLs and some throw the abovementioned error. I do some processing on each URL.
If some URL in the array throws an error like this, I want the execution to proceed ahead with processing of next URL without it disturbing anything. My code is something like this:
foreach ($results as $result)
{
$url=$result->Url;
$worddict2=myfunc($url,$worddict2,$history,$n_gram);
}
Here myfunc does the processing and uses the 3rd party HTML stripper I mentioned before.
I tried modifying the code to this:
foreach ($results as $result)
{
$url=$result->Url;
$worddicttemp=array();
try
{
$worddicttemp=myfunc($url,$worddict2,$history,$n_gram); //returns the string represenation of what matters, hopefully
//The below line will be executed only when the above function doesn't throw a fatal error
$worddict2=$worddicttemp;
}
catch(Exception $e)
{
continue;
}
}
But I'm still getting the same error.
What is wrong? Why is the code inside myfunc() now transferring control to the catch blocks as soon as it encounters that fatal error?
I propose you to use some beautifier script like Tidy before parsing. And your problem can be solved by adding
$html_content = htmlspecialchars($html_content)
You can't catch Parse Errors (or any Fatal Errors for that matter, but Parse Errors are even worse since they'll be generated as soon as the code is loaded). The best way I know of to isolate them is to run completely independent PHP processes for whatever you want to recover from and expect to generate Fatal Errors.
See also How do I catch a PHP Fatal Error
Is there a way to make the code continue (not exit) when you get a fatal error in PHP?
For example I get a timeout fatal error and I want whenever it happens to skip this task and the continue with others.
In this case the script exits.
There is a hack using output buffering that will let you log certain fatal errors, but there's no way to continue a script after a fatal error occurs - that's what makes it fatal!
If your script is timing out you can use set_time_limit() to give it more time to execute.
"Fatal Error", as it's name indicates, is Fatal : it stop the execution of the script / program.
If you are using PHP to generate web pages and get a Fatal error related to max_execution_time which, by defaults, equals 30 seconds, you are certainly doing something that really takes too mych time : users won't probably wait for so long to get the page.
If you are using PHP to do some heavy calculations, not in a webpage (but via CLI, or a cron, or stuff like that), you can set another (greater) value for max_execution_time.
You have two ways of doing that :
First is to modify php.ini, to set this value (it's already in the file ; just edit the property's value). Problem is it'll modify it also for the web server, which is bad (this is a security measure, after all).
Better way is to create a copy of php.ini, called, for instance, phpcli.ini, and modify this file. Then, use it when invoking php :
php -c phpcli.ini myscript.php
This'll work great if you have many properties you need to configure for CLI execution. (Like memory_limit, which often has to be set to a higher value for long-running batches)
The other way is to define a different value for max_execution_time when you invoke php, like this :
php -d max_execution_time=60 myscript.php
This is great if you launch this via the crontab, for instance.
It depends on the exact error type. You can catch errors by creating your own error handler. See the documentation on set_error_handler(), but not all types of errors can be caught. Look at the timeout error you get and see what type it is. If it is one of E_ERROR, E_PARSE, E_CORE_ERROR, E_CORE_WARNING, E_COMPILE_ERROR or E_COMPILE_WARNING then you cannot catch it with an error handler. If it another type then you can. Catch it with the error handler and simply return.
If you have a suitable PHP version (PHP>=5.2 for error_get_last) you can try the technique described here which uses register_shutdown_function and error_get_last.
This won't allow you to "continue" when you get a fatal error, but it at least allows you to log the error (and perhaps send a warning email) before displaying a custom error page to the user.
It works something like this:
function fatalErrorHandler()
{
$lastError = error_get_last();
if (isset($lastError["type"]) && $lastError["type"]==E_ERROR) {
// do something with the fatal error
}
}
...
register_shutdown_function('fatalErrorHandler');
A few points:
you can use ob_clean() to remove any content that was generated prior to the fatal error.
it's a really bad idea to do anything to intensive in the shutdown handler, this technique is about graceful failure rather than recovery.
whatever you do, don't try to log the error to a database ... what if it was a database timeout that caused the fatal error?
for some reason I've had problems getting this technique to work 100% of the time when developing in Windows using WAMP.
The most simple answer I can give you is this function: http://php.net/manual/en/function.pcntl-fork.php
In more detail, what you can do is:
Fork the part of the process you think might or might not cause a fatal error (i.e. the bulk of your code)
The script that forks the process should be a very simple script.
For example this is something that I would do with a job queue that I have:
<?php
// ... load stuff regarding the job queue
while ($job = $queue->getJob()) {
$pid = pcntl_fork();
switch ($pid) {
case -1:
echo "Fork failed";
break;
case 0:
// do your stuff here
echo "Child finished working";
break;
default:
echo "Waiting for child...";
pcntl_wait($status);
// check the status using other pcntl* functions if you want
break;
}
}
Is there a way then to limit the execution time of an function but not all script?
For example
function blabla()
{
return "yes";
}
to make it so that if it is not executed in 25 seconds to return no;
I'm looking to run a bit of custom error handling for PHP's parse errors - the type when the syntax is wrong, and you get those white screens of death.
(To be clear, the type that would result when running malformed code as so:
<?php
if () {
?>
)
I had a look at setting a custom error handler, but couldn't get anything to happen.
Another idea: If you have an own root server or just want to execute the script on your local PC you could do the following:
Put the code to test in a new file, say failure.php.
In your script (same directory), where you want to check for errors, do it this way:
$path_to_test = 'failure.php';
$result = `php -l $path_to_test`;
Then you have the parse error messages in $result, because the flag -l makes PHP only parse the code. It will never execute anything. You can parse the error messages if any on your own and even get the line numbers out of them.
Normally you'd use set_error_handler for this, but the docs note this:
The following error types cannot be handled with a user defined function: E_ERROR, E_PARSE, E_CORE_ERROR, E_CORE_WARNING, E_COMPILE_ERROR, E_COMPILE_WARNING, and most of E_STRICT raised in the file where set_error_handler() is called.
What you have there is a PARSE_ERROR and is not catachble by this. In the "user comment" sections of the set_error_handler page there is a plethora of solutions to catch all errors, and some say it works and some say it doesn't, so I suggest just going through them and finding if any in fact work.
It isn't a Fatal error as the term is used in PHP. It is a Parse error. This means that PHP cannot understand your code and it thus never comes to execution of the code at all. Therefore you can't catch such errors.
If you're sure the code to test does not contain any harmful injections, you can eval it:
if ( !#eval( 'if () {' ) )
{
echo "An error occured.";
}
But be sure to read advices on how and when to use eval(). It can be quite dangerous.