PluginProbe
Visualizer – Tables & Charts Manager with Built-in AI Generator / 3.10.13
Visualizer – Tables & Charts Manager with Built-in AI Generator v3.10.13
4.0.8 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 All 149 releases
← All changes | classes/Visualizer/Source/Query.php +118 -43 3.1.03.10.13 View file →
@@ -35,23 +35,35 @@
35 35 */
36 36 protected $_query;
37 37
38 38 /**
39 - * The error message.
39 + * The chart id.
40 40 *
41 41 * @access protected
42 - * @var string
42 + * @var int
43 43 */
44 - protected $_error;
44 + protected $_chart_id;
45 45
46 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 + /**
47 55 * Constructor.
48 56 *
49 57 * @access public
50 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).
51 61 */
52 - public function __construct( $query = null ) {
62 + public function __construct( $query = null, $chart_id = null, $params = null ) {
53 63 $this->_query = $query;
64 + $this->_chart_id = $chart_id;
65 + $this->_params = $params;
54 66 }
55 67
56 68 /**
57 69 * Fetches information from source, parses it and builds series and data arrays.
@@ -56,55 +68,129 @@
56 68 /**
57 69 * Fetches information from source, parses it and builds series and data arrays.
58 70 *
59 71 * @param bool $as_html Should the result be fetched as an HTML table or as an object.
72 + * @param bool $results_as_numeric_array Should the result be fetched as ARRAY_N instead of ARRAY_A.
73 + * @param bool $raw_results Should the result be returned without processing.
60 74 * @access public
61 75 * @return boolean TRUE on success, otherwise FALSE.
62 76 */
63 - public function fetch( $as_html = false ) {
77 + public function fetch( $as_html = false, $results_as_numeric_array = false, $raw_results = false ) {
64 78 if ( empty( $this->_query ) ) {
65 79 return false;
66 80 }
67 81
82 + // only select queries allowed.
83 + if ( ! preg_match( '/\s*(\bselect\b)\s/i', $this->_query ) ) {
84 + $this->_error = __( 'Only SELECT queries are allowed', 'visualizer' );
85 + return false;
86 + }
87 +
88 + // if previous check passed, check for disallowed query parts to prevent subqueries and other harmful queries.
89 + $disallow_query_parts = array(
90 + 'INSERT',
91 + 'UPDATE',
92 + 'DELETE',
93 + 'RENAME',
94 + 'DROP',
95 + 'CREATE',
96 + 'TRUNCATE',
97 + 'ALTER',
98 + 'COMMIT',
99 + 'ROLLBACK',
100 + 'MERGE',
101 + 'CALL',
102 + 'EXPLAIN',
103 + 'LOCK',
104 + 'GRANT',
105 + 'REVOKE',
106 + 'SAVEPOINT',
107 + 'TRANSACTION',
108 + 'SET',
109 + );
110 + $disallow_regex = implode(
111 + '|',
112 + array_map(
113 + function ( $value ) {
114 + return '\b' . $value . '\b';
115 + }, $disallow_query_parts
116 + )
117 + );
118 +
119 + if ( preg_match( '/(' . $disallow_regex . ')/i', $this->_query) !== 0 ) {
120 + $this->_error = __( 'Only SELECT queries are allowed', 'visualizer' );
121 + return false;
122 + }
123 +
68 124 // impose a limit if no limit clause is provided.
69 125 if ( strpos( strtolower( $this->_query ), ' limit ' ) === false ) {
70 - $this->_query .= ' LIMIT ' . apply_filters( 'visualizer_sql_query_limit', 300 );
126 + $this->_query .= ' LIMIT ' . apply_filters( 'visualizer_sql_query_limit', 1000, $this->_chart_id );
71 127 }
72 128
73 - global $wpdb;
74 - $wpdb->hide_errors();
75 - // @codingStandardsIgnoreStart
76 - $rows = $wpdb->get_results( $this->_query, ARRAY_A );
77 - // @codingStandardsIgnoreEnd
78 - $wpdb->show_errors();
129 + $this->_query = apply_filters( 'visualizer_db_query', $this->_query, $this->_chart_id, $this->_params );
79 130
80 - if ( $rows ) {
81 - $results = array();
82 - $headers = array();
131 + $results = array();
132 + $headers = array();
133 +
134 + // short circuit results for remote dbs.
135 + if ( false !== ( $remote_results = apply_filters( 'visualizer_db_query_execute', false, $this->_query, $as_html, $results_as_numeric_array, $raw_results, $this->_chart_id, $this->_params ) ) ) {
136 + $error = $remote_results['error'];
137 + if ( empty( $error ) ) {
138 + $results = $remote_results['results'];
139 + $headers = $remote_results['headers'];
140 + }
141 +
142 + $this->_error = $error;
143 +
144 + if ( $raw_results ) {
145 + return $results;
146 + }
147 + }
148 +
149 + if ( ! ( $results && $headers ) ) {
150 + global $wpdb;
151 + $wpdb->hide_errors();
152 + // @codingStandardsIgnoreStart
153 + $rows = $wpdb->get_results( $this->_query, $results_as_numeric_array ? ARRAY_N : ARRAY_A );
154 + // @codingStandardsIgnoreEnd
155 + $wpdb->show_errors();
156 +
157 + if ( $raw_results ) {
158 + return $rows;
159 + }
160 +
83 161 if ( $rows ) {
84 - $row_num = 0;
85 - foreach ( $rows as $row ) {
86 - $result = array();
87 - $col_num = 0;
88 - foreach ( $row as $k => $v ) {
89 - $result[] = $v;
90 - if ( 0 === $row_num ) {
91 - $headers[] = array( 'type' => $this->get_col_type( $col_num++ ), 'label' => $k );
162 + $results = array();
163 + $headers = array();
164 + if ( $rows ) {
165 + $row_num = 0;
166 + foreach ( $rows as $row ) {
167 + $result = array();
168 + $col_num = 0;
169 + foreach ( $row as $k => $v ) {
170 + $result[] = $v;
171 + if ( 0 === $row_num ) {
172 + $headers[] = array( 'type' => $this->get_col_type( $col_num++ ), 'label' => $k );
173 + }
92 174 }
175 + $results[] = $result;
176 + $row_num++;
93 177 }
94 - $results[] = $result;
95 - $row_num++;
96 178 }
179 +
180 + $this->_error = $wpdb->last_error;
97 181 }
182 + }
183 + // Query log.
184 + 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__ );
98 185
99 - if ( $as_html ) {
100 - return $this->html( $headers, $results );
101 - }
102 - return $this->object( $headers, $results );
186 + if ( $as_html ) {
187 + $results = $this->html( $headers, $results );
188 + } else {
189 + $results = $this->object( $headers, $results );
103 190 }
104 191
105 - $this->_error = $wpdb->last_error;
106 - return null;
192 + return apply_filters( 'visualizer_db_query_results', $results, $headers, $as_html, $results_as_numeric_array, $raw_results, $this->_query, $this->_chart_id, $this->_params );
107 193 }
108 194
109 195 /**
110 196 * Get the data type of the column.
@@ -166,20 +252,9 @@
166 252 foreach ( $results as $row ) {
167 253 $data[] = $this->_normalizeData( $row );
168 254 }
169 255 $this->_data = $data;
170 -
171 - return true;
172 - }
173 -
174 - /**
175 - * Returns the error, if any.
176 - *
177 - * @access public
178 - * @return string
179 - */
180 - public function get_error() {
181 - return $this->_error;
256 + return $this->_data;
182 257 }
183 258
184 259 /**
185 260 * Returns the final query.