M\á:l‹°;ZfbJôØèÞ®^—X£ß (qª·vÓIÍnÛ³séRÈEÜ]ð>=½ô €“²ñ–ïsHƒR<¿×™¦.¤yÈrHl‚·üêãpÞ´-)QAù€pëægÇv¼T†¶�hnç+4K¸ Bl›¤ñ1IoZOg6¹ å›­\BÇV£äøºV¹qurÊœ�¢ARK­qcZé�FE®}5(ˆ{É�ö1fb…Ão×)?ÞwïÞ#4ËpŸ”‹°A¹÷<©óC*¸½ÆÐ<ѺGäÙ¶Ç…*ÿ[œ…†ÕRÔ¢KJ>¡÷ÝÈSâÒ�þo­ô±úoŠÑw`¶pâ(K�b;þ⎆º&)òÇ`?«%'þ‰·\¹þ=wûÐz]Çî~û2Ø×„ J³°¹=ªñ»tö=6}ù[‡âY�›¸›ë«8'—ïå^k�¡€nO9Ìp+pi& ꪄكm*ÈS…ä@áÀR_>ÞŽzàú¯…Z�–BÜ“LªýïÜf{lE2[—àóò¾…èløp<YQŽ e'ÏÑ$C))²_Czªb±!ôÆ M¤/$­¸F>/àþ¶3ôWFÚ‚_„SK~×"Š)š}Óˆ/Ú¥NÈÇ�Ä–KM;VœÞÉV·�)9[ =ãÈ#5¸Bk¹8”%ŸZ¨ãÀ e‡.Ã6õí~ñý8L¹“Ý<–ŒÁ¦Xé¶RÇõWÓ†Á4FDigJ-Uú7‰IÐd–jY7ší€u—BmŒ~£�™^xÇ8=¡Í�€yƒf’C õ8–u×Ù‹v4b‚ò:}]c�# "UÓt“»oª�v‹"¶pY½Ùäî{ÏxRØÀðªdoÞìh@.Gqö¨úBêRÖnŽ¡äòçꌅ|SGÑÓª÷9¼Lh—4綾sÙØÉ~ÒWä°'ó^@�÷".X"‹mL@—„WÞÀŠñÜ-˜¹©–æg®…þLc%øÙ®~ùègñSÒ»¬GŸ ³< ­‚u¤qùxÛ9ò”EÍ?˜E¹-^!�zx†®fQLx1z¢ü“/è¡/†¹ �¿g2Ç<´è|ýÆSâ‡rpŠ�W<ʺø‘m²ê__|׿EíG+²¡y ÑŒ´a[Û”(ú+:›Û9ºB¥ÝˆEO@q-æ…’ì{;ƒ�O«l7âù��c¹Ö îÿÁxû=¢D:†o/Obøõù§c%ÿ…¤È¼�&2�ýXÀ:xtØ vÈZ&º¡NV¤A¢?JÌ%hTÈþK„Ãb.e�Š�I4þ”8¢›¿mH‚Ö9¢”î†v£,dPUWYˆœõcvæ;oHñ#[kyÆ“íz ÈÖ��¦iìòL£ÔJWc‘y% »�íÒ_®Cséý¯x•ÃÆ;áó¢°*— ê÷N‡Ñ�¨ö¦iÁ]-5ó�ïËw;GB;·„ fÙÌÁF+ k+{@’±_òñÇå¾Hr –—Å ¥_sŸ×²Y%0v²;–ß&7צÌ%Î…7ñ¯#ß#Ò}Æ?øš æÇ²³W¨z4F9¤„S¢[—¸oWÞè§È„:›WWIe¶³Ñû×Ú½å DXQæ€Ö¬^LK1ÍsÁZ|ðìsÃÑò¦JèÖVG–�p§ÎÈ ÑÁYÑ”#©ôìÐP÷ QX)ø…>ö™Ô ŒE:·ýã.ˆtSÙ“qB³ W@Èm½�#ä�`s¡>üpU–q°®U£]1PÁ67PK—Q K=‡YÊ:6–sƒa—JÃÛ�WV·Ê‘ÛÞ�¯Î :©+• ¤ùR¾�S¨\´“Vùè3·²ÓÇóOs¢‡kå?‚'ænfkÁoQºM9LuºåŽ ªî;ÌYá´$p¯ßL±i�ªVΆ|º³SƳwÛI³�h®ÅÆÈr=['ºÄÑ _H©'Y%ñ�ÏÀ.?P$!åŸ4Îÿ·cv1ŽÇÜM} æ¥2øƒ s+!ua1K\þù7\IóFi^õüiðu/ã×úŠ;pB¾2_¼;Wx®­§ðÙm×V"v®è,0ÞN */ 12: 13: namespace DataTables\Editor; 14: if (!defined('DATATABLES')) exit(); 15: 16: use DataTables\Editor\ValidateOptions; 17: 18: /** 19: * Validation methods for DataTables Editor fields. 20: * 21: * These methods will typically be applied through the {@link Field::validator} 22: * method and thus the arguments to be passed will be automatically resolved 23: * by Editor. 24: * 25: * The validation methods in this class all take three parameters: 26: * 27: * 1. Data to be validated 28: * 2. Full data from the form (this can be used with a custom validation method 29: * for dependent validation). 30: * 3. Validation configuration options. 31: * 32: * When using the `Validate` class functions with the {@link Field::validator} 33: * method, the second parameter passed into {@link Field::validator} is given 34: * to the validation functions here as the third parameter. The first and 35: * second parameters are automatically resolved by the {@link Field} class. 36: * 37: * The validation configuration options is an array of options that can be used 38: * to customise the validation - for example defining a date format for date 39: * validation. Each validation method has the option of defining its own 40: * validation options, but all validation methods provide four common options: 41: * 42: * * `{boolean} optional` - Require the field to be submitted (`false`) or not 43: * (`true` - default). When set to `true` the field does not need to be 44: * included in the list of parameters sent by the client - if set to `false` 45: * then it must be included. This option can be be particularly used in Editor 46: * as Editor will not set a value for fields which have not been submitted - 47: * giving the ability to submit just a partial list of options. 48: * * `{boolean} empty` - Allow a field to be empty, i.e. a zero length string - 49: * `''` (`true` - default) or require it to be non-zero length (`false`). 50: * * `{boolean} required` - Short-cut for `optional=false` and `empty=false`. 51: * Note that if this option is set the `optional` and `empty` parameters are 52: * automatically set and cannot be overridden by passing in different values. 53: * * `{string} message` - Error message shown should validation fail. This 54: * provides complete control over the message shown to the end user, including 55: * internationalisation (i.e. to provide a translation that is not in the 56: * English language). 57: * 58: * @example 59: * <code> 60: * // Ensure that a non-empty value is given for a field 61: * Field::inst( 'engine' )->validator( Validate::required() ) 62: * </code> 63: * 64: * @example 65: * <code> 66: * // Don't require a field to be submitted, but if it is submitted, it 67: * // must be non-empty 68: * Field::inst( 'reg_date' )->validator( Validate::notEmpty() ) 69: * </code> 70: * 71: * @example 72: * <code> 73: * // Date validation 74: * Field::inst( 'reg_date' )->validator( Validate::dateFormat( 'D, d M y' ) ) 75: * </code> 76: * 77: * @example 78: * <code> 79: * // Date validation with a custom error message 80: * Field::inst( 'reg_date' )->validator( Validate::dateFormat( 'D, d M y', 81: * ValidateOptions::inst() 82: * ->message( 'Invalid date' ) 83: * ) ) 84: * </code> 85: * 86: * @example 87: * <code> 88: * // Require a non-empty e-mail address 89: * Field::inst( 'reg_date' )->validator( Validate::email( ValidateOptions::inst() 90: * ->empty( false ) 91: * ) ) 92: * </code> 93: * 94: * @example 95: * <code> 96: * // Custom validation - closure 97: * Field::inst( 'engine' )->validator( function($val, $data, $opts) { 98: * if ( ! preg_match( '/^1/', $val ) ) { 99: * return "Value <b>must</b> start with a 1"; 100: * } 101: * return true; 102: * } ) 103: * </code> 104: */ 105: class Validate { 106: /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 107: * Internal functions 108: */ 109: 110: /** 111: * "Magic" method to automatically apply the required check to any of the 112: * static methods simply by adding '_required' or '_empty' to the end of the 113: * method's name, depending on if you need the field to be submitted or not. 114: * 115: * This is retained for backwards compatibility, but the validation options 116: * are now the recommended way of indicating that a field is required. 117: * 118: * @internal 119: * @param string $name Function name 120: * @param array $arguments Function arguments 121: * @return mixed|string 122: */ 123: public static function __callStatic( $name, $arguments ) { 124: if ( preg_match( '/_required$/', $name ) ) { 125: if ( $arguments[0] === null || $arguments[0] === '' ) { 126: return 'This field is required'; 127: } 128: 129: return call_user_func_array( 130: __NAMESPACE__.'\Validate::'.str_replace( '_required', '', $name ), 131: $arguments 132: ); 133: } 134: } 135: 136: 137: /** 138: * Extend the options from the user function and the validation function 139: * with core defaults. 140: * 141: * @internal 142: */ 143: public static function _extend( $userOpts, $prop, $fnOpts ) { 144: $cfg = array( 145: 'message' => 'Input not valid', 146: 'required' => false, 147: 'empty' => true, 148: 'optional' => true 149: ); 150: 151: if ( ! is_array( $userOpts ) ) { 152: if ( $prop ) { 153: $cfg[ $prop ] = $userOpts; 154: } 155: 156: // Not an array, but the non-array case has been handled above, so 157: // just an empty array 158: $userOpts = array(); 159: } 160: 161: // Merge into a single array - first array gets priority if there is a 162: // key clash, so user first, then function commands and finally the 163: // global options 164: $cfg = $userOpts + $fnOpts + $cfg; 165: 166: return $cfg; 167: } 168: 169: 170: /** 171: * Perform common validation using the configuration parameters 172: * 173: * @internal 174: */ 175: public static function _common( $val, $opts ) { 176: $optional = $opts->optional(); 177: $empty = $opts->allowEmpty(); 178: 179: // Error state tests 180: if ( ! $optional && $val === null ) { 181: // Value must be given 182: return false; 183: } 184: else if ( $empty === false && $val === '' ) { 185: // Value must not be empty 186: return false; 187: } 188: 189: // Validation passed states 190: if ( $optional && $val === null ) { 191: return true; 192: } 193: else if ( $empty === true && $val === '' ) { 194: return true; 195: } 196: 197: // Have the specific validation function perform its tests 198: return null; 199: } 200: 201: /** 202: * Convert the old style validation parameters into ValidateOptions 203: * 204: * @internal 205: */ 206: public static function _commonLegacy( $cfg ) { 207: $opts = new ValidateOptions(); 208: 209: if ( is_array( $cfg ) ) { 210: // `required` is a legacy shortcut for optional=false, empty=false 211: if ( isset( $cfg['required'] ) ) { 212: $opts->optional( false ); 213: $opts->allowEmpty( false ); 214: } 215: 216: if ( isset( $cfg['empty'] ) ) { 217: $opts->allowEmpty( $cfg['empty'] ); 218: } 219: 220: if ( isset( $cfg['message'] ) ) { 221: $opts->message( $cfg['message'] ); 222: } 223: 224: if ( isset( $cfg['optional'] ) ) { 225: $opts->optional( $cfg['optional'] ); 226: } 227: } 228: 229: return $opts; 230: } 231: 232: 233: 234: /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 235: * Basic validation 236: */ 237: 238: /** 239: * No validation - all inputs are valid. 240: * @return callable Validation function 241: */ 242: public static function none() { 243: return function ( $val, $data, $field, $host ) { 244: return true; 245: }; 246: } 247: 248: 249: /** 250: * Basic validation - this is used to perform the validation provided by the 251: * validation options only. If the validation options pass (e.g. `required`, 252: * `empty` and `optional`) then the validation will pass regardless of the 253: * actual value. 254: * 255: * Note that there are two helper short-cut methods that provide the same 256: * function as this method, but are slightly shorter: 257: * 258: * ``` 259: * // Required: 260: * Validate::required() 261: * 262: * // is the same as 263: * Validate::basic( $val, $data, array( 264: * "required" => true 265: * ); 266: * ``` 267: * 268: * ``` 269: * // Optional, but not empty if given: 270: * Validate::notEmpty() 271: * 272: * // is the same as 273: * Validate::basic( $val, $data, array( 274: * "empty" => false 275: * ); 276: * ``` 277: * 278: * @param string $val The value to check for validity 279: * @param string[] $data The full data set submitted 280: * @param array $opts Validation options. No additional options are 281: * available or required for this validation method. 282: * @param array $host Host information 283: * @return string|true true if the value is valid, a string with an error 284: * message otherwise. 285: */ 286: static function basic( $cfg=null ) { 287: $opts = ValidateOptions::select( $cfg ); 288: 289: return function ( $val, $data, $field, $host ) use ( $opts ) { 290: $common = Validate::_common( $val, $opts ); 291: 292: return $common === false ? 293: $opts->message() : 294: true; 295: }; 296: } 297: 298: 299: /** 300: * Required field - there must be a value and it must be a non-empty value 301: * 302: * This is a helper short-cut method which is the same as: 303: * 304: * ``` 305: * Validate::basic( $val, $data, array( 306: * "required" => true 307: * ); 308: * ``` 309: * 310: * @param string $val The value to check for validity 311: * @param string[] $data The full data set submitted 312: * @param array $opts Validation options. No additional options are 313: * available or required for this validation method. 314: * @param array $host Host information 315: * @return string|true true if the value is valid, a string with an error 316: * message otherwise. 317: */ 318: static function required( $cfg=null ) { 319: $opts = ValidateOptions::select( $cfg ); 320: $opts->allowEmpty( false ); 321: $opts->optional( false ); 322: 323: return function ( $val, $data, $field, $host ) use ( $opts ) { 324: $common = Validate::_common( $val, $opts ); 325: 326: return $common === false ? 327: $opts->message() : 328: true; 329: }; 330: } 331: 332: 333: /** 334: * Optional field, but if given there must be a non-empty value 335: * 336: * This is a helper short-cut method which is the same as: 337: * 338: * ``` 339: * Validate::basic( $val, $data, array( 340: * "empty" => false 341: * ); 342: * ``` 343: * 344: * @param ValidateOptions $cfg Validation options 345: * @return callable Validation function 346: */ 347: static function notEmpty( $cfg=null ) { 348: $opts = ValidateOptions::select( $cfg ); 349: $opts->allowEmpty( false ); 350: 351: return function ( $val, $data, $field, $host ) use ( $opts ) { 352: $common = Validate::_common( $val, $opts ); 353: 354: return $common === false ? 355: $opts->message() : 356: true; 357: }; 358: } 359: 360: 361: /** 362: * Validate an input as a boolean value. 363: * 364: * @param string $val The value to check for validity 365: * @param string[] $data The full data set submitted 366: * @param array $opts Validation options. No additional options are 367: * available or required for this validation method. 368: * @param array $host Host information 369: * @return string|true true if the value is valid, a string with an error 370: * message otherwise. 371: */ 372: public static function boolean( $cfg=null ) { 373: $opts = ValidateOptions::select( $cfg ); 374: 375: return function ( $val, $data, $field, $host ) use ( $opts ) { 376: $common = Validate::_common( $val, $opts ); 377: 378: if ( $common !== null ) { 379: return $common === false ? 380: $opts->message() : 381: $common; 382: } 383: 384: if ( filter_var($val, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE) === null ) { 385: return $opts->message(); 386: } 387: return true; 388: }; 389: } 390: 391: 392: 393: /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 394: * Number validation methods 395: */ 396: 397: /** 398: * Check that any input is numeric. 399: * 400: * @param string $val The value to check for validity 401: * @param string[] $data The full data set submitted 402: * @param array $opts Validation options. Additional options: 403: * * `decimal`: is available to indicate what character should be used 404: * as the decimal 405: * @param array $host Host information 406: * @return string|true true if the value is valid, a string with an error 407: * message otherwise. 408: */ 409: public static function numeric ( $decimal=".", $cfg=null ) { 410: $opts = ValidateOptions::select( $cfg ); 411: 412: return function ( $val, $data, $field, $host ) use ( $opts, $decimal ) { 413: $common = Validate::_common( $val, $opts ); 414: 415: if ( $common !== null ) { 416: return $common === false ? 417: $opts->message() : 418: $common; 419: } 420: 421: if ( $decimal !== '.' ) { 422: $val = str_replace( $decimal, '.', $val ); 423: } 424: 425: return ! is_numeric( $val ) ? 426: $opts->message() : 427: true; 428: }; 429: } 430: 431: /** 432: * Check for a numeric input and that it is greater than a given value. 433: * 434: * @param string $val The value to check for validity 435: * @param string[] $data The full data set submitted 436: * @param int|array $opts Validation options. Additional options: 437: * * `min`: indicate the minimum value. If only the default validation 438: * options are required, this parameter can be given as an integer 439: * value, which will be used as the minimum value. 440: * * `decimal`: is available to indicate what character should be used 441: * as the decimal 442: * separator (default '.'). 443: * @param array $host Host information 444: * @return string|true true if the value is valid, a string with an error 445: * message otherwise. 446: */ 447: public static function minNum ( $min, $decimal=".", $cfg=null ) { 448: $opts = ValidateOptions::select( $cfg ); 449: 450: return function ( $val, $data, $field, $host ) use ( $opts, $min, $decimal ) { 451: $common = Validate::_common( $val, $opts ); 452: 453: if ( $common !== null ) { 454: return $common === false ? 455: $opts->message() : 456: $common; 457: } 458: 459: $fn = Validate::numeric( $decimal, $opts ); 460: $numeric = $fn( $val, $data, $field, $host ); 461: 462: if ( $numeric !== true ) { 463: return $numeric; 464: } 465: 466: if ( $decimal !== '.' ) { 467: $val = str_replace( $decimal, '.', $val ); 468: } 469: 470: return $val < $min ? 471: $opts->message() : 472: true; 473: }; 474: } 475: 476: /** 477: * Check for a numeric input and that it is less than a given value. 478: * 479: * @param string $val The value to check for validity 480: * @param string[] $data The full data set submitted 481: * @param int|array $opts Validation options. 482: * * `max`: indicate the maximum value. If only the default validation 483: * options are required, this parameter can be given as an integer 484: * value, which will be used as the maximum value. 485: * * `decimal`: is available to indicate what character should be used 486: * as the decimal 487: * @param array $host Host information 488: * @return string|true true if the value is valid, a string with an error 489: * message otherwise. 490: */ 491: public static function maxNum ( $max, $decimal=".", $cfg=null ) { 492: $opts = ValidateOptions::select( $cfg ); 493: 494: return function ( $val, $data, $field, $host ) use ( $opts, $max, $decimal ) { 495: $common = Validate::_common( $val, $opts ); 496: 497: if ( $common !== null ) { 498: return $common === false ? 499: $opts->message() : 500: $common; 501: } 502: 503: $fn = Validate::numeric( $decimal, $opts ); 504: $numeric = $fn( $val, $data, $field, $host ); 505: 506: if ( $numeric !== true ) { 507: return $numeric; 508: } 509: 510: if ( $decimal !== '.' ) { 511: $val = str_replace( $decimal, '.', $val ); 512: } 513: 514: return $val > $max ? 515: $opts->message() : 516: true; 517: }; 518: } 519: 520: 521: /** 522: * Check for a numeric input and that it is both greater and smaller than 523: * given numbers. 524: * 525: * @param string $val The value to check for validity 526: * @param string[] $data The full data set submitted 527: * @param int|array $opts Validation options. Additional options: 528: * * `min`: indicate the minimum value. 529: * * `max`: indicate the maximum value. 530: * * `decimal`: is available to indicate what character should be used 531: * as the decimal 532: * @param array $host Host information 533: * @return string|true true if the value is valid, a string with an error 534: * message otherwise. 535: */ 536: public static function minMaxNum ( $min, $max, $decimal='.', $cfg=null ) { 537: $opts = ValidateOptions::select( $cfg ); 538: 539: return function ( $val, $data, $field, $host ) use ( $opts, $min, $max, $decimal ) { 540: $common = Validate::_common( $val, $opts ); 541: 542: if ( $common !== null ) { 543: return $common === false ? 544: $opts->message() : 545: $common; 546: } 547: 548: $fn = Validate::numeric( $decimal, $opts ); 549: $numeric = $fn( $val, $data, $field, $host ); 550: 551: if ( $numeric !== true ) { 552: return $numeric; 553: } 554: 555: $fn = Validate::minNum( $min, $decimal, $opts ); 556: $numeric = $fn( $val, $data, $field, $host ); 557: 558: if ( $numeric !== true ) { 559: return $numeric; 560: } 561: 562: $fn = Validate::maxNum( $max, $decimal, $opts ); 563: $numeric = $fn( $val, $data, $field, $host ); 564: 565: if ( $numeric !== true ) { 566: return $numeric; 567: } 568: 569: return true; 570: }; 571: } 572: 573: 574: 575: /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 576: * String validation methods 577: */ 578: 579: /** 580: * Validate an input as an e-mail address. 581: * 582: * @param string $val The value to check for validity 583: * @param string[] $data The full data set submitted 584: * @param array $opts Validation options. No additional options are 585: * available or required for this validation method. 586: * @param array $host Host information 587: * @return string|true true if the value is valid, a string with an error 588: * message otherwise. 589: */ 590: public static function email( $cfg=null ) { 591: $opts = ValidateOptions::select( $cfg ); 592: 593: return function ( $val, $data, $field, $host ) use ( $opts ) { 594: $common = Validate::_common( $val, $opts ); 595: 596: if ( $common !== null ) { 597: return $common === false ? 598: $opts->message() : 599: $common; 600: } 601: 602: return filter_var($val, FILTER_VALIDATE_EMAIL) !== false ? 603: true : 604: $opts->message(); 605: }; 606: } 607: 608: 609: /** 610: * Validate a string has a minimum length. 611: * 612: * @param string $val The value to check for validity 613: * @param string[] $data The full data set submitted 614: * @param int|array $opts Validation options. The additional option of 615: * `min` is available for this method to indicate the minimum string 616: * length. If only the default validation options are required, this 617: * parameter can be given as an integer value, which will be used as the 618: * minimum string length. 619: * @param array $host Host information 620: * @return string|true true if the value is valid, a string with an error 621: * message otherwise. 622: */ 623: public static function minLen( $min, $cfg=null ) { 624: $opts = ValidateOptions::select( $cfg ); 625: 626: return function ( $val, $data, $field, $host ) use ( $min, $opts ) { 627: $common = Validate::_common( $val, $opts ); 628: 629: if ( $common !== null ) { 630: return $common === false ? 631: $opts->message() : 632: $common; 633: } 634: 635: $strlen = is_callable('mb_strlen') ? 636: 'mb_strlen' : 637: 'strlen'; 638: 639: return $strlen( $val ) < $min ? 640: $opts->message() : 641: true; 642: }; 643: } 644: 645: 646: /** 647: * Validate a string does not exceed a maximum length. 648: * 649: * @param string $val The value to check for validity 650: * @param string[] $data The full data set submitted 651: * @param int|array $opts Validation options. The additional option of 652: * `max` is available for this method to indicate the maximum string 653: * length. If only the default validation options are required, this 654: * parameter can be given as an integer value, which will be used as the 655: * maximum string length. 656: * @param array $host Host information 657: * @return string|true true if the value is valid, a string with an error 658: * message otherwise. 659: */ 660: public static function maxLen( $max, $cfg=null ) { 661: $opts = ValidateOptions::select( $cfg ); 662: 663: return function ( $val, $data, $field, $host ) use ( $max, $opts ) { 664: $common = Validate::_common( $val, $opts ); 665: 666: if ( $common !== null ) { 667: return $common === false ? 668: $opts->message() : 669: $common; 670: } 671: 672: $strlen = is_callable('mb_strlen') ? 673: 'mb_strlen' : 674: 'strlen'; 675: 676: return $strlen( $val ) > $max ? 677: $opts->message() : 678: true; 679: }; 680: } 681: 682: /** 683: * Require a string with a certain minimum or maximum number of characters. 684: * 685: * @param string $val The value to check for validity 686: * @param string[] $data The full data set submitted 687: * @param int|array $opts Validation options. The additional options of 688: * `min` and `max` are available for this method to indicate the minimum 689: * and maximum string lengths, respectively. 690: * @param array $host Host information 691: * @return string|true true if the value is valid, a string with an error 692: * message otherwise. 693: */ 694: public static function minMaxLen( $min, $max, $cfg=null ) { 695: $opts = ValidateOptions::select( $cfg ); 696: 697: return function ( $val, $data, $field, $host ) use ( $opts, $min, $max ) { 698: $common = Validate::_common( $val, $opts ); 699: 700: if ( $common !== null ) { 701: return $common === false ? 702: $opts->message() : 703: $common; 704: } 705: 706: $fn = Validate::minLen( $min, $opts ); 707: $res = $fn( $val, $data, $field, $host ); 708: 709: if ( $res !== true ) { 710: return $res; 711: } 712: 713: $fn = Validate::maxLen( $max, $opts ); 714: $res = $fn( $val, $data, $field, $host ); 715: 716: if ( $res !== true ) { 717: return $res; 718: } 719: 720: return true; 721: }; 722: } 723: 724: 725: /** 726: * Validate as an IP address. 727: * 728: * @param string $val The value to check for validity 729: * @param string[] $data The full data set submitted 730: * @param array $opts Validation options. No additional options are 731: * available or required for this validation method. 732: * @param array $host Host information 733: * @return string|true true if the value is valid, a string with an error 734: * message otherwise. 735: */ 736: public static function ip( $cfg=null ) { 737: $opts = ValidateOptions::select( $cfg ); 738: 739: return function ( $val, $data, $field, $host ) use ( $opts ) { 740: $common = Validate::_common( $val, $opts ); 741: 742: if ( $common !== null ) { 743: return $common === false ? 744: $opts->message() : 745: $common; 746: } 747: 748: return filter_var($val, FILTER_VALIDATE_IP) !== false ? 749: true : 750: $opts->message(); 751: }; 752: } 753: 754: 755: /** 756: * Validate as an URL address. 757: * 758: * @param string $val The value to check for validity 759: * @param string[] $data The full data set submitted 760: * @param array $opts Validation options. No additional options are 761: * available or required for this validation method. 762: * @param array $host Host information 763: * @return string|true true if the value is valid, a string with an error 764: * message otherwise. 765: */ 766: public static function url( $cfg=null ) { 767: $opts = ValidateOptions::select( $cfg ); 768: 769: return function ( $val, $data, $field, $host ) use ( $opts ) { 770: $common = Validate::_common( $val, $opts ); 771: 772: if ( $common !== null ) { 773: return $common === false ? 774: $opts->message() : 775: $common; 776: } 777: 778: return filter_var($val, FILTER_VALIDATE_URL) !== false ? 779: true : 780: $opts->message(); 781: }; 782: } 783: 784: 785: /** 786: * Check if string could contain an XSS attack string 787: * 788: * @param string $val The value to check for validity 789: * @param string[] $data The full data set submitted 790: * @param int|array $opts Validation options. The additional options of 791: * `db` - database connection object, `table` - database table to use and 792: * `column` - the column to check this value against as value, are also 793: * available. These options are not required and if not given are 794: * automatically derived from the Editor and Field instances. 795: * @param array $host Host information 796: * @return string|true true if the value is valid, a string with an error 797: * message otherwise. 798: */ 799: public static function xss ( $cfg=null ) { 800: $opts = ValidateOptions::select( $cfg ); 801: 802: return function ( $val, $data, $field, $host ) use ( $opts ) { 803: $common = Validate::_common( $val, $opts ); 804: 805: if ( $common !== null ) { 806: return $common === false ? 807: $opts->message() : 808: $common; 809: } 810: 811: return $field->xssSafety( $val ) != $val ? 812: $opts->message() : 813: true; 814: }; 815: } 816: 817: 818: /** 819: * Confirm that the value submitted is in a list of allowable values 820: * 821: * @param string $val The value to check for validity 822: * @param string[] $data The full data set submitted 823: * @param int|array $opts Validation options. The additional options of 824: * `db` - database connection object, `table` - database table to use and 825: * `column` - the column to check this value against as value, are also 826: * available. These options are not required and if not given are 827: * automatically derived from the Editor and Field instances. 828: * @param array $host Host information 829: * @return string|true true if the value is valid, a string with an error 830: * message otherwise. 831: */ 832: public static function values( $values, $cfg=null ) { 833: $opts = ValidateOptions::select( $cfg ); 834: 835: return function ( $val, $data, $field, $host ) use ( $values, $opts ) { 836: $common = Validate::_common( $val, $opts ); 837: 838: if ( $common !== null ) { 839: return $common === false ? 840: $opts->message() : 841: $common; 842: } 843: 844: return in_array($val, $values) ? 845: true : 846: $opts->message(); 847: }; 848: } 849: 850: 851: /** 852: * Check if there are any tags in the submitted value 853: * 854: * @param string $val The value to check for validity 855: * @param string[] $data The full data set submitted 856: * @param int|array $opts Validation options. The additional options of 857: * `db` - database connection object, `table` - database table to use and 858: * `column` - the column to check this value against as value, are also 859: * available. These options are not required and if not given are 860: * automatically derived from the Editor and Field instances. 861: * @param array $host Host information 862: * @return string|true true if the value is valid, a string with an error 863: * message otherwise. 864: */ 865: public static function noTags ( $cfg=null ) { 866: $opts = ValidateOptions::select( $cfg ); 867: 868: return function ( $val, $data, $field, $host ) use ( $opts ) { 869: $common = Validate::_common( $val, $opts ); 870: 871: if ( $common !== null ) { 872: return $common === false ? 873: $opts->message() : 874: $common; 875: } 876: 877: return strip_tags( $val ) != $val ? 878: $opts->message() : 879: true; 880: }; 881: } 882: 883: 884: 885: /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 886: * Date validation methods 887: */ 888: 889: /** 890: * Check that a valid date input is given 891: * 892: * @param string $val The value to check for validity 893: * @param string[] $data The full data set submitted 894: * @param array|string $opts If given as a string, then $opts is the date 895: * format to check the validity of. If given as an array, then the 896: * date format is in the 'format' parameter, and the return error 897: * message in the 'message' parameter. 898: * @param array $host Host information 899: * @return string|true true if the value is valid, a string with an error 900: * message otherwise. 901: */ 902: public static function dateFormat( $format, $cfg=null ) { 903: $opts = ValidateOptions::select( $cfg ); 904: 905: return function ( $val, $data, $field, $host ) use ( $format, $opts ) { 906: $common = Validate::_common( $val, $opts ); 907: 908: if ( $common !== null ) { 909: return $common === false ? 910: $opts->message() : 911: $common; 912: } 913: 914: $formatCreate = substr($format, 0, 1) !== '!' ? 915: '!'.$format : 916: $format; 917: 918: $date = \DateTime::createFromFormat( $formatCreate, $val ); 919: 920: return $date && $date->format( $format ) == $val ? 921: true : 922: $opts->message(); 923: }; 924: } 925: 926: 927: /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 928: * Database validation methods 929: */ 930: 931: /** 932: * Check that the given value is unique in the database 933: * 934: * @param string $val The value to check for validity 935: * @param string[] $data The full data set submitted 936: * @param int|array $opts Validation options. The additional options of 937: * `db` - database connection object, `table` - database table to use and 938: * `column` - the column to check this value against as value, are also 939: * available. These options are not required and if not given are 940: * automatically derived from the Editor and Field instances. 941: * @param array $host Host information 942: * @return string|true true if the value is valid, a string with an error 943: * message otherwise. 944: */ 945: public static function unique( $cfg=null, $column=null, $table=null, $db=null ) { 946: $opts = ValidateOptions::select( $cfg ); 947: 948: return function ( $val, $data, $field, $host ) use ( $opts, $column, $table, $db ) { 949: $common = Validate::_common( $val, $opts ); 950: 951: if ( $common !== null ) { 952: return $common === false ? 953: $opts->message() : 954: $common; 955: } 956: 957: $editor = $host['editor']; 958: 959: if ( ! $db ) { 960: $db = $host['db']; 961: } 962: 963: if ( ! $table ) { 964: $table = $editor->table(); // Returns an array, but `select` will take an array 965: } 966: 967: if ( ! $column ) { 968: $column = $field->dbField(); 969: } 970: 971: $query = $db 972: ->query( 'select', $table ) 973: ->get( $column ) 974: ->where( $column, $val ); 975: 976: // If doing an edit, then we need to also discount the current row, 977: // since it is of course already validly unique 978: if ( $host['action'] === 'edit' ) { 979: $cond = $editor->pkeyToArray( $host['id'], true ); 980: $query->where( $cond, null, '!=' ); 981: } 982: 983: $res = $query->exec(); 984: 985: return $res->count() === 0 ? 986: true : 987: $opts->message(); 988: }; 989: } 990: 991: /** 992: * Check that the given value is a value that is available in a database - 993: * i.e. a join primary key. This will attempt to automatically use the table 994: * name and value column from the field's `options` method (under the 995: * assumption that it will typically be used with a joined field), but the 996: * table and field can also be specified via the options. 997: * 998: * @param string $val The value to check for validity 999: * @param string[] $data The full data set submitted 1000: * @param int|array $opts Validation options. The additional options of 1001: * `db` - database connection object, `table` - database table to use and 1002: * `column` - the column to check this value against as value, are also 1003: * available. These options are not required and if not given are 1004: * automatically derived from the Editor and Field instances. 1005: * @param array $host Host information 1006: * @return string|true true if the value is valid, a string with an error 1007: * message otherwise. 1008: */ 1009: public static function dbValues( $cfg=null, $column=null, $table=null, $db=null, $values=array() ) { 1010: $opts = ValidateOptions::select( $cfg ); 1011: 1012: return function ( $val, $data, $field, $host ) use ( $opts, $column, $table, $db, $values ) { 1013: $common = Validate::_common( $val, $opts ); 1014: 1015: if ( $common !== null ) { 1016: return $common === false ? 1017: $opts->message() : 1018: $common; 1019: } 1020: 1021: // Allow local values to be defined - for example null 1022: if ( in_array($val, $values) ) { 1023: return true; 1024: } 1025: 1026: $editor = $host['editor']; 1027: $options = $field->options(); 1028: 1029: if ( ! $db ) { 1030: $db = $host['db']; 1031: } 1032: 1033: if ( ! $table ) { 1034: $table = $options->table(); // Returns an array, but `select` will take an array 1035: } 1036: 1037: if ( ! $column ) { 1038: $column = $options->value(); 1039: } 1040: 1041: if ( ! $table ) { 1042: throw new \Exception('Table for database value check is not defined for field '.$field->name()); 1043: } 1044: 1045: if ( ! $column ) { 1046: throw new \Exception('Value column for database value check is not defined for field '.$field->name()); 1047: } 1048: 1049: // Try / catch in case the submitted value can't be represented as the 1050: // database type (e.g. an empty string as an integer) 1051: try { 1052: $count = $db 1053: ->query( 'select', $table ) 1054: ->get( $column ) 1055: ->where( $column, $val ) 1056: ->exec() 1057: ->count(); 1058: 1059: return $count === 0 ? 1060: $opts->message() : 1061: true; 1062: } 1063: catch (\Exception $e) { 1064: return $opts->message(); 1065: } 1066: }; 1067: } 1068: 1069: 1070: 1071: /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 1072: * File validation methods 1073: */ 1074: static function fileExtensions ( $extensions, $msg="This file type cannot be uploaded." ) { 1075: return function ( $file ) use ( $extensions, $msg ) { 1076: $extn = pathinfo($file['name'], PATHINFO_EXTENSION); 1077: 1078: for ( $i=0, $ien=count($extensions) ; $i<$ien ; $i++ ) { 1079: if ( strtolower( $extn ) === strtolower( $extensions[$i] ) ) { 1080: return true; 1081: } 1082: } 1083: 1084: return $msg; 1085: }; 1086: } 1087: 1088: static function fileSize ( $size, $msg="Uploaded file is too large." ) { 1089: return function ( $file ) use ( $size, $msg ) { 1090: return $file['size'] > $size ? 1091: $msg : 1092: true; 1093: }; 1094: } 1095: 1096: 1097: 1098: /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 1099: * Mjoin validation methods 1100: */ 1101: static function mjoinMinCount ( $count, $msg="Too few items." ) { 1102: return function ( $editor, $action, $values ) use ( $count, $msg ) { 1103: if ( $action === 'create' || $action === 'edit' ) { 1104: return count($values) < $count ? 1105: $msg : 1106: true; 1107: } 1108: return true; 1109: }; 1110: } 1111: 1112: static function mjoinMaxCount ( $count, $msg="Too many items." ) { 1113: return function ( $editor, $action, $values ) use ( $count, $msg ) { 1114: if ( $action === 'create' || $action === 'edit' ) { 1115: return count($values) > $count ? 1116: $msg : 1117: true; 1118: } 1119: return true; 1120: }; 1121: } 1122: 1123: 1124: /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 1125: * Internal functions 1126: * These legacy methods are for backwards compatibility with the old way of 1127: * using the validation methods. They basically do argument swapping. 1128: */ 1129: 1130: /** 1131: * @internal 1132: */ 1133: static function noneLegacy( $legacyOpts ) { 1134: return Validate::none(); 1135: } 1136: 1137: /** 1138: * @internal 1139: */ 1140: static function basicLegacy( $legacyOpts ) { 1141: $cfg = Validate::_extend( $legacyOpts, null, array() ); 1142: $opts = Validate::_commonLegacy( $cfg ); 1143: 1144: return Validate::required( $opts ); 1145: } 1146: 1147: /** 1148: * @internal 1149: */ 1150: static function requiredLegacy( $legacyOpts ) { 1151: $cfg = Validate::_extend( $legacyOpts, null, array( 1152: 'message' => "This field is required." 1153: ) ); 1154: $opts = Validate::_commonLegacy( $cfg ); 1155: 1156: return Validate::required( $opts ); 1157: } 1158: 1159: /** 1160: * @internal 1161: */ 1162: static function notEmptyLegacy( $legacyOpts ) { 1163: $cfg = Validate::_extend( $legacyOpts, null, array( 1164: 'message' => "This field is required." 1165: ) ); 1166: $opts = Validate::_commonLegacy( $cfg ); 1167: 1168: return Validate::notEmpty( $opts ); 1169: } 1170: 1171: /** 1172: * @internal 1173: */ 1174: static function booleanLegacy( $legacyOpts ) { 1175: $cfg = Validate::_extend( $legacyOpts, null, array( 1176: 'message' => "Please enter true or false." 1177: ) ); 1178: $opts = Validate::_commonLegacy( $cfg ); 1179: 1180: return Validate::notEmpty( $opts ); 1181: } 1182: 1183: /** 1184: * @internal 1185: */ 1186: static function numericLegacy( $legacyOpts ) { 1187: $cfg = Validate::_extend( $legacyOpts, null, array( 1188: 'message' => "This input must be given as a number." 1189: ) ); 1190: $opts = Validate::_commonLegacy( $cfg ); 1191: 1192: return isset( $legacyOpts['decimal'] ) ? 1193: Validate::numeric( $legacyOpts['decimal'], $opts ) : 1194: Validate::numeric( '.', $opts ); 1195: } 1196: 1197: /** 1198: * @internal 1199: */ 1200: static function minNumLegacy( $legacyOpts ) { 1201: $min = is_array($legacyOpts) ? $legacyOpts['min'] : $legacyOpts; 1202: $cfg = Validate::_extend( $legacyOpts, null, array( 1203: 'message' => "Number is too small, must be ".$min." or larger." 1204: ) ); 1205: $opts = Validate::_commonLegacy( $cfg ); 1206: 1207: return isset( $legacyOpts['decimal'] ) ? 1208: Validate::minNum( $min, $legacyOpts['decimal'], $opts ) : 1209: Validate::minNum( $min, '.', $opts ); 1210: } 1211: 1212: /** 1213: * @internal 1214: */ 1215: static function maxNumLegacy( $legacyOpts ) { 1216: $max = is_array($legacyOpts) ? $legacyOpts['max'] : $legacyOpts; 1217: $cfg = Validate::_extend( $legacyOpts, null, array( 1218: 'message' => "Number is too large, must be ".$max." or smaller." 1219: ) ); 1220: $opts = Validate::_commonLegacy( $cfg ); 1221: 1222: return isset( $legacyOpts['decimal'] ) ? 1223: Validate::maxNum( $max, $legacyOpts['decimal'], $opts ) : 1224: Validate::maxNum( $max, '.', $opts ); 1225: } 1226: 1227: /** 1228: * @internal 1229: */ 1230: static function minMaxNumLegacy( $legacyOpts ) { 1231: $min = $legacyOpts['min']; 1232: $max = $legacyOpts['max']; 1233: $cfg = Validate::_extend( $legacyOpts, null, array() ); 1234: $opts = Validate::_commonLegacy( $cfg ); 1235: 1236: return isset( $legacyOpts['decimal'] ) ? 1237: Validate::minMaxNum( $min, $max, $legacyOpts['decimal'], $opts ) : 1238: Validate::minMaxNum( $min, $max, '.', $opts ); 1239: } 1240: 1241: /** 1242: * @internal 1243: */ 1244: static function emailLegacy( $legacyOpts ) { 1245: $cfg = Validate::_extend( $legacyOpts, null, array( 1246: 'message' => "Please enter a valid e-mail address." 1247: ) ); 1248: $opts = Validate::_commonLegacy( $cfg ); 1249: 1250: return Validate::email( $opts ); 1251: } 1252: 1253: /** 1254: * @internal 1255: */ 1256: static function minLenLegacy( $legacyOpts ) { 1257: $min = is_array($legacyOpts) ? $legacyOpts['min'] : $legacyOpts; 1258: $cfg = Validate::_extend( $legacyOpts, null, array( 1259: 'message' => "The input is too short. ".$min." characters required." 1260: ) ); 1261: $opts = Validate::_commonLegacy( $cfg ); 1262: 1263: return Validate::minLen( $min, $opts ); 1264: } 1265: 1266: /** 1267: * @internal 1268: */ 1269: static function maxLenLegacy( $legacyOpts ) { 1270: $max = is_array($legacyOpts) ? $legacyOpts['max'] : $legacyOpts; 1271: $cfg = Validate::_extend( $legacyOpts, null, array( 1272: 'message' => "The input is too long. ".$max." characters maximum." 1273: ) ); 1274: $opts = Validate::_commonLegacy( $cfg ); 1275: 1276: return Validate::maxLen( $max, $opts ); 1277: } 1278: 1279: /** 1280: * @internal 1281: */ 1282: static function minMaxLenLegacy( $legacyOpts ) { 1283: $min = $legacyOpts['min']; 1284: $max = $legacyOpts['max']; 1285: $cfg = Validate::_extend( $legacyOpts, null, array() ); 1286: $opts = Validate::_commonLegacy( $cfg ); 1287: 1288: return Validate::minMaxLen( $min, $max, $opts ); 1289: } 1290: 1291: /** 1292: * @internal 1293: */ 1294: static function ipLegacy( $legacyOpts ) { 1295: $cfg = Validate::_extend( $legacyOpts, null, array( 1296: 'message' => "Please enter a valid IP address." 1297: ) ); 1298: $opts = Validate::_commonLegacy( $cfg ); 1299: 1300: return Validate::ip( $opts ); 1301: } 1302: 1303: /** 1304: * @internal 1305: */ 1306: static function urlLegacy( $legacyOpts ) { 1307: $cfg = Validate::_extend( $legacyOpts, null, array( 1308: 'message' => "Please enter a valid URL." 1309: ) ); 1310: $opts = Validate::_commonLegacy( $cfg ); 1311: 1312: return Validate::url( $opts ); 1313: } 1314: 1315: /** 1316: * @internal 1317: */ 1318: static function xssLegacy( $legacyOpts ) { 1319: $cfg = Validate::_extend( $legacyOpts, null, array( 1320: 'message' => "This field contains potentially unsafe data." 1321: ) ); 1322: $opts = Validate::_commonLegacy( $cfg ); 1323: 1324: return Validate::xss( $opts ); 1325: } 1326: 1327: /** 1328: * @internal 1329: */ 1330: static function valuesLegacy( $legacyOpts ) { 1331: $values = isset($legacyOpts['valid']) ? $legacyOpts['valid'] : $legacyOpts; 1332: $cfg = Validate::_extend( $legacyOpts, null, array( 1333: 'message' => "This value is not valid." 1334: ) ); 1335: $opts = Validate::_commonLegacy( $cfg ); 1336: 1337: return Validate::values( $values, $opts ); 1338: } 1339: 1340: /** 1341: * @internal 1342: */ 1343: static function noTagsLegacy( $legacyOpts ) { 1344: $cfg = Validate::_extend( $legacyOpts, null, array( 1345: 'message' => "This field may not contain HTML." 1346: ) ); 1347: $opts = Validate::_commonLegacy( $cfg ); 1348: 1349: return Validate::noTags( $opts ); 1350: } 1351: 1352: /** 1353: * @internal 1354: */ 1355: static function dateFormatLegacy( $legacyOpts ) { 1356: $format = is_array($legacyOpts) ? $legacyOpts['format'] : $legacyOpts; 1357: $cfg = Validate::_extend( $legacyOpts, null, array( 1358: 'message' => "Date is not in the expected format." 1359: ) ); 1360: $opts = Validate::_commonLegacy( $cfg ); 1361: 1362: return Validate::dateFormat( $format, $opts ); 1363: } 1364: 1365: /** 1366: * @internal 1367: */ 1368: static function uniqueLegacy( $legacyOpts ) { 1369: $table = isset( $legacyOpts['table'] ) ? $legacyOpts['table'] : null; 1370: $column = isset( $legacyOpts['column'] ) ? $legacyOpts['column'] : null; 1371: $db = isset( $legacyOpts['db'] ) ? $legacyOpts['db'] : null; 1372: $cfg = Validate::_extend( $legacyOpts, null, array( 1373: 'message' => "This field must have a unique value." 1374: ) ); 1375: $opts = Validate::_commonLegacy( $cfg ); 1376: 1377: return Validate::unique( $opts, $column, $table, $db ); 1378: } 1379: 1380: /** 1381: * @internal 1382: */ 1383: static function dbValuesLegacy( $legacyOpts ) { 1384: $table = isset( $legacyOpts['table'] ) ? $legacyOpts['table'] : null; 1385: $column = isset( $legacyOpts['column'] ) ? $legacyOpts['column'] : null; 1386: $db = isset( $legacyOpts['db'] ) ? $legacyOpts['db'] : null; 1387: $values = isset( $legacyOpts['values'] ) ? $legacyOpts['values'] : array(); 1388: $cfg = Validate::_extend( $legacyOpts, null, array( 1389: 'message' => "This value is not valid." 1390: ) ); 1391: $opts = Validate::_commonLegacy( $cfg ); 1392: 1393: return Validate::dbValues( $opts, $column, $table, $db, $values ); 1394: } 1395: } 1396: 1397: