Code in try block continues executing after exception? - php

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)

Related

How to get rid of the "Uncaught TypeError: feof(): supplied resource is not a valid stream resource" logged error?

For years now, I've been trying to solve this insanely annoying issue. Seemingly at random, my fsockopen-using code fails and PHP-logs the error:
PHP Fatal error: Uncaught TypeError: feof(): supplied resource is not a valid stream resource
For the if (feof($the_connection)) line.
Normally, it works. This only happens "sometimes", presumably when there's a temporary network issue or a proxy is temporarily unavailable or something like that.
I've tried to use # to suppress it. Doesn't work. I've tried looking in the manual for feof to see if it has some parameter to turn this off. It doesn't.
In desperation, I've even tried wrapping it inside a try...catch block to make it shut up. It doesn't help:
try
{
if (feof($the_connection))
return false;
}
catch (exception $e)
{
return false;
}
No matter what I do, the damn "TypeError" sometimes happens and is logged, frustrating me since my code isn't "rock solid" to handle this case.
Online, there's no reference at all to this error, which is very unusual.
How do I make it stop? What can I possibly need to do since I actually do "try" and "catch"?

Alternating class not found error when using session handler

First of all, if it's relevant, this is in a session handler. This function is the one that writes to the database and is passed to session_set_save_handler along with my other functions like this
session_set_save_handler('sess_open', 'sess_close', 'sess_read', 'sess_write', 'sess_destroy', 'sess_gc');
I have this chunk of code...
$qid = "select count(*) as total
from zen_sessions
where sesskey = '" . $key . "'";
if(!class_exists('DB'))
require_once dirname(dirname(__FILE__)).'/class/DB.class.php';
var_dump(new DB()); //this is line 109
$total = DB::select_one($qid);
the conditional and var_dump are for testing. Oddly enough sometimes it works fine while others it gives me an error:
Fatal error: Class 'DB' not found in /path/to/file/session_functions.php on line 109
I cannot figure how this wouldn't crash at the require instead of the var_dump and why only sometimes?
Thanks in advance for any insight.
edit-- response to comment/question:
The result of the following code
var_dump(class_exists('DB', false));
var_dump(is_file(dirname(__DIR__).'/class/DB.class.php'));
is:
bool(false) bool(true)
before trying to require it and the same result after the require(or true true when it doesn't give me an error)
Looks something like:
bool(true) bool(true) object(DB)#3 (0) { }
The previous code chunk is the result about once out of every 5 page loads while the error is the result the other 4.
Edit2 -- new findings.
Even more curious is according to the manual I should never see these debugging statements or errors
Note:
The "write" handler is not executed until after the output stream is
closed. Thus, output from debugging statements in the "write" handler
will never be seen in the browser. If debugging output is necessary,
it is suggested that the debug output be written to a file instead.
Edit 3 - A Note for clarity:
The DB class Should have been autoloaded(and is everywhere else in the application) the class_exists and require are simply there for testing purposes.
Edit 4 - Stack trace
I decided to try and throw an exception when the class isn't found to see the stack trace, this is what I get
Fatal error: Uncaught exception 'Exception' with message 'DB Class Not Found.'
in /path/to/file/session_functions.php:108
Stack trace: #0 [internal function]: sess_write('074dabb967260e9...', 'securityToken|s...')
#1 {main} thrown in /path/to/file/session_functions.php on line 108
The only thing that I can think of that may be causing this, is from a notice in the PHP docs for session_set_save_handler:
Warning
Current working directory is changed with some SAPIs if session is closed in the script termination. It is possible to close the session earlier with session_write_close().
From what you are experiencing, I am guessing the current working directory is changed, so require_once doesn't find the file.
I would try adding session_write_close(); to somewhere in your function and see if that fixes it.
Admittedly, not sure why is_file would return true in this case, but maybe worth a shot.
Even though I can not be sure, but I bet that the error is somewhere else and it's just projecting itself as you've described it.
In order to test and debug your code, you need to use a debugger like PDT. But then the problem is that you need to debug a part of your code that is out of debugger's reach, the session writer! To overcome this problem you can use session_write_close. You can put it somewhere at the end of your bootstrap or if you don't have one, you can do it like this:
<?php
function shutdown_function()
{
session_write_close();
}
register_shutdown_function('shutdown_function');
Then by setting a break point, you can start debugging your session code from here. Let me know if I win the bet.
try:
$save_handler = new DB();
session_set_save_handler($save_handler, true);
then map read, write, etc functions inside your class. i faced a similar issue(bizarre random errors about a class not being found) implementing another user's custom save handler workaround for HHVM with redis, and this is how i fixed it. if you are using HipHopVirtualMachine (or possibly some other type of JIT compiler or app cache), sometimes your project can cache some functions without updating, producing odd errors like this. usually a restart of the fastcgi daemon and adding white space to one of your files is enough to force it to re interpret your project.

How to continue execution with in the next loop if a function throws fatal error in PHP?

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

PHP script halts on a mysql query with no exception thrown and no entry in php error log

I have a script that produces a report. For most widgets* it produces a report with no problem. For a particular widget it exits in the middle during a mysql query and a 500 is returned to the browser. By inserting writes to the php_error log I know the exact last line to be executed and it's always the same line. It's not a timeout because other widget reports run longer (and it bombs out in about 10 seconds).
Also, I've tried running the query it's trying to run in phpadmin and it runs OK.
When this abort occurs I see nothing appear in php_error.log, nothing in apache's error log and when I surround the offending statement with a try/catch, no exception is caught.
Is there somewhere else I can look that might show what error is occurring?
* by widget I'm not referring to a UI component. I'm using widget in the sense of fictional product from a fictional company
addendum ======================================================================
Since it was requested I posted the code although I think the problem isn't the code since it works in all but this once case. The problem is more likely in the data for this particular case.
error_log('['.__FILE__.']['.__LINE__."] check");
$table = new metrics_sessions();
//here I print out the SQL statement that will eventually be executed
error_log('['.__FILE__.']['.__LINE__."] check: "."guider_slug=? ".($effective_mindate!=null?" and date>'".$effective_mindate."'":"").($effective_maxdate!=null?" and date<'".$effective_maxdate." 23:59:59'":"").($effective_version!=0 && $effective_version!="all"?" and version=".$specific_version:"").($effective_campaign!==null && $effective_campaign!="all" ?" and campaign='".$effective_campaign."'":"")." order by date");
// BELOW IS THE LAST LINE I SEE IN PHP ERROR
error_log('['.__FILE__.']['.__LINE__."] check");
try {
$sessions = $table->Find("guider_slug=? ".($effective_mindate!=null?" and date>'".$effective_mindate."'":"").($effective_maxdate!=null?" and date<'".$effective_maxdate." 23:59:59'":"").($effective_version!=0 && $effective_version!="all"?" and version=".$specific_version:"").($effective_campaign!==null && $effective_campaign!="all" ?" and campaign='".$effective_campaign."'":"")." order by date",array($param_gslug));
error_log('['.__FILE__.']['.__LINE__."] check");
}catch(Exception $e){
error_log('['.__FILE__.']['.__LINE__."] check");
error_log('Caught exception: '.$e->getMessage());
error_log('File: '.$e->getFile());
error_log('Line: '.$e->getLine());
error_log('Trace: '.$e->getTraceAsString());
}
error_log('['.__FILE__.']['.__LINE__."] session count: ".count($sessions));
Check for error supression operators (#) in your code and the code you are calling.
Try editing your error php.ini file to allow warnings and error codes to be displayed.
error_reporting = E_ALL | E_STRICT
This would be sufficient.

eval() and PHP errors

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.

Categories