[ Index ] |
|
Code source de b2evolution 2.1.0-beta |
1 <?php 2 /** 3 * This file implements parameter handling functions. 4 * 5 * This inlcudes: 6 * - sanity checking of inputs 7 * - removing PHP's stupid "magic" quotes 8 * - validating specific inputs (urls, regexps...) 9 * - memorizing params 10 * - regenerating urls with the memorized params 11 * - manually reconstructing urls 12 * 13 * This file is part of the evoCore framework - {@link http://evocore.net/} 14 * See also {@link http://sourceforge.net/projects/evocms/}. 15 * 16 * @copyright (c)2003-2007 by Francois PLANQUE - {@link http://fplanque.net/} 17 * Parts of this file are copyright (c)2004-2006 by Daniel HAHLER - {@link http://thequod.de/contact}. 18 * Parts of this file are copyright (c)2005-2006 by PROGIDISTRI - {@link http://progidistri.com/}. 19 * 20 * {@internal License choice 21 * - If you have received this file as part of a package, please find the license.txt file in 22 * the same folder or the closest folder above for complete license terms. 23 * - If you have received this file individually (e-g: from http://evocms.cvs.sourceforge.net/) 24 * then you must choose one of the following licenses before using the file: 25 * - GNU General Public License 2 (GPL) - http://www.opensource.org/licenses/gpl-license.php 26 * - Mozilla Public License 1.1 (MPL) - http://www.opensource.org/licenses/mozilla1.1.php 27 * }} 28 * 29 * {@internal Open Source relicensing agreement: 30 * Daniel HAHLER grants Francois PLANQUE the right to license 31 * Daniel HAHLER's contributions to this file and the b2evolution project 32 * under any OSI approved OSS license (http://www.opensource.org/licenses/). 33 * }} 34 * 35 * @package evocore 36 * 37 * @author cafelog (team) 38 * @author blueyed: Daniel HAHLER. 39 * @author fplanque: Francois PLANQUE. 40 * 41 * @version $Id: _param.funcs.php,v 1.5 2007/11/01 19:52:46 fplanque Exp $ 42 */ 43 if( !defined('EVO_MAIN_INIT') ) die( 'Please, do not access this page directly.' ); 44 45 46 /** 47 * Sets a parameter with values from the request or to provided default, 48 * except if param is already set! 49 * 50 * Also removes magic quotes if they are set automatically by PHP. 51 * Also forces type. 52 * Priority order: POST, GET, COOKIE, DEFAULT. 53 * 54 * @param string Variable to set 55 * @param string Force value type to one of: 56 * - integer 57 * - float, double 58 * - string (strips (HTML-)Tags, trims whitespace) 59 * - array (TODO: array/integer , array/array/string ) 60 * - html (does nothing) 61 * - '' (does nothing) 62 * - '/^...$/' check regexp pattern match (string) 63 * - boolean (will force type to boolean, but you can't use 'true' as a default since it has special meaning. There is no real reason to pass booleans on a URL though. Passing 0 and 1 as integers seems to be best practice). 64 * Value type will be forced only if resulting value (probably from default then) is !== NULL 65 * @param mixed Default value or TRUE if user input required 66 * @param boolean Do we need to memorize this to regenerate the URL for this page? 67 * @param boolean Override if variable already set 68 * @param boolean Force setting of variable to default if no param is sent and var wasn't set before 69 * @param mixed true will refuse illegal values, 70 * false will try to convert illegal to legal values, 71 * 'allow_empty' will refuse illegal values but will always accept empty values (This helps blocking dirty spambots or borked index bots. Saves a lot of processor time by killing invalid requests) 72 * @return mixed Final value of Variable, or false if we don't force setting and did not set 73 */ 74 function param( $var, $type = '', $default = '', $memorize = false, 75 $override = false, $use_default = true, $strict_typing = 'allow_empty' ) 76 { 77 global $Debuglog, $debug, $evo_charset, $io_charset; 78 // NOTE: we use $GLOBALS[$var] instead of $$var, because otherwise it would conflict with param names which are used as function params ("var", "type", "default", ..)! 79 80 /* 81 * STEP 1 : Set the variable 82 * 83 * Check if already set 84 * WARNING: when PHP register globals is ON, COOKIES get priority over GET and POST with this!!! 85 * dh> I never understood that comment.. does it refer to "variables_order" php.ini setting? 86 * fp> I guess 87 */ 88 if( ! isset( $GLOBALS[$var] ) || $override ) 89 { 90 if( isset($_POST[$var]) ) 91 { 92 $GLOBALS[$var] = remove_magic_quotes( $_POST[$var] ); 93 // if( isset($Debuglog) ) $Debuglog->add( 'param(-): '.$var.'='.$GLOBALS[$var].' set by POST', 'params' ); 94 } 95 elseif( isset($_GET[$var]) ) 96 { 97 $GLOBALS[$var] = remove_magic_quotes($_GET[$var]); 98 // if( isset($Debuglog) ) $Debuglog->add( 'param(-): '.$var.'='.$GLOBALS[$var].' set by GET', 'params' ); 99 } 100 elseif( isset($_COOKIE[$var])) 101 { 102 $GLOBALS[$var] = remove_magic_quotes($_COOKIE[$var]); 103 // if( isset($Debuglog) ) $Debuglog->add( 'param(-): '.$var.'='.$GLOBALS[$var].' set by COOKIE', 'params' ); 104 } 105 elseif( $default === true ) 106 { 107 bad_request_die( sprintf( T_('Parameter «%s» is required!'), $var ) ); 108 } 109 elseif( $use_default ) 110 { // We haven't set any value yet and we really want one: use default: 111 $GLOBALS[$var] = $default; 112 // echo '<br>param(-): '.$var.'='.$GLOBALS[$var].' set by default'; 113 // if( isset($Debuglog) ) $Debuglog->add( 'param(-): '.$var.'='.$GLOBALS[$var].' set by default', 'params' ); 114 } 115 else 116 { // param not found! don't set the variable. 117 // Won't be memorized nor type-forced! 118 return false; 119 } 120 } 121 else 122 { // Variable was already set but we need to remove the auto quotes 123 $GLOBALS[$var] = remove_magic_quotes($GLOBALS[$var]); 124 125 // if( isset($Debuglog) ) $Debuglog->add( 'param(-): '.$var.' already set to ['.var_export($GLOBALS[$var], true).']!', 'params' ); 126 } 127 128 if( isset($io_charset) && ! empty($evo_charset) ) 129 { 130 $GLOBALS[$var] = convert_charset( $GLOBALS[$var], $evo_charset, $io_charset ); 131 } 132 133 /* 134 * STEP 2: make sure the data fits the expected type 135 * 136 * type will be forced even if it was set before and not overriden 137 */ 138 if( !empty($type) && $GLOBALS[$var] !== NULL ) 139 { // Force the type 140 // echo "forcing type!"; 141 switch( $type ) 142 { 143 case 'html': 144 // do nothing 145 if( isset($Debuglog) ) $Debuglog->add( 'param(-): <strong>'.$var.'</strong> as HTML', 'params' ); 146 break; 147 148 case 'string': 149 // strip out any html: 150 // echo $var, '=', $GLOBALS[$var], '<br />'; 151 if( ! is_scalar($GLOBALS[$var]) ) 152 { // This happens if someone uses "foo[]=x" where "foo" is expected as string 153 // TODO: dh> debug_die() instead? 154 $GLOBALS[$var] = ''; 155 $Debuglog->add( 'param(-): <strong>'.$var.'</strong> is not scalar!', 'params' ); 156 } 157 else 158 { 159 $GLOBALS[$var] = trim( strip_tags($GLOBALS[$var]) ); 160 // Make sure the string is a single line 161 $GLOBALS[$var] = preg_replace( '¤\r|\n¤', '', $GLOBALS[$var] ); 162 } 163 $Debuglog->add( 'param(-): <strong>'.$var.'</strong> as string', 'params' ); 164 break; 165 166 default: 167 if( substr( $type, 0, 1 ) == '/' ) 168 { // We want to match against a REGEXP: 169 if( preg_match( $type, $GLOBALS[$var] ) ) 170 { // Okay, match 171 if( isset($Debuglog) ) $Debuglog->add( 'param(-): <strong>'.$var.'</strong> matched against '.$type, 'params' ); 172 } 173 elseif( $strict_typing == 'allow_empty' && empty($GLOBALS[$var]) ) 174 { // No match but we accept empty value: 175 if( isset($Debuglog) ) $Debuglog->add( 'param(-): <strong>'.$var.'</strong> is empty: ok', 'params' ); 176 } 177 elseif( $strict_typing ) 178 { // We cannot accept this MISMATCH: 179 bad_request_die( sprintf( T_('Illegal value received for parameter «%s»!'), $var ) ); 180 } 181 else 182 { // Fall back to default: 183 $GLOBALS[$var] = $default; 184 if( isset($Debuglog) ) $Debuglog->add( 'param(-): <strong>'.$var.'</strong> DID NOT match '.$type.' set to default value='.$GLOBALS[$var], 'params' ); 185 } 186 187 // From now on, consider this as a string: (we need this when memorizing) 188 $type = 'string'; 189 } 190 elseif( $GLOBALS[$var] === '' ) 191 { // Special handling of empty values. 192 if( $strict_typing === false && $use_default ) 193 { // ADDED BY FP 2006-07-06 194 // We want to consider empty values as invalid and fall back to the default value: 195 $GLOBALS[$var] = $default; 196 } 197 else 198 { // We memorize the empty value as NULL: 199 // fplanque> note: there might be side effects to this, but we need 200 // this to distinguish between 0 and 'no input' 201 // Note: we do this after regexps because we may or may not want to allow empty strings in regexps 202 $GLOBALS[$var] = NULL; 203 if( isset($Debuglog) ) $Debuglog->add( 'param(-): <strong>'.$var.'</strong> set to NULL', 'params' ); 204 } 205 } 206 elseif( $GLOBALS[$var] === array() ) 207 { 208 if( $strict_typing === false && $use_default ) 209 { // ADDED BY FP 2006-09-07 210 // We want to consider empty values as invalid and fall back to the default value: 211 $GLOBALS[$var] = $default; 212 } 213 } 214 // TODO: dh> if a var (e.g. from POST) comes in as '' but has type "array" it does not get "converted" to array type (nor gets the default used!) 215 else 216 { 217 if( $strict_typing ) 218 { // We want to make sure the value is valid: 219 $regexp = ''; 220 switch( $type ) 221 { 222 case 'boolean': 223 $regexp = '/^(0|1|false|true)$/i'; 224 break; 225 226 case 'integer': 227 $regexp = '/^(\+|-)?[0-9]+$/'; 228 break; 229 230 case 'float': 231 case 'double': 232 $regexp = '/^(\+|-)?[0-9]+(.[0-9]+)?$/'; 233 break; 234 235 // Note: other types are not tested here. 236 } 237 if( $strict_typing == 'allow_empty' && empty($GLOBALS[$var]) ) 238 { // We have an empty value and we accept it 239 // ok.. 240 } 241 elseif( !empty( $regexp ) && ( !is_scalar($GLOBALS[$var]) || !preg_match( $regexp, $GLOBALS[$var] ) ) ) 242 { // Value does not match! 243 bad_request_die( sprintf( T_('Illegal value received for parameter «%s»!'), $var ) ); 244 } 245 } 246 247 // Change the variable type: 248 settype( $GLOBALS[$var], $type ); 249 if( isset($Debuglog) ) $Debuglog->add( 'param(-): <strong>'.$var.'</strong> typed to '.$type.', new value='.$GLOBALS[$var], 'params' ); 250 } 251 } 252 } 253 254 255 /* 256 * STEP 3: memorize the value for later url regeneration 257 */ 258 if( $memorize ) 259 { // Memorize this parameter 260 memorize_param( $var, $type, $default ); 261 } 262 263 // echo $var, '(', gettype($GLOBALS[$var]), ')=', $GLOBALS[$var], '<br />'; 264 return $GLOBALS[$var]; 265 } 266 267 268 /** 269 * Get the param from an array param's first index instead of the value. 270 * 271 * E.g., for "param[value]" as a submit button you can get the value with 272 * <code>Request::param_arrayindex( 'param' )</code>. 273 * 274 * @see param_action() 275 * @param string Param name 276 * @param mixed Default to use 277 * @return string 278 */ 279 function param_arrayindex( $param_name, $default = '' ) 280 { 281 $array = array_keys( param( $param_name, 'array', array() ) ); 282 $value = array_pop( $array ); 283 if( is_string($value) ) 284 { 285 $value = substr( strip_tags($value), 0, 50 ); // sanitize it 286 } 287 elseif( !empty($value) ) 288 { // this is probably a numeric index from '<input name="array[]" .. />' 289 debug_die( 'Invalid array param!' ); 290 } 291 else 292 { 293 $value = $default; 294 } 295 296 return $value; 297 } 298 299 300 /** 301 * Get the action from params. 302 * 303 * If we got no "action" param, we'll check for an "actionArray" param 304 * ( <input type="submit" name="actionArray[real_action]" ...> ). 305 * And the real $action will be found in the first key... 306 * When there are multiple submit buttons, this is smarter than checking the value which is a translated string. 307 * When there is an image button, this allows to work around IE not sending the value (it only sends X & Y coords of the click). 308 * 309 * @param mixed Default to use. 310 * @return string 311 */ 312 function param_action( $default = '', $memorize = false ) 313 { 314 $action = param( 'action', 'string', NULL, $memorize ); 315 316 if( is_null($action) ) 317 { // Check $actionArray 318 $action = param_arrayindex( 'actionArray', $default ); 319 320 set_param( 'action', $action ); // always set "action" 321 } 322 323 return $action; 324 } 325 326 327 /** 328 * Get a param from cookie. 329 * 330 * {@internal This is just a wrapper around {@link param()} which unsets and 331 * restores GET and POST. IMHO this is less hackish, at least performance 332 * wise then using a $sources param for param()}} 333 * 334 * @uses param() 335 * @see param() 336 */ 337 function param_cookie($var, $type = '', $default = '', $memorize = false, 338 $override = false, $use_default = true, $strict_typing = 'allow_empty') 339 { 340 $save_GET = $_GET; 341 $save_POST = $_POST; 342 343 unset( $_GET, $_POST ); 344 345 $r = param( $var, $type, $default, $memorize, $override, $use_default, $strict_typing ); 346 347 $_GET = $save_GET; 348 $_POST = $save_POST; 349 350 return $r; 351 } 352 353 354 /** 355 * @param string param name 356 * @param string error message 357 * @param string|NULL error message for form field ($err_msg gets used if === NULL). 358 * @return boolean true if OK 359 */ 360 function param_string_not_empty( $var, $err_msg, $field_err_msg = NULL ) 361 { 362 param( $var, 'string', true ); 363 return param_check_not_empty( $var, $err_msg, $field_err_msg ); 364 } 365 366 367 /** 368 * @param string param name 369 * @param string error message 370 * @param string|NULL error message for form field ($err_msg gets used if === NULL). 371 * @return boolean true if OK 372 */ 373 function param_check_not_empty( $var, $err_msg, $field_err_msg = NULL ) 374 { 375 if( empty( $GLOBALS[$var] ) ) 376 { 377 param_error( $var, $err_msg, $field_err_msg ); 378 return false; 379 } 380 return true; 381 } 382 383 384 /** 385 * Checks if the param is a decimal number (no float, e.g. 3.14). 386 * 387 * @param string param name 388 * @param string error message 389 * @return boolean true if OK 390 */ 391 function param_check_number( $var, $err_msg, $required = false ) 392 { 393 if( empty( $GLOBALS[$var] ) && ! $required ) 394 { // empty is OK: 395 return true; 396 } 397 398 if( ! preg_match( '#^[0-9]+$#', $GLOBALS[$var] ) ) 399 { 400 param_error( $var, $err_msg ); 401 return false; 402 } 403 return true; 404 } 405 406 407 /** 408 * Gets a param and makes sure it's a decimal number (no float, e.g. 3.14) in a given range. 409 * 410 * @param string param name 411 * @param integer min value 412 * @param integer max value 413 * @param string error message (gets printf'ed with $min and $max) 414 * @return boolean true if OK 415 */ 416 function param_integer_range( $var, $min, $max, $err_msg, $required = true ) 417 { 418 param( $var, 'integer', $required ? true : '' ); 419 return param_check_range( $var, $min, $max, $err_msg, $required ); 420 } 421 422 423 /** 424 * Checks if the param is a decimal number (no float, e.g. 3.14) in a given range. 425 * 426 * @param string param name 427 * @param integer min value 428 * @param integer max value 429 * @param string error message (gets printf'ed with $min and $max) 430 * @param boolean Is the param required? 431 * @return boolean true if OK 432 */ 433 function param_check_range( $var, $min, $max, $err_msg, $required = true ) 434 { 435 if( empty( $GLOBALS[$var] ) && ! $required ) 436 { // empty is OK: 437 return true; 438 } 439 440 if( ! preg_match( '~^[-+]?\d+$~', $GLOBALS[$var] ) || $GLOBALS[$var] < $min || $GLOBALS[$var] > $max ) 441 { 442 param_error( $var, sprintf( $err_msg, $min, $max ) ); 443 return false; 444 } 445 return true; 446 } 447 448 449 /** 450 * @param string param name 451 * @return boolean true if OK 452 */ 453 function param_check_email( $var, $required = false ) 454 { 455 if( empty( $GLOBALS[$var] ) && ! $required ) 456 { // empty is OK: 457 return true; 458 } 459 460 if( !is_email( $GLOBALS[$var] ) ) 461 { 462 param_error( $var, T_('The email address is invalid.') ); 463 return false; 464 } 465 return true; 466 } 467 468 469 /** 470 * @param string param name 471 * @param string error message 472 * @return boolean true if OK 473 */ 474 function param_check_url( $var, & $uri_scheme ) 475 { 476 if( $error_detail = validate_url( $GLOBALS[$var], $uri_scheme ) ) 477 { 478 param_error( $var, sprintf( T_('Supplied URL is invalid. (%s)'), $error_detail ) ); 479 return false; 480 } 481 return true; 482 } 483 484 485 /** 486 * Check if the value is a file name 487 * 488 * @param string param name 489 * @param string error message 490 * @return boolean true if OK 491 */ 492 function param_check_filename( $var, $err_msg ) 493 { 494 if( $error_filename = validate_filename( $GLOBALS[$var] ) ) 495 { 496 param_error( $var, $error_filename ); 497 return false; 498 } 499 return true; 500 } 501 502 503 /** 504 * Check if the value of a param is a regular expression (syntax). 505 * 506 * @param string param name 507 * @param string error message 508 * @param string|NULL error message for form field ($err_msg gets used if === NULL). 509 * @return boolean true if OK 510 */ 511 function param_check_isregexp( $var, $err_msg, $field_err_msg = NULL ) 512 { 513 if( ! is_regexp( $GLOBALS[$var] ) ) 514 { 515 param_error( $var, $field_err_msg ); 516 return false; 517 } 518 return true; 519 } 520 521 522 /** 523 * Sets a date parameter by converting locale date (if valid) to ISO date. 524 * 525 * If the date is not valid, it is set to the param unchanged (unconverted). 526 * 527 * @param string param name 528 * @param string error message 529 * @param boolean Is a non-empty date required? 530 * @param string Default (in the format of $date_format) 531 * @param string|NULL date format (php format), defaults to {@link locale_datefmt()} 532 */ 533 function param_date( $var, $err_msg, $required, $default = '', $date_format = NULL ) 534 { 535 param( $var, 'string', $default ); 536 537 $iso_date = param_check_date( $var, $err_msg, $required, $date_format ); 538 539 if( $iso_date ) 540 { 541 set_param( $var, $iso_date ); 542 } 543 544 return $GLOBALS[$var]; 545 } 546 547 548 /** 549 * Check if param is an ISO date. 550 * 551 * NOTE: for tokens like e.g. "D" (abbr. weekday), T_() gets used and it uses the current locale! 552 * 553 * @param string param name 554 * @param string error message 555 * @param boolean Is a non-empty date required? 556 * @param string date format (php format) 557 * @return boolean|string false if not OK, ISO date if OK 558 */ 559 function param_check_date( $var, $err_msg, $required = false, $date_format = NULL ) 560 { 561 if( empty( $GLOBALS[$var] ) ) 562 { // empty is OK if not required: 563 if( $required ) 564 { 565 param_error( $var, $err_msg ); 566 return false; 567 } 568 return ''; 569 } 570 571 if( empty( $date_format ) ) 572 { // Use locale date format: 573 $date_format = locale_datefmt(); 574 } 575 576 // Convert PHP date format to regexp pattern: 577 $date_regexp = '~'.preg_replace_callback( '~(\\\)?(\w)~', create_function( '$m', ' 578 if( $m[1] == "\\\" ) return $m[2]; // escaped 579 switch( $m[2] ) 580 { 581 case "d": return "([0-3]\\d)"; // day, 01-31 582 case "j": return "([1-3]?\\d)"; // day, 1-31 583 case "l": return "(".str_replace("~", "\~", implode("|", array_map("trim", array_map("T_", $GLOBALS["weekday"])))).")"; 584 case "D": return "(".str_replace("~", "\~", implode("|", array_map("trim", array_map("T_", $GLOBALS["weekday_abbrev"])))).")"; 585 case "e": // b2evo extension! 586 return "(".str_replace("~", "\~", implode("|", array_map("trim", array_map("T_", $GLOBALS["weekday_letter"])))).")"; 587 case "S": return "(st|nd|rd|th)"; // english suffix for day 588 589 case "m": return "([0-1]\\d)"; // month, 01-12 590 case "n": return "(1?\\d)"; // month, 1-12 591 case "F": return "(".str_replace("~", "\~", implode("|", array_map("trim", array_map("T_", $GLOBALS["month"])))).")"; // A full textual representation of a month, such as January or March 592 case "M": return "(".str_replace("~", "\~", implode("|", array_map("trim", array_map("T_", $GLOBALS["month_abbrev"])))).")"; 593 594 case "y": return "(\\d\\d)"; // year, 00-99 595 case "Y": return "(\\d{4})"; // year, XXXX 596 default: 597 return $m[0]; 598 }' ), $date_format ).'~i'; // case-insensitive? 599 // Allow additional spaces, e.g. "03 May 2007" when format is "d F Y": 600 $date_regexp = preg_replace( '~ +~', '\s+', $date_regexp ); 601 // echo $date_format.'...'.$date_regexp; 602 603 // Check that the numbers match the date pattern: 604 if( preg_match( $date_regexp, $GLOBALS[$var], $numbers ) ) 605 { // Date does match pattern: 606 //pre_dump( $numbers ); 607 608 // Get all date pattern parts. We should get 3 parts!: 609 preg_match_all( '/(?<!\\\\)[A-Za-z]/', $date_format, $parts ); // "(?<!\\\\)" means that the letter is not escaped with "\" 610 //pre_dump( $parts ); 611 612 foreach( $parts[0] as $position => $part ) 613 { 614 switch( $part ) 615 { 616 case 'd': 617 case 'j': 618 $day = $numbers[$position+1]; 619 break; 620 621 case 'm': 622 case 'n': 623 $month = $numbers[$position+1]; 624 break; 625 case 'F': // full month name 626 $month = array_search( strtolower($numbers[$position+1]), array_map('strtolower', array_map('trim', array_map('T_', $GLOBALS['month']))) ); 627 break; 628 case 'M': 629 $month = array_search( strtolower($numbers[$position+1]), array_map('strtolower', array_map('trim', array_map('T_', $GLOBALS['month_abbrev']))) ); 630 break; 631 632 case 'y': 633 case 'Y': 634 $year = $numbers[$position+1]; 635 if( $year < 50 ) 636 { 637 $year = 2000 + $year; 638 } 639 elseif( $year < 100 ) 640 { 641 $year = 1900 + $year; 642 } 643 break; 644 } 645 } 646 647 if( checkdate( $month, $day, $year ) ) 648 { // all clean! :) 649 650 // We convert the value to ISO: 651 $iso_date = substr( '0'.$year, -4 ).'-'.substr( '0'.$month, -2 ).'-'.substr( '0'.$day, -2 ); 652 653 return $iso_date; 654 } 655 } 656 657 // Date did not pass all tests: 658 659 param_error( $var, $err_msg ); 660 661 return false; 662 } 663 664 665 /** 666 * Sets a date parameter with values from the request or to provided default, 667 * And check we have a compact date (numbers only) ( used for URL filtering ) 668 * 669 * @param string Variable to set 670 * @param mixed Default value or TRUE if user input required 671 * @param boolean memorize ( see {@link param()} ) 672 * @param string error message 673 * @param boolean 'required': Is non-empty date required? Default: true. 674 * 675 * @return string the compact date value ( yyyymmdd ) 676 */ 677 function param_compact_date( $var, $default = '', $memorize = false, $err_msg, $required = false ) 678 { 679 global $$var; 680 681 param( $var, 'string', $default, $memorize ); 682 683 if( preg_match( '#^[0-9]{4,}$#', $$var ) ) 684 { // Valid compact date, all good. 685 return $$var; 686 } 687 688 // We do not have a compact date, try normal date matching: 689 $iso_date = param_check_date( $var, $err_msg, $required ); 690 691 if( $iso_date ) 692 { 693 set_param( $var, compact_date( $iso_date ) ); 694 return $$var; 695 } 696 697 // Nothing valid found.... 698 return ''; 699 } 700 701 702 /** 703 * Sets a time parameter with the value from the request of the var argument 704 * or of the concat of the var argument_h: var argument_mn: var argument_s , 705 * except if param is already set! 706 * 707 * @param string Variable to set 708 * @param mixed Default value or TRUE if user input required 709 * @param boolean Do we need to memorize this to regenerate the URL for this page? 710 * @param boolean Override if variable already set 711 * @param boolean Force setting of variable to default? 712 * @return mixed Final value of Variable, or false if we don't force setting and did not set 713 */ 714 function param_time( $var, $default = '', $memorize = false, $override = false, $forceset = true ) 715 { 716 global $$var; 717 718 $got_time = false; 719 720 if( param( $var, 'string', $default, $memorize, $override, $forceset ) ) 721 { // Got a time from text field: 722 if( preg_match( '/^(\d\d):(\d\d)(:(\d\d))?$/', $$var, $matches ) ) 723 { 724 $time_h = $matches[1]; 725 $time_mn = $matches[2]; 726 $time_s = empty( $matches[4] ) ? 0 : $matches[4]; 727 $got_time = true; 728 } 729 } 730 elseif( ( $time_h = param( $var.'_h', 'integer', -1 ) ) != -1 731 && ( $time_mn = param( $var.'_mn', 'integer', -1 ) ) != -1 ) 732 { // Got a time from selects: 733 $time_s = param( $var.'_s', 'integer', 0 ); 734 $$var = substr('0'.$time_h,-2).':'.substr('0'.$time_mn,-2).':'.substr('0'.$time_s,-2); 735 $got_time = true; 736 } 737 738 if( $got_time ) 739 { // We got a time... 740 // Check if ranges are correct: 741 if( $time_h >= 0 && $time_h <= 23 742 && $time_mn >= 0 && $time_mn <= 59 743 && $time_s >= 0 && $time_s <= 59 ) 744 { 745 // Time is correct 746 return $$var; 747 } 748 } 749 750 param_error( $var, T_('Please enter a valid time.') ); 751 752 return false; 753 } 754 755 756 /** 757 * Extend a LIST parameter with an ARRAY param. 758 * 759 * Will be used for author/authorsel[], etc. 760 * Note: cannot be used for catsel[], because catsel is NON-recursive. 761 * @see param_compile_cat_array() 762 * 763 * @param string Variable to extend 764 * @param string Name of array Variable to use as an extension 765 * @param boolean Save non numeric prefix? ( 1 char -- can be used as a modifier, e-g: - + * ) 766 */ 767 function param_extend_list( $var, $var_ext_array, $save_prefix = true ) 768 { 769 // Make sure original var exists: 770 if( !isset($GLOBALS[$var]) ) 771 { 772 debug_die( 'Cannot extend non existing param : '.$var ); 773 } 774 $original_val = $GLOBALS[$var]; 775 776 // Get extension array: 777 $ext_values_array = param( $var_ext_array, 'array', array(), false ); 778 if( empty($ext_values_array) ) 779 { // No extension required: 780 return $original_val; 781 } 782 783 // Handle prefix: 784 $prefix = ''; 785 if( $save_prefix ) 786 { // We might want to save a prefix: 787 $prefix = substr( $original_val, 0, 1 ); 788 if( is_numeric( $prefix ) ) 789 { // The prefix is numeric, so it's NOT a prefix 790 $prefix = ''; 791 } 792 else 793 { // We save the prefix, we must crop if off from the values: 794 $original_val = substr( $original_val, 1 ); 795 } 796 } 797 798 // Merge values: 799 if( empty($original_val) ) 800 { 801 $original_values_array = array(); 802 } 803 else 804 { 805 $original_values_array = explode( ',', $original_val ); 806 } 807 $new_values = array_merge( $original_values_array, $ext_values_array ); 808 $new_values = array_unique( $new_values ); 809 $GLOBALS[$var] = $prefix.implode( ',', $new_values ); 810 811 812 return $GLOBALS[$var]; 813 } 814 815 816 /** 817 * Compiles the cat array from $cat (recursive + optional modifiers) and $catsel[] (non recursive) 818 * and keeps those values available for future reference (category widget) 819 */ 820 function param_compile_cat_array( $restrict_to_blog = 0, $cat_default = NULL, $catsel_default = array() ) 821 { 822 // For now, we'll need those as globals! 823 // fp> this is used for the categories widget 824 // fp> we want might to use a $set_globals params to compile_cat_array() 825 global $cat_array, $cat_modifier; 826 827 $cat = param( 'cat', '/^[*\-]?([0-9]+(,[0-9]+)*)?$/', $cat_default, true ); // List of cats to restrict to 828 $catsel = param( 'catsel', 'array', $catsel_default, true ); // Array of cats to restrict to 829 830 $cat_array = array(); 831 $cat_modifier = ''; 832 833 compile_cat_array( $cat, $catsel, /* by ref */ $cat_array, /* by ref */ $cat_modifier, $restrict_to_blog ); 834 } 835 836 837 /** 838 * @param array of param names 839 * @param string error message 840 * @param string|NULL error message for form field ($err_msg gets used if === NULL). 841 * @return boolean true if OK 842 */ 843 function params_check_at_least_one( $vars, $err_msg, $field_err_msg = NULL ) 844 { 845 foreach( $vars as $var ) 846 { 847 if( !empty( $GLOBALS[$var] ) ) 848 { // Okay, we got at least one: 849 return true; 850 } 851 } 852 853 // Error! 854 param_error_multiple( $vars, $err_msg, $field_err_msg ); 855 return false; 856 } 857 858 859 /** 860 * Sets a combo parameter with values from the request, 861 * => the value of the select option and the input text value if new is selected 862 * Display an error if the new value is selected that the input text has a value 863 * 864 * @param string Variable to set 865 * @param mixed Default value or TRUE if user input required 866 * @param boolean true: allows to select new without entring a value in the input combo text 867 * @param string error message 868 * 869 * @return string position status ID or 'new' or '' if new is seleted but not input text value 870 * 871 */ 872 function param_combo( $var, $default, $allow_none, $err_msg = '' ) 873 { 874 param( $var, 'string', $default ); 875 876 if( $GLOBALS[$var] == 'new' ) 877 { // The new option is selected in the combo select, so we need to check if we have a value in the combo input text: 878 $GLOBALS[$var.'_combo'] = param( $var.'_combo', 'string' ); 879 880 if( empty( $GLOBALS[$var.'_combo'] ) ) 881 { // We have no value in the combo input text 882 883 // Set request param to null 884 $GLOBALS[$var] = NULL; 885 886 if( !$allow_none ) 887 { // it's not allowed, so display error: 888 param_error( $var, $err_msg ); 889 } 890 } 891 } 892 893 return $GLOBALS[$var]; 894 } 895 896 897 /** 898 * set a parameter with the second part(X2) of the value from request ( X1-X2 ) 899 * 900 * @param string Variable to set 901 * 902 */ 903 function param_child_select_value( $var ) 904 { 905 global $$var; 906 907 if( $val = param( $var, 'string' ) ) 908 { // keep only the second part of val 909 preg_match( '/^[0-9]+-([0-9]+)$/', $val, $res ); 910 911 if( isset( $res[1] ) ) 912 { //set to the var the second part of val 913 $$var = $res[1]; 914 return $$var; 915 } 916 } 917 return ''; 918 } 919 920 921 /** 922 * @param string param name 923 * @return boolean true if OK 924 */ 925 function param_check_phone( $var, $required = false ) 926 { 927 global $$var; 928 929 if( empty( $$var ) && ! $required ) 930 { // empty is OK: 931 return true; 932 } 933 934 if( ! preg_match( '|^\+?[\-*#/(). 0-9]+$|', $$var ) ) 935 { 936 param_error( $var, T_('The phone number is invalid.') ); 937 return false; 938 } 939 else 940 { // Keep only 0123456789+ caracters 941 $$var = preg_replace( '#[^0-9+]#', '', $$var ); 942 } 943 return true; 944 } 945 946 947 /** 948 * @param string param name 949 * @param string param name 950 * @param boolean Is a password required? (non-empty) 951 * @return boolean true if OK 952 */ 953 function param_check_passwords( $var1, $var2, $required = false ) 954 { 955 global $Settings; 956 957 $pass1 = $GLOBALS[$var1]; 958 $pass2 = $GLOBALS[$var2]; 959 960 if( empty($pass1) && empty($pass2) && ! $required ) 961 { // empty is OK: 962 return true; 963 } 964 965 if( empty($pass1) ) 966 { 967 param_error( $var1, T_('Please enter your password twice.') ); 968 return false; 969 } 970 if( empty($pass2) ) 971 { 972 param_error( $var2, T_('Please enter your password twice.') ); 973 return false; 974 } 975 976 // checking the password has been typed twice the same: 977 if( $pass1 != $pass2 ) 978 { 979 param_error_multiple( array( $var1, $var2), T_('You typed two different passwords.') ); 980 return false; 981 } 982 983 if( strlen($pass1) < $Settings->get('user_minpwdlen') ) 984 { 985 param_error_multiple( array( $var1, $var2), sprintf( T_('The minimum password length is %d characters.'), $Settings->get('user_minpwdlen') ) ); 986 return false; 987 } 988 989 return true; 990 } 991 992 993 /** 994 * Check if there have been validation errors 995 * 996 * We play it safe here and check for all kind of errors, not just those from this particular class. 997 * 998 * @return integer 999 */ 1000 function param_errors_detected() 1001 { 1002 global $Messages; 1003 1004 return $Messages->count('error'); 1005 } 1006 1007 1008 /** 1009 * Tell if there is an error on given field. 1010 */ 1011 function param_has_error( $var ) 1012 { 1013 global $param_input_err_messages; 1014 1015 return isset( $param_input_err_messages[$var] ); 1016 } 1017 1018 1019 /** 1020 * Get error message for a param 1021 * 1022 * @return string 1023 */ 1024 function param_get_error_msg( $var ) 1025 { 1026 global $param_input_err_messages; 1027 1028 if( empty( $param_input_err_messages[$var] ) ) 1029 { 1030 return ''; 1031 } 1032 1033 return $param_input_err_messages[$var]; 1034 } 1035 1036 1037 /** 1038 * Add an error for a variable, either to the Form's field and/or the global {@link $Messages} object. 1039 * 1040 * @param string param name 1041 * @param string|NULL error message (by using NULL you can only add an error to the field, but not the $Message object) 1042 * @param string|NULL error message for form field ($err_msg gets used if === NULL). 1043 */ 1044 function param_error( $var, $err_msg, $field_err_msg = NULL ) 1045 { 1046 global $param_input_err_messages; 1047 1048 if( ! isset( $param_input_err_messages[$var] ) ) 1049 { // We haven't already recorded an error for this field: 1050 if( $field_err_msg === NULL ) 1051 { 1052 $field_err_msg = $err_msg; 1053 } 1054 $param_input_err_messages[$var] = $field_err_msg; 1055 1056 if( isset($err_msg) ) 1057 { 1058 param_add_message_to_Log( $var, $err_msg, 'error' ); 1059 } 1060 } 1061 } 1062 1063 1064 /** 1065 * Add an error for multiple variables, either to the Form's field and/or the global {@link $Messages} object. 1066 * 1067 * @param array of param names 1068 * @param string|NULL error message (by using NULL you can only add an error to the field, but not the $Message object) 1069 * @param string|NULL error message for form fields ($err_msg gets used if === NULL). 1070 */ 1071 function param_error_multiple( $vars, $err_msg, $field_err_msg = NULL ) 1072 { 1073 global $param_input_err_messages; 1074 1075 if( $field_err_msg === NULL ) 1076 { 1077 $field_err_msg = $err_msg; 1078 } 1079 1080 foreach( $vars as $var ) 1081 { 1082 if( ! isset( $param_input_err_messages[$var] ) ) 1083 { // We haven't already recorded an error for this field: 1084 $param_input_err_messages[$var] = $field_err_msg; 1085 } 1086 } 1087 1088 if( isset($err_msg) ) 1089 { 1090 param_add_message_to_Log( $var, $err_msg, 'error' ); 1091 } 1092 } 1093 1094 1095 /** 1096 * This function is used by {@link param_error()} and {@link param_error_multiple()}. 1097 * 1098 * If {@link $link_param_err_messages_to_field_IDs} is true, it will link those parts of the 1099 * error message that are not already links, to the html IDs of the fields with errors. 1100 * 1101 * @param string param name 1102 * @param string error message 1103 */ 1104 function param_add_message_to_Log( $var, $err_msg, $log_category = 'error' ) 1105 { 1106 global $link_param_err_messages_to_field_IDs; 1107 global $Messages; 1108 1109 if( !empty($link_param_err_messages_to_field_IDs) ) 1110 { 1111 $var_id = Form::get_valid_id($var); 1112 $start_link = '<a href="#'.$var_id.'" onclick="var form_elem = document.getElementById(\''.$var_id.'\'); if( form_elem ) { if(form_elem.select) { form_elem.select(); } else if(form_elem.focus) { form_elem.focus(); } }">'; // "SELECT" does not have .select() 1113 1114 if( strpos( $err_msg, '<a' ) !== false ) 1115 { // there is at least one link in $err_msg, link those parts that are no links 1116 $err_msg = preg_replace( '~(\s*)(<a\s+[^>]+>[^<]*</a>\s*)~i', '</a>$1»$2'.$start_link, $err_msg ); 1117 } 1118 1119 if( substr($err_msg, 0, 4) == '</a>' ) 1120 { // There was a link at the beginning of $err_msg: we do not prepend an emtpy link before it 1121 $Messages->add( substr( $err_msg, 4 ).'</a>', $log_category ); 1122 } 1123 else 1124 { 1125 $Messages->add( $start_link.$err_msg.'</a>', $log_category ); 1126 } 1127 } 1128 else 1129 { 1130 $Messages->add( $err_msg, $log_category ); 1131 } 1132 } 1133 1134 1135 1136 /** 1137 * Set a param (global) & Memorize it for automatic future use in regenerate_url() 1138 * 1139 * @param string Variable to memorize 1140 * @param string Type of the variable 1141 * @param mixed Default value to compare to when regenerating url 1142 * @param mixed Value to set 1143 */ 1144 function memorize_param( $var, $type, $default, $value = NULL ) 1145 { 1146 global $Debuglog, $global_param_list, $$var; 1147 1148 if( !isset($global_param_list) ) 1149 { // Init list if necessary: 1150 if( isset($Debuglog) ) $Debuglog->add( 'init $global_param_list', 'params' ); 1151 $global_param_list = array(); 1152 } 1153 1154 $Debuglog->add( "memorize_param: $var $type default=$default" 1155 .(is_null($value) ? '' : " value=$value"), 'params'); 1156 1157 $global_param_list[$var] = array( 'type' => $type, 'default' => (($default===true) ? NULL : $default) ); 1158 1159 if( !is_null( $value ) ) 1160 { // We want to set the variable too. 1161 set_param( $var, $value ); 1162 } 1163 } 1164 1165 1166 /** 1167 * Forget a param so that is will not get included in subsequent {@link regenerate_url()} calls. 1168 * @param string Param name 1169 */ 1170 function forget_param( $var ) 1171 { 1172 global $Debuglog, $global_param_list; 1173 1174 $Debuglog->add( 'forget_param('.$var.')', 'params' ); 1175 1176 unset( $global_param_list[$var] ); 1177 } 1178 1179 1180 /** 1181 * Has the param already been memorized? 1182 */ 1183 function param_ismemorized( $var ) 1184 { 1185 global $global_param_list; 1186 1187 return isset($global_param_list[$var]); 1188 } 1189 1190 1191 /** 1192 * Set the value of a param (by force! :P) 1193 * 1194 * Same as setting a global, except you don't need a global declaration in your function. 1195 */ 1196 function set_param( $var, $value ) 1197 { 1198 $GLOBALS[$var] = $value; 1199 } 1200 1201 1202 1203 /** 1204 * Get the value of a param. 1205 * 1206 * @return NULL|mixed The value of the param, if set. NULL otherwise. 1207 */ 1208 function get_param( $var ) 1209 { 1210 if( ! isset($GLOBALS[$var]) ) 1211 { 1212 return NULL; 1213 } 1214 1215 return $GLOBALS[$var]; 1216 } 1217 1218 1219 /** 1220 * Construct an array of memorized params which are not in the ignore list 1221 * 1222 * @param mixed string or array of ignore params 1223 */ 1224 function get_memorized( $ignore = '' ) 1225 { 1226 global $global_param_list; 1227 1228 $memo = array(); 1229 1230 // Transform ignore params into an array: 1231 if( empty ( $ignore ) ) 1232 { 1233 $ignore = array(); 1234 } 1235 elseif( !is_array($ignore) ) 1236 { 1237 $ignore = explode( ',', $ignore ); 1238 } 1239 1240 // Loop on memorize params 1241 if( isset($global_param_list) ) 1242 { 1243 foreach( $global_param_list as $var => $thisparam ) 1244 { 1245 if( !in_array( $var, $ignore ) ) 1246 { 1247 global $$var; 1248 $value = $$var; 1249 $memo[$var] = $$var; 1250 } 1251 } 1252 } 1253 return $memo; 1254 } 1255 1256 1257 /** 1258 * Regenerate current URL from parameters 1259 * This may clean it up 1260 * But it is also useful when generating static pages: you cannot rely on $_REQUEST[] 1261 * 1262 * @param mixed|string (delimited by commas) or array of params to ignore (can be regexps in /.../) 1263 * @param array|string Param(s) to set 1264 * @param mixed|string Alternative URL we want to point to if not the current URL (may be absolute if BASE tag gets used) 1265 * @param string Delimiter to use for multiple params (typically '&' or '&') 1266 */ 1267 function regenerate_url( $ignore = '', $set = '', $pagefileurl = '', $glue = '&' ) 1268 { 1269 global $Debuglog, $global_param_list, $ReqHost, $ReqPath; 1270 global $base_tag_set; 1271 1272 // Transform ignore param into an array: 1273 if( empty($ignore) ) 1274 { 1275 $ignore = array(); 1276 } 1277 elseif( !is_array($ignore) ) 1278 { 1279 $ignore = explode( ',', $ignore ); 1280 } 1281 1282 // Construct array of all params that have been memorized: 1283 // (Note: we only include values if they differ from the default and they are not in the ignore list) 1284 $params = array(); 1285 if( isset($global_param_list) ) foreach( $global_param_list as $var => $thisparam ) 1286 { // For each saved param... 1287 $type = $thisparam['type']; 1288 $defval = $thisparam['default']; 1289 1290 // Check if the param should to be ignored: 1291 $skip = false; 1292 foreach( $ignore as $ignore_pattern ) 1293 { 1294 if( $ignore_pattern[0] == '/' ) 1295 { // regexp: 1296 if( preg_match( $ignore_pattern, $var ) ) 1297 { // Skip this param! 1298 $skip = true; 1299 break; 1300 } 1301 } 1302 else 1303 { 1304 if( $var == $ignore_pattern ) 1305 { // Skip this param! 1306 $skip = true; 1307 break; 1308 } 1309 } 1310 } 1311 if( $skip ) 1312 { // we don't want to include that param 1313 // if( isset($Debuglog) ) $Debuglog->add( 'regenerate_url(): EXPLICIT IGNORE '.$var, 'params' ); 1314 continue; 1315 } 1316 1317 $value = $GLOBALS[$var]; 1318 if( $value != $defval ) 1319 { // Value is not set to default value: 1320 // Note: sometimes we will want to include an empty value, especially blog=0 ! In that case we set the default for blog to -1. 1321 // echo "adding $var \n"; 1322 // if( isset($Debuglog) ) $Debuglog->add( "regenerate_url(): Using var=$var, type=$type, defval=[$defval], val=[$value]", 'params' ); 1323 1324 if( $type === 'array' ) 1325 { // there is a special formatting in case of arrays 1326 $url_array = array(); 1327 foreach( $value as $value ) 1328 { 1329 $params[] = $var.'%5B%5D='.rawurlencode($value); 1330 } 1331 } 1332 else 1333 { // not an array : normal formatting 1334 $params[] = $var.'='.rawurlencode($value); 1335 } 1336 } 1337 else 1338 { 1339 // if( isset($Debuglog) ) $Debuglog->add( "regenerate_url(): DEFAULT ignore var=$var, type=$type, defval=[$defval], val=[$value]", 'params' ); 1340 } 1341 } 1342 1343 // Merge in the params we want to force to a specific value: 1344 if( !empty( $set ) ) 1345 { // We got some forced params: 1346 // Transform set param into an array: 1347 if( !is_array($set) ) 1348 { 1349 $set = array( $set ); 1350 } 1351 // Merge them in: 1352 $params = array_merge( $params, $set ); 1353 } 1354 1355 // Construct URL: 1356 if( ! empty($pagefileurl) ) 1357 { 1358 $url = $pagefileurl; 1359 } 1360 else 1361 { 1362 if( ! empty($base_tag_set) ) 1363 { 1364 if( isset($Debuglog) ) $Debuglog->add( 'regenerate_url(): Using full URL because of $base_tag_set.', 'params' ); 1365 $url = $ReqHost.$ReqPath; 1366 } 1367 else 1368 { // Use just absolute path, because there's no <base> tag used 1369 $url = $ReqPath; 1370 } 1371 } 1372 1373 if( !empty( $params ) ) 1374 { 1375 $url = url_add_param( $url, implode( $glue, $params ), $glue ); 1376 } 1377 // if( isset($Debuglog) ) $Debuglog->add( 'regenerate_url(): ['.$url.']', 'params' ); 1378 return $url; 1379 } 1380 1381 1382 /** 1383 * Add param(s) at the end of an URL, using either "?" or "&" depending on existing url 1384 * 1385 * @param string existing url 1386 * @param string params to add 1387 * @param string delimiter to use for more params 1388 */ 1389 function url_add_param( $url, $param, $glue = '&' ) 1390 { 1391 if( empty($param) ) 1392 { 1393 return $url; 1394 } 1395 1396 if( ($anchor_pos = strpos($url, '#')) !== false ) 1397 { // There's an "#anchor" in the URL 1398 $anchor = substr($url, $anchor_pos); 1399 $url = substr($url, 0, $anchor_pos); 1400 } 1401 else 1402 { // URL without "#anchor" 1403 $anchor = ''; 1404 } 1405 1406 if( strpos( $url, '?' ) !== false ) 1407 { // There are already params in the URL 1408 return $url.$glue.$param.$anchor; 1409 } 1410 1411 1412 // These are the first params 1413 return $url.'?'.$param.$anchor; 1414 } 1415 1416 1417 /** 1418 * Add a tail (starting with "/") at the end of an URL before any params (starting with "?") 1419 * 1420 * @param string existing url 1421 * @param string tail to add 1422 */ 1423 function url_add_tail( $url, $tail ) 1424 { 1425 $parts = explode( '?', $url ); 1426 if( substr($parts[0], -1) == '/' ) 1427 { 1428 $parts[0] = substr($parts[0], 0, -1); 1429 } 1430 if( isset($parts[1]) ) 1431 { 1432 return $parts[0].$tail.'?'.$parts[1]; 1433 } 1434 1435 return $parts[0].$tail; 1436 } 1437 1438 1439 /** 1440 * Check the validity of a given URL 1441 * 1442 * Checks allowed URI schemes and URL ban list. 1443 * URL can be empty. 1444 * 1445 * Note: We have a problem when trying to "antispam" a keyword which is already blacklisted 1446 * If that keyword appears in the URL... then the next page has a bad referer! :/ 1447 * 1448 * {@internal This function gets tested in misc.funcs.simpletest.php.}} 1449 * 1450 * @param string Url to validate 1451 * @param array Allowed URI schemes (see /conf/_formatting.php) 1452 * @param boolean Must the URL be absolute? 1453 * @param boolean Return verbose error message? (Should get only used in the backoffice) 1454 * @return mixed false (which means OK) or error message 1455 */ 1456 function validate_url( $url, & $allowed_uri_scheme, $absolute = false, $verbose = false ) 1457 { 1458 global $Debuglog; 1459 1460 if( empty($url) ) 1461 { // Empty URL, no problem 1462 return false; 1463 } 1464 1465 // Validate URL structure 1466 // fp> NOTE: I made this much more laxist than it used to be. 1467 // fp> If it turns out I blocked something that was previously allowed, it's a mistake. 1468 // 1469 if( preg_match( '~^\w+:~', $url ) ) 1470 { // there's a scheme and therefor an absolute URL: 1471 if( substr($url, 0, 6) == 'mailto' ) 1472 { // mailto:link 1473 preg_match( '~^(mailto):(.*?)(\?.*)?$~', $url, $match ); 1474 if( ! $match ) 1475 { 1476 return $verbose 1477 ? sprintf( T_('Invalid email link: %s.'), htmlspecialchars($url) ) 1478 : T_('Invalid email link.'); 1479 } 1480 elseif( ! is_email($match[2]) ) 1481 { 1482 return $verbose 1483 ? sprintf( T_('Supplied email address (%s) is invalid.'), htmlspecialchars($match[2]) ) 1484 : T_('Invalid email address.'); 1485 } 1486 } 1487 elseif( ! preg_match('~^ # start 1488 ([a-z][a-z0-9+.\-]*) # scheme 1489 :// # authorize absolute URLs only ( // not present in clsid: -- problem? ; mailto: handled above) 1490 (\w+(:\w+)?@)? # username or username and password (optional) 1491 [a-z0-9]([a-z0-9\-])+ # Don t allow anything too funky like entities 1492 \. # require at least 1 dot 1493 [a-z0-9]([a-z0-9.\-])+ # Don t allow anything too funky like entities 1494 (:[0-9]+)? # optional port specification 1495 ~ix', $url, $match) ) 1496 { // Cannot validate URL structure 1497 $Debuglog->add( 'URL «'.$url.'» does not match url pattern!', 'error' ); 1498 return $verbose 1499 ? sprintf( T_('Invalid URL format (%s).'), htmlspecialchars($url) ) 1500 : T_('Invalid URL format.'); 1501 } 1502 1503 $scheme = strtolower($match[1]); 1504 if( !in_array( $scheme, $allowed_uri_scheme ) ) 1505 { // Scheme not allowed 1506 $Debuglog->add( 'URI scheme «'.$scheme.'» not allowed!', 'error' ); 1507 return $verbose 1508 ? sprintf( T_('URI scheme "%s" not allowed.'), htmlspecialchars($scheme) ) 1509 : T_('URI scheme not allowed.'); 1510 } 1511 1512 // Search for blocked URLs: 1513 if( $block = antispam_check($url) ) 1514 { 1515 return $verbose 1516 ? sprintf( T_('URL "%s" not allowed: blacklisted word "%s".'), htmlspecialchars($url), $block ) 1517 : T_('URL not allowed'); 1518 } 1519 } 1520 else 1521 { // URL is relative.. 1522 if( $absolute ) 1523 { 1524 return $verbose ? sprintf( T_('URL "%s" must be absolute.'), htmlspecialchars($url) ) : T_('URL must be absolute.'); 1525 } 1526 1527 $char = substr($url, 0, 1); 1528 if( $char != '/' && $char != '#' ) 1529 { // must start with a slash or hash (for HTML anchors to the same page) 1530 return $verbose 1531 ? sprintf( T_('URL "%s" must be a full path starting with "/" or an anchor starting with "#".'), htmlspecialchars($url) ) 1532 : T_('URL must be a full path starting with "/" or an anchor starting with "#".'); 1533 } 1534 } 1535 1536 return false; // OK 1537 } 1538 1539 1540 /** 1541 * Checks if a given regular expression is valid. 1542 * 1543 * It changes the error_handler and restores it. 1544 * 1545 * @author plenque at hotmail dot com {@link http://php.net/manual/en/function.preg-match.php} 1546 * @param string the regular expression to test 1547 * @param boolean does the regular expression includes delimiters (and optionally modifiers)? 1548 * @return boolean 1549 */ 1550 function is_regexp( $reg_exp, $includes_delim = false ) 1551 { 1552 $sPREVIOUSHANDLER = set_error_handler( '_trapError' ); 1553 if( ! $includes_delim ) 1554 { 1555 $reg_exp = '#'.str_replace( '#', '\#', $reg_exp ).'#'; 1556 } 1557 preg_match( $reg_exp, '' ); 1558 restore_error_handler( $sPREVIOUSHANDLER ); 1559 1560 return !_traperror(); 1561 } 1562 1563 1564 /** 1565 * Meant to replace error handler temporarily. 1566 * 1567 * @return integer number of errors 1568 */ 1569 function _trapError( $reset = 1 ) 1570 { 1571 static $iERRORES; 1572 1573 if( !func_num_args() ) 1574 { 1575 $iRETORNO = $iERRORES; 1576 $iERRORES = 0; 1577 return $iRETORNO; 1578 } 1579 else 1580 { 1581 $iERRORES++; 1582 } 1583 } 1584 1585 1586 /* 1587 * Clean up the mess PHP has created with its funky quoting everything! 1588 */ 1589 if( get_magic_quotes_gpc() ) 1590 { // That stupid PHP behaviour consisting of adding slashes everywhere is unfortunately on 1591 1592 if( in_array( strtolower(ini_get('magic_quotes_sybase')), array('on', '1', 'true', 'yes') ) ) 1593 { // overrides "magic_quotes_gpc" and only replaces single quotes with themselves ( "'" => "''" ) 1594 /** 1595 * @ignore 1596 */ 1597 function remove_magic_quotes( $mixed ) 1598 { 1599 if( is_array( $mixed ) ) 1600 { 1601 foreach($mixed as $k => $v) 1602 { 1603 $mixed[$k] = remove_magic_quotes( $v ); 1604 } 1605 } 1606 elseif( is_string($mixed) ) 1607 { 1608 // echo 'Removing slashes '; 1609 $mixed = str_replace( '\'\'', '\'', $mixed ); 1610 } 1611 return $mixed; 1612 } 1613 } 1614 else 1615 { 1616 /** 1617 * Remove quotes from input. 1618 * This handles magic_quotes_gpc and magic_quotes_sybase PHP settings/variants. 1619 * 1620 * NOTE: you should not use it directly, but one of the param-functions! 1621 * 1622 * @param mixed string or array (function is recursive) 1623 * @return mixed Value, with magic quotes removed 1624 */ 1625 function remove_magic_quotes( $mixed ) 1626 { 1627 if( is_array( $mixed ) ) 1628 { 1629 foreach($mixed as $k => $v) 1630 { 1631 $mixed[$k] = remove_magic_quotes( $v ); 1632 } 1633 } 1634 elseif( is_string($mixed) ) 1635 { 1636 // echo 'Removing slashes '; 1637 $mixed = stripslashes( $mixed ); 1638 } 1639 return $mixed; 1640 } 1641 } 1642 } 1643 else 1644 { 1645 /** 1646 * @ignore 1647 */ 1648 function remove_magic_quotes( $mixed ) 1649 { 1650 return $mixed; 1651 } 1652 } 1653 1654 1655 /* 1656 * $Log: _param.funcs.php,v $ 1657 * Revision 1.5 2007/11/01 19:52:46 fplanque 1658 * better comment forms 1659 * 1660 * Revision 1.4 2007/09/22 19:23:56 fplanque 1661 * various fixes & enhancements 1662 * 1663 * Revision 1.3 2007/09/04 19:48:33 fplanque 1664 * small fixes 1665 * 1666 * Revision 1.2 2007/06/29 00:24:43 fplanque 1667 * $cat_array cleanup tentative 1668 * 1669 * Revision 1.1 2007/06/25 10:58:53 fplanque 1670 * MODULES (refactored MVC) 1671 * 1672 * Revision 1.40 2007/06/17 23:39:59 blueyed 1673 * Fixed remove_magic_quotes() 1674 * 1675 * Revision 1.39 2007/05/28 01:33:22 fplanque 1676 * permissions/fixes 1677 * 1678 * Revision 1.38 2007/05/20 01:02:32 fplanque 1679 * magic quotes fix 1680 * 1681 * Revision 1.37 2007/05/13 18:36:52 blueyed 1682 * param_check_date(): Allow multiple whitespaces 1683 * 1684 * Revision 1.36 2007/05/09 00:54:44 fplanque 1685 * Attempt to normalize all URLs before adding params 1686 * 1687 * Revision 1.35 2007/04/26 00:11:08 fplanque 1688 * (c) 2007 1689 * 1690 * Revision 1.34 2007/03/11 19:12:08 blueyed 1691 * Escape input in verbose validate_url() 1692 * 1693 * Revision 1.33 2007/03/02 01:36:51 fplanque 1694 * small fixes 1695 * 1696 * Revision 1.32 2007/02/28 23:33:19 blueyed 1697 * doc 1698 * 1699 * Revision 1.31 2007/02/26 03:41:16 fplanque 1700 * doc 1701 * 1702 * Revision 1.30 2007/02/25 18:29:55 blueyed 1703 * MFB: Support "S" (ordinal date suffix) in date format (calendar and validator) 1704 * 1705 * Revision 1.29 2007/02/12 17:59:52 blueyed 1706 * $verbose param for validate_url() - not used yet anywhere, but useful IMHO, e.g. in the backoffice. 1707 * 1708 * Revision 1.28 2007/01/26 00:21:23 blueyed 1709 * Fixed possible E_NOTICE; TODO 1710 * 1711 * Revision 1.27 2006/12/28 18:31:30 fplanque 1712 * prevent impersonating of blog in multiblog situation 1713 * 1714 * Revision 1.26 2006/12/22 00:25:48 blueyed 1715 * Added $absolute param to url_validate() 1716 * 1717 * Revision 1.25 2006/12/18 16:16:12 blueyed 1718 * Fixed E_NOTICE if we're expecting e.g. "integer" but receive "array" 1719 * 1720 * Revision 1.24 2006/11/27 21:10:23 fplanque 1721 * doc 1722 * 1723 * Revision 1.23 2006/11/26 23:33:10 blueyed 1724 * doc 1725 * 1726 * Revision 1.22 2006/11/26 02:30:39 fplanque 1727 * doc / todo 1728 * 1729 * Revision 1.21 2006/11/24 18:27:27 blueyed 1730 * Fixed link to b2evo CVS browsing interface in file docblocks 1731 * 1732 * Revision 1.20 2006/11/17 00:20:44 blueyed 1733 * doc 1734 * 1735 * Revision 1.19 2006/11/14 17:37:22 blueyed 1736 * doc 1737 * 1738 * Revision 1.18 2006/11/14 00:21:58 blueyed 1739 * debug info for "relative" urls in validate_url() 1740 * 1741 * Revision 1.17 2006/11/09 22:56:57 blueyed 1742 * todo 1743 * 1744 * Revision 1.16 2006/11/02 16:31:53 blueyed 1745 * MFB 1746 * 1747 * Revision 1.15 2006/10/26 09:28:58 blueyed 1748 * - Made param funcs independent from $Debuglog global 1749 * - Made url_add_param() respect anchors/fragments 1750 * 1751 * Revision 1.14 2006/10/23 21:16:00 blueyed 1752 * MFB: Fix for encoding in regenerate_url() 1753 * 1754 * Revision 1.13 2006/10/17 17:27:07 blueyed 1755 * Allow "#anchor" as valid URL 1756 * 1757 * Revision 1.12 2006/10/14 02:12:01 blueyed 1758 * Added url_absolute(), make_rel_links_abs() + Tests; Fixed validate_url() and allow relative URLs, which get converted to absolute ones in feeds. 1759 */ 1760 ?>
titre
Description
Corps
titre
Description
Corps
titre
Description
Corps
titre
Corps
Généré le : Thu Nov 29 23:58:50 2007 | par Balluche grâce à PHPXref 0.7 |
![]() |