Issues (435)

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.

includes/CMB2_Sanitize.php (8 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
 * CMB2 field sanitization
4
 *
5
 * @since  0.0.4
6
 *
7
 * @category  WordPress_Plugin
8
 * @package   CMB2
9
 * @author    WebDevStudios
10
 * @license   GPL-2.0+
11
 * @link      http://webdevstudios.com
12
 *
13
 * @method string _id()
14
 */
15
class CMB2_Sanitize {
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.

You can fix this by adding a namespace to your class:

namespace YourVendor;

class YourClass { }

When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.

Loading history...
16
17
	/**
18
	 * A CMB field object
19
	 *
20
	 * @var CMB2_Field object
21
	 */
22
	public $field;
23
24
	/**
25
	 * Field's value
26
	 *
27
	 * @var mixed
28
	 */
29
	public $value;
30
31
	/**
32
	 * Setup our class vars
33
	 *
34
	 * @since 1.1.0
35
	 * @param CMB2_Field $field A CMB2 field object
36
	 * @param mixed      $value Field value
37
	 */
38 15
	public function __construct( CMB2_Field $field, $value ) {
39 15
		$this->field = $field;
40 15
		$this->value = stripslashes_deep( $value ); // get rid of those evil magic quotes
41 15
	}
42
43
	/**
44
	 * Catchall method if field's 'sanitization_cb' is NOT defined, or field type does not have a corresponding validation method
45
	 *
46
	 * @since  1.0.0
47
	 * @param  string $name      Non-existent method name
48
	 * @param  array  $arguments All arguments passed to the method
49
	 */
50 12
	public function __call( $name, $arguments ) {
51 12
		return $this->default_sanitization();
52
	}
53
54
	/**
55
	 * Default fallback sanitization method. Applies filters.
56
	 *
57
	 * @since  1.0.2
58
	 */
59 12
	public function default_sanitization() {
60
61
		/**
62
		 * This exists for back-compatibility, but validation
63
		 * is not what happens here.
64
		 *
65
		 * @deprecated See documentation for "cmb2_sanitize_{$this->type()}".
66
		 */
67 12
		if ( function_exists( 'apply_filters_deprecated' ) ) {
68
			$override_value = apply_filters_deprecated( "cmb2_validate_{$this->field->type()}", array( null, $this->value, $this->field->object_id, $this->field->args(), $this ), '2.0.0', "cmb2_sanitize_{$this->field->type()}" );
0 ignored issues
show
The property $object_id is declared protected in CMB2_Base. Since you implemented __get(), maybe consider adding a @property or @property-read annotation. This makes it easier for IDEs to provide auto-completion.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
69
		} else {
70 12
			$override_value = apply_filters( "cmb2_validate_{$this->field->type()}", null, $this->value, $this->field->object_id, $this->field->args(), $this );
0 ignored issues
show
The property $object_id is declared protected in CMB2_Base. Since you implemented __get(), maybe consider adding a @property or @property-read annotation. This makes it easier for IDEs to provide auto-completion.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
71
		}
72
73 12
		if ( null !== $override_value ) {
74
			return $override_value;
75
		}
76
77 12
		$sanitized_value = '';
0 ignored issues
show
$sanitized_value 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...
78 12
		switch ( $this->field->type() ) {
79 12
			case 'wysiwyg':
80 12
			case 'textarea_small':
81 12
			case 'oembed':
82 2
				$sanitized_value = $this->textarea();
83 2
				break;
84 12
			case 'taxonomy_select':
85 12
			case 'taxonomy_radio':
86 12
			case 'taxonomy_radio_inline':
87 12
			case 'taxonomy_multicheck':
88 12
			case 'taxonomy_multicheck_inline':
89 1
				$sanitized_value = $this->_taxonomy();
90 1
				break;
91 12
			case 'multicheck':
92 12
			case 'multicheck_inline':
93 12
			case 'file_list':
94 12
			case 'group':
95
				// no filtering
96 3
				$sanitized_value = $this->value;
97 3
				break;
98 11
			default:
99
				// Handle repeatable fields array
100
				// We'll fallback to 'sanitize_text_field'
101 11
				$sanitized_value = $this->_default_sanitization();
102 11
				break;
103 12
		}
104
105 12
		return $this->_is_empty_array( $sanitized_value ) ? '' : $sanitized_value;
106
	}
107
108
	/**
109
	 * Default sanitization method, sanitize_text_field. Checks if value is array.
110
	 *
111
	 * @since  2.2.4
112
	 * @return mixed  Sanitized value.
113
	 */
114 11
	protected function _default_sanitization() {
115
		// Handle repeatable fields array
116 11
		return is_array( $this->value ) ? array_map( 'sanitize_text_field', $this->value ) : sanitize_text_field( $this->value );
117
	}
118
119
	/**
120
	 * Sets the object terms to the object (if not options-page) and optionally returns the sanitized term values.
121
	 *
122
	 * @since  2.2.4
123
	 * @return mixed  Blank value, or sanitized term values if "cmb2_return_taxonomy_values_{$cmb_id}" is true.
124
	 */
125 1
	protected function _taxonomy() {
126 1
		$sanitized_value = '';
127
128 1
		if ( ! $this->field->args( 'taxonomy' ) ) {
129
			CMB2_Utils::log_if_debug( __METHOD__, __LINE__, "{$this->field->type()} {$this->field->_id()} is missing the 'taxonomy' parameter." );
130
		} else {
131
132 1
			if ( 'options-page' === $this->field->object_type ) {
0 ignored issues
show
The property $object_type is declared protected in CMB2_Base. Since you implemented __get(), maybe consider adding a @property or @property-read annotation. This makes it easier for IDEs to provide auto-completion.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
133
				$return_values = true;
134
			} else {
135 1
				wp_set_object_terms( $this->field->object_id, $this->value, $this->field->args( 'taxonomy' ) );
0 ignored issues
show
The property $object_id is declared protected in CMB2_Base. Since you implemented __get(), maybe consider adding a @property or @property-read annotation. This makes it easier for IDEs to provide auto-completion.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
136 1
				$return_values = false;
137
			}
138
139 1
			$cmb_id = $this->field->cmb_id;
0 ignored issues
show
The property $cmb_id is declared protected in CMB2_Base. Since you implemented __get(), maybe consider adding a @property or @property-read annotation. This makes it easier for IDEs to provide auto-completion.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
140
141
			/**
142
			 * Filter whether 'taxonomy_*' fields should return their value when being sanitized.
143
			 *
144
			 * By default, these fields do not return a value as we do not want them stored to meta
145
			 * (as they are stored as terms). This allows overriding that and is used by CMB2::get_sanitized_values().
146
			 *
147
			 * The dynamic portion of the hook, $cmb_id, refers to the this field's CMB2 box id.
148
			 *
149
			 * @since 2.2.4
150
			 *
151
			 * @param bool          $return_values By default, this is only true for 'options-page' boxes. To enable:
152
			 *                                     `add_filter( "cmb2_return_taxonomy_values_{$cmb_id}", '__return_true' );`
153
			 * @param CMB2_Sanitize $sanitizer This object.
154
			 */
155 1
			if ( apply_filters( "cmb2_return_taxonomy_values_{$cmb_id}", $return_values, $this ) ) {
156 1
				$sanitized_value = $this->_default_sanitization();
157 1
			}
158
		}
159
160 1
		return $sanitized_value;
161
	}
162
163
	/**
164
	 * Simple checkbox validation
165
	 *
166
	 * @since  1.0.1
167
	 * @return string|false 'on' or false
168
	 */
169
	public function checkbox() {
170
		return $this->value === 'on' ? 'on' : false;
171
	}
172
173
	/**
174
	 * Validate url in a meta value
175
	 *
176
	 * @since  1.0.1
177
	 * @return string        Empty string or escaped url
178
	 */
179 2
	public function text_url() {
180 2
		$protocols = $this->field->args( 'protocols' );
181
		// for repeatable
182 2
		if ( is_array( $this->value ) ) {
183
			foreach ( $this->value as $key => $val ) {
184
				$this->value[ $key ] = $val ? esc_url_raw( $val, $protocols ) : $this->field->get_default();
185
			}
186
		} else {
187 2
			$this->value = $this->value ? esc_url_raw( $this->value, $protocols ) : $this->field->get_default();
188
		}
189
190 2
		return $this->value;
191
	}
192
193
	public function colorpicker() {
194
		// for repeatable
195
		if ( is_array( $this->value ) ) {
196
			$check = $this->value;
197
			$this->value = array();
198
			foreach ( $check as $key => $val ) {
199
				if ( $val && '#' != $val ) {
200
					$this->value[ $key ] = esc_attr( $val );
201
				}
202
			}
203
		} else {
204
			$this->value = ! $this->value || '#' == $this->value ? '' : esc_attr( $this->value );
205
		}
206
		return $this->value;
207
	}
208
209
	/**
210
	 * Validate email in a meta value
211
	 *
212
	 * @since  1.0.1
213
	 * @return string       Empty string or sanitized email
214
	 */
215
	public function text_email() {
216
		// for repeatable
217
		if ( is_array( $this->value ) ) {
218
			foreach ( $this->value as $key => $val ) {
219
				$val = trim( $val );
220
				$this->value[ $key ] = is_email( $val ) ? $val : '';
221
			}
222
		} else {
223
			$this->value = trim( $this->value );
224
			$this->value = is_email( $this->value ) ? $this->value : '';
225
		}
226
227
		return $this->value;
228
	}
229
230
	/**
231
	 * Validate money in a meta value
232
	 *
233
	 * @since  1.0.1
234
	 * @return string Empty string or sanitized money value
235
	 */
236 1
	public function text_money() {
237 1
		if ( ! $this->value ) {
238 1
			return '';
239
		}
240
241 1
		global $wp_locale;
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...
242
243 1
		$search = array( $wp_locale->number_format['thousands_sep'], $wp_locale->number_format['decimal_point'] );
244 1
		$replace = array( '', '.' );
245
246
		// for repeatable
247 1
		if ( is_array( $this->value ) ) {
248
			foreach ( $this->value as $key => $val ) {
249
				if ( $val ) {
250
					$this->value[ $key ] = number_format_i18n( (float) str_ireplace( $search, $replace, $val ), 2 );
251
				}
252
			}
253
		} else {
254 1
			$this->value = number_format_i18n( (float) str_ireplace( $search, $replace, $this->value ), 2 );
255
		}
256
257 1
		return $this->value;
258
	}
259
260
	/**
261
	 * Converts text date to timestamp
262
	 *
263
	 * @since  1.0.2
264
	 * @return string Timestring
265
	 */
266
	public function text_date_timestamp() {
267
		return is_array( $this->value )
268
			? array_map( array( $this->field, 'get_timestamp_from_value' ), $this->value )
269
			: $this->field->get_timestamp_from_value( $this->value );
270
	}
271
272
	/**
273
	 * Datetime to timestamp
274
	 *
275
	 * @since  1.0.1
276
	 * @return string|array Timestring
277
	 */
278
	public function text_datetime_timestamp( $repeat = false ) {
279
280
		$test = is_array( $this->value ) ? array_filter( $this->value ) : '';
281
		if ( empty( $test ) ) {
282
			return '';
283
		}
284
285
		$repeat_value = $this->_check_repeat( __FUNCTION__, $repeat );
286
		if ( false !== $repeat_value ) {
287
			return $repeat_value;
288
		}
289
290
		if ( isset( $this->value['date'], $this->value['time'] ) ) {
291
			$this->value = $this->field->get_timestamp_from_value( $this->value['date'] . ' ' . $this->value['time'] );
292
		}
293
294
		if ( $tz_offset = $this->field->field_timezone_offset() ) {
295
			$this->value += (int) $tz_offset;
296
		}
297
298
		return $this->value;
299
	}
300
301
	/**
302
	 * Datetime to timestamp with timezone
303
	 *
304
	 * @since  1.0.1
305
	 * @return string       Timestring
306
	 */
307 2
	public function text_datetime_timestamp_timezone( $repeat = false ) {
308 2
		static $utc_values = array();
309
310 2
		$test = is_array( $this->value ) ? array_filter( $this->value ) : '';
311 2
		if ( empty( $test ) ) {
312 1
			return '';
313
		}
314
315 2
		$utc_key = $this->field->_id() . '_utc';
316
317 2
		$repeat_value = $this->_check_repeat( __FUNCTION__, $repeat );
318 2
		if ( false !== $repeat_value ) {
319 1
			if ( ! empty( $utc_values[ $utc_key ] ) ) {
320
				$this->_save_utc_value( $utc_key, $utc_values[ $utc_key ] );
321
				unset( $utc_values[ $utc_key ] );
322
			}
323
324 1
			return $repeat_value;
325
		}
326
327 2
		$tzstring = null;
328
329 2
		if ( is_array( $this->value ) && array_key_exists( 'timezone', $this->value ) ) {
330 2
			$tzstring = $this->value['timezone'];
331 2
		}
332
333 2
		if ( empty( $tzstring ) ) {
334
			$tzstring = CMB2_Utils::timezone_string();
335
		}
336
337 2
		$offset = CMB2_Utils::timezone_offset( $tzstring );
338
339 2
		if ( 'UTC' === substr( $tzstring, 0, 3 ) ) {
340 1
			$tzstring = timezone_name_from_abbr( '', $offset, 0 );
341
			/*
342
			 * timezone_name_from_abbr() returns false if not found based on offset.
343
			 * Since there are currently some invalid timezones in wp_timezone_dropdown(),
344
			 * fallback to an offset of 0 (UTC+0)
345
			 * https://core.trac.wordpress.org/ticket/29205
346
			 */
347 1
			$tzstring = false !== $tzstring ? $tzstring : timezone_name_from_abbr( '', 0, 0 );
348 1
		}
349
350 2
		$full_format = $this->field->args['date_format'] . ' ' . $this->field->args['time_format'];
351 2
		$full_date   = $this->value['date'] . ' ' . $this->value['time'];
352
353
		try {
354
355 2
			$datetime = date_create_from_format( $full_format, $full_date );
356
357 2
			if ( ! is_object( $datetime ) ) {
358
				$this->value = $utc_stamp = '';
359
			} else {
360 2
				$timestamp   = $datetime->setTimezone( new DateTimeZone( $tzstring ) )->getTimestamp();
361 2
				$utc_stamp   = $timestamp - $offset;
362 2
				$this->value = serialize( $datetime );
363
			}
364
365 2
			if ( $this->field->group ) {
366 1
				$this->value = array(
367 1
					'supporting_field_value' => $utc_stamp,
368 1
					'supporting_field_id'    => $utc_key,
369 1
					'value'                  => $this->value,
370
				);
371 1
			} else {
372
				// Save the utc timestamp supporting field
373 1
				if ( $repeat ) {
374
					$utc_values[ $utc_key ][] = $utc_stamp;
375
				} else {
376 1
					$this->_save_utc_value( $utc_key, $utc_stamp );
377
				}
378
			}
379 2
		} catch ( Exception $e ) {
380
			$this->value = '';
381
			CMB2_Utils::log_if_debug( __METHOD__, __LINE__, $e->getMessage() );
382
		}
383
384 2
		return $this->value;
385
	}
386
387
	/**
388
	 * Sanitize textareas and wysiwyg fields
389
	 *
390
	 * @since  1.0.1
391
	 * @return string       Sanitized data
392
	 */
393 2
	public function textarea() {
394 2
		return is_array( $this->value ) ? array_map( 'wp_kses_post', $this->value ) : wp_kses_post( $this->value );
395
	}
396
397
	/**
398
	 * Sanitize code textareas
399
	 *
400
	 * @since  1.0.2
401
	 * @return string       Sanitized data
402
	 */
403
	public function textarea_code( $repeat = false ) {
404
		$repeat_value = $this->_check_repeat( __FUNCTION__, $repeat );
405
		if ( false !== $repeat_value ) {
406
			return $repeat_value;
407
		}
408
409
		return htmlspecialchars_decode( stripslashes( $this->value ) );
410
	}
411
412
	/**
413
	 * Handles saving of attachment post ID and sanitizing file url
414
	 *
415
	 * @since  1.1.0
416
	 * @return string        Sanitized url
417
	 */
418 2
	public function file() {
419 2
		$file_id_key = $this->field->_id() . '_id';
420
421 2
		if ( $this->field->group ) {
422
			// Return an array with url/id if saving a group field
423 2
			$this->value = $this->_get_group_file_value_array( $file_id_key );
424 2
		} else {
425
			$this->_save_file_id_value( $file_id_key );
426
			$this->text_url();
427
		}
428
429 2
		return $this->value;
430
	}
431
432
	/**
433
	 * Gets the values for the `file` field type from the data being saved.
434
	 *
435
	 * @since  2.2.0
436
	 */
437 2
	public function _get_group_file_value_array( $id_key ) {
438 2
		$alldata = $this->field->group->data_to_save;
439 2
		$base_id = $this->field->group->_id();
440 2
		$i       = $this->field->group->index;
441
442
		// Check group $alldata data
443 2
		$id_val  = isset( $alldata[ $base_id ][ $i ][ $id_key ] )
444 2
			? absint( $alldata[ $base_id ][ $i ][ $id_key ] )
445 2
			: '';
446
447
		// We don't want to save 0 to the DB for file fields.
448 2
		if ( 0 === $id_val ) {
449 1
			$id_val = '';
450 1
		}
451
452
		return array(
453 2
			'value' => $this->text_url(),
454 2
			'supporting_field_value' => $id_val,
455 2
			'supporting_field_id'    => $id_key,
456 2
		);
457
	}
458
459
	/**
460
	 * Peforms saving of `file` attachement's ID
461
	 *
462
	 * @since  1.1.0
463
	 */
464
	public function _save_file_id_value( $file_id_key ) {
465
		$id_field = $this->_new_supporting_field( $file_id_key );
466
467
		// Check standard data_to_save data
468
		$id_val = isset( $this->field->data_to_save[ $file_id_key ] )
469
			? $this->field->data_to_save[ $file_id_key ]
470
			: null;
471
472
		// If there is no ID saved yet, try to get it from the url
473
		if ( $this->value && ! $id_val ) {
474
			$id_val = CMB2_Utils::image_id_from_url( $this->value );
475
		}
476
477
		return $id_field->save_field( $id_val );
478
	}
479
480
	/**
481
	 * Peforms saving of `text_datetime_timestamp_timezone` utc timestamp
482
	 *
483
	 * @since  2.2.0
484
	 */
485 1
	public function _save_utc_value( $utc_key, $utc_stamp ) {
486 1
		return $this->_new_supporting_field( $utc_key )->save_field( $utc_stamp );
487
	}
488
489
	/**
490
	 * Returns a new, supporting, CMB2_Field object based on a new field id.
491
	 *
492
	 * @since  2.2.0
493
	 */
494 1
	public function _new_supporting_field( $new_field_id ) {
495 1
		return $this->field->get_field_clone( array(
496 1
			'id' => $new_field_id,
497 1
			'sanitization_cb' => false,
498 1
		) );
499
	}
500
501
	/**
502
	 * If repeating, loop through and re-apply sanitization method
503
	 *
504
	 * @since  1.1.0
505
	 * @param  string $method Class method
506
	 * @param  bool   $repeat Whether repeating or not
507
	 * @return mixed          Sanitized value
508
	 */
509 2
	public function _check_repeat( $method, $repeat ) {
510 2
		if ( $repeat || ! $this->field->args( 'repeatable' ) ) {
511 2
			return false;
512
		}
513
514 1
		$values_array = $this->value;
515
516 1
		$new_value = array();
517 1
		foreach ( $values_array as $iterator => $this->value ) {
518 1
			if ( $this->value ) {
519 1
				$val = $this->$method( true );
520 1
				if ( ! empty( $val ) ) {
521 1
					$new_value[] = $val;
522 1
				}
523 1
			}
524 1
		}
525
526 1
		$this->value = $new_value;
527
528 1
		return empty( $this->value ) ? null : $this->value;
529
	}
530
531
	/**
532
	 * Determine if passed value is an empty array
533
	 *
534
	 * @since  2.0.6
535
	 * @param  mixed $to_check Value to check
536
	 * @return boolean          Whether value is an array that's empty
537
	 */
538 12
	public function _is_empty_array( $to_check ) {
539 12
		if ( is_array( $to_check ) ) {
540 5
			$cleaned_up = array_filter( $to_check );
541 5
			return empty( $cleaned_up );
542
		}
543 10
		return false;
544
	}
545
546
}
547