b2evolution PHP Cross Reference Blogging Systems

Source: /inc/plugins/_plugin.funcs.php - 1126 lines - 31717 bytes - Summary - Text - Print

Description: Functions for Plugin handling. This file is part of the evoCore framework - {@link http://evocore.net/} See also {@link http://sourceforge.net/projects/evocms/}.

   1  <?php
   2  /**
   3   * Functions for Plugin handling.
   4   *
   5   * This file is part of the evoCore framework - {@link http://evocore.net/}
   6   * See also {@link http://sourceforge.net/projects/evocms/}.
   7   *
   8   * @copyright (c)2003-2014 by Francois Planque - {@link http://fplanque.com/}
   9   * Parts of this file are copyright (c)2004-2006 by Daniel HAHLER - {@link http://thequod.de/contact}.
  10   *
  11   * {@internal License choice
  12   * - If you have received this file as part of a package, please find the license.txt file in
  13   *   the same folder or the closest folder above for complete license terms.
  14   * - If you have received this file individually (e-g: from http://evocms.cvs.sourceforge.net/)
  15   *   then you must choose one of the following licenses before using the file:
  16   *   - GNU General Public License 2 (GPL) - http://www.opensource.org/licenses/gpl-license.php
  17   *   - Mozilla Public License 1.1 (MPL) - http://www.opensource.org/licenses/mozilla1.1.php
  18   * }}
  19   *
  20   * {@internal Open Source relicensing agreement:
  21   * Daniel HAHLER grants Francois PLANQUE the right to license
  22   * Daniel HAHLER's contributions to this file and the b2evolution project
  23   * under any OSI approved OSS license (http://www.opensource.org/licenses/).
  24   * }}
  25   *
  26   * @package evocore
  27   *
  28   * {@internal Below is a list of authors who have contributed to design/coding of this file: }}
  29   * @author fplanque: Francois PLANQUE
  30   * @author blueyed: Daniel HAHLER
  31   *
  32   * @version $Id: _plugin.funcs.php 6136 2014-03-08 07:59:48Z manuel $
  33   */
  34  if( !defined('EVO_MAIN_INIT') ) die( 'Please, do not access this page directly.' );
  35  
  36  
  37  /**
  38   * Recursive helper function to display a field of the plugin's settings (by manipulating a Form).
  39   *
  40   * Used for PluginSettings ("Edit plugin") and PluginUserSettings ("Edit user settings") as well as widgets.
  41   *
  42   * @todo dh> Allow to move setting sets up and down (order). Control goes into /inc/CONTROL/settings/plugins.php.
  43   * @todo NOTE: fp> I'm using this outside of Plugins; I'm not sure about proper factorization yet.
  44   *       This should probably be an extension of the Form class. Sth like "AutoForm" ;)
  45   *
  46   * @param string Settings path, e.g. 'locales[0]' or 'setting'
  47   * @param array Meta data for this setting.
  48   * @param Form (by reference)
  49   * @param string Settings type ('Settings' or 'UserSettings' or 'Widget' or 'Skin')
  50   * @param Plugin|Widget
  51   * @param mixed Target (User object for 'UserSettings')
  52   * @param mixed Value to really use (used for recursion into array type settings)
  53   */
  54  function autoform_display_field( $parname, $parmeta, & $Form, $set_type, $Obj, $set_target = NULL, $use_value = NULL )
  55  {
  56      global $debug;
  57      global $htsrv_url;
  58      static $has_array_type;
  59  
  60      if( ! empty($parmeta['no_edit']) )
  61      { // this setting is not editable
  62          return;
  63      }
  64  
  65      $params = array();
  66  
  67      if( $use_value === NULL )
  68      { // outermost level
  69          $has_array_type = false; // for adding a note about JS
  70          $outer_most = true;
  71      }
  72      else
  73      {
  74          $outer_most = false;
  75      }
  76  
  77      // Passthrough some attributes to elements:
  78      foreach( $parmeta as $k => $v )
  79      {
  80          if( in_array( $k, array( 'id', 'onchange', 'onclick', 'onfocus', 'onkeyup', 'onkeydown', 'onreset', 'onselect', 'cols', 'rows', 'maxlength' ) ) )
  81          {
  82              $params[$k] = $v;
  83          }
  84      }
  85      if( ! empty($parmeta['multiple']) )
  86      { // "multiple" attribute for "select" inputs:
  87          $params['multiple'] = 'multiple';
  88      }
  89  
  90      if( isset($parmeta['note']) )
  91      {
  92          $params['note'] = $parmeta['note'];
  93      }
  94  
  95      if( ! isset($parmeta['type']) || $parmeta['type'] == 'html_input' )
  96      {
  97          $parmeta['type'] = 'text';
  98      }
  99      elseif( $parmeta['type'] == 'html_textarea' )
 100      {
 101          $parmeta['type'] = 'textarea';
 102      }
 103  
 104      if( strpos($parmeta['type'], 'select_') === 0 )
 105      { // 'allow_none' setting for select_* types
 106          if( isset($parmeta['allow_none']) )
 107          {
 108              $params['allow_none'] = $parmeta['allow_none'];
 109          }
 110      }
 111  
 112      $help_icon = NULL;
 113      if( isset($parmeta['help']) )
 114      {
 115          if( $parmeta['help'] === true )
 116          { // link to $parname-target:
 117              $help_target = '#'.preg_replace( array('~\]?\[\d+\]\[~', '~\]$~'), array('_',''), $parname );
 118          }
 119          else
 120          {
 121              $help_target = $parmeta['help'];
 122          }
 123          $help_icon = $Obj->get_help_link( $help_target );
 124      }
 125  
 126      $set_label = isset($parmeta['label']) ? $parmeta['label'] : '';
 127  
 128      if( ! empty($parmeta['disabled']) )
 129      {
 130          $params['disabled'] = 'disabled';
 131      }
 132  
 133  
 134      // "Layout" settings:
 135      if( isset($parmeta['layout']) )
 136      {
 137          switch( $parmeta['layout'] )
 138          {
 139              case 'begin_fieldset':
 140                  $fieldset_title = $set_label;
 141                  $Form->begin_fieldset( $fieldset_title.$help_icon );
 142                  break;
 143  
 144              case 'end_fieldset':
 145                  $Form->end_fieldset();
 146                  break;
 147  
 148              case 'separator':
 149                  echo '<hr />';
 150                  break;
 151  
 152              case 'html': // Output HTML code here
 153                  if( ! isset($parmeta['value']) )
 154                  {
 155                      $parmeta['value'] = '<div class="error">HTML layout usage:<pre>'.
 156                              htmlentities("'layout' => 'html',\n'value' => '<em>My HTML code</em>',").'</pre></div>';
 157                  }
 158                  echo $parmeta['value'];
 159                  break;
 160          }
 161          return;
 162      }
 163  
 164      if( ! empty($help_icon) )
 165      { // Append help icon to note:
 166          if( empty($params['note']) )
 167          {
 168              $params['note'] = $help_icon;
 169          }
 170          else
 171          {
 172              $params['note'] .= ' '.$help_icon;
 173          }
 174      }
 175  
 176      if( isset($use_value) )
 177      {
 178          $set_value = $use_value;
 179      }
 180      else
 181      {
 182          switch( $set_type )
 183          {
 184              case 'CollSettings':
 185                  $set_value = $Obj->get_coll_setting( $parname, $set_target );
 186                  $error_value = NULL;
 187                  break;
 188  
 189              case 'Skin':
 190                  $set_value = $Obj->get_setting( $parname );
 191                  $error_value = NULL;
 192                  break;
 193  
 194              case 'Widget':
 195                  $set_value = $Obj->get_param( $parname );
 196                  $error_value = NULL;
 197                  break;
 198  
 199              case 'UserSettings':
 200                  // NOTE: this assumes we come here only on recursion or with $use_value set..!
 201                  $set_value = $Obj->UserSettings->get( $parname, $set_target->ID );
 202                  $error_value = $Obj->PluginUserSettingsValidateSet( $tmp_params = array(
 203                      'name' => $parname,
 204                      'value' => & $set_value,
 205                      'meta' => $parmeta,
 206                      'User' => $set_target,
 207                      'action' => 'display' ) );
 208                  break;
 209  
 210              case 'Settings':
 211                  // NOTE: this assumes we come here only on recursion or with $use_value set..!
 212                  $set_value = $Obj->Settings->get( $parname );
 213                  $error_value = $Obj->PluginSettingsValidateSet( $tmp_params = array(
 214                      'name' => $parname,
 215                      'value' => & $set_value,
 216                      'meta' => $parmeta,
 217                      'action' => 'display' ) );
 218                  break;
 219  
 220              default:
 221                  debug_die( "unhandled set_type $set_type" );
 222                  break;
 223          }
 224  
 225          if( $error_value )
 226          { // add error
 227              param_error( 'edit_plugin_'.$Obj->ID.'_set_'.$parname, NULL, $error_value ); // only add the error to the field
 228          }
 229      }
 230  
 231      // Display input element:
 232      $input_name = 'edit_plugin_'.$Obj->ID.'_set_'.$parname;
 233      if( substr($parmeta['type'], 0, 6) == 'select' && ! empty($parmeta['multiple']) )
 234      { // a "multiple" select:
 235          $input_name .= '[]';
 236      }
 237  
 238      // Get a value from _POST request to display it e.g. when some error was created during update
 239      $value_from_request = get_param( $input_name );
 240      if( $value_from_request !== NULL )
 241      {
 242          $set_value = $value_from_request;
 243      }
 244  
 245      switch( $parmeta['type'] )
 246      {
 247          case 'checkbox':
 248              $Form->checkbox_input( $input_name, $set_value, $set_label, $params );
 249              break;
 250  
 251          case 'textarea':
 252              $textarea_rows = isset($parmeta['rows']) ? $parmeta['rows'] : 3;
 253              $Form->textarea_input( $input_name, $set_value, $textarea_rows, $set_label, $params );
 254              break;
 255  
 256          case 'select':
 257              $params['force_keys_as_values'] = true; // so that numeric keys get used as values! autoform_validate_param_value() checks for the keys only.
 258              $Form->select_input_array( $input_name, $set_value, $parmeta['options'], $set_label, isset($parmeta['note']) ? $parmeta['note'] : NULL, $params );
 259              break;
 260  
 261          case 'select_blog':
 262              $BlogCache = & get_BlogCache();
 263              $Form->select_input_object( $input_name, $set_value, $BlogCache, $set_label, $params );
 264              break;
 265  
 266          case 'select_group':
 267              $GroupCache = & get_GroupCache();
 268              $Form->select_input_object( $input_name, $set_value, $GroupCache, $set_label, $params );
 269              break;
 270  
 271          case 'select_user':
 272              $UserCache = & get_UserCache();
 273              $UserCache->load_all();
 274              if( ! isset($params['loop_object_method']) )
 275              {
 276                  $params['loop_object_method'] = 'get_preferred_name';
 277              }
 278              $Form->select_input_object( $input_name, $set_value, $UserCache, $set_label, $params );
 279              break;
 280  
 281          case 'radio':
 282              if( ! isset($parmeta['field_lines']) )
 283              {
 284                  $parmeta['field_lines'] = false;
 285              }
 286              $Form->radio( $input_name, $set_value, $parmeta['options'], $set_label, $parmeta['field_lines'], $parmeta['note'] );
 287              break;
 288  
 289          case 'array':
 290              $has_array_type = true;
 291  
 292              // Always use 'fieldset' layout to display it the same way from normal and ajax calls
 293              $Form->switch_layout( 'fieldset' );
 294              if( substr_count( $parname, '[' ) % 2 )
 295              { // this refers to a specific array type set (with index pos at the end), e.g. when adding a field through AJAX:
 296                  $pos_last_bracket = strrpos($parname, '[');
 297                  $k_nb = substr( $parname, $pos_last_bracket+1, -1 );
 298                  $disp_arrays = array( '' => $set_value ); // empty key..
 299                  $parname = substr($parname, 0, $pos_last_bracket);
 300              }
 301              else
 302              { // display all values hold in this set:
 303                  $disp_whole_set = true;
 304                  $disp_arrays = $set_value;
 305                  $fieldset_title = $set_label;
 306                  if( $debug )
 307                  {
 308                      $fieldset_title .= ' [debug: '.$parname.']';
 309                  }
 310                  $Form->begin_fieldset( $fieldset_title );
 311  
 312                  if( ! empty($params['note']) )
 313                  {
 314                      echo '<p class="notes">'.$params['note'].'</p>';
 315                  }
 316                  $k_nb = 0;
 317              }
 318  
 319  
 320              $user_ID = $set_type == 'UserSettings' ? $set_target->ID : '';
 321              if( is_array( $set_value ) && ! empty($set_value) )
 322              { // Display value of the setting. It may be empty, if there's no set yet.
 323                  foreach( $disp_arrays as $k => $v )
 324                  {
 325                      $remove_action = '';
 326                      if( ! isset($parmeta['min_count']) || count($set_value) > $parmeta['min_count'] )
 327                      { // provide icon to remove this set
 328                          $remove_action = action_icon(
 329                                  T_('Delete set!'),
 330                                  'delete',
 331                                  regenerate_url( 'action', array('action=del_settings_set&amp;set_path='.$parname.'['.$k.']'.( $set_type == 'UserSettings' ? '&amp;user_ID='.$user_ID : '' ), 'plugin_ID='.$Obj->ID) ),
 332                                  '',
 333                                  5, 0, /* icon/text prio */
 334                                  // attach onclick event to remove the whole fieldset:
 335                                  array(
 336                                      'onclick' => "
 337                                          jQuery('#".$parname.'_'.$k_nb."').remove();
 338                                          return false;",
 339                                      )
 340                                  );
 341                      }
 342                      $Form->begin_fieldset( '#'.$k_nb.$remove_action, array( 'class' => 'bordered', 'id' => $parname.'_'.$k_nb ) );
 343  
 344                      if( isset($parmeta['key']) )
 345                      { // KEY FOR THIS ENTRY:
 346                          if( ! strlen($k) && isset($parmeta['key']['defaultvalue']) )
 347                          { // key is not given/set and we have a default:
 348                              $l_value = $parmeta['key']['defaultvalue'];
 349                          }
 350                          else
 351                          {
 352                              $l_value = $k;
 353                          }
 354                          // RECURSE:
 355                          autoform_display_field( $parname.'['.$k_nb.'][__key__]', $parmeta['key'], $Form, $set_type, $Obj, $set_target, $l_value );
 356                      }
 357  
 358                      foreach( $parmeta['entries'] as $l_set_name => $l_set_entry )
 359                      {
 360                          $l_value = isset($set_value[$k][$l_set_name]) ? $set_value[$k][$l_set_name] : NULL;
 361                          // RECURSE:
 362                          autoform_display_field( $parname.'['.$k_nb.']['.$l_set_name.']', $l_set_entry, $Form, $set_type, $Obj, $set_target, $l_value );
 363                      }
 364                      $Form->end_fieldset();
 365                      $k_nb++;
 366                  }
 367              }
 368  
 369              // TODO: fix this for AJAX callbacks, when removing and re-adding items (dh):
 370              if( ! isset( $parmeta['max_number'] ) || $parmeta['max_number'] > ($k_nb) )
 371              { // no max_number defined or not reached: display link to add a new set
 372                  $set_path = $parname.'['.$k_nb.']';
 373  
 374                  echo '<div id="'.$parname.'_add_new">';
 375                  echo action_icon(
 376                      sprintf( T_('Add a new set of &laquo;%s&raquo;'), $set_label),
 377                      'new',
 378                      regenerate_url( 'action', array('action=add_settings_set', 'set_path='.$set_path.( $set_type == 'UserSettings' ? '&amp;user_ID='.get_param('user_ID') : '' ), 'plugin_ID='.$Obj->ID) ),
 379                      T_('New set'),
 380                      5, 1, /* icon/text prio */
 381                      // Replace the 'add new' action icon div with a new set of setting and a new 'add new' action icon div
 382                      array('onclick'=>"
 383                          var oThis = this;
 384                          jQuery.get('{$htsrv_url}async.php', {
 385                                  action: 'add_plugin_sett_set',
 386                                  plugin_ID: '{$Obj->ID}',
 387                                  set_type: '$set_type',
 388                                  set_path: '$set_path'
 389                              },
 390                              function(r, status) {
 391                                  jQuery('#".$parname."_add_new').replaceWith(r);
 392                              }
 393                          );
 394                          return false;")
 395                      );
 396                  echo '</div>';
 397              }
 398  
 399              if( ! empty($disp_whole_set) )
 400              { // close the surrounding fieldset:
 401                  $Form->end_fieldset();
 402              }
 403              $Form->switch_layout( NULL );
 404  
 405              break;
 406  
 407          case 'password':
 408              $params['type'] = 'password'; // same as text input, but type=password
 409  
 410          case 'float':
 411          case 'integer':
 412          case 'text':
 413              // Default: "text input"
 414              if( isset($parmeta['size']) )
 415              {
 416                  $size = (int)$parmeta['size'];
 417              }
 418              else
 419              { // Default size:
 420                  $size = 15;
 421              }
 422              if( isset($parmeta['maxlength']) )
 423              {
 424                  $params['maxlength'] = (int)$parmeta['maxlength'];
 425              }
 426              else
 427              { // do not use size as maxlength, if not given!
 428                  $params['maxlength'] = '';
 429              }
 430  
 431              $Form->text_input( $input_name, $set_value, $size, $set_label, '', $params ); // TEMP: Note already in params
 432              break;
 433  
 434          case 'info':
 435              $Form->info( $parmeta['label'], $parmeta['info'] );
 436              break;
 437  
 438          case 'color':
 439              $Form->color_input( $input_name, $set_value, $set_label, '', $params );
 440              break;
 441  
 442          default:
 443              debug_die( 'Unsupported type ['.$parmeta['type'].'] from GetDefaultSettings()!' );
 444      }
 445  
 446      if( $outer_most && $has_array_type )
 447      { // Note for Non-Javascript users:
 448          echo '<script type="text/javascript"></script><noscript>';
 449          echo '<p class="note">'.T_('Note: before adding a new set you have to save any changes.').'</p>';
 450          echo '</noscript>';
 451      }
 452  }
 453  
 454  
 455  /**
 456   * Helper method for "add_settings_set" and "delete_settings_set" action.
 457   *
 458   * Walks the given settings path and either inits the target entry or unsets it ($init_value=NULL).
 459   *
 460   * @param Plugin
 461   * @param string Settings type ("Settings" or "UserSettings")
 462   * @param string The settings path, e.g. 'setting[0]foo[1]'. (Is used as array internally for recursion.)
 463   * @param mixed The initial value of the setting, typically array() - NULL to unset it (action "delete_settings_set" uses it)
 464   * @return array|false
 465   */
 466  function _set_setting_by_path( & $Plugin, $set_type, $path, $init_value = array() )
 467  {
 468      $r = get_plugin_settings_node_by_path( $Plugin, $set_type, $path, true );
 469      if( $r === false )
 470      {
 471          return false;
 472      }
 473  
 474      // Make return value handier. Note: list() would copy and destroy the references (setting and set_node)!
 475      $set_name = & $r['set_name'];
 476      $set_node = & $r['set_node'];
 477      $set_meta = & $r['set_meta'];
 478      $set_parent = & $r['set_parent'];
 479      $set_key  = & $r['set_key'];
 480      $setting  = & $r['setting'];
 481      #pre_dump( $r );
 482  
 483      #if( isset($set_node) && $init_value !== NULL )
 484      #{ // Setting already exists (and we do not want to delete), e.g. page reload!
 485      #    return false;
 486      #    /*
 487      #    while( isset($l_setting[ $path[0] ]) )
 488      #    { // bump the index until not set
 489      #        $path[0]++;
 490      #    }
 491      #    */
 492      #}
 493      #else
 494      if( is_null($init_value) )
 495      { // NULL is meant to unset it
 496          unset($set_parent[$set_key]);
 497      }
 498      else
 499      { // Init entries:
 500          // destroys reference: $set_node = $init_value;
 501  
 502          // Copy meta entries:
 503          foreach( $set_meta['entries'] as $k => $v )
 504          {
 505              if( isset( $v['defaultvalue'] ) )
 506              { // set to defaultvalue
 507                  $set_node[$k] = $v['defaultvalue'];
 508              }
 509              else
 510              {
 511                  if( isset($v['type']) && $v['type'] == 'array' )
 512                  {
 513                      $set_node[$k] = array();
 514                  }
 515                  else
 516                  {
 517                      $set_node[$k] = '';
 518                  }
 519              }
 520          }
 521      }
 522  
 523      // Set it into $Plugin->Settings or $Plugin->UserSettings:
 524      $Plugin->$set_type->set( $set_name, $setting );
 525  
 526      return $setting;
 527  }
 528  
 529  
 530  /**
 531   * Get a node from settings by path (e.g. "locales[0][questions]")
 532   *
 533   * @param Plugin
 534   * @param string Settings type ("Settings" or "UserSettings")
 535   * @param string The settings path, e.g. 'setting[0]foo[1]' or even 'setting[]'. (Is used as array internally for recursion.)
 536   * @return array Array(
 537   *          - 'set_name': setting name (string); key of the first level
 538   *          - 'set_node': selected setting node, may be NULL (by reference)
 539   *          - 'set_meta': meta info (from GetDefault[User]Settings()) for selected node (array)
 540   *          - 'set_parent': parent node (by reference)
 541   *          - 'set_key': key in parent node (by reference)
 542   *          - 'setting': whole settings (array)
 543   */
 544  function get_plugin_settings_node_by_path( & $Plugin, $set_type, $path, $create = false )
 545  {
 546      // Init:
 547      if( ! preg_match( '~^\w+(\[\w+\])+$~', $path ) )
 548      {
 549          debug_die( 'Invalid path param!' );
 550      }
 551  
 552      $path = preg_split( '~(\[|\]\[?)~', $path, -1 ); // split by "[" and "][", so we get an array with setting name and index alternating
 553      $foo = array_pop($path); // remove last one
 554      if( ! empty($foo) )
 555          debug_die('Assertion failed!');
 556  
 557      $set_name = $path[0];
 558  
 559      $setting = $Plugin->$set_type->get($set_name);  // $Plugin->Settings or $Plugin->UserSettings
 560      if( ! is_array($setting) )
 561      { // this may happen, if there was a non-array setting stored previously:
 562          // discard those!
 563          $setting = array();
 564      }
 565  
 566      // meta info for this setting:
 567      $method = 'GetDefault'.$set_type; // GetDefaultSettings or GetDefaultUserSettings
 568      $defaults = $Plugin->$method( $tmp_params = array('for_editing'=>true) );
 569      if( ! isset($defaults[ $set_name ]) )
 570      {
 571          //debug_die( 'Invalid setting ('.$set_name.') - no meta data!' );
 572          return false;
 573      }
 574  
 575      $found_node = & $setting;
 576      $defaults_node = & $defaults;
 577      $set_meta = $defaults[$set_name];
 578      $set_parent = NULL;
 579      $set_key = NULL;
 580  
 581      $count = 0;
 582      while( count($path) )
 583      {
 584          $count++;
 585  
 586          $loop_name = array_shift($path);
 587  
 588          if( $count > 1 )
 589          {
 590              $set_parent = & $found_node[$loop_name];
 591              $set_key = NULL;
 592              $defaults_node = & $defaults_node['entries'][$loop_name];
 593              $found_node = & $found_node[$loop_name];
 594          }
 595          else
 596          {
 597              $defaults_node = & $defaults_node[$loop_name];
 598              $set_parent = & $setting;
 599          }
 600  
 601          if( count($path) )
 602          { // has an index => array
 603              $loop_index = array_shift($path);
 604  
 605              #$set_parent = & $set_parent[$loop_name];
 606              $set_key = $loop_index;
 607  
 608              if( $set_key === '' )
 609              { // []-syntax: append entry
 610                  if( $create && ! count($path) )
 611                  { // only create, if at the end
 612                      $found_node[] = array();
 613                  }
 614                  $found_node = & $found_node[ array_pop(array_keys($found_node)) ];
 615              }
 616              else
 617              { // specific key:
 618                  if( ! isset($found_node[$loop_index]) )
 619                  {
 620                      $found_node[$loop_index] = array();
 621                  }
 622                  $found_node = & $found_node[$loop_index];
 623              }
 624          }
 625      }
 626  
 627      #echo '<h1>RETURN</h1>'; pre_dump( $set_parent, $set_key );
 628      return array(
 629          'set_name' => $set_name,
 630          'set_node' => & $found_node,
 631          'set_meta' => $defaults_node,
 632          'set_parent' => & $set_parent,
 633          'set_key' => & $set_key,
 634          'setting' => & $setting );
 635  }
 636  
 637  
 638  /**
 639   * Set Plugin settings from params.
 640   *
 641   * fp> WARNING: also used outside of plugins. Work in progress.
 642   *
 643   * This handled plugin specific params when saving a user profile (PluginUserSettings) or plugin settings (PluginSettings).
 644   *
 645   * @param string Settings path, e.g. 'locales[0]' or 'setting'
 646   * @param array Meta data for this setting.
 647   * @param Plugin|Widget
 648   * @param string Type of Settings (either 'Settings' or 'UserSettings').
 649   * @param mixed Target (User object for 'UserSettings')
 650   */
 651  function autoform_set_param_from_request( $parname, $parmeta, & $Obj, $set_type, $set_target = NULL )
 652  {
 653      if( isset($parmeta['layout']) )
 654      { // a layout "setting"
 655          return;
 656      }
 657  
 658      if( ! empty($parmeta['disabled']) || ! empty($parmeta['no_edit']) )
 659      { // the setting is disabled
 660          return;
 661      }
 662  
 663      $l_param_type = 'string';
 664      $l_param_default = '';
 665      if( isset($parmeta['type']) )
 666      {
 667          if( substr($parmeta['type'], 0, 6) == 'select' && ! empty($parmeta['multiple']) )
 668          { // a "multiple" select:
 669              $l_param_type = 'array';
 670          }
 671          switch( $parmeta['type'] )
 672          {
 673              case 'array':
 674                  // this settings has a type
 675                  $l_param_type = $parmeta['type'];
 676                  break;
 677  
 678              case 'checkbox':
 679                  $l_param_type = 'integer';
 680                  $l_param_default = 0;
 681                  break;
 682  
 683              case 'html_input':
 684              case 'html_textarea':
 685                  $l_param_type = 'html';
 686                  break;
 687  
 688              default:
 689          }
 690      }
 691  
 692      // Get the value:
 693      $l_value = param( 'edit_plugin_'.$Obj->ID.'_set_'.$parname, $l_param_type, $l_param_default );
 694      // pre_dump( $parname, $l_value );
 695  
 696      if( isset($parmeta['type']) && $parmeta['type'] == 'array' )
 697      { // make keys (__key__) in arrays unique and remove them
 698          handle_array_keys_in_plugin_settings($l_value);
 699      }
 700  
 701      if( ! autoform_validate_param_value('edit_plugin_'.$Obj->ID.'_set_'.$parname, $l_value, $parmeta) )
 702      {
 703          return;
 704      }
 705  
 706      // Validate form values:
 707      switch( $set_type )
 708      {
 709          case 'CollSettings':
 710              $error_value = NULL;
 711              $Obj->set_coll_setting( $parname, $l_value );
 712              break;
 713  
 714          case 'Skin':
 715              $error_value = NULL;
 716              $Obj->set_setting( $parname, $l_value );
 717              break;
 718  
 719          case 'Widget':
 720              $error_value = NULL;
 721              $Obj->set( $parname, $l_value );
 722              break;
 723  
 724          case 'UserSettings':
 725              // Plugin User settings:
 726              $error_value = $Obj->PluginUserSettingsValidateSet( $dummy = array(
 727                  'name' => $parname,
 728                  'value' => & $l_value,
 729                  'meta' => $parmeta,
 730                  'User' => $set_target,
 731                  'action' => 'set' ) );
 732              // Update the param value, because a plugin might have changed it (through reference):
 733              $GLOBALS['edit_plugin_'.$Obj->ID.'_set_'.$parname] = $l_value;
 734  
 735              if( empty( $error_value ) )
 736              {
 737                  $Obj->UserSettings->set( $parname, $l_value, $set_target->ID );
 738              }
 739              break;
 740  
 741          case 'Settings':
 742              // Plugin global settings:
 743              $error_value = $Obj->PluginSettingsValidateSet( $dummy = array(
 744                  'name' => $parname,
 745                  'value' => & $l_value,
 746                  'meta' => $parmeta,
 747                  'action' => 'set' ) );
 748              // Update the param value, because a plugin might have changed it (through reference):
 749              $GLOBALS['edit_plugin_'.$Obj->ID.'_set_'.$parname] = $l_value;
 750  
 751              if( empty( $error_value ) )
 752              {
 753                  $Obj->Settings->set( $parname, $l_value );
 754              }
 755              break;
 756  
 757          default:
 758              debug_die( "unhandled set_type $set_type" );
 759              break;
 760      }
 761  
 762      if( $error_value )
 763      { // A validation error has occured, record error message:
 764          param_error( 'edit_plugin_'.$Obj->ID.'_set_'.$parname, $error_value );
 765      }
 766  }
 767  
 768  
 769  /**
 770   * Validates settings according to their meta info recursively.
 771   *
 772   * @todo Init "checkbox" values in "array" type settings (they do not get send) (dh)
 773   * @param string Param name
 774   * @param array Meta info
 775   * @return boolean
 776   */
 777  function autoform_validate_param_value( $param_name, $value, $meta )
 778  {
 779      global $Messages;
 780  
 781      if( is_array($value) && isset($meta['entries']) )
 782      {
 783          $r = true;
 784          if(isset($meta['key']))
 785          { // validate keys:
 786              foreach( array_keys($value) as $k )
 787              {
 788                  if( ! autoform_validate_param_value($param_name.'['.$k.'][__key__]', $k, $meta['key']) )
 789                  {
 790                      $r = false;
 791                  }
 792              }
 793          }
 794  
 795          // Check max_count/min_count
 796          // dh> TODO: find a way to link it to the form's fieldset (and add an "error" class to it)
 797          if( isset($meta['max_count']) && count($value) > $meta['max_count'] )
 798          {
 799              $r = false;
 800              $label = isset($meta['label']) ? $meta['label'] : $param_name;
 801              $Messages->add( sprintf( T_('Too many entries in the "%s" set. It must have %d at most.'), $label, $meta['max_count'] ), 'error' );
 802          }
 803          elseif( isset($meta['min_count']) && count($value) < $meta['min_count'] )
 804          {
 805              $r = false;
 806              $label = isset($meta['label']) ? $meta['label'] : $param_name;
 807              $Messages->add( sprintf( T_('Too few entries in the "%s" set. It must have %d at least.'), $label, $meta['min_count'] ), 'error' );
 808          }
 809  
 810          foreach( $meta['entries'] as $mk => $mv )
 811          {
 812              foreach( $value as $vk => $vv )
 813              {
 814                  if( ! isset($vv[$mk]) )
 815                      continue;
 816  
 817                  if( ! autoform_validate_param_value($param_name.'['.$vk.']['.$mk.']', $vv[$mk], $mv) )
 818                  {
 819                      $r = false;
 820                  }
 821              }
 822          }
 823          return $r;
 824      }
 825  
 826  
 827      if( isset($meta['type']) )
 828      {
 829          switch( $meta['type'] )
 830          {
 831              case 'integer':
 832                  if( ! preg_match( '~^[-+]?\d+$~', $value ) )
 833                  {
 834                      param_error( $param_name, sprintf( T_('The value for &laquo;%s&raquo; must be numeric.'), $meta['label'] ), T_('The value must be numeric.') );
 835                      return false;
 836                  }
 837                  break;
 838  
 839              case 'float':
 840                  if( ! preg_match( '~^[-+]?\d+(\.\d+)?$~', $value ) )
 841                  {
 842                      param_error( $param_name, sprintf( T_('The value for &laquo;%s&raquo; must be numeric.'), $meta['label'] ), T_('The value must be numeric.') );
 843                      return false;
 844                  }
 845                  break;
 846  
 847              case 'radio':
 848                  $check_value = false;
 849                  foreach($meta['options'] as $arr)
 850                  {
 851                      if( ! is_array($arr) )
 852                      {
 853                          param_error( $param_name, sprintf( T_('Invalid option &laquo;%s&raquo;.'), $arr ) );
 854                          return false;
 855                      }
 856                      if( $value == $arr[0] )
 857                      {
 858                          $check_value = true;
 859                          break;
 860                      }
 861                  }
 862                  if ( ! $check_value )
 863                  {
 864                      param_error( $param_name, sprintf( T_('Invalid option &laquo;%s&raquo;.'), $value ) );
 865                      return false;
 866                  }
 867                  break;
 868  
 869              case 'select':
 870                  $check_options = $value;
 871                  if( ! is_array($check_options) )
 872                  { // no "multiple" select:
 873                      $check_options = array($check_options);
 874                  }
 875  
 876                  foreach($check_options as $v)
 877                  {
 878                      if( ! in_array( $v, array_keys($meta['options']) ) )
 879                      {
 880                          param_error( $param_name, sprintf( T_('Invalid option &laquo;%s&raquo;.'), $v ) );
 881                          return false;
 882                      }
 883                  }
 884                  break;
 885  
 886              case 'select_blog':
 887              case 'select_group':
 888              case 'select_user':
 889                  if( is_array($value) && empty($value) // empty "multiple" select
 890                      || ( ! is_array($value) && ! strlen($value) ) )
 891                  {
 892                      if( empty($meta['allow_none']) )
 893                      { // empty is not ok
 894                          param_error( $param_name, sprintf( T_('Invalid option &laquo;%s&raquo;.'), $value ) );
 895                          return false;
 896                      }
 897                  }
 898                  else
 899                  { // Try retrieving the value from the corresponding Cache:
 900                      switch( $meta['type'] )
 901                      {
 902                          case 'select_blog':
 903                              $Cache = & get_BlogCache();
 904                              break;
 905  
 906                          case 'select_group':
 907                              $Cache = & get_GroupCache();
 908                              break;
 909  
 910                          case 'select_user':
 911                              $Cache = & get_UserCache();
 912                              break;
 913                      }
 914  
 915                      $check_options = $value;
 916                      if( ! is_array($check_options) )
 917                      { // no "multiple" select:
 918                          $check_options = array($check_options);
 919                      }
 920  
 921                      foreach($check_options as $v)
 922                      {
 923                          if( empty($v) && ! empty($meta['allow_none']) )
 924                          { // empty is ok:
 925                              continue;
 926                          }
 927                          if( ! $Cache->get_by_ID($v, false, false) )
 928                          {
 929                              param_error( $param_name, sprintf( T_('Invalid option &laquo;%s&raquo;.'), $v ) );
 930                              return false;
 931                          }
 932                      }
 933                  }
 934                  break;
 935          }
 936      }
 937  
 938      // Check maxlength:
 939      if( isset($meta['maxlength']) )
 940      {
 941          if( evo_strlen($value) > $meta['maxlength'] )
 942          {
 943              param_error( $param_name, sprintf( T_('The value is too long.'), $value ) );
 944          }
 945      }
 946  
 947      // Check valid pattern:
 948      if( isset($meta['valid_pattern']) )
 949      {
 950          $param_pattern = is_array($meta['valid_pattern']) ? $meta['valid_pattern']['pattern'] : $meta['valid_pattern'];
 951          if( ! preg_match( $param_pattern, $value ) )
 952          {
 953              $param_error = is_array($meta['valid_pattern']) ? $meta['valid_pattern']['error'] : sprintf(T_('The value is invalid. It must match the regular expression &laquo;%s&raquo;.'), $param_pattern);
 954              param_error( $param_name, $param_error );
 955              return false;
 956          }
 957      }
 958  
 959      // Check valid range:
 960      if( isset($meta['valid_range']) )
 961      {
 962          // Transform numeric indexes into associative keys:
 963          if( ! isset($meta['valid_range']['min'], $meta['valid_range']['max'])
 964              && isset($meta['valid_range'][0], $meta['valid_range'][1]) )
 965          {
 966              $meta['valid_range']['min'] = $meta['valid_range'][0];
 967              $meta['valid_range']['max'] = $meta['valid_range'][1];
 968          }
 969          if( isset($meta['valid_range'][2]) && ! isset($meta['valid_range']['error']) )
 970          {
 971              $meta['valid_range']['error'] = $meta['valid_range'][2];
 972          }
 973  
 974          if( (isset($meta['valid_range']['min']) && $value < $meta['valid_range']['min'])
 975                  || (isset($meta['valid_range']['max']) && $value > $meta['valid_range']['max']) )
 976          {
 977              if( isset($meta['valid_range']['error']) )
 978              {
 979                  $param_error = $meta['valid_range']['error'];
 980              }
 981              else
 982              {
 983                  if( isset($meta['valid_range']['min']) && isset($meta['valid_range']['max']) )
 984                  {
 985                      $param_error = sprintf(T_('The value is invalid. It must be in the range from %s to %s.'), $meta['valid_range']['min'], $meta['valid_range']['max']);
 986                  }
 987                  elseif( isset($meta['valid_range']['max']) )
 988                  {
 989                      $param_error = sprintf(T_('The value is invalid. It must be smaller than or equal to %s.'), $meta['valid_range']['max']);
 990                  }
 991                  else
 992                  {
 993                      $param_error = sprintf(T_('The value is invalid. It must be greater than or equal to %s.'), $meta['valid_range']['min']);
 994                  }
 995              }
 996  
 997              param_error( $param_name, $param_error );
 998              return false;
 999          }
1000      }
1001  
1002      return true;
1003  }
1004  
1005  
1006  /**
1007   * This handles the special "__key__" index in all array type values
1008   * in the given array. It makes sure, that "__key__" is unique and
1009   * replaces the original key of the value with it.
1010   * @param array (by reference)
1011   */
1012  function handle_array_keys_in_plugin_settings( & $a )
1013  {
1014      if( ! is_array($a) )
1015      {
1016          return;
1017      }
1018  
1019      $new_arr = array(); // use a new array to maintain order, also for "numeric" keys
1020  
1021      foreach( array_keys($a) as $k )
1022      {
1023          $v = & $a[$k];
1024  
1025          if( is_array($v) && isset($v['__key__']) )
1026          {
1027              if( $k != $v['__key__'] )
1028              {
1029                  $k = $v['__key__'];
1030                  if( ! strlen($k) || isset($a[ $k ]) )
1031                  { // key already exists (or is empty):
1032                      $c = 1;
1033  
1034                      while( isset($a[ $k.'_'.$c ]) )
1035                      {
1036                          $c++;
1037                      }
1038                      $k = $k.'_'.$c;
1039                  }
1040              }
1041              unset($v['__key__']);
1042  
1043              $new_arr[$k] = $v;
1044          }
1045          else
1046          {
1047              $new_arr[$k] = $v;
1048          }
1049  
1050          // Recurse:
1051          foreach( array_keys($v) as $rk )
1052          {
1053              if( is_array($v[$rk]) )
1054              {
1055                  handle_array_keys_in_plugin_settings($v[$rk]);
1056              }
1057          }
1058      }
1059      $a = $new_arr;
1060  }
1061  
1062  
1063  /**
1064   * Helper function to do the action part of DB schema upgrades for "enable" and "install"
1065   * actions.
1066   *
1067   * @param object Plugin
1068   * @param boolean Force install DB for the plugin (used in installation of b2evo)
1069   * @return boolean True, if no changes needed or done; false if we should break out to display "install_db_schema" action payload.
1070   */
1071  function install_plugin_db_schema_action( & $Plugin, $force_install_db_deltas = false )
1072  {
1073      global $inc_path, $install_db_deltas, $DB, $Messages;
1074  
1075      // Prepare vars for DB layout changes
1076      $install_db_deltas_confirm_md5 = param( 'install_db_deltas_confirm_md5' );
1077  
1078      $db_layout = $Plugin->GetDbLayout();
1079      $install_db_deltas = array(); // This holds changes to make, if any (just all queries)
1080      //pre_dump( $db_layout );
1081  
1082      if( ! empty($db_layout) )
1083      { // The plugin has a DB layout attached
1084          load_funcs('_core/model/db/_upgrade.funcs.php');
1085  
1086          // Get the queries to make:
1087          foreach( db_delta($db_layout) as $table => $queries )
1088          {
1089              foreach( $queries as $query_info )
1090              {
1091                  foreach( $query_info['queries'] as $query )
1092                  { // subqueries for this query (usually one, but may include required other queries)
1093                      $install_db_deltas[] = $query;
1094                  }
1095              }
1096          }
1097  
1098          if( ! empty($install_db_deltas) )
1099          { // delta queries to make
1100              if( empty($install_db_deltas_confirm_md5) && !$force_install_db_deltas )
1101              { // delta queries have to be confirmed in payload
1102                  return false;
1103              }
1104              elseif( $install_db_deltas_confirm_md5 == md5( implode('', $install_db_deltas) ) || $force_install_db_deltas )
1105              { // Confirmed in first step:
1106                  foreach( $install_db_deltas as $query )
1107                  {
1108                      $DB->query( $query );
1109                  }
1110  
1111                  $Messages->add( T_('The database has been updated.'), 'success' );
1112              }
1113              else
1114              { // should not happen
1115                  $Messages->add( T_('The DB schema has been changed since confirmation.'), 'error' );
1116  
1117                  // delta queries have to be confirmed (again) in payload
1118                  return false;
1119              }
1120          }
1121      }
1122  
1123      return true;
1124  }
1125  
1126  ?>

title

Description

title

Description

title

Description

title

title

Body