Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- <?php
- require(__DIR__ . '/rewrite.php');
- // Для начала, оставим только те файлы, которые содержат паттерн, который мы собираемся заменять
- $files = exec('grep -RF \'$db->sql_query($sql\' * | awk -F: \'{print $1;}\'', $out, $retval);
- if ($retval) exit(1);
- $num_lines = 0;
- foreach (array_unique($out) as $filename) {
- foreach ($excludes as $excl) {
- if (strpos($filename, $excl) === 0) continue(2);
- }
- echo "$filename\n";
- $contents = file_get_contents($filename);
- if ($contents === false) exit(1);
- $lines = explode("\n", $contents);
- // Получаем массив всех токенов в файле
- $tokens = token_get_all($contents);
- $num = count($tokens);
- $line = 1;
- $type = $text = '';
- $result_tokens = $tokens;
- // Нам нужно найти 5 идущих подряд токенов: '$db', '->', 'sql_query', '(' и '$sql'
- foreach ($tokens as $cur_idx => $tok) {
- parse_token($tok, $type, $text, $line);
- // Пропускаем токены в самом конце, где точно не могут уместиться наши 5 токенов
- if ($cur_idx >= $num - 5) continue;
- $ln = $line;
- $i = $cur_idx + 1;
- // Список токенов доступен в документации (http://php.net/manual/tokens.php)
- if ($type !== T_VARIABLE || $text !== '$db') continue;
- parse_token($tokens[$i++], $type, $text, $ln);
- if ($type !== T_OBJECT_OPERATOR || $text !== '->') continue;
- parse_token($tokens[$i++], $type, $text, $ln);
- if ($type !== T_STRING || $text !== 'sql_query') continue;
- $sql_query_idx = $i - 1;
- parse_token($tokens[$i++], $type, $text, $ln);
- if ($type !== '(') continue;
- parse_token($tokens[$i++], $type, $text, $ln);
- if ($type !== T_VARIABLE || $text !== '$sql') continue;
- $dollar_sql_idx = $i - 1;
- $positions = find_dollar_sql_assignment($tokens, $cur_idx);
- if (!is_array($positions)) {
- echo " $positions\n";
- continue;
- }
- $query_tokens = array();
- for ($i = $positions['begin']; $i <= $positions['end']; $i++) {
- parse_token($tokens[$i], $type, $text, $ln);
- $query_tokens[] = $tokens[$i];
- }
- $rewrite_result = rewrite_tokens($query_tokens);
- if (!is_array($rewrite_result)) {
- echo " Error: $rewrite_result\n";
- } else {
- for ($i = $positions['begin']; $i <= $positions['end']; $i++) {
- parse_token($tokens[$i], $type, $text, $ln);
- if ($i > $positions['begin']) unset($result_tokens[$i]);
- }
- $result_tokens[$sql_query_idx] = 'sql_query_escaped';
- $result_tokens[$positions['begin']] = tokens_to_string($rewrite_result['tokens'], true);
- $result_tokens[$dollar_sql_idx] = '$sql';
- foreach ($rewrite_result['params'] as $par) $result_tokens[$dollar_sql_idx] .= ', ' . trim($par);
- $num_lines++;
- }
- }
- file_put_contents($filename, tokens_to_string($result_tokens, true));
- exec("php -l " . escapeshellarg($filename), $out, $retval);
- if ($retval) {
- fwrite(STDERR, "PHP Syntax error in $filename\n");
- exit(1);
- }
- }
- echo "Total lines recognized: $num_lines\n";
- // Найти $sql = '...'; перед $db->sql_query($sql
- function find_dollar_sql_assignment($tokens, $db_idx)
- {
- $depth = 0;
- $line = 1;
- $type = $text = '';
- // Пройдемся по предыдущим токенам и найдем упоминания $sql
- for ($idx = $db_idx - 1; $idx > 0; $idx--) {
- parse_token($tokens[$idx], $type, $text, $line);
- // учет вложенности скобок
- if ($type === ')') $depth++;
- else if ($type === '(') $depth--;
- if ($depth < 0) {
- return "depth < 0 on line " . __LINE__;
- }
- /*
- Мы ничего не можем сделать в случаях следующего вида, поэтому
- их нужно определять и пропускать:
- if (...) {
- $sql = 'SELECT * FROM Table1 WHERE user_id = $user_id';
- } else {
- $sql = 'SELECT * FROM Table2';
- }
- $result = $db->sql_query($sql);
- */
- if ($type === '{' || $type === '}') {
- return "open/close brace found on line " . __LINE__;
- }
- if ($type === T_VARIABLE && $text === '$sql') {
- $i = $idx + 1;
- parse_token($tokens[$i++], $type, $text, $line);
- if ($type === T_WHITESPACE) parse_token($tokens[$i++], $type, $text, $line);
- if ($type !== '=') continue;
- // мы нашли "$sql = " !
- $begin_pos = $i;
- break;
- }
- }
- // Мы уже нашли начало присваивания "$sql = ", теперь нужно найти конец
- // Будем считать, что выражение у нас всегда оканчивается на ";"
- $depth = 0;
- for ($idx = $begin_pos; $idx < $db_idx; $idx++) {
- parse_token($tokens[$idx], $type, $text, $line);
- if ($type === '(') $depth++;
- else if ($type === ')') $depth--;
- if ($depth < 0) {
- return "depth < 0 on line " . __LINE__;
- }
- if ($depth === 0 && $type === ';') {
- return array('begin' => $begin_pos, 'end' => $idx - 1);
- }
- }
- // Если цикл закончился, значит между найденным нами началом и $db->sql_query нет ";"
- // То есть, наше предположение было неверно
- return "Statement does not terminate on line " . __LINE__;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement