PageRenderTime 47ms CodeModel.GetById 18ms RepoModel.GetById 1ms app.codeStats 0ms

/vendor/cmb2/includes/CMB2_Sanitize.php

https://gitlab.com/almoore1/buy-button-wordpress
PHP | 469 lines | 261 code | 68 blank | 140 comment | 44 complexity | 13af8c677e94554a42950e2025116780 MD5 | raw file
  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 {
  16. /**
  17. * A CMB field object
  18. * @var CMB2_Field object
  19. */
  20. public $field;
  21. /**
  22. * Field's value
  23. * @var mixed
  24. */
  25. public $value;
  26. /**
  27. * Setup our class vars
  28. * @since 1.1.0
  29. * @param CMB2_Field $field A CMB2 field object
  30. * @param mixed $value Field value
  31. */
  32. public function __construct( CMB2_Field $field, $value ) {
  33. $this->field = $field;
  34. $this->value = stripslashes_deep( $value ); // get rid of those evil magic quotes
  35. }
  36. /**
  37. * Catchall method if field's 'sanitization_cb' is NOT defined, or field type does not have a corresponding validation method
  38. * @since 1.0.0
  39. * @param string $name Non-existent method name
  40. * @param array $arguments All arguments passed to the method
  41. */
  42. public function __call( $name, $arguments ) {
  43. return $this->default_sanitization();
  44. }
  45. /**
  46. * Default fallback sanitization method. Applies filters.
  47. * @since 1.0.2
  48. */
  49. public function default_sanitization() {
  50. /**
  51. * This exists for back-compatibility, but validation
  52. * is not what happens here.
  53. * @deprecated See documentation for "cmb2_sanitize_{$this->type()}".
  54. */
  55. $override_value = apply_filters( "cmb2_validate_{$this->field->type()}", null, $this->value, $this->field->object_id, $this->field->args(), $this );
  56. if ( null !== $override_value ) {
  57. return $override_value;
  58. }
  59. $sanitized_value = '';
  60. switch ( $this->field->type() ) {
  61. case 'wysiwyg':
  62. case 'textarea_small':
  63. case 'oembed':
  64. $sanitized_value = $this->textarea();
  65. break;
  66. case 'taxonomy_select':
  67. case 'taxonomy_radio':
  68. case 'taxonomy_radio_inline':
  69. case 'taxonomy_multicheck':
  70. case 'taxonomy_multicheck_inline':
  71. if ( $this->field->args( 'taxonomy' ) ) {
  72. wp_set_object_terms( $this->field->object_id, $this->value, $this->field->args( 'taxonomy' ) );
  73. } else {
  74. cmb2_utils()->log_if_debug( __METHOD__, __LINE__, "{$this->field->type()} {$this->field->_id()} is missing the 'taxonomy' parameter." );
  75. }
  76. break;
  77. case 'multicheck':
  78. case 'multicheck_inline':
  79. case 'file_list':
  80. case 'group':
  81. // no filtering
  82. $sanitized_value = $this->value;
  83. break;
  84. default:
  85. // Handle repeatable fields array
  86. // We'll fallback to 'sanitize_text_field'
  87. $sanitized_value = is_array( $this->value ) ? array_map( 'sanitize_text_field', $this->value ) : sanitize_text_field( $this->value );
  88. break;
  89. }
  90. return $this->_is_empty_array( $sanitized_value ) ? '' : $sanitized_value;
  91. }
  92. /**
  93. * Simple checkbox validation
  94. * @since 1.0.1
  95. * @return string|false 'on' or false
  96. */
  97. public function checkbox() {
  98. return $this->value === 'on' ? 'on' : false;
  99. }
  100. /**
  101. * Validate url in a meta value
  102. * @since 1.0.1
  103. * @return string Empty string or escaped url
  104. */
  105. public function text_url() {
  106. $protocols = $this->field->args( 'protocols' );
  107. // for repeatable
  108. if ( is_array( $this->value ) ) {
  109. foreach ( $this->value as $key => $val ) {
  110. $this->value[ $key ] = $val ? esc_url_raw( $val, $protocols ) : $this->field->args( 'default' );
  111. }
  112. } else {
  113. $this->value = $this->value ? esc_url_raw( $this->value, $protocols ) : $this->field->args( 'default' );
  114. }
  115. return $this->value;
  116. }
  117. public function colorpicker() {
  118. // for repeatable
  119. if ( is_array( $this->value ) ) {
  120. $check = $this->value;
  121. $this->value = array();
  122. foreach ( $check as $key => $val ) {
  123. if ( $val && '#' != $val ) {
  124. $this->value[ $key ] = esc_attr( $val );
  125. }
  126. }
  127. } else {
  128. $this->value = ! $this->value || '#' == $this->value ? '' : esc_attr( $this->value );
  129. }
  130. return $this->value;
  131. }
  132. /**
  133. * Validate email in a meta value
  134. * @since 1.0.1
  135. * @return string Empty string or sanitized email
  136. */
  137. public function text_email() {
  138. // for repeatable
  139. if ( is_array( $this->value ) ) {
  140. foreach ( $this->value as $key => $val ) {
  141. $val = trim( $val );
  142. $this->value[ $key ] = is_email( $val ) ? $val : '';
  143. }
  144. } else {
  145. $this->value = trim( $this->value );
  146. $this->value = is_email( $this->value ) ? $this->value : '';
  147. }
  148. return $this->value;
  149. }
  150. /**
  151. * Validate money in a meta value
  152. * @since 1.0.1
  153. * @return string Empty string or sanitized money value
  154. */
  155. public function text_money() {
  156. global $wp_locale;
  157. $search = array( $wp_locale->number_format['thousands_sep'], $wp_locale->number_format['decimal_point'] );
  158. $replace = array( '', '.' );
  159. // for repeatable
  160. if ( is_array( $this->value ) ) {
  161. foreach ( $this->value as $key => $val ) {
  162. $this->value[ $key ] = number_format_i18n( (float) str_ireplace( $search, $replace, $val ), 2 );
  163. }
  164. } else {
  165. $this->value = number_format_i18n( (float) str_ireplace( $search, $replace, $this->value ), 2 );
  166. }
  167. return $this->value;
  168. }
  169. /**
  170. * Converts text date to timestamp
  171. * @since 1.0.2
  172. * @return string Timestring
  173. */
  174. public function text_date_timestamp() {
  175. return is_array( $this->value )
  176. ? array_map( array( $this->field, 'get_timestamp_from_value' ), $this->value )
  177. : $this->field->get_timestamp_from_value( $this->value );
  178. }
  179. /**
  180. * Datetime to timestamp
  181. * @since 1.0.1
  182. * @return string Timestring
  183. */
  184. public function text_datetime_timestamp( $repeat = false ) {
  185. $test = is_array( $this->value ) ? array_filter( $this->value ) : '';
  186. if ( empty( $test ) ) {
  187. return '';
  188. }
  189. $repeat_value = $this->_check_repeat( __FUNCTION__, $repeat );
  190. if ( false !== $repeat_value ) {
  191. return $repeat_value;
  192. }
  193. if ( isset( $this->value['date'], $this->value['time'] ) ) {
  194. $this->value = $this->field->get_timestamp_from_value( $this->value['date'] . ' ' . $this->value['time'] );
  195. }
  196. if ( $tz_offset = $this->field->field_timezone_offset() ) {
  197. $this->value += (int) $tz_offset;
  198. }
  199. return $this->value;
  200. }
  201. /**
  202. * Datetime to timestamp with timezone
  203. * @since 1.0.1
  204. * @return string Timestring
  205. */
  206. public function text_datetime_timestamp_timezone( $repeat = false ) {
  207. static $utc_values = array();
  208. $test = is_array( $this->value ) ? array_filter( $this->value ) : '';
  209. if ( empty( $test ) ) {
  210. return '';
  211. }
  212. $utc_key = $this->field->_id() . '_utc';
  213. $repeat_value = $this->_check_repeat( __FUNCTION__, $repeat );
  214. if ( false !== $repeat_value ) {
  215. if ( ! empty( $utc_values[ $utc_key ] ) ) {
  216. $this->_save_utc_value( $utc_key, $utc_values[ $utc_key ] );
  217. unset( $utc_values[ $utc_key ] );
  218. }
  219. return $repeat_value;
  220. }
  221. $tzstring = null;
  222. if ( is_array( $this->value ) && array_key_exists( 'timezone', $this->value ) ) {
  223. $tzstring = $this->value['timezone'];
  224. }
  225. if ( empty( $tzstring ) ) {
  226. $tzstring = cmb2_utils()->timezone_string();
  227. }
  228. $offset = cmb2_utils()->timezone_offset( $tzstring );
  229. if ( 'UTC' === substr( $tzstring, 0, 3 ) ) {
  230. $tzstring = timezone_name_from_abbr( '', $offset, 0 );
  231. /*
  232. * timezone_name_from_abbr() returns false if not found based on offset.
  233. * Since there are currently some invalid timezones in wp_timezone_dropdown(),
  234. * fallback to an offset of 0 (UTC+0)
  235. * https://core.trac.wordpress.org/ticket/29205
  236. */
  237. $tzstring = false !== $tzstring ? $tzstring : timezone_name_from_abbr( '', 0, 0 );
  238. }
  239. $full_format = $this->field->args['date_format'] . ' ' . $this->field->args['time_format'];
  240. $full_date = $this->value['date'] . ' ' . $this->value['time'];
  241. try {
  242. $datetime = date_create_from_format( $full_format, $full_date );
  243. if ( ! is_object( $datetime ) ) {
  244. $this->value = $utc_stamp = '';
  245. } else {
  246. $timestamp = $datetime->setTimezone( new DateTimeZone( $tzstring ) )->getTimestamp();
  247. $utc_stamp = $timestamp - $offset;
  248. $this->value = serialize( $datetime );
  249. }
  250. if ( $this->field->group ) {
  251. $this->value = array(
  252. 'supporting_field_value' => $utc_stamp,
  253. 'supporting_field_id' => $utc_key,
  254. 'value' => $this->value,
  255. );
  256. } else {
  257. // Save the utc timestamp supporting field
  258. if ( $repeat ) {
  259. $utc_values[ $utc_key ][] = $utc_stamp;
  260. } else {
  261. $this->_save_utc_value( $utc_key, $utc_stamp );
  262. }
  263. }
  264. } catch ( Exception $e ) {
  265. $this->value = '';
  266. cmb2_utils()->log_if_debug( __METHOD__, __LINE__, $e->getMessage() );
  267. }
  268. return $this->value;
  269. }
  270. /**
  271. * Sanitize textareas and wysiwyg fields
  272. * @since 1.0.1
  273. * @return string Sanitized data
  274. */
  275. public function textarea() {
  276. return is_array( $this->value ) ? array_map( 'wp_kses_post', $this->value ) : wp_kses_post( $this->value );
  277. }
  278. /**
  279. * Sanitize code textareas
  280. * @since 1.0.2
  281. * @return string Sanitized data
  282. */
  283. public function textarea_code( $repeat = false ) {
  284. $repeat_value = $this->_check_repeat( __FUNCTION__, $repeat );
  285. if ( false !== $repeat_value ) {
  286. return $repeat_value;
  287. }
  288. return htmlspecialchars_decode( stripslashes( $this->value ) );
  289. }
  290. /**
  291. * Handles saving of attachment post ID and sanitizing file url
  292. * @since 1.1.0
  293. * @return string Sanitized url
  294. */
  295. public function file() {
  296. $file_id_key = $this->field->_id() . '_id';
  297. if ( $this->field->group ) {
  298. // Return an array with url/id if saving a group field
  299. $this->value = $this->_get_group_file_value_array( $file_id_key );
  300. } else {
  301. $this->_save_file_id_value( $file_id_key );
  302. $this->text_url();
  303. }
  304. return $this->value;
  305. }
  306. /**
  307. * Gets the values for the `file` field type from the data being saved.
  308. * @since 2.2.0
  309. */
  310. public function _get_group_file_value_array( $id_key ) {
  311. $alldata = $this->field->group->data_to_save;
  312. $base_id = $this->field->group->_id();
  313. $i = $this->field->group->index;
  314. // Check group $alldata data
  315. $id_val = isset( $alldata[ $base_id ][ $i ][ $id_key ] )
  316. ? absint( $alldata[ $base_id ][ $i ][ $id_key ] )
  317. : 0;
  318. return array(
  319. 'value' => $this->text_url(),
  320. 'supporting_field_value' => $id_val,
  321. 'supporting_field_id' => $id_key,
  322. );
  323. }
  324. /**
  325. * Peforms saving of `file` attachement's ID
  326. * @since 1.1.0
  327. */
  328. public function _save_file_id_value( $file_id_key ) {
  329. $id_field = $this->_new_supporting_field( $file_id_key );
  330. // Check standard data_to_save data
  331. $id_val = isset( $this->field->data_to_save[ $file_id_key ] )
  332. ? $this->field->data_to_save[ $file_id_key ]
  333. : null;
  334. // If there is no ID saved yet, try to get it from the url
  335. if ( $this->value && ! $id_val ) {
  336. $id_val = cmb2_utils()->image_id_from_url( $this->value );
  337. }
  338. return $id_field->save_field( $id_val );
  339. }
  340. /**
  341. * Peforms saving of `text_datetime_timestamp_timezone` utc timestamp
  342. * @since 2.2.0
  343. */
  344. public function _save_utc_value( $utc_key, $utc_stamp ) {
  345. return $this->_new_supporting_field( $utc_key )->save_field( $utc_stamp );
  346. }
  347. /**
  348. * Returns a new, supporting, CMB2_Field object based on a new field id.
  349. * @since 2.2.0
  350. */
  351. public function _new_supporting_field( $new_field_id ) {
  352. $args = $this->field->args();
  353. unset( $args['_id'], $args['_name'] );
  354. $args['id'] = $new_field_id;
  355. $args['sanitization_cb'] = false;
  356. // And get new field object
  357. return new CMB2_Field( array(
  358. 'field_args' => $args,
  359. 'group_field' => $this->field->group,
  360. 'object_id' => $this->field->object_id,
  361. 'object_type' => $this->field->object_type,
  362. ) );
  363. }
  364. /**
  365. * If repeating, loop through and re-apply sanitization method
  366. * @since 1.1.0
  367. * @param string $method Class method
  368. * @param bool $repeat Whether repeating or not
  369. * @return mixed Sanitized value
  370. */
  371. public function _check_repeat( $method, $repeat ) {
  372. if ( $repeat || ! $this->field->args( 'repeatable' ) ) {
  373. return false;
  374. }
  375. $values_array = $this->value;
  376. $new_value = array();
  377. foreach ( $values_array as $iterator => $this->value ) {
  378. if ( $this->value ) {
  379. $val = $this->$method( true );
  380. if ( ! empty( $val ) ) {
  381. $new_value[] = $val;
  382. }
  383. }
  384. }
  385. $this->value = $new_value;
  386. return empty( $this->value ) ? null : $this->value;
  387. }
  388. /**
  389. * Determine if passed value is an empty array
  390. * @since 2.0.6
  391. * @param mixed $to_check Value to check
  392. * @return boolean Whether value is an array that's empty
  393. */
  394. public function _is_empty_array( $to_check ) {
  395. if ( is_array( $to_check ) ) {
  396. $cleaned_up = array_filter( $to_check );
  397. return empty( $cleaned_up );
  398. }
  399. return false;
  400. }
  401. }