[ Index ]
 

Code source de b2evolution 2.1.0-beta

Accédez au Source d'autres logiciels libres

Classes | Fonctions | Variables | Constantes | Tables

title

Body

[fermer]

/blogs/inc/_core/ -> _param.funcs.php (source)

   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 &laquo;%s&raquo; 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 &laquo;%s&raquo;!'), $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 &laquo;%s&raquo;!'), $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&raquo;$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 '&amp;' or '&')

1266   */
1267  function regenerate_url( $ignore = '', $set = '', $pagefileurl = '', $glue = '&amp;' )
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 "&amp;" 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 = '&amp;' )
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 &laquo;'.$url.'&raquo; 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 &laquo;'.$scheme.'&raquo; 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  ?>


Généré le : Thu Nov 29 23:58:50 2007 par Balluche grâce à PHPXref 0.7
  Clicky Web Analytics