ErrorHandling php - php

I wrote an error handler to handle different kind of errors in php(even parse errors etc.).
Question:
As I now can detect an errortype(the constant) it is necessary to identify which errors I should allow or not and in which case do a gentle shutdown.
If I look at http://www.php.net/manual/en/errorfunc.constants.php I see all the different constants for different kind of errors.
The question is:
1)Is there some kind of relation between these constants for error handling. Lets say above a level I know that I dont want to print the error on my screen etc? Or do I have to set this manually for every error-constant(seems like it)?
2) How to provoke every error on the screen example without using trigger_error() or user_error()? Is there some kind of list to produce those errors and which ones I can produce with code?
Cheers and thanks a lot for answers.

You can group all the notice, warning and error constants together like this:
notice : 8 + 1024 + 2048 + 8192 + 16384 = 27656 0x6c08
warning: 2 + 32 + 128 + 512 = 674 0x2a2
error : 1 + 16 + 64 + 256 + 4096 = 4433 0x1151
You could also add them by explicitly using the constant names, e.g. E_ERROR, etc.
So:
$is_notice = $code & 0x6c08 != 0;
$is_warning = $code & 0x2a2 != 0;
$is_error = $code & 0x1151 != 0;
As for your second question, are you looking for code that would trigger the above distinct levels?
$f = fopen($a, 'r'); // notice + warning
$f->read(); // error
include 'script_with_parse_error.php'; // e_parse
function test(Iterator $i) { }
test(123); // e_recoverable_error
function modify(&$i) { ++$i; }
modify(123); // e_strict
$x = split(',', ''); // e_deprecated
The E_USER events can only be generated with trigger_error() of course.

Related

PHP8 - Fatal User Error: Unsupported operand types: array & int

I am trying to fix some PHP8 errors in forum software, need assistance with this.
Error thrown is Fatal User Error: Unsupported operand types: array & int on these lines.
$forumperms & $this->registry->bf_ugp_forumpermissions['cangetattachment'],
$forumperms & $this->registry->bf_ugp_forumpermissions['canseethumbnails']
For reference the whole code section below.
/*
* Processes any attachments to this post.
*/
function process_attachments()
{
global $show;
$forumperms = fetch_permissions($this->thread['forumid']);
require_once(DIR . '/packages/vbattach/attach.php');
$attach = new vB_Attach_Display_Content($this->registry, 'vBForum_Post');
if ($this->post['allattachments'])
{
foreach($this->post['allattachments'] AS $attachmentid => $info)
{
if (!$this->post['attachments'][$attachmentid])
{
unset($this->post['allattachments'][$attachmentid]);
}
}
$attach->process_attachments(
$this->post,
$this->post['allattachments'],
(THIS_SCRIPT == 'external'),
can_moderate($this->forum['forumid'], 'canmoderateattachments'),
$forumperms & $this->registry->bf_ugp_forumpermissions['cangetattachment'], //ERROR
$forumperms & $this->registry->bf_ugp_forumpermissions['canseethumbnails'] //ERROR
);
}
else
{
$show['attachments'] = $show['moderatedattachment'] = $show['thumbnailattachment'] = $show['otherattachment'] = false;
$show['imageattachment'] = $show['imageattachmentlink'] = false;
}
}
Have not tried anything yet trying to work out how those lines must be changed for PHP8 compatability.
Unsupported operand type errors occurred when some kind of mathematical calculation was involved in some part of the code and one of the operands could not be automatically converted to the other type. In your case, the calculation seems to have one operand as int and the other one being an array and an array could not be automatically converted to int, hence the issue.
In your code, the 2 lines that you have marked as the error-causing lines are not the actual point of error. Starting from PHP 8 strict typings have been introduced almost everywhere in PHP core functions so legacy code will break. You can read more here
I think you need to check for vB_Attach_Display_Content::process_attachments method for any mathematical calculations. In the given code block you are passing different parameters to that function and maybe those parameters are not strictly typed. Hence the function is accepting anything.

Google Cloud Vision - PHP Error occurred during parsing

Im using Vision API Client Library for PHP.
This is my code:
use Google\Cloud\Vision\V1\ImageAnnotatorClient;
putenv("GOOGLE_APPLICATION_CREDENTIALS=/json.json");
$imageAnnotator = new ImageAnnotatorClient();
$fileName = 'textinjpeg.jpg';
$image = file_get_contents($fileName);
$response = $imageAnnotator->labelDetection($image);
$labels = $response->getLabelAnnotations();
if ($labels) {
echo("Labels:" . PHP_EOL);
foreach ($labels as $label) {
echo($label->getDescription() . PHP_EOL);
}
} else {
echo('No label found' . PHP_EOL);
}
And I receive this error:
Error occurred during parsing: Fail to push limit. (0)
/srv/www/site.ru/htdocs/vendor/google/protobuf/src/Google/Protobuf/Internal/CodedInputStream.php:345
#0: Google\Protobuf\Internal\CodedInputStream->pushLimit(integer)
/srv/www/site.ru/htdocs/vendor/google/protobuf/src/Google/Protobuf/Internal/CodedInputStream.php:368
#1: Google\Protobuf\Internal\CodedInputStream->incrementRecursionDepthAndPushLimit(integer, integer, integer)
....
....
....
#15: Google\Cloud\Vision\V1\ImageAnnotatorClient->labelDetection(string)
/srv/www/site.ru/htdocs/local/php_interface/GoogleCloud.php:41
This is the place, where Exception goes from:
public function pushLimit($byte_limit)
{
// Current position relative to the beginning of the stream.
$current_position = $this->current();
$old_limit = $this->current_limit;
// security: byte_limit is possibly evil, so check for negative values
// and overflow.
if ($byte_limit >= 0 &&
$byte_limit <= PHP_INT_MAX - $current_position &&
$byte_limit <= $this->current_limit - $current_position) {
$this->current_limit = $current_position + $byte_limit;
$this->recomputeBufferLimits();
} else {
throw new GPBDecodeException("Fail to push limit.");
}
return $old_limit;
}
$byte_limit <= $this->current_limit - $current_position is true
Should I increase current_position? And if I should, how can i do it? Change something on server or in PHP config?
It's a crazy thing to do!
The error "Fail to push limit" appears from time to time in forums. Various ideas are given there as to where the problem could lie. One cause could be when the source code is composed on the local PC via Composer and then transferred to the server via (S)FTP. The FTP programme decides on the basis of the file extension whether it saves the data on the server in ASCII or binary format.
In vendor/google/protobuf/src/Google/Protobuf/ there are various generated files that have a .php extension but are actually BINARY! (if you open the file, you can see it immediately, e.g. : vendor/google/protobuf/src/GPBMetadata/Google/Protobuf/Any.php)
The solution to transfer these files explicitly via binary to the server worked in my case! If in doubt, transfer the complete module from Google/protobuf as a binary...
You mentioned that $byte_limit <= $this->current_limit - $current_position is true, so either $byte_limit >= 0 or $byte_limit <= PHP_INT_MAX - $current_position are false.
If $byte_limit <= PHP_INT_MAX - $current_position is false, then increasing $current_position, won't turn it true. If you want to tweak the values, so the expression get evaluated as true, you would need to increase the value of PHP_INT_MAX instead.
If $byte_limit >= 0 is false, then modifying $current_limit won't avoid the exception.
Either way, it seems that the error is an issue with the protobuf php library, so I'd recommend you to report the issue there, rather than try to modify the values directly.
mbstring.func_overload was 2
This was the reason of error
Changed to 0 and it worked

php constants math operation

Currently i am learning php. Here I have a confusion this is my php code
class OBJECT_ENUM
{
const USER = 10;
const POST = 30;
const SECURE_REQUEST = 40;
}
class OPERATION_ENUM
{
const INSERT_USER = OBJECT_ENUM::USER + 1; // <- here it gives an error
const SEND_MAIL = OBJECT_ENUM::USER + 2;
const LIKE_POST = OBJECT_ENUM::POST + 1;
const INSERT_POST = OBJECT_ENUM::POST + 2;
const ENCRYPT = OBJECT_ENUM::SECURE_REQUEST + 1;
}
error message:
Parse error: syntax error, unexpected '+', expecting ',' or ';' in /var/www/workspace/6thAssignment/include/tempCall.php on line 15
I just don't understand why this error occurs.?? cany anybody explain me.??
Thank you in advance
ORIGINAL ANSWER:
As you can see in http://www.php.net/manual/en/language.oop5.constants.php:
The value must be a constant expression, not (for example) a
variable, a property, a result of a mathematical operation, or a
function call.
UPDATED:
From PHP version 5.6 now it is possible to use expressions in constants.
I think you can not do mathematical operation to be assigned to a const variable. Try changing
const INSERT_USER = OBJECT_ENUM::USER + 1;
to
$INSERT_USER = OBJECT_ENUM::USER + 1;
I believe expressions (like $a + 1) are not allowed in constants definitions, so there is why you are getting that error.
At the moment this is not allowed by PHP. There was an RFC (Request for comments) to get this added to the language:
https://wiki.php.net/rfc/const_scalar_expressions
however this was withdrawn as the author of the RFC has left the internals development team. So I suspect this may not happen any time soon but that's not to say that this won't come back in some form or another at a later date.

In PHP, how can I detect that input vars were truncated due to max_input_vars being exceeded?

I know that an E_WARNING is generated by PHP
PHP Warning: Unknown: Input variables exceeded 1000
But how can I detect this in my script?
A "close enough" method would be to check if( count($_POST, COUNT_RECURSIVE) == ini_get("max_input_vars"))
This will cause a false positive if the number of POST vars happens to be exactly on the limit, but considering the default limit is 1000 it's unlikely to ever be a concern.
count($_POST, COUNT_RECURSIVE) is not accurate because it counts all nodes in the array tree whereas input_vars are only the terminal nodes. For example, $_POST['a']['b'] = 'c' has 1 input_var but using COUNT_RECURSIVE will return 3.
php://input cannot be used with enctype="multipart/form-data". http://php.net/manual/en/wrappers.php.php
Since this issue only arises with PHP >= 5.3.9, we can use anonymous functions. The following recursively counts the terminals in an array.
function count_terminals($a) {
return is_array($a)
? array_reduce($a, function($carry, $item) {return $carry + count_terminals($item);}, 0)
: 1;
}
What works for me is this. Firstly, I put this at the top of my script/handler/front controller. This is where the error will be saved (or $e0 will be null, which is OK).
$e0 = error_get_last();
Then I run a bunch of other processing, bootstrapping my application, registering plugins, establishing sessions, checking database state - lots of things - that I can accomplish regardless of exceeding this condition.. Then I check this $e0 state. If it's not null, we have an error so I bail out (assume that App is a big class with lots of your magic in it)
if (null != $e0) {
ob_end_clean(); // Purge the outputted Warning
App::bail($e0); // Spew the warning in a friendly way
}
Tweak and tune error handlers for your own state.
Registering an error handler won't catch this condition because it exists before your error handler is registered.
Checking input var count to equal the maximum is not reliable.
The above $e0 will be an array, with type => 8, and line => 0; the message will explicitly mention input_vars so you could regex match to create a very narrow condition and ensure positive identification of the specific case.
Also note, according to the PHP specs this is a Warning not an Error.
function checkMaxInputVars()
{
$max_input_vars = ini_get('max_input_vars');
# Value of the configuration option as a string, or an empty string for null values, or FALSE if the configuration option doesn't exist
if($max_input_vars == FALSE)
return FALSE;
$php_input = substr_count(file_get_contents('php://input'), '&');
$post = count($_POST, COUNT_RECURSIVE);
echo $php_input, $post, $max_input_vars;
return $php_input > $post;
}
echo checkMaxInputVars() ? 'POST has been truncated.': 'POST is not truncated.';
Call error_get_last() as soon as possible in your script (before you have a chance to cause errors, as they will obscure this one.) In my testing, the max_input_vars warning will be there if applicable.
Here is my test script with max_input_vars set to 100:
<?php
if (($error = error_get_last()) !== null) {
echo 'got error:';
var_dump($error);
return;
}
unset($error);
if (isset($_POST['0'])) {
echo 'Got ',count($_POST),' vars';
return;
}
?>
<form method="post">
<?php
for ($i = 0; $i < 200; $i++) {
echo '<input name="',$i,'" value="foo" type="hidden">';
}
?>
<input type="submit">
</form>
Output when var limit is hit:
got error:
array
'type' => int 2
'message' => string 'Unknown: Input variables exceeded 100. To increase the limit change max_input_vars in php.ini.' (length=94)
'file' => string 'Unknown' (length=7)
'line' => int 0
Tested on Ubuntu with PHP 5.3.10 and Apache 2.2.22.
I would be hesitant to check explicitly for this error string, for stability (they could change it) and general PHP good practice. I prefer to turn all PHP errors into exceptions, like this (separate subclasses may be overkill, but I like this example because it allows # error suppression.) It would be a little different coming from error_get_last() but should be pretty easy to adapt.
I don't know if there are other pre-execution errors that could get caught by this method.
What about something like that:
$num_vars = count( explode( '###', http_build_query($array, '', '###') ) );
You can repeat it both for $_POST, $_GET, $_COOKIE, whatever.
Still cant be considered 100% accurate, but I guess it get pretty close to it.

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