Issues (2873)

Security Analysis    not enabled

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

classes/PodsMigrate.php (59 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
/**
4
 * @package Pods
5
 */
6
class PodsMigrate {
7
8
	/**
9
	 * @var null|string
10
	 */
11
	public $type = 'php';
12
13
	/**
14
	 * @var array
15
	 */
16
	public $types = array( 'php', 'json', 'sv', 'xml' );
17
18
	/**
19
	 * @var array
20
	 */
21
	public $mimes = array(
22
		'json' => 'application/json',
23
		'csv'  => 'text/csv',
24
		'tsv'  => 'text/tsv',
25
		'xml'  => 'text/xml',
26
	);
27
28
	/**
29
	 * @var null|string
30
	 */
31
	public $delimiter = ',';
32
33
	/**
34
	 * @var null
35
	 */
36
	public $data = array(
37
		'items'   => array(),
38
		'columns' => array(),
39
		'fields'  => array(),
40
		'single'  => false,
41
	);
42
43
	/**
44
	 * @var null
45
	 */
46
	public $input;
47
48
	/**
49
	 * @var
50
	 */
51
	public $parsed;
52
53
	/**
54
	 * @var
55
	 */
56
	public $built;
57
58
	/**
59
	 * Migrate Data to and from Pods
60
	 *
61
	 * @param string $type      Export Type (php, json, sv, xml)
0 ignored issues
show
Should the type for parameter $type not be string|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
62
	 * @param string $delimiter Delimiter for export type 'sv'
0 ignored issues
show
Should the type for parameter $delimiter not be string|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
63
	 * @param array  $data      Array of data settings
0 ignored issues
show
Should the type for parameter $data not be array|null? Also, consider making the array more specific, something like array<String>, or String[].

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive. In addition it looks for parameters that have the generic type array and suggests a stricter type like array<String>.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
64
	 *
65
	 * @return \PodsMigrate
0 ignored issues
show
Comprehensibility Best Practice introduced by
Adding a @return annotation to constructors is generally not recommended as a constructor does not have a meaningful return value.

Adding a @return annotation to a constructor is not recommended, since a constructor does not have a meaningful return value.

Please refer to the PHP core documentation on constructors.

Loading history...
66
	 *
67
	 * @license http://www.gnu.org/licenses/gpl-2.0.html
68
	 * @since   2.0
69
	 */
70
	public function __construct( $type = null, $delimiter = null, $data = null ) {
71
72
		if ( ! empty( $type ) ) {
73
			if ( 'csv' === $type ) {
74
				$type = 'sv';
75
76
				if ( null === $delimiter ) {
77
					$delimiter = ',';
78
				}
79
			} elseif ( 'tsv' === $type ) {
80
				$type = 'sv';
81
82
				if ( null === $delimiter ) {
83
					$delimiter = "\t";
84
				}
85
			}
86
87
			if ( in_array( $type, $this->types, true ) ) {
88
				$this->type = $type;
89
			}
90
		}
91
92
		if ( ! empty( $delimiter ) ) {
93
			$this->delimiter = $delimiter;
94
		}
95
96
		if ( ! empty( $data ) ) {
97
			$this->set_data( $data );
98
		}
99
	}
100
101
	/**
102
	 * @param $data
103
	 */
104
	public function set_data( $data ) {
105
106
		$defaults = array(
107
			'items'   => array(),
108
			'columns' => array(),
109
			'fields'  => array(),
110
		);
111
112
		$this->data = array_merge( $defaults, (array) $data );
113
	}
114
115
	/**
116
	 * Importing / Parsing / Validating Code
117
	 *
118
	 * @param array  $data      Array of data
0 ignored issues
show
Should the type for parameter $data not be array|null? Also, consider making the array more specific, something like array<String>, or String[].

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive. In addition it looks for parameters that have the generic type array and suggests a stricter type like array<String>.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
119
	 * @param string $type      Export Type (php, json, sv, xml)
0 ignored issues
show
Should the type for parameter $type not be string|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
120
	 * @param string $delimiter Delimiter for export type 'sv'
0 ignored issues
show
Should the type for parameter $delimiter not be string|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
121
	 *
122
	 * @return bool
123
	 */
124
	public function import( $data = null, $type = null, $delimiter = null ) {
125
126
		$this->parse( $data, $type, $delimiter );
127
128
		return $this->import_pod_items();
129
130
	}
131
132
	/**
133
	 * @param array  $data Array of data
0 ignored issues
show
Should the type for parameter $data not be array|null? Also, consider making the array more specific, something like array<String>, or String[].

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive. In addition it looks for parameters that have the generic type array and suggests a stricter type like array<String>.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
134
	 * @param string $type Export Type (php, json, sv, xml)
0 ignored issues
show
Should the type for parameter $type not be string|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
135
	 *
136
	 * @return bool
137
	 */
138
	public function import_pod_items( $data = null, $type = null ) {
139
140
		if ( ! empty( $data ) ) {
141
			$this->input = $data;
142
		}
143
144
		if ( ! empty( $type ) && in_array( $type, $this->types, true ) ) {
145
			$this->type = $type;
146
		}
147
148
		return false;
149
	}
150
151
	/**
152
	 * @param array $data       Array of data
0 ignored issues
show
Should the type for parameter $data not be array|null? Also, consider making the array more specific, something like array<String>, or String[].

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive. In addition it looks for parameters that have the generic type array and suggests a stricter type like array<String>.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
153
	 * @param string $type      Parse Type (php, json, sv, xml)
0 ignored issues
show
Should the type for parameter $type not be string|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
154
	 * @param string $delimiter Delimiter for export type 'sv'
0 ignored issues
show
Should the type for parameter $delimiter not be string|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
155
	 *
156
	 * @return null
157
	 */
158
	public function parse( $data = null, $type = null, $delimiter = null ) {
159
160
		if ( ! empty( $data ) ) {
161
			$this->input = $data;
162
		}
163
164
		if ( ! empty( $type ) && in_array( $type, $this->types, true ) ) {
165
			$this->type = $type;
166
		}
167
168
		if ( !empty( $delimiter ) )
169
			$this->delimiter = $delimiter;
170
171
		if ( method_exists( $this, "parse_{$this->type}" ) ) {
172
			return call_user_func( array( $this, 'parse_' . $this->type ) );
173
		}
174
175
		return $this->parsed;
176
	}
177
178
	/**
179
	 * @param array $data Array of data
0 ignored issues
show
Should the type for parameter $data not be array|null? Also, consider making the array more specific, something like array<String>, or String[].

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive. In addition it looks for parameters that have the generic type array and suggests a stricter type like array<String>.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
180
	 *
181
	 * @return bool
0 ignored issues
show
Should the return type not be false|array? Also, consider making the array more specific, something like array<String>, or String[].

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

If the return type contains the type array, this check recommends the use of a more specific type like String[] or array<String>.

Loading history...
182
	 */
183
	public function parse_json( $data = null ) {
184
185
		if ( ! empty( $data ) ) {
186
			$this->input = $data;
187
		}
188
189
		$items = @json_decode( $this->input, true );
0 ignored issues
show
Silencing errors is discouraged
Loading history...
190
191
		if ( ! is_array( $items ) ) {
192
			return false;
193
		}
194
195
		// Only export to a basic object if building for a single item.
196
		if ( ! empty( $this->data['single'] ) ) {
197
			$data = $items;
198
		} else {
199
			$data = array(
200
				'columns' => array(),
201
				'items'   => array(),
202
				'fields'  => array(),
203
			);
204
205
			foreach ( $items as $key => $item ) {
206
				if ( ! is_array( $item ) ) {
207
					continue;
208
				}
209
210
				foreach ( $item as $column => $value ) {
211
					if ( ! in_array( $column, $data['columns'], true ) ) {
212
						$data['columns'][] = $column;
213
					}
214
				}
215
216
				$data['items'][ $key ] = $item;
217
			}
218
		}
219
220
		$this->parsed = $data;
221
222
		return $this->parsed;
223
	}
224
225
	/**
226
	 * @param array  $data      Array of data
0 ignored issues
show
Should the type for parameter $data not be array|null? Also, consider making the array more specific, something like array<String>, or String[].

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive. In addition it looks for parameters that have the generic type array and suggests a stricter type like array<String>.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
227
	 * @param string $delimiter Delimiter for export type 'sv'
0 ignored issues
show
Should the type for parameter $delimiter not be string|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
228
	 *
229
	 * @return bool
0 ignored issues
show
Should the return type not be false|array<string,array>?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
230
	 */
231
	public function parse_sv( $data = null, $delimiter = null ) {
232
233
		if ( ! empty( $data ) ) {
234
			$this->input = $data;
235
		}
236
237
		if ( ! empty( $delimiter ) ) {
238
			$this->delimiter = $delimiter;
239
		}
240
241
		$rows = $this->str_getcsv( $this->input, '\n' );
242
243
		if ( empty( $rows ) || 2 > count( $rows ) ) {
244
			return false;
245
		}
246
247
		$data = array(
248
			'columns' => array(),
249
			'items'   => array(),
250
		);
251
252
		foreach ( $rows as $key => $row ) {
253
			if ( 0 === $key ) {
254
				$data['columns'] = $this->str_getcsv( $row, $this->delimiter );
255
			} else {
256
				$row = $this->str_getcsv( $row, $this->delimiter );
257
258
				$data['items'][ $key ] = array();
259
260
				foreach ( $data['columns'] as $ckey => $column ) {
261
					$data['items'][ $key ][ $column ] = ( isset( $row[ $ckey ] ) ? $row[ $ckey ] : '' );
262
263
					if ( 'NULL' === $data['items'][ $key ][ $column ] ) {
264
						$data['items'][ $key ][ $column ] = null;
265
					}
266
				}
267
			}
268
		}
269
270
		$this->parsed = $data;
271
272
		return $this->parsed;
273
	}
274
275
	/**
276
	 * Handle str_getcsv for cases where it's not set
277
	 *
278
	 * @param        $line
279
	 * @param string $delimiter
280
	 * @param string $enclosure
281
	 * @param string $escape
282
	 *
283
	 * @return array|mixed
284
	 */
285
	public function str_getcsv( $line, $delimiter = ',', $enclosure = '"', $escape = '\\' ) {
286
287
		$line = str_replace( "\r\n", "\n", $line );
288
		$line = str_replace( "\r", "\n", $line );
289
290
		if ( '\n' !== $delimiter && function_exists( 'str_getcsv' ) ) {
291
			return str_getcsv( $line, $delimiter, $enclosure, $escape );
292
		}
293
294
		$delimiter = str_replace( '/', '\/', $delimiter );
295
		$enclosure = preg_quote( $enclosure, '/' );
296
297
		$split = "/{$delimiter}(?=(?:[^{$enclosure}]*{$enclosure}[^{$enclosure}]*{$enclosure})*(?![^{$enclosure}]*{$enclosure}))/";
298
299
		$data = preg_split( $split, trim( $line ), - 1, PREG_SPLIT_NO_EMPTY );
300
301
		if ( '\n' !== $delimiter ) {
302
			$data = preg_replace( "/^{$enclosure}(.*){$enclosure}$/s", '$1', $data );
303
		}
304
305
		return $data;
306
	}
307
308
	/**
309
	 * @param array $data Array of data
0 ignored issues
show
Should the type for parameter $data not be array|null? Also, consider making the array more specific, something like array<String>, or String[].

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive. In addition it looks for parameters that have the generic type array and suggests a stricter type like array<String>.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
310
	 *
311
	 * @return bool
0 ignored issues
show
Should the return type not be false|array<string,array>?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
312
	 */
313
	public function parse_xml( $data = null ) {
314
315
		if ( ! empty( $data ) ) {
316
			$this->input = $data;
317
		}
318
319
		$xml = new SimpleXMLElement( $this->input );
320
321
		if ( ! isset( $xml->items ) ) {
322
			return false;
323
		}
324
325
		$data = array(
326
			'columns' => array(),
327
			'items'   => array(),
328
		);
329
330
		/**
331
		 * @var $child      SimpleXMLElement
332
		 * @var $item_child SimpleXMLElement
333
		 * @var $data_child SimpleXMLElement
334
		 */
335
336
		if ( isset( $xml->columns ) ) {
337
			foreach ( $xml->columns->children() as $child ) {
338
				$sub = $child->getName();
339
340
				if ( empty( $sub ) || 'column' !== $sub ) {
341
					continue;
342
				}
343
344
				if ( isset( $child->name ) ) {
345
					if ( is_array( $child->name ) ) {
346
						$column = $child->name[0];
347
					} else {
348
						$column = $child->name;
349
					}
350
351
					$data['columns'][] = $column;
352
				}
353
			}
354
		}
355
356
		foreach ( $xml->items->children() as $child ) {
357
			$sub = $child->getName();
358
359
			if ( empty( $sub ) || 'item' !== $sub ) {
360
				continue;
361
			}
362
363
			$item = array();
364
365
			$attributes = $child->attributes();
366
367
			if ( ! empty( $attributes ) ) {
368
				foreach ( $attributes as $column => $value ) {
369
					if ( ! in_array( $column, $data['columns'], true ) ) {
370
						$data['columns'][] = $column;
371
					}
372
373
					$item[ $column ] = $value;
374
				}
375
			}
376
377
			$item_child = $child->children();
378
379
			if ( ! empty( $item_child ) ) {
380
				foreach ( $item_child->children() as $data_child ) {
381
					$column = $data_child->getName();
382
383
					if ( ! in_array( $column, $data['columns'], true ) ) {
384
						$data['columns'][] = $column;
385
					}
386
387
					$item[ $column ] = $item_child->$column;
388
				}
389
			}
390
391
			if ( ! empty( $item ) ) {
392
				$data['items'][] = $item;
393
			}
394
		}//end foreach
395
396
		$this->parsed = $data;
397
398
		return $this->parsed;
399
	}
400
401
	/**
402
	 * @param array $data Array of data
0 ignored issues
show
Should the type for parameter $data not be array|null? Also, consider making the array more specific, something like array<String>, or String[].

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive. In addition it looks for parameters that have the generic type array and suggests a stricter type like array<String>.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
403
	 *
404
	 * @return mixed
0 ignored issues
show
Consider making the return type a bit more specific; maybe use array|null.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
405
	 *
406
	 * @todo For much much later
407
	 */
408
	public function parse_sql( $data = null ) {
409
410
		if ( ! empty( $data ) ) {
411
			$this->input = $data;
412
		}
413
414
		$this->parsed = $data;
415
416
		return $this->parsed;
417
	}
418
419
	/**
420
	 * Exporting / Building Code
421
	 *
422
	 * @param array  $data      Array of data
0 ignored issues
show
Should the type for parameter $data not be array|null? Also, consider making the array more specific, something like array<String>, or String[].

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive. In addition it looks for parameters that have the generic type array and suggests a stricter type like array<String>.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
423
	 * @param string $type      Export Type (php, json, sv, xml)
0 ignored issues
show
Should the type for parameter $type not be string|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
424
	 * @param string $delimiter Delimiter for export type 'sv'
0 ignored issues
show
Should the type for parameter $delimiter not be string|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
425
	 *
426
	 * @return mixed
0 ignored issues
show
Consider making the return type a bit more specific; maybe use string|array|null.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
427
	 */
428
	public function export( $data = null, $type = null, $delimiter = null ) {
429
430
		if ( ! empty( $data ) ) {
431
			$this->set_data( $data );
432
		}
433
434
		if ( ! empty( $type ) && in_array( $type, $this->types, true ) ) {
435
			$this->type = $type;
436
		}
437
438
		if ( ! empty( $delimiter ) ) {
439
			$this->delimiter = $delimiter;
440
		}
441
442
		if ( method_exists( $this, "build_{$this->type}" ) ) {
443
			call_user_func( array( $this, 'build_' . $this->type ) );
444
		}
445
446
		return $this->built;
447
	}
448
449
	/**
450
	 * @param array $data Array of data
0 ignored issues
show
Should the type for parameter $data not be array|null? Also, consider making the array more specific, something like array<String>, or String[].

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive. In addition it looks for parameters that have the generic type array and suggests a stricter type like array<String>.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
451
	 */
452
	public function export_pod_items( $data = null ) {
453
454
		if ( ! empty( $data ) ) {
455
			$this->set_data( $data );
456
		}
457
	}
458
459
	/**
460
	 * @param array  $data Array of data
0 ignored issues
show
Should the type for parameter $data not be array|null? Also, consider making the array more specific, something like array<String>, or String[].

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive. In addition it looks for parameters that have the generic type array and suggests a stricter type like array<String>.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
461
	 * @param string $type Export Type (php, json, sv, xml)
0 ignored issues
show
Should the type for parameter $type not be string|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
462
	 *
463
	 * @return null
464
	 */
465
	public function build( $data = null, $type = null ) {
466
467
		if ( ! empty( $data ) ) {
468
			$this->set_data( $data );
469
		}
470
471
		if ( ! empty( $type ) && in_array( $type, $this->types, true ) ) {
472
			$this->type = $type;
473
		}
474
475
		if ( method_exists( $this, "build_{$this->type}" ) ) {
476
			call_user_func( array( $this, 'build_' . $this->type ) );
477
		}
478
479
		return $this->data;
480
	}
481
482
	/**
483
	 * @param array $data Array of data
0 ignored issues
show
Should the type for parameter $data not be array|null? Also, consider making the array more specific, something like array<String>, or String[].

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive. In addition it looks for parameters that have the generic type array and suggests a stricter type like array<String>.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
484
	 *
485
	 * @return bool
486
	 */
487
	public function build_json( $data = null ) {
488
489
		if ( ! empty( $data ) ) {
490
			$this->set_data( $data );
491
		}
492
493
		if ( empty( $this->data ) || ! is_array( $this->data ) ) {
494
			return false;
495
		}
496
497
		// Only export to a basic object if building for a single item.
498
		if ( ! empty( $this->data['single'] ) ) {
499
			$data = $this->data['items'];
500
		} else {
501
			$data = array(
502
				'items' => array(
503
					'count' => count( $this->data['items'] ),
504
					'item'  => array(),
505
				),
506
			);
507
508
			foreach ( $this->data['items'] as $item ) {
509
				$row = array();
510
511
				foreach ( $this->data['columns'] as $column => $label ) {
512
					if ( is_numeric( $column ) && ( ( is_object( $item ) && ! isset( $item->$column ) ) || ( is_array( $item ) && ! isset( $item[ $column ] ) ) ) ) {
513
						$column = $label;
514
					}
515
516
					$value = '';
517
518
					if ( is_object( $item ) ) {
519
						if ( ! isset( $item->$column ) ) {
520
							$item->$column = '';
521
						}
522
523
						$value = $item->$column;
524
					} elseif ( is_array( $item ) ) {
525
						if ( ! isset( $item[ $column ] ) ) {
526
							$item[ $column ] = '';
527
						}
528
529
						$value = $item[ $column ];
530
					}
531
532
					$row[ $column ] = $value;
533
				}//end foreach
534
535
				$data['items']['item'][] = $row;
536
			}//end foreach
537
		}
538
539
		$this->built = @json_encode( $data );
0 ignored issues
show
Silencing errors is discouraged
Loading history...
540
541
		return $this->built;
542
	}
543
544
	/**
545
	 * @param array  $data      Array of data
0 ignored issues
show
Should the type for parameter $data not be array|null? Also, consider making the array more specific, something like array<String>, or String[].

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive. In addition it looks for parameters that have the generic type array and suggests a stricter type like array<String>.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
546
	 * @param string $delimiter Delimiter for export type 'sv'
0 ignored issues
show
Should the type for parameter $delimiter not be string|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
547
	 *
548
	 * @return bool
0 ignored issues
show
Should the return type not be false|string?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
549
	 */
550
	public function build_sv( $data = null, $delimiter = null ) {
551
552
		if ( ! empty( $data ) ) {
553
			$this->set_data( $data );
554
		}
555
556
		if ( ! empty( $delimiter ) ) {
557
			$this->delimiter = $delimiter;
558
		}
559
560
		if ( empty( $this->data ) || ! is_array( $this->data ) ) {
561
			return false;
562
		}
563
564
		$head  = '';
565
		$lines = '';
566
567
		foreach ( $this->data['columns'] as $column => $label ) {
568
			$head .= '"' . $label . '"' . $this->delimiter;
569
		}
570
571
		$head = substr( $head, 0, - 1 );
572
573
		foreach ( $this->data['items'] as $item ) {
574
			$line = '';
575
576
			foreach ( $this->data['columns'] as $column => $label ) {
577
				if ( is_numeric( $column ) && ( ( is_object( $item ) && ! isset( $item->$column ) ) || ( is_array( $item ) && ! isset( $item[ $column ] ) ) ) ) {
578
					$column = $label;
579
				}
580
581
				$value = '';
582
583
				if ( is_object( $item ) ) {
584
					if ( ! isset( $item->$column ) ) {
585
						$item->$column = '';
586
					}
587
588
					$value = $item->$column;
589
				} elseif ( is_array( $item ) ) {
590
					if ( ! isset( $item[ $column ] ) ) {
591
						$item[ $column ] = '';
592
					}
593
594
					$value = $item[ $column ];
595
				}
596
597
				if ( is_array( $value ) || is_object( $value ) ) {
598
					$value = pods_serial_comma(
599
						$value, array(
600
							'field'  => $column,
601
							'fields' => pods_var_raw( $column, $this->data['fields'] ),
602
							'and'    => '',
603
						)
604
					);
605
				}
606
607
				$value = str_replace( array( '"', "\r\n", "\r", "\n" ), array( '\\"', "\n", "\n", '\n' ), $value );
608
609
				$line .= '"' . $value . '"' . $this->delimiter;
610
			}//end foreach
611
612
			$lines .= substr( $line, 0, - 1 ) . "\n";
613
		}//end foreach
614
615
		if ( ! empty( $lines ) ) {
616
			$lines = "\n" . substr( $lines, 0, - 1 );
617
		}
618
619
		$this->built = $head . $lines;
620
621
		return $this->built;
622
	}
623
624
	/**
625
	 * @param array $data Array of data
0 ignored issues
show
Should the type for parameter $data not be array|null? Also, consider making the array more specific, something like array<String>, or String[].

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive. In addition it looks for parameters that have the generic type array and suggests a stricter type like array<String>.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
626
	 *
627
	 * @return bool
0 ignored issues
show
Should the return type not be false|string?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
628
	 */
629
	public function build_xml( $data = null ) {
630
631
		if ( ! empty( $data ) ) {
632
			$this->set_data( $data );
633
		}
634
635
		if ( empty( $this->data ) || ! is_array( $this->data ) ) {
636
			return false;
637
		}
638
639
		$head  = '<' . '?' . 'xml version="1.0" encoding="utf-8" ' . '?' . '>' . "\r\n<items count=\"" . count( $this->data['items'] ) . "\">\r\n";
640
		$lines = '';
641
642
		foreach ( $this->data['items'] as $item ) {
643
			$line = "\t<item>\r\n";
644
645
			foreach ( $this->data['columns'] as $column => $label ) {
646
				if ( is_numeric( $column ) && ( ( is_object( $item ) && ! isset( $item->$column ) ) || ( is_array( $item ) && ! isset( $item[ $column ] ) ) ) ) {
647
					$column = $label;
648
				}
649
650
				$line .= $this->build_xml_level( $item, $column );
651
			}
652
653
			$line  .= "\t</item>\r\n";
654
			$lines .= $line;
655
		}
656
657
		$foot = '</items>';
658
659
		$this->built = $head . $lines . $foot;
660
661
		return $this->built;
662
	}
663
664
	/**
665
	 * @param array|object $item
666
	 * @param string       $column
667
	 * @param int          $level
668
	 * @param string       $column_name
669
	 *
670
	 * @return string
671
	 */
672
	public function build_xml_level( $item, $column, $level = 2, $column_name = '' ) {
673
674
		$column = pods_clean_name( $column, false, false );
675
676
		$line = '';
677
678
		$value = '';
679
680
		if ( is_object( $item ) ) {
681
			if ( ! isset( $item->$column ) ) {
682
				$item->$column = '';
683
			}
684
685
			$value = $item->$column;
686
		} elseif ( is_array( $item ) ) {
687
			if ( ! isset( $item[ $column ] ) ) {
688
				$item[ $column ] = '';
689
			}
690
691
			$value = $item[ $column ];
692
		}
693
694
		if ( ! empty( $column_name ) ) {
695
			$column = $column_name;
696
		}
697
698
		$tabs = str_repeat( "\t", $level );
699
700
		$line .= $tabs . "<{$column}>";
701
702
		if ( is_array( $value ) || is_object( $value ) ) {
703
			if ( is_object( $value ) ) {
704
				$value = get_object_vars( $value );
705
			}
706
707
			foreach ( $value as $k => $v ) {
708
				if ( is_int( $k ) ) {
709
					$line .= $this->build_xml_level( $value, $k, $level + 1, 'value' );
710
				} else {
711
					$line .= $this->build_xml_level( $value, $k, $level + 1 );
712
				}
713
			}
714
		} elseif ( false !== strpos( $value, '<' ) ) {
715
			$value = str_replace( array( '<![CDATA[', ']]>' ), array( '&lt;![CDATA[', ']]&gt;' ), $value );
716
717
			$line .= '<![CDATA[' . $value . ']]>';
718
		} else {
719
			$line .= str_replace( '&', '&amp;', $value );
720
		}
721
722
		$line .= "</{$column}>\r\n";
723
724
		return $line;
725
	}
726
727
	/**
728
	 * @param array $data Array of data
0 ignored issues
show
Should the type for parameter $data not be array|null? Also, consider making the array more specific, something like array<String>, or String[].

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive. In addition it looks for parameters that have the generic type array and suggests a stricter type like array<String>.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
729
	 *
730
	 * @return mixed
0 ignored issues
show
Consider making the return type a bit more specific; maybe use array|null.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
731
	 */
732
	public function build_sql( $data = null ) {
733
734
		if ( ! empty( $data ) ) {
735
			$this->set_data( $data );
736
		}
737
738
		$this->built = $data;
739
740
		return $this->built;
741
	}
742
743
	/**
744
	 * Save export to a file.
745
	 *
746
	 * @param array $params Additional options for saving.
747
	 *
748
	 * @return string The URL of the saved file, a path if not attached.
749
	 */
750
	public function save( $params = array() ) {
751
752
		$defaults = array(
753
			'file'   => null,
754
			'path'   => null,
755
			'attach' => false,
756
		);
757
758
		$params = array_merge( $defaults, $params );
759
760
		$extension = 'txt';
761
762
		if ( ! empty( $params['file'] ) ) {
763
			$export_file = $params['file'];
764
765
			if ( false !== strpos( $export_file, '.' ) ) {
766
				$extension = explode( '.', $export_file );
767
				$extension = end( $extension );
768
			}
769
		} else {
770
			if ( 'sv' === $this->type ) {
771
				if ( ',' === $this->delimiter ) {
772
					$extension = 'csv';
773
				} elseif ( "\t" === $this->delimiter ) {
774
					$extension = 'tsv';
775
				}
776
			} else {
777
				$extension = $this->type;
778
			}
779
780
			$export_file = sprintf(
781
				'pods_export_%s.%s',
782
				wp_create_nonce( date_i18n( 'm-d-Y_h-i-sa' ) ),
783
				$extension
784
			);
785
		}
786
787
		if ( ! empty( $params['path'] ) ) {
788
			$new_file = sprintf(
789
				'%s/%s',
790
				untrailingslashit( $params['path'] ),
791
				$export_file
792
			);
793
794
			$filename = $export_file;
795
		} else {
796
			$uploads = wp_upload_dir( current_time( 'mysql' ) );
797
798
			if ( ! $uploads || false === $uploads['error'] ) {
799
				return pods_error( __( 'There was an issue saving the export file in your uploads folder.', 'pods' ), true );
800
			}
801
802
			// Generate unique file name
803
			$filename = wp_unique_filename( $uploads['path'], $export_file );
804
805
			// move the file to the uploads dir
806
			$new_file = $uploads['path'] . '/' . $filename;
807
		}
808
809
		file_put_contents( $new_file, $this->built );
0 ignored issues
show
Filesystem writes are forbidden, you should not be using file_put_contents()
Loading history...
810
811
		// Set correct file permissions
812
		$stat  = stat( dirname( $new_file ) );
813
		$perms = $stat['mode'] & 0000666;
814
		@chmod( $new_file, $perms );
0 ignored issues
show
Silencing errors is discouraged
Loading history...
Filesystem writes are forbidden, you should not be using chmod()
Loading history...
815
816
		// Only attach if we want to and don't have a custom path.
817
		if ( $params['attach'] && empty( $params['path'] ) ) {
818
			// Get the file type
819
			$wp_filetype = wp_check_filetype( $filename, $this->mimes );
820
821
			// construct the attachment array
822
			$attachment = array(
823
				'post_mime_type' => 'text/' . $extension,
824
				'guid'           => $uploads['url'] . '/' . $filename,
0 ignored issues
show
The variable $uploads does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
825
				'post_parent'    => null,
826
				'post_title'     => 'Pods Export (' . $export_file . ')',
827
				'post_content'   => '',
828
				'post_status'    => 'private'
829
			);
830
831
			if ( $wp_filetype['type'] ) {
832
				$attachment['post_mime_type'] = $wp_filetype['type'];
833
			}
834
835
			// insert attachment
836
			$attachment_id = wp_insert_attachment( $attachment, $new_file );
837
838
			// error!
839
			if ( is_wp_error( $attachment_id ) ) {
840
				return pods_error( __( 'There was an issue saving the export file in your uploads folder.', 'pods' ), true );
841
			}
842
843
			$url = $attachment['guid'];
844
		} else {
845
			$url = $new_file;
846
		}
847
848
		return $url;
849
850
	}
851
852
	/*
853
	* The real enchilada!
854
	*/
855
	/*
0 ignored issues
show
Unused Code Comprehensibility introduced by
61% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
856
	 EXAMPLES
857
	//// minimal import (if your fields match on both your pods and tables)
858
	$import = array('my_pod' => array('table' => 'my_table')); // if your table name doesn't match the pod name
859
	$import = array('my_pod'); // if your table name matches your pod name
860
861
	//// advanced import
862
	$import = array();
863
	$import['my_pod'] = array();
864
	$import['my_pod']['fields']['this_field'] = 'field_name_in_table'; // if the field name doesn't match on table and pod
865
	$import['my_pod']['fields'][] = 'that_field'; // if the field name matches on table and pod
866
	$import['my_pod']['fields']['this_other_field'] = array('filter' => 'wpautop'); // if you want the value to be different than is provided, set a filter function to use [filter uses = filter_name($value,$rowdata)]
867
	$import['my_pod']['fields']['another_field'] = array('field' => 'the_real_field_in_table','filter' => 'my_custom_function'); // if you want the value to be filtered, and the field name doesn't match on the table and pod
868
	$import[] = 'my_other_pod'; // if your table name matches your pod name
869
	$import['another_pod'] = array('update_on' => 'main_field'); // you can update a pod item if the value of this field is the same on both tables
870
	$import['another_pod'] = array('reset' => true); // you can choose to reset all data in a pod before importing
871
872
	//// run import
873
	pods_import_it($import);
874
	*/
875
	/**
876
	 * @param      $import
877
	 * @param bool   $output
878
	 */
879
	public function heres_the_beef( $import, $output = true ) {
880
881
		global $wpdb;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
882
883
		$api = pods_api();
884
885
		for ( $i = 0; $i < 40000; $i ++ ) {
886
			echo "  \t";
887
			// extra spaces
888
		}
889
890
		$default_data = array(
891
			'pod'            => null,
892
			'table'          => null,
893
			'reset'          => null,
894
			'update_on'      => null,
895
			'where'          => null,
896
			'fields'         => array(),
897
			'row_filter'     => null,
898
			'pre_save'       => null,
899
			'post_save'      => null,
900
			'sql'            => null,
901
			'sort'           => null,
902
			'limit'          => null,
903
			'page'           => null,
904
			'output'         => null,
905
			'page_var'       => 'ipg',
906
			'bypass_helpers' => false,
907
		);
908
909
		$default_field_data = array(
910
			'field'  => null,
911
			'filter' => null,
912
		);
913
914
		if ( ! is_array( $import ) ) {
915
			$import = array( $import );
916
		} elseif ( empty( $import ) ) {
917
			die( '<h1 style="color:red;font-weight:bold;">ERROR: No imports configured</h1>' );
918
		}
919
920
		$import_counter = 0;
921
		$total_imports  = count( $import );
922
		$paginated      = false;
923
		$avg_time       = - 1;
924
		$total_time     = 0;
925
		$counter        = 0;
926
		$avg_unit       = 100;
927
		$avg_counter    = 0;
928
929
		foreach ( $import as $datatype => $data ) {
930
			$import_counter ++;
931
932
			flush();
933
			@ob_end_flush();
0 ignored issues
show
Silencing errors is discouraged
Loading history...
934
			usleep( 50000 );
935
936
			if ( ! is_array( $data ) ) {
937
				$datatype = $data;
938
				$data     = array( 'table' => $data );
939
			}
940
941
			if ( isset( $data[0] ) ) {
942
				$data = array( 'table' => $data[0] );
943
			}
944
945
			$data = array_merge( $default_data, $data );
946
947
			if ( null === $data['pod'] ) {
948
				$data['pod'] = array( 'name' => $datatype );
949
			}
950
951
			if ( false !== $output ) {
952
				echo '<br />' . date( 'Y-m-d h:i:sa' ) . ' - <em>' . $data['pod']['name'] . '</em> - <em>' . $data['pod']['name'] . '</em> - <strong>Loading Pod: ' . $data['pod']['name'] . "</strong>\n";
953
			}
954
955
			if ( 2 > count( $data['pod'] ) ) {
956
				$data['pod'] = $api->load_pod( array( 'name' => $data['pod']['name'] ) );
957
			}
958
959
			if ( empty( $data['pod']['fields'] ) ) {
960
				continue;
961
			}
962
963
			if ( null === $data['table'] ) {
964
				$data['table'] = $data['pod']['name'];
965
			}
966
967
			if ( $data['reset'] === true ) {
0 ignored issues
show
Found "=== true". Use Yoda Condition checks, you must
Loading history...
968
				if ( false !== $output ) {
969
					echo '<br />' . date( 'Y-m-d h:i:sa' ) . ' - <em>' . $data['pod']['name'] . "</em> - <strong style='color:blue;'>Resetting Pod: " . $data['pod']['name'] . "</strong>\n";
970
				}
971
972
				$api->reset_pod(
973
					array(
974
						'id'   => $data['pod']['id'],
975
						'name' => $data['pod']['name'],
976
					)
977
				);
978
			}
979
980
			if ( null === $data['sort'] && null !== $data['update_on'] && isset( $data['fields'][ $data['update_on'] ] ) ) {
981
				if ( isset( $data['fields'][ $data['update_on'] ]['field'] ) ) {
982
					$data['sort'] = $data['fields'][ $data['update_on'] ]['field'];
983
				} else {
984
					$data['sort'] = $data['update_on'];
985
				}
986
			}
987
988
			$page = 1;
989
990
			if ( false !== $data['page_var'] && isset( $_GET[ $data['page_var'] ] ) ) {
991
				$page = absval( $_GET[ $data['page_var'] ] );
992
			}
993
994
			if ( null === $data['sql'] ) {
995
				$data['sql'] = "SELECT * FROM {$data['table']}" . ( null !== $data['where'] ? " WHERE {$data['where']}" : '' ) . ( null !== $data['sort'] ? " ORDER BY {$data['sort']}" : '' ) . ( null !== $data['limit'] ? ' LIMIT ' . ( 1 < $page ? ( ( $page - 1 ) * $data['limit'] ) . ',' : '' ) . "{$data['limit']}" : '' );
996
			}
997
998
			if ( false !== $output ) {
999
				echo '<br />' . date( 'Y-m-d h:i:sa' ) . ' - <em>' . $data['pod']['name'] . '</em> - Getting Results: ' . $data['pod']['name'] . "\n";
1000
			}
1001
1002
			if ( false !== $output ) {
1003
				echo '<br />' . date( 'Y-m-d h:i:sa' ) . ' - <em>' . $data['pod']['name'] . '</em> - Using Query: <small><code>' . $data['sql'] . "</code></small>\n";
1004
			}
1005
1006
			$result = $wpdb->get_results( $data['sql'], ARRAY_A );
0 ignored issues
show
Usage of a direct database call is discouraged.
Loading history...
Usage of a direct database call without caching is prohibited. Use wp_cache_get / wp_cache_set.
Loading history...
1007
1008
			if ( false !== $output ) {
1009
				echo '<br />' . date( 'Y-m-d h:i:sa' ) . ' - <em>' . $data['pod']['name'] . '</em> - Results Found: ' . count( $result ) . "\n";
1010
			}
1011
1012
			$avg_time     = - 1;
1013
			$total_time   = 0;
1014
			$counter      = 0;
1015
			$avg_unit     = 100;
1016
			$avg_counter  = 0;
1017
			$result_count = count( $result );
1018
			$paginated    = false;
1019
1020
			if ( false !== $data['page_var'] && $result_count === $data['limit'] ) {
1021
				$paginated = "<input type=\"button\" onclick=\"document.location=\'" . pods_ui_var_update( array( $data['page_var'] => $page + 1 ), false, false ) . "\';\" value=\"  Continue Import &raquo;  \" />";
1022
			}
1023
1024
			if ( $result_count < $avg_unit && 5 < $result_count ) {
1025
				$avg_unit = number_format( $result_count / 5, 0, '', '' );
1026
			} elseif ( 2000 < $result_count && 10 < count( $data['pod']['fields'] ) ) {
1027
				$avg_unit = 40;
1028
			}
1029
1030
			$data['count'] = $result_count;
1031
			timer_start();
1032
1033
			if ( false !== $output && 1 === $import_counter ) {
1034
				echo "<div style='width:50%;background-color:navy;padding:10px 10px 30px 10px;color:#FFF;position:absolute;top:10px;left:25%;text-align:center;'><p id='progress_status' align='center'>" . date( 'Y-m-d h:i:sa' ) . ' - <em>' . $data['pod']['name'] . '</em> - Running Importer..</p><br /><small>This will automatically update every ' . $avg_unit . " rows</small></div>\n";
1035
			}
1036
1037
			foreach ( $result as $k => $row ) {
1038
				flush();
1039
				@ob_end_flush();
0 ignored issues
show
Silencing errors is discouraged
Loading history...
1040
				usleep( 50000 );
1041
1042
				if ( false !== $output ) {
1043
					echo '<br />' . date( 'Y-m-d h:i:sa' ) . ' - <em>' . $data['pod']['name'] . '</em> - Processing Row #' . ( $k + 1 ) . "\n";
1044
				}
1045
1046
				if ( null !== $data['row_filter'] && function_exists( $data['row_filter'] ) ) {
1047
					if ( false !== $output ) {
1048
						echo '<br />' . date( 'Y-m-d h:i:sa' ) . ' - <em>' . $data['pod']['name'] . '</em> - Filtering <strong>' . $data['row_filter'] . '</strong> on Row #' . ( $k + 1 ) . "\n";
1049
					}
1050
1051
					$row = $data['row_filter']( $row, $data );
1052
				}
1053
1054
				if ( ! is_array( $row ) ) {
1055
					continue;
1056
				}
1057
1058
				$params = array(
1059
					'datatype'       => $data['pod']['name'],
1060
					'columns'        => array(),
1061
					'bypass_helpers' => $data['bypass_helpers'],
1062
				);
1063
1064
				foreach ( $data['pod']['fields'] as $fk => $field_info ) {
1065
					$field = $field_info['name'];
1066
1067
					if ( ! empty( $data['fields'] ) && ! isset( $data['fields'][ $field ] ) && ! in_array( $field, $data['fields'], true ) ) {
1068
						continue;
1069
					}
1070
1071
					if ( isset( $data['fields'][ $field ] ) ) {
1072
						if ( is_array( $data['fields'][ $field ] ) ) {
1073
							$field_data = $data['fields'][ $field ];
1074
						} else {
1075
							$field_data = array( 'field' => $data['fields'][ $field ] );
1076
						}
1077
					} else {
1078
						$field_data = array();
1079
					}
1080
1081
					if ( ! is_array( $field_data ) ) {
1082
						$field      = $field_data;
1083
						$field_data = array();
1084
					}
1085
1086
					$field_data = array_merge( $default_field_data, $field_data );
1087
1088
					if ( null === $field_data['field'] ) {
1089
						$field_data['field'] = $field;
1090
					}
1091
1092
					$data['fields'][ $field ] = $field_data;
1093
					$value                    = '';
1094
1095
					if ( isset( $row[ $field_data['field'] ] ) ) {
1096
						$value = $row[ $field_data['field'] ];
1097
					}
1098
1099
					if ( null !== $field_data['filter'] ) {
1100
						if ( function_exists( $field_data['filter'] ) ) {
1101
							if ( false !== $output ) {
1102
								echo '<br />' . date( 'Y-m-d h:i:sa' ) . ' - <em>' . $data['pod']['name'] . '</em> - Filtering <strong>' . $field_data['filter'] . '</strong> on Field: ' . $field . "\n";
1103
							}
1104
1105
							$value = $field_data['filter']( $value, $row, $data );
1106
						} else {
1107
							$value = '';
1108
						}
1109
					}
1110
1111
					if ( 1 > strlen( $value ) && 1 === $field_info['required'] ) {
1112
						die( '<h1 style="color:red;font-weight:bold;">ERROR: Field Required for <strong>' . $field . '</strong></h1>' );
1113
					}
1114
1115
					$params['columns'][ $field ] = $value;
1116
1117
					unset( $value, $field_data, $field_info, $fk );
1118
				}//end foreach
1119
1120
				if ( empty( $params['columns'] ) ) {
1121
					continue;
1122
				}
1123
1124
				$params['columns'] = pods_sanitize( $params['columns'] );
1125
1126
				if ( null !== $data['update_on'] && isset( $params['columns'][ $data['update_on'] ] ) ) {
1127
					if ( false !== $output ) {
1128
						echo '<br />' . date( 'Y-m-d h:i:sa' ) . ' - <em>' . $data['pod']['name'] . "</em> - Checking for Existing Item\n";
1129
					}
1130
1131
					$check = new Pod( $data['pod']['name'] );
0 ignored issues
show
Deprecated Code introduced by
The class Pod has been deprecated with message: deprecated since version 2.0

This class, trait or interface has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the type will be removed from the class and what other constant to use instead.

Loading history...
1132
					$check->findRecords(
0 ignored issues
show
Documentation Bug introduced by
The method findRecords does not exist on object<Pod>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
1133
						array(
1134
							'orderby' => 't.id',
1135
							'limit'   => 1,
1136
							'where'   => "t.{$data['update_on']} = '{$params['columns'][$data['update_on']]}'",
1137
							'search'  => false,
1138
							'page'    => 1,
1139
						)
1140
					);
1141
1142
					if ( 0 < $check->getTotalRows() ) {
0 ignored issues
show
Documentation Bug introduced by
The method getTotalRows does not exist on object<Pod>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
1143
						$check->fetchRecord();
0 ignored issues
show
Documentation Bug introduced by
The method fetchRecord does not exist on object<Pod>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
1144
1145
						$params['tbl_row_id'] = $check->get_field( 'id' );
0 ignored issues
show
Documentation Bug introduced by
The method get_field does not exist on object<Pod>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
1146
						$params['pod_id']     = $check->get_pod_id();
0 ignored issues
show
Documentation Bug introduced by
The method get_pod_id does not exist on object<Pod>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
1147
1148
						if ( false !== $output ) {
1149
							echo '<br />' . date( 'Y-m-d h:i:sa' ) . ' - <em>' . $data['pod']['name'] . '</em> - Found Existing Item w/ ID: ' . $params['tbl_row_id'] . "\n";
1150
						}
1151
1152
						unset( $check );
1153
					}
1154
1155
					if ( ! isset( $params['tbl_row_id'] ) && false !== $output ) {
1156
						echo '<br />' . date( 'Y-m-d h:i:sa' ) . ' - <em>' . $data['pod']['name'] . "</em> - Existing item not found - Creating New\n";
1157
					}
1158
				}//end if
1159
1160
				if ( null !== $data['pre_save'] && function_exists( $data['pre_save'] ) ) {
1161
					if ( false !== $output ) {
1162
						echo '<br />' . date( 'Y-m-d h:i:sa' ) . ' - <em>' . $data['pod']['name'] . '</em> - Running Pre Save <strong>' . $data['pre_save'] . '</strong> on ' . $data['pod']['name'] . "\n";
1163
					}
1164
1165
					$params = $data['pre_save']( $params, $row, $data );
1166
				}
1167
1168
				$id = $api->save_pod_item( $params );
1169
1170
				if ( false !== $output ) {
1171
					echo '<br />' . date( 'Y-m-d h:i:sa' ) . ' - <em>' . $data['pod']['name'] . '</em> - <strong>Saved Row #' . ( $k + 1 ) . ' w/ ID: ' . $id . "</strong>\n";
1172
				}
1173
1174
				$params['tbl_row_id'] = $id;
1175
1176
				if ( null !== $data['post_save'] && function_exists( $data['post_save'] ) ) {
1177
					if ( false !== $output ) {
1178
						echo '<br />' . date( 'Y-m-d h:i:sa' ) . ' - <em>' . $data['pod']['name'] . '</em> - Running Post Save <strong>' . $data['post_save'] . '</strong> on ' . $data['pod']['name'] . "\n";
1179
					}
1180
1181
					$data['post_save']( $params, $row, $data );
1182
				}
1183
1184
				unset( $params, $result[ $k ], $row );
1185
1186
				wp_cache_flush();
1187
				$wpdb->queries = array();
1188
1189
				$avg_counter ++;
1190
				$counter ++;
1191
1192
				if ( $avg_counter === $avg_unit && false !== $output ) {
1193
					$avg_counter         = 0;
1194
					$avg_time            = timer_stop( 0, 10 );
1195
					$total_time         += $avg_time;
1196
					$rows_left           = $result_count - $counter;
1197
					$estimated_time_left = ( ( $total_time / $counter ) * $rows_left ) / 60;
1198
					$percent_complete    = 100 - ( ( $rows_left * 100 ) / $result_count );
1199
1200
					echo "<script type='text/javascript'>document.getElementById('progress_status').innerHTML = '" . date( 'Y-m-d h:i:sa' ) . ' - <em>' . $data['pod']['name'] . '</em><br /><strong>' . $percent_complete . '% Complete</strong><br /><strong>Estimated Time Left:</strong> ' . $estimated_time_left . ' minute(s) or ' . ( $estimated_time_left / 60 ) . ' hours(s)<br /><strong>Time Spent:</strong> ' . ( $total_time / 60 ) . ' minute(s)<br /><strong>Rows Done:</strong> ' . ( $result_count - $rows_left ) . '/' . $result_count . '<br /><strong>Rows Left:</strong> ' . $rows_left . "';</script>\n";
1201
					echo '<br />' . date( 'Y-m-d h:i:sa' ) . ' - <em>' . $data['pod']['name'] . '</em> - <strong>Updated Status:</strong> ' . $percent_complete . "% Complete</strong>\n";
1202
				}
1203
			}//end foreach
1204
1205
			if ( false !== $output ) {
1206
				$avg_counter         = 0;
1207
				$avg_time            = timer_stop( 0, 10 );
1208
				$total_time         += $avg_time;
1209
				$rows_left           = $result_count - $counter;
1210
				$estimated_time_left = ( ( $total_time / $counter ) * $rows_left ) / 60;
1211
				$percent_complete    = 100 - ( ( $rows_left * 100 ) / $result_count );
1212
1213
				echo "<script type='text/javascript'>document.getElementById('progress_status').innerHTML = '" . date( 'Y-m-d h:i:sa' ) . ' - <em>' . $data['pod']['name'] . "</em><br /><strong style=\'color:green;\'>100% Complete</strong><br /><br /><strong>Time Spent:</strong> " . ( $total_time / 60 ) . ' minute(s)<br /><strong>Rows Imported:</strong> ' . $result_count . ( false !== $paginated ? '<br /><br />' . $paginated : '' ) . "';</script>\n";
1214
				echo '<br />' . date( 'Y-m-d h:i:sa' ) . ' - <em>' . $data['pod']['name'] . "</em> - <strong style='color:green;'>Done Importing: " . $data['pod']['name'] . "</strong>\n";
1215
			}
1216
1217
			unset( $result, $import[ $datatype ], $datatype, $data );
1218
1219
			wp_cache_flush();
1220
			$wpdb->queries = array();
1221
		}//end foreach
1222
1223
		if ( false !== $output ) {
1224
			$avg_counter = 0;
1225
			$avg_time    = timer_stop( 0, 10 );
1226
			$total_time += $avg_time;
1227
			$rows_left   = $result_count - $counter;
0 ignored issues
show
The variable $result_count does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
1228
1229
			echo "<script type='text/javascript'>document.getElementById('progress_status').innerHTML = '" . date( 'Y-m-d h:i:sa' ) . " - <strong style=\'color:green;\'>Import Complete</strong><br /><br /><strong>Time Spent:</strong> " . ( $total_time / 60 ) . ' minute(s)<br /><strong>Rows Imported:</strong> ' . $result_count . ( false !== $paginated ? '<br /><br />' . $paginated : '' ) . "';</script>\n";
1230
			echo '<br />' . date( 'Y-m-d h:i:sa' ) . " - <strong style='color:green;'>Import Complete</strong>\n";
1231
		}
1232
	}
1233
1234
	/**
1235
	 * Export data to a file.
1236
	 *
1237
	 * @param string $file   File to export to.
1238
	 * @param array  $data   Data to export.
1239
	 * @param bool   $single Whether this is a single item export.
1240
	 *
1241
	 * @return mixed
0 ignored issues
show
Consider making the return type a bit more specific; maybe use string.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
1242
	 */
1243
	public static function export_data_to_file( $file, $data, $single = false ) {
1244
1245
		$path = ABSPATH;
1246
1247
		// Detect path if it is set in the file param.
1248
		if ( false !== strpos( $file, '/' ) ) {
1249
			$path = dirname( $file );
1250
			$file = basename( $file );
1251
		}
1252
1253
		$format = 'json';
1254
1255
		// Detect the export format.
1256
		if ( false !== strpos( $file, '.' ) ) {
1257
			$format = explode( '.', $file );
1258
			$format = end( $format );
1259
		}
1260
1261
		$migrate_data = array(
1262
			'items'  => array( $data ),
1263
			'single' => $single,
1264
		);
1265
1266
		$migrate = new self( $format, null, $migrate_data );
1267
1268
		// Handle processing the data into the format needed.
1269
		$migrate->export();
1270
1271
		$save_params = array(
1272
			'path'   => $path,
1273
			'file'   => $file,
1274
			'attach' => true,
1275
		);
1276
1277
		return $migrate->save( $save_params );
1278
1279
	}
1280
1281
	/**
1282
	 * Get data from a file.
1283
	 *
1284
	 * @param string $file   File to get data from.
1285
	 * @param bool   $single Whether this is a single item.
1286
	 *
1287
	 * @return mixed
1288
	 */
1289
	public static function get_data_from_file( $file, $single = false ) {
1290
1291
		$path = ABSPATH;
1292
1293
		// Detect path if it is set in the file param.
1294
		if ( false !== strpos( $file, '/' ) ) {
1295
			$path = dirname( $file );
1296
			$file = basename( $file );
1297
		}
1298
1299
		$format = 'json';
1300
1301
		// Detect the export format.
1302
		if ( false !== strpos( $file, '.' ) ) {
1303
			$format = explode( '.', $file );
1304
			$format = end( $format );
1305
		}
1306
1307
		$migrate_data = array(
1308
			'single' => $single,
1309
		);
1310
1311
		$migrate = new self( $format, null, $migrate_data );
1312
1313
		$raw_data = file_get_contents( $file );
0 ignored issues
show
file_get_contents is highly discouraged, please use wpcom_vip_file_get_contents() instead.
Loading history...
1314
1315
		// Handle processing the raw data from the format needed.
1316
		$data = $migrate->parse( $raw_data );
0 ignored issues
show
Are you sure the assignment to $data is correct as $migrate->parse($raw_data) (which targets PodsMigrate::parse()) seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
1317
1318
		return $data;
1319
1320
	}
1321
1322
}
1323