A few months ago I proposed a patch that would permit stopping the Zend Parser at a certain point in the script and not having it try to examine any subsequent content. The logic behind this feature was to simplify the process of creating single-script installers, such as the one used by FUDforum. The installer is a single script that at the end of it contains a code archive of the application being installed, which the installation process places into the set locations. The problem with implementing such installer at this point was that the data must be made PHP safe, so no <?php or similar "start-php-context" tokens that may be present in the archive are not treated as such resulting in undesired code execution. The solution required either encoding of the data using base64, making it 30% large or custom encoding scheme that would “hide” anything resembling a PHP start tag. Even with this problem solved, one last issue remained, this being the memory limit. Since the Zend Parser takes the entire script it needs to allocate memory for storing the archive that can be several megabytes large, this allocation quickly exhausts the default 8meg limit and causes a fatal out-of-memory error. By gaining the ability to stop the parser, this can be avoided since the data beyond the stoppage point will not be examined.
The main downside of the originally proposed patch was it provided no easy way to determine where does the archive portion of the file starts. The developer would need to parse their own script looking for the “STOP” point to determine the end of the script and the start of the archive. Given an overwhelming support for this feature, Zeev Suraski decided to rewrite the patch to include an easy way to determine this position. After some hacking on Zeev’s part and a fair bit of testing on mine a new patch was created and today applied to CVS. The patch provides a __HALT_COMPILER() construct that can be used to stop the parser and a __COMPILER_HALT_OFFSET__ constant indicating the “script-end” position.
Here is a brief example of it’s usage:
PHP:
<?php
echo file_get_contents(__FILE__, NULL, NULL, __COMPILER_HALT_OFFSET__);
?>
<?php __HALT_COMPILER();
some archive data, which can be binary
Output:
some archive data, which can be binary
The output of the code will be just the archive data, which can now be fetched without having to manually look for the "stop" portion inside the file. Kudos to Zeev for taking the time to improve on my idea and developing this patch, which as of today is part of PHP 5.1.