If you work in a large development team on the same project, then refactoring becomes a very difficult task. Here is an example: we want to rename the do_something () function to do_something_with_blackjack (). We renamed all occurrences of this function in our branch and sent the task for testing. At the same time, someone else added another function call, but with the old name, also in its branch. Individually, the changesets will work, but after the merge, you get an error.<?php -function do_something() +function print_hello() { echo "Hello world!\n"; } $a = 1; -do_something(); +print_hello(); $b = 2; $c = 3; <?php function do_something() { echo "Hello world!\n"; } $a = 1; do_something(); $b = 2; +do_something(); $c = 3; <?php function print_hello() { echo "Hello world!\n"; } $a = 1; print_hello(); $b = 2; do_something(); $c = 3; #!/bin/sh grep do_something file.php #!/bin/sh sed -i 's/do_something/print_hello/g' file.php $func_prefix = "do_"; $func_name = $func_prefix . "something"; // , PHP , $func_name(); function do_something() { error_log(__FUNCTION__ . " found. Trace: " . (new Exception())); return print_hello(); } $ ls includes/db db_tools.php index.htm mssqlnative.php oracle.php dbal.php mssql.php mysql.php postgres.php firebird.php mssql_odbc.php mysqli.php sqlite.php $ grep -RF 'sql_query(' * | wc -l 1611 function sql_query($query = '', $cache_ttl = 0) … $sql = 'SELECT forum_id FROM ' . TOPICS_TABLE . " WHERE topic_id = $topic_id"; $result = $db->sql_query($sql); $sql = 'SELECT forum_id FROM ' . TOPICS_TABLE . ' WHERE topic_id = ?d'; $result = $db->sql_query_escaped($sql, $topic_id); /** * Execute escaped SQL query * * First parameter, $query_template is the SQL template that has the following placeholders: * * ?d - value is integer * ?s - value is string (escaped by default) * ?a - array of integers for usage like IN(?a) * ?r - raw SQL (eg for use in dynamic part of SQL expression) * * Example: * * sql_query_escaped("SELECT * FROM table WHERE table_id = ?d", 42) will be executed as * * SELECT * FROM table WHERE table_id = 42 * * sql_query_escaped("SELECT * FROM table WHERE table_id IN(?a)", array(1, 2, 3)) will be executed as * * SELECT * FROM table WHERE table_id IN(1, 2, 3) * */ function sql_query_escaped($query_template) { $values = func_get_args(); array_shift($values); $regexp = '/\\?[dsar]/s'; preg_match_all($regexp, $query_template, $matches); foreach ($matches[0] as $i => $m) { if ($m == '?d') $values[$i] = intval($values[$i]); else if ($m == '?s') $values[$i] = "'" . $this->sql_escape($values[$i]) . "'"; else if ($m == '?a') $values[$i] = implode(',', array_map('intval', $values[$i])); } $idx = 0; $replace_func = function($placeholder) use ($values, &$idx) { $placeholder = $placeholder[0]; return $values[$idx++]; }; $query = preg_replace_callback($regexp, $replace_func, $query_template); return $this->sql_query($query); } --- a/includes/db/mysqli.php +++ b/includes/db/mysqli.php @@ -151,6 +151,8 @@ class dbal_mysqli extends dbal return true; } + var $queries = array(); + /** * Base query method * @@ -162,6 +164,7 @@ class dbal_mysqli extends dbal */ function sql_query($query = '', $cache_ttl = 0) { + $this->queries[] = $query; if ($query != '') { global $cache; --- a/includes/functions.php +++ b/includes/functions.php @@ -4735,6 +4735,10 @@ function page_footer($run_cron = true) } $debug_output .= ' | <a href="' . build_url() . '&explain=1">Explain</a>'; + + foreach ($db->queries as $query) { + $debug_output .= "<pre style='text-align: left; margin-bottom: 10px;'>" . htmlspecialchars($query) . "</pre>\n<hr/>\n"; + } } } $ grep -RF 'sql_query(' * | less $ grep -RF 'sql_query(' * | grep -vF '$db->sql_query(' <?php // , : $files = exec('grep -RF \'$db->sql_query(\' * | awk -F: \'{print $1;}\'', $out, $retval); if ($retval) exit(1); // replacer/ $excludes = array('includes/db/', 'replacer/'); $num_lines = 0; foreach (array_unique($out) as $filename) { foreach ($excludes as $excl) { if (strpos($filename, $excl) === 0) continue(2); } $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 = ''; // 5 : '$db', '->', 'sql_query', '(' // «» $accepted_value_types = array(T_CONSTANT_ENCAPSED_STRING, T_ENCAPSED_AND_WHITESPACE, '"'); 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; parse_token($tokens[$i++], $type, $text, $ln); if ($type !== '(') continue; parse_token($tokens[$i++], $type, $text, $ln); if (!in_array($type, $accepted_value_types, true)) continue; // : , $depth = 1; $query = ''; for ($i = $i - 1; $i < $num; $i++) { parse_token($tokens[$i], $type, $text, $ln); if ($type === '(') $depth++; else if ($type === ')') $depth--; if ($depth == 0) break; $query .= $text; } $query = preg_replace(array("/[\t ]+/s", '/^/m'), array(' ', ' '), $query); $results[$filename][] = $query; $num_lines++; } } foreach ($results as $filename => $list) { echo "$filename\n"; foreach ($list as $row) echo "$row\n"; echo "\n"; } echo "Total lines recognized: $num_lines\n"; // . token_get_all function parse_token($tok, &$type, &$text, &$line) { if (is_array($tok)) list($type, $text, $line) = $tok; else $type = $text = $tok; } includes/acp/acp_attachments.php 'INSERT INTO ' . EXTENSIONS_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary) includes/acp/acp_bbcodes.php 'INSERT INTO ' . BBCODES_TABLE . $db->sql_build_array('INSERT', $sql_ary) $ grep -A 5 -B 5 -RF '$db->sql_query($sql' * | less $sql = '...'; // $db->sql_query($sql); <?php // , $files = exec('grep -RF \'$db->sql_query($sql\' * | awk -F: \'{print $1;}\'', $out, $retval); if ($retval) exit(1); // replacer/ $excludes = array('includes/db/', 'replacer/'); $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 = ''; // 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; parse_token($tokens[$i++], $type, $text, $ln); if ($type !== '(') continue; parse_token($tokens[$i++], $type, $text, $ln); if ($type !== T_VARIABLE || $text !== '$sql') continue; // . grep printf("%6d %s\n", $line, ltrim($lines[$line - 1])); $positions = find_dollar_sql_assignment($tokens, $cur_idx); if (!is_array($positions)) { echo " $positions\n\n"; continue; } $query = ''; for ($i = $positions['begin']; $i <= $positions['end']; $i++) { parse_token($tokens[$i], $type, $text, $ln); $query .= $text; } $query = preg_replace(array("/[\t ]+/s", '/^/m'), array(' ', ' '), $query); echo "\n" . $query . "\n\n"; $num_lines++; } echo "\n"; } echo "Total lines recognized: $num_lines\n"; // . token_get_all function parse_token($tok, &$type, &$text, &$line) { if (is_array($tok)) list($type, $text, $line) = $tok; else $type = $text = $tok; } // $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__; } cron.php 59 $db->sql_query($sql); 'UPDATE ' . CONFIG_TABLE . " SET config_value = '" . $db->sql_escape(CRON_ID) . "' WHERE config_name = 'cron_lock' AND config_value = '" . $db->sql_escape($config['cron_lock']) . "'" … includes/acp/acp_forums.php 243 $result = $db->sql_query($sql); 'SELECT * FROM ' . FORUMS_TABLE . " WHERE forum_id = $forum_id" ... 1096 $db->sql_query($sql); 'DELETE FROM ' . FORUMS_TABLE . ' WHERE ' . $db->sql_in_set('forum_id', $forum_ids) includes/acp/acp_reasons.php ... 96 $result = $db->sql_query($sql); 'SELECT reason_id FROM ' . REPORTS_REASONS_TABLE . " WHERE reason_title = '" . $db->sql_escape($reason_row['reason_title']) . "'" ... includes/acp/acp_search.php 320 $result = $db->sql_query($sql); 'SELECT post_id, poster_id, forum_id FROM ' . POSTS_TABLE . ' WHERE post_id >= ' . (int) ($post_counter + 1) . ' AND post_id <= ' . (int) ($post_counter + $this->batch_size) $sql = /* */ 'SELECT user_id, author_id FROM ' . PRIVMSGS_TO_TABLE . ' WHERE msg_id = ' . $attachment['post_msg_id'] /* */; $result = $db->sql_query($sql); // $sql = 'SELECT user_id, author_id FROM ' . PRIVMSGS_TO_TABLE . ' WHERE msg_id = ?d'; $result = $db->sql_query_escaped($sql, $attachment['post_msg_id']); function rewrite_tokens($in_tokens) { static $string_types = array(T_CONSTANT_ENCAPSED_STRING, T_ENCAPSED_AND_WHITESPACE, '"'); $type = $text = null; $line = 1; // , , , , : // ($action == 'add') ? 'INSERT INTO ' . EXTENSION_GROUPS_TABLE . ' ' : 'UPDATE ' . EXTENSION_GROUPS_TABLE . ' SET ' parse_token($in_tokens[0], $type, $text, $line); if ($type === T_WHITESPACE) parse_token($in_tokens[1], $type, $text, $line); if (!in_array($type, $string_types, true)) return "Expected first token to be string (got $type)"; $out_params = $out_tokens = array(); // , : // // 'SELECT * FROM ' . TABLE_SOMETHING . ' WHERE lang_id = ' . intval($lang_id) // // // // array(array('SELECT * FROM ', TABLE_SOMETHING), array(' WHERE lang_id = ', intval($lang_id))) // // , , $state = 'begin'; $left_tokens = $right_tokens = $groups = array(); $depth = 0; // foreach ($in_tokens as $tok) { parse_token($tok, $type, $text, $line); if ($type === '(') $depth++; else if ($type === ')') $depth--; if ($depth < 0) return "Brace depth less than zero"; if ($state == 'begin') { // «» , if ($depth > 0 || $type !== '.') { $left_tokens[] = $tok; } else { $state = 'end'; } } else { // , $groups if ($depth > 0 || $type !== '.') { $right_tokens[] = $tok; } else { $state = 'begin'; $groups[] = array($left_tokens, $right_tokens); $left_tokens = $right_tokens = array(); } } } // - , if (count($left_tokens)) $groups[] = array($left_tokens, $right_tokens); foreach ($groups as $grp) { list($left_tokens, $right_tokens) = $grp; // , parse_token($left_tokens[0], $type, $text, $line); if ($type === T_WHITESPACE) parse_token($left_tokens[1], $type, $text, $line); if (!in_array($type, $string_types, true)) return "first token in a group is not string"; // , foreach ($left_tokens as $tok) { parse_token($left_tokens[0], $type, $text, $line); $out_tokens[] = $tok; } if (!count($right_tokens)) break; $out_tokens[] = '.'; // - *_TABLE, , $param = tokens_to_string($right_tokens); if (preg_match('/^\\s*([A-Z0-9_]+)_TABLE\\s*$/s', $param)) { foreach ($right_tokens as $tok) $out_tokens[] = $tok; } else { // '?r', «» $out_tokens[] = array(T_CONSTANT_ENCAPSED_STRING, "'?r'", $line); $out_params[] = $param; } $out_tokens[] = '.'; } // , // , syntax error parse_token(end($out_tokens), $type, $text, $line); if ($type === '.') array_pop($out_tokens); return array( 'tokens' => $out_tokens, 'params' => $out_params, ); } function tokens_to_string($tokens) { $str = ''; $type = $text = null; $line = 1; foreach ($tokens as $tok) { parse_token($tok, $type, $text, $line); $str .= $text; } $str = preg_replace(array("/[\t ]+/s", '/^/m'), array(' ', ' '), $str); return $str; } $sql = 'UPDATE ' . CONFIG_TABLE . " SET config_value = '" .'?r'. "' WHERE config_name = 'cron_lock' AND config_value = '" .'?r'. "'"; $db->sql_query_escaped($sql, $db->sql_escape(CRON_ID), $db->sql_escape($config['cron_lock'])); $sql = 'UPDATE ' . CONFIG_TABLE . " - SET config_value = '" . $db->sql_escape(CRON_ID) . "' - WHERE config_name = 'cron_lock' AND config_value = '" . $db->sql_escape($config['cron_lock']) . "'"; -$db->sql_query($sql); + SET config_value = '" .'?r'. "' + WHERE config_name = 'cron_lock' AND config_value = '" .'?r'. "'"; +$db->sql_query_escaped($sql, $db->sql_escape(CRON_ID), $db->sql_escape($config['cron_lock'])); - $db->sql_query('UPDATE ' . CONFIG_TABLE . ' SET config_value = ' . $sql_update . " WHERE config_name = '" . $db->sql_escape($config_name) . "'"); + $db->sql_query_escaped('UPDATE ' . CONFIG_TABLE . ' SET config_value = ' .'?r'. " WHERE config_name = '" .'?r'. "'", $sql_update, $db->sql_escape($config_name)); $ grep -RF 'sql_query(' * | wc -l 335 "... '?r' ..." , "... ?s ..." ;Source: https://habr.com/ru/post/167337/
All Articles