Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
109 views
in Technique[技术] by (71.8m points)

Why does PHP error handler run out of order?

I'm using PHP to process input from an AJAX form. I have written an error handler function to make sure the response is always valid JSON, and it's been working fine so far. But when I add this PDF generator code using TCPDF, it breaks. It returns two separate dicts like this:

{"error":false,"msg":""}{"error":true,"msg":"Error 2 in tcpdf.php line 7791: unlink(/tmp/__tcpdf_ccbb9a106b69bdb317365acaf9c33cb8_imgmask_alpha_b21911b6576fec1bf27dd6546bc66baf): No such file or directory"}

I can debug the PDF issue myself. I just don't understand why the error handler function doesn't work. It looks like the generatePDF function returns an empty string, then this is echoed, and then the error handler runs after that even though I added an explicit die() statement.

The error here is triggered by $pdf->writeHTML() so my expectation is that would invoke the error handler function, and then die without returning from generatePDF(). Here is a simplified example of the code.

<?php
// make sure we always return valid JSON
header('Content-Type: application/json');
set_error_handler('errorHandler');

// initialize array for AJAX response
$res = array('error' => false, 'msg' => '');

require __DIR__ . "/../vendor/autoload.php";

$bodyHtml = file_get_contents(__DIR__ . "/../template.html");
$res['msg'] .= generatePDF($bodyHtml);

// return to AJAX
echo json_encode($res);
die();

function generatePDF($bodyHtml) {
  $pdf = new TCPDF();
  $pdf->AddPage();
  $pdf->writeHTML($bodyHtml, $ln=true, $fill=false, $reseth=false, $cell=false, $align='');
  return $pdf->Output(__DIR__ . "/output.pdf", "F");
}

function errorHandler($errno, $errstr, $errfile, $errline) {
  global $res;
  $res['error'] = true;
  $res['msg'] .= "Error $errno in " . basename($errfile) . " line $errline: $errstr";
  echo json_encode($res);
  die();
}
?>
question from:https://stackoverflow.com/questions/65831919/why-does-php-error-handler-run-out-of-order

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

I think I have found the answer. The triggering call from line 7791 is @unlink($file);. The PHP manual says:

If you have set a custom error handler function with set_error_handler() then it will still get called, but this custom error handler can (and should) call error_reporting() which will return 0 when the call that triggered the error was preceded by an @.

So my solution is to add a test in the error handler:

function errorHandler($errno, $errstr, $errfile, $errline) {
  if (error_reporting()) {
    global $res;
    $res['error'] = true;
    $res['msg'] .= "Error $errno in " . basename($errfile) . " line $errline: $errstr";
    echo json_encode($res);
    die();
  }
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...