diff options
Diffstat (limited to 'extensions/LocalisationUpdate/QuickArrayReader.php')
-rw-r--r-- | extensions/LocalisationUpdate/QuickArrayReader.php | 187 |
1 files changed, 187 insertions, 0 deletions
diff --git a/extensions/LocalisationUpdate/QuickArrayReader.php b/extensions/LocalisationUpdate/QuickArrayReader.php new file mode 100644 index 00000000..214d5a61 --- /dev/null +++ b/extensions/LocalisationUpdate/QuickArrayReader.php @@ -0,0 +1,187 @@ +<?php + +/** + * Quickie parser class that can happily read the subset of PHP we need + * for our localization arrays safely. + * + * About an order of magnitude faster than ConfEditor(), but still an + * order of magnitude slower than eval(). + */ +class QuickArrayReader { + var $vars = array(); + + /** + * @param $string string + */ + function __construct( $string ) { + $scalarTypes = array( + T_LNUMBER => true, + T_DNUMBER => true, + T_STRING => true, + T_CONSTANT_ENCAPSED_STRING => true, + ); + $skipTypes = array( + T_WHITESPACE => true, + T_COMMENT => true, + T_DOC_COMMENT => true, + ); + $tokens = token_get_all( $string ); + $count = count( $tokens ); + for( $i = 0; $i < $count; ) { + while( isset($skipTypes[$tokens[$i][0]] ) ) { + $i++; + } + switch( $tokens[$i][0] ) { + case T_OPEN_TAG: + $i++; + continue; + case T_VARIABLE: + // '$messages' -> 'messages' + $varname = trim( substr( $tokens[$i][1], 1 ) ); + $varindex = null; + + while( isset($skipTypes[$tokens[++$i][0]] ) ); + + if( $tokens[$i] === '[' ) { + while( isset($skipTypes[$tokens[++$i][0]] ) ); + + if( isset($scalarTypes[$tokens[$i][0]] ) ) { + $varindex = $this->parseScalar( $tokens[$i] ); + } else { + throw $this->except( $tokens[$i], 'scalar index' ); + } + while( isset($skipTypes[$tokens[++$i][0]] ) ); + + if( $tokens[$i] !== ']' ) { + throw $this->except( $tokens[$i], ']' ); + } + while( isset($skipTypes[$tokens[++$i][0]] ) ); + } + + if( $tokens[$i] !== '=' ) { + throw $this->except( $tokens[$i], '=' ); + } + while( isset($skipTypes[$tokens[++$i][0]] ) ); + + if( isset($scalarTypes[$tokens[$i][0]] ) ) { + $buildval = $this->parseScalar( $tokens[$i] ); + } elseif( $tokens[$i][0] === T_ARRAY ) { + while( isset($skipTypes[$tokens[++$i][0]] ) ); + if( $tokens[$i] !== '(' ) { + throw $this->except( $tokens[$i], '(' ); + } + $buildval = array(); + do { + while( isset($skipTypes[$tokens[++$i][0]] ) ); + + if( $tokens[$i] === ')' ) { + break; + } + if( isset($scalarTypes[$tokens[$i][0]] ) ) { + $key = $this->parseScalar( $tokens[$i] ); + } + while( isset($skipTypes[$tokens[++$i][0]] ) ); + + if( $tokens[$i][0] !== T_DOUBLE_ARROW ) { + throw $this->except( $tokens[$i], '=>' ); + } + while( isset($skipTypes[$tokens[++$i][0]] ) ); + + if( isset($scalarTypes[$tokens[$i][0]] ) ) { + $val = $this->parseScalar( $tokens[$i] ); + } + @$buildval[$key] = $val; + while( isset($skipTypes[$tokens[++$i][0]] ) ); + + if( $tokens[$i] === ',' ) { + continue; + } elseif( $tokens[$i] === ')' ) { + break; + } else { + throw $this->except( $tokens[$i], ', or )' ); + } + } while(true); + } else { + throw $this->except( $tokens[$i], 'scalar or array' ); + } + if( is_null( $varindex ) ) { + $this->vars[$varname] = $buildval; + } else { + @$this->vars[$varname][$varindex] = $buildval; + } + while( isset($skipTypes[$tokens[++$i][0]] ) ); + if( $tokens[$i] !== ';' ) { + throw $this->except($tokens[$i], ';'); + } + $i++; + break; + default: + throw $this->except($tokens[$i], 'open tag, whitespace, or variable.'); + } + } + } + + /** + * @param $got string + * @param $expected string + * @return Exception + */ + private function except( $got, $expected ) { + if( is_array( $got ) ) { + $got = token_name( $got[0] ) . " ('" . $got[1] . "')"; + } else { + $got = "'" . $got . "'"; + } + return new Exception( "Expected $expected, got $got" ); + } + + /** + * Parse a scalar value in PHP + * + * @param $token string + * + * @return mixed Parsed value + */ + function parseScalar( $token ) { + if( is_array( $token ) ) { + $str = $token[1]; + } else { + $str = $token; + } + if ( $str !== '' && $str[0] == '\'' ) + // Single-quoted string + // @fixme trim() call is due to mystery bug where whitespace gets + // appended to the token; without it we ended up reading in the + // extra quote on the end! + return strtr( substr( trim( $str ), 1, -1 ), + array( '\\\'' => '\'', '\\\\' => '\\' ) ); + if ( $str !== '' && @$str[0] == '"' ) + // Double-quoted string + // @fixme trim() call is due to mystery bug where whitespace gets + // appended to the token; without it we ended up reading in the + // extra quote on the end! + return stripcslashes( substr( trim( $str ), 1, -1 ) ); + if ( substr( $str, 0, 4 ) === 'true' ) + return true; + if ( substr( $str, 0, 5 ) === 'false' ) + return false; + if ( substr( $str, 0, 4 ) === 'null' ) + return null; + // Must be some kind of numeric value, so let PHP's weak typing + // be useful for a change + return $str; + } + + /** + * @param $varname string + * @return null|string + */ + function getVar( $varname ) { + if( isset( $this->vars[$varname] ) ) { + return $this->vars[$varname]; + } else { + return null; + } + } +} + |