PHP Sadness

(<5.4) Syntax errors re-arm superglobals

Before version 5.4, PHP had a peculiar behavior with regard to how it handled superglobal loading during syntax errors. While it seems obscure, this bug cost many hours of debugging unit tests that verify behavior when encountering syntax errors when loading PHP modules.

When a syntax error is encountered, PHP "armed" the superglobals (like $_REQUEST), marking them for repopulation when next encountered by the parser. If other values had been put in $_REQUEST (for example, to mock out global state for a unit test), those values would be mysteriously lost the next time a file containing $_REQUEST were parsed.

We can use @eval('!'); to simulate loading a file containing a syntax error, and eval('$_REQUEST;'); to simulate loading a file containing $_REQUEST.

<?php
@eval('!');               # simulate loading a file with a syntax error
$_REQUEST['xyz'] = 'pdq'; # even values written after the syntax error will be lost
eval('$_REQUEST;');       # later, load a file containing $_REQUEST, causing it to be repopulated
var_dump($_REQUEST);      # the changes made to $_REQUEST are now lost

Prior to PHP 5.4, the output from this script is an empty array:

array(0) {
}

Starting with PHP 5.4, the output is fixed (starting with PHP 7.0, the parse error has to be trapped with try/catch, not @):

array(1) {
  ["xyz"]=>
  string(3) "pdq"
}

The workaround here is to be very careful with modified superglobals anytime you might trigger a syntax error. If possible, you can also upgrade to at least PHP 5.4.