b2evolution PHP Cross Reference Blogging Systems

Source: /htsrv/async.php - 563 lines - 19084 bytes - Summary - Text - Print

Description: This is the handler for asynchronous 'AJAX' calls. This file is part of the evoCore framework - {@link http://evocore.net/} See also {@link http://sourceforge.net/projects/evocms/}.

   1  <?php
   2  /**
   3   * This is the handler for asynchronous 'AJAX' calls.
   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   * fp> TODO: it would be better to have the code for the actions below part of the controllers they belong to.
   9   * This would require some refectoring but would be better for maintenance and code clarity.
  10   *
  11   * @copyright (c)2003-2014 by Francois Planque - {@link http://fplanque.com/}
  12   *
  13   * {@internal License choice
  14   * - If you have received this file as part of a package, please find the license.txt file in
  15   *   the same folder or the closest folder above for complete license terms.
  16   * - If you have received this file individually (e-g: from http://evocms.cvs.sourceforge.net/)
  17   *   then you must choose one of the following licenses before using the file:
  18   *   - GNU General Public License 2 (GPL) - http://www.opensource.org/licenses/gpl-license.php
  19   *   - Mozilla Public License 1.1 (MPL) - http://www.opensource.org/licenses/mozilla1.1.php
  20   * }}
  21   *
  22   * {@internal Open Source relicensing agreement:
  23   * }}
  24   *
  25   * @package evocore
  26   *
  27   * @version $Id: async.php 6136 2014-03-08 07:59:48Z manuel $
  28   */
  29  
  30  
  31  /**
  32   * Do the MAIN initializations:
  33   */
  34  require_once dirname(__FILE__).'/../conf/_config.php';
  35  
  36  /**
  37   * HEAVY :(
  38   *
  39   * @todo dh> refactor _main.inc.php to be able to include small parts
  40   *           (e.g. $current_User, charset init, ...) only..
  41   *           It worked already for $DB (_connect_db.inc.php).
  42   * fp> I think I'll try _core_main.inc , _evo_main.inc , _blog_main.inc ; this file would only need _core_main.inc
  43   */
  44  require_once $inc_path.'_main.inc.php';
  45  
  46  // create global $blog variable
  47  global $blog;
  48  // Init $blog with NULL to avoid injections, it will get the correct value from param where it is required
  49  $blog = NULL;
  50  
  51  param( 'action', 'string', '' );
  52  
  53  // Check global permission:
  54  if( empty($current_User) || ! $current_User->check_perm( 'admin', 'restricted' ) )
  55  {    // No permission to access admin...
  56      require $adminskins_path.'_access_denied.main.php';
  57  }
  58  
  59  // Make sure the async responses are never cached:
  60  header_nocache();
  61  header_content_type( 'text/html', $io_charset );
  62  
  63  // Save current debug values
  64  $current_debug = $debug;
  65  $current_debug_jslog = $debug_jslog;
  66  
  67  // Do not append Debuglog to response!
  68  $debug = false;
  69  
  70  // Do not append Debug JSlog to response!
  71  $debug_jslog = false;
  72  
  73  // Init AJAX log
  74  $Ajaxlog = new Log();
  75  
  76  $Ajaxlog->add( sprintf( T_('action: %s'), $action ), 'note' );
  77  
  78  $incorrect_action = false;
  79  
  80  $add_response_end_comment = true;
  81  
  82  // fp> Does the following have an HTTP fallback when Javascript/AJ is not available?
  83  // dh> yes, but not through this file..
  84  // dh> IMHO it does not make sense to let the "normal controller" handle the AJAX call
  85  //     if there's something lightweight like calling "$UserSettings->param_Request()"!
  86  //     Hmm.. bad example (but valid). Better example: something like the actions below, which
  87  //     output only a small part of what the "real controller" does..
  88  switch( $action )
  89  {
  90      case 'add_plugin_sett_set':
  91          // Dislay a new Plugin(User)Settings set ( it's used only from plugins with "array" type settings):
  92  
  93          // This does not require CSRF because it doesn't update the db, it only displays a new block of empty plugin setting fields
  94  
  95          // Check permission to view plugin settings:
  96          $current_User->check_perm( 'options', 'view', true );
  97  
  98          param( 'plugin_ID', 'integer', true );
  99  
 100          $admin_Plugins = & get_Plugins_admin(); // use Plugins_admin, because a plugin might be disabled
 101          $Plugin = & $admin_Plugins->get_by_ID($plugin_ID);
 102          if( ! $Plugin )
 103          {
 104              bad_request_die('Invalid Plugin.');
 105          }
 106          param( 'set_type', 'string', '' ); // "Settings" or "UserSettings"
 107          if( $set_type != 'Settings' /* && $set_type != 'UserSettings' */ )
 108          {
 109              bad_request_die('Invalid set_type param!');
 110          }
 111          param( 'set_path', '/^\w+(?:\[\w+\])+$/', '' );
 112  
 113          load_funcs('plugins/_plugin.funcs.php');
 114  
 115          // Init the new setting set:
 116          _set_setting_by_path( $Plugin, $set_type, $set_path, array() );
 117  
 118          // Get the new plugin setting set and display it with a fake Form
 119          $r = get_plugin_settings_node_by_path( $Plugin, $set_type, $set_path, /* create: */ false );
 120  
 121          $Form = new Form(); // fake Form to display plugin setting
 122          autoform_display_field( $set_path, $r['set_meta'], $Form, $set_type, $Plugin, NULL, $r['set_node'] );
 123          break;
 124  
 125      case 'set_object_link_position':
 126          // Change a position of a link on the edit item screen (fieldset "Images & Attachments")
 127  
 128          // Check that this action request is not a CSRF hacked request:
 129          $Session->assert_received_crumb( 'link' );
 130  
 131          // Check item/comment edit permission below after we have the $LinkOwner object ( we call LinkOwner->check_perm ... )
 132  
 133          param('link_ID', 'integer', true);
 134          param('link_position', 'string', true);
 135  
 136          $LinkCache = & get_LinkCache();
 137          if( ( $Link = & $LinkCache->get_by_ID( $link_ID ) ) === false )
 138          {    // Bad request with incorrect link ID
 139              echo '';
 140              exit(0);
 141          }
 142          $LinkOwner = & $Link->get_LinkOwner();
 143  
 144          // Check permission:
 145          $LinkOwner->check_perm( 'edit', true );
 146  
 147          if( $Link->set( 'position', $link_position ) && $Link->dbupdate() )
 148          {    // update was successful
 149              echo 'OK';
 150  
 151              // Update last touched date of Item
 152              $LinkOwner->item_update_last_touched_date();
 153          }
 154          else
 155          {    // return the current value on failure
 156              echo $Link->get( 'position' );
 157          }
 158          break;
 159  
 160      case 'get_login_list':
 161          // Get users login list for username form field hintbox.
 162  
 163          // current user must have at least view permission to see users login
 164          $current_User->check_perm( 'users', 'view', true );
 165  
 166          $text = trim( urldecode( param( 'q', 'string', '' ) ) );
 167  
 168          /**
 169           * sam2kb> The code below decodes percent-encoded unicode string produced by Javascript "escape"
 170           * function in format %uxxxx where xxxx is a Unicode value represented as four hexadecimal digits.
 171           * Example string "MAMA" (cyrillic letters) encoded with "escape": %u041C%u0410%u041C%u0410
 172           * Same word encoded with "encodeURI": %D0%9C%D0%90%D0%9C%D0%90
 173           *
 174           * jQuery hintbox plugin uses "escape" function to encode URIs
 175           *
 176           * More info here: http://en.wikipedia.org/wiki/Percent-encoding#Non-standard_implementations
 177           */
 178          if( preg_match( '~%u[0-9a-f]{3,4}~i', $text ) && version_compare(PHP_VERSION, '5', '>=') )
 179          {    // Decode UTF-8 string (PHP 5 and up)
 180              $text = preg_replace( '~%u([0-9a-f]{3,4})~i', '&#x\\1;', $text );
 181              $text = html_entity_decode( $text, ENT_COMPAT, 'UTF-8' );
 182          }
 183  
 184          if( !empty( $text ) )
 185          {
 186              $SQL = new SQL();
 187              $SQL->SELECT( 'user_login' );
 188              $SQL->FROM( 'T_users' );
 189              $SQL->WHERE( 'user_login LIKE "'.$DB->escape($text).'%"' );
 190              $SQL->LIMIT( '10' );
 191              $SQL->ORDER_BY('user_login');
 192  
 193              echo implode( "\n", $DB->get_col($SQL->get()) );
 194          }
 195  
 196          // don't show ajax response end comment, because the result will be processed with jquery hintbox
 197          $add_response_end_comment = false;
 198          break;
 199  
 200      case 'get_opentrash_link':
 201          // Used to get a link 'Open recycle bin' in order to show it in the header of comments list
 202  
 203          // Check that this action request is not a CSRF hacked request:
 204          $Session->assert_received_crumb( 'comment' );
 205  
 206          echo get_opentrash_link( true, true );
 207          break;
 208  
 209      case 'set_comment_status':
 210          // Used for quick moderation of comments in dashboard, item list full view and comment list screens
 211  
 212          // Check that this action request is not a CSRF hacked request:
 213          $Session->assert_received_crumb( 'comment' );
 214  
 215          // Check comment moderate permission below after we have the $edited_Comment object
 216  
 217          $is_admin_page = true;
 218          $blog = param( 'blogid', 'integer' );
 219          $moderation = param( 'moderation', 'string', NULL );
 220          $status = param( 'status', 'string' );
 221          $expiry_status = param( 'expiry_status', 'string', 'active' );
 222          $limit = param( 'limit', 'integer', 0 );
 223          $edited_Comment = & Comment_get_by_ID( param( 'commentid', 'integer' ), false );
 224          if( $edited_Comment !== false )
 225          {    // The comment still exists
 226              // Check permission:
 227              $current_User->check_perm( 'comment!'.$status, 'moderate', true, $edited_Comment );
 228  
 229              $redirect_to = param( 'redirect_to', 'url', NULL );
 230  
 231              $edited_Comment->set( 'status', $status );
 232              // Comment moderation is done, handle moderation "secret"
 233              $edited_Comment->handle_qm_secret();
 234              $edited_Comment->dbupdate();
 235  
 236              if( $status == 'published' )
 237              {
 238                  $edited_Comment->handle_notifications();
 239              }
 240  
 241              if( $moderation != NULL )
 242              {
 243                  $statuses = param( 'statuses', 'string', NULL );
 244                  $item_ID = param( 'itemid', 'integer' );
 245                  $currentpage = param( 'currentpage', 'integer', 1 );
 246  
 247                  if( strlen($statuses) > 2 )
 248                  {
 249                      $statuses = substr( $statuses, 1, strlen($statuses) - 2 );
 250                  }
 251                  $status_list = explode( ',', $statuses );
 252                  if( $status_list == NULL )
 253                  {
 254                      $status_list = get_visibility_statuses( 'keys', array( 'redirected', 'trash' ) );
 255                  }
 256  
 257                  // In case of comments_fullview we must set a filterset name to be abble to restore filterset.
 258                  // If $moderation is not NULL, then this requests came from the comments_fullview
 259                  // TODO: asimo> This should be handled with a better solution
 260                  $filterset_name = ( $item_ID > 0 ) ? '' : 'fullview';
 261                  if( $limit == 0 )
 262                  {
 263                      $limit = $UserSettings->get( 'results_per_page' ); 
 264                  }
 265                  echo_item_comments( $blog, $item_ID, $status_list, $currentpage, $limit, array(), $filterset_name, $expiry_status );
 266                  break;
 267              }
 268          }
 269  
 270          if( $moderation == NULL )
 271          {
 272              get_comments_awaiting_moderation( $blog );
 273          }
 274  
 275          break;
 276  
 277      case 'delete_comment':
 278          // Delete a comment from dashboard screen
 279  
 280          // Check that this action request is not a CSRF hacked request:
 281          $Session->assert_received_crumb( 'comment' );
 282  
 283          // Check comment moderate permission below after we have the $edited_Comment objects
 284  
 285          $is_admin_page = true;
 286          $blog = param( 'blogid', 'integer' );
 287          $edited_Comment = & Comment_get_by_ID( param( 'commentid', 'integer' ), false );
 288          if( $edited_Comment !== false )
 289          {    // The comment still exists
 290              // Check permission:
 291              $current_User->check_perm( 'comment!CURSTATUS', 'delete', true, $edited_Comment );
 292  
 293              $edited_Comment->dbdelete();
 294          }
 295  
 296          get_comments_awaiting_moderation( $blog );
 297          break;
 298  
 299      case 'delete_comments':
 300          // Delete the comments from the list on dashboard, on comments full text view screen or on a view item screen
 301  
 302          // Check that this action request is not a CSRF hacked request:
 303          $Session->assert_received_crumb( 'comment' );
 304  
 305          // Check comment moderate permission below after we have the $edited_Comment objects
 306  
 307          $is_admin_page = true;
 308          $blog = param( 'blogid', 'integer' );
 309          $commentIds = param( 'commentIds', 'array' );
 310          $statuses = param( 'statuses', 'string', NULL );
 311          $expiry_status = param( 'expiry_status', 'string', 'active' );
 312          $item_ID = param( 'itemid', 'integer' );
 313          $currentpage = param( 'currentpage', 'integer', 1 );
 314          $limit = param( 'limit', 'integer', 0 );
 315  
 316          foreach( $commentIds as $commentID )
 317          {
 318              $edited_Comment = & Comment_get_by_ID( $commentID, false );
 319              if( $edited_Comment !== false )
 320              { // The comment still exists
 321                  // Check permission:
 322                  $current_User->check_perm( 'comment!CURSTATUS', 'delete', true, $edited_Comment );
 323  
 324                  $edited_Comment->dbdelete();
 325              }
 326          }
 327  
 328          if( strlen($statuses) > 2 )
 329          {
 330              $statuses = substr( $statuses, 1, strlen($statuses) - 2 );
 331          }
 332          $status_list = explode( ',', $statuses );
 333          if( $status_list == NULL )
 334          {
 335              $status_list = get_visibility_statuses( 'keys', array( 'redirected', 'trash' ) );
 336          }
 337  
 338          // In case of comments_fullview we must set a filterset name to be abble to restore filterset.
 339          // If $item_ID is not valid, then this requests came from the comments_fullview
 340          // TODO: asimo> This should be handled with a better solution
 341          $filterset_name = /*'';*/( $item_ID > 0 ) ? '' : 'fullview';
 342          if( $limit == 0 )
 343          {
 344              $limit = $UserSettings->get( 'results_per_page' ); 
 345          }
 346          echo_item_comments( $blog, $item_ID, $status_list, $currentpage, $limit, array(), $filterset_name, $expiry_status );
 347          break;
 348  
 349      case 'delete_comment_url':
 350          // Delete spam URL from a comment directly in the dashboard - comment remains otherwise untouched
 351  
 352          // Check that this action request is not a CSRF hacked request:
 353          $Session->assert_received_crumb( 'comment' );
 354  
 355          // Check comment edit permission below after we have the $edited_Comment object
 356  
 357          $blog = param( 'blogid', 'integer' );
 358          $edited_Comment = & Comment_get_by_ID( param( 'commentid', 'integer' ), false );
 359          if( $edited_Comment !== false && $edited_Comment->author_url != NULL )
 360          {    // The comment still exists
 361              // Check permission:
 362              $current_User->check_perm( 'comment!CURSTATUS', 'edit', true, $edited_Comment );
 363  
 364              $edited_Comment->set( 'author_url', NULL );
 365              $edited_Comment->dbupdate();
 366          }
 367  
 368          break;
 369  
 370      case 'refresh_comments':
 371          // Refresh the comments list on dashboard by clicking on the refresh icon or after ban url
 372  
 373          // Check that this action request is not a CSRF hacked request:
 374          $Session->assert_received_crumb( 'comment' );
 375  
 376          $is_admin_page = true;
 377          $blog = param( 'blogid', 'integer' );
 378          // Check minimum permissions ( The comment specific permissions are checked when displaying the comments )
 379          $current_User->check_perm( 'blog_ismember', 'view', true, $blog );
 380  
 381          get_comments_awaiting_moderation( $blog );
 382          break;
 383  
 384      case 'refresh_item_comments':
 385          // Refresh item comments on the item view screen, or refresh all blog comments on comments view, if param itemid = -1
 386          // A refresh is used on the actions:
 387          // 1) click on the refresh icon.
 388          // 2) limit by selected status(radioboxes 'Draft', 'Published', 'All comments').
 389          // 3) ban by url of a comment
 390  
 391          load_funcs( 'items/model/_item.funcs.php' );
 392  
 393          $is_admin_page = true;
 394          $blog = param( 'blogid', 'integer' );
 395          $item_ID = param( 'itemid', 'integer', NULL );
 396          $statuses = param( 'statuses', 'string', NULL );
 397          $expiry_status = param( 'expiry_status', 'string', 'active' );
 398          $currentpage = param( 'currentpage', 'string', 1 );
 399  
 400          // Check minimum permissions ( The comment specific permissions are checked when displaying the comments )
 401          $current_User->check_perm( 'blog_ismember', 'view', true, $blog );
 402  
 403          if( strlen($statuses) > 2 )
 404          {
 405              $statuses = substr( $statuses, 1, strlen($statuses) - 2 );
 406          }
 407          $status_list = explode( ',', $statuses );
 408          if( $status_list == NULL )
 409          { // init statuses
 410              $status_list = get_visibility_statuses( 'keys', array( 'redirected', 'trash' ) );
 411          }
 412  
 413          echo_item_comments( $blog, $item_ID, $status_list, $currentpage, 20, array(), '', $expiry_status );
 414          break;
 415  
 416      case 'get_tags':
 417          // Get list of item tags, where $term is part of the tag name (sorted)
 418          // To be used for Tag autocompletion
 419  
 420          // Crumb check and permission check are not required because this won't modify anything and it returns public info
 421  
 422          $term = param('term', 'string');
 423  
 424          $tags = $DB->get_results( '
 425              SELECT tag_name AS id, tag_name AS title
 426                FROM T_items__tag
 427               WHERE tag_name LIKE '.$DB->quote('%'.$term.'%').'
 428               ORDER BY tag_name', ARRAY_A );
 429  
 430          // Check if current term is not an existing tag
 431          $term_is_new_tag = true;
 432          foreach( $tags as $tag )
 433          {
 434              if( $tag['title'] == $term )
 435              { // Current term is an existing tag
 436                  $term_is_new_tag = false;
 437              }
 438          }
 439          if( $term_is_new_tag )
 440          {    // Add current term in the beginning of the tags list
 441              array_unshift( $tags, array( 'id' => $term, 'title' => $term ) );
 442          }
 443  
 444          echo evo_json_encode( $tags );
 445          exit(0);
 446  
 447      case 'dom_type_edit':
 448          // Update type of a reffering domain from list screen by clicking on the type column
 449  
 450          // Check that this action request is not a CSRF hacked request:
 451          $Session->assert_received_crumb( 'domtype' );
 452  
 453          // Check permission:
 454          $current_User->check_perm( 'stats', 'edit', true );
 455  
 456          load_funcs('sessions/model/_hitlog.funcs.php');
 457  
 458          $dom_type = param( 'new_dom_type', 'string' );
 459          $dom_name = param( 'dom_name', 'string' );
 460  
 461          $DB->query( 'UPDATE T_basedomains
 462                          SET dom_type = '.$DB->quote($dom_type).'
 463                          WHERE dom_name =' . $DB->quote($dom_name));
 464          echo '<a href="#" rel="'.$dom_type.'">'.stats_dom_type_title( $dom_type ).'</a>';
 465          break;
 466  
 467      case 'iprange_status_edit':
 468          // Update status of IP range from list screen by clicking on the status column
 469  
 470          // Check that this action request is not a CSRF hacked request:
 471          $Session->assert_received_crumb( 'iprange' );
 472  
 473          // Check permission:
 474          $current_User->check_perm( 'spamblacklist', 'edit', true );
 475  
 476          $new_status = param( 'new_status', 'string' );
 477          $iprange_ID = param( 'iprange_ID', 'integer', true );
 478  
 479          $DB->query( 'UPDATE T_antispam__iprange
 480                          SET aipr_status = '.( empty( $new_status ) ? 'NULL' : $DB->quote( $new_status ) ).'
 481                          WHERE aipr_ID =' . $DB->quote( $iprange_ID ) );
 482          echo '<a href="#" rel="'.$new_status.'" color="'.aipr_status_color( $new_status ).'">'.aipr_status_title( $new_status ).'</a>';
 483          break;
 484  
 485      case 'emblk_status_edit':
 486          // Update blocked status of email address
 487  
 488          // Check that this action request is not a CSRF hacked request:
 489          $Session->assert_received_crumb( 'emblkstatus' );
 490  
 491          // Check permission:
 492          $current_User->check_perm( 'emails', 'edit', true );
 493  
 494          $new_status = param( 'new_status', 'string' );
 495          $emblk_ID = param( 'emblk_ID', 'integer', true );
 496  
 497          load_funcs('tools/model/_email.funcs.php');
 498  
 499          $DB->query( 'UPDATE T_email__blocked
 500                          SET emblk_status = '.( empty( $new_status ) ? 'NULL' : $DB->quote( $new_status ) ).'
 501                          WHERE emblk_ID =' . $DB->quote( $emblk_ID ) );
 502          echo '<a href="#" rel="'.$new_status.'" color="'.emblk_get_status_color( $new_status ).'">'.emblk_get_status_title( $new_status ).'</a>';
 503          break;
 504  
 505      case 'user_level_edit':
 506          // Update level of an user from list screen by clicking on the level column
 507  
 508          // Check that this action request is not a CSRF hacked request:
 509          $Session->assert_received_crumb( 'userlevel' );
 510  
 511          // Check permission:
 512          $current_User->check_perm( 'users', 'edit', true );
 513  
 514          $user_level = param( 'new_user_level', 'integer' );
 515          $user_ID = param( 'user_ID', 'string' );
 516  
 517          $UserCache = & get_UserCache();
 518          if( $User = & $UserCache->get_by_ID( $user_ID, false ) )
 519          {
 520              $User->set( 'level', $user_level );
 521              $User->dbupdate();
 522              echo '<a href="#" rel="'.$user_level.'">'.$user_level.'</a>';
 523          }
 524          break;
 525  
 526      default:
 527          $incorrect_action = true;
 528          break;
 529  }
 530  
 531  if( !$incorrect_action )
 532  {
 533      if( $current_debug || $current_debug_jslog )
 534      {    // debug is ON
 535          $Ajaxlog->display( NULL, NULL, true, 'all',
 536                          array(
 537                                  'error' => array( 'class' => 'jslog_error', 'divClass' => false ),
 538                                  'note'  => array( 'class' => 'jslog_note',  'divClass' => false ),
 539                              ), 'ul', 'jslog' );
 540      }
 541  
 542      if( $add_response_end_comment )
 543      { // add ajax response end comment
 544          echo '<!-- Ajax response end -->';
 545      }
 546  
 547      exit(0);
 548  }
 549  
 550  /**
 551   * Get comments awaiting moderation
 552   *
 553   * @param integer blog_ID
 554   */
 555  function get_comments_awaiting_moderation( $blog_ID )
 556  {
 557      $limit = 5;
 558  
 559      load_funcs( 'dashboard/model/_dashboard.funcs.php' );
 560      show_comments_awaiting_moderation( $blog_ID, NULL, $limit, array(), false );
 561  }
 562  
 563  ?>

title

Description

title

Description

title

Description

title

title

Body