PluginProbe
SQLite Database Integration / 2.2.0
SQLite Database Integration v2.2.0
3.0.2 3.0.1 trunk 2.1.13 2.1.14 2.1.15 2.1.16 2.2.0 2.2.1 2.2.10 2.2.11 2.2.12 2.2.13 2.2.14 2.2.15 2.2.16 2.2.17 2.2.18 2.2.19 2.2.2 2.2.20 2.2.21 2.2.22 2.2.23 2.2.3 All 32 releases
sqlite-database-integration / wp-includes / sqlite / class-wp-sqlite-token.php

class-wp-sqlite-token.php in SQLite Database Integration 2.2.0, at wp-includes/sqlite/class-wp-sqlite-token.php

328 lines 8.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * This file is a port of the Token class from the PHPMyAdmin/sql-parser library.
4 *
5 * @package wp-sqlite-integration
6 * @see https://github.com/phpmyadmin/sql-parser
7 */
8
9 /**
10 * Defines a token along with a set of types and flags and utility functions.
11 *
12 * An array of tokens will result after parsing the query.
13 *
14 * A structure representing a lexeme that explicitly indicates its categorization for the purpose of parsing.
15 */
16 class WP_SQLite_Token {
17
18 /**
19 * This type is used when the token is invalid or its type cannot be
20 * determined because of the ambiguous context. Further analysis might be
21 * required to detect its type.
22 */
23 const TYPE_NONE = 0;
24
25 /**
26 * SQL specific keywords: SELECT, UPDATE, INSERT, etc.
27 */
28 const TYPE_KEYWORD = 1;
29
30 /**
31 * Any type of legal operator.
32 *
33 * Arithmetic operators: +, -, *, /, etc.
34 * Logical operators: ===, <>, !==, etc.
35 * Bitwise operators: &, |, ^, etc.
36 * Assignment operators: =, +=, -=, etc.
37 * SQL specific operators: . (e.g. .. WHERE database.table ..),
38 * * (e.g. SELECT * FROM ..)
39 */
40 const TYPE_OPERATOR = 2;
41
42 /**
43 * Spaces, tabs, new lines, etc.
44 */
45 const TYPE_WHITESPACE = 3;
46
47 /**
48 * Any type of legal comment.
49 *
50 * Bash (#), C (/* *\/) or SQL (--) comments:
51 *
52 * -- SQL-comment
53 *
54 * #Bash-like comment
55 *
56 * /*C-like comment*\/
57 *
58 * or:
59 *
60 * /*C-like
61 * comment*\/
62 *
63 * Backslashes were added to respect PHP's comments syntax.
64 */
65 const TYPE_COMMENT = 4;
66
67 /**
68 * Boolean values: true or false.
69 */
70 const TYPE_BOOL = 5;
71
72 /**
73 * Numbers: 4, 0x8, 15.16, 23e42, etc.
74 */
75 const TYPE_NUMBER = 6;
76
77 /**
78 * Literal strings: 'string', "test".
79 * Some of these strings are actually symbols.
80 */
81 const TYPE_STRING = 7;
82
83 /**
84 * Database, table names, variables, etc.
85 * For example: ```SELECT `foo`, `bar` FROM `database`.`table`;```.
86 */
87 const TYPE_SYMBOL = 8;
88
89 /**
90 * Delimits an unknown string.
91 * For example: ```SELECT * FROM test;```, `test` is a delimiter.
92 */
93 const TYPE_DELIMITER = 9;
94
95 /**
96 * Labels in LOOP statement, ITERATE statement etc.
97 * For example (only for begin label):
98 * begin_label: BEGIN [statement_list] END [end_label]
99 * begin_label: LOOP [statement_list] END LOOP [end_label]
100 * begin_label: REPEAT [statement_list] ... END REPEAT [end_label]
101 * begin_label: WHILE ... DO [statement_list] END WHILE [end_label].
102 */
103 const TYPE_LABEL = 10;
104
105 // Flags that describe the tokens in more detail.
106 // All keywords must have flag 1 so `Context::isKeyword` method doesn't
107 // require strict comparison.
108 const FLAG_KEYWORD_RESERVED = 2;
109 const FLAG_KEYWORD_COMPOSED = 4;
110 const FLAG_KEYWORD_DATA_TYPE = 8;
111 const FLAG_KEYWORD_KEY = 16;
112 const FLAG_KEYWORD_FUNCTION = 32;
113
114 // Numbers related flags.
115 const FLAG_NUMBER_HEX = 1;
116 const FLAG_NUMBER_FLOAT = 2;
117 const FLAG_NUMBER_APPROXIMATE = 4;
118 const FLAG_NUMBER_NEGATIVE = 8;
119 const FLAG_NUMBER_BINARY = 16;
120
121 // Strings related flags.
122 const FLAG_STRING_SINGLE_QUOTES = 1;
123 const FLAG_STRING_DOUBLE_QUOTES = 2;
124
125 // Comments related flags.
126 const FLAG_COMMENT_BASH = 1;
127 const FLAG_COMMENT_C = 2;
128 const FLAG_COMMENT_SQL = 4;
129 const FLAG_COMMENT_MYSQL_CMD = 8;
130
131 // Operators related flags.
132 const FLAG_OPERATOR_ARITHMETIC = 1;
133 const FLAG_OPERATOR_LOGICAL = 2;
134 const FLAG_OPERATOR_BITWISE = 4;
135 const FLAG_OPERATOR_ASSIGNMENT = 8;
136 const FLAG_OPERATOR_SQL = 16;
137
138 // Symbols related flags.
139 const FLAG_SYMBOL_VARIABLE = 1;
140 const FLAG_SYMBOL_BACKTICK = 2;
141 const FLAG_SYMBOL_USER = 4;
142 const FLAG_SYMBOL_SYSTEM = 8;
143 const FLAG_SYMBOL_PARAMETER = 16;
144
145 /**
146 * The token it its raw string representation.
147 *
148 * @var string
149 */
150 public $token;
151
152 /**
153 * The value this token contains (i.e. token after some evaluation).
154 *
155 * @var mixed
156 */
157 public $value;
158
159 /**
160 * The keyword value this token contains, always uppercase.
161 *
162 * @var mixed|string|null
163 */
164 public $keyword = null;
165
166 /**
167 * The type of this token.
168 *
169 * @var int
170 */
171 public $type;
172
173 /**
174 * The flags of this token.
175 *
176 * @var int
177 */
178 public $flags;
179
180 /**
181 * The position in the initial string where this token started.
182 *
183 * The position is counted in chars, not bytes, so you should
184 * use mb_* functions to properly handle utf-8 multibyte chars.
185 *
186 * @var int|null
187 */
188 public $position;
189
190 /**
191 * Constructor.
192 *
193 * @param string $token The value of the token.
194 * @param int $type The type of the token.
195 * @param int $flags The flags of the token.
196 */
197 public function __construct( $token, $type = 0, $flags = 0 ) {
198 $this->token = $token;
199 $this->type = $type;
200 $this->flags = $flags;
201 $this->value = $this->extract();
202 }
203
204 /**
205 * Check if the token matches the given parameters.
206 *
207 * @param int|null $type The type of the token.
208 * @param int|null $flags The flags of the token.
209 * @param array|null $values The values of the token.
210 *
211 * @return bool
212 */
213 public function matches( $type = null, $flags = null, $values = null ) {
214 if ( null === $type && null === $flags && ( null === $values || array() === $values ) ) {
215 return ! $this->is_semantically_void();
216 }
217
218 return (
219 ( null === $type || $this->type === $type )
220 && ( null === $flags || ( $this->flags & $flags ) )
221 && ( null === $values || in_array( strtoupper( $this->value ?? '' ), $values, true ) )
222 );
223 }
224
225 /**
226 * Check if the token is semantically void (i.e. whitespace or comment).
227 *
228 * @return bool
229 */
230 public function is_semantically_void() {
231 return $this->matches( self::TYPE_WHITESPACE ) || $this->matches( self::TYPE_COMMENT );
232 }
233
234 /**
235 * Does little processing to the token to extract a value.
236 *
237 * If no processing can be done it will return the initial string.
238 *
239 * @return mixed
240 */
241 private function extract() {
242 switch ( $this->type ) {
243 case self::TYPE_KEYWORD:
244 $this->keyword = strtoupper( $this->token ?? '' );
245 if ( ! ( $this->flags & self::FLAG_KEYWORD_RESERVED ) ) {
246 /*
247 * Unreserved keywords should stay the way they are
248 * because they might represent field names.
249 */
250 return $this->token;
251 }
252
253 return $this->keyword;
254
255 case self::TYPE_WHITESPACE:
256 return ' ';
257
258 case self::TYPE_BOOL:
259 return strtoupper( $this->token ?? '' ) === 'TRUE';
260
261 case self::TYPE_NUMBER:
262 $ret = str_replace( '--', '', $this->token ); // e.g. ---42 === -42.
263 if ( $this->flags & self::FLAG_NUMBER_HEX ) {
264 $ret = str_replace( array( '-', '+' ), '', $this->token );
265 if ( $this->flags & self::FLAG_NUMBER_NEGATIVE ) {
266 $ret = -hexdec( $ret );
267 } else {
268 $ret = hexdec( $ret );
269 }
270 } elseif ( ( $this->flags & self::FLAG_NUMBER_APPROXIMATE ) || ( $this->flags & self::FLAG_NUMBER_FLOAT ) ) {
271 $ret = (float) $ret;
272 } elseif ( ! ( $this->flags & self::FLAG_NUMBER_BINARY ) ) {
273 $ret = (int) $ret;
274 }
275
276 return $ret;
277
278 case self::TYPE_STRING:
279 // Trims quotes.
280 $str = $this->token;
281 $str = mb_substr( $str, 1, -1, 'UTF-8' );
282
283 // Removes surrounding quotes.
284 $quote = $this->token[0];
285 $str = str_replace( $quote . $quote, $quote, $str );
286
287 /*
288 * Finally unescapes the string.
289 *
290 * `stripcslashes` replaces escape sequences with their
291 * representation.
292 */
293 $str = stripcslashes( $str );
294
295 return $str;
296
297 case self::TYPE_SYMBOL:
298 $str = $this->token;
299 if ( isset( $str[0] ) && ( '@' === $str[0] ) ) {
300 /*
301 * `mb_strlen($str)` must be used instead of `null` because
302 * in PHP 5.3- the `null` parameter isn't handled correctly.
303 */
304 $str = mb_substr(
305 $str,
306 ! empty( $str[1] ) && ( '@' === $str[1] ) ? 2 : 1,
307 mb_strlen( $str ),
308 'UTF-8'
309 );
310 }
311
312 if ( isset( $str[0] ) && ( ':' === $str[0] ) ) {
313 $str = mb_substr( $str, 1, mb_strlen( $str ), 'UTF-8' );
314 }
315
316 if ( isset( $str[0] ) && ( ( '`' === $str[0] ) || ( '"' === $str[0] ) || ( '\'' === $str[0] ) ) ) {
317 $quote = $str[0];
318 $str = str_replace( $quote . $quote, $quote, $str );
319 $str = mb_substr( $str, 1, -1, 'UTF-8' );
320 }
321
322 return $str;
323 }
324
325 return $this->token;
326 }
327 }
328