/extensions/LocalisationUpdate/QuickArrayReader.php
https://gitlab.com/link233/bootmw · PHP · 215 lines · 157 code · 22 blank · 36 comment · 47 complexity · 31a5fb2c399a5a5587adc31a212d69b0 MD5 · raw file
- <?php
- /**
- * Quickie parser class that can happily read the subset of PHP we need
- * for our localization arrays safely.
- *
- * Still an order of magnitude slower than eval().
- */
- class QuickArrayReader {
- private $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] );
- }
- wfSuppressWarnings();
- $buildval[$key] = $val;
- wfRestoreWarnings();
- 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 {
- wfSuppressWarnings();
- $this->vars[$varname][$varindex] = $buildval;
- wfRestoreWarnings();
- }
- 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( '\\\'' => '\'', '\\\\' => '\\' ) );
- }
- wfSuppressWarnings();
- 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!
- wfRestoreWarnings();
- return stripcslashes( substr( trim( $str ), 1, -1 ) );
- }
- wfRestoreWarnings();
- 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;
- }
- }
- }