PluginProbe
Charitable – Donation & Fundraising Platform (Donation Forms, Recurring Donations & Fundraising Campaigns) / 1.6.57
Charitable – Donation & Fundraising Platform (Donation Forms, Recurring Donations & Fundraising Campaigns) v1.6.57
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 1.8.0 All 210 releases
charitable / includes / utilities / class-charitable-data-processor.php

class-charitable-data-processor.php in Charitable – Donation & Fundraising Platform (Donation Forms, Recurring Donations & Fundraising Campaigns) 1.6.57, at includes/utilities/class-charitable-data-processor.php

505 lines 12.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Responsible for accepting a set of raw data, such as form submission data,
4 * and sanitizing and normalizing that data, depending on its data type and
5 * the type of data (text, checkbox, etc.).
6 *
7 * @package Charitable/Classes/Charitable_Data_Processor
8 * @author Eric Daams
9 * @copyright Copyright (c) 2022, Studio 164a
10 * @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
11 * @since 1.5.9
12 * @version 1.6.55
13 */
14
15 // Exit if accessed directly.
16 if ( ! defined( 'ABSPATH' ) ) {
17 exit;
18 }
19
20
21 if ( ! class_exists( 'Charitable_Data_Processor' ) ) :
22
23 /**
24 * Data processor class.
25 *
26 * @since 1.5.9
27 */
28 class Charitable_Data_Processor {
29 /**
30 * The raw input data.
31 *
32 * @since 1.5.9
33 *
34 * @var array
35 */
36 protected $data;
37
38 /**
39 * The map of fields.
40 *
41 * @since 1.5.9
42 *
43 * @var array
44 */
45 protected $fields;
46
47 /**
48 * An array of valid options for specific fields.
49 *
50 * @since 1.6.51
51 *
52 * @var array
53 */
54 protected $options;
55
56 /**
57 * This is the output data. It has the same structure
58 * as the map of fields, but has the sanitized &
59 * normalized values from the input data.
60 *
61 * @since 1.5.9
62 *
63 * @var array
64 */
65 protected $output;
66
67 /**
68 * Instantiate the formatter with a dataset and array of fields.
69 *
70 * @since 1.5.9
71 *
72 * @param array $data The raw input data.
73 * @param array $fields The map of fields.
74 */
75 public function __construct( $data, $fields, $options = array() ) {
76 $this->data = $data;
77 $this->fields = $fields;
78 $this->options = $options;
79 $this->output = array();
80 $this->invalid = false;
81
82 $this->process_data( $this->fields );
83 }
84
85 /**
86 * Returns whether the data is valid.
87 *
88 * @since 1.5.9
89 *
90 * @return boolean
91 */
92 public function is_valid() {
93 return false == $this->invalid;
94 }
95
96 /**
97 * Return a single field's output data.
98 *
99 * @since 1.5.9
100 *
101 * @param string $key The field key.
102 * @param string|false $data_type Optional. The data type.
103 * @return mixed|null
104 */
105 public function get( $key, $data_type = false ) {
106 if ( $data_type ) {
107 return $this->get_from_data_type( $key, $data_type );
108 }
109
110 return isset( $this->output[ $key ] ) ? $this->output[ $key ] : null;
111 }
112
113 /**
114 * Return a single field's output data, from a data type.
115 *
116 * @since 1.5.9
117 *
118 * @param string $key The field key.
119 * @param string $data_type The data type.
120 * @return mixed|null
121 */
122 public function get_from_data_type( $key, $data_type ) {
123 return isset( $this->output[ $data_type ][ $key ] ) ? $this->output[ $data_type ][ $key ] : null;
124 }
125
126 /**
127 * Returns the full output array.
128 *
129 * @since 1.5.9
130 *
131 * @return array
132 */
133 public function output() {
134 return $this->output;
135 }
136
137 /**
138 * Process an array of fields.
139 *
140 * @since 1.5.9
141 *
142 * @param array $fields Map of fields.
143 * @param false|string $data_type Optional. Data type.
144 * @return void
145 */
146 protected function process_data( $fields, $data_type = false ) {
147 $data = array();
148
149 foreach ( $fields as $key => $type ) {
150 if ( is_array( $type ) ) {
151 $this->process_data( $type, $key );
152 continue;
153 }
154
155 $data[ $key ] = $this->process_field( $key, $type, $data_type );
156 }
157
158 if ( ! empty( $data ) ) {
159 $this->set_output( $data, $data_type );
160 }
161 }
162
163 /**
164 * Add a set of data to the output array.
165 *
166 * @since 1.5.9
167 *
168 * @param array $data The processed data.
169 * @param false|string $data_type Optional. Data type.
170 * @return void
171 */
172 protected function set_output( $data, $data_type = false ) {
173 if ( $data_type ) {
174 $this->output[ $data_type ] = $data;
175 } else {
176 $this->output = $data;
177 }
178 }
179
180 /**
181 * Apply the correct function to a field, based on the type of function
182 * and the key, type and data type of the field.
183 *
184 * @since 1.5.9
185 *
186 * @param array $functions Stack of functions, in order of priority, with $args
187 * passed as the value of the function.
188 * @param mixed $default The default value to return if none of the functions exist.
189 * @return mixed|null
190 */
191 protected function apply_function_to_field( $functions, $default = '' ) {
192 foreach ( $functions as $function => $args ) {
193 if ( method_exists( $this, $function ) ) {
194 return call_user_func_array( array( $this, $function ), $args );
195 }
196 }
197
198 return $default;
199 }
200
201 /**
202 * Process a single field, returning the set value or null.
203 *
204 * @since 1.5.9
205 *
206 * @param string $key The field key.
207 * @param string $type The type of field.
208 * @param string|false $data_type Optional. The data type.
209 * @return mixed|null The set value of the field, or NULL if the
210 * field was not contained in the data.
211 */
212 protected function process_field( $key, $type, $data_type = false ) {
213 $sanitized_key = str_replace( '-', '_', $key );
214 $sanitized_type = str_replace( '-', '_', $type );
215 $sanitized_data_type = str_replace( '-', '_', $data_type );
216 $field_options = isset( $this->options[ $key ] ) ? $this->options[ $key ] : null;
217
218 /* Retrieve the value. */
219 $value = $this->apply_function_to_field(
220 array(
221 'process_' . $sanitized_key => array( $type, $data_type ),
222 'process_' . $sanitized_data_type => array( $key, $type ),
223 'process_' . $sanitized_type => array( $key, $data_type ),
224 'process_generic_field' => array( $key ),
225 )
226 );
227
228 /* Return the value after it is sanitized. */
229 return $this->apply_function_to_field(
230 array(
231 'sanitize_' . $sanitized_key => array( $value, $type, $data_type, $field_options ),
232 'sanitize_' . $sanitized_data_type => array( $value, $key, $type, $field_options ),
233 'sanitize_' . $sanitized_type => array( $value, $key, $data_type, $field_options ),
234 'sanitize_generic_field' => array( $value, $key, $field_options ),
235 ),
236 $value
237 );
238 }
239
240 /**
241 * Process a checkbox field.
242 *
243 * @since 1.5.9
244 *
245 * @param string $key The field key.
246 * @return int|string Returns 0 if the checkbox was not checked, or the
247 * value of the checkbox if checked.
248 */
249 protected function process_checkbox( $key ) {
250 return array_key_exists( $key, $this->data ) ? $this->data[ $key ] : 0;
251 }
252
253 /**
254 * Process a picture field.
255 *
256 * @since 1.5.9
257 *
258 * @param string $key The key of the picture field.
259 * @return int|false
260 */
261 protected function process_picture( $key ) {
262 $value = array_key_exists( $key, $this->data ) ? $this->data[ $key ] : '';
263
264 /**
265 * If Javascript is enabled, we do not expect to have a $_FILES array with the
266 * picture, as the upload was already handled client-side.
267 */
268 if ( ! $this->picture_file_exists( $key ) ) {
269 return $value;
270 }
271
272 $value = $this->upload_attachment( $key );
273
274 if ( is_wp_error( $value ) ) {
275 charitable_get_notices()->add_errors_from_wp_error( $value );
276 $value = '';
277 $this->invalid = true;
278 }
279
280 return $value;
281 }
282
283 /**
284 * Process a generic field. i.e. One that hasn't been processed
285 * by any of the other processors.
286 *
287 * @since 1.5.9
288 *
289 * @param string $key The field key.
290 * @return mixed|null The set value of the field, or NULL if the
291 * field was not contained in the data.
292 */
293 public function process_generic_field( $key ) {
294 return isset( $this->data[ $key ] ) ? $this->data[ $key ] : null;
295 }
296
297 /**
298 * Sanitize a number.
299 *
300 * @since 1.5.9
301 *
302 * @param string|int $value The number to be sanitized.
303 * @return int
304 */
305 public static function sanitize_number( $value ) {
306 return intval( $value );
307 }
308
309 /**
310 * Sanitize a value received from a datepicker.
311 *
312 * @since 1.5.9
313 *
314 * @param string $value The datepicker value.
315 * @return string|int If a date was chosen, returns the date in YYYY-MM-DD format.
316 * Otherwise, returns 0.
317 */
318 public static function sanitize_datepicker( $value ) {
319 if ( empty( $value ) ) {
320 return 0;
321 }
322
323 if ( ! charitable()->registry()->get( 'i18n' )->decline_months() ) {
324 $value = charitable_sanitize_date( $value, 'Y-m-d' );
325 }
326
327 return $value;
328 }
329
330 /**
331 * Sanitize editor fields.
332 *
333 * @since 1.6.51
334 *
335 * @param mixed $value The submitted value.
336 * @return string
337 */
338 public static function sanitize_editor( $value ) {
339 return wp_kses_post( $value );
340 }
341
342 /**
343 * Sanitize textarea.
344 *
345 * @since 1.6.51
346 *
347 * @param mixed $value The submitted value.
348 * @return string
349 */
350 public static function sanitize_textarea( $value ) {
351 return sanitize_textarea_field( $value );
352 }
353
354 /**
355 * Sanitize submitted email.
356 *
357 * @since 1.6.51
358 *
359 * @param mixed $value The submitted value.
360 * @return string
361 */
362 public static function sanitize_email( $value ) {
363 return sanitize_email( $value );
364 }
365
366 /**
367 * Escape a submitted url.
368 *
369 * @since 1.6.51
370 *
371 * @param mixed $value The submitted value.
372 * @return string
373 */
374 public static function sanitize_url( $value ) {
375 return esc_url_raw( $value );
376 }
377
378 /**
379 * Fallback sanitization, using sanitize_text_field.
380 *
381 * @since 1.6.51
382 *
383 * @param mixed $value The submitted value.
384 * @return string
385 */
386 public static function sanitize_text( $value ) {
387 return sanitize_text_field( $value );
388 }
389
390 /**
391 * Sanitize multi-checkbox fields.
392 *
393 * @since 1.6.51
394 *
395 * @param mixed $value The submitted value.
396 * @param string $key The field key.
397 * @param string $data_type The type of data.
398 * @param null|array $options The options for the field.
399 * @return string|array
400 */
401 public static function sanitize_multi_checkbox( $value, $key, $data_type, $options = null ) {
402 /* Multi-checkbox should return an empty string or an array. */
403 if ( ! is_array( $value ) ) {
404 return '';
405 }
406
407 if ( is_null( $options ) ) {
408 return $value;
409 }
410
411 /* Check against a specific set of options that are valid for this field. */
412 foreach ( $value as $i => $option ) {
413 /* If the selected option is not valid, remove it. */
414 if ( ! in_array( $option, $options ) ) {
415 unset( $value[ $i ] );
416 }
417 }
418
419 return $value;
420 }
421
422 /**
423 * Fallback sanitization.
424 *
425 * @since 1.6.51
426 *
427 * @param mixed $value The submitted value.
428 * @param string $key The field key.
429 * @param null|array $options The options for the field.
430 * @return string
431 */
432 public static function sanitize_generic_field( $value, $key, $options = null ) {
433 /* Check against a specific set of options that are valid for this field. */
434 if ( is_array( $options ) ) {
435 $value = in_array( $value, $options ) ? $value : '';
436 }
437
438 return $value;
439 }
440
441 /**
442 * Returns true if a file was found for the picture in the $_FILES array.
443 *
444 * @since 1.5.9
445 *
446 * @param string $key The picture file key.
447 * @return boolean
448 */
449 protected function picture_file_exists( $key ) {
450 return isset( $_FILES ) && isset( $_FILES[ $key ] );
451 }
452
453 /**
454 * Uploads a file and attaches it to the given post.
455 *
456 * @since 1.5.9
457 *
458 * @param string $file_key Key of the file input.
459 * @param int $post_id Post ID.
460 * @return int|WP_Error ID of the attachment or a WP_Error object on failure.
461 */
462 public function upload_attachment( $file_key, $post_id = 0 ) {
463 require_once( ABSPATH . 'wp-admin/includes/image.php' );
464 require_once( ABSPATH . 'wp-admin/includes/file.php' );
465 require_once( ABSPATH . 'wp-admin/includes/media.php' );
466
467 $overrides = $this->get_file_overrides( $file_key, $overrides );
468
469 return media_handle_upload( $file_key, $post_id, array(), $overrides );
470 }
471
472 /**
473 * Return overrides array for use with upload_attachment() methods.
474 *
475 * @since 1.0.0
476 *
477 * @param string $file_key Reference to a single element of `$_FILES`. Call the
478 * function once for each uploaded file.
479 * @param array $overrides Optional. An associative array of names=>values to
480 * override default variables. Default false.
481 * @return array
482 */
483 protected function get_file_overrides( $file_key, $overrides = array() ) {
484 $allowed_mimes = array(
485 'jpg|jpeg|jpe' => 'image/jpeg',
486 'gif' => 'image/gif',
487 'png' => 'image/png',
488 'bmp' => 'image/bmp',
489 'tif|tiff' => 'image/tiff',
490 'ico' => 'image/x-icon',
491 );
492
493 $defaults = array(
494 'test_form' => false,
495 'mimes' => apply_filters( 'charitable_file_' . $file_key . '_allowed_mimes', $allowed_mimes ),
496 );
497
498 $overrides = wp_parse_args( $overrides, $defaults );
499
500 return $overrides;
501 }
502 }
503
504 endif;
505