Test Failed
Pull Request — master (#2814)
by Devin
05:29
created

Give_Import_Donations::html()   C

Complexity

Conditions 7
Paths 10

Size

Total Lines 47
Code Lines 29

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 7
eloc 29
nc 10
nop 0
dl 0
loc 47
rs 6.7272
c 0
b 0
f 0
1
<?php
2
/**
3
 * Donations Import Class
4
 *
5
 * This class handles donations import.
6
 *
7
 * @package     Give
8
 * @subpackage  Classes/Give_Import_Donations
9
 * @copyright   Copyright (c) 2017, WordImpress
10
 * @license     https://opensource.org/licenses/gpl-license GNU Public License
11
 * @since       1.8.14
12
 */
13
14
if ( ! defined( 'ABSPATH' ) ) {
15
	exit; // Exit if accessed directly
16
}
17
18
if ( ! class_exists( 'Give_Import_Donations' ) ) {
19
20
	/**
21
	 * Give_Import_Donations.
22
	 *
23
	 * @since 1.8.14
24
	 */
25
	final class Give_Import_Donations {
26
27
		/**
28
		 * Importer type
29
		 *
30
		 * @since 1.8.13
31
		 * @var string
32
		 */
33
		private $importer_type = 'import_donations';
34
35
		/**
36
		 * Instance.
37
		 *
38
		 * @since
39
		 * @access private
40
		 * @var
41
		 */
42
		static private $instance;
43
44
		/**
45
		 * Importing donation per page.
46
		 *
47
		 * @since 1.8.14
48
		 *
49
		 * @var   int
50
		 */
51
		public static $per_page = 25;
52
53
		/**
54
		 * Singleton pattern.
55
		 *
56
		 * @since
57
		 * @access private
58
		 */
59
		private function __construct() {
60
			self::$per_page  = ! empty( $_GET['per_page'] ) ? absint( $_GET['per_page'] ) : self::$per_page;
0 ignored issues
show
introduced by
Detected access of super global var $_GET, probably need manual inspection.
Loading history...
61
		}
62
63
		/**
64
		 * Get instance.
65
		 *
66
		 * @since
67
		 * @access public
68
		 *
69
		 * @return static
70
		 */
71
		public static function get_instance() {
72
			if ( null === static::$instance ) {
73
				self::$instance = new static();
74
			}
75
76
			return self::$instance;
77
		}
78
79
		/**
80
		 * Setup
81
		 *
82
		 * @since 1.8.14
83
		 *
84
		 * @return void
85
		 */
86
		public function setup() {
87
			$this->setup_hooks();
88
		}
89
90
91
		/**
92
		 * Setup Hooks.
93
		 *
94
		 * @since 1.8.14
95
		 *
96
		 * @return void
97
		 */
98 View Code Duplication
		private function setup_hooks() {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
99
			if ( ! $this->is_donations_import_page() ) {
100
				return;
101
			}
102
103
			// Do not render main import tools page.
104
			remove_action( 'give_admin_field_tools_import', array( 'Give_Settings_Import', 'render_import_field', ) );
105
0 ignored issues
show
Coding Style introduced by
Functions must not contain multiple empty lines in a row; found 2 empty lines
Loading history...
106
107
			// Render donation import page
108
			add_action( 'give_admin_field_tools_import', array( $this, 'render_page' ) );
109
110
			// Print the HTML.
111
			add_action( 'give_tools_import_donations_form_start', array( $this, 'html' ), 10 );
112
113
			// Run when form submit.
114
			add_action( 'give-tools_save_import', array( $this, 'save' ) );
115
116
			add_action( 'give-tools_update_notices', array( $this, 'update_notices' ), 11, 1 );
117
118
			// Used to add submit button.
119
			add_action( 'give_tools_import_donations_form_end', array( $this, 'submit' ), 10 );
120
		}
121
122
		/**
123
		 * Update notice
124
		 *
125
		 * @since 1.8.14
126
		 *
127
		 * @param $messages
128
		 *
129
		 * @return mixed
130
		 */
131 View Code Duplication
		public function update_notices( $messages ) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
132
			if ( ! empty( $_GET['tab'] ) && 'import' === give_clean( $_GET['tab'] ) ) {
0 ignored issues
show
introduced by
Detected access of super global var $_GET, probably need manual inspection.
Loading history...
introduced by
Detected usage of a non-sanitized input variable: $_GET
Loading history...
133
				unset( $messages['give-setting-updated'] );
134
			}
135
136
			return $messages;
137
		}
138
139
		/**
140
		 * Print submit and nonce button.
141
		 *
142
		 * @since 1.8.14
143
		 */
144
		public function submit() {
145
			wp_nonce_field( 'give-save-settings', '_give-save-settings' );
146
			?>
147
			<input type="hidden" class="import-step" id="import-step" name="step" value="<?php echo $this->get_step(); ?>"/>
0 ignored issues
show
introduced by
Expected next thing to be a escaping function, not '$this'
Loading history...
148
			<input type="hidden" class="importer-type" value="<?php echo $this->importer_type; ?>"/>
0 ignored issues
show
introduced by
Expected next thing to be a escaping function, not '$this'
Loading history...
149
			<?php
150
		}
151
152
		/**
153
		 * Print the HTML for importer.
154
		 *
155
		 * @since 1.8.14
156
		 */
157
		public function html() {
158
			$step = $this->get_step();
159
160
			// Show progress.
161
			$this->render_progress();
162
			?>
163
			<section>
164
				<table class="widefat export-options-table give-table <?php echo "step-{$step}"; ?>" id="<?php echo "step-{$step}"; ?>">
0 ignored issues
show
introduced by
Expected next thing to be a escaping function, not '"step-{$step}"'
Loading history...
165
					<tbody>
166
						<?php
167
						switch ( $this->get_step() ) {
168
							case 1:
169
								$this->render_media_csv();
170
								break;
171
172
							case 2:
173
								$this->render_dropdown();
174
								break;
175
176
							case 3:
177
								$this->start_import();
178
								break;
179
180
							case 4:
181
								$this->import_success();
182
						}
183
184
						if ( false === $this->check_for_dropdown_or_import() ) {
185
							?>
186
							<tr valign="top">
187
								<th></th>
188
								<th>
189
									<input type="submit"
190
									       class=" button button-primary button-large button-secondary <?php echo "step-{$step}"; ?>"
0 ignored issues
show
introduced by
Expected next thing to be a escaping function, not '"step-{$step}"'
Loading history...
191
									       id="recount-stats-submit"
192
									       <?php echo ( 2 === $step ) ? 'disabled' : ''; ?>
0 ignored issues
show
introduced by
Expected next thing to be a escaping function, not '('
Loading history...
193
									       value="<?php esc_attr_e( 'Submit', 'give' ); ?>"/>
194
								</th>
195
							</tr>
196
							<?php
197
						}
198
						?>
199
					</tbody>
200
				</table>
201
			</section>
202
			<?php
203
		}
204
205
		/**
206
		 * Show success notice
207
		 *
208
		 * @since 1.8.14
209
		 */
210
		public function import_success() {
211
212
			$delete_csv = ( ! empty( $_GET['delete_csv'] ) ? absint( $_GET['delete_csv'] ) : false );
0 ignored issues
show
introduced by
Detected access of super global var $_GET, probably need manual inspection.
Loading history...
213
			$csv        = ( ! empty( $_GET['csv'] ) ? absint( $_GET['csv'] ) : false );
0 ignored issues
show
introduced by
Detected access of super global var $_GET, probably need manual inspection.
Loading history...
214
			if ( ! empty( $delete_csv ) && ! empty( $csv ) ) {
215
				wp_delete_attachment( $csv, true );
216
			}
217
218
			$report      = give_import_donation_report();
219
220
			$report_html = array(
221
				'duplicate_donor'    => array(
222
					__( '%s duplicate %s detected', 'give' ),
223
					__( 'donor', 'give' ),
224
					__( 'donors', 'give' ),
225
				),
226
				'create_donor'       => array(
227
					__( '%s %s created', 'give' ),
228
					__( 'donor', 'give' ),
229
					__( 'donors', 'give' ),
230
				),
231
				'create_form'        => array(
232
					__( '%s donation %s created', 'give' ),
233
					__( 'form', 'give' ),
234
					__( 'forms', 'give' ),
235
				),
236
				'duplicate_donation' => array(
237
					__( '%s duplicate %s detected', 'give' ),
238
					__( 'donation', 'give' ),
239
					__( 'donations', 'give' ),
240
				),
241
				'create_donation'    => array(
242
					__( '%s %s imported', 'give' ),
243
					__( 'donation', 'give' ),
244
					__( 'donations', 'give' ),
245
				),
246
			);
247
			$total       = (int) $_GET['total'];
0 ignored issues
show
introduced by
Detected access of super global var $_GET, probably need manual inspection.
Loading history...
introduced by
Detected usage of a non-validated input variable: $_GET
Loading history...
248
			-- $total;
249
			$success = (bool) $_GET['success'];
0 ignored issues
show
introduced by
Detected access of super global var $_GET, probably need manual inspection.
Loading history...
introduced by
Detected usage of a non-validated input variable: $_GET
Loading history...
250
			?>
251
			<tr valign="top" class="give-import-dropdown">
252
				<th colspan="2">
253
					<h2>
254
						<?php
255
						if ( $success ) {
256
							printf(
257
								_n( 'Import complete! %s donation processed', 'Import complete! %s donations processed', $total, 'give' ),
258
								"<strong>{$total}</strong>"
259
							);
260
						} else {
261
							printf(
262
								_n( 'Failed to import %s donation', 'Failed to import %s donations', $total, 'give' ),
263
								"<strong>{$total}</strong>"
264
							);
265
						}
266
						?>
267
					</h2>
268
269
					<?php
270
					$text      = __( 'Import Donation', 'give' );
271
					$query_arg = array(
272
						'post_type' => 'give_forms',
273
						'page'      => 'give-tools',
274
						'tab'       => 'import',
275
					);
276
					if ( $success ) {
277
						$query_arg = array(
278
							'post_type' => 'give_forms',
279
							'page'      => 'give-payment-history',
280
						);
281
						$text      = __( 'View Donations', 'give' );
282
					}
283
284
					foreach ( $report as $key => $value ) {
285
						if ( array_key_exists( $key, $report_html ) && ! empty( $value ) ) {
286
							?>
287
							<p>
288
								<?php echo esc_html( wp_sprintf( $report_html[ $key ][0], $value, _n( $report_html[ $key ][1], $report_html[ $key ][2], $value, 'give' ) ) ); ?>
0 ignored issues
show
introduced by
Expected next thing to be a escaping function, not '$report_html'
Loading history...
289
							</p>
290
							<?php
291
						}
292
					}
293
					?>
294
295
					<p>
296
						<a class="button button-large button-secondary" href="<?php echo add_query_arg( $query_arg, admin_url( 'edit.php' ) ); ?>"><?php echo $text; ?></a>
0 ignored issues
show
introduced by
Expected a sanitizing function (see Codex for 'Data Validation'), but instead saw 'add_query_arg'
Loading history...
introduced by
Expected next thing to be a escaping function, not '$text'
Loading history...
297
					</p>
298
				</th>
299
			</tr>
300
			<?php
301
		}
302
303
		/**
304
		 * Will start Import
305
		 *
306
		 * @since 1.8.14
307
		 */
308
		public function start_import() {
309
			// Reset the donation form report.
310
			give_import_donation_report_reset();
311
312
			$csv         = (int) $_REQUEST['csv'];
0 ignored issues
show
introduced by
Detected access of super global var $_REQUEST, probably need manual inspection.
Loading history...
introduced by
Detected usage of a non-validated input variable: $_REQUEST
Loading history...
313
			$delimiter   = ( ! empty( $_REQUEST['delimiter'] ) ? give_clean( $_REQUEST['delimiter'] ) : 'csv' );
0 ignored issues
show
introduced by
Detected access of super global var $_REQUEST, probably need manual inspection.
Loading history...
introduced by
Detected usage of a non-sanitized input variable: $_REQUEST
Loading history...
314
			$index_start = 1;
315
			$index_end   = 1;
0 ignored issues
show
Unused Code introduced by
$index_end is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
316
			$next        = true;
317
			$total       = self::get_csv_total( $csv );
318
			if ( self::$per_page < $total ) {
319
				$total_ajax = ceil( $total / self::$per_page );
320
				$index_end  = self::$per_page;
321
			} else {
322
				$total_ajax = 1;
323
				$index_end  = $total;
324
				$next       = false;
325
			}
326
			$current_percentage = 100 / ( $total_ajax + 1 );
327
328
			?>
329
			<tr valign="top" class="give-import-dropdown">
330
				<th colspan="2">
331
					<h2 id="give-import-title"><?php esc_html_e( 'Importing', 'give' ) ?></h2>
332
					<p class="give-field-description"><?php esc_html_e( 'Your donations are now being imported...', 'give' ) ?></p>
333
				</th>
334
			</tr>
335
336
			<tr valign="top" class="give-import-dropdown">
337
				<th colspan="2">
338
					<span class="spinner is-active"></span>
339
					<div class="give-progress"
340
						 data-current="1"
341
						 data-total_ajax="<?php echo $total_ajax; ?>"
0 ignored issues
show
introduced by
Expected next thing to be a escaping function, not '$total_ajax'
Loading history...
342
						 data-start="<?php echo $index_start; ?>"
0 ignored issues
show
introduced by
Expected next thing to be a escaping function, not '$index_start'
Loading history...
343
						 data-end="<?php echo $index_end; ?>"
0 ignored issues
show
introduced by
Expected next thing to be a escaping function, not '$index_end'
Loading history...
344
						 data-next="<?php echo $next; ?>"
0 ignored issues
show
introduced by
Expected next thing to be a escaping function, not '$next'
Loading history...
345
						 data-total="<?php echo $total; ?>"
0 ignored issues
show
introduced by
Expected next thing to be a escaping function, not '$total'
Loading history...
346
						 data-per_page="<?php echo self::$per_page; ?>">
0 ignored issues
show
introduced by
Expected next thing to be a escaping function, not 'self'
Loading history...
347
348
						<div style="width: <?php echo $current_percentage; ?>%"></div>
0 ignored issues
show
introduced by
Expected next thing to be a escaping function, not '$current_percentage'
Loading history...
349
					</div>
350
					<input type="hidden" value="3" name="step">
351
					<input type="hidden" value='<?php echo maybe_serialize( $_REQUEST['mapto'] ); ?>' name="mapto"
0 ignored issues
show
introduced by
Expected a sanitizing function (see Codex for 'Data Validation'), but instead saw 'maybe_serialize'
Loading history...
introduced by
Detected access of super global var $_REQUEST, probably need manual inspection.
Loading history...
introduced by
Detected usage of a non-validated input variable: $_REQUEST
Loading history...
introduced by
Detected usage of a non-sanitized input variable: $_REQUEST
Loading history...
352
						   class="mapto">
353
					<input type="hidden" value="<?php echo $_REQUEST['csv']; ?>" name="csv" class="csv">
0 ignored issues
show
introduced by
Detected access of super global var $_REQUEST, probably need manual inspection.
Loading history...
introduced by
Expected next thing to be a escaping function, not '$_REQUEST'
Loading history...
introduced by
Detected usage of a non-sanitized input variable: $_REQUEST
Loading history...
354
					<input type="hidden" value="<?php echo $_REQUEST['mode']; ?>" name="mode" class="mode">
0 ignored issues
show
introduced by
Detected access of super global var $_REQUEST, probably need manual inspection.
Loading history...
introduced by
Expected next thing to be a escaping function, not '$_REQUEST'
Loading history...
introduced by
Detected usage of a non-sanitized input variable: $_REQUEST
Loading history...
355
					<input type="hidden" value="<?php echo $_REQUEST['create_user']; ?>" name="create_user"
0 ignored issues
show
introduced by
Detected access of super global var $_REQUEST, probably need manual inspection.
Loading history...
introduced by
Expected next thing to be a escaping function, not '$_REQUEST'
Loading history...
introduced by
Detected usage of a non-sanitized input variable: $_REQUEST
Loading history...
356
						   class="create_user">
357
					<input type="hidden" value="<?php echo $_REQUEST['delete_csv']; ?>" name="delete_csv"
0 ignored issues
show
introduced by
Detected access of super global var $_REQUEST, probably need manual inspection.
Loading history...
introduced by
Expected next thing to be a escaping function, not '$_REQUEST'
Loading history...
introduced by
Detected usage of a non-sanitized input variable: $_REQUEST
Loading history...
358
						   class="delete_csv">
359
					<input type="hidden" value="<?php echo $delimiter; ?>" name="delimiter">
0 ignored issues
show
introduced by
Expected next thing to be a escaping function, not '$delimiter'
Loading history...
360
					<input type="hidden" value='<?php echo maybe_serialize( self::get_importer( $csv, 0, $delimiter ) ); ?>'
0 ignored issues
show
Bug introduced by
It seems like $delimiter defined by !empty($_REQUEST['delimi...T['delimiter']) : 'csv' on line 313 can also be of type array; however, Give_Import_Donations::get_importer() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
introduced by
Expected a sanitizing function (see Codex for 'Data Validation'), but instead saw 'maybe_serialize'
Loading history...
361
						   name="main_key"
362
						   class="main_key">
363
				</th>
364
			</tr>
365
366
			<script type="text/javascript">
367
				jQuery(document).ready(function () {
368
					give_on_donation_import_start();
369
				});
370
			</script>
371
			<?php
372
		}
373
374
		/**
375
		 * Will return true if importing can be started or not else false.
376
		 *
377
		 * @since 1.8.14
378
		 */
379
		public function check_for_dropdown_or_import() {
380
			$return = true;
381
			if ( isset( $_REQUEST['mapto'] ) ) {
382
				$mapto = (array) $_REQUEST['mapto'];
0 ignored issues
show
introduced by
Detected access of super global var $_REQUEST, probably need manual inspection.
Loading history...
introduced by
Detected usage of a non-sanitized input variable: $_REQUEST
Loading history...
383
				if ( false === in_array( 'form_title', $mapto ) && false === in_array( 'form_id', $mapto ) ) {
384
					Give_Admin_Settings::add_error( 'give-import-csv-form', __( 'In order to import donations, a column must be mapped to either the "Donation Form Title" or "Donation Form ID" field. Please map a column to one of those fields.', 'give' ) );
385
					$return = false;
386
				}
387
388
				if ( false === in_array( 'amount', $mapto ) ) {
389
					Give_Admin_Settings::add_error( 'give-import-csv-amount', __( 'In order to import donations, a column must be mapped to the "Amount" field. Please map a column to that field.', 'give' ) );
390
					$return = false;
391
				}
392
393
				if ( false === in_array( 'email', $mapto ) && false === in_array( 'donor_id', $mapto ) ) {
394
					Give_Admin_Settings::add_error( 'give-import-csv-donor', __( 'In order to import donations, a column must be mapped to either the "Donor Email" or "Donor ID" field. Please map a column to that field.', 'give' ) );
395
					$return = false;
396
				}
397
			} else {
398
				$return = false;
399
			}
400
401
			return $return;
402
		}
403
404
		/**
405
		 * Print the Dropdown option for CSV.
406
		 *
407
		 * @since 1.8.14
408
		 */
409
		public function render_dropdown() {
410
			$csv       = (int) $_GET['csv'];
0 ignored issues
show
introduced by
Detected access of super global var $_GET, probably need manual inspection.
Loading history...
introduced by
Detected usage of a non-validated input variable: $_GET
Loading history...
411
			$delimiter = ( ! empty( $_GET['delimiter'] ) ? give_clean( $_GET['delimiter'] ) : 'csv' );
0 ignored issues
show
introduced by
Detected access of super global var $_GET, probably need manual inspection.
Loading history...
introduced by
Detected usage of a non-sanitized input variable: $_GET
Loading history...
412
413
			// TO check if the CSV files that is being add is valid or not if not then redirect to first step again
414
			if ( ! $this->is_valid_csv( $csv ) ) {
415
				$url = give_import_page_url();
416
				?>
417
				<script type="text/javascript">
418
					window.location = "<?php echo $url; ?>"
0 ignored issues
show
introduced by
Expected next thing to be a escaping function, not '$url'
Loading history...
419
				</script>
420
				<?php
421
			} else {
422
				?>
423
				<tr valign="top" class="give-import-dropdown">
424
					<th colspan="2">
425
						<h2 id="give-import-title"><?php esc_html_e( 'Map CSV fields to donations', 'give' ) ?></h2>
426
427
						<p class="give-import-donation-required-fields-title"><?php _e( 'Required Fields' ); ?></p>
428
429
						<p class="give-field-description"><?php _e( 'These fields are required for the import to submitted' ); ?></p>
430
431
						<ul class="give-import-donation-required-fields">
432
							<li class="give-import-donation-required-email" title="Please configure all required fields to start the import process.">
433
								<span class="give-import-donation-required-symbol dashicons dashicons-no-alt"></span>
434
								<span class="give-import-donation-required-text">
435
									<?php
436
									_e( 'Email Access', 'give' );
437
									?>
438
								</span>
439
							</li>
440
441
							<li class="give-import-donation-required-first" title="Please configure all required fields to start the import process.">
442
								<span class="give-import-donation-required-symbol dashicons dashicons-no-alt"></span>
443
								<span class="give-import-donation-required-text">
444
									<?php
445
									_e( 'First Name', 'give' );
446
									?>
447
								</span>
448
							</li>
449
450
							<li class="give-import-donation-required-amount" title="Please configure all required fields to start the import process.">
451
								<span class="give-import-donation-required-symbol dashicons dashicons-no-alt"></span>
452
								<span class="give-import-donation-required-text">
453
									<?php
454
									_e( 'Donation Amount', 'give' );
455
									?>
456
								</span>
457
							</li>
458
459
							<li class="give-import-donation-required-form" title="Please configure all required fields to start the import process.">
460
								<span class="give-import-donation-required-symbol dashicons dashicons-no-alt"></span>
461
								<span class="give-import-donation-required-text">
462
									<?php
463
									_e( 'Form Title or ID', 'give' );
464
									?>
465
								</span>
466
							</li>
467
						</ul>
468
469
						<p class="give-field-description"><?php esc_html_e( 'Select fields from your CSV file to map against donations fields or to ignore during import.', 'give' ) ?></p>
470
					</th>
471
				</tr>
472
473
				<tr valign="top" class="give-import-dropdown">
474
					<th><b><?php esc_html_e( 'Column name', 'give' ); ?></b></th>
475
					<th><b><?php esc_html_e( 'Map to field', 'give' ); ?></b></th>
476
				</tr>
477
478
				<?php
479
				$raw_key   = $this->get_importer( $csv, 0, $delimiter );
0 ignored issues
show
Bug introduced by
It seems like $delimiter defined by !empty($_GET['delimiter'...T['delimiter']) : 'csv' on line 411 can also be of type array; however, Give_Import_Donations::get_importer() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
480
				$mapto     = (array) ( isset( $_REQUEST['mapto'] ) ? $_REQUEST['mapto'] : array() );
0 ignored issues
show
introduced by
Detected access of super global var $_REQUEST, probably need manual inspection.
Loading history...
introduced by
Detected usage of a non-sanitized input variable: $_REQUEST
Loading history...
481
482
				foreach ( $raw_key as $index => $value ) {
0 ignored issues
show
Bug introduced by
The expression $raw_key of type array<integer,string|nul...":"string|null"}>|false is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
483
					?>
484
					<tr valign="top" class="give-import-option">
485
						<th><?php echo $value; ?></th>
0 ignored issues
show
introduced by
Expected next thing to be a escaping function, not '$value'
Loading history...
486
						<th>
487
							<?php
488
							$this->get_columns( $index, $value, $mapto );
489
							?>
490
						</th>
491
					</tr>
492
					<?php
493
				}
494
			}
495
		}
496
497
		/**
498
		 * @param $option_value
499
		 * @param $value
500
		 *
501
		 * @return string
502
		 */
503
		public function selected( $option_value, $value ) {
504
			$option_value = strtolower( $option_value );
505
			$value = strtolower( $value );
506
507
			$selected = '';
508
			if ( stristr( $value, $option_value ) ) {
509
				$selected = 'selected';
510
			} elseif ( strrpos( $value, '_' ) && stristr( $option_value, __( 'Import as Meta', 'give' ) ) ) {
511
				$selected = 'selected';
512
			}
513
514
			return $selected;
515
		}
516
517
		/**
518
		 * Print the columns from the CSV.
519
		 *
520
		 * @since 1.8.14
521
		 * @access private
522
		 *
523
		 * @param string  $index
524
		 * @param bool  $value
525
		 * @param array $mapto
526
		 *
527
		 * @return void
528
		 */
529
		private function get_columns( $index, $value = false, $mapto = array() ) {
530
			$default       = give_import_default_options();
531
			$current_mapto = (string) ( ! empty( $mapto[ $index ] ) ? $mapto[ $index ] : '' );
532
			?>
533
			<select name="mapto[<?php echo $index; ?>]">
0 ignored issues
show
introduced by
Expected next thing to be a escaping function, not '$index'
Loading history...
534
				<?php $this->get_dropdown_option_html( $default, $current_mapto, $value ); ?>
535
536
				<optgroup label="<?php _e( 'Donations', 'give' ); ?>">
537
					<?php
538
					$this->get_dropdown_option_html( give_import_donations_options(), $current_mapto, $value );
539
					?>
540
				</optgroup>
541
542
				<optgroup label="<?php _e( 'Donors', 'give' ); ?>">
543
					<?php
544
					$this->get_dropdown_option_html( give_import_donor_options(), $current_mapto, $value );
545
					?>
546
				</optgroup>
547
548
				<optgroup label="<?php _e( 'Forms', 'give' ); ?>">
549
					<?php
550
					$this->get_dropdown_option_html( give_import_donation_form_options(), $current_mapto, $value );
551
					?>
552
				</optgroup>
553
554
				<?php
555
				/**
556
				 * Fire the action
557
				 * You can use this filter to add new options.
558
				 *
559
				 * @since 1.8.15
560
				 */
561
				do_action( 'give_import_dropdown_option', $index, $value, $mapto, $current_mapto );
562
				?>
563
			</select>
564
			<?php
565
		}
566
567
		/**
568
		 * Print the option html for select in importer
569
		 *
570
		 * @since  1.8.15
571
		 * @access public
572
		 *
573
		 * @param  array  $options
574
		 * @param  string $current_mapto
575
		 * @param bool    $value
576
		 *
577
		 * @return void
578
		 */
579
		public function get_dropdown_option_html( $options, $current_mapto, $value = false ) {
580
			foreach ( $options as $option => $option_value ) {
581
				$option_value_texts = (array) $option_value;
582
				$option_text = $option_value_texts[0];
583
584
				$checked = ( ( $current_mapto === $option ) ? 'selected' : false );
585
				if ( empty( $checked ) ) {
586
					foreach ( $option_value_texts as $option_value_text ) {
587
						$checked = $this->selected( $option_value_text, $value );
588
						if ( $checked ) {
589
							break;
590
						}
591
					}
592
				}
593
594
				echo sprintf(
0 ignored issues
show
introduced by
Expected a sanitizing function (see Codex for 'Data Validation'), but instead saw 'sprintf'
Loading history...
595
					'<option value="%1$s" %2$s >%3$s</option>',
596
					$option,
597
					$checked,
598
					$option_text
599
				);
600
			}
601
		}
602
603
		/**
604
		 * Get column count of csv file.
605
		 *
606
		 * @since 1.8.14
607
		 *
608
		 * @param $file_id
609
		 *
610
		 * @return bool|int
611
		 */
612
		public function get_csv_total( $file_id ) {
613
			$total = false;
614
			if ( $file_id ) {
615
				$file_dir = get_attached_file( $file_id );
616
				if ( $file_dir ) {
617
					$file = new SplFileObject( $file_dir, 'r' );
618
					$file->seek( PHP_INT_MAX );
619
					$total = $file->key() + 1;
620
				}
621
			}
622
623
			return $total;
624
		}
625
626
		/**
627
		 * Get the CSV fields title from the CSV.
628
		 *
629
		 * @since 1.8.14
630
		 *
631
		 * @param (int) $file_id
632
		 * @param int    $index
633
		 * @param string $delimiter
634
		 *
635
		 * @return array|bool $raw_data title of the CSV file fields
636
		 */
637
		public function get_importer( $file_id, $index = 0, $delimiter = 'csv' ) {
638
			/**
639
			 * Filter to modify delimiter of Import.
640
			 *
641
			 * @since 1.8.14
642
			 *
643
			 * Return string $delimiter.
644
			 */
645
			$delimiter = (string) apply_filters( 'give_import_delimiter_set', $delimiter );
646
647
			$raw_data = false;
648
			$file_dir = get_attached_file( $file_id );
649
			if ( $file_dir ) {
650
				if ( false !== ( $handle = fopen( $file_dir, 'r' ) ) ) {
651
					$raw_data = fgetcsv( $handle, $index, $delimiter );
652
					// Remove BOM signature from the first item.
653
					if ( isset( $raw_data[0] ) ) {
654
						$raw_data[0] = $this->remove_utf8_bom( $raw_data[0] );
655
					}
656
				}
657
			}
658
659
			return $raw_data;
660
		}
661
662
		/**
663
		 * Remove UTF-8 BOM signature.
664
		 *
665
		 * @since 1.8.14
666
		 *
667
		 * @param  string $string String to handle.
668
		 *
669
		 * @return string
670
		 */
671
		public function remove_utf8_bom( $string ) {
672
			if ( 'efbbbf' === substr( bin2hex( $string ), 0, 6 ) ) {
673
				$string = substr( $string, 3 );
674
			}
675
676
			return $string;
677
		}
678
679
680
		/**
681
		 * Is used to show the process when user upload the donor form.
682
		 *
683
		 * @since 1.8.14
684
		 */
685
		public function render_progress() {
686
			$step = $this->get_step();
687
			?>
688
			<ol class="give-progress-steps">
689
				<li class="<?php echo( 1 === $step ? 'active' : '' ); ?>">
0 ignored issues
show
introduced by
Expected next thing to be a escaping function, not '('
Loading history...
690
					<?php esc_html_e( 'Upload CSV file', 'give' ); ?>
691
				</li>
692
				<li class="<?php echo( 2 === $step ? 'active' : '' ); ?>">
0 ignored issues
show
introduced by
Expected next thing to be a escaping function, not '('
Loading history...
693
					<?php esc_html_e( 'Column mapping', 'give' ); ?>
694
				</li>
695
				<li class="<?php echo( 3 === $step ? 'active' : '' ); ?>">
0 ignored issues
show
introduced by
Expected next thing to be a escaping function, not '('
Loading history...
696
					<?php esc_html_e( 'Import', 'give' ); ?>
697
				</li>
698
				<li class="<?php echo( 4 === $step ? 'active' : '' ); ?>">
0 ignored issues
show
introduced by
Expected next thing to be a escaping function, not '('
Loading history...
699
					<?php esc_html_e( 'Done!', 'give' ); ?>
700
				</li>
701
			</ol>
702
			<?php
703
		}
704
705
		/**
706
		 * Will return the import step.
707
		 *
708
		 * @since 1.8.14
709
		 *
710
		 * @return int $step on which step doest the import is on.
711
		 */
712 View Code Duplication
		public function get_step() {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
713
			$step    = (int) ( isset( $_REQUEST['step'] ) ? give_clean( $_REQUEST['step'] ) : 0 );
0 ignored issues
show
introduced by
Detected access of super global var $_REQUEST, probably need manual inspection.
Loading history...
introduced by
Detected usage of a non-sanitized input variable: $_REQUEST
Loading history...
714
			$on_step = 1;
715
716
			if ( empty( $step ) || 1 === $step ) {
717
				$on_step = 1;
718
			} elseif ( $this->check_for_dropdown_or_import() ) {
719
				$on_step = 3;
720
			} elseif ( 2 === $step ) {
721
				$on_step = 2;
722
			} elseif ( 4 === $step ) {
723
				$on_step = 4;
724
			}
725
726
			return $on_step;
727
		}
728
729
		/**
730
		 * Render donations import page
731
		 *
732
		 * @since 1.8.14
733
		 */
734
		public function render_page() {
735
			include_once GIVE_PLUGIN_DIR . 'includes/admin/tools/views/html-admin-page-import-donations.php';
736
		}
737
738
		/**
739
		 * Add CSV upload HTMl
740
		 *
741
		 * Print the html of the file upload from which CSV will be uploaded.
742
		 *
743
		 * @since 1.8.14
744
		 * @return void
745
		 */
746
		public function render_media_csv() {
747
			?>
748
			<tr valign="top">
749
				<th colspan="2">
750
					<h2 id="give-import-title"><?php esc_html_e( 'Import donations from a CSV file', 'give' ) ?></h2>
751
					<p class="give-field-description"><?php esc_html_e( 'This tool allows you to import or add donation data to your give form(s) via a CSV file.', 'give' ) ?></p>
752
				</th>
753
			</tr>
754
			<?php
755
			$csv         = ( isset( $_POST['csv'] ) ? give_clean( $_POST['csv'] ) : '' );
0 ignored issues
show
introduced by
Detected access of super global var $_POST, probably need manual inspection.
Loading history...
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
756
			$csv_id      = ( isset( $_POST['csv_id'] ) ? give_clean( $_POST['csv_id'] ) : '' );
0 ignored issues
show
introduced by
Detected access of super global var $_POST, probably need manual inspection.
Loading history...
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
757
			$delimiter   = ( isset( $_POST['delimiter'] ) ? give_clean( $_POST['delimiter'] ) : 'csv' );
0 ignored issues
show
introduced by
Detected access of super global var $_POST, probably need manual inspection.
Loading history...
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
758
			$mode        = empty( $_POST['mode'] ) ?
0 ignored issues
show
introduced by
Detected access of super global var $_POST, probably need manual inspection.
Loading history...
759
				'disabled' :
760
				( give_is_setting_enabled( give_clean( $_POST['mode'] ) ) ? 'enabled' : 'disabled' );
0 ignored issues
show
introduced by
Detected access of super global var $_POST, probably need manual inspection.
Loading history...
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
761
			$create_user = empty( $_POST['create_user'] ) ?
0 ignored issues
show
introduced by
Detected access of super global var $_POST, probably need manual inspection.
Loading history...
762
				'enabled' :
763
				( give_is_setting_enabled( give_clean( $_POST['create_user'] ) ) ? 'enabled' : 'disabled' );
0 ignored issues
show
introduced by
Detected access of super global var $_POST, probably need manual inspection.
Loading history...
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
764
			$delete_csv  = empty( $_POST['delete_csv'] ) ?
0 ignored issues
show
introduced by
Detected access of super global var $_POST, probably need manual inspection.
Loading history...
765
				'enabled' :
766
				( give_is_setting_enabled( give_clean( $_POST['delete_csv'] ) ) ? 'enabled' : 'disabled' );
0 ignored issues
show
introduced by
Detected access of super global var $_POST, probably need manual inspection.
Loading history...
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
767
768
			// Reset csv and csv_id if csv
769
			if ( empty( $csv_id ) || ! $this->is_valid_csv( $csv_id, $csv ) ) {
0 ignored issues
show
Bug introduced by
It seems like $csv defined by isset($_POST['csv']) ? g...ean($_POST['csv']) : '' on line 755 can also be of type array; however, Give_Import_Donations::is_valid_csv() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
770
				$csv_id = $csv = '';
771
			}
772
			$per_page = isset( $_POST['per_page'] ) ? absint( $_POST['per_page'] ) : self::$per_page;
0 ignored issues
show
introduced by
Detected access of super global var $_POST, probably need manual inspection.
Loading history...
773
774
			$settings = array(
775
				array(
776
					'id'          => 'csv',
777
					'name'        => __( 'Choose a CSV file:', 'give' ),
778
					'type'        => 'file',
779
					'attributes'  => array( 'editing' => 'false', 'library' => 'text' ),
780
					'description' => __( 'The file must be a Comma Seperated Version (CSV) file type only.', 'give' ),
781
					'fvalue'      => 'url',
782
					'default'     => $csv,
783
				),
784
				array(
785
					'id'    => 'csv_id',
786
					'type'  => 'hidden',
787
					'value' => $csv_id,
788
				),
789
				array(
790
					'id'          => 'delimiter',
791
					'name'        => __( 'CSV Delimiter:', 'give' ),
792
					'description' => __( 'In case your CSV file supports a different type of separator (or delimiter) -- like a tab or space -- you can set that here.', 'give' ),
793
					'default'     => $delimiter,
794
					'type'        => 'select',
795
					'options'     => array(
796
						'csv'                  => esc_html__( 'Comma', 'give' ),
797
						'tab-separated-values' => esc_html__( 'Tab', 'give' ),
798
					),
799
				),
800
				array(
801
					'id'          => 'mode',
802
					'name'        => __( 'Test Mode:', 'give' ),
803
					'description' => __( 'Test mode allows you to preview what this import would look like without making any actual changes to your site or your database.', 'give' ),
804
					'default'     => $mode,
805
					'type'        => 'radio_inline',
806
					'options'     => array(
807
						'enabled'  => __( 'Enabled', 'give' ),
808
						'disabled' => __( 'Disabled', 'give' ),
809
					),
810
				),
811
				array(
812
					'id'          => 'create_user',
813
					'name'        => __( 'Create WP users for new donors:', 'give' ),
814
					'description' => __( 'The importer can create WordPress user accounts based on the names and email addresses of the donations in your CSV file. Enable this option if you\'d like the importer to do that.', 'give' ),
815
					'default'     => $create_user,
816
					'type'        => 'radio_inline',
817
					'options'     => array(
818
						'enabled'  => __( 'Enabled', 'give' ),
819
						'disabled' => __( 'Disabled', 'give' ),
820
					),
821
				),
822
				array(
823
					'id'          => 'delete_csv',
824
					'name'        => __( 'Delete CSV after import:', 'give' ),
825
					'description' => __( 'Your CSV file will be uploaded via the WordPress Media Library. It\'s a good idea to delete it after the import is finished so that your sensitive data is not accessible on the web. Disable this only if you plan to delete the file manually later.', 'give' ),
826
					'default'     => $delete_csv,
827
					'type'        => 'radio_inline',
828
					'options'     => array(
829
						'enabled'  => __( 'Enabled', 'give' ),
830
						'disabled' => __( 'Disabled', 'give' ),
831
					),
832
				),
833
				array(
834
					'id'          => 'per_page',
835
					'name'        => __( 'Process Rows Per Batch:', 'give' ),
836
					'type'        => 'number',
837
					'description' => __( 'Determine how many rows you would like to import per cycle.', 'give' ),
838
					'default'     => $per_page,
839
					'class'       => 'give-text-small',
840
				),
841
			);
842
843
			$settings = apply_filters( 'give_import_file_upload_html', $settings );
844
845
			Give_Admin_Settings::output_fields( $settings, 'give_settings' );
846
		}
847
848
		/**
849
		 * Run when user click on the submit button.
850
		 *
851
		 * @since 1.8.14
852
		 */
853
		public function save() {
854
			// Get the current step.
855
			$step = $this->get_step();
856
857
			// Validation for first step.
858
			if ( 1 === $step ) {
859
				$csv_id = absint( $_POST['csv_id'] );
0 ignored issues
show
introduced by
Detected access of super global var $_POST, probably need manual inspection.
Loading history...
introduced by
Detected usage of a non-validated input variable: $_POST
Loading history...
860
861
				if ( $this->is_valid_csv( $csv_id, esc_url( $_POST['csv'] ) ) ) {
862
863
					$url = give_import_page_url( (array) apply_filters( 'give_import_step_two_url', array(
864
						'step'          => '2',
865
						'importer-type' => $this->importer_type,
866
						'csv'           => $csv_id,
867
						'delimiter'     => isset( $_REQUEST['delimiter'] ) ? give_clean( $_REQUEST['delimiter'] ) : 'csv',
0 ignored issues
show
introduced by
Detected access of super global var $_REQUEST, probably need manual inspection.
Loading history...
introduced by
Detected usage of a non-sanitized input variable: $_REQUEST
Loading history...
868
						'mode'          => empty( $_POST['mode'] ) ?
0 ignored issues
show
introduced by
Detected access of super global var $_POST, probably need manual inspection.
Loading history...
869
							'0' :
870
							( give_is_setting_enabled( give_clean( $_POST['mode'] ) ) ? '1' : '0' ),
0 ignored issues
show
introduced by
Detected access of super global var $_POST, probably need manual inspection.
Loading history...
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
871
						'create_user'   => empty( $_POST['create_user'] ) ?
0 ignored issues
show
introduced by
Detected access of super global var $_POST, probably need manual inspection.
Loading history...
872
							'0' :
873
							( give_is_setting_enabled( give_clean( $_POST['create_user'] ) ) ? '1' : '0' ),
0 ignored issues
show
introduced by
Detected access of super global var $_POST, probably need manual inspection.
Loading history...
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
874
						'delete_csv'    => empty( $_POST['delete_csv'] ) ?
0 ignored issues
show
introduced by
Detected access of super global var $_POST, probably need manual inspection.
Loading history...
875
							'1' :
876
							( give_is_setting_enabled( give_clean( $_POST['delete_csv'] ) ) ? '1' : '0' ),
0 ignored issues
show
introduced by
Detected access of super global var $_POST, probably need manual inspection.
Loading history...
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
877
						'per_page'      => isset( $_POST['per_page'] ) ? absint( $_POST['per_page'] ) : self::$per_page,
0 ignored issues
show
introduced by
Detected access of super global var $_POST, probably need manual inspection.
Loading history...
878
					) ) );
879
					?>
880
					<script type="text/javascript">
881
						window.location = "<?php echo $url; ?>"
0 ignored issues
show
introduced by
Expected next thing to be a escaping function, not '$url'
Loading history...
882
					</script>
883
					<?php
884
				}
885
			}
886
		}
887
888
		/**
889
		 * Check if user uploaded csv is valid or not.
890
		 *
891
		 * @since  1.8.14
892
		 * @access public
893
		 *
894
		 * @param mixed  $csv       ID of the CSV files.
895
		 * @param string $match_url ID of the CSV files.
896
		 *
897
		 * @return bool $has_error CSV is valid or not.
898
		 */
899
		private function is_valid_csv( $csv = false, $match_url = '' ) {
900
			$is_valid_csv = true;
901
902
			if ( $csv ) {
903
				$csv_url = wp_get_attachment_url( $csv );
904
905
				$delimiter = ( ! empty( $_REQUEST['delimiter'] ) ? give_clean( $_REQUEST['delimiter'] ) : 'csv' );
0 ignored issues
show
introduced by
Detected access of super global var $_REQUEST, probably need manual inspection.
Loading history...
introduced by
Detected usage of a non-sanitized input variable: $_REQUEST
Loading history...
906
907
				if (
908
					! $csv_url ||
909
					( ! empty( $match_url ) && ( $csv_url !== $match_url ) ) ||
910
					( ( $mime_type = get_post_mime_type( $csv ) ) && ! strpos( $mime_type, $delimiter ) )
911
				) {
912
					$is_valid_csv = false;
913
					Give_Admin_Settings::add_error( 'give-import-csv', __( 'Please upload or provide a valid CSV file.', 'give' ) );
914
				}
915
			} else {
916
				$is_valid_csv = false;
917
				Give_Admin_Settings::add_error( 'give-import-csv', __( 'Please upload or provide a valid CSV file.', 'give' ) );
918
			}
919
920
			return $is_valid_csv;
921
		}
922
923
924
		/**
925
		 * Render report import field
926
		 *
927
		 * @since  1.8.14
928
		 * @access public
929
		 *
930
		 * @param $field
931
		 * @param $option_value
932
		 */
933
		public function render_import_field( $field, $option_value ) {
934
			include_once GIVE_PLUGIN_DIR . 'includes/admin/tools/views/html-admin-page-imports.php';
935
		}
936
937
		/**
938
		 * Get if current page import donations page or not
939
		 *
940
		 * @since 1.8.14
941
		 * @return bool
942
		 */
943
		private function is_donations_import_page() {
944
			return 'import' === give_get_current_setting_tab() &&
945
			       isset( $_GET['importer-type'] ) &&
0 ignored issues
show
introduced by
Detected access of super global var $_GET, probably need manual inspection.
Loading history...
946
			       $this->importer_type === give_clean( $_GET['importer-type'] );
0 ignored issues
show
introduced by
Detected access of super global var $_GET, probably need manual inspection.
Loading history...
introduced by
Detected usage of a non-sanitized input variable: $_GET
Loading history...
947
		}
948
	}
949
950
	Give_Import_Donations::get_instance()->setup();
951
}
952