Ideas for Drupal: trapping obsolete functions

Submitted by Frederic Marand on

The recent removal of the quasi-official node_validate_title() function from 4.7 causing various errors with contrib modules, I wondered whether there wouldn't be a way to trap such errors in a way that would be helpful to newbies, instead of the current situation where all they get from their newly haphazard drupal install is a PHP fatal error.

The idea, then, is to register obsolete functions in some form of legacy maintenance module, to generate a useful help page pointing the user to a doc page on drupal explaining why there is an error in his configuration and what he should do. In node_validate_title()'s case, the help is a bit succinct: http://drupal.org/node/22218#node_validate_title.

Now, the problem is that PHP doesn't allow user error handlers to trap such fatal errors as undefined functions. But a workaround is suggested in the comments for set_error_handler(): use output buffering, and parse the error message.

When I tossed this idea on the Drupal IRC development channel, it was greeted rather cooly, so I figured I'd try to implement it before going further, and here is a proof-of-concept example:

<?php
function fatal_error_handler($buffer)
  {
 
$obsolete_functions = array
    (
   
'node_validate_title' => 'http://drupal.org/node/22218#node_validate_title'
   
);

 
$handled_error = '  Call to undefined function ';
 
$handled_length = strlen($handled_error);
 
  if (
ereg ("(error</b>:)(.+)(<br)", $buffer, $regs) )
    {
   
$err = preg_replace("/<.*?" . ">/","", $regs[2]);
    if (
strncmp($err, $handled_error, $handled_length) === 0)
      {
     
$err2 = substr($err, $handled_length);
     
$arErr2 = explode(' ', $err2);
     
/**
       * 0: function
       * 1: 'in'
       * 2: path
       * 3: 'on'
       * 4: 'line'
       * 5: line
       */
     
$function = rtrim($arErr2[0], '()');
     
$path     = $arErr2[2];
     
$line     = $arErr2[5];
     
     
$ret = "File $path used function $function at line $line, but it shouldn't have." ;
      if (
array_key_exists($function, $obsolete_functions))
        {
       
$ret .= '<p>You\'ll find help at <a href="/riff.org/blog/' . $obsolete_functions[$function]
              .
'">' . $obsolete_functions[$function] . '</a></p>';
        }
      
      }
    else
     
$ret = "Unhandled error caught: [$err]";
    }
  else
   
$ret = $buffer;
  return
$ret;
  }


ob_start("fatal_error_handler");

node_validate_title();
ob_end_flush();
?>

This example is currently live at http://www.plusvite.net/errors.php.

In this example, the obsolete function node_validate_title(); is called, but instead of causing a PHP fatal error, it redirects to an explanation page on Drupal.org. Such migration info pages should probably be adapted for end user consumption, but I think it would make for a better first experience with the product and possibly result in higher adoption rates than the current situation, where users find a PHP error and most of them drop the product as being broken, or at best come to complain on IRC before even trying to understand the cause of the error.

Can't help but think of the Cluetrain manifesto in this case: talk to the user instead of throwing him face to face with the brutality of a programming language error.

Of course, to be made into an actual feature, this should be implemented within Drupal and, to avoid the RAM use resulting from the potentially large array of help info, function description should be loaded from a text config file or from a DB table.