1 | <?php |
||
8 | class Helper |
||
9 | { |
||
10 | /** |
||
11 | * KEYWORDS1. |
||
12 | * |
||
13 | * @var string |
||
14 | */ |
||
15 | const KEYWORDS1 = 'SELECT|(?:ON\s+DUPLICATE\s+KEY)?UPDATE|INSERT(?:\s+INTO)?|REPLACE(?:\s+INTO)?|DELETE|CALL|UNION|FROM|WHERE|HAVING|GROUP\s+BY|ORDER\s+BY|LIMIT|OFFSET|SET|VALUES|LEFT\s+JOIN|INNER\s+JOIN|TRUNCATE'; |
||
16 | |||
17 | /** |
||
18 | * KEYWORDS2. |
||
19 | * |
||
20 | * @var string |
||
21 | */ |
||
22 | const KEYWORDS2 = 'ALL|DISTINCT|DISTINCTROW|IGNORE|AS|USING|ON|AND|OR|IN|IS|NOT|NULL|[RI]?LIKE|REGEXP|TRUE|FALSE'; |
||
23 | |||
24 | /** |
||
25 | * Returns syntax highlighted SQL command. |
||
26 | * |
||
27 | * |
||
28 | * @param string $sql |
||
29 | * @param array $bindings |
||
30 | * @param \PDO $pdo |
||
31 | * @return string |
||
32 | */ |
||
33 | 4 | public static function hightlight($sql, array $bindings = [], PDO $pdo = null) |
|
34 | { |
||
35 | // insert new lines |
||
36 | 4 | $sql = " $sql "; |
|
37 | 4 | $sql = preg_replace('#(?<=[\\s,(])('.static::KEYWORDS1.')(?=[\\s,)])#i', "\n\$1", $sql); |
|
38 | |||
39 | // reduce spaces |
||
40 | 4 | $sql = preg_replace('#[ \t]{2,}#', ' ', $sql); |
|
41 | |||
42 | // syntax highlight |
||
43 | 4 | $sql = htmlspecialchars($sql, ENT_IGNORE, 'UTF-8'); |
|
44 | 4 | $sql = preg_replace_callback('#(/\\*.+?\\*/)|(\\*\\*.+?\\*\\*)|(?<=[\\s,(])('.static::KEYWORDS1.')(?=[\\s,)])|(?<=[\\s,(=])('.static::KEYWORDS2.')(?=[\\s,)=])#is', function ($matches) { |
|
45 | 4 | if (! empty($matches[1])) { // comment |
|
46 | 1 | return '<em style="color:gray">'.$matches[1].'</em>'; |
|
47 | 4 | } elseif (! empty($matches[2])) { // error |
|
48 | 1 | return '<strong style="color:red">'.$matches[2].'</strong>'; |
|
49 | 4 | } elseif (! empty($matches[3])) { // most important keywords |
|
50 | 4 | return '<strong style="color:blue; text-transform: uppercase;">'.$matches[3].'</strong>'; |
|
51 | 1 | } elseif (! empty($matches[4])) { // other keywords |
|
52 | 1 | return '<strong style="color:green">'.$matches[4].'</strong>'; |
|
53 | } |
||
54 | 4 | }, $sql); |
|
55 | |||
56 | 4 | $bindings = array_map(function ($binding) use ($pdo) { |
|
57 | 3 | if (is_array($binding) === true) { |
|
58 | 1 | $binding = implode(', ', array_map(function ($value) { |
|
59 | 1 | return is_string($value) === true ? htmlspecialchars('\''.$value.'\'', ENT_NOQUOTES, 'UTF-8') : $value; |
|
60 | 1 | }, $binding)); |
|
61 | |||
62 | 1 | return htmlspecialchars('('.$binding.')', ENT_NOQUOTES, 'UTF-8'); |
|
63 | } |
||
64 | |||
65 | 3 | if (is_string($binding) === true && (preg_match('#[^\x09\x0A\x0D\x20-\x7E\xA0-\x{10FFFF}]#u', $binding) || preg_last_error())) { |
|
66 | return '<i title="Length '.strlen($binding).' bytes"><binary></i>'; |
||
67 | } |
||
68 | |||
69 | 3 | if (is_string($binding) === true) { |
|
70 | 3 | $text = htmlspecialchars($pdo ? $pdo->quote($binding) : '\''.$binding.'\'', ENT_NOQUOTES, 'UTF-8'); |
|
71 | |||
72 | 3 | return '<span title="Length '.strlen($text).' characters">'.$text.'</span>'; |
|
73 | } |
||
74 | |||
75 | 1 | if (is_resource($binding) === true) { |
|
76 | 1 | $type = get_resource_type($binding); |
|
77 | 1 | if ($type === 'stream') { |
|
78 | 1 | $info = stream_get_meta_data($binding); |
|
79 | } |
||
80 | |||
81 | 1 | return '<i'.(isset($info['uri']) ? ' title="'.htmlspecialchars($info['uri'], ENT_NOQUOTES, 'UTF-8').'"' : null) |
|
82 | 1 | .'><'.htmlspecialchars($type, ENT_NOQUOTES, 'UTF-8').' resource></i>'; |
|
83 | } |
||
84 | |||
85 | 1 | if ($binding instanceof DateTime) { |
|
86 | 1 | return htmlspecialchars('\''.$binding->format('Y-m-d H:i:s').'\'', ENT_NOQUOTES, 'UTF-8'); |
|
87 | } |
||
88 | |||
89 | return htmlspecialchars($binding, ENT_NOQUOTES, 'UTF-8'); |
||
90 | 4 | }, $bindings); |
|
91 | 4 | $sql = str_replace(['%', '?'], ['%%', '%s'], $sql); |
|
92 | |||
93 | 4 | return '<div><code>'.nl2br(trim(vsprintf($sql, $bindings))).'</code></div>'; |
|
94 | } |
||
95 | |||
96 | /** |
||
97 | * perform quer analysis hint. |
||
98 | * |
||
99 | * @param string $sql |
||
100 | * @param string $version |
||
101 | * @param float $driver |
||
102 | * @return array |
||
103 | */ |
||
104 | 2 | public static function performQueryAnalysis($sql, $version = null, $driver = null) |
|
137 | |||
138 | /** |
||
139 | * explain sql. |
||
140 | * |
||
141 | * @param PDO $pdo |
||
142 | * @param string $sql |
||
143 | * @param array $bindings |
||
144 | * @return array |
||
145 | */ |
||
146 | 1 | public static function explain(PDO $pdo, $sql, $bindings = []) |
|
157 | } |
||
158 |