PluginProbe
Charitable – Donation & Fundraising Platform (Donation Forms, Recurring Donations & Fundraising Campaigns) / 1.8.13
Charitable – Donation & Fundraising Platform (Donation Forms, Recurring Donations & Fundraising Campaigns) v1.8.13
1.8.13 1.8.12.3 1.8.12.2 1.8.12.1 1.8.12 1.8.11.3 1.8.11.2 1.8.11.1 1.8.11 1.6.6 1.6.60 1.6.7 1.6.8 1.6.9 1.7.0 1.7.0.1 1.7.0.11 1.7.0.12 1.7.0.14 1.7.0.2 1.7.0.3 1.7.0.5 1.7.0.6 1.7.0.7 1.7.0.9 All 211 releases
← All changes | includes/abstracts/abstract-class-charitable-db.php +97 -12 1.7.0.2 → 1.8.13 View file →
@@ -6,14 +6,16 @@
6 6 * https://github.com/easydigitaldownloads/Easy-Digital-Downloads/blob/master/includes/class-edd-db.php
7 7 *
8 8 * @package Charitable/Classes/Charitable_DB
9 9 * @author David Bisset
10 - * @copyright Copyright (c) 2022, WP Charitable LLC
10 + * @copyright Copyright (c) 2023, WP Charitable LLC
11 11 * @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
12 12 * @since 1.0.0
13 - * @version 1.5.11
13 + * @version 1.8.9.1
14 14 */
15 15
16 +// phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared,WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare
17 +
16 18 // Exit if accessed directly.
17 19 if ( ! defined( 'ABSPATH' ) ) {
18 20 exit;
19 21 }
@@ -83,8 +85,9 @@
83 85 /**
84 86 * Return the format for the given column.
85 87 *
86 88 * @since 1.0.0
89 + * @version 1.8.9.1
87 90 *
88 91 * @param string $column The column to get the format for.
89 92 * @return %s, %d or %f
90 93 */
@@ -91,22 +94,39 @@
91 94 public function get_column_format( $column ) {
92 95 $columns = $this->get_columns();
93 96 $format = isset( $columns[ $column ] ) ? $columns[ $column ] : false;
94 97
95 - // If the column isn't found, throw an exception.
96 - if ( false === $format ) {
97 - throw new Exception( sprintf( 'Invalid column passed %s', $column ) );
98 - }
98 + // If the column isn't found, throw an exception.
99 + if ( false === $format ) {
100 + throw new Exception( sprintf( 'Invalid column passed %s', esc_html( $column ) ) );
101 + }
99 102
100 - // If the column format isn't valid, throw an exception.
101 - if ( ! in_array( $format, array( '%s', '%d', '%f' ) ) ) {
102 - throw new Exception( sprintf( 'Invalid column format for column %s. Format returned %s', $column, $format ) );
103 - }
103 + // If the column format isn't valid, throw an exception.
104 + if ( ! in_array( $format, array( '%s', '%d', '%f' ) ) ) {
105 + throw new Exception( sprintf( 'Invalid column format for column %s. Format returned %s', esc_html( $column ), esc_html( $format ) ) );
106 + }
104 107
105 108 return $format;
106 109 }
107 110
108 111 /**
112 + * Validate that a column name exists in the table schema.
113 + *
114 + * @since 1.8.8.6
115 + *
116 + * @param string $column The column name to validate.
117 + * @return string The validated column name.
118 + * @throws Exception If column is invalid.
119 + */
120 + protected function validate_column_name( $column ) {
121 + $columns = $this->get_columns();
122 + if ( ! isset( $columns[ $column ] ) ) {
123 + throw new Exception( sprintf( 'Invalid column passed %s', esc_html( $column ) ) );
124 + }
125 + return $column;
126 + }
127 +
128 + /**
109 129 * Retrieve a row by the primary key
110 130 *
111 131 * @since 1.0.0
112 132 *
@@ -114,8 +134,11 @@
114 134 */
115 135 public function get( $row_id ) {
116 136 global $wpdb;
117 137
138 + // phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,PluginCheck.Security.DirectDB.UnescapedDBParameter
139 + // Direct database queries are expected in this database abstraction class.
140 + // $this->table_name and $this->primary_key are class properties set at initialization and validated.
118 141 return $wpdb->get_row(
119 142 $wpdb->prepare(
120 143 "SELECT * FROM $this->table_name WHERE $this->primary_key = %d LIMIT 1;",
121 144 $row_id
@@ -120,8 +143,9 @@
120 143 "SELECT * FROM $this->table_name WHERE $this->primary_key = %d LIMIT 1;",
121 144 $row_id
122 145 )
123 146 );
147 + // phpcs:enable WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,PluginCheck.Security.DirectDB.UnescapedDBParameter
124 148 }
125 149
126 150 /**
127 151 * Retrieve a row by a specific column / value
@@ -131,8 +155,14 @@
131 155 */
132 156 public function get_by( $column, $row_id ) {
133 157 global $wpdb;
134 158
159 + // Validate column name before use.
160 + $column = $this->validate_column_name( $column );
161 +
162 + // phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,PluginCheck.Security.DirectDB.UnescapedDBParameter
163 + // Direct database queries are expected in this database abstraction class.
164 + // $column is validated above via validate_column_name(), $this->table_name is a class property set at initialization.
135 165 return $wpdb->get_row(
136 166 $wpdb->prepare(
137 167 "SELECT * FROM $this->table_name WHERE $column = {$this->get_column_format($column)} LIMIT 1;",
138 168 $row_id
@@ -137,8 +167,9 @@
137 167 "SELECT * FROM $this->table_name WHERE $column = {$this->get_column_format($column)} LIMIT 1;",
138 168 $row_id
139 169 )
140 170 );
171 + // phpcs:enable WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching
141 172 }
142 173
143 174 /**
144 175 * Retrieve a specific column's value by the primary key.
@@ -149,8 +180,14 @@
149 180 */
150 181 public function get_column( $column, $row_id ) {
151 182 global $wpdb;
152 183
184 + // Validate column name before use.
185 + $column = $this->validate_column_name( $column );
186 +
187 + // phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,PluginCheck.Security.DirectDB.UnescapedDBParameter
188 + // Direct database queries are expected in this database abstraction class.
189 + // $column is validated above via validate_column_name(), $this->table_name and $this->primary_key are class properties set at initialization.
153 190 return $wpdb->get_var(
154 191 $wpdb->prepare(
155 192 "SELECT $column FROM $this->table_name WHERE $this->primary_key = %d LIMIT 1;",
156 193 $row_id
@@ -155,8 +192,9 @@
155 192 "SELECT $column FROM $this->table_name WHERE $this->primary_key = %d LIMIT 1;",
156 193 $row_id
157 194 )
158 195 );
196 + // phpcs:enable WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching
159 197 }
160 198
161 199 /**
162 200 * Retrieve a specific column's value by the the specified column / value
@@ -170,8 +208,15 @@
170 208 */
171 209 public function get_column_by( $column, $column_where, $column_value ) {
172 210 global $wpdb;
173 211
212 + // Validate column names before use.
213 + $column = $this->validate_column_name( $column );
214 + $column_where = $this->validate_column_name( $column_where );
215 +
216 + // phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,PluginCheck.Security.DirectDB.UnescapedDBParameter
217 + // Direct database queries are expected in this database abstraction class.
218 + // $column and $column_where are validated above via validate_column_name(), $this->table_name is a class property set at initialization.
174 219 return $wpdb->get_var(
175 220 $wpdb->prepare(
176 221 "SELECT $column FROM $this->table_name WHERE $column_where = {$this->get_column_format($column_where)} LIMIT 1;",
177 222 $column_value
@@ -176,8 +221,9 @@
176 221 "SELECT $column FROM $this->table_name WHERE $column_where = {$this->get_column_format($column_where)} LIMIT 1;",
177 222 $column_value
178 223 )
179 224 );
225 + // phpcs:enable WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching
180 226 }
181 227
182 228 /**
183 229 * Retrieve all values in a specific column by the specified column / value.
@@ -191,8 +237,15 @@
191 237 */
192 238 public function get_column_all_by( $column, $column_where, $column_value ) {
193 239 global $wpdb;
194 240
241 + // Validate column names before use.
242 + $column = $this->validate_column_name( $column );
243 + $column_where = $this->validate_column_name( $column_where );
244 +
245 + // phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,PluginCheck.Security.DirectDB.UnescapedDBParameter
246 + // Direct database queries are expected in this database abstraction class.
247 + // $column and $column_where are validated above via validate_column_name(), $this->table_name is a class property set at initialization.
195 248 return $wpdb->get_col(
196 249 $wpdb->prepare(
197 250 "SELECT $column FROM $this->table_name WHERE $column_where = {$this->get_column_format($column_where)};",
198 251 $column_value
@@ -197,8 +250,9 @@
197 250 "SELECT $column FROM $this->table_name WHERE $column_where = {$this->get_column_format($column_where)};",
198 251 $column_value
199 252 )
200 253 );
254 + // phpcs:enable WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching
201 255 }
202 256
203 257 /**
204 258 * Count all rows.
@@ -209,11 +263,15 @@
209 263 */
210 264 public function count_all() {
211 265 global $wpdb;
212 266
267 + // phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching
268 + // Direct database queries are expected in this database abstraction class.
269 + // $this->table_name is a class property set at initialization.
213 270 return $wpdb->get_var(
214 271 "SELECT COUNT( * ) FROM $this->table_name;"
215 272 );
273 + // phpcs:enable WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching
216 274 }
217 275
218 276 /**
219 277 * Count all rows that certain criteria.
@@ -224,8 +282,14 @@
224 282 */
225 283 public function count_by( $column, $column_value ) {
226 284 global $wpdb;
227 285
286 + // Validate column name before use.
287 + $column = $this->validate_column_name( $column );
288 +
289 + // phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,PluginCheck.Security.DirectDB.UnescapedDBParameter
290 + // Direct database queries are expected in this database abstraction class.
291 + // $column is validated above via validate_column_name(), $this->table_name is a class property set at initialization.
228 292 return $wpdb->get_var(
229 293 $wpdb->prepare(
230 294 "SELECT COUNT( * ) FROM $this->table_name WHERE $column = {$this->get_column_format($column)};",
231 295 $column_value
@@ -230,14 +294,16 @@
230 294 "SELECT COUNT( * ) FROM $this->table_name WHERE $column = {$this->get_column_format($column)};",
231 295 $column_value
232 296 )
233 297 );
298 + // phpcs:enable WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching
234 299 }
235 300
236 301 /**
237 302 * Insert a new row
238 303 *
239 - * @since 1.0.0
304 + * @since 1.0.0
305 + * @version 1.8.8.6
240 306 *
241 307 * @return int
242 308 */
243 309 public function insert( $data, $type = '' ) {
@@ -260,9 +326,13 @@
260 326 /* Reorder $column_formats to match the order of columns given in $data */
261 327 $data_keys = array_keys( $data );
262 328 $column_formats = array_merge( array_flip( $data_keys ), $column_formats );
263 329
330 + // phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching
331 + // Direct database queries are expected in this database abstraction class.
332 + // $this->table_name is a class property set at initialization, and $data/$column_formats are sanitized above.
264 333 $inserted = $wpdb->insert( $this->table_name, $data, $column_formats );
334 + // phpcs:enable WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching
265 335
266 336 /* If the insert failed, return 0 */
267 337 if ( false === $inserted ) {
268 338 return 0;
@@ -276,8 +346,9 @@
276 346 /**
277 347 * Update a row.
278 348 *
279 349 * @since 1.0.0
350 + * @version 1.8.8.6
280 351 *
281 352 * @global WPDB $wpdb
282 353 * @param int $row_id The record to update.
283 354 * @param array $data Data to update.
@@ -310,9 +381,16 @@
310 381 /* Reorder $column_formats to match the order of columns given in $data. */
311 382 $data_keys = array_keys( $data );
312 383 $column_formats = array_merge( array_flip( $data_keys ), $column_formats );
313 384
314 - if ( false === $wpdb->update( $this->table_name, $data, array( $where => $row_id ), $column_formats ) ) {
385 + // phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching
386 + // Direct database queries are expected in this database abstraction class.
387 + // $this->table_name is a class property set at initialization, $where is validated (defaults to primary_key or validated column),
388 + // $row_id is sanitized via absint(), and $data/$column_formats are sanitized above.
389 + $updated = $wpdb->update( $this->table_name, $data, array( $where => $row_id ), $column_formats );
390 + // phpcs:enable WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching
391 +
392 + if ( false === $updated ) {
315 393 return false;
316 394 }
317 395
318 396 return true;
@@ -349,9 +427,16 @@
349 427 */
350 428 public function delete_by( $column, $row_id = 0 ) {
351 429 global $wpdb;
352 430
431 + // Validate column name before use.
432 + $column = $this->validate_column_name( $column );
433 +
434 + // phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,PluginCheck.Security.DirectDB.UnescapedDBParameter
435 + // Direct database queries are expected in this database abstraction class.
436 + // $column is validated above via validate_column_name(), $this->table_name is a class property set at initialization.
353 437 $result = $wpdb->query( $wpdb->prepare( "DELETE FROM $this->table_name WHERE $column = {$this->get_column_format($column)}", $row_id ) );
438 + // phpcs:enable WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,PluginCheck.Security.DirectDB.UnescapedDBParameter
354 439
355 440 return false !== $result;
356 441 }
357 442