3v4l.org

run code in 300+ PHP versions simultaneously
<?php const TK_WHITESPACES = 0, TK_OPENING_PARENTHESIS = 2, // 0b00000010 TK_CLOSING_PARENTHESIS = 4, // 0b00000100 TK_LOGICAL_CONJUNCTION = 8, // 0b00001000 TK_LOGICAL_DISJUNCTION = 16, // 0b00010000 TK_LOGICAL_NEGATION = 32, // etc. TK_STRING = 64, TK_EQUAL = 128, TK_NOT_EQUAL = 256, TK_COLUMN_NAME = 512, TK_END = 1024; const ERR_NONE = 0, ERROR = 1; // 0b00000001 const TOKENIZATION_ERROR = 3, // 0b00000011 ERR_UNEXPECTED_CHAR = 7, // 0b00000111 ERR_UNCLOSED_STRING = 11, // 0b00001011 ERR_BAD_UTF8 = 19, // 0b00010011 ERR_EMPTY_STRING = 35; // TE const LOGIC_ERROR = 129, // 0b10000001 ERR_UNEXPECTED_TOKEN = 133, // 0b10000101 ERR_UNEXPECTED_CLOSING_PARENTHESIS = 137, // 0b10001001 ERR_MISSING_CLOSING_PARENTHESIS = 145, // 0b10010001 ERR_UNKNOW_COLUMN_NAME = 161, // 0b10100001 ERR_EMPTY_QUERY = 193; // L E const RULES = [ TK_COLUMN_NAME => TK_EQUAL | TK_NOT_EQUAL, TK_EQUAL => TK_STRING, TK_NOT_EQUAL => TK_STRING, TK_STRING => TK_END | TK_CLOSING_PARENTHESIS | TK_LOGICAL_DISJUNCTION | TK_LOGICAL_CONJUNCTION, TK_CLOSING_PARENTHESIS => TK_END | TK_CLOSING_PARENTHESIS | TK_LOGICAL_DISJUNCTION | TK_LOGICAL_CONJUNCTION, TK_LOGICAL_DISJUNCTION => TK_LOGICAL_NEGATION | TK_OPENING_PARENTHESIS | TK_COLUMN_NAME, TK_LOGICAL_CONJUNCTION => TK_LOGICAL_NEGATION | TK_OPENING_PARENTHESIS | TK_COLUMN_NAME, TK_LOGICAL_NEGATION => TK_OPENING_PARENTHESIS | TK_COLUMN_NAME, TK_OPENING_PARENTHESIS => TK_OPENING_PARENTHESIS | TK_COLUMN_NAME ]; const COLUMN_NAMES = ['family', 'conditions_of_use', 'taxonomical_group']; const ERROR_MESSAGES = [ ERR_UNEXPECTED_CHAR => 'caractère inattendu à la position %d.', ERR_UNCLOSED_STRING => 'chaîne de caractères non fermée à la position %d.', ERR_BAD_UTF8 => 'erreur d\'encodage UTF-8 à la position %d.', ERR_EMPTY_STRING => 'chaîne vide à la position %d.', // ***** ERR_UNEXPECTED_TOKEN => 'élément inattendu à la position %d.', ERR_UNEXPECTED_CLOSING_PARENTHESIS => 'parenthèse fermante inattendue à la position %d.', ERR_MISSING_CLOSING_PARENTHESIS => 'parenthèse fermante manquante à la position %d.', ERR_UNKNOW_COLUMN_NAME => 'nom de colonne inconnu à la position %d.', ERR_EMPTY_QUERY => 'requête vide à la position %d.' ]; const TOKEN2SQL = [ TK_EQUAL => ' = ', TK_NOT_EQUAL => ' <> ', TK_CLOSING_PARENTHESIS => ')', TK_OPENING_PARENTHESIS => '(', TK_LOGICAL_DISJUNCTION => ' OR ', TK_LOGICAL_CONJUNCTION => ' AND ', TK_LOGICAL_NEGATION => 'NOT ', TK_STRING => '?' // placeholder ]; function tokenize(string $str) { $pattern = <<<'REGEX' ~ \s+ (*:TK_WHITESPACES) | \( (*:TK_OPENING_PARENTHESIS) | \) (*:TK_CLOSING_PARENTHESIS) | \b ET \b (*:TK_LOGICAL_CONJUNCTION) | \b OU \b (*:TK_LOGICAL_DISJUNCTION) | \b NON \b (*:TK_LOGICAL_NEGATION) | \B " [^"\\]* (?s: \\ . [^"\\]* )* (?: " \B (*:TK_STRING) | " (*:ERR_UNEXPECTED_CHAR) | \z (*:ERR_UNCLOSED_STRING) ) | \b \w+ (*:TK_COLUMN_NAME) | = (*:TK_EQUAL) | (?: != | <> ) (*:TK_NOT_EQUAL) | \z (*:TK_END) | (*COMMIT) (*FAIL) # UNEXPECTED CHARACTER ⮕ tokenization aborted ~xu REGEX; $count = preg_match_all($pattern, $str, $matches, PREG_SET_ORDER | PREG_OFFSET_CAPTURE); if ( preg_last_error() === PREG_BAD_UTF8_ERROR ) { preg_match('~(?: # séquences UTF-8 valides [\x00-\x7F] | [\xC2-\xDF][\x80-\xBF] | \xE0[\xA0-\xBF][\x80-\xBF] | \xED[\x80-\x9F][\x80-\xBF] | [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2} | \xF0[\x90-\xBF][\x80-\xBF]{2} | \xF4[\x80-\x8F][\x80-\xBF]{2} | [\xF1-\xF3][\x80-\xBF]{3} )*~x', $str, $m); return [ 'error' => ['type' => ERR_BAD_UTF8, 'offset' => strlen($m[0])] ]; } if ( $count === 0 ) // (*COMMIT) (*FAIL) a été atteint dés la première position return [ 'error' => ['type' => ERR_UNEXPECTED_CHAR, 'offset' => 0] ]; $errors = array_filter($matches, fn($m) => constant($m['MARK']) & ERROR); if ( !empty($errors) ) { // la fin a été atteinte mais il y a des marqueurs d'erreurs parmi les tokens $error = array_shift($errors); list($match, $offset) = $error[0]; return [ 'error' => ['type' => constant($error['MARK']), 'offset' => $offset + strlen($match)] ]; } $lastMatch = end($matches); if ( constant($lastMatch['MARK']) !== TK_END ) { // (*COMMIT) (*FAIL) a été atteint avant la fin list($match, $offset) = $lastMatch[0]; return [ 'error' => ['type' => ERR_UNEXPECTED_CHAR, 'offset' => $offset + strlen($match)] ]; } if ( $count === 1 ) // l'unique token est TK_END, la chaîne est vide return [ 'error' => ['type' => ERR_EMPTY_STRING, 'offset' => 0] ]; return [ 'error' => ERR_NONE, 'tokens' => array_map( fn($m) => [ 'value' => $m[0][0], 'offset' => $m[0][1], 'type' => constant($m['MARK']) ], $matches ) ]; } function checkLogic($tokens) { $parenthesis = 0; $current = current($tokens); if ( $current['type'] === TK_END ) return [ 'type' => ERR_EMPTY_QUERY, 'offset' => $current['offset'] ]; do { if ( $current['type'] === TK_COLUMN_NAME && !in_array($current['value'], COLUMN_NAMES) ) return [ 'type' => ERR_UNKNOW_COLUMN_NAME, 'offset' => $current['offset'] ]; if ( $current['type'] === TK_OPENING_PARENTHESIS ) $parenthesis++; elseif ( $current['type'] === TK_CLOSING_PARENTHESIS && --$parenthesis < 0 ) return [ 'type' => ERR_UNEXPECTED_CLOSING_PARENTHESIS, 'offset' => $current['offset'] ]; $next = next($tokens); if ( RULES[$current['type']] & $next['type'] ) // le token courant est suivi par un token autorisé $current = $next; else return [ 'type' => ERR_UNEXPECTED_TOKEN, 'offset' => $next['offset'] ]; } while ( $next['type'] !== TK_END ); return $parenthesis ? [ 'type' => ERR_MISSING_CLOSING_PARENTHESIS, 'offset' => $current['offset'] ] : true ; } function displayError($error, $query) { $position = grapheme_strlen(substr($query, 0, $error['offset'])); $format = ERROR_MESSAGES[$error['type']]."\n%s\n" . str_repeat(' ', $position) . '^'; printf($format, $position, $query); } function buildQuery($tokens, $prefix = '') { $SQLQuery = $prefix; $params = []; foreach ($tokens as $token) { switch($token['type']) { case TK_COLUMN_NAME: $SQLQuery .= $token['value']; break; case TK_END: break; case TK_STRING: $param = substr($token['value'], 1, -1); $params[] = strtr($param, ['\\\\' => '\\\\', '\\"' => '"']); default: $SQLQuery .= TOKEN2SQL[$token['type']]; } } return [$SQLQuery, $params]; } $query = "".'family="_\\"bîd'."u\xCC\x8A".'le\\"_" OU (((taxonomical_group="machin")))'; $tokenization = tokenize($query); $error = $tokenization['error']; if ( $error !== ERR_NONE ) { displayError($error, $query); } else { $tokens = array_filter($tokenization['tokens'], fn($token) => $token['type'] !== TK_WHITESPACES); if ( true !== $error = checkLogic($tokens) ) { displayError($error, $query); } else { $prefix = 'SELECT * FROM matable WHERE '; list($SQLQuery, $params) = buildQuery($tokens, $prefix); echo "requête: $query", PHP_EOL, "requête préparée: $SQLQuery", PHP_EOL, 'paramètres: ', print_r($params, true); // $sth = $dbh->prepare($SQLQuery); // $sth->execute($params); } }

Here you find the average performance (time & memory) of each version. A grayed out version indicates it didn't complete successfully (based on exit-code).

VersionSystem time (s)User time (s)Memory (MiB)
8.4.120.0160.00620.72
8.4.110.0050.00622.84
8.4.100.0170.00418.44
8.4.90.0110.01119.04
8.4.80.0130.00718.16
8.4.70.0060.00318.47
8.4.60.0090.01320.74
8.4.50.0110.01022.36
8.4.40.0030.00619.84
8.4.30.0070.01420.43
8.4.20.0130.00618.02
8.4.10.0060.00319.66
8.3.250.0160.00418.91
8.3.240.0160.00417.03
8.3.230.0110.00916.70
8.3.220.0040.00519.08
8.3.210.0080.00716.84
8.3.200.0060.00316.83
8.3.190.0090.00817.52
8.3.180.0110.00818.92
8.3.170.0130.00617.14
8.3.160.0130.00617.07
8.3.150.0170.00317.44
8.3.140.0030.01718.85
8.3.130.0070.00316.97
8.3.120.0160.00320.88
8.3.110.0040.00417.00
8.3.100.0060.00317.14
8.3.90.0050.00326.77
8.3.80.0060.00317.00
8.3.70.0100.01018.52
8.3.60.0100.01018.68
8.3.50.0130.00318.61
8.3.40.0150.00319.52
8.3.30.0110.00419.33
8.3.20.0080.00024.18
8.3.10.0080.00024.66
8.3.00.0050.00326.16
8.2.290.0120.00720.34
8.2.280.0070.00318.73
8.2.270.0160.00416.87
8.2.260.0160.00319.19
8.2.250.0080.00017.28
8.2.240.0070.00318.82
8.2.230.0080.00020.94
8.2.220.0060.00324.06
8.2.210.0090.00026.77
8.2.200.0030.00716.88
8.2.190.0110.00717.00
8.2.180.0060.00925.92
8.2.170.0120.00319.19
8.2.160.0110.00422.96
8.2.150.0050.00325.66
8.2.140.0000.00824.66
8.2.130.0080.00026.16
8.2.120.0030.00619.74
8.2.110.0110.00722.25
8.2.100.0040.00820.01
8.2.90.0000.00818.25
8.2.80.0000.00819.15
8.2.70.0000.00817.88
8.2.60.0060.00317.75
8.2.50.0000.00917.98
8.2.40.0040.00418.59
8.2.30.0080.00018.39
8.2.20.0050.00320.53
8.2.10.0050.00318.22
8.2.00.0040.00419.42
8.1.330.0150.00816.86
8.1.320.0050.00516.60
8.1.310.0120.00317.00
8.1.300.0040.00718.21
8.1.290.0030.00630.84
8.1.280.0070.00725.92
8.1.270.0070.00023.99
8.1.260.0040.00426.35
8.1.250.0000.00828.09
8.1.240.0070.00723.82
8.1.230.0070.00419.09
8.1.220.0040.00418.97
8.1.210.0060.00318.77
8.1.200.0080.00017.72
8.1.190.0080.00017.48
8.1.180.0040.00418.10
8.1.170.0080.00017.62
8.1.160.0030.00519.00
8.1.150.0030.00618.91
8.1.140.0000.00817.81
8.1.130.0000.00719.09
8.1.120.0000.01017.82
8.1.110.0040.00717.83
8.1.100.0030.00617.81
8.1.90.0040.00417.75
8.1.80.0000.01017.76
8.1.70.0040.00417.74
8.1.60.0030.00617.86
8.1.50.0080.00017.87
8.1.40.0060.00317.77
8.1.30.0170.00317.94
8.1.20.0190.00617.95
8.1.10.0220.00417.84
8.1.00.0240.00017.77
8.0.300.0030.00518.77
8.0.290.0060.00317.13
8.0.280.0070.00018.68
8.0.270.0040.00417.12
8.0.260.0030.00318.53
8.0.250.0000.00817.28
8.0.240.0070.00017.33
8.0.230.0040.00417.35
8.0.220.0040.00417.29
8.0.210.0000.00717.37
8.0.200.0000.00817.24
8.0.190.0040.00417.30
8.0.180.0040.00417.35
8.0.170.0030.00617.34
8.0.160.0140.00717.23
8.0.150.0150.00517.23
8.0.140.0170.00317.14
8.0.130.0100.01017.20
8.0.120.0160.00417.18
8.0.110.0090.00917.38
8.0.100.0100.01017.37
8.0.90.0120.00817.36
8.0.80.0160.00317.38
8.0.70.0140.00617.35
8.0.60.0150.00517.11
8.0.50.0140.00617.28
8.0.30.0200.00017.35
8.0.20.0160.00517.43
8.0.10.0110.00717.25
7.4.330.0030.00315.55
7.4.320.0030.00516.95
7.4.300.0030.00317.00
7.4.290.0070.00016.78
7.4.280.0180.00316.99
7.4.270.0140.00716.98
7.4.260.0160.00616.98
7.4.250.0100.01016.91
7.4.240.0210.00016.96
7.4.230.0100.00816.82
7.4.220.0140.00416.95
7.4.210.0150.00616.83
7.4.200.0150.00516.99
7.4.190.0160.00416.89
7.4.180.0130.00716.75
7.4.160.0150.00416.89
7.4.150.0140.00716.79
7.4.140.0150.00316.82
7.4.130.0170.00316.92
7.4.120.0170.00316.89
7.4.110.0140.00516.81
7.4.100.0140.00516.79
7.4.90.0170.00216.72
7.4.80.0150.00616.86
7.4.70.0150.00416.74
7.4.60.0170.00016.86
7.4.50.0180.00016.77
7.4.40.0120.00616.66
7.4.30.0160.00316.73
7.4.20.0110.00816.75
7.4.10.0140.00416.86
7.4.00.0070.01116.89

preferences:
103.68 ms | 403 KiB | 5 Q