Try except in PHP - php

How could I perform the equivalent to an open try:this except:pass in Python?
I have the following code:
$banana = true;
unserialize($banana);
And it returns the error:
Warning: array_keys() expects parameter 1 to be array, boolean given
Which is expected, as I fed it a boolean.
This is just an example; I am using unserialize(), but I'm not purposely feeding it booleans. I need it to work this way.

Since unserialize doesn't throw an exception, there is nothing to catch.
One of the workarounds is using the silence operator (#) and check whether the
outcome of the unserialize method equals false.
$foo = #unserialize($bar);
if ($foo === false && $bar !== 'b:0;') {
// Unserialize went wrong
}

set_error_handler(function ($errno, $errstr) {
throw new Exception($errstr, 0);
}, E_NOTICE);
try {
$result = unserialize($banana); // correct
} catch (Exception $e) {
$result = array(); // default value
}
restore_error_handler();
print_r($result);

Related

Check if call_user_func_array was executed succesfully

A function or method can be called dynamically using call_user_func_array. If the call itself fails, FALSE is returned. Also, call_user_func_array returns the return values from the function or method that is called.
So when the called function or method returns FALSE as well (for example, see SO example), that value would be recognised as a false positive.
How can one reliably check if the function or method call was executed succesfully by call_user_func_array?
EDIT: People tend to point out the existence of is_callable. But this is not about checking if a method exists before calling it, thus avoiding possible errors. Actually before doing call_user_func_array the function call and it's arguments and argument types are already verified using Reflection to avoid a Massive Assign attack.
The documentation mentions the FALSE return value, but I fail to see how it can be used to check if the call was succesful.
You can explicitly check whether an error occurred during the last call:
error_clear_last(); // since PHP 7, before that you'll need to store and
// compare the error state before and after the call
$result = call_user_func_array($foo, $bar);
if ($result === false && error_get_last()) {
echo 'Failed to call ', $foo;
}
The above is a generic check for any error, perhaps you want to inspect the last error in more detail. It'll look something like:
Array
(
[type] => 2
[message] => call_user_func_array() expects parameter 1 to be a valid callback, function 'foo' not found or invalid function name
[file] => /in/M8PrG
[line] => 3
)
You might want to check that the message matches something like 'call_user_func_array() expects parameter 1 to be a valid callback' and/or that the line it refers to is the line above. Note that especially checking the message may break between PHP versions.
The alternative is to check before whether your supposed callback is_callable.
I'd transform the boolean callable into one that is void but that throws an exception on error.
That way, you could catch the exception and you would know if false was returned by the call_user_func_array that only its call failed:
<?php
$booleanCallable = function (... $args): bool {
foreach ($args as $arg) {
echo "$arg \n";
};
return false;
};
$transformBooleanCallableToVoidThrowingException = function (callable $c): callable {
return function (... $args) use ($c): void {
if (false === $c(... $args)) {
throw new \RuntimeException("the call to the callable failed");
}
};
};
try {
$callable = $transformBooleanCallableToVoidThrowingException($booleanCallable);
$response = call_user_func_array($callable, [1, 2, 3]);
if (false === $response) {
throw new \RuntimeException("call_user_func_array failed");
}
} catch (\Exception $e) {
echo $e->getMessage();
}
This will output the provided arguments and an error message:
1
2
3
the call to the callable failed

how to catch hex2bin() warning

Came across this today, not sure how to solve it.
I want to catch an E_WARNING level error issued by hex2bin().
I thought I might be able to use a try()catch() exception method but it did not work.
try {
$foo = hex2bin($bar);
}
catch (Exception $e) {
die('Custom message');
}
The standard E_WARNING that is issued is, of course:
Warning: hex2bin(): Input string must be hexadecimal string
In this particular situation I do not want to use the standard methods to disable errors, such as:
error_reporting(-1);
error_reporting(E_ALL);
ini_set("display_errors", 1);
Nor do I want to suppress the error using a #hex2bin method.
I actually want to have a custom error displayed, but I just do not seem to be able to find a way to catch when hex2bin throws an error.
You can check the input value to verify that it is hex before passing it to the hex2bin method.
if (ctype_xdigit($bar) && strlen($bar) % 2 == 0) {
$foo = hex2bin($bar);
} else {
//display error here
}
Per the documentation, hex2bin returns:
the binary representation of the given data or FALSE on failure.
That means you can do something like this if you want to use it in a try/catch block:
try {
$foo = #hex2bin($bar);
if(false === $foo) {
throw new Exception("Invalid hexedecimal value.");
}
} catch(Exception $e) {
echo $e;
}
Yes, hex2bin is suppressed. You can remove the # if you set error_reporting to suppress warnings.
Alternatively, you can check the type of $foo with ctype_xdigit() prior to using hex2bin().

How to catch the error of file_get_contents() in php

How i can catch the error of the file_get_contents()?
I tried this :
if(!$contenido = file_get_contents($url))
{
$save=false;
}
It did not work
file_get_contents() returns FALSE on failure. You must check for that value with the === operator. If you wish to suppress the warning, you can use the # operator in front of file_get_contents().
$contenido = #file_get_contents($url);
if (contenido === FALSE) {
$save=FALSE;
}
From the file_get_contents() docs:
Warning
This function may return Boolean FALSE, but may also return a non-Boolean value which evaluates to FALSE. Please read the section on Booleans for more information. Use the === operator for testing the return value of this function.
In PHP 5.x you really can't. The best you can do is suppress the error using the dreaded # symbol. This is not considered good coding practice because you're turning off notices, but in this case there's no other option.
if(!$contenido = #file_get_contents($url))
You'll still get your return of false but no Warnings, etc.
As of php-7 you will be able to catch errors like that
On failure, file_get_contents() will return FALSE, but it will be accompanied by an error message. You can hide that error message, but still get returns FALSE, you need to use the '#' symbol before the function name.
Try this:
$url = "path/to/file";
$contents = #file_get_contents($url);
if ($contents !== FALSE) {
// TODO
}

How to prevent ob_start() output when an error occur?

Please, consider the following example:
template.php:
<?php
echo $vars['arr'];
echo " -------- ";
echo $vars['obj'];
?>
test.php:
<?php
$file = "template.php";
$vars = array( 'arr' => array(), 'obj' => new StdClass() );
var_dump( json_encode($vars) );
function loadFile($file, $vars)
{
try
{
if (is_array($vars) && !empty($vars)) {
extract($vars);
}
ob_start();
include $file;
return ob_get_clean();
}
catch (Exception $e)
{
return false;
}
}
loadFile($file, $vars);
?>
This code will output:
string(19) "{"arr":[],"obj":{}}"
PHP Catchable fatal error: Object of class stdClass could not be converted to string in template.php
The problem here is, in the template.php I am considering $vars to be an array() however 1 of the elements is an Object as you can see from the json output.
Adding a simple checking in the template to verify if the ekement is an array or not would solve the problem, however I would need to this to multiple elements, elements, so, not very good =) so, I trying to find a way to prevent the error in the moment of binding the template and $vars.
Thank you
simply turn error_reporting off while parsing:
$old_level = error_reporting(0); // no errors, preserve old error reporting level
ob_start();
include $file;
$content = ob_get_clean();
error_reporting($old_level); // reset error reporting level
return $content;
Note: This will only hide errors that aren't very critical.
In order to catch a Catchable Fatal Error, see this question: How can I catch a "catchable fatal error" on PHP type hinting?
You need to register an error handler using set_error_handler:
function handleError($errno, $errstr, $errfile, $errline) {
// handle error
// return true, so the normal php handler doesn't get called
return true;
}
set_error_handler('handleError');
If you want to integrate you handler cleanly into other code which also sets error_handlers, you might consider restoring the error handler afterwards using restore_error_handler
You might try checking to see if the values are an object first, and then using the PHP function to convert to an array.
Note, this section of your code:
if (is_array($vars) && !empty($vars)) {
extract($vars);
}
After that, if I'm reading your code correctly, you have a variable possibly called $vars that could be an object. So, you could do this:
if (is_object($vars)) {
$vars = get_object_vars($vars);
}
That should convert it to what you need. Of course, you may need to experiment a bit to make sure it fits your scenario. Thanks!
You can use __toString() method in your class to avoid the error. You can set the __toString() method with any value you need, maybe return an array.
http://www.php.net/manual/en/language.oop5.magic.php#object.tostring
Another option, is use array_walk :
function checkObj(&$vars){
if (is_object($vars)) {
$vars = get_object_vars($vars);
}
}
array_walk($vars, "checkObj");
Since you are using ob_start(), you can pass it a call-back that will check for any errors. It should even work with fatal errors. Inside your call-back use something like "error_get_last" to check for any error and just return false if it's not null, like so:
WARNING: I've not tested this code, but I use something similar myself.
<?php
$file = "template.php";
$vars = array( 'arr' => array(), 'obj' => new StdClass() );
var_dump( json_encode($vars) );
function loadFile($file, $vars)
{
try
{
if (is_array($vars) && !empty($vars)) {
extract($vars);
}
ob_start('errorHandler');
include $file;
return ob_get_clean();
}
catch (Exception $e)
{
return false;
}
}
function errorHandler($pBuffer)
{
$lastError = error_get_last();
// Uh-oh, an error has occurred.
if ($lastError !== NULL)
{
return FALSE;
}
// No problems.
return $pBuffer;
}
loadFile($file, $vars);
?>

Test if a regular expression is a valid one in PHP

I am writing a form validation class and wish to include regular expressions in the validation. Therefore, the regex provided isn't guaranteed to be valid.
How can I (efficiently) check that the regex is valid?
Use the pattern in your preg_* calls. If the function returns false there is likely a problem with your pattern. As far as I know this is the easiest way to check if a regex pattern is valid in PHP.
Here's an example specifying the right kind of boolean check:
$invalidPattern = 'i am not valid regex';
$subject = 'This is some text I am searching in';
if (#preg_match($invalidPattern, $subject) === false) {
// the regex failed and is likely invalid
}
When you have error reporting on, you can't get away with simply testing the boolean result. If the regex fails warnings are thrown (i.e. 'Warning: No ending delimiter xxx found'.)
What I find odd, is that the PHP documentation tells nothing about these thrown warnings.
Below is my solution for this problem, using try, catch.
//Enable all errors to be reported. E_WARNING is what we must catch, but I like to have all errors reported, always.
error_reporting(E_ALL);
ini_set('display_errors', 1);
//My error handler for handling exceptions.
set_error_handler(function($severity, $message, $file, $line)
{
if(!(error_reporting() & $severity))
{
return;
}
throw new ErrorException($message, $severity, $severity, $file, $line);
});
//Very long function name for example purpose.
function checkRegexOkWithoutNoticesOrExceptions($test)
{
try
{
preg_match($test, '');
return true;
}
catch(Exception $e)
{
return false;
}
}
You shouldn't be using # to silence all errors because it also silences fatal errors.
function isRegularExpression($string) {
set_error_handler(function() {}, E_WARNING);
$isRegularExpression = preg_match($string, "") !== FALSE;
restore_error_handler();
return isRegularExpression;
}
This only silences warnings for the preg_match call.
Anyone still looking at this question anno 2018, and is using php 7, should be using try/catch.
try {
preg_match($mypattern, '');
} catch (\Throwable $exception) {
// regex was invalid and more info is in $exception->getMessage()
}
PHP has progressed quite a bit since this question was first asked (and answered). You can now (PHP 5.2+) simply write the following to, not only test if the regular expression is valid, but to get the detailed error message if it's not:
if(#preg_match($pattern, '') === false){
echo error_get_last()["message"];
}
Placed in a function
/**
* Return an error message if the given pattern argument or its underlying regular expression
* are not syntactically valid. Otherwise (if they are valid), NULL is returned.
*
* #param $pattern
*
* #return string|null
*/
function regexHasErrors($pattern): ?string
{
if(#preg_match($pattern, '') === false){
//Silence the error by using a #
return str_replace("preg_match(): ", "", error_get_last()["message"]);
//Make it prettier by removing the function name prefix
}
return NULL;
}
Demo
This is my solution using the upcoming warning if something is wrong with the expression:
function isRegEx($test)
{
$notThisLine = error_get_last();
$notThisLine = isset($notThisLine['line']) ? $notThisLine['line'] + 0 : 0;
while (($lines = rand(1, 100)) == $notThisLine);
eval(
str_repeat("\n", $lines) .
'#preg_match(\'' . addslashes($test) . '\', \'\');'
);
$check = error_get_last();
$check = isset($check['line']) ? $check['line'] + 0 : 0;
return $check == $notThisLine;
}

Categories