Before pp4php | After pp4php |
|
|
===== Core concepts =====
**A preprocessor constant (builtin or user-defined) is replaced in PHP comments, embedded HTML code and PHP code. (cf. example above)**
On the the contrary, a PHP constant name (''define("x1","value")'') is available only in PHP code. To define a new constant:
''#pp4php __codename__ bigjoe''
It has to be terminated by a newline
**The graph of included files is unfolded statically (cf. example above). **
On the contrary, a PHP include/require is done dynamically.
The main advantage is to enable the distribution of a single PHP file which is the results of multiple input source files used for development. If you want to disable the replacement of an ''include/require'' by its content, prefix it by an @:
''@include("foo.php");''
** Strings enclosed by ''pp4php:hidden'' and ''neddih'' are not shown at all**. The main usage is to hide passwords and TODO (cf. example above)
===== Builtin Variables =====
First pp4php supports some of [[http://php.net/manual/en/language.constants.predefined.php|the magic constants of PHP]].
__PPFILE__ is replaced by the full path the current preprocessed filename. It depends on the graphof ''include/require''.
__PPDIR__ is replaced by the full path of the directory containing the current preprocessed filename.
__PPLINE__ is replaced by the line number in the current preprocessed filename.
__PPSFILE__ is replaced by the file name the current preprocessed filename.
__MTIME__ is replaced by the day-wise modification time of the current preprocessed filename (e.g. 20091025).
__XMTIME__ is replaced by the second-wise modification time of the current preprocessed filename (e.g. 20091025-1324)..
Second, pp4php supports handy special tags:
__NOW__ is replaced by the day-wise download date of the code (e.g. 20091025), useful for traceability links.
__XNOW__ is replaced by the second-wise download date of the code (e.g. 20091025-1810), useful for traceability links.
Third, pp4php supports shortcuts of PHP $_SERVER variables. They are not only shortcuts but also available in PHP comments and embedded HTML code.
__USER_AGENT__ is replaced by the value of ''$_SERVER["HTTP_USER_AGENT"]''
__REFERER__ is replaced by the value of ''$_SERVER["HTTP_REFERER"]''
__USER_NAME__ is replaced by the value of ''$_SERVER["PHP_AUTH_USER"]''
__REMOTE_ADDR__ is replaced by the value of ''$_SERVER["REMOTE_ADDR"]''
__REMOTE_HOST__ is replaced by the value of ''gethostbyaddr($_SERVER["REMOTE_ADDR"])''
Misc:
__POWEREDBY__ is replaced by a mention and a link to pp4php :-)
__ID__ is a shortcut for "__URL__, v__XMTIME__, retrieved __XNOW__", inspired by [[http://svnbook.red-bean.com/en/1.4/svn.advanced.props.special.keywords.html|SVN $id$]]
''/*pp4php:serl*/ DEV_ONLY_ERROR_LEVEL /*lres*/'' is replaced by E_ERROR. serl stands for Safe Error Reporting Level. Using SERL, the code you redistribute should not produce undesirable notice and warning messages on different configurations.
__UNIQ__ is replaced by a unique ID.
===== Usage =====
The basic usage is to call pp4php and giving it the filename as parameter:
''http://domain.com/pp4php.php?pp4php_source=xxscript.php''
If you want to hide the the call to pp4php you can encapsulate it in a RewriteRule
# the first loop is required to avoid infinite RewriteRule loops
RewriteRule pp4php.php$ - [L]
RewriteRule (*.php)$ pp4php.php?pp4php_source=$1 [L]
===== Download =====
pp4php is released under the GNU General Publice Licence. Here is the source code: [[https://www.monperrus.net/martin/pp4php.php?pp4php_source=pp4php.php]]. Note that pp4php is bootstrapped: the source you obtain is the result of processing ''pp4php.php'' with pp4php :-)
For feature requests, bug reports, or patch proposals, [[http://www.monperrus.net/martin/|please drop me an email ]].
*/
function pp4php($filename) {
// you can not pass a array() directly by reference
$x=array();
$y=array();
return pp4php_internal($filename, $x, $y);
}
function pp4php_internal($filename, &$already_included, &$user_defined_variables) {
$result="";
// precondition
if (!is_readable($filename)) {
header('HTTP/1.1 404 Not found');
die("{$filename} is not readable");
}
$fhandler=fopen($filename,'r');
$linenumber=0;
while (!feof($fhandler)) {
$buffer = fgets($fhandler, 4096);
$linenumber++;
// defining new variables
if (preg_match("/^(.*)#pp4php\s+(\w+)\s+([\w.']+)\s*$/",$buffer, $matches)) {
$user_defined_variables[$matches[2]]= $matches[3];
$buffer = $matches[1];
}
// since it's before the rest, it allows the user to override built-ins
foreach($user_defined_variables as $name => $value) {
$buffer = preg_replace('/'.$name.'/',$value,$buffer);
}
// composite constants
$buffer = preg_replace('/__'.'ID__/','__'.'URL__, v__'.'XMTIME__, retrieved __'.'XNOW__',$buffer);
$buffer = preg_replace('/__'.'POWEREDBY__/','source code produced with pp4php v__'.'MTIME__ (http://www.monperrus.net/martin/pp4php)',$buffer);
//http://php.net/manual/en/language.constants.predefined.php
// emulating default PHP magic constants
$buffer = preg_replace('/__'.'PPFILE__/',realpath($filename),$buffer);
$buffer = preg_replace('/__'.'PPDIR__/',dirname($filename),$buffer);
$buffer = preg_replace('/__'.'PPLINE__/',$linenumber,$buffer);
$buffer = preg_replace('/__'.'PPSFILE__/',basename($filename),$buffer);
$buffer = preg_replace('/__'.'GITHUB__/',date('Ymd',time()),$buffer);
$buffer = preg_replace('/__'.'MTIME__/',date('Ymd',filemtime($filename)),$buffer);
$buffer = preg_replace('/__'.'XMTIME__/',date('Ymd-Gi',filemtime($filename)),$buffer);
$buffer = preg_replace('/__'.'UNIQ__/',uniqid(),$buffer);
// THIS IS REGEX AND THE FOLLOWING IF/THEN/ELSE IS THE CORE OF PP4PHP
if (preg_match("/^(.*)(^|[^@])(include|require)(_once)?\([\"']([^\"']*)[\"']\);(.*)$/",$buffer, $matches)) {
$included=$matches[5];
// warning or error if the file is not accessible
if (!is_readable($included)) {
if ($matches[3]=="require") { die('pp4php: required file '.$included.' does not exists ('.$filename.':'.$linenumber.')');}
$buffer = $matches[1].
'// warning: pp4php: included file '.$included.' does not exist ('.$filename.':'.$linenumber.")\n".
$matches[6]."\n";
} // end is_readable
// SUPPORTING INCLUDE_ONCE AND REQUIRE_ONCE
else {
if ( ($matches[4]!='_once' && $filename!=$included) || ($matches[4]=='_once' && !in_array($included,$already_included))) {
$already_included[]=$included;
$buffer = $matches[1].'?>'.pp4php_internal(dirname($filename).'/'.$included, $already_included, $user_defined_variables).'