PluginProbe
Visualizer – Tables & Charts Manager with Built-in AI Generator / 4.0.8
Visualizer – Tables & Charts Manager with Built-in AI Generator v4.0.8
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 +67 -5 3.10.104.0.8 View file →
@@ -59,14 +59,31 @@
59 59 * @param int $chart_id The chart id.
60 60 * @param array $params Any additional parameters (e.g. for connecting to a remote db).
61 61 */
62 62 public function __construct( $query = null, $chart_id = null, $params = null ) {
63 - $this->_query = $query;
63 + $this->_query = $this->strip_sql_comments( $query );
64 64 $this->_chart_id = $chart_id;
65 65 $this->_params = $params;
66 66 }
67 67
68 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 + /**
69 86 * Fetches information from source, parses it and builds series and data arrays.
70 87 *
71 88 * @param bool $as_html Should the result be fetched as an HTML table or as an object.
72 89 * @param bool $results_as_numeric_array Should the result be fetched as ARRAY_N instead of ARRAY_A.
@@ -78,14 +95,53 @@
78 95 if ( empty( $this->_query ) ) {
79 96 return false;
80 97 }
81 98
82 - // only select queries allowed.
83 - if ( preg_match( '/^\s*(insert|delete|update|replace|create|alter|drop|truncate)\s/i', $this->_query ) ) {
99 + // only select queries allowed. must start with SELECT keyword.
100 + if ( ! preg_match( '/^(\bselect\b)\s/i', $this->_query ) ) {
84 101 $this->_error = __( 'Only SELECT queries are allowed', 'visualizer' );
85 102 return false;
86 103 }
87 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 +
88 144 // impose a limit if no limit clause is provided.
89 145 if ( strpos( strtolower( $this->_query ), ' limit ' ) === false ) {
90 146 $this->_query .= ' LIMIT ' . apply_filters( 'visualizer_sql_query_limit', 1000, $this->_chart_id );
91 147 }
@@ -95,9 +151,10 @@
95 151 $results = array();
96 152 $headers = array();
97 153
98 154 // short circuit results for remote dbs.
99 - 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 ) ) ) {
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 ) {
100 157 $error = $remote_results['error'];
101 158 if ( empty( $error ) ) {
102 159 $results = $remote_results['results'];
103 160 $headers = $remote_results['headers'];
@@ -121,8 +178,13 @@
121 178 if ( $raw_results ) {
122 179 return $rows;
123 180 }
124 181
182 + if ( $wpdb->last_error ) {
183 + $this->_error = $wpdb->last_error;
184 + return array();
185 + }
186 +
125 187 if ( $rows ) {
126 188 $results = array();
127 189 $headers = array();
128 190 if ( $rows ) {
@@ -136,9 +198,9 @@
136 198 $headers[] = array( 'type' => $this->get_col_type( $col_num++ ), 'label' => $k );
137 199 }
138 200 }
139 201 $results[] = $result;
140 - $row_num++;
202 + ++$row_num;
141 203 }
142 204 }
143 205
144 206 $this->_error = $wpdb->last_error;