Before pp4phpAfter 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).'