try/catch doesn't work in PHP - php

Why am I getting this error?
Warning: file_get_contents(http://www.example.com) [function.file-get-contents]: failed to open stream: HTTP request failed! in C:\xampp\htdocs\test.php on line 22
Fatal error: Maximum execution time of 30 seconds exceeded in C:\xampp\htdocs\test.php on line 22
Here is the code:
try {
$sgs = file_get_contents("http://www.example.com");
}
catch (Exception $e) {
echo '123';
}
echo '467';
Aren't try\catch supposed to continue the excecution of the code? Or maybe there is some different way to do it?

try... catch is more for null object exceptions and manually thrown exceptions. It really isn't the same paradigm as you might see in Java. Warnings are almost deceptive in the fact that they will specifically ignore try...catch blocks.
To suppress a warning, prefix the method call (or array access) with an #.
$a = array();
$b = #$a[ 1 ]; // array key does not exist, but there is no error.
$foo = #file_get_contents( "http://somewhere.com" );
if( FALSE === $foo ){
// you may want to read on === there;s a lot to cover here.
// read has failed.
}
Oh, and it is best to view Fatal Exceptions are also completely uncatchable. Some of them can be caught in some circumstances, but really, you want to fix fatal errors, you don't want to handle them.

catch cannot catch a fatal error.
Just search for timeout in the manual for file_get_contents, there are several solutions listed there, here is one:
$ctx = stream_context_create(array(
'http' => array(
'timeout' => 1
)
)
);
file_get_contents("http://example.com/", 0, $ctx);

try..catch will only catch exceptions. A fatal error is not an exception.
If PHP exceeds its maximum execution time, there's nothing you can do. PHP simply stops dead. It's the same if PHP runs out of memory: Nothing you can do to fix it after it's happened.
In other words, exceptions are errors you can potentially recover from. Fatal errors are, well, fatal and unrecoverable.

In PHP a fatal error will halt execution of the script. There are ways to do something when you run into them, but the idea of a fatal error is that it should not be caught.

Here are some good details: http://pc-technic.blogspot.com/2010/10/php-filegetcontents-exception-handling.html
Basically change your code to do the following:
try {
#$sgs = file_get_contents("http://www.example.com");
if ($sgs == FALSE)
{
// throw the exception or just deal with it
}
} catch (Exception $e) {
echo '123';
}
echo '467';
Note the use of the '#' symbol. This tells PHP to ignore errors raised by that particular piece of code. Exception handling in PHP is very different than java/c# due to the "after the fact" nature of it.

Fatal errors in PHP are not caught. Error handling and Exception handling are two different things. However if you are hell bent on handling fatal errors as exception, you will need to set up your own error handler and direct all errors to it, make your error handler throw exceptions and you can then catch them.

file_get_contents doesn't throw exception (and thus errors and warnings it throws aren't catchable). You are getting PHP warning and then fatal error, which explains you why the script doesn't continue - it exceeded limit for loading scripts set in php.ini.

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"?

Code in try block continues executing after exception?

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)

php - try/catch gearman not catching timeout warning

I'm using the php gearman client and I'm trying to catch/ignore any errors in the event the gearman server is offline:
try {
$gearman = new GearmanClient();
$gearman->addServer('apps-1');
$gearman->setTimeout(4000);
$result = $gearman->doNormal("function", "params");
} catch (Exception $e) {}
However, this is still outputting the following error message:
Warning: GearmanClient::doNormal(): _client_do(GEARMAN_TIMEOUT) occured during gearman_client_run_tasks() -> libgearman/client.cc:154
I know the error message is just a warning not a fatal error but I was hoping the try/catch would suppress it. Anyone know of a way around this? Putting an # symbol just before $gearman->doNormal() does suppress the error however I don't know if thats the politically correct way of doing it.
Can someone help me out?
That is due to implementation. In PHP errors do not raise exceptions. If you want your program to be notified when a timeout occurs you have to manually inject into the errorhandler using set_error_handler.
$errorHandler = set_error_handler(
function($errorNumer, $errorString) {
//possibly handle error here
}
);
$gearman = new GearmanClient();
$gearman->addServer('apps-1');
$gearman->setTimeout(4000);
$result = $gearman->doNormal("function", "params");
if (isset($errorHandler)) {
set_error_handle($errorHandler);
}

includes many php-files in one pgm and catch errors

i call an php pgm per cronjob at different times.
the pgm includes many php-files.
each file sends or gets data from partners.
How can i handle errors in one includes pgm.
at the time, one ftp-connection in an included pgm fails so the complete script crushes.
how can i handle this ?
You should wrap code, which is possible to crash, into try/catch construction. This will throw exeption, but the script will continue to work. More here.
Need to know more about you code inorder to give you definite answer.
In general php errors isn't catchable unless you define your own error handler from which you throw exceptions your self. Using the code below makes most runtime errors catchable (as long as they arent considered fatal)
error_reporing(E_ALL);
set_error_handler(function($errno, $errstr, $errfile, $errline) {
if($errno == E_STRICT || $errno == E_DEPRECATED) {
return true;
}
throw new RuntimeException('Triggered error (code '.$errno.') with message "'.$errstr.'"');
});
Btw, You could also define your own exception handler to display triggered errors with a full stack trace when an exception isn't catched.
Notice! I would not suggest that you add this code to a production website without rigorous testing first, making sure everything still works as expected.
Edit:
I have no idea what your code looks like, but I guess you can do something like:
require 'error-handler.php'; // where you have your error handler (the code seen above)
$files_to_include = array(
'some-file.php',
'some-other-file.php',
...
);
foreach($files_to_include as $file) {
try {
include $file;
}
catch(Exception $e) {
echo "$file failed\nMessage: ".$e->getMessage()."\nTrace:\n".$e->getTraceAsString();
}
}

How can I get php to return 500 upon encountering a fatal exception?

PHP fatal errors come back as status code 200 to the HTTP client. How can I make it return a status code 500 (Internal server error)?
header("HTTP/1.1 500 Internal Server Error");
This is exactly the problem I had yesterday and I found solution as follows:
1) first of all, you need to catch PHP fatal errors, which is error type E_ERROR. when this error occurs, script will be stored the error and terminate execution. you can get the stored error by calling function error_get_last().
2) before script terminated, a callback function register_shutdown_function() will always be called. so you need to register a error handler by this function to do what you want, in this case, return header 500 and a customized internal error page (optional).
function my_error_handler()
{
$last_error = error_get_last();
if ($last_error && $last_error['type']==E_ERROR)
{
header("HTTP/1.1 500 Internal Server Error");
echo '...';//html for 500 page
}
}
register_shutdown_function('my_error_handler');
Note: if you want to catch custom error type, which start with E_USER*, you can use function set_error_handler() to register error handler and trigger error by function trigger_error, however, this error handler can not handle E_ERROR error type. see explanation on php.net about error handler
Standard PHP configuration does return 500 when error occurs! Just make sure that your display_errors = off. You can simulate it with:
ini_set('display_errors', 0);
noFunction();
On production display_errors directive is off by default.
I have used "set_exception_handler" to handle uncaught exceptions.
function handleException($ex) {
error_log("Uncaught exception class=" . get_class($ex) . " message=" . $ex->getMessage() . " line=" . $ex->getLine());
ob_end_clean(); # try to purge content sent so far
header('HTTP/1.1 500 Internal Server Error');
echo 'Internal error';
}
set_exception_handler('handleException');
Since PHP >= 5.4
http_response_code(500);
echo json_encode( [ 'success' => false , 'message' => 'Crazy thing just happened!' ]);
exit();
Please set the httpCode before echo.
It is not possible to handle PHP E_ERROR in any way according to the PHP documentation:
http://www.php.net/manual/en/function.set-error-handler.php
Nor is is possible to handle "E_PARSE, E_CORE_ERROR, E_CORE_WARNING, E_COMPILE_ERROR, E_COMPILE_WARNING, and most of E_STRICT" according to that link.
You CAN provide a handler for the other error, warning, and notices including E_USER_ERROR, but that's really not as useful as it sounds since this error only gets thrown intentionally by the programmer with trigger_error().
And of course you can catch any Exception (even the ones thrown by the native PHP functions).
I agree that this is a problem. Servers should NOT return 200 OK when application code crashes and burns.
You can use php error handling
http://www.w3schools.com/php/php_error.asp
You would have to catch the thrown error using try/catch and then use that catch block to send a header() with the 500 error.
try {
...badcode...
throw new Exception('error');
} catch (Exception $e) {
header("Status: 500 Server Error");
var_dump($e->getMessage());
}
If the fatal exception is not surrounded by try {} catch blocks then you must register a global handler and use register_shutdown_function() to check for an error at script end.
Never forget to set header("HTTP/1.1 200 OK", true, 200); as the last line of any execution path:
//first things first:
header("HTTP/1.1 500 Internal Server Error", true, 500);
//Application code, includes, requires, etc. [...]
//somewhere something happens
//die();
throw new Exception("Uncaught exception!");
//last things last, only reached if code execution was not stopped by uncaught exception or some fatal error
header("HTTP/1.1 200 OK", true, 200);
In PHP 5.4 you can replace the header function above with the much better http_response_code(200) or http_response_code(500).
The hard thing when dealing with fatal errors (compile errors, for example a missing semicolon) is that the script won't be executed, so it won't help to set the status code in that script. However, when you include or require a script, the calling script will be executed, regardless of errors in the included script. With this, I come to this solution:
rock-solid-script.php:
// minimize changes to this script to keep it rock-solid
http_response_code(500); // PHP >= 5.4
require_once("script-i-want-to-guard-for-errors.php");
script-i-want-to-guard-for-errors.php:
// do all the processsing
// don't produce any output
// you might want to use output buffering
http_response_code(200); // PHP >= 5.4
// here you can produce the output
Direct your call to the rock-solid-script.php and you're ready to go.
I would have liked it better to set the default status code to 500 in .htaccess. That seems more elegant to me but I can't find a way to pull it off. I tried the RewriteRule R-flag, but this prevents execution of php altogether, so that's no use.

Categories