Imagick will not catch Notices or Warnings - php

When a Notice or Warning occurs, the image fails. However, I am unable to catch the notice or warning.
<?php
$image = new Imagick($resource);
try {
$image->setImageCompressionQuality("Should be a Number Here not String");
}
catch ( ImagickException $e ) {
echo "This is a catch"; // should catch here but nope!
}
?>
The code above should catch because of the string passed when should be INT. The image fails but catch does not execute. I still get this message:
Notice: Use of undefined constant Should be a Number Here not String - assumed 'd' in /var/www/class.php on line 15
Warning: Imagick::setimagecompressionquality() expects parameter 1 to be long, string given in /var/www/class.php on line 15
I also tried ( Exception $e )

As said above, you should also check return value of $image->setImageCompressionQuality and can hide notices with #.
But also you can convert notices in your code to exceptions like described in this post. It is interesting solution, but i dont recommend to follow it. Checking correctness is better.

Because the method doesn't throw an exception in case on invalid input. You should do something like:
$result = #$image->setImageCompressionQuality("Should be a Number Here not String");
if (!$result) {
throw new \Exception('Operation has failed');
}

Related

Prevent PHP from echoing if exception occured

I noticed that PHP's echo successfully prints strings even if somewhere in the script an error is thrown and not handled. For example:
error_reporting(E_ALL);
ini_set('display_errors', 1);
echo "started";
throw new Exception("big error");
echo "done";
prints "started", even though an error occured. The status code is 500 indeed, but I don't think displaying partial results works for all cases.
Using ob_start() and ob_get_contents() offers some flexibility, but I expected that PHP offers a switch to set displaying to none if error occured. Does this switch exist?
when you say throw new Exception() this means you are saying move the program control to caller and don't execute the further statements after this throw statement.
thanks to: Difference between "throw new Exception" and "new Exception"?
echo "started"; // <- This will occurs
throw new Exception("big error"); // <- And here the Exception will be thrown
echo "done"; // <- therefore, this line won't be reached
One way to solve this would be using a variable to store what you want to echo and only echo it if there are no uncaught exceptions
$echoStr = "";
$echoStr .="started";
throw new Exception("big error");
$echoStr .="done";
echo $echoStr;
Echo instantly send the data to the server (at least in this code it does) and no longer can be affected by what happens next. It's generally bad practice to work like that (eg: after an echo you can no longer change headers like a redirect, which can be very inconfinient), better would be to stored everything in a variable and output it when you want:
$output = "started";
throw new Exception("big error");
$output.= "done";
echo $output; // or if in a function, return instead of echo

PHP Exception within a try catch block not being caught unless the print function is called?

TL;DR:
My PHP-Exception only get caught, if i use a print-statement in the catch-block.
I am seeing some strange behaviour with a PHP try catch block. My PHP version is 7.0.14.
Here is a method that I've defined which simply explodes a string and stores the result in memory. If the exploded string doesn't have the expected amount of constituent parts, an Exception will be thrown.
public function importString($string) {
// separate the string with the delimiter.
$separated = explode($this->delimiter, $string);
// If there is a different number of segments to specified id's throw exception.
if (count($separated) != count($this->ids)) {
$class = static::class;
throw new \Exception("Invalid Pseudo ID '{$string}' for type '{$class}'.");
}
//store separated id strings
foreach($separated as $i => $item) {
$this->data[$this->ids[$i]] = $item;
}
}
This method is contained within a class called PseudoId from which the two classes below inherit.
Below is the code that calls the method defined above; the majority of the time I expect the imported string to be constructed from three different values (e.g. "one_two_three") but on occasion there can be strings with four components (e.g. "one_two_three_four"), therefore I first attempt to import the string into the object that expects the string to have three components, falling back to the object that expects four.
try {
//Added later for debug
throw new \Exception("error");
$productInfo = new PseudoIdFeedProduct(0, 0, 0);
$productInfo->importString($data['productId']);
} catch (\Exception $e) {
//Added later for debug
print "caught.";
$productInfo = new PseudoIdFeedProductIndividualBilling(0, 0, 0, 0);
$productInfo->importString($data['productId']);
}
// Added for debug
var_dump($productInfo);
Now here's the weird part: When passing in a string with four components, the Exception thrown in PseudoIdFeedProduct::importString() isn't caught. So for the sake of debugging I added an Exception to the top of the try block, calling the print function in the catch block as a check and it worked. So I removed the exception at the top of the try block, and it still worked. Slightly baffled, I removed the call to the print function and it stopped working...
Whether the thrown Exception is caught depends on whether the print function is called in the catch block, I added and removed it a couple of times to double check.
Clearly I don't want to have to call the print function here, what am I doing wrong here and how can I get this to work as expected?

Handling expection catch block - xdebug

I am new to exceptions, so I am trying to learn it.
The first thing what I've tired now is to copy paste the code from the php.net doc:
function inverse($x) {
if (!$x) {
throw new Exception('Division by zero.');
}
return 1 / $x;
}
try {
echo inverse(5) . "\n";
echo inverse(0) . "\n";
} catch (Exception $e) {
echo 'Caught exception: ', $e->getMessage(), "\n";
}
// Continue execution
echo "Hello World\n";
Document says, output will be:
0.2
Caught exception: Division by zero.
Hello World
I expected this output, because as I know this is the point of the exception handling that not show that ugly big error code with trace.
Instead of this output I've get:
0.2
( ! ) Exception: Division by zero. in D:\Apache\htdocs\SO\index.php on line 10
Call Stack
# Time Memory Function Location
1 0.0005 363040 {main}( ) ...\index.php:0
2 0.0009 363584 inverse( ) ...\index.php:17
Caught exception: Division by zero. Hello World
Why do am I getting this error? I am using xDebug, could that be the reason of this? If yes, what should I do programmaticaly to not get this error but what php document wrote.
UPDATE:
If I am adding the xdebug_disable(); before the try it works normal, and get the expected output.
My original question turns to: how to handle exception and not show this ugly error when xdebug enabled?
If you dont want permanently you can uninstall that extension.
To disable specific areas, check the extenstion extension_loaded, and disable like this.
if (extension_loaded('xdebug')) {
xdebug_disable();
}

Can missing delimiter errors in a preg/PHP regexp be read programmatically?

I have a need to detect whether a regular expression is valid, so that invalid ones can be gracefully rejected in a user interface. On Stack Overflow there is a clever abomination to do this with another regular expression, which I plan to strenuously avoid.
There is a much simpler approach of running a match and checking for errors, which returns the correct boolean result, but it would be interesting to get the failure reason/message as well:
// The error is that preg delimiters are missing
$testRegex = 'Location: (.+)';
// This bit is fine
$result = preg_match($testRegex, ''); // returns false i.e. failure
$valid = is_int($result); // false, i.e. the regex is invalid
// Returns PREG_NO_ERROR, which means no error occured
echo preg_last_error() . "\n";
If I run this I correctly get:
PHP Warning: preg_match(): Delimiter must not be alphanumeric or backslash in ... on line ...
However, the output of the error function is 0, which is equal to PREG_NO_ERROR. I would have thought this would return a non-zero error code -- and it would be even better if I can get my hands on a clean version of the warning message.
It is of course possible that this is not generally available (i.e. is just available to the PHP engine for the purposes of printing the warning). I am running 5.5.3-1ubuntu2.6 (cli).
This should work for you:
Here I just turn on output buffering with ob_start(). Then I capture the last error with error_get_last(). Then I end the output buffering with ob_end_clean(). After this you can check if the array is empty and if not an error occurred.
ob_start();
$result = preg_match(".*", "Location: xy");
$error = error_get_last();
ob_end_clean();
if(!empty($error))
echo "<b>Error:</b> " . $error["message"];
else
echo "no error found!";
output:
Error: preg_match(): No ending delimiter '.' found
EDIT:
If you want you can create your own error handler, which basically just throws an Exception for each error which you would normally get.
Then you can put your code into a try - catch block and catch the exception.
set_error_handler(function($errno, $errstr, $errfile, $errline, array $errcontext) {
// error was suppressed with the #-operator
if (0 === error_reporting()) {
return false;
}
throw new ErrorException($errstr, 0, $errno, $errfile, $errline);
});
try {
$result = preg_match(".*", "Location: xy");
} catch(Exception $e) {
echo "<b>Error:</b> " . $e->getMessage();
}
The code for the error handler is from Philippe Gerber in this answer
Maybe you could use error_get_last() to get a little bit more information.
Array
(
[type] => 2
[message] => preg_match(): Delimiter must not be alphanumeric or backslash
[file] => /Users/ivan/Desktop/test.php
[line] => 6
)
The type is E_WARNING and you can safely assume the function name string from the message part, since it will always be in the same format.
You can then do
$lastError = error_get_last()['message']; // php 5.5 expression
if(strpos($lastError, 'preg_match(): ') === 0){
$error = substr($lastError, 14);
}
And $error will be var_dump'ed to
string(47) "Delimiter must not be alphanumeric or backslash"
Or a null
Also, in response to another answer, you can surpress warnings by using #preg_match(...) so you don't have to handle output buffers yourself. error_get_last() will still catch the error.

Throwing errors from its "correct" source

I hope the title isn't too confusing, I'll try to explain better below.
Suppose I have a function in a separate file, functions.php:
function divide($num1, $num2) {
if ($num1 == 0 || $num2 == 0) {
trigger_error("Cannot divide by 0", E_USER_ERROR);
} else {
return ($num1 / $num2);
}
}
And another file that calls it:
include "functions.php";
echo divide(10, 0);
My error is
Fatal error: Cannot divide by 0 in
C:\Users\Derek\Desktop\projects\functions.php on line 5
My question is, how do I make that error instead point to the location of the error in the main code, so I instead get:
Fatal error: Cannot divide by 0 in
C:\Users\Derek\Desktop\projects\main.php on line 3
The particular reason I want this is because I have a function called load_class that simply finds a PHP file and instantiates the object inside, but if given an incorrect file name, it reports an error from inside load_class, which is technically true, but it's not particularly helpful if I don't remember where I called load_class in the first place. I would like the error to point to the file that called load_class incorrectly.
Also, I would like to write a function error() (something like below) that when given a message as a parameter would throw more "meaningful" error messages, but when done that way, the error always says it comes from error(), not from where the error actually came from!
For example, in an error.php:
/**
* error()
*
* Throws an error of a certain type
*
* #param string $type The type of error. "Fatal", "warning," or "notice"
* #param string $message A description of the error
* #return void
*/
function error($type, $message) {
switch (strtolower($type)) {
case 'fatal':
trigger_error($message, E_USER_ERROR);
break;
case 'notice':
trigger_error($message, E_USER_NOTICE);
default:
trigger_error($message, E_USER_WARNING);
break;
}
}
And in an index.php
error("fatal", "A sample warning!");
My error given is:
Fatal error: A sample warning! in
C:\Users\Derek\Desktop\projects\synthesis\sys\Error.php on line 45
But the error didn't occur in error.php, it happened in index.php! How can I make it show where it really came from?
The debug_backtrace function allows you to obtain the stacktrace as an array. You can pick the original location from there.
Next to that you need to slip into the error message to make this look-alike. Example:
function divide($num1, $num2) {
if ($num1 == 0 || $num2 == 0) {
trigger_error_original("Cannot divide by 0", E_USER_ERROR);
} else {
return ($num1 / $num2);
}
}
function trigger_error_original($message, $type) {
$trace = debug_backtrace(FALSE);
list($location) = array_slice($trace, 1, 1) + array('file' => 'unknown', 'line' => 'unknown');
$message .= sprintf(" in %s on line %d\nTriggered", $location['file'], $location['line']);
trigger_error($message, $type);
}
divide(1, 0);
The error message than shows something like:
> php test-pad.php
Fatal error: Cannot divide by 0 in test-pad.php on line 18
Triggered in test-pad.php on line 15
The downside of this is, that you need to change your code to have this "feature". If you need this for debugging your own code, it's much better that you enable backtraces in your logs. The Xdebug extension does this for you, or you can write your own error handler that takes care of that.
See as well the related question Caller function in PHP 5?. I used array_slice so that you could create an additional parameter to define the number of steps you want to go "up" in the backtrace.
Use debug_backtrace(), and debug_print_backtrace() for a full call stack. These are especially effective when using Xdebug, which will override the function to colorize the output.
I have this same problem...
#1: while 10/0 = ERROR, 0/10 = 0 is perfectly legal, you shouldn't have an exception for that.
#2: when you include a file, it effectively becomes part of this new file, so perhaps you might have to toy a little bit with things like __FILE__ and see if you can make it point it to the file before it gets included in the other file..
You can use xdebug - it will show you the stacktrace or you can register your own error handndler and display the stacktrace. Just check the example in php.net for set_error_handler().
Maybe exceptions are better to use in your case. You get the full stacktrace and can locate where the function was called without relying on some tricky code :)

Categories