PluginProbe
Visualizer – Tables & Charts Manager with Built-in AI Generator / 4.0.2
Visualizer – Tables & Charts Manager with Built-in AI Generator v4.0.2
4.0.7 4.0.6 4.0.5 4.0.4 4.0.3 3.0.5 3.0.6 3.0.7 3.0.8 3.0.9 3.1.0 3.1.1 3.1.2 3.1.3 3.10.0 3.10.1 3.10.10 3.10.11 3.10.12 3.10.13 3.10.14 3.10.15 3.10.2 3.10.3 3.10.4 All 148 releases
visualizer / classes / Visualizer / Source / Query.php

Query.php in Visualizer – Tables & Charts Manager with Built-in AI Generator 4.0.2, at classes/Visualizer/Source/Query.php

307 lines 8.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 // +----------------------------------------------------------------------+
4 // | Copyright 2013 Madpixels (email : visualizer@madpixels.net) |
5 // +----------------------------------------------------------------------+
6 // | This program is free software; you can redistribute it and/or modify |
7 // | it under the terms of the GNU General Public License, version 2, as |
8 // | published by the Free Software Foundation. |
9 // | |
10 // | This program is distributed in the hope that it will be useful, |
11 // | but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 // | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
13 // | GNU General Public License for more details. |
14 // | |
15 // | You should have received a copy of the GNU General Public License |
16 // | along with this program; if not, write to the Free Software |
17 // | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, |
18 // | MA 02110-1301 USA |
19 // +----------------------------------------------------------------------+
20 // | Author: Eugene Manuilov <eugene@manuilov.org> |
21 // +----------------------------------------------------------------------+
22 /**
23 * Source manager for query builder.
24 *
25 * @category Visualizer
26 * @package Source
27 */
28 class Visualizer_Source_Query extends Visualizer_Source {
29
30 /**
31 * The query.
32 *
33 * @access protected
34 * @var string
35 */
36 protected $_query;
37
38 /**
39 * The chart id.
40 *
41 * @access protected
42 * @var int
43 */
44 protected $_chart_id;
45
46 /**
47 * Any additional parameters (e.g. for connecting to a remote db).
48 *
49 * @access protected
50 * @var array
51 */
52 protected $_params;
53
54 /**
55 * Constructor.
56 *
57 * @access public
58 * @param string $query The query.
59 * @param int $chart_id The chart id.
60 * @param array $params Any additional parameters (e.g. for connecting to a remote db).
61 */
62 public function __construct( $query = null, $chart_id = null, $params = null ) {
63 $this->_query = $this->strip_sql_comments( $query );
64 $this->_chart_id = $chart_id;
65 $this->_params = $params;
66 }
67
68 /**
69 * Strips SQL comments from the query.
70 *
71 * @param string $query The query.
72 *
73 * @return string
74 */
75 private function strip_sql_comments( $query = '' ) {
76 if ( empty( $query ) ) {
77 return $query;
78 }
79
80 // Regex https://regex101.com/r/xd5Vrg/1
81 $sql_comments_regex = '@(--[^\r\n]*)|(\#[^\r\n]*)|(/\*[\w\W]*?(?=\*/)\*/)@ms';
82 return trim( preg_replace( $sql_comments_regex, '', $query ) );
83 }
84
85 /**
86 * Fetches information from source, parses it and builds series and data arrays.
87 *
88 * @param bool $as_html Should the result be fetched as an HTML table or as an object.
89 * @param bool $results_as_numeric_array Should the result be fetched as ARRAY_N instead of ARRAY_A.
90 * @param bool $raw_results Should the result be returned without processing.
91 * @access public
92 * @return boolean TRUE on success, otherwise FALSE.
93 */
94 public function fetch( $as_html = false, $results_as_numeric_array = false, $raw_results = false ) {
95 if ( empty( $this->_query ) ) {
96 return false;
97 }
98
99 // only select queries allowed. must start with SELECT keyword.
100 if ( ! preg_match( '/^(\bselect\b)\s/i', $this->_query ) ) {
101 $this->_error = __( 'Only SELECT queries are allowed', 'visualizer' );
102 return false;
103 }
104
105 // if previous check passed, check for disallowed query parts to prevent subqueries and other harmful queries.
106 $disallow_query_parts = array(
107 'CREATE',
108 'ALTER',
109 'TRUNCATE',
110 'DROP',
111
112 'INSERT',
113 'DELETE',
114 'UPDATE',
115 'REPLACE',
116
117 'RENAME',
118 'COMMIT',
119 'ROLLBACK',
120 'MERGE',
121 'CALL',
122 'EXPLAIN',
123 'LOCK',
124 'GRANT',
125 'REVOKE',
126 'SAVEPOINT',
127 'TRANSACTION',
128 'SET',
129 );
130 $disallow_regex = implode(
131 '|',
132 array_map(
133 function ( $value ) {
134 return '\b' . $value . '\b';
135 }, $disallow_query_parts
136 )
137 );
138
139 if ( preg_match( '/(' . $disallow_regex . ')/i', $this->_query) !== 0 ) {
140 $this->_error = __( 'Only SELECT queries are allowed', 'visualizer' );
141 return false;
142 }
143
144 // impose a limit if no limit clause is provided.
145 if ( strpos( strtolower( $this->_query ), ' limit ' ) === false ) {
146 $this->_query .= ' LIMIT ' . apply_filters( 'visualizer_sql_query_limit', 1000, $this->_chart_id );
147 }
148
149 $this->_query = apply_filters( 'visualizer_db_query', $this->_query, $this->_chart_id, $this->_params );
150
151 $results = array();
152 $headers = array();
153
154 // short circuit results for remote dbs.
155 $remote_results = apply_filters( 'visualizer_db_query_execute', false, $this->_query, $as_html, $results_as_numeric_array, $raw_results, $this->_chart_id, $this->_params );
156 if ( false !== $remote_results ) {
157 $error = $remote_results['error'];
158 if ( empty( $error ) ) {
159 $results = $remote_results['results'];
160 $headers = $remote_results['headers'];
161 }
162
163 $this->_error = $error;
164
165 if ( $raw_results ) {
166 return $results;
167 }
168 }
169
170 if ( ! ( $results && $headers ) ) {
171 global $wpdb;
172 $wpdb->hide_errors();
173 // @codingStandardsIgnoreStart
174 $rows = $wpdb->get_results( $this->_query, $results_as_numeric_array ? ARRAY_N : ARRAY_A );
175 // @codingStandardsIgnoreEnd
176 $wpdb->show_errors();
177
178 if ( $raw_results ) {
179 return $rows;
180 }
181
182 if ( $wpdb->last_error ) {
183 $this->_error = $wpdb->last_error;
184 return array();
185 }
186
187 if ( $rows ) {
188 $results = array();
189 $headers = array();
190 if ( $rows ) {
191 $row_num = 0;
192 foreach ( $rows as $row ) {
193 $result = array();
194 $col_num = 0;
195 foreach ( $row as $k => $v ) {
196 $result[] = $v;
197 if ( 0 === $row_num ) {
198 $headers[] = array( 'type' => $this->get_col_type( $col_num++ ), 'label' => $k );
199 }
200 }
201 $results[] = $result;
202 ++$row_num;
203 }
204 }
205
206 $this->_error = $wpdb->last_error;
207 }
208 }
209 // Query log.
210 do_action( 'themeisle_log_event', Visualizer_Plugin::NAME, sprintf( 'Firing query %s to get results %s with error %s', $this->_query, print_r( $rows, true ), print_r( $wpdb->last_error, true ) ), 'debug', __FILE__, __LINE__ );
211
212 if ( $as_html ) {
213 $results = $this->html( $headers, $results );
214 } else {
215 $results = $this->object( $headers, $results );
216 }
217
218 return apply_filters( 'visualizer_db_query_results', $results, $headers, $as_html, $results_as_numeric_array, $raw_results, $this->_query, $this->_chart_id, $this->_params );
219 }
220
221 /**
222 * Get the data type of the column.
223 *
224 * @param int $col_num The column index in the fetched result set.
225 * @access private
226 * @return int
227 */
228 private function get_col_type( $col_num ) {
229 global $wpdb;
230 switch ( $wpdb->get_col_info( 'type', $col_num ) ) {
231 case 0:
232 case 5:
233 case 4:
234 case 9:
235 case 3:
236 case 2:
237 case 246:
238 case 8:
239 // numeric.
240 return 'number';
241 case 10:
242 case 12:
243 case 14:
244 // date.
245 return 'date';
246 }
247 return 'string';
248 }
249
250 /**
251 * Returns the HTML output.
252 *
253 * @param array $headers The headers of the result set.
254 * @param array $results The data of the result set.
255 * @access private
256 * @return string
257 */
258 private function html( $headers, $results ) {
259 return Visualizer_Render_Layout::show( 'db-wizard-results', $headers, $results );
260 }
261
262 /**
263 * Sets the series and data.
264 *
265 * @param array $headers The headers of the result set.
266 * @param array $results The data of the result set.
267 * @access private
268 * @return bool
269 */
270 private function object( $headers, $results ) {
271 $series = array();
272 foreach ( $headers as $header ) {
273 $series[] = $header;
274 }
275 $this->_series = $series;
276
277 $data = array();
278 foreach ( $results as $row ) {
279 $data[] = $this->_normalizeData( $row );
280 }
281 $this->_data = $data;
282 return $this->_data;
283 }
284
285 /**
286 * Returns the final query.
287 *
288 * @access public
289 * @return string
290 */
291 public function get_query() {
292 return $this->_query;
293 }
294
295 /**
296 * Returns source name.
297 *
298 * @since 1.0.0
299 *
300 * @access public
301 * @return string The name of source.
302 */
303 public function getSourceName() {
304 return __CLASS__;
305 }
306 }
307