]> scripts.mit.edu Git - autoinstallsdev/mediawiki.git/blob - extensions/LocalisationUpdate/QuickArrayReader.php
MediaWiki 1.30.2
[autoinstallsdev/mediawiki.git] / extensions / LocalisationUpdate / QuickArrayReader.php
1 <?php
2
3 /**
4  * Quickie parser class that can happily read the subset of PHP we need
5  * for our localization arrays safely.
6  *
7  * Still an order of magnitude slower than eval().
8  */
9 class QuickArrayReader {
10         private $vars = [];
11
12         /**
13          * @param $string string
14          */
15         function __construct( $string ) {
16                 $scalarTypes = [
17                         T_LNUMBER => true,
18                         T_DNUMBER => true,
19                         T_STRING => true,
20                         T_CONSTANT_ENCAPSED_STRING => true,
21                 ];
22                 $skipTypes = [
23                         T_WHITESPACE => true,
24                         T_COMMENT => true,
25                         T_DOC_COMMENT => true,
26                 ];
27                 $tokens = token_get_all( $string );
28                 $count = count( $tokens );
29                 for ( $i = 0; $i < $count; ) {
30                         while ( isset( $skipTypes[$tokens[$i][0]] ) ) {
31                                 $i++;
32                         }
33                         switch ( $tokens[$i][0] ) {
34                                 case T_OPEN_TAG:
35                                         $i++;
36                                         continue;
37                                 case T_VARIABLE:
38                                         // '$messages' -> 'messages'
39                                         $varname = trim( substr( $tokens[$i][1], 1 ) );
40                                         $varindex = null;
41
42                                         while ( isset( $skipTypes[$tokens[++$i][0]] ) ) {
43                                         }
44
45                                         if ( $tokens[$i] === '[' ) {
46                                                 while ( isset( $skipTypes[$tokens[++$i][0]] ) ) {
47                                                 }
48
49                                                 if ( isset( $scalarTypes[$tokens[$i][0]] ) ) {
50                                                         $varindex = $this->parseScalar( $tokens[$i] );
51                                                 } else {
52                                                         throw $this->except( $tokens[$i], 'scalar index' );
53                                                 }
54                                                 while ( isset( $skipTypes[$tokens[++$i][0]] ) ) {
55                                                 }
56
57                                                 if ( $tokens[$i] !== ']' ) {
58                                                         throw $this->except( $tokens[$i], ']' );
59                                                 }
60                                                 while ( isset( $skipTypes[$tokens[++$i][0]] ) ) {
61                                                 }
62                                         }
63
64                                         if ( $tokens[$i] !== '=' ) {
65                                                 throw $this->except( $tokens[$i], '=' );
66                                         }
67                                         while ( isset( $skipTypes[$tokens[++$i][0]] ) ) {
68                                         }
69
70                                         if ( isset( $scalarTypes[$tokens[$i][0]] ) ) {
71                                                 $buildval = $this->parseScalar( $tokens[$i] );
72                                         } elseif ( $tokens[$i][0] === T_ARRAY ) {
73                                                 while ( isset( $skipTypes[$tokens[++$i][0]] ) ) {
74                                                 }
75                                                 if ( $tokens[$i] !== '(' ) {
76                                                         throw $this->except( $tokens[$i], '(' );
77                                                 }
78                                                 $buildval = [];
79                                                 do {
80                                                         while ( isset( $skipTypes[$tokens[++$i][0]] ) ) {
81                                                         }
82
83                                                         if ( $tokens[$i] === ')' ) {
84                                                                 break;
85                                                         }
86                                                         if ( isset( $scalarTypes[$tokens[$i][0]] ) ) {
87                                                                 $key = $this->parseScalar( $tokens[$i] );
88                                                         }
89                                                         while ( isset( $skipTypes[$tokens[++$i][0]] ) ) {
90                                                         }
91
92                                                         if ( $tokens[$i][0] !== T_DOUBLE_ARROW ) {
93                                                                 throw $this->except( $tokens[$i], '=>' );
94                                                         }
95                                                         while ( isset( $skipTypes[$tokens[++$i][0]] ) ) {
96                                                         }
97
98                                                         if ( isset( $scalarTypes[$tokens[$i][0]] ) ) {
99                                                                 $val = $this->parseScalar( $tokens[$i] );
100                                                         }
101                                                         wfSuppressWarnings();
102                                                         $buildval[$key] = $val;
103                                                         wfRestoreWarnings();
104                                                         while ( isset( $skipTypes[$tokens[++$i][0]] ) ) {
105                                                         }
106
107                                                         if ( $tokens[$i] === ',' ) {
108                                                                 continue;
109                                                         } elseif ( $tokens[$i] === ')' ) {
110                                                                 break;
111                                                         } else {
112                                                                 throw $this->except( $tokens[$i], ', or )' );
113                                                         }
114                                                 } while ( true );
115                                         } else {
116                                                 throw $this->except( $tokens[$i], 'scalar or array' );
117                                         }
118                                         if ( is_null( $varindex ) ) {
119                                                 $this->vars[$varname] = $buildval;
120                                         } else {
121                                                 wfSuppressWarnings();
122                                                 $this->vars[$varname][$varindex] = $buildval;
123                                                 wfRestoreWarnings();
124                                         }
125                                         while ( isset( $skipTypes[$tokens[++$i][0]] ) ) {
126                                         }
127                                         if ( $tokens[$i] !== ';' ) {
128                                                 throw $this->except( $tokens[$i], ';' );
129                                         }
130                                         $i++;
131                                         break;
132                                 default:
133                                         throw $this->except( $tokens[$i], 'open tag, whitespace, or variable.' );
134                         }
135                 }
136         }
137
138         /**
139          * @param $got string
140          * @param $expected string
141          * @return Exception
142          */
143         private function except( $got, $expected ) {
144                 if ( is_array( $got ) ) {
145                         $got = token_name( $got[0] ) . " ('" . $got[1] . "')";
146                 } else {
147                         $got = "'" . $got . "'";
148                 }
149
150                 return new Exception( "Expected $expected, got $got" );
151         }
152
153         /**
154          * Parse a scalar value in PHP
155          *
156          * @param $token string
157          *
158          * @return mixed Parsed value
159          */
160         function parseScalar( $token ) {
161                 if ( is_array( $token ) ) {
162                         $str = $token[1];
163                 } else {
164                         $str = $token;
165                 }
166                 if ( $str !== '' && $str[0] == '\'' ) {
167                         // Single-quoted string
168                         // @fixme trim() call is due to mystery bug where whitespace gets
169                         // appended to the token; without it we ended up reading in the
170                         // extra quote on the end!
171                         return strtr( substr( trim( $str ), 1, -1 ),
172                                 [ '\\\'' => '\'', '\\\\' => '\\' ] );
173                 }
174
175                 wfSuppressWarnings();
176                 if ( $str !== '' && $str[0] == '"' ) {
177                         // Double-quoted string
178                         // @fixme trim() call is due to mystery bug where whitespace gets
179                         // appended to the token; without it we ended up reading in the
180                         // extra quote on the end!
181                         wfRestoreWarnings();
182                         return stripcslashes( substr( trim( $str ), 1, -1 ) );
183                 }
184                 wfRestoreWarnings();
185
186                 if ( substr( $str, 0, 4 ) === 'true' ) {
187                         return true;
188                 }
189
190                 if ( substr( $str, 0, 5 ) === 'false' ) {
191                         return false;
192                 }
193
194                 if ( substr( $str, 0, 4 ) === 'null' ) {
195                         return null;
196                 }
197
198                 // Must be some kind of numeric value, so let PHP's weak typing
199                 // be useful for a change
200                 return $str;
201         }
202
203         /**
204          * @param $varname string
205          * @return null|string
206          */
207         function getVar( $varname ) {
208                 if ( isset( $this->vars[$varname] ) ) {
209                         return $this->vars[$varname];
210                 } else {
211                         return null;
212                 }
213         }
214 }