Attached file, implements validate_file(), which implements a php space syntax check for PHP scripts. It returns a boolean true/false value indicating whether the script has parse errors or not. Essentially a "php -l" from within PHP.
strip_file() is added for completion (might as well :) ) and implements "php -w", which strips comments & whitespace from a PHP file. A quick obfuscater of sorts. Any comments? Ilia
Index: basic_functions.c =================================================================== RCS file: /repository/php-src/ext/standard/basic_functions.c,v retrieving revision 1.543.2.22 diff -u -3 -p -r1.543.2.22 basic_functions.c --- basic_functions.c 29 Sep 2003 14:02:55 -0000 1.543.2.22 +++ basic_functions.c 3 Oct 2003 00:56:51 -0000 @@ -32,6 +32,72 @@ #include "ext/session/php_session.h" #include "zend_operators.h" +typedef struct yy_buffer_state *YY_BUFFER_STATE; +typedef unsigned int yy_size_t; +struct yy_buffer_state + { + FILE *yy_input_file; + + char *yy_ch_buf; /* input buffer */ + char *yy_buf_pos; /* current position in input buffer */ + + /* Size of input buffer in bytes, not including room for EOB + * characters. + */ + yy_size_t yy_buf_size; + + /* Number of characters read into yy_ch_buf, not including EOB + * characters. + */ + int yy_n_chars; + + /* Whether we "own" the buffer - i.e., we know we created it, + * and can realloc() it to grow it, and should free() it to + * delete it. + */ + int yy_is_our_buffer; + + /* Whether this is an "interactive" input source; if so, and + * if we're using stdio for input, then we want to use getc() + * instead of fread(), to make sure we stop fetching input after + * each newline. + */ + int yy_is_interactive; + + /* Whether we're considered to be at the beginning of a line. + * If so, '^' rules will be active on the next match, otherwise + * not. + */ + int yy_at_bol; + + /* Whether to try to fill the input buffer when we reach the + * end of it. + */ + int yy_fill_buffer; + + int yy_buffer_status; +#define YY_BUFFER_NEW 0 +#define YY_BUFFER_NORMAL 1 + /* When an EOF's been seen but there's still some text to process + * then we mark the buffer as YY_EOF_PENDING, to indicate that we + * shouldn't try reading from the input source any more. We might + * still have a bunch of tokens to match, though, because of + * possible backing-up. + * + * When we actually see the EOF, we change the status to "new" + * (via yyrestart()), so that the user can continue scanning by + * just pointing yyin at a new input file. + */ +#define YY_BUFFER_EOF_PENDING 2 + }; + +#include "zend.h" +#include "zend_language_scanner.h" +#include "zend_language_parser.h" + +#define zendtext LANG_SCNG(yy_text) +#define zendleng LANG_SCNG(yy_leng) + #include <stdarg.h> #include <stdlib.h> #include <math.h> @@ -561,6 +627,8 @@ function_entry basic_functions[] = { PHP_FE(highlight_file, NULL) PHP_FALIAS(show_source, highlight_file, NULL) PHP_FE(highlight_string, NULL) + PHP_FE(strip_file, NULL) + PHP_FE(validate_file, NULL) PHP_FE(ini_get, NULL) PHP_FE(ini_get_all, NULL) @@ -2179,6 +2247,107 @@ PHP_FUNCTION(highlight_file) } /* }}} */ +/* {{{ proto string strip_file(string file_name) + Return source with stripped comments and whitespace */ +PHP_FUNCTION(strip_file) +{ + char *filename; + int filename_len; + zend_lex_state original_lex_state; + zend_file_handle file_handle = {0}; + char resolved_path[MAXPATHLEN]; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &filename, &filename_len) == FAILURE) { + RETURN_FALSE; + } + + if (!VCWD_REALPATH(filename, resolved_path)) { + RETURN_FALSE; + } + + if (PG(safe_mode) && (!php_checkuid(resolved_path, NULL, CHECKUID_ALLOW_ONLY_FILE))) { + RETURN_FALSE; + } + + if (php_check_open_basedir(resolved_path TSRMLS_CC)) { + RETURN_FALSE; + } + + php_start_ob_buffer(NULL, 0, 1 TSRMLS_CC); + + file_handle.type = ZEND_HANDLE_FILENAME; + file_handle.filename = resolved_path; + file_handle.free_filename = 0; + file_handle.opened_path = NULL; + zend_save_lexical_state(&original_lex_state TSRMLS_CC); + if (open_file_for_scanning(&file_handle TSRMLS_CC)==FAILURE) { + RETURN_EMPTY_STRING(); + } + + zend_strip(TSRMLS_C); + + zend_destroy_file_handle(&file_handle TSRMLS_CC); + zend_restore_lexical_state(&original_lex_state TSRMLS_CC); + + php_ob_get_buffer(return_value TSRMLS_CC); + php_end_ob_buffer(0, 0 TSRMLS_CC); + + return; +} +/* }}} */ + +/* {{{ proto bool validate_file(string file_name) + Check the syntax of the specified file. */ +PHP_FUNCTION(validate_file) +{ + char *filename; + int filename_len; + zend_file_handle file_handle = {0}; + char resolved_path[MAXPATHLEN]; + zend_lex_state original_lex_state; + + int old_errors = PG(display_errors); + int old_track_errors = PG(track_errors); + int log_errors = PG(log_errors); + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &filename, &filename_len) == FAILURE) { + RETURN_FALSE; + } + + if (!VCWD_REALPATH(filename, resolved_path)) { + RETURN_FALSE; + } + + if (PG(safe_mode) && (!php_checkuid(resolved_path, NULL, CHECKUID_ALLOW_ONLY_FILE))) { + RETURN_FALSE; + } + + if (php_check_open_basedir(resolved_path TSRMLS_CC)) { + RETURN_FALSE; + } + + file_handle.type = ZEND_HANDLE_FILENAME; + file_handle.filename = resolved_path; + file_handle.free_filename = 0; + file_handle.opened_path = NULL; + + PG(log_errors) = PG(display_errors) = 0; + PG(track_errors) = 1; + + if (php_lint_script(&file_handle TSRMLS_CC) != SUCCESS) { + RETVAL_FALSE; + } else { + RETVAL_TRUE; + } + + PG(display_errors) = old_errors; + PG(log_errors) = log_errors; + PG(track_errors) = old_track_errors; + + return; +} +/* }}} */ + /* {{{ proto bool highlight_string(string string [, bool return] ) Syntax highlight a string or optionally return it */ PHP_FUNCTION(highlight_string) @@ -2187,6 +2356,7 @@ PHP_FUNCTION(highlight_string) zend_syntax_highlighter_ini syntax_highlighter_ini; char *hicompiled_string_description; zend_bool i = 0; + int old_error_reporting = EG(error_reporting); if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|b", &expr, &i) == FAILURE) { RETURN_FALSE; @@ -2197,6 +2367,8 @@ PHP_FUNCTION(highlight_string) php_start_ob_buffer (NULL, 0, 1 TSRMLS_CC); } + EG(error_reporting) = E_ERROR; + php_get_highlight_struct(&syntax_highlighter_ini); hicompiled_string_description = zend_make_compiled_string_description("highlighted code" TSRMLS_CC); @@ -2206,6 +2378,8 @@ PHP_FUNCTION(highlight_string) RETURN_FALSE; } efree(hicompiled_string_description); + + EG(error_reporting) = old_error_reporting; if (i) { php_ob_get_buffer (return_value TSRMLS_CC); Index: basic_functions.h =================================================================== RCS file: /repository/php-src/ext/standard/basic_functions.h,v retrieving revision 1.109.2.1 diff -u -3 -p -r1.109.2.1 basic_functions.h --- basic_functions.h 31 Dec 2002 16:35:25 -0000 1.109.2.1 +++ basic_functions.h 3 Oct 2003 00:56:51 -0000 @@ -72,6 +72,8 @@ PHP_FUNCTION(call_user_method_array); PHP_FUNCTION(register_shutdown_function); PHP_FUNCTION(highlight_file); PHP_FUNCTION(highlight_string); +PHP_FUNCTION(strip_file); +PHP_FUNCTION(validate_file); ZEND_API void php_get_highlight_struct(zend_syntax_highlighter_ini *syntax_highlighter_ini); PHP_FUNCTION(ini_get);
-- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php