[ Index ]
 

Code source de GeekLog 1.4.1

Accédez au Source d'autres logiciels libres

title

Body

[fermer]

/public_html/ -> lib-common.php (source)

   1  <?php
   2  
   3  /* Reminder: always indent with 4 spaces (no tabs). */
   4  // +---------------------------------------------------------------------------+
   5  // | Geeklog 1.4                                                               |
   6  // +---------------------------------------------------------------------------+
   7  // | lib-common.php                                                            |
   8  // |                                                                           |
   9  // | Geeklog common library.                                                   |
  10  // +---------------------------------------------------------------------------+
  11  // | Copyright (C) 2000-2006 by the following authors:                         |
  12  // |                                                                           |
  13  // | Authors: Tony Bibbs        - tony AT tonybibbs DOT com                    |
  14  // |          Mark Limburg      - mlimburg AT users DOT sourceforge DOT net    |
  15  // |          Jason Whittenburg - jwhitten AT securitygeeks DOT com            |
  16  // |          Dirk Haun         - dirk AT haun-online DOT de                   |
  17  // |          Vincent Furia     - vinny01 AT users DOT sourceforge DOT net     |
  18  // +---------------------------------------------------------------------------+
  19  // |                                                                           |
  20  // | This program is free software; you can redistribute it and/or             |
  21  // | modify it under the terms of the GNU General Public License               |
  22  // | as published by the Free Software Foundation; either version 2            |
  23  // | of the License, or (at your option) any later version.                    |
  24  // |                                                                           |
  25  // | This program is distributed in the hope that it will be useful,           |
  26  // | but WITHOUT ANY WARRANTY; without even the implied warranty of            |
  27  // | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             |
  28  // | GNU General Public License for more details.                              |
  29  // |                                                                           |
  30  // | You should have received a copy of the GNU General Public License         |
  31  // | along with this program; if not, write to the Free Software Foundation,   |
  32  // | Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.           |
  33  // |                                                                           |
  34  // +---------------------------------------------------------------------------+
  35  //
  36  // $Id: lib-common.php,v 1.611 2006/12/16 18:10:37 dhaun Exp $
  37  
  38  // Prevent PHP from reporting uninitialized variables
  39  error_reporting( E_ERROR | E_WARNING | E_PARSE | E_COMPILE_ERROR );
  40  
  41  /**
  42  * This is the common library for Geeklog.  Through our code, you will see
  43  * functions with the COM_ prefix (e.g. COM_siteHeader()).  Any such functions
  44  * can be found in this file.  This file provides all configuration variables
  45  * needed by Geeklog with a series of includes (see futher down).
  46  *
  47  * --- You only need to modify one line in this file! ---
  48  *
  49  * WARNING: put any custom hacks in lib-custom.php and not in here.  This file is
  50  * modified frequently by the Geeklog development team.  If you put your hacks in
  51  * lib-custom.php you will find upgrading much easier.
  52  *
  53  */
  54  
  55  /**
  56  * Turn this on to get various debug messages from the code in this library
  57  * @global Boolean $_COM_VERBOSE
  58  */
  59  
  60  $_COM_VERBOSE = false;
  61  
  62  /**
  63    * Here, we shall establish an error handler. This will mean that whenever a
  64    * php level error is encountered, our own code handles it. This will hopefuly
  65    * go someway towards preventing nasties like path exposures from ever being
  66    * possible. That is, unless someone has overridden our error handler with one
  67    * with a path exposure issue...
  68    *
  69    * Must make sure that the function hasn't been disabled before calling it.
  70    *
  71    */
  72  if( function_exists('set_error_handler') )
  73  {
  74      if( PHP_VERSION >= 5 )
  75      {
  76          /* Tell the error handler to use the default error reporting options.
  77           * you may like to change this to use it in more/less cases, if so,
  78           * just use the syntax used in the call to error_reporting() above.
  79           */
  80          $defaultErrorHandler = set_error_handler('COM_handleError', error_reporting());
  81      } else {
  82          $defaultErrorHandler = set_error_handler('COM_handleError');
  83      }
  84  }
  85  
  86  /**
  87  * Configuration Include: You should ONLY have to modify this line.
  88  * Leave the rest of this file intact!
  89  *
  90  * Make sure to include the name of the config file,
  91  * i.e. the path should end in .../config.php
  92  */
  93  require_once( '/path/to/geeklog/config.php' );
  94  
  95  // Before we do anything else, check to ensure site is enabled
  96  
  97  if( isset( $_CONF['site_enabled'] ) && !$_CONF['site_enabled'] )
  98  {
  99      if( empty( $_CONF['site_disabled_msg'] ))
 100      {
 101          echo $_CONF['site_name'] . ' is temporarily down.  Please check back soon';
 102      }
 103      else
 104      {
 105          // if the msg starts with http: assume it's a URL we should redirect to
 106          if( preg_match( "/^(https?):/", $_CONF['site_disabled_msg'] ) === 1 )
 107          {
 108              echo COM_refresh( $_CONF['site_disabled_msg'] );
 109          }
 110          else
 111          {
 112              echo $_CONF['site_disabled_msg'];
 113          }
 114      }
 115  
 116      exit;
 117  }
 118  
 119  // this file can't be used on its own - redirect to index.php
 120  if( strpos( $_SERVER['PHP_SELF'], 'lib-common.php' ) !== false )
 121  {
 122      echo COM_refresh( $_CONF['site_url'] . '/index.php' );
 123      exit;
 124  }
 125  
 126  // timezone hack - set the webserver's timezone
 127  if( !empty( $_CONF['timezone'] ) && !ini_get( 'safe_mode' ) &&
 128          function_exists( 'putenv' )) {
 129      putenv( 'TZ=' . $_CONF['timezone'] );
 130  }
 131  
 132  
 133  // +---------------------------------------------------------------------------+
 134  // | Library Includes: You shouldn't have to touch anything below here         |
 135  // +---------------------------------------------------------------------------+
 136  
 137  /**
 138  * If needed, add our PEAR path to the list of include paths
 139  *
 140  */
 141  if( !$_CONF['have_pear'] )
 142  {
 143      $curPHPIncludePath = ini_get( 'include_path' );
 144      if( defined( 'PATH_SEPARATOR' ))
 145      {
 146          $separator = PATH_SEPARATOR;
 147      }
 148      else
 149      {
 150          // prior to PHP 4.3.0, we have to guess the correct separator ...
 151          $separator = ';';
 152          if( strpos( $curPHPIncludePath, $separator ) === false )
 153          {
 154              $separator = ':';
 155          }
 156      }
 157      if( ini_set( 'include_path', $_CONF['path_pear'] . $separator
 158                                   . $curPHPIncludePath ) === false )
 159      {
 160          COM_errorLog( 'ini_set failed - there may be problems using the PEAR classes.', 1);
 161      }
 162  }
 163  
 164  
 165  /**
 166  * This is necessary to ensure compatibility with PHP 4.1.x
 167  *
 168  */
 169  if( !function_exists( 'is_a' ))
 170  {
 171      require_once( 'PHP/Compat.php' );
 172  
 173      PHP_Compat::loadFunction( 'is_a' );
 174  }
 175  
 176  
 177  /**
 178  * Include page time -- used to time how fast each page was created
 179  *
 180  */
 181  
 182  require_once( $_CONF['path_system'] . 'classes/timer.class.php' );
 183  $_PAGE_TIMER = new timerobject();
 184  $_PAGE_TIMER->startTimer();
 185  
 186  /**
 187  * Include URL class
 188  *
 189  * This provides optional URL rewriting functionality.
 190  * Please note this code is still experimental and is only currently used by the
 191  * staticpages plugin.
 192  */
 193  
 194  require_once( $_CONF['path_system'] . 'classes/url.class.php' );
 195  $_URL = new url( $_CONF['url_rewrite'] );
 196  
 197  /**
 198  * This is our HTML template class.  It is the same one found in PHPLib and is
 199  * licensed under the LGPL.  See that file for details
 200  *
 201  */
 202  
 203  require_once( $_CONF['path_system'] . 'classes/template.class.php' );
 204  
 205  /**
 206  * This is the database library.
 207  *
 208  * Including this gives you a working connection to the database
 209  *
 210  */
 211  
 212  require_once( $_CONF['path_system'] . 'lib-database.php' );
 213  
 214  /**
 215  * This is the security library used for application security
 216  *
 217  */
 218  
 219  require_once( $_CONF['path_system'] . 'lib-security.php' );
 220  
 221  /**
 222  * This is the syndication library used to offer (RSS) feeds.
 223  *
 224  */
 225  
 226  require_once( $_CONF['path_system'] . 'lib-syndication.php' );
 227  
 228  /**
 229  * This is the custom library.
 230  *
 231  * It is the sandbox for every Geeklog Admin to play in.
 232  * We will never modify this file.  This should hold all custom
 233  * hacks to make upgrading easier.
 234  *
 235  */
 236  
 237  require_once( $_CONF['path_system'] . 'lib-custom.php' );
 238  
 239  /**
 240  * Include plugin class.
 241  * This is a poorly implemented class that was not very well thought out.
 242  * Still very necessary
 243  *
 244  */
 245  
 246  require_once( $_CONF['path_system'] . 'lib-plugins.php' );
 247  
 248  /**
 249  * Session management library
 250  *
 251  */
 252  
 253  require_once( $_CONF['path_system'] . 'lib-sessions.php' );
 254  
 255  /**
 256  * Ulf Harnhammar's kses class
 257  *
 258  */
 259  
 260  require_once( $_CONF['path_system'] . 'classes/kses.class.php' );
 261  
 262  /**
 263  * Multibyte functions
 264  *
 265  */
 266  require_once( $_CONF['path_system'] . 'lib-mbyte.php' );
 267  
 268  // Set theme
 269  // Need to modify this code to check if theme was cached in user cookie.  That
 270  // way if user logged in and set theme and then logged out we would still know
 271  // which theme to show them.
 272  
 273  $usetheme = '';
 274  if( isset( $_POST['usetheme'] ))
 275  {
 276      $usetheme = preg_replace( '/[^a-zA-Z0-9\-_\.]/', '', $_POST['usetheme'] );
 277      $usetheme = str_replace( '..', '', $usetheme );
 278  }
 279  if( !empty( $usetheme ) && is_dir( $_CONF['path_themes'] . $usetheme ))
 280  {
 281      $_CONF['theme'] = $usetheme;
 282      $_CONF['path_layout'] = $_CONF['path_themes'] . $_CONF['theme'] . '/';
 283      $_CONF['layout_url'] = $_CONF['site_url'] . '/layout/' . $_CONF['theme'];
 284  }
 285  else if( $_CONF['allow_user_themes'] == 1 )
 286  {
 287      if( isset( $_COOKIE[$_CONF['cookie_theme']] ) && empty( $_USER['theme'] ))
 288      {
 289          $theme = preg_replace( '/[^a-zA-Z0-9\-_\.]/', '',
 290                                 $_COOKIE[$_CONF['cookie_theme']] );
 291          $theme = str_replace( '..', '', $theme );
 292          if( is_dir( $_CONF['path_themes'] . $theme ))
 293          {
 294              $_USER['theme'] = $theme;
 295          }
 296      }
 297  
 298      if( !empty( $_USER['theme'] ))
 299      {
 300          if( is_dir( $_CONF['path_themes'] . $_USER['theme'] ))
 301          {
 302              $_CONF['theme'] = $_USER['theme'];
 303              $_CONF['path_layout'] = $_CONF['path_themes'] . $_CONF['theme'] . '/';
 304              $_CONF['layout_url'] = $_CONF['site_url'] . '/layout/' . $_CONF['theme'];
 305          }
 306          else
 307          {
 308              $_USER['theme'] = $_CONF['theme'];
 309          }
 310      }
 311  }
 312  
 313  /**
 314  * Include theme functions file
 315  */
 316  
 317  // Include theme functions file which may/may not do anything
 318  
 319  if( file_exists( $_CONF['path_layout'] . 'functions.php' ))
 320  {
 321      require_once( $_CONF['path_layout'] . 'functions.php' );
 322  }
 323  
 324  // themes can now specify the default image type
 325  // fall back to 'gif' if they don't
 326  
 327  if( empty( $_IMAGE_TYPE ))
 328  {
 329      $_IMAGE_TYPE = 'gif';
 330  }
 331  
 332  // Similarly set language
 333  
 334  if( isset( $_COOKIE[$_CONF['cookie_language']] ) && empty( $_USER['language'] ))
 335  {
 336      $language = preg_replace( '/[^a-z0-9\-_]/', '',
 337                                $_COOKIE[$_CONF['cookie_language']] );
 338      if( is_file( $_CONF['path_language'] . $language . '.php' ) &&
 339              ( $_CONF['allow_user_language'] == 1 ))
 340      {
 341          $_USER['language'] = $language;
 342          $_CONF['language'] = $language;
 343      }
 344  }
 345  else if( !empty( $_USER['language'] ))
 346  {
 347      if( is_file( $_CONF['path_language'] . $_USER['language'] . '.php' ) &&
 348              ( $_CONF['allow_user_language'] == 1 ))
 349      {
 350          $_CONF['language'] = $_USER['language'];
 351      }
 352  }
 353  else if( isset( $_CONF['languages'] ) && isset( $_CONF['language_files'] ))
 354  {
 355      $_CONF['language'] = COM_getLanguage();
 356  }
 357  
 358  // Handle Who's Online block
 359  if( empty( $_USER['uid'] ) OR $_USER['uid'] == 1 )
 360  {
 361      // The following code handles anonymous users so they show up properly
 362      DB_query( "DELETE FROM {$_TABLES['sessions']} WHERE remote_ip = '{$_SERVER['REMOTE_ADDR']}' AND uid = 1" );
 363  
 364      $tries = 0;
 365      do
 366      {
 367          // Build a useless sess_id (needed for insert to work properly)
 368          mt_srand(( double )microtime() * 1000000 );
 369          $sess_id = mt_rand();
 370          $curtime = time();
 371  
 372          // Insert anonymous user session
 373          $result = DB_query( "INSERT INTO {$_TABLES['sessions']} (sess_id, start_time, remote_ip, uid) VALUES ($sess_id, $curtime, '{$_SERVER['REMOTE_ADDR']}', 1)", 1 );
 374          $tries++;
 375      }
 376      while(( $result === false) && ( $tries < 5 ));
 377  }
 378  
 379  // Clear out any expired sessions
 380  DB_query( "DELETE FROM {$_TABLES['sessions']} WHERE uid = 1 AND start_time < " . ( time() - $_CONF['whosonline_threshold'] ));
 381  
 382  /**
 383  *
 384  * Language include
 385  *
 386  */
 387  
 388  require_once( $_CONF['path_language'] . $_CONF['language'] . '.php' );
 389  
 390  COM_switchLocaleSettings();
 391  
 392  if( setlocale( LC_ALL, $_CONF['locale'] ) === false )
 393  {
 394      setlocale( LC_TIME, $_CONF['locale'] );
 395  }
 396  
 397  /**
 398  * Global array of groups current user belongs to
 399  *
 400  * @global array $_GROUPS
 401  *
 402  */
 403  
 404  if( isset( $_USER['uid'] ))
 405  {
 406      $_GROUPS = SEC_getUserGroups( $_USER['uid'] );
 407  }
 408  else
 409  {
 410      $_GROUPS = SEC_getUserGroups( 1 );
 411  }
 412  
 413  /**
 414  * Global array of current user permissions [read,edit]
 415  *
 416  * @global array $_RIGHTS
 417  *
 418  */
 419  
 420  $_RIGHTS = explode( ',', SEC_getUserPermissions() );
 421  
 422  if( isset( $_GET['topic'] ))
 423  {
 424      $topic = COM_applyFilter( $_GET['topic'] );
 425  }
 426  else if( isset( $_POST['topic'] ))
 427  {
 428      $topic = COM_applyFilter( $_POST['topic'] );
 429  }
 430  else
 431  {
 432      $topic = '';
 433  }
 434  
 435  
 436  // +---------------------------------------------------------------------------+
 437  // | HTML WIDGETS                                                              |
 438  // +---------------------------------------------------------------------------+
 439  
 440  /**
 441  * Return the file to use for a block template.
 442  *
 443  * This returns the template needed to build the HTML for a block.  This function
 444  * allows designers to give a block it's own custom look and feel.  If no
 445  * templates for the block are specified, the default blockheader.html and
 446  * blockfooter.html will be used.
 447  *
 448  * @param        string      $blockname      corresponds to name field in block table
 449  * @param        string      $which          can be either 'header' or 'footer' for corresponding template
 450  * @see function COM_startBlock
 451  * @see function COM_endBlock
 452  * @see function COM_showBlocks
 453  * @see function COM_showBlock
 454  * @return   string  template name
 455  */
 456  function COM_getBlockTemplate( $blockname, $which )
 457  {
 458      global $_BLOCK_TEMPLATE, $_COM_VERBOSE;
 459  
 460      if( $_COM_VERBOSE )
 461      {
 462          COM_errorLog( "_BLOCK_TEMPLATE[$blockname] = " . $_BLOCK_TEMPLATE[$blockname], 1 );
 463      }
 464  
 465      if( !empty( $_BLOCK_TEMPLATE[$blockname] ))
 466      {
 467          $templates = explode( ',', $_BLOCK_TEMPLATE[$blockname] );
 468          if( $which == 'header' )
 469          {
 470              if( !empty( $templates[0] ))
 471              {
 472                  $template = $templates[0];
 473              }
 474              else
 475              {
 476                  $template = 'blockheader.thtml';
 477              }
 478          }
 479          else
 480          {
 481              if( !empty( $templates[1] ))
 482              {
 483                  $template = $templates[1];
 484              }
 485              else
 486              {
 487                  $template = 'blockfooter.thtml';
 488              }
 489          }
 490      }
 491      else
 492      {
 493          if( $which == 'header' )
 494          {
 495              $template = 'blockheader.thtml';
 496          }
 497          else
 498          {
 499              $template = 'blockfooter.thtml';
 500          }
 501      }
 502  
 503      if( $_COM_VERBOSE )
 504      {
 505          COM_errorLog( "Block template for the $which of $blockname is: $template", 1 );
 506      }
 507  
 508      return $template;
 509  }
 510  
 511  /**
 512  * Gets all installed themes
 513  *
 514  * Returns a list of all the directory names in $_CONF['path_themes'], i.e.
 515  * a list of all the theme names.
 516  *
 517  * @param    bool    $all    if true, return all themes even if users aren't allowed to change their default themes
 518  * @return   array           All installed themes
 519  *
 520  */
 521  function COM_getThemes( $all = false )
 522  {
 523      global $_CONF;
 524  
 525      $index = 1;
 526  
 527      $themes = array();
 528  
 529      $fd = opendir( $_CONF['path_themes'] );
 530  
 531      // If users aren't allowed to change their theme then only return the default theme
 532  
 533      if(( $_CONF['allow_user_themes'] == 0 ) && !$all )
 534      {
 535          $themes[$index] = $_CONF['theme'];
 536      }
 537      else
 538      {
 539          while(( $dir = @readdir( $fd )) == TRUE )
 540          {
 541              if( is_dir( $_CONF['path_themes'] . $dir) && $dir <> '.' && $dir <> '..' && $dir <> 'CVS' && substr( $dir, 0 , 1 ) <> '.' )
 542              {
 543                  clearstatcache();
 544                  $themes[$index] = $dir;
 545                  $index++;
 546              }
 547          }
 548      }
 549  
 550      return $themes;
 551  }
 552  
 553  /**
 554  * Create the menu, i.e. replace {menu_elements} in the site header with the
 555  * actual menu entries.
 556  *
 557  * @param    Template    $header     reference to the header template
 558  * @param    array       $plugin_menu    array of plugin menu entries, if any
 559  *
 560  */
 561  function COM_renderMenu( &$header, $plugin_menu )
 562  {
 563      global $_CONF, $_USER, $LANG01, $topic;
 564  
 565      if( empty( $_CONF['menu_elements'] ))
 566      {
 567          $_CONF['menu_elements'] = array( // default set of links
 568                  'contribute', 'search', 'stats', 'directory', 'plugins' );
 569      }
 570  
 571      $anon = ( empty( $_USER['uid'] ) || ( $_USER['uid'] <= 1 )) ? true : false;
 572      $menuCounter = 0;
 573      $allowedCounter = 0;
 574      $counter = 0;
 575  
 576      $num_plugins = sizeof( $plugin_menu );
 577      if( ( $num_plugins == 0 ) && in_array( 'plugins', $_CONF['menu_elements'] ))
 578      {
 579          $key = array_search( 'plugins', $_CONF['menu_elements'] );
 580          unset( $_CONF['menu_elements'][$key] );
 581      }
 582  
 583      if( in_array( 'custom', $_CONF['menu_elements'] ))
 584      {
 585          $custom_entries = array();
 586          if( function_exists( 'CUSTOM_menuEntries' ))
 587          {
 588              $custom_entries = CUSTOM_menuEntries();
 589          }
 590          if( sizeof( $custom_entries ) == 0 )
 591          {
 592              $key = array_search( 'custom', $_CONF['menu_elements'] );
 593              unset( $_CONF['menu_elements'][$key] );
 594          }
 595      }
 596  
 597      $num_elements = sizeof( $_CONF['menu_elements'] );
 598  
 599      foreach( $_CONF['menu_elements'] as $item )
 600      {
 601          $counter++;
 602          $allowed = true;
 603          $last_entry = ( $counter == $num_elements ) ? true : false;
 604  
 605          switch( $item )
 606          {
 607              case 'contribute':
 608                  if( empty( $topic ))
 609                  {
 610                      $url = $_CONF['site_url'] . '/submit.php?type=story';
 611                      $header->set_var( 'current_topic', '' );
 612                  }
 613                  else
 614                  {
 615                      $url = $_CONF['site_url']
 616                           . '/submit.php?type=story&amp;topic=' . $topic;
 617                      $header->set_var( 'current_topic', '&amp;topic=' . $topic );
 618                  }
 619                  $label = $LANG01[71];
 620                  if( $anon && ( $_CONF['loginrequired'] ||
 621                          $_CONF['submitloginrequired'] ))
 622                  {
 623                      $allowed = false;
 624                  }
 625                  break;
 626  
 627              case 'custom':
 628                  $custom_count = 0;
 629                  $custom_size = sizeof( $custom_entries );
 630                  foreach( $custom_entries as $entry )
 631                  {
 632                      $custom_count++;
 633  
 634                      if( empty( $entry['url'] ) || empty( $entry['label'] ))
 635                      {
 636                          continue;
 637                      }
 638  
 639                      $header->set_var( 'menuitem_url',  $entry['url'] );
 640                      $header->set_var( 'menuitem_text', $entry['label'] );
 641  
 642                      if( $last_entry && ( $custom_count == $custom_size ))
 643                      {
 644                          $header->parse( 'menu_elements', 'menuitem_last',
 645                                          true );
 646                      }
 647                      else
 648                      {
 649                          $header->parse( 'menu_elements', 'menuitem', true );
 650                      }
 651                      $menuCounter++;
 652                  }
 653                  $url = '';
 654                  $label = '';
 655                  break;
 656  
 657              case 'directory':
 658                  $url = $_CONF['site_url'] . '/directory.php';
 659                  if( !empty( $topic ))
 660                  {
 661                      $url = COM_buildUrl( $url . '?topic='
 662                                           . urlencode( $topic ));
 663                  }
 664                  $label = $LANG01[117];
 665                  if( $anon && ( $_CONF['loginrequired'] ||
 666                          $_CONF['directoryloginrequired'] ))
 667                  {
 668                      $allowed = false;
 669                  }
 670                  break;
 671  
 672              case 'home':
 673                  $url = $_CONF['site_url'] . '/';
 674                  $label = $LANG01[90];
 675                  break;
 676  
 677              case 'plugins':
 678                  for( $i = 1; $i <= $num_plugins; $i++ )
 679                  {
 680                      $header->set_var( 'menuitem_url', current( $plugin_menu ));
 681                      $header->set_var( 'menuitem_text', key( $plugin_menu ));
 682  
 683                      if( $last_entry && ( $i == $num_plugins ))
 684                      {
 685                          $header->parse( 'menu_elements', 'menuitem_last',
 686                                          true );
 687                      }
 688                      else
 689                      {
 690                          $header->parse( 'menu_elements', 'menuitem', true );
 691                      }
 692                      $menuCounter++;
 693  
 694                      next( $plugin_menu );
 695                  }
 696                  $url = '';
 697                  $label = '';
 698                  break;
 699  
 700              case 'prefs':
 701                  $url = $_CONF['site_url'] . '/usersettings.php?mode=edit';
 702                  $label = $LANG01[48];
 703                  break;
 704  
 705              case 'search':
 706                  $url = $_CONF['site_url'] . '/search.php';
 707                  $label = $LANG01[75];
 708                  if( $anon && ( $_CONF['loginrequired'] ||
 709                          $_CONF['searchloginrequired'] ))
 710                  {
 711                      $allowed = false;
 712                  }
 713                  break;
 714  
 715              case 'stats':
 716                  $url = $_CONF['site_url'] . '/stats.php';
 717                  $label = $LANG01[76];
 718                  if( $anon &&
 719                      ( $_CONF['loginrequired'] || $_CONF['statsloginrequired'] ))
 720                  {
 721                      $allowed = false;
 722                  }
 723                  break;
 724  
 725              default: // unknown entry
 726                  $url = '';
 727                  $label = '';
 728                  break;
 729          }
 730  
 731          if( !empty( $url ) && !empty( $label ))
 732          {
 733              $header->set_var( 'menuitem_url',  $url );
 734              $header->set_var( 'menuitem_text', $label );
 735              if( $last_entry )
 736              {
 737                  $header->parse( 'menu_elements', 'menuitem_last', true );
 738              }
 739              else
 740              {
 741                  $header->parse( 'menu_elements', 'menuitem', true );
 742              }
 743              $menuCounter++;
 744  
 745              if( $allowed )
 746              {
 747                  if( $last_entry )
 748                  {
 749                      $header->parse( 'allowed_menu_elements', 'menuitem_last',
 750                                      true );
 751                  }
 752                  else
 753                  {
 754                      $header->parse( 'allowed_menu_elements', 'menuitem', true );
 755                  }
 756                  $allowedCounter++;
 757              }
 758          }
 759      }
 760  
 761      if( $menuCounter == 0 )
 762      {
 763          $header->parse( 'menu_elements', 'menuitem_none', true );
 764      }
 765      if( $allowedCounter == 0 )
 766      {
 767          $header->parse( 'allowed_menu_elements', 'menuitem_none', true );
 768      }
 769  }
 770  
 771  /**
 772  * Returns the site header
 773  *
 774  * This loads the proper templates, does variable substitution and returns the
 775  * HTML for the site header with or without blocks depending on the value of $what
 776  *
 777  * Programming Note:
 778  *
 779  * The two functions COM_siteHeader and COM_siteFooter provide the framework for
 780  * page display in Geeklog.  COM_siteHeader controls the display of the Header
 781  * and left blocks and COM_siteFooter controls the dsiplay of the right blocks
 782  * and the footer.  You use them like a sandwich.  Thus the following code will
 783  * display a Geeklog page with both right and left blocks displayed.
 784  *
 785  * -------------------------------------------------------------------------------------
 786  * <?php
 787  * require_once('lib-common.php');
 788  * $display .= COM_siteHeader(); //Change to COM_siteHeader('none') to not display left blocks
 789  * $display .= "Here is your html for display";
 790  * $display .= COM_siteFooter(true);  // Change to COM_siteFooter() to not display right blocks
 791  * echo $display;
 792  * ? >
 793  * ---------------------------------------------------------------------------------------
 794  *
 795  * Note that the default for the header is to display the left blocks and the
 796  * default of the footer is to not display the right blocks.
 797  *
 798  * This sandwich produces code like this (greatly simplified)
 799  *
 800  * // COM_siteHeader
 801  * <table><tr><td colspan="3">Header</td></tr>
 802  * <tr><td>Left Blocks</td><td>
 803  *
 804  * // Your HTML goes here
 805  * Here is your html for display
 806  *
 807  * // COM_siteFooter
 808  * </td><td>Right Blocks</td></tr>
 809  * <tr><td colspan="3">Footer</td></table>
 810  *
 811  * @param    string  $what       If 'none' then no left blocks are returned, if 'menu' (default) then right blocks are returned
 812  * @param    string  $pagetitle  optional content for the page's <title>
 813  * @param    string  $headercode optional code to go into the page's <head>
 814  * @return   string              Formatted HTML containing the site header
 815  * @see function COM_siteFooter
 816  *
 817  */
 818  
 819  function COM_siteHeader( $what = 'menu', $pagetitle = '', $headercode = '' )
 820  {
 821      global $_CONF, $_TABLES, $_USER, $LANG01, $LANG_BUTTONS, $LANG_CHARSET,
 822             $LANG_DIRECTION, $_IMAGE_TYPE, $topic, $_COM_VERBOSE;
 823  
 824      // If the theme implemented this for us then call their version instead.
 825  
 826      $function = $_CONF['theme'] . '_siteHeader';
 827  
 828      if( function_exists( $function ))
 829      {
 830          return $function( $what, $pagetitle, $headercode );
 831      }
 832  
 833      // send out the charset header
 834  
 835      if( empty( $LANG_CHARSET )) {
 836          $charset = $_CONF['default_charset'];
 837          if( empty( $charset )) {
 838              $charset = 'iso-8859-1';
 839          }
 840      } else {
 841          $charset = $LANG_CHARSET;
 842      }
 843      header ('Content-Type: text/html; charset=' . $charset);
 844  
 845      // If we reach here then either we have the default theme OR
 846      // the current theme only needs the default variable substitutions
 847  
 848      $header = new Template( $_CONF['path_layout'] );
 849      $header->set_file( array(
 850          'header'        => 'header.thtml',
 851          'menuitem'      => 'menuitem.thtml',
 852          'menuitem_last' => 'menuitem_last.thtml',
 853          'menuitem_none' => 'menuitem_none.thtml',
 854          'leftblocks'    => 'leftblocks.thtml'
 855          ));
 856  
 857      // get topic if not on home page
 858      if( !isset( $_GET['topic'] ))
 859      {
 860          if( isset( $_GET['story'] ))
 861          {
 862              $sid = COM_applyFilter( $_GET['story'] );
 863          }
 864          elseif( isset( $_GET['sid'] ))
 865          {
 866              $sid = COM_applyFilter( $_GET['sid'] );
 867          }
 868          elseif( isset( $_POST['story'] ))
 869          {
 870              $sid = COM_applyFilter( $_POST['story'] );
 871          }
 872          if( empty( $sid ) && $_CONF['url_rewrite'] &&
 873                  ( strpos( $_SERVER['PHP_SELF'], 'article.php' ) !== false ))
 874          {
 875              COM_setArgNames( array( 'story', 'mode' ));
 876              $sid = COM_applyFilter( COM_getArgument( 'story' ));
 877          }
 878          if( !empty( $sid ))
 879          {
 880              $topic = DB_getItem( $_TABLES['stories'], 'tid', "sid='$sid'" );
 881          }
 882      }
 883      else
 884      {
 885          $topic = COM_applyFilter( $_GET['topic'] );
 886      }
 887  
 888      $feed_url = array();
 889      if( $_CONF['backend'] == 1 ) // add feed-link to header if applicable
 890      {
 891          $baseurl = SYND_getFeedUrl();
 892  
 893          $sql = 'SELECT format, filename, title, language FROM '
 894               . $_TABLES['syndication'] . " WHERE (header_tid = 'all')";
 895          if( !empty( $topic ))
 896          {
 897              $sql .= " OR (header_tid = '" . addslashes( $topic ) . "')";
 898          }
 899          $result = DB_query( $sql );
 900          $numRows = DB_numRows( $result );
 901          for( $i = 0; $i < $numRows; $i++ )
 902          {
 903              $A = DB_fetchArray( $result );
 904              if ( !empty( $A['filename'] ))
 905              {
 906                  $format = explode( '-', $A['format'] );
 907                  $format_type = strtolower( $format[0] );
 908                  $format_name = ucwords( $format[0] );
 909  
 910                  $feed_url[] = '<link rel="alternate" type="application/'
 911                            . $format_type . '+xml" hreflang="' . $A['language']
 912                            . '" href="' . $baseurl . $A['filename'] . '" title="'
 913                            . $format_name . ' Feed: ' . $A['title'] . '">';
 914              }
 915          }
 916      }
 917      $header->set_var( 'feed_url', implode( LB, $feed_url ));
 918  
 919      $relLinks = array();
 920      if( !COM_onFrontpage() )
 921      {
 922          $relLinks['home'] = '<link rel="home" href="' . $_CONF['site_url']
 923                            . '/" title="' . $LANG01[90] . '">';
 924      }
 925      $loggedInUser = ( isset( $_USER['uid'] ) && ( $_USER['uid'] > 1 ));
 926      if( $loggedInUser || (( $_CONF['loginrequired'] == 0 ) &&
 927                  ( $_CONF['searchloginrequired'] == 0 )))
 928      {
 929          if(( substr( $_SERVER['PHP_SELF'], -strlen( '/search.php' ))
 930                  != '/search.php' ) || isset( $_GET['mode'] ))
 931          {
 932              $relLinks['search'] = '<link rel="search" href="'
 933                                  . $_CONF['site_url'] . '/search.php" title="'
 934                                  . $LANG01[75] . '">';
 935          }
 936      }
 937      if( $loggedInUser || (( $_CONF['loginrequired'] == 0 ) &&
 938                  ( $_CONF['directoryloginrequired'] == 0 )))
 939      {
 940          if( strpos( $_SERVER['PHP_SELF'], '/article.php' ) !== false ) {
 941              $relLinks['contents'] = '<link rel="contents" href="'
 942                          . $_CONF['site_url'] . '/directory.php" title="'
 943                          . $LANG01[117] . '">';
 944          }
 945      }
 946      // TBD: add a plugin API and a lib-custom.php function
 947      $header->set_var( 'rel_links', implode( LB, $relLinks ));
 948  
 949      if( empty( $pagetitle ) && isset( $_CONF['pagetitle'] ))
 950      {
 951          $pagetitle = $_CONF['pagetitle'];
 952      }
 953      if( empty( $pagetitle ))
 954      {
 955          if( empty( $topic ))
 956          {
 957              $pagetitle = $_CONF['site_slogan'];
 958          }
 959          else
 960          {
 961              $pagetitle = stripslashes( DB_getItem( $_TABLES['topics'], 'topic',
 962                                                     "tid = '$topic'" ));
 963          }
 964      }
 965      if( !empty( $pagetitle ))
 966      {
 967          $pagetitle = ' - ' . $pagetitle;
 968      }
 969      $header->set_var( 'page_title', $_CONF['site_name'] . $pagetitle );
 970  
 971      if( isset( $_CONF['advanced_editor'] ) && ( $_CONF['advanced_editor'] == 1 )
 972              && file_exists( $_CONF['path_layout']
 973                              . 'advanced_editor_header.thtml' ))
 974      {
 975          $header->set_file( 'editor'  , 'advanced_editor_header.thtml');
 976          $header->parse( 'advanced_editor', 'editor' );
 977  
 978      }
 979      else
 980      {
 981           $header->set_var( 'advanced_editor', '' );
 982      }
 983  
 984      $langAttr = '';
 985      if( isset( $_CONF['languages'] ) && isset( $_CONF['language_files'] ))
 986      {
 987          $langId = COM_getLanguageId();
 988      }
 989      else
 990      {
 991          // try to derive the language id from the locale
 992          $l = explode( '.', $_CONF['locale'] );
 993          $langId = $l[0];
 994      }
 995      if( !empty( $langId ))
 996      {
 997          $l = explode( '-', str_replace( '_', '-', $langId ));
 998          if(( count( $l ) == 1 ) && ( strlen( $langId ) == 2 ))
 999          {
1000              $langAttr = 'lang="' . $langId . '"';
1001          }
1002          else if( count( $l ) == 2 )
1003          {
1004              if(( $l[0] == 'i' ) || ( $l[0] == 'x' ))
1005              {
1006                  $langId = implode( '-', $l );
1007                  $langAttr = 'lang="' . $langId . '"';
1008              }
1009              else if( strlen( $l[0] ) == 2 )
1010              {
1011                  $langId = implode( '-', $l );
1012                  $langAttr = 'lang="' . $langId . '"';
1013              }
1014              else
1015              {
1016                  $langId = $l[0];
1017              }
1018          }
1019      }
1020      $header->set_var( 'lang_id', $langId );
1021      $header->set_var( 'lang_attribute', $langAttr );
1022  
1023      $header->set_var( 'background_image', $_CONF['layout_url']
1024                                            . '/images/bg.' . $_IMAGE_TYPE );
1025      $header->set_var( 'site_url', $_CONF['site_url'] );
1026      $header->set_var( 'layout_url', $_CONF['layout_url'] );
1027      $header->set_var( 'site_mail', "mailto:{$_CONF['site_mail']}" );
1028      $header->set_var( 'site_name', $_CONF['site_name'] );
1029      $header->set_var( 'site_slogan', $_CONF['site_slogan'] );
1030      $rdf = substr_replace( $_CONF['rdf_file'], $_CONF['site_url'], 0,
1031                             strlen( $_CONF['path_html'] ) - 1 );
1032      $header->set_var( 'rdf_file', $rdf );
1033      $header->set_var( 'rss_url', $rdf );
1034  
1035      $msg = $LANG01[67] . ' ' . $_CONF['site_name'];
1036  
1037      if( !empty( $_USER['username'] ))
1038      {
1039          $msg .= ', ' . COM_getDisplayName( $_USER['uid'], $_USER['username'],
1040                                             $_USER['fullname'] );
1041      }
1042  
1043      $curtime =  COM_getUserDateTimeFormat();
1044  
1045      $header->set_var( 'welcome_msg', $msg );
1046      $header->set_var( 'datetime', $curtime[0] );
1047      $header->set_var( 'site_logo', $_CONF['layout_url']
1048                                     . '/images/logo.' . $_IMAGE_TYPE );
1049      $header->set_var( 'css_url', $_CONF['layout_url'] . '/style.css' );
1050      $header->set_var( 'theme', $_CONF['theme'] );
1051  
1052      if( empty( $LANG_CHARSET ))
1053      {
1054          $charset = $_CONF['default_charset'];
1055  
1056          if( empty( $charset ))
1057          {
1058              $charset = 'iso-8859-1';
1059          }
1060      }
1061      else
1062      {
1063          $charset = $LANG_CHARSET;
1064      }
1065  
1066      $header->set_var( 'charset', $charset );
1067      if( empty( $LANG_DIRECTION ))
1068      {
1069          // default to left-to-right
1070          $header->set_var( 'direction', 'ltr' );
1071      }
1072      else
1073      {
1074          $header->set_var( 'direction', $LANG_DIRECTION );
1075      }
1076  
1077      // Now add variables for buttons like e.g. those used by the Yahoo theme
1078      $header->set_var( 'button_home', $LANG_BUTTONS[1] );
1079      $header->set_var( 'button_contact', $LANG_BUTTONS[2] );
1080      $header->set_var( 'button_contribute', $LANG_BUTTONS[3] );
1081      $header->set_var( 'button_sitestats', $LANG_BUTTONS[7] );
1082      $header->set_var( 'button_personalize', $LANG_BUTTONS[8] );
1083      $header->set_var( 'button_search', $LANG_BUTTONS[9] );
1084      $header->set_var( 'button_advsearch', $LANG_BUTTONS[10] );
1085      $header->set_var( 'button_directory', $LANG_BUTTONS[11] );
1086  
1087      // Get plugin menu options
1088      $plugin_menu = PLG_getMenuItems();
1089  
1090      if( $_COM_VERBOSE )
1091      {
1092          COM_errorLog( 'num plugin menu items in header = ' . count( $plugin_menu ), 1 );
1093      }
1094  
1095      // Now add nested template for menu items
1096      COM_renderMenu( $header, $plugin_menu );
1097  
1098      if( count( $plugin_menu ) == 0 )
1099      {
1100          $header->parse( 'plg_menu_elements', 'menuitem_none', true );
1101      }
1102      else
1103      {
1104          for( $i = 1; $i <= count( $plugin_menu ); $i++ )
1105          {
1106              $header->set_var( 'menuitem_url', current( $plugin_menu ));
1107              $header->set_var( 'menuitem_text', key( $plugin_menu ));
1108  
1109              if( $i == count( $plugin_menu ))
1110              {
1111                  $header->parse( 'plg_menu_elements', 'menuitem_last', true );
1112              }
1113              else
1114              {
1115                  $header->parse( 'plg_menu_elements', 'menuitem', true );
1116              }
1117  
1118              next( $plugin_menu );
1119          }
1120      }
1121  
1122      if( $_CONF['left_blocks_in_footer'] == 1 )
1123      {
1124          $header->set_var( 'geeklog_blocks', '' );
1125          $header->set_var( 'left_blocks', '' );
1126      }
1127      else
1128      {
1129          $lblocks = '';
1130  
1131          /* Check if an array has been passed that includes the name of a plugin
1132           * function or custom function
1133           * This can be used to take control over what blocks are then displayed
1134           */
1135          if( is_array( $what ))
1136          {
1137              $function = $what[0];
1138              if( function_exists( $function ))
1139              {
1140                  $lblocks = $function( $what[1], 'left' );
1141              }
1142              else
1143              {
1144                  $lblocks = COM_showBlocks( 'left', $topic );
1145              }
1146          }
1147          else if( $what <> 'none' )
1148          {
1149              // Now show any blocks -- need to get the topic if not on home page
1150              $lblocks = COM_showBlocks( 'left', $topic );
1151          }
1152  
1153          if( empty( $lblocks ))
1154          {
1155              $header->set_var( 'geeklog_blocks', '' );
1156              $header->set_var( 'left_blocks', '' );
1157          }
1158          else
1159          {
1160              $header->set_var( 'geeklog_blocks', $lblocks );
1161              $header->parse( 'left_blocks', 'leftblocks', true );
1162          }
1163      }
1164  
1165      // Call any plugin that may want to include extra Meta tags
1166      // or Javascript functions
1167      $header->set_var( 'plg_headercode', $headercode . PLG_getHeaderCode() );
1168  
1169      // Call to plugins to set template variables in the header
1170      PLG_templateSetVars( 'header', $header );
1171  
1172      // The following lines allow users to embed PHP in their templates.  This
1173      // is almost a contradition to the reasons for using templates but this may
1174      // prove useful at times ...
1175      // Don't use PHP in templates if you can live without it!
1176  
1177      $tmp = $header->parse( 'index_header', 'header' );
1178  
1179      ob_start();
1180      eval( '?>' . $tmp );
1181      $retval = ob_get_contents();
1182      ob_end_clean();
1183  
1184      return $retval;
1185  }
1186  
1187  
1188  /**
1189  * Returns the site footer
1190  *
1191  * This loads the proper templates, does variable substitution and returns the
1192  * HTML for the site footer.
1193  *
1194  * @param   boolean     $rightblock     Whether or not to show blocks on right hand side default is no
1195  * @param   array       $custom         An array defining custom function to be used to format Rightblocks
1196  * @see function COM_siteHeader
1197  * @return   string  Formated HTML containing site footer and optionally right blocks
1198  *
1199  */
1200  function COM_siteFooter( $rightblock = -1, $custom = '' )
1201  {
1202      global $_CONF, $_TABLES, $LANG01, $_PAGE_TIMER, $topic;
1203  
1204      if( $rightblock < 0 )
1205      {
1206          if( isset( $_CONF['show_right_blocks'] ))
1207          {
1208              $rightblock = $_CONF['show_right_blocks'];
1209          }
1210          else
1211          {
1212              $rightblock = false;
1213          }
1214      }
1215  
1216      // If the theme implemented this for us then call their version instead.
1217  
1218      $function = $_CONF['theme'] . '_siteFooter';
1219  
1220      if( function_exists( $function ))
1221      {
1222          return $function( $rightblock, $custom );
1223      }
1224  
1225      // Set template directory
1226      $footer = new Template( $_CONF['path_layout'] );
1227  
1228      // Set template file
1229      $footer->set_file( array(
1230              'footer'      => 'footer.thtml',
1231              'rightblocks' => 'rightblocks.thtml',
1232              'leftblocks'  => 'leftblocks.thtml'
1233              ));
1234  
1235      // Do variable assignments
1236      DB_change( $_TABLES['vars'], 'value', 'value + 1', 'name', 'totalhits', '', true );
1237  
1238      $footer->set_var( 'site_url', $_CONF['site_url']);
1239      $footer->set_var( 'layout_url',$_CONF['layout_url']);
1240      $footer->set_var( 'site_mail', "mailto:{$_CONF['site_mail']}" );
1241      $footer->set_var( 'site_name', $_CONF['site_name'] );
1242      $footer->set_var( 'site_slogan', $_CONF['site_slogan'] );
1243      $rdf = substr_replace( $_CONF['rdf_file'], $_CONF['site_url'], 0,
1244                             strlen( $_CONF['path_html'] ) - 1 );
1245      $footer->set_var( 'rdf_file', $rdf );
1246      $footer->set_var( 'rss_url', $rdf );
1247  
1248      $year = date( 'Y' );
1249      $copyrightyear = $year;
1250      if( !empty( $_CONF['copyrightyear'] ))
1251      {
1252          $copyrightyear = $_CONF['copyrightyear'];
1253      }
1254      $footer->set_var( 'copyright_notice', '&nbsp;' . $LANG01[93] . ' &copy; '
1255              . $copyrightyear . ' ' . $_CONF['site_name'] . '<br>&nbsp;'
1256              . $LANG01[94] );
1257      $footer->set_var( 'copyright_msg', $LANG01[93] . ' &copy; '
1258              . $copyrightyear . ' ' . $_CONF['site_name'] );
1259      $footer->set_var( 'current_year', $year );
1260      $footer->set_var( 'lang_copyright', $LANG01[93] );
1261      $footer->set_var( 'trademark_msg', $LANG01[94] );
1262      $footer->set_var( 'powered_by', $LANG01[95] );
1263      $footer->set_var( 'geeklog_url', 'http://www.geeklog.net/' );
1264      $footer->set_var( 'geeklog_version', VERSION );
1265  
1266      /* Check if an array has been passed that includes the name of a plugin
1267       * function or custom function.
1268       * This can be used to take control over what blocks are then displayed
1269       */
1270      if( is_array( $custom ))
1271      {
1272          $function = $custom['0'];
1273          if( function_exists( $function ))
1274          {
1275              $rblocks = $function( $custom['1'], 'right' );
1276          }
1277      }
1278      elseif( $rightblock )
1279      {
1280          $rblocks = COM_showBlocks( 'right', $topic );
1281      }
1282      if( $rightblock && !empty( $rblocks ))
1283      {
1284          $footer->set_var( 'geeklog_blocks', $rblocks );
1285          $footer->parse( 'right_blocks', 'rightblocks', true );
1286      }
1287      else
1288      {
1289          $footer->set_var( 'geeklog_blocks', '' );
1290          $footer->set_var( 'right_blocks', '' );
1291      }
1292  
1293      if( $_CONF['left_blocks_in_footer'] == 1 )
1294      {
1295          $lblocks = '';
1296  
1297          /* Check if an array has been passed that includes the name of a plugin
1298           * function or custom function
1299           * This can be used to take control over what blocks are then displayed
1300           */
1301          if( is_array( $custom ))
1302          {
1303              $function = $custom[0];
1304              if( function_exists( $function ))
1305              {
1306                  $lblocks = $function( $custom[1], 'left' );
1307              }
1308          }
1309          else
1310          {
1311              $lblocks = COM_showBlocks( 'left', $topic );
1312          }
1313  
1314          if( empty( $lblocks ))
1315          {
1316              $footer->set_var( 'geeklog_blocks', '' );
1317              $footer->set_var( 'left_blocks', '' );
1318          }
1319          else
1320          {
1321              $footer->set_var( 'geeklog_blocks', $lblocks );
1322              $footer->parse( 'left_blocks', 'leftblocks', true );
1323          }
1324      }
1325  
1326      // Global centerspan variable set in index.php
1327      if( isset( $GLOBALS['centerspan'] ))
1328      {
1329          $footer->set_var( 'centerblockfooter-span', '</td></tr></table>' );
1330      }
1331  
1332      $exectime = $_PAGE_TIMER->stopTimer();
1333      $exectext = $LANG01[91] . ' ' . $exectime . ' ' . $LANG01[92];
1334  
1335      $footer->set_var( 'execution_time', $exectime );
1336      $footer->set_var( 'execution_textandtime', $exectext );
1337  
1338      // Call to plugins to set template variables in the footer
1339      PLG_templateSetVars( 'footer', $footer );
1340  
1341      // Actually parse the template and make variable substitutions
1342      $footer->parse( 'index_footer', 'footer' );
1343  
1344      // Return resulting HTML
1345      return $footer->finish( $footer->get_var( 'index_footer' ));
1346  }
1347  
1348  /**
1349  * Prints out standard block header
1350  *
1351  * Prints out standard block header but pulling header HTML formatting from
1352  * the database.
1353  *
1354  * Programming Note:  The two functions COM_startBlock and COM_endBlock are used
1355  * to sandwich your block content.  These functions are not used only for blocks
1356  * but anything that uses that format, e.g. Stats page.  They are used like
1357  * COM_siteHeader and COM_siteFooter but for internal page elements.
1358  *
1359  *
1360  * @param        string      $title      Value to set block title to
1361  * @param        string      $helpfile   Help file, if one exists
1362  * @param        string      $template   HTML template file to use to format the block
1363  * @see COM_endBlock
1364  * @see COM_siteHeader  For similiar construct
1365  * @return   string  Formatted HTML containing block header
1366  *
1367  */
1368  
1369  function COM_startBlock( $title='', $helpfile='', $template='blockheader.thtml' )
1370  {
1371      global $_CONF, $LANG01, $_IMAGE_TYPE;
1372  
1373      $block = new Template( $_CONF['path_layout'] );
1374      $block->set_file( 'block', $template );
1375  
1376      $block->set_var( 'site_url', $_CONF['site_url'] );
1377      $block->set_var( 'layout_url', $_CONF['layout_url'] );
1378      $block->set_var( 'block_title', stripslashes( $title ));
1379  
1380      if( !empty( $helpfile ))
1381      {
1382          $helpimg = $_CONF['layout_url'] . '/images/button_help.' . $_IMAGE_TYPE;
1383          if( !stristr( $helpfile, 'http://' ))
1384          {
1385              $help = '<a class="blocktitle" href="' . $_CONF['site_url'] . '/help/' . $helpfile
1386                  . '" target="_blank"><img src="' . $helpimg
1387                  . '" border="0" alt="?"></a>';
1388          }
1389          else
1390          {
1391              $help = '<a class="blocktitle" href="' . $helpfile
1392                  . '" target="_blank"><img src="' . $helpimg
1393                  . '" border="0" alt="?"></a>';
1394          }
1395  
1396          $block->set_var( 'block_help', $help );
1397      }
1398  
1399      $block->parse( 'startHTML', 'block' );
1400  
1401      return $block->finish( $block->get_var( 'startHTML' ));
1402  }
1403  
1404  /**
1405  * Closes out COM_startBlock
1406  *
1407  * @param        string      $template       HTML template file used to format block footer
1408  * @return   string  Formatted HTML to close block
1409  * @see function COM_startBlock
1410  *
1411  */
1412  function COM_endBlock( $template='blockfooter.thtml' )
1413  {
1414      global $_CONF;
1415  
1416      $block = new Template( $_CONF['path_layout'] );
1417      $block->set_file( 'block', $template );
1418  
1419      $block->set_var( 'site_url', $_CONF['site_url'] );
1420      $block->set_var( 'layout_url', $_CONF['layout_url'] );
1421      $block->parse( 'endHTML', 'block' );
1422  
1423      return $block->finish( $block->get_var( 'endHTML' ));
1424  }
1425  
1426  
1427  /**
1428  * Creates a <option> list from a database list for use in forms
1429  *
1430  * Creates option list form field using given arguments
1431  *
1432  * @param        string      $table      Database Table to get data from
1433  * @param        string      $selection  Comma delimited string of fields to pull The first field is the value of the option and the second is the label to be displayed.  This is used in a SQL statement and can include DISTINCT to start.
1434  * @param        string/array      $selected   Value (from $selection) to set to SELECTED or default
1435  * @param        int         $sortcol    Which field to sort option list by 0 (value) or 1 (label)
1436  * @param        string      $where      Optional WHERE clause to use in the SQL Selection
1437  * @see function COM_checkList
1438  * @return   string  Formated HTML of option values
1439  *
1440  */
1441  function COM_optionList( $table, $selection, $selected='', $sortcol=1, $where='' )
1442  {
1443      global $_DB_table_prefix;
1444  
1445      $retval = '';
1446  
1447      $LangTableName = '';
1448      if( substr( $table, 0, strlen( $_DB_table_prefix )) == $_DB_table_prefix )
1449      {
1450          $LangTableName = 'LANG_' . substr( $table, strlen( $_DB_table_prefix ));
1451      }
1452      else
1453      {
1454          $LangTableName = 'LANG_' . $table;
1455      }
1456  
1457      global $$LangTableName;
1458  
1459      if( isset( $$LangTableName ))
1460      {
1461          $LangTable = $$LangTableName;
1462      }
1463      else
1464      {
1465          $LangTable = array();
1466      }
1467  
1468      $tmp = str_replace( 'DISTINCT ', '', $selection );
1469      $select_set = explode( ',', $tmp );
1470  
1471      $sql = "SELECT $selection FROM $table";
1472      if( $where != '' )
1473      {
1474          $sql .= " WHERE $where";
1475      }
1476      $sql .= " ORDER BY {$select_set[$sortcol]}";
1477      $result = DB_query( $sql );
1478      $nrows = DB_numRows( $result );
1479  
1480      for( $i = 0; $i < $nrows; $i++ )
1481      {
1482          $A = DB_fetchArray( $result, true );
1483          $retval .= '<option value="' . $A[0] . '"';
1484  
1485          if( is_array( $selected ) AND count( $selected ) > 0 )
1486          {
1487              foreach( $selected as $selected_item )
1488              {
1489                  if( $A[0] == $selected_item )
1490                  {
1491                      $retval .= ' selected="selected"';
1492                  }
1493              }
1494          }
1495          elseif( !is_array( $selected ) AND $A[0] == $selected )
1496          {
1497              $retval .= ' selected="selected"';
1498          }
1499  
1500          $retval .= '>';
1501          if( empty( $LangTable[$A[0]] ))
1502          {
1503              $retval .= $A[1];
1504          }
1505          else
1506          {
1507              $retval .= $LangTable[$A[0]];
1508          }
1509          $retval .= '</option>' . LB;
1510      }
1511  
1512      return $retval;
1513  }
1514  
1515  /**
1516  * Create and return a dropdown-list of available topics
1517  *
1518  * This is a variation of COM_optionList() from lib-common.php. It will add
1519  * only those topics to the option list which are accessible by the current
1520  * user.
1521  *
1522  * @param        string      $selection  Comma delimited string of fields to pull The first field is the value of the option and the second is the label to be displayed.  This is used in a SQL statement and can include DISTINCT to start.
1523  * @param        string      $selected   Value (from $selection) to set to SELECTED or default
1524  * @param        int         $sortcol    Which field to sort option list by 0 (value) or 1 (label)
1525  * @see function COM_optionList
1526  * @return   string  Formated HTML of option values
1527  *
1528  */
1529  
1530  function COM_topicList( $selection, $selected = '', $sortcol = 1, $ignorelang = false )
1531  {
1532      global $_TABLES;
1533  
1534      $retval = '';
1535  
1536      $tmp = str_replace( 'DISTINCT ', '', $selection );
1537      $select_set = explode( ',', $tmp );
1538  
1539      $sql = "SELECT $selection FROM {$_TABLES['topics']}";
1540      if( $ignorelang )
1541      {
1542          $sql .= COM_getPermSQL();
1543      }
1544      else
1545      {
1546          $permsql = COM_getPermSQL();
1547          if( empty( $permsql ))
1548          {
1549              $sql .= COM_getLangSQL( 'tid' );
1550          }
1551          else
1552          {
1553              $sql .= $permsql . COM_getLangSQL( 'tid', 'AND' );
1554          }
1555      }
1556      $sql .=  " ORDER BY $select_set[$sortcol]";
1557  
1558      $result = DB_query( $sql );
1559      $nrows = DB_numRows( $result );
1560  
1561      for( $i = 0; $i < $nrows; $i++ )
1562      {
1563          $A = DB_fetchArray( $result, true );
1564          $retval .= '<option value="' . $A[0] . '"';
1565  
1566          if( $A[0] == $selected )
1567          {
1568              $retval .= ' selected="selected"';
1569          }
1570  
1571          $retval .= '>' . stripslashes( $A[1] ) . '</option>' . LB;
1572      }
1573  
1574      return $retval;
1575  }
1576  
1577  /**
1578  * Creates a <input> checklist from a database list for use in forms
1579  *
1580  * Creates a group of checkbox form fields with given arguments
1581  *
1582  * @param        string      $table      DB Table to pull data from
1583  * @param        string      $selection  Comma delimited list of fields to pull from table
1584  * @param        string      $where      Where clause of SQL statement
1585  * @param        string      $selected   Value to set to CHECKED
1586  * @see function COM_optionList
1587  * @return   string  HTML with Checkbox code
1588  *
1589  */
1590  
1591  function COM_checkList( $table, $selection, $where='', $selected='' )
1592  {
1593      global $_TABLES, $_COM_VERBOSE;
1594  
1595      $retval = '';
1596  
1597      $sql = "SELECT $selection FROM $table";
1598  
1599      if( !empty( $where ))
1600      {
1601          $sql .= " WHERE $where";
1602      }
1603  
1604      $result = DB_query( $sql );
1605      $nrows = DB_numRows( $result );
1606  
1607      if( !empty( $selected ))
1608      {
1609          if( $_COM_VERBOSE )
1610          {
1611              COM_errorLog( "exploding selected array: $selected in COM_checkList", 1 );
1612          }
1613  
1614          $S = explode( ' ', $selected );
1615      }
1616      else
1617      {
1618          if( $_COM_VERBOSE)
1619          {
1620              COM_errorLog( 'selected string was empty COM_checkList', 1 );
1621          }
1622  
1623          $S = array();
1624      }
1625  
1626      for( $i = 0; $i < $nrows; $i++ )
1627      {
1628          $access = true;
1629          $A = DB_fetchArray( $result, true );
1630  
1631          if( $table == $_TABLES['topics'] AND SEC_hasTopicAccess( $A['tid'] ) == 0 )
1632          {
1633              $access = false;
1634          }
1635  
1636          if( $access )
1637          {
1638              $retval .= '<input type="checkbox" name="' . $table . '[]" value="' . $A[0] . '"';
1639  
1640              for( $x = 0; $x < sizeof( $S ); $x++ )
1641              {
1642                  if( $A[0] == $S[$x] )
1643                  {
1644                      $retval .= ' checked="checked"';
1645                  }
1646              }
1647  
1648              if(( $table == $_TABLES['blocks'] ) && isset( $A[2] ) && ( $A[2] == 'gldefault' ))
1649              {
1650                  $retval .= '><b>' . stripslashes( $A[1] ) . '</b><br>' . LB;
1651              }
1652              else
1653              {
1654                  $retval .= '>' . stripslashes( $A[1] ) . '<br>' . LB;
1655              }
1656          }
1657      }
1658  
1659      return $retval;
1660  }
1661  
1662  /**
1663  * Prints out an associative array for debugging
1664  *
1665  * The core of this code has been lifted from phpweblog which is licenced
1666  * under the GPL.  This is not used very much in the code but you can use it
1667  * if you see fit
1668  *
1669  * @param        array       $A      Array to loop through and print values for
1670  * @return   string  Formated HTML List
1671  *
1672  */
1673  
1674  function COM_debug( $A )
1675  {
1676      if( !empty( $A ))
1677      {
1678          $retval .= LB . '<pre><p>---- DEBUG ----</p>';
1679  
1680          for( reset( $A ); $k = key( $A ); next( $A ))
1681          {
1682              $retval .= sprintf( "<li>%13s [%s]</li>\n", $k, $A[$k] );
1683          }
1684  
1685          $retval .= '<p>---------------</p></pre>' . LB;
1686      }
1687  
1688      return $retval;
1689  }
1690  
1691  /**
1692  *
1693  * Checks to see if RDF file needs updating and updates it if so.
1694  * Checks to see if we need to update the RDF as a result
1695  * of an article with a future publish date reaching it's
1696  * publish time and if so updates the RDF file.
1697  *
1698  * @param    string  $updated_type   (optional) feed type to update
1699  * @param    string  $updated_topic  (optional) feed topic to update
1700  * @param    string  $updated_id     (optional) feed id to update
1701  *
1702  * @note When called without parameters, this will only check for new entries to
1703  *       include in the feeds. Pass the $updated_XXX parameters when the content
1704  *       of an existing entry has changed.
1705  *
1706  * @see file lib-syndication.php
1707  *
1708  */
1709  function COM_rdfUpToDateCheck( $updated_type = '', $updated_topic = '', $updated_id = '' )
1710  {
1711      global $_CONF, $_TABLES;
1712  
1713      if( $_CONF['backend'] > 0 )
1714      {
1715          if( !empty( $updated_type ) && ( $updated_type != 'geeklog' ))
1716          {
1717              // when a plugin's feed is to be updated, skip Geeklog's own feeds
1718              $sql = "SELECT fid,type,topic,limits,update_info FROM {$_TABLES['syndication']} WHERE (is_enabled = 1) AND (type <> 'geeklog')";
1719          }
1720          else
1721          {
1722              $sql = "SELECT fid,type,topic,limits,update_info FROM {$_TABLES['syndication']} WHERE is_enabled = 1";
1723          }
1724          $result = DB_query( $sql );
1725          $num = DB_numRows( $result );
1726          for( $i = 0; $i < $num; $i++)
1727          {
1728              $A = DB_fetchArray( $result );
1729  
1730              $is_current = true;
1731              if( $A['type'] == 'geeklog' )
1732              {
1733                  $is_current = SYND_feedUpdateCheck( $A['topic'],
1734                                  $A['update_info'], $A['limits'],
1735                                  $updated_topic, $updated_id );
1736              }
1737              else
1738              {
1739                  $is_current = PLG_feedUpdateCheck( $A['type'], $A['fid'],
1740                                  $A['topic'], $A['update_info'], $A['limits'],
1741                                  $updated_type, $updated_topic, $updated_id );
1742              }
1743              if( !$is_current )
1744              {
1745                  SYND_updateFeed( $A['fid'] );
1746              }
1747          }
1748      }
1749  }
1750  
1751  /**
1752  * Checks and Updates the featured status of all articles.
1753  *
1754  * Checks to see if any articles that were published for the future have been
1755  * published and, if so, will see if they are featured.  If they are featured,
1756  * this will set old featured article (if there is one) to normal
1757  *
1758  */
1759  
1760  function COM_featuredCheck()
1761  {
1762      global $_TABLES;
1763  
1764      $curdate = date( "Y-m-d H:i:s", time() );
1765  
1766      if( DB_getItem( $_TABLES['stories'], 'count(*)', "featured = 1 AND draft_flag = 0 AND date <= '$curdate'" ) > 1 )
1767      {
1768          // OK, we have two featured stories, fix that
1769  
1770          $sid = DB_getItem( $_TABLES['stories'], 'sid', "featured = 1 AND draft_flag = 0 ORDER BY date LIMIT 1" );
1771          DB_query( "UPDATE {$_TABLES['stories']} SET featured = 0 WHERE sid = '$sid'" );
1772      }
1773  }
1774  
1775  /**
1776  *
1777  * Logs messages to error.log or the web page or both
1778  *
1779  * Prints a well formatted message to either the web page, error log
1780  * or both.
1781  *
1782  * @param        string      $logentry       Text to log to error log
1783  * @param        int         $actionid       1 = write to log file, 2 = write to screen (default) both
1784  * @see function COM_accessLog
1785  * @return   string  If $actionid = 2 or '' then HTML formatted string (wrapped in block) else nothing
1786  *
1787  */
1788  
1789  function COM_errorLog( $logentry, $actionid = '' )
1790  {
1791      global $_CONF, $LANG01;
1792  
1793      $retval = '';
1794  
1795      if( !empty( $logentry ))
1796      {
1797          $logentry = str_replace( array( '<?', '?>' ), array( '(@', '@)' ),
1798                                   $logentry );
1799  
1800          $timestamp = strftime( '%c' );
1801  
1802          switch( $actionid )
1803          {
1804              case 1:
1805                  $logfile = $_CONF['path_log'] . 'error.log';
1806  
1807                  if( !$file = fopen( $logfile, 'a' ))
1808                  {
1809                      $retval .= $LANG01[33] . ' ' . $logfile . ' (' . $timestamp . ')<br>' . LB;
1810                  }
1811                  else
1812                  {
1813                      fputs( $file, "$timestamp - $logentry \n" );
1814                  }
1815                  break;
1816  
1817             case 2:
1818                  $retval .= COM_startBlock( $LANG01[55] . ' ' . $timestamp, '',
1819                                 COM_getBlockTemplate( '_msg_block', 'header' ))
1820                          . nl2br( $logentry )
1821                          . COM_endBlock( COM_getBlockTemplate( '_msg_block',
1822                                                                'footer' ));
1823                  break;
1824  
1825              default:
1826                  $logfile = $_CONF['path_log'] . 'error.log';
1827  
1828                  if( !$file = fopen( $logfile, 'a' ))
1829                  {
1830                      $retval .= $LANG01[33] . ' ' . $logfile . ' (' . $timestamp . ')<br>' . LB;
1831                  }
1832                  else
1833                  {
1834                      fputs( $file, "$timestamp - $logentry \n" );
1835                      $retval .= COM_startBlock( $LANG01[34] . ' - ' . $timestamp,
1836                                     '', COM_getBlockTemplate( '_msg_block',
1837                                     'header' ))
1838                              . nl2br( $logentry )
1839                              . COM_endBlock( COM_getBlockTemplate( '_msg_block',
1840                                                                    'footer' ));
1841                  }
1842                  break;
1843          }
1844      }
1845  
1846      return $retval;
1847  }
1848  
1849  /**
1850  * Logs message to access.log
1851  *
1852  * This will print a message to the Geeklog access log
1853  *
1854  * @param        string      $string         Message to write to access log
1855  * @see COM_errorLog
1856  *
1857  */
1858  
1859  function COM_accessLog( $logentry )
1860  {
1861      global $_CONF, $_USER, $LANG01;
1862  
1863      $retval = '';
1864  
1865      if( !empty( $logentry ))
1866      {
1867          $logentry = str_replace( array( '<?', '?>' ), array( '(@', '@)' ),
1868                                   $logentry );
1869  
1870          $timestamp = strftime( '%c' );
1871          $logfile = $_CONF['path_log'] . 'access.log';
1872  
1873          if( !$file = fopen( $logfile, 'a' ))
1874          {
1875              return $LANG01[33] . $logfile . ' (' . $timestamp . ')<br>' . LB;
1876          }
1877  
1878          if( isset( $_USER['uid'] ))
1879          {
1880              $byuser = $_USER['uid'] . '@' . $_SERVER['REMOTE_ADDR'];
1881          }
1882          else
1883          {
1884              $byuser = 'anon@' . $_SERVER['REMOTE_ADDR'];
1885          }
1886  
1887          fputs( $file, "$timestamp ($byuser) - $logentry\n" );
1888      }
1889  
1890      return $retval;
1891  }
1892  
1893  /**
1894  * Shows all available topics
1895  *
1896  * Show the topics in the system the user has access to and prints them in HTML.
1897  * This function is used to show the topics in the topics block.
1898  *
1899  * @param    string    $topic      ID of currently selected topic
1900  * @return   string                HTML formatted topic list
1901  *
1902  */
1903  
1904  function COM_showTopics( $topic='' )
1905  {
1906      global $_CONF, $_TABLES, $_USER, $LANG01, $_BLOCK_TEMPLATE, $page;
1907  
1908      $langsql = COM_getLangSQL( 'tid' );
1909      if( empty( $langsql ))
1910      {
1911          $op = 'WHERE';
1912      }
1913      else
1914      {
1915          $op = 'AND';
1916      }
1917  
1918      $sql = "SELECT tid,topic,imageurl FROM {$_TABLES['topics']}" . $langsql;
1919      if( !empty( $_USER['uid'] ) && ( $_USER['uid'] > 1 ))
1920      {
1921          $tids = DB_getItem( $_TABLES['userindex'], 'tids',
1922                              "uid = '{$_USER['uid']}'" );
1923          if( !empty( $tids ))
1924          {
1925              $sql .= " $op (tid NOT IN ('" . str_replace( ' ', "','", $tids )
1926                   . "'))" . COM_getPermSQL( 'AND' );
1927          }
1928          else
1929          {
1930              $sql .= COM_getPermSQL( $op );
1931          }
1932      }
1933      else
1934      {
1935          $sql .= COM_getPermSQL( $op );
1936      }
1937      if( $_CONF['sortmethod'] == 'alpha' )
1938      {
1939          $sql .= ' ORDER BY topic ASC';
1940      }
1941      else
1942      {
1943          $sql .= ' ORDER BY sortnum';
1944      }
1945      $result = DB_query( $sql );
1946  
1947      $retval = '';
1948      $sections = new Template( $_CONF['path_layout'] );
1949      if( isset( $_BLOCK_TEMPLATE['topicoption'] ))
1950      {
1951          $templates = explode( ',', $_BLOCK_TEMPLATE['topicoption'] );
1952          $sections->set_file( array( 'option'  => $templates[0],
1953                                      'current' => $templates[1] ));
1954      }
1955      else
1956      {
1957          $sections->set_file( array( 'option'   => 'topicoption.thtml',
1958                                      'inactive' => 'topicoption_off.thtml' ));
1959      }
1960      $sections->set_var( 'site_url', $_CONF['site_url'] );
1961      $sections->set_var( 'layout_url', $_CONF['layout_url'] );
1962      $sections->set_var( 'block_name', str_replace( '_', '-', 'section_block' ));
1963  
1964      if( $_CONF['hide_home_link'] == 0 )
1965      {
1966          // Give a link to the homepage here since a lot of people use this for
1967          // navigating the site
1968  
1969          if( COM_onFrontpage() )
1970          {
1971              $sections->set_var( 'option_url', '' );
1972              $sections->set_var( 'option_label', $LANG01[90] );
1973              $sections->set_var( 'option_count', '' );
1974              $sections->set_var( 'topic_image', '' );
1975              $retval .= $sections->parse( 'item', 'inactive' );
1976          }
1977          else
1978          {
1979              $sections->set_var( 'option_url',
1980                                  $_CONF['site_url'] . '/index.php' );
1981              $sections->set_var( 'option_label', $LANG01[90] );
1982              $sections->set_var( 'option_count', '' );
1983              $sections->set_var( 'topic_image', '' );
1984              $retval .= $sections->parse( 'item', 'option' );
1985          }
1986      }
1987  
1988      if( $_CONF['showstorycount'] )
1989      {
1990          $sql = "SELECT tid, COUNT(*) AS count FROM {$_TABLES['stories']} "
1991               . 'WHERE (draft_flag = 0) AND (date <= NOW()) '
1992               . COM_getPermSQL( 'AND' )
1993               . ' GROUP BY tid';
1994          $rcount = DB_query( $sql );
1995          while( $C = DB_fetchArray( $rcount ))
1996          {
1997              $storycount[$C['tid']] = $C['count'];
1998          }
1999      }
2000  
2001      if( $_CONF['showsubmissioncount'] )
2002      {
2003          $sql = "SELECT tid, COUNT(*) AS count FROM {$_TABLES['storysubmission']} "
2004               . ' GROUP BY tid';
2005          $rcount = DB_query( $sql );
2006          while( $C = DB_fetchArray( $rcount ))
2007          {
2008              $submissioncount[$C['tid']] = $C['count'];
2009          }
2010      }
2011  
2012      while( $A = DB_fetchArray( $result ) )
2013      {
2014          $topicname = stripslashes( $A['topic'] );
2015          $sections->set_var( 'option_url', $_CONF['site_url']
2016                              . '/index.php?topic=' . $A['tid'] );
2017          $sections->set_var( 'option_label', $topicname );
2018  
2019          $countstring = '';
2020          if( $_CONF['showstorycount'] || $_CONF['showsubmissioncount'] )
2021          {
2022              $countstring .= '(';
2023  
2024              if( $_CONF['showstorycount'] )
2025              {
2026                  if( empty( $storycount[$A['tid']] ))
2027                  {
2028                      $countstring .= 0;
2029                  }
2030                  else
2031                  {
2032                      $countstring .= COM_numberFormat( $storycount[$A['tid']] );
2033                  }
2034              }
2035  
2036              if( $_CONF['showsubmissioncount'] )
2037              {
2038                  if( $_CONF['showstorycount'] )
2039                  {
2040                      $countstring .= '/';
2041                  }
2042                  if( empty( $submissioncount[$A['tid']] ))
2043                  {
2044                      $countstring .= 0;
2045                  }
2046                  else
2047                  {
2048                      $countstring .= COM_numberFormat( $submissioncount[$A['tid']] );
2049                  }
2050              }
2051  
2052              $countstring .= ')';
2053          }
2054          $sections->set_var( 'option_count', $countstring );
2055  
2056          $topicimage = '';
2057          if( !empty( $A['imageurl'] ))
2058          {
2059              $imageurl = COM_getTopicImageUrl( $A['imageurl'] );
2060              $topicimage = '<img src="' . $imageurl . '" alt="' . $topicname
2061                          . '" title="' . $topicname . '" border="0">';
2062          }
2063          $sections->set_var( 'topic_image', $topicimage );
2064  
2065          if(( $A['tid'] == $topic ) && ( $page == 1 ))
2066          {
2067              $retval .= $sections->parse( 'item', 'inactive' );
2068          }
2069          else
2070          {
2071              $retval .= $sections->parse( 'item', 'option' );
2072          }
2073      }
2074  
2075      return $retval;
2076  }
2077  
2078  /**
2079  * Shows the user their menu options
2080  *
2081  * This shows the average joe use their menu options. This is the user block on right side
2082  *
2083  * @param        string      $help       Help file to show
2084  * @param        string      $title      Title of Menu
2085  * @see function COM_adminMenu
2086  *
2087  */
2088  
2089  function COM_userMenu( $help='', $title='' )
2090  {
2091      global $_TABLES, $_USER, $_CONF, $LANG01, $LANG04, $_BLOCK_TEMPLATE;
2092  
2093      $retval = '';
2094  
2095      if( !empty( $_USER['uid'] ) && ( $_USER['uid'] > 1 ))
2096      {
2097          $usermenu = new Template( $_CONF['path_layout'] );
2098          if( isset( $_BLOCK_TEMPLATE['useroption'] ))
2099          {
2100              $templates = explode( ',', $_BLOCK_TEMPLATE['useroption'] );
2101              $usermenu->set_file( array( 'option' => $templates[0],
2102                                          'current' => $templates[1] ));
2103          }
2104          else
2105          {
2106             $usermenu->set_file( array( 'option' => 'useroption.thtml',
2107                                         'current' => 'useroption_off.thtml' ));
2108          }
2109          $usermenu->set_var( 'site_url', $_CONF['site_url'] );
2110          $usermenu->set_var( 'layout_url', $_CONF['layout_url'] );
2111          $usermenu->set_var( 'block_name', str_replace( '_', '-', 'user_block' ));
2112  
2113          if( empty( $title ))
2114          {
2115              $title = DB_getItem( $_TABLES['blocks'], 'title',
2116                                   "name='user_block'" );
2117          }
2118  
2119          // what's our current URL?
2120          $thisUrl = COM_getCurrentURL();
2121  
2122          $retval .= COM_startBlock( $title, $help,
2123                             COM_getBlockTemplate( 'user_block', 'header' ));
2124  
2125          // This function will show the user options for all installed plugins
2126          // (if any)
2127  
2128          $plugin_options = PLG_getUserOptions();
2129          $nrows = count( $plugin_options );
2130  
2131          for( $i = 0; $i < $nrows; $i++ )
2132          {
2133              $plg = current( $plugin_options );
2134              $usermenu->set_var( 'option_label', $plg->adminlabel );
2135  
2136              if( !empty( $plg->numsubmissions ))
2137              {
2138                  $usermenu->set_var( 'option_count', '(' . $plg->numsubmissions . ')' );
2139              }
2140              else
2141              {
2142                  $usermenu->set_var( 'option_count', '' );
2143              }
2144  
2145              $usermenu->set_var( 'option_url', $plg->adminurl );
2146              if( $thisUrl == $plg->adminurl )
2147              {
2148                  $retval .= $usermenu->parse( 'item', 'current' );
2149              }
2150              else
2151              {
2152                  $retval .= $usermenu->parse( 'item', 'option' );
2153              }
2154              next( $plugin_options );
2155          }
2156  
2157          $url = $_CONF['site_url'] . '/usersettings.php?mode=edit';
2158          $usermenu->set_var( 'option_label', $LANG01[48] );
2159          $usermenu->set_var( 'option_count', '' );
2160          $usermenu->set_var( 'option_url', $url );
2161          if( $thisUrl == $url )
2162          {
2163              $retval .= $usermenu->parse( 'item', 'current' );
2164          }
2165          else
2166          {
2167              $retval .= $usermenu->parse( 'item', 'option' );
2168          }
2169  
2170          $url = $_CONF['site_url'] . '/users.php?mode=logout';
2171          $usermenu->set_var( 'option_label', $LANG01[19] );
2172          $usermenu->set_var( 'option_count', '' );
2173          $usermenu->set_var( 'option_url', $url );
2174          $retval .= $usermenu->parse( 'item', 'option' );
2175  
2176          $retval .=  COM_endBlock( COM_getBlockTemplate( 'user_block', 'footer' ));
2177      }
2178      else
2179      {
2180          $retval .= COM_startBlock( $LANG01[47], $help,
2181                             COM_getBlockTemplate( 'user_block', 'header' ));
2182  
2183          $login = new Template( $_CONF['path_layout'] );
2184          $login->set_file( 'form', 'loginform.thtml' );
2185          $login->set_var( 'site_url', $_CONF['site_url'] );
2186          $login->set_var( 'layout_url', $_CONF['layout_url'] );
2187          $login->set_var( 'lang_username', $LANG01[21] );
2188          $login->set_var( 'lang_password', $LANG01[57] );
2189          $login->set_var( 'lang_forgetpassword', $LANG01[119] );
2190          $login->set_var( 'lang_login', $LANG01[58] );
2191          if( $_CONF['disable_new_user_registration'] == 1 )
2192          {
2193              $login->set_var( 'lang_signup', '' );
2194          }
2195          else
2196          {
2197              $login->set_var( 'lang_signup', $LANG01[59] );
2198          }
2199          if( $_CONF['remoteauthentication'] && !$_CONF['usersubmission'] )
2200          {
2201              // Build select
2202              $select = '<select name="service" id="service"><option value="">' .
2203                              $_CONF['site_name'] . '</option>';
2204              if( is_dir( $_CONF['path_system'] . 'classes/authentication/' ))
2205              {
2206                  $folder = opendir( $_CONF['path_system']
2207                                     . 'classes/authentication/' );
2208                  while(( $filename = @readdir( $folder )) !== false )
2209                  {
2210                      $strpos = strpos( $filename, '.auth.class.php' );
2211                      if( $strpos )
2212                      {
2213                          $service = substr( $filename, 0, $strpos );
2214                          $select .= '<option value="' . $service . '">'
2215                                  . $service . '</option>';
2216                      }
2217                  }
2218              }
2219              $select .= '</select>';
2220              $login->set_file( 'services', 'blockservices.thtml' );
2221              $login->set_var( 'lang_service', $LANG04[121] );
2222              $login->set_var( 'select_service', $select );
2223              $login->parse( 'output', 'services' );
2224              $login->set_var( 'services',
2225                               $login->finish( $login->get_var( 'output' )));
2226          }
2227          else
2228          {
2229              $login->set_var( 'services', '' );
2230          }
2231          $retval .= $login->parse( 'output', 'form' );
2232  
2233          $retval .= COM_endBlock( COM_getBlockTemplate( 'user_block', 'footer' ));
2234      }
2235  
2236      return $retval;
2237  }
2238  
2239  /**
2240  * Prints administration menu
2241  *
2242  * This will return the administration menu items that the user has
2243  * sufficient rights to -- Admin Block on right side.
2244  *
2245  * @param        string      $help       Help file to show
2246  * @param        string      $title      Menu Title
2247  * @see function COM_userMenu
2248  *
2249  */
2250  
2251  function COM_adminMenu( $help = '', $title = '' )
2252  {
2253      global $_TABLES, $_USER, $_CONF, $LANG01, $_BLOCK_TEMPLATE, $LANG_PDF,
2254             $_DB_dbms;
2255  
2256      $retval = '';
2257  
2258      if( empty( $_USER['username'] ))
2259      {
2260          return $retval;
2261      }
2262  
2263      $plugin_options = PLG_getAdminOptions();
2264      $num_plugins = count( $plugin_options );
2265  
2266      if( SEC_isModerator() OR SEC_hasRights( 'story.edit,block.edit,topic.edit,user.edit,plugin.edit,user.mail,syndication.edit', 'OR' ) OR ( $num_plugins > 0 ))
2267      {
2268          // what's our current URL?
2269          $thisUrl = COM_getCurrentURL();
2270  
2271          $adminmenu = new Template( $_CONF['path_layout'] );
2272          if( isset( $_BLOCK_TEMPLATE['adminoption'] ))
2273          {
2274              $templates = explode( ',', $_BLOCK_TEMPLATE['adminoption'] );
2275              $adminmenu->set_file( array( 'option' => $templates[0],
2276                                           'current' => $templates[1] ));
2277          }
2278          else
2279          {
2280              $adminmenu->set_file( array( 'option' => 'adminoption.thtml',
2281                                           'current' => 'adminoption_off.thtml' ));
2282          }
2283          $adminmenu->set_var( 'site_url', $_CONF['site_url'] );
2284          $adminmenu->set_var( 'layout_url', $_CONF['layout_url'] );
2285          $adminmenu->set_var( 'block_name', str_replace( '_', '-', 'admin_block' ));
2286  
2287          if( empty( $title ))
2288          {
2289              $title = DB_getItem( $_TABLES['blocks'], 'title',
2290                                   "name = 'admin_block'" );
2291          }
2292  
2293          $retval .= COM_startBlock( $title, $help,
2294                             COM_getBlockTemplate( 'admin_block', 'header' ));
2295  
2296          $topicsql = '';
2297          if( SEC_isModerator() || SEC_hasRights( 'story.edit' ))
2298          {
2299              $tresult = DB_query( "SELECT tid FROM {$_TABLES['topics']}"
2300                                   . COM_getPermSQL() );
2301              $trows = DB_numRows( $tresult );
2302              if( $trows > 0 )
2303              {
2304                  $tids = array();
2305                  for( $i = 0; $i < $trows; $i++ )
2306                  {
2307                      $T = DB_fetchArray( $tresult );
2308                      $tids[] = $T['tid'];
2309                  }
2310                  if( sizeof( $tids ) > 0 )
2311                  {
2312                      $topicsql = " (tid IN ('" . implode( "','", $tids ) . "'))";
2313                  }
2314              }
2315          }
2316  
2317          $modnum = 0;
2318          if( SEC_hasRights( 'story.edit,story.moderate', 'OR' ) || (( $_CONF['usersubmission'] == 1 ) && SEC_hasRights( 'user.edit,user.delete' )))
2319          {
2320  
2321              if( SEC_hasRights( 'story.moderate' ))
2322              {
2323                  if( empty( $topicsql ))
2324                  {
2325                      $modnum += DB_count( $_TABLES['storysubmission'] );
2326                  }
2327                  else
2328                  {
2329                      $sresult = DB_query( "SELECT COUNT(*) AS count FROM {$_TABLES['storysubmission']} WHERE" . $topicsql );
2330                      $S = DB_fetchArray( $sresult );
2331                      $modnum += $S['count'];
2332                  }
2333              }
2334  
2335              if(( $_CONF['listdraftstories'] == 1 ) && SEC_hasRights( 'story.edit' ))
2336              {
2337                  $sql = "SELECT COUNT(*) AS count FROM {$_TABLES['stories']} WHERE (draft_flag = 1)";
2338                  if( !empty( $topicsql ))
2339                  {
2340                      $sql .= ' AND' . $topicsql;
2341                  }
2342                  $result = DB_query( $sql . COM_getPermSQL( 'AND', 0, 3 ));
2343                  $A = DB_fetchArray( $result );
2344                  $modnum += $A['count'];
2345              }
2346  
2347              if( $_CONF['usersubmission'] == 1 )
2348              {
2349                  if( SEC_hasRights( 'user.edit' ) && SEC_hasRights( 'user.delete' ))
2350                  {
2351                      $modnum += DB_count( $_TABLES['users'], 'status', '2' );
2352                  }
2353              }
2354          }
2355  
2356          // now handle submissions for plugins
2357          $modnum += PLG_getSubmissionCount();
2358  
2359          if( SEC_hasRights( 'story.edit' ))
2360          {
2361              $url = $_CONF['site_admin_url'] . '/story.php';
2362              $adminmenu->set_var( 'option_url', $url );
2363              $adminmenu->set_var( 'option_label', $LANG01[11] );
2364              if( empty( $topicsql ))
2365              {
2366                  $numstories = DB_count( $_TABLES['stories'] );
2367              }
2368              else
2369              {
2370                  $nresult = DB_query( "SELECT COUNT(*) AS count from {$_TABLES['stories']} WHERE" . $topicsql . COM_getPermSql( 'AND' ));
2371                  $N = DB_fetchArray( $nresult );
2372                  $numstories = $N['count'];
2373              }
2374              $adminmenu->set_var( 'option_count',
2375                                   COM_numberFormat( $numstories ));
2376              $menu_item = $adminmenu->parse( 'item',
2377                      ( $thisUrl == $url ) ? 'current' : 'option' );
2378              $link_array[$LANG01[11]] = $menu_item;
2379          }
2380  
2381          if( SEC_hasRights( 'block.edit' ))
2382          {
2383              $result = DB_query( "SELECT COUNT(*) AS count FROM {$_TABLES['blocks']}" . COM_getPermSql());
2384              list( $count ) = DB_fetchArray( $result );
2385  
2386              $url = $_CONF['site_admin_url'] . '/block.php';
2387              $adminmenu->set_var( 'option_url', $url );
2388              $adminmenu->set_var( 'option_label', $LANG01[12] );
2389              $adminmenu->set_var( 'option_count', COM_numberFormat( $count ));
2390  
2391              $menu_item = $adminmenu->parse( 'item',
2392                      ( $thisUrl == $url ) ? 'current' : 'option' );
2393              $link_array[$LANG01[12]] = $menu_item;
2394          }
2395  
2396          if( SEC_hasRights( 'topic.edit' ))
2397          {
2398              $result = DB_query( "SELECT COUNT(*) AS count FROM {$_TABLES['topics']}" . COM_getPermSql());
2399              list( $count ) = DB_fetchArray( $result );
2400  
2401              $url = $_CONF['site_admin_url'] . '/topic.php';
2402              $adminmenu->set_var( 'option_url', $url );
2403              $adminmenu->set_var( 'option_label', $LANG01[13] );
2404              $adminmenu->set_var( 'option_count', COM_numberFormat( $count ));
2405  
2406              $menu_item = $adminmenu->parse( 'item',
2407                      ( $thisUrl == $url ) ? 'current' : 'option' );
2408              $link_array[$LANG01[13]] = $menu_item;
2409          }
2410  
2411          if( SEC_hasRights( 'user.edit' ))
2412          {
2413              $url = $_CONF['site_admin_url'] . '/user.php';
2414              $adminmenu->set_var( 'option_url', $url );
2415              $adminmenu->set_var( 'option_label', $LANG01[17] );
2416              $adminmenu->set_var( 'option_count',
2417                      COM_numberFormat( DB_count( $_TABLES['users'] ) -1 ));
2418  
2419              $menu_item = $adminmenu->parse( 'item',
2420                      ( $thisUrl == $url ) ? 'current' : 'option' );
2421              $link_array[$LANG01[17]] = $menu_item;
2422          }
2423  
2424          if( SEC_hasRights( 'group.edit' ))
2425          {
2426              if (SEC_inGroup('Root')) {
2427                  $grpFilter = '';
2428              } else {
2429                  $thisUsersGroups = SEC_getUserGroups ();
2430                  $grpFilter = 'WHERE (grp_id IN (' . implode (',', $thisUsersGroups) . '))';
2431              }
2432              $result = DB_query( "SELECT COUNT(*) AS count FROM {$_TABLES['groups']} $grpFilter;" );
2433              $A = DB_fetchArray( $result );
2434  
2435              $url = $_CONF['site_admin_url'] . '/group.php';
2436              $adminmenu->set_var( 'option_url', $url );
2437              $adminmenu->set_var( 'option_label', $LANG01[96] );
2438              $adminmenu->set_var( 'option_count',
2439                                   COM_numberFormat( $A['count'] ));
2440  
2441              $menu_item = $adminmenu->parse( 'item',
2442                      ( $thisUrl == $url ) ? 'current' : 'option' );
2443              $link_array[$LANG01[96]] = $menu_item;
2444          }
2445  
2446          if( SEC_hasRights( 'user.mail' ))
2447          {
2448              $url = $_CONF['site_admin_url'] . '/mail.php';
2449              $adminmenu->set_var( 'option_url', $url );
2450              $adminmenu->set_var( 'option_label', $LANG01[105] );
2451              $adminmenu->set_var( 'option_count', 'N/A' );
2452  
2453              $menu_item = $adminmenu->parse( 'item',
2454                      ( $thisUrl == $url ) ? 'current' : 'option' );
2455              $link_array[$LANG01[105]] = $menu_item;
2456          }
2457  
2458          if(( $_CONF['backend'] == 1 ) && SEC_hasRights( 'syndication.edit' ))
2459          {
2460              $url = $_CONF['site_admin_url'] . '/syndication.php';
2461              $adminmenu->set_var( 'option_url', $url );
2462              $adminmenu->set_var( 'option_label', $LANG01[38] );
2463              $count = COM_numberFormat( DB_count( $_TABLES['syndication'] ));
2464              $adminmenu->set_var( 'option_count', $count );
2465  
2466              $menu_item = $adminmenu->parse( 'item',
2467                      ( $thisUrl == $url ) ? 'current' : 'option' );
2468              $link_array[$LANG01[38]] = $menu_item;
2469          }
2470  
2471          if(( $_CONF['trackback_enabled'] || $_CONF['pingback_enabled'] ||
2472                  $_CONF['ping_enabled'] ) && SEC_hasRights( 'story.ping' ))
2473          {
2474              $url = $_CONF['site_admin_url'] . '/trackback.php';
2475              $adminmenu->set_var( 'option_url', $url );
2476              $adminmenu->set_var( 'option_label', $LANG01[116] );
2477              if( $_CONF['ping_enabled'] )
2478              {
2479                  $count = COM_numberFormat( DB_count( $_TABLES['pingservice'] ));
2480                  $adminmenu->set_var( 'option_count', $count );
2481              }
2482              else
2483              {
2484                  $adminmenu->set_var( 'option_count', 'N/A' );
2485              }
2486  
2487              $menu_item = $adminmenu->parse( 'item',
2488                      ( $thisUrl == $url ) ? 'current' : 'option' );
2489              $link_array[$LANG01[116]] = $menu_item;
2490          }
2491  
2492          if( SEC_hasRights( 'plugin.edit' ))
2493          {
2494              $url = $_CONF['site_admin_url'] . '/plugins.php';
2495              $adminmenu->set_var( 'option_url', $url );
2496              $adminmenu->set_var( 'option_label', $LANG01[77] );
2497              $adminmenu->set_var( 'option_count',
2498                      COM_numberFormat( DB_count( $_TABLES['plugins'] )));
2499  
2500              $menu_item = $adminmenu->parse( 'item',
2501                      ( $thisUrl == $url ) ? 'current' : 'option' );
2502              $link_array[$LANG01[77]] = $menu_item;
2503          }
2504  
2505          // This will show the admin options for all installed plugins (if any)
2506  
2507          for( $i = 0; $i < $num_plugins; $i++ )
2508          {
2509              $plg = current( $plugin_options );
2510  
2511              $adminmenu->set_var( 'option_url', $plg->adminurl );
2512              $adminmenu->set_var( 'option_label', $plg->adminlabel );
2513  
2514              if( empty( $plg->numsubmissions ))
2515              {
2516                  $adminmenu->set_var( 'option_count', 'N/A' );
2517              }
2518              else
2519              {
2520                  $adminmenu->set_var( 'option_count',
2521                                       COM_numberFormat( $plg->numsubmissions ));
2522              }
2523  
2524              $menu_item = $adminmenu->parse( 'item',
2525                      ( $thisUrl == $plg->adminurl ) ? 'current' : 'option', true );
2526              $link_array[$plg->adminlabel] = $menu_item;
2527  
2528              next( $plugin_options );
2529          }
2530  
2531          if(( $_CONF['allow_mysqldump'] == 1 ) AND ( $_DB_dbms == 'mysql' ) AND
2532                  SEC_inGroup( 'Root' ))
2533          {
2534              $url = $_CONF['site_admin_url'] . '/database.php';
2535              $adminmenu->set_var( 'option_url', $url );
2536              $adminmenu->set_var( 'option_label', $LANG01[103] );
2537              $adminmenu->set_var( 'option_count', 'N/A' );
2538  
2539              $menu_item = $adminmenu->parse( 'item',
2540                      ( $thisUrl == $url ) ? 'current' : 'option' );
2541              $link_array[$LANG01[103]] = $menu_item;
2542          }
2543  
2544          // Add PDF Generator Link if the feature is enabled
2545          if(( $_CONF['pdf_enabled'] == 1 ) AND SEC_inGroup( 'Root' ))
2546          {
2547              $url = $_CONF['site_url'] . '/pdfgenerator.php';
2548              $adminmenu->set_var( 'option_url', $url );
2549              $adminmenu->set_var( 'option_label', $LANG_PDF[9] );
2550              $adminmenu->set_var( 'option_count', 'N/A' );
2551  
2552              $menu_item = $adminmenu->parse( 'item',
2553                      ( $thisUrl == $url ) ? 'current' : 'option' );
2554              $link_array[$LANG_PDF[9]] = $menu_item;
2555          }
2556  
2557          if( $_CONF['link_documentation'] == 1 )
2558          {
2559              $adminmenu->set_var( 'option_url',
2560                                   $_CONF['site_url'] . '/docs/index.html' );
2561              $adminmenu->set_var( 'option_label', $LANG01[113] );
2562              $adminmenu->set_var( 'option_count', 'N/A' );
2563              $menu_item = $adminmenu->parse( 'item', 'option' );
2564              $link_array[$LANG01[113]] = $menu_item;
2565          }
2566  
2567          if( SEC_inGroup( 'Root' ))
2568          {
2569              $adminmenu->set_var( 'option_url',
2570                 'http://www.geeklog.net/versionchecker.php?version=' . VERSION );
2571              $adminmenu->set_var( 'option_label', $LANG01[107] );
2572              $adminmenu->set_var( 'option_count', VERSION );
2573  
2574              $menu_item = $adminmenu->parse( 'item', 'option' );
2575              $link_array[$LANG01[107]] = $menu_item;
2576          }
2577  
2578          if( $_CONF['sort_admin'] )
2579          {
2580              uksort( $link_array, 'strcasecmp' );
2581          }
2582  
2583          $url = $_CONF['site_admin_url'] . '/moderation.php';
2584          $adminmenu->set_var( 'option_url', $url );
2585          $adminmenu->set_var( 'option_label', $LANG01[10] );
2586          $adminmenu->set_var( 'option_count', COM_numberFormat( $modnum ));
2587          $menu_item = $adminmenu->parse( 'item',
2588                      ( $thisUrl == $url ) ? 'current' : 'option' );
2589          $link_array = array( $menu_item ) + $link_array;
2590  
2591          foreach( $link_array as $link )
2592          {
2593              $retval .= $link;
2594          }
2595  
2596          $retval .= COM_endBlock( COM_getBlockTemplate( 'admin_block', 'footer' ));
2597      }
2598  
2599      return $retval;
2600  }
2601  
2602  /**
2603  * Redirects user to a given URL
2604  *
2605  * This function COM_passes a meta tag to COM_refresh after a form is sent.  This is
2606  * necessary because for some reason Nutscrape and PHP4 don't play well with
2607  * the header() function COM_100% of the time.
2608  *
2609  * @param        string      $url        URL to send user to
2610  *
2611  */
2612  
2613  function COM_refresh( $url )
2614  {
2615      return "<html><head><meta http-equiv=\"refresh\" content=\"0; URL=$url\"></head></html>\n";
2616  }
2617  
2618  /**
2619   * DEPRECIATED -- see CMT_userComments in lib-comment.php
2620   */
2621  function COM_userComments( $sid, $title, $type='article', $order='', $mode='', $pid = 0, $page = 1, $cid = false, $delete_option = false ) {
2622      global $_CONF;
2623  
2624      require_once $_CONF['path_system'] . 'lib-comment.php';
2625      return CMT_userComments( $sid, $title, $type, $order, $mode, $pid, $page, $cid, $delete_option );
2626  }
2627  
2628  /**
2629  * This censors inappropriate content
2630  *
2631  * This will replace 'bad words' with something more appropriate
2632  *
2633  * @param        string      $Message        String to check
2634  * @see function COM_checkHTML
2635  * @return   string  Edited $Message
2636  *
2637  */
2638  
2639  function COM_checkWords( $Message )
2640  {
2641      global $_CONF;
2642  
2643      $EditedMessage = $Message;
2644  
2645      if( $_CONF['censormode'] != 0 )
2646      {
2647          if( is_array( $_CONF['censorlist'] ))
2648          {
2649              $Replacement = $_CONF['censorreplace'];
2650  
2651              switch( $_CONF['censormode'])
2652              {
2653                  case 1: # Exact match
2654                      $RegExPrefix = '(\s*)';
2655                      $RegExSuffix = '(\W*)';
2656                      break;
2657  
2658                  case 2: # Word beginning
2659                      $RegExPrefix = '(\s*)';
2660                      $RegExSuffix = '(\w*)';
2661                      break;
2662  
2663                  case 3: # Word fragment
2664                      $RegExPrefix   = '(\w*)';
2665                      $RegExSuffix   = '(\w*)';
2666                      break;
2667              }
2668  
2669              for( $i = 0; $i < count( $_CONF['censorlist']); $i++ )
2670              {
2671                  $EditedMessage = MBYTE_eregi_replace( $RegExPrefix . $_CONF['censorlist'][$i] . $RegExSuffix, "\\1$Replacement\\2", $EditedMessage );
2672              }
2673          }
2674      }
2675  
2676      return $EditedMessage;
2677  }
2678  
2679  /**
2680  *  Takes some amount of text and replaces all javascript events on*= with in
2681  *
2682  *  This script takes some amount of text and matches all javascript events, on*= (onBlur= onMouseClick=)
2683  *  and replaces them with in*=
2684  *  Essentially this will cause onBlur to become inBlur, onFocus to be inFocus
2685  *  These are not valid javascript events and the browser will ignore them.
2686  * @param    string  $Message    Text to filter
2687  * @return   string  $Message with javascript filtered
2688  * @see  COM_checkWords
2689  * @see  COM_checkHTML
2690  *
2691  */
2692  
2693  function COM_killJS( $Message )
2694  {
2695      return( preg_replace( '/(\s)+[oO][nN](\w*) ?=/', '\1in\2=', $Message ));
2696  }
2697  
2698  /**
2699  * Handles the part within a [code] ... [/code] section, i.e. escapes all
2700  * special characters.
2701  *
2702  * @param   string  $str  the code section to encode
2703  * @return  string  $str with the special characters encoded
2704  * @see     COM_checkHTML
2705  *
2706  */
2707  function COM_handleCode( $str )
2708  {
2709      $search  = array( '&',     '\\',    '<',    '>',    '[',     ']'     );
2710      $replace = array( '&amp;', '&#92;', '&lt;', '&gt;', '&#91;', '&#93;' );
2711  
2712      $str = str_replace( $search, $replace, $str );
2713  
2714      return( $str );
2715  }
2716  
2717  /**
2718  * This function checks html tags.
2719  *
2720  * Checks to see that the HTML tags are on the approved list and
2721  * removes them if not.
2722  *
2723  * @param    string  $str            HTML to check
2724  * @param    string  $permissions    comma-separated list of rights which identify the current user as an "Admin"
2725  * @return   string                  Filtered HTML
2726  *
2727  */
2728  function COM_checkHTML( $str, $permissions = 'story.edit' )
2729  {
2730      global $_CONF;
2731  
2732      // replace any \ with &#092; (HTML equiv)
2733      $str = str_replace('\\', '&#092;', COM_stripslashes($str) );
2734  
2735      // Get rid of any newline characters
2736      $str = preg_replace( "/\n/", '', $str );
2737  
2738      // Replace any $ with &#36; (HTML equiv)
2739      $str = str_replace( '$', '&#36;', $str );
2740      // handle [code] ... [/code]
2741      do
2742      {
2743          $start_pos = MBYTE_strpos( MBYTE_strtolower( $str ), '[code]' );
2744          if( $start_pos !== false )
2745          {
2746              $end_pos = MBYTE_strpos( MBYTE_strtolower( $str ), '[/code]' );
2747              if( $end_pos !== false )
2748              {
2749                  $encoded = COM_handleCode( MBYTE_substr( $str, $start_pos + 6,
2750                          $end_pos - ( $start_pos + 6 )));
2751                  $encoded = '<pre><code>' . $encoded . '</code></pre>';
2752                  $str = MBYTE_substr( $str, 0, $start_pos ) . $encoded
2753                       . MBYTE_substr( $str, $end_pos + 7 );
2754              }
2755              else // missing [/code]
2756              {
2757                  // Treat the rest of the text as code (so as not to lose any
2758                  // special characters). However, the calling entity should
2759                  // better be checking for missing [/code] before calling this
2760                  // function ...
2761                  $encoded = COM_handleCode( MBYTE_substr( $str, $start_pos + 6 ));
2762                  $encoded = '<pre><code>' . $encoded . '</code></pre>';
2763                  $str = MBYTE_substr( $str, 0, $start_pos ) . $encoded;
2764              }
2765          }
2766      }
2767      while( $start_pos !== false );
2768  
2769      if( isset( $_CONF['skip_html_filter_for_root'] ) &&
2770               ( $_CONF['skip_html_filter_for_root'] == 1 ) &&
2771              SEC_inGroup( 'Root' ))
2772      {
2773          return $str;
2774      }
2775  
2776      // strip_tags() gets confused by HTML comments ...
2777      $str = preg_replace( '/<!--.+?-->/', '', $str );
2778  
2779      $filter = new kses4;
2780      if( isset( $_CONF['allowed_protocols'] ) && is_array( $_CONF['allowed_protocols'] ) && ( sizeof( $_CONF['allowed_protocols'] ) > 0 ))
2781      {
2782          $filter->SetProtocols( $_CONF['allowed_protocols'] );
2783      }
2784      else
2785      {
2786          $filter->SetProtocols( array( 'http:', 'https:', 'ftp:' ));
2787      }
2788  
2789      if( empty( $permissions) || !SEC_hasRights( $permissions ) ||
2790              empty( $_CONF['admin_html'] ))
2791      {
2792          $html = $_CONF['user_html'];
2793      }
2794      else
2795      {
2796          $html = array_merge_recursive( $_CONF['user_html'],
2797                                         $_CONF['admin_html'] );
2798      }
2799  
2800      foreach( $html as $tag => $attr )
2801      {
2802          $filter->AddHTML( $tag, $attr );
2803      }
2804  
2805      return $filter->Parse( $str );
2806  }
2807  
2808  /**
2809  * undo function for htmlspecialchars()
2810  *
2811  * This function translates HTML entities created by htmlspecialchars() back
2812  * into their ASCII equivalents. Also handles the entities for $, {, and }.
2813  *
2814  * @param    string   $string   The string to convert.
2815  * @return   string   The converted string.
2816  *
2817  */
2818  function COM_undoSpecialChars( $string )
2819  {
2820      $string = str_replace( '&#36;',  '$', $string );
2821      $string = str_replace( '&#123;', '{', $string );
2822      $string = str_replace( '&#125;', '}', $string );
2823      $string = str_replace( '&gt;',   '>', $string );
2824      $string = str_replace( '&lt;',   '<', $string );
2825      $string = str_replace( '&quot;', '"', $string );
2826      $string = str_replace( '&nbsp;', ' ', $string );
2827      $string = str_replace( '&amp;',  '&', $string );
2828  
2829      return( $string );
2830  }
2831  
2832  /**
2833  * Makes an ID based on current date/time
2834  *
2835  * This function creates a 17 digit sid for stories based on the 14 digit date
2836  * and a 3 digit random number that was seeded with the number of microseconds
2837  * (.000001th of a second) since the last full second.
2838  * NOTE: this is now used for more than just stories!
2839  *
2840  * @return   string  $sid  Story ID
2841  *
2842  */
2843  
2844  function COM_makesid()
2845  {
2846      $sid = date( 'YmdHis' );
2847      srand(( double ) microtime() * 1000000 );
2848      $sid .= rand( 0, 999 );
2849  
2850      return $sid;
2851  }
2852  
2853  /**
2854  * Checks to see if email address is valid.
2855  *
2856  * This function checks to see if an email address is in the correct from.
2857  *
2858  * @param    string    $email   Email address to verify
2859  * @return   boolean            True if valid otherwise false
2860  *
2861  */
2862  function COM_isEmail( $email )
2863  {
2864      require_once( 'Mail/RFC822.php' );
2865  
2866      $rfc822 = new Mail_RFC822;
2867  
2868      return( $rfc822->isValidInetAddress( $email ) ? true : false );
2869  }
2870  
2871  
2872  /**
2873  * Encode a string such that it can be used in an email header
2874  *
2875  * @param    string  $string     the text to be encoded
2876  * @return   string              encoded text
2877  *
2878  */
2879  function COM_emailEscape( $string )
2880  {
2881      global $_CONF, $LANG_CHARSET;
2882  
2883      if( empty( $LANG_CHARSET ))
2884      {
2885          $charset = $_CONF['default_charset'];
2886          if( empty( $charset ))
2887          {
2888              $charset = 'iso-8859-1';
2889          }
2890      }
2891      else
2892      {
2893          $charset = $LANG_CHARSET;
2894      }
2895  
2896      if(( $charset == 'utf-8' ) && ( $string != utf8_decode( $string )))
2897      {
2898          if( function_exists( 'iconv_mime_encode' ))
2899          {
2900              $mime_parameters = array( 'input-charset'  => 'utf-8',
2901                                        'output-charset' => 'utf-8',
2902                                        // 'Q' encoding is more readable than 'B'
2903                                        'scheme'         => 'Q'
2904                                      );
2905              $string = substr( iconv_mime_encode( '', $string,
2906                                                   $mime_parameters ), 2 );
2907          }
2908          else
2909          {
2910              $string = '=?' . $charset . '?B?' . base64_encode( $string ) . '?=';
2911          }
2912      }
2913      else if( preg_match( '/[^0-9a-z\-\.,:;\?! ]/i', $string ))
2914      {
2915          $string = '=?' . $charset . '?B?' . base64_encode( $string ) . '?=';
2916      }
2917  
2918      return $string;
2919  }
2920  
2921  /**
2922  * Takes a name and an email address and returns a string that vaguely
2923  * resembles an email address specification conforming to RFC(2)822 ...
2924  *
2925  * @param    string  $name       name, e.g. John Doe
2926  * @param    string  $address    email address only, e.g. john.doe@example.com
2927  * @return   string              formatted email address
2928  *
2929  */
2930  function COM_formatEmailAddress( $name, $address )
2931  {
2932      $formatted_name = COM_emailEscape( $name );
2933  
2934      // if the name comes back unchanged, it's not UTF-8, so preg_match is fine
2935      if(( $formatted_name == $name ) && preg_match( '/[^0-9a-z ]/i', $name ))
2936      {
2937          $formatted_name = str_replace( '"', '\\"', $formatted_name );
2938          $formatted_name = '"' . $formatted_name . '"';
2939      }
2940  
2941      return $formatted_name . ' <' . $address . '>';
2942  }
2943  
2944  /**
2945  * Send an email.
2946  *
2947  * All emails sent by Geeklog are sent through this function now.
2948  *
2949  * @param    string      $to         recipients name and email address
2950  * @param    string      $subject    subject of the email
2951  * @param    string      $message    the text of the email
2952  * @param    string      $from       (optional) sender of the the email
2953  * @param    boolean     $html       (optional) true if to be sent as HTML email
2954  * @param    int         $priority   (optional) add X-Priority header, if > 0
2955  * @param    string      $cc         (optional) other recipients (name + email)
2956  * @return   boolean                 true if successful,  otherwise false
2957  *
2958  * @note Please note that using the $cc parameter will expose the email addresses
2959  *       of all recipients. Use with care.
2960  *
2961  */
2962  function COM_mail( $to, $subject, $message, $from = '', $html = false, $priority = 0, $cc = '' )
2963  {
2964      global $_CONF, $LANG_CHARSET;
2965  
2966      static $mailobj;
2967  
2968      if( empty( $from ))
2969      {
2970          $from = COM_formatEmailAddress( $_CONF['site_name'], $_CONF['site_mail']);
2971      }
2972  
2973      $to = substr( $to, 0, strcspn( $to, "\r\n" ));
2974      $cc = substr( $cc, 0, strcspn( $cc, "\r\n" ));
2975      $from = substr( $from, 0, strcspn( $from, "\r\n" ));
2976      $subject = substr( $subject, 0, strcspn( $subject, "\r\n" ));
2977      $subject = COM_emailEscape( $subject );
2978  
2979      if( function_exists( 'CUSTOM_mail' ))
2980      {
2981          return CUSTOM_mail( $to, $subject, $message, $from, $html, $priority, $cc );
2982      }
2983  
2984      include_once( 'Mail.php' );
2985      include_once( 'Mail/RFC822.php' );
2986  
2987      $method = $_CONF['mail_settings']['backend'];
2988  
2989      if( !isset( $mailobj ))
2990      {
2991          if(( $method == 'sendmail' ) || ( $method == 'smtp' ))
2992          {
2993              $mailobj =& Mail::factory( $method, $_CONF['mail_settings'] );
2994          }
2995          else
2996          {
2997              $method = 'mail';
2998              $mailobj =& Mail::factory( $method );
2999          }
3000      }
3001  
3002      if( empty( $LANG_CHARSET ))
3003      {
3004          $charset = $_CONF['default_charset'];
3005          if( empty( $charset ))
3006          {
3007              $charset = 'iso-8859-1';
3008          }
3009      }
3010      else
3011      {
3012          $charset = $LANG_CHARSET;
3013      }
3014  
3015      $headers = array();
3016  
3017      $headers['From'] = $from;
3018      if( $method != 'mail' )
3019      {
3020          $headers['To'] = $to;
3021      }
3022      if( !empty( $cc ))
3023      {
3024          $headers['Cc'] = $cc;
3025      }
3026      $headers['Date'] = date( 'r' ); // RFC822 formatted date
3027      if( $method == 'smtp' )
3028      {
3029          list( $usec, $sec ) = explode( ' ', microtime());
3030          $m = substr( $usec, 2, 5 );
3031          $headers['Message-Id'] = '<' .  date( 'YmdHis' ) . '.' . $m
3032                                 . '@' . $_CONF['mail_settings']['host'] . '>';
3033      }
3034      if( $html )
3035      {
3036          $headers['Content-Type'] = 'text/html; charset=' . $charset;
3037          $headers['Content-Transfer-Encoding'] = '8bit';
3038      }
3039      else
3040      {
3041          $headers['Content-Type'] = 'text/plain; charset=' . $charset;
3042      }
3043      $headers['Subject'] = $subject;
3044      if( $priority > 0 )
3045      {
3046          $headers['X-Priority'] = $priority;
3047      }
3048      $headers['X-Mailer'] = 'GeekLog ' . VERSION;
3049  
3050      $retval = $mailobj->send( $to, $headers, $message );
3051      if( $retval !== true )
3052      {
3053          COM_errorLog( $retval->toString(), 1 );
3054      }
3055  
3056      return( $retval === true ? true : false );
3057  }
3058  
3059  
3060  /**
3061  * Creates older stuff block
3062  *
3063  * Creates the olderstuff block for display.
3064  * Actually updates the olderstuff record in the gl_blocks database.
3065  * @return   void
3066  */
3067  
3068  function COM_olderStuff()
3069  {
3070      global $_TABLES, $_CONF;
3071  
3072      $sql = "SELECT sid,tid,title,comments,UNIX_TIMESTAMP(date) AS day FROM {$_TABLES['stories']} WHERE (perm_anon = 2) AND (frontpage = 1) AND (date <= NOW()) AND (draft_flag = 0)" . COM_getTopicSQL( 'AND', 1 ) . " ORDER BY featured DESC, date DESC LIMIT {$_CONF['limitnews']}, {$_CONF['limitnews']}";
3073      $result = DB_query( $sql );
3074      $nrows = DB_numRows( $result );
3075  
3076      if( $nrows > 0 )
3077      {
3078          $dateonly = $_CONF['dateonly'];
3079          if( empty( $dateonly ))
3080          {
3081              $dateonly = '%d-%b'; // fallback: day - abbrev. month name
3082          }
3083  
3084          $day = 'noday';
3085          $string = '';
3086  
3087          for( $i = 0; $i < $nrows; $i++ )
3088          {
3089              $A = DB_fetchArray( $result );
3090  
3091              $daycheck = strftime( '%A', $A['day'] );
3092              if( $day != $daycheck )
3093              {
3094                  if( $day != 'noday' )
3095                  {
3096                      $daylist = COM_makeList( $oldnews, 'list-older-stories' );
3097                      $daylist = preg_replace( "/(\015\012)|(\015)|(\012)/",
3098                                               '', $daylist );
3099                      $string .= $daylist . '<br>';
3100                  }
3101  
3102                  $day2 = strftime( $dateonly, $A['day'] );
3103                  $string .= '<h3>' . $daycheck . '<small>' . $day2
3104                          . '</small></h3>' . LB;
3105                  $oldnews = array();
3106                  $day = $daycheck;
3107              }
3108  
3109              $oldnews[] = '<a href="' . COM_buildUrl( $_CONF['site_url']
3110                  . '/article.php?story=' . $A['sid'] ) . '">' . $A['title']
3111                  . '</a> (' . COM_numberFormat( $A['comments'] ) . ')';
3112          }
3113  
3114          if( !empty( $oldnews ))
3115          {
3116              $daylist = COM_makeList( $oldnews, 'list-older-stories' );
3117              $daylist = preg_replace( "/(\015\012)|(\015)|(\012)/", '', $daylist );
3118              $string .= $daylist;
3119              $string = addslashes( $string );
3120  
3121              DB_query( "UPDATE {$_TABLES['blocks']} SET content = '$string' WHERE name = 'older_stories'" );
3122          }
3123      }
3124  }
3125  
3126  /**
3127  * Shows a single Geeklog block
3128  *
3129  * This shows a single block and is typically called from
3130  * COM_showBlocks OR from plugin code
3131  *
3132  * @param        string      $name       Logical name of block (not same as title) -- 'user_block', 'admin_block', 'section_block', 'whats_new_block'.
3133  * @param        string      $help       Help file location
3134  * @param        string      $title      Title shown in block header
3135  * @see function COM_showBlocks
3136  * @return   string  HTML Formated block
3137  *
3138  */
3139  
3140  function COM_showBlock( $name, $help='', $title='' )
3141  {
3142      global $_CONF, $topic, $_TABLES, $_USER;
3143  
3144      $retval = '';
3145  
3146      if( !isset( $_USER['noboxes'] ))
3147      {
3148          if( !empty( $_USER['uid'] ))
3149          {
3150              $_USER['noboxes'] = DB_getItem( $_TABLES['userindex'], 'noboxes',
3151                                              "uid = {$_USER['uid']}" );
3152          }
3153          else
3154          {
3155              $_USER['noboxes'] = 0;
3156          }
3157      }
3158  
3159      switch( $name )
3160      {
3161          case 'user_block':
3162              $retval .= COM_userMenu( $help,$title );
3163              break;
3164  
3165          case 'admin_block':
3166              $retval .= COM_adminMenu( $help,$title );
3167              break;
3168  
3169          case 'section_block':
3170              $retval .= COM_startBlock( $title, $help,
3171                                 COM_getBlockTemplate( $name, 'header' ))
3172                  . COM_showTopics( $topic )
3173                  . COM_endBlock( COM_getBlockTemplate( $name, 'footer' ));
3174              break;
3175  
3176          case 'whats_new_block':
3177              if( !$_USER['noboxes'] )
3178              {
3179                  $retval .= COM_whatsNewBlock( $help, $title );
3180              }
3181              break;
3182      }
3183  
3184      return $retval;
3185  }
3186  
3187  
3188  /**
3189  * Shows Geeklog blocks
3190  *
3191  * Returns HTML for blocks on a given side and, potentially, for
3192  * a given topic. Currentlly only used by static pages.
3193  *
3194  * @param        string      $side       Side to get blocks for (right or left for now)
3195  * @param        string      $topic      Only get blocks for this topic
3196  * @param        string      $name       Block name (not used)
3197  * @see function COM_showBlock
3198  * @return   string  HTML Formated blocks
3199  *
3200  */
3201  
3202  function COM_showBlocks( $side, $topic='', $name='all' )
3203  {
3204      global $_CONF, $_TABLES, $_USER, $LANG21, $topic, $page;
3205  
3206      $retval = '';
3207  
3208      // Get user preferences on blocks
3209      if( !isset( $_USER['noboxes'] ) || !isset( $_USER['boxes'] ))
3210      {
3211          if( !empty( $_USER['uid'] ))
3212          {
3213              $result = DB_query( "SELECT boxes,noboxes FROM {$_TABLES['userindex']} "
3214                                 ."WHERE uid = '{$_USER['uid']}'" );
3215              list($_USER['boxes'], $_USER['noboxes']) = DB_fetchArray( $result );
3216          }
3217          else
3218          {
3219              $_USER['boxes'] = '';
3220              $_USER['noboxes'] = 0;
3221          }
3222      }
3223  
3224      $sql = "SELECT *,UNIX_TIMESTAMP(rdfupdated) AS date "
3225           . "FROM {$_TABLES['blocks']} WHERE is_enabled = 1";
3226  
3227      if( $side == 'left' )
3228      {
3229          $sql .= " AND onleft = 1";
3230      }
3231      else
3232      {
3233          $sql .= " AND onleft = 0";
3234      }
3235  
3236      if( !empty( $topic ))
3237      {
3238          $sql .= " AND (tid = '$topic' OR tid = 'all')";
3239      }
3240      else
3241      {
3242          if( COM_onFrontpage() )
3243          {
3244              $sql .= " AND (tid = 'homeonly' OR tid = 'all')";
3245          }
3246          else
3247          {
3248              $sql .= " AND (tid = 'all')";
3249          }
3250      }
3251  
3252      if( !empty( $_USER['boxes'] ))
3253      {
3254          $BOXES = str_replace( ' ', ',', $_USER['boxes'] );
3255  
3256          $sql .= " AND (bid NOT IN ($BOXES) OR bid = '-1')";
3257      }
3258  
3259      $sql .= ' ORDER BY blockorder,title asc';
3260  
3261      $result = DB_query( $sql );
3262      $nrows = DB_numRows( $result );
3263  
3264      // convert result set to an array of associated arrays
3265      $blocks = array();
3266      for( $i = 0; $i < $nrows; $i++ )
3267      {
3268          $blocks[] = DB_fetchArray( $result );
3269      }
3270  
3271      // Check and see if any plugins have blocks to show
3272      $pluginBlocks = PLG_getBlocks( $side, $topic, $name );
3273      $blocks = array_merge( $blocks, $pluginBlocks );
3274  
3275      // sort the resulting array by block order
3276      $column = 'blockorder';
3277      $sortedBlocks = $blocks;
3278      for( $i = 0; $i < sizeof( $sortedBlocks ) - 1; $i++ )
3279      {
3280          for( $j = 0; $j < sizeof( $sortedBlocks ) - 1 - $i; $j++ )
3281          {
3282              if( $sortedBlocks[$j][$column] > $sortedBlocks[$j+1][$column] )
3283              {
3284                  $tmp = $sortedBlocks[$j];
3285                  $sortedBlocks[$j] = $sortedBlocks[$j + 1];
3286                  $sortedBlocks[$j + 1] = $tmp;
3287              }
3288          }
3289      }
3290      $blocks = $sortedBlocks;
3291  
3292      // Loop though resulting sorted array and pass associative arrays
3293      // to COM_formatBlock
3294      foreach( $blocks as $A )
3295      {
3296          if( $A['type'] == 'dynamic' or SEC_hasAccess( $A['owner_id'], $A['group_id'], $A['perm_owner'], $A['perm_group'], $A['perm_members'], $A['perm_anon'] ) > 0 )
3297          {
3298             $retval .= COM_formatBlock( $A, $_USER['noboxes'] );
3299          }
3300      }
3301  
3302      return $retval;
3303  }
3304  
3305  /**
3306  * Formats a Geeklog block
3307  *
3308  * This shows a single block and is typically called from
3309  * COM_showBlocks OR from plugin code
3310  *
3311  * @param        array     $A          Block Record
3312  * @param        bool      $noboxes    Set to true if userpref is no blocks
3313  * @return       string    HTML Formated block
3314  *
3315  */
3316  function COM_formatBlock( $A, $noboxes = false )
3317  {
3318      global $_CONF, $_TABLES, $_USER, $LANG21;
3319  
3320      $retval = '';
3321      if( $A['type'] == 'portal' )
3322      {
3323          if( COM_rdfCheck( $A['bid'], $A['rdfurl'], $A['date'], $A['rdflimit'] ))
3324          {
3325              $A['content'] = DB_getItem( $_TABLES['blocks'], 'content',
3326                                          "bid = '{$A['bid']}'");
3327          }
3328      }
3329  
3330      if( $A['type'] == 'gldefault' )
3331      {
3332          $retval .= COM_showBlock( $A['name'], $A['help'], $A['title'] );
3333      }
3334  
3335      if( $A['type'] == 'phpblock' && !$noboxes )
3336      {
3337          if( !( $A['name'] == 'whosonline_block' AND DB_getItem( $_TABLES['blocks'], 'is_enabled', "name='whosonline_block'" ) == 0 ))
3338          {
3339              $function = $A['phpblockfn'];
3340              $blkheader = COM_startBlock( $A['title'], $A['help'],
3341                      COM_getBlockTemplate( $A['name'], 'header' ));
3342              $blkfooter = COM_endBlock( COM_getBlockTemplate( $A['name'],
3343                      'footer' ));
3344  
3345              if( function_exists( $function ))
3346              {
3347                  $fretval = $function();
3348                  if( !empty( $fretval ))
3349                  {
3350                      $retval .= $blkheader;
3351                      $retval .= $fretval;
3352                      $retval .= $blkfooter;
3353                  }
3354              }
3355              else
3356              {
3357                  // show error message
3358                  $retval .= $blkheader;
3359                  $retval .= sprintf( $LANG21[31], $function );
3360                  $retval .= $blkfooter;
3361              }
3362          }
3363      }
3364  
3365      if( !empty( $A['content'] ) && ( trim( $A['content'] ) != '' ) && !$noboxes )
3366      {
3367          $blockcontent = stripslashes( $A['content'] );
3368  
3369          // Hack: If the block content starts with a '<' assume it
3370          // contains HTML and do not call nl2br() which would only add
3371          // unwanted <br> tags.
3372  
3373          if( substr( $blockcontent, 0, 1 ) != '<' )
3374          {
3375              $blockcontent = nl2br( $blockcontent );
3376          }
3377  
3378          if ($A['allow_autotags'] == 1) {
3379              $blockcontent = PLG_replaceTags( $blockcontent );
3380          }
3381          $blockcontent = str_replace( array( '<?', '?>' ), '', $blockcontent );
3382  
3383          $retval .= COM_startBlock( $A['title'], $A['help'],
3384                         COM_getBlockTemplate( $A['name'], 'header' ))
3385                  . $blockcontent . LB
3386                  . COM_endBlock( COM_getBlockTemplate( $A['name'], 'footer' ));
3387      }
3388  
3389      return $retval;
3390  }
3391  
3392  
3393  /**
3394  * Checks to see if it's time to import and RDF/RSS block again
3395  *
3396  * Updates RDF/RSS block if needed
3397  *
3398  * @param    string  $bid            Block ID
3399  * @param    string  $rdfurl         URL to get headlines from
3400  * @param    string  $date           Last time the headlines were imported
3401  * @param    string  $maxheadlines   max. number of headlines to import
3402  * @return   void
3403  * @see function COM_rdfImport
3404  *
3405  */
3406  function COM_rdfCheck( $bid, $rdfurl, $date, $maxheadlines = 0 )
3407  {
3408      $retval = false;
3409      $nextupdate = $date + 3600;
3410  
3411      if( $nextupdate < time() )
3412      {
3413          COM_rdfImport( $bid, $rdfurl, $maxheadlines );
3414          $retval = true;
3415      }
3416  
3417      return $retval;
3418  }
3419  
3420  /**
3421  * Syndication import function. Imports headline data to a portal block.
3422  *
3423  * Rewritten December 19th 2004 by Michael Jervis (mike@fuckingbrit.com). Now
3424  * utilises a Factory Pattern to open a URL and automaticaly retreive a feed
3425  * object populated with feed data. Then import it into the portal block.
3426  *
3427  * @param    string  $bid            Block ID
3428  * @param    string  $rdfurl         URL to get content from
3429  * @param    int     $maxheadlines   Maximum number of headlines to display
3430  * @return   void
3431  * @see function COM_rdfCheck
3432  *
3433  */
3434  function COM_rdfImport( $bid, $rdfurl, $maxheadlines = 0 )
3435  {
3436      global $_CONF, $_TABLES, $LANG21, $LANG_CHARSET;
3437  
3438      // Import the feed handling classes:
3439      require_once( $_CONF['path_system']
3440                    . '/classes/syndication/parserfactory.class.php' );
3441      require_once( $_CONF['path_system']
3442                    . '/classes/syndication/feedparserbase.class.php' );
3443  
3444      // Load the actual feed handlers:
3445      $factory = new FeedParserFactory( $_CONF['path_system']
3446                                        . '/classes/syndication/' );
3447      $factory->userAgent = 'GeekLog/' . VERSION;
3448      $feed = $factory->reader( $rdfurl, $_CONF['default_charset'] );
3449  
3450      // Aquire a reader:
3451      if( $feed )
3452      {
3453          /* We have located a reader, and populated it with the information from
3454           * the syndication file. Now we will sort out our display, and update
3455           * the block.
3456           */
3457          if( $maxheadlines == 0 )
3458          {
3459              if( !empty( $_CONF['syndication_max_headlines'] ))
3460              {
3461                  $maxheadlines = $_CONF['syndication_max_headlines'];
3462              }
3463              else
3464              {
3465                  $maxheadlines = count( $feed->articles );
3466              }
3467          }
3468  
3469          $update = date( 'Y-m-d H:i:s' );
3470          $result = DB_change( $_TABLES['blocks'], 'rdfupdated', $update,
3471                                                   'bid', $bid );
3472  
3473          if( empty( $LANG_CHARSET ))
3474          {
3475              $charset = $_CONF['default_charset'];
3476              if( empty( $charset ))
3477              {
3478                  $charset = 'iso-8859-1';
3479              }
3480          }
3481          else
3482          {
3483              $charset = $LANG_CHARSET;
3484          }
3485  
3486          // format articles for display
3487          $readmax = min( $maxheadlines, count( $feed->articles ));
3488          for( $i = 0; $i < $readmax; $i++ )
3489          {
3490              if( empty( $feed->articles[$i]['title'] ))
3491              {
3492                  $feed->articles[$i]['title'] = $LANG21[61];
3493              }
3494  
3495              if( $charset == 'utf-8' )
3496              {
3497                  $title = $feed->articles[$i]['title'];
3498              }
3499              else
3500              {
3501                  $title = utf8_decode( $feed->articles[$i]['title'] );
3502              }
3503              $content = '<a href="' . $feed->articles[$i]['link'] . '">'
3504                       . $title . '</a>';
3505              $articles[] = $content;
3506          }
3507  
3508          // build a list
3509          $content = COM_makeList( $articles, 'list-feed' );
3510          $content = preg_replace( "/(\015\012)|(\015)|(\012)/", '', $content );
3511  
3512          // Standard theme based function to put it in the block
3513          $result = DB_change( $_TABLES['blocks'], 'content',
3514                               addslashes( $content ), 'bid', $bid );
3515      }
3516      else
3517      {
3518          // failed to aquire info, 0 out the block and log an error
3519          COM_errorLog( "Unable to aquire feed reader for $rdfurl", 1 );
3520          COM_errorLog( $factory->errorStatus[0] . ' ' .
3521                                      $factory->errorStatus[1] . ' ' .
3522                                      $factory->errorStatus[2] );
3523          $result = DB_change( $_TABLES['blocks'], 'content',
3524                               addslashes( $LANG21[4] ), 'bid', $bid );
3525      }
3526  }
3527  
3528  
3529  /**
3530  * Returns what HTML is allowed in content
3531  *
3532  * Returns what HTML tags the system allows to be used inside content.
3533  * You can modify this by changing $_CONF['user_html'] in config.php
3534  * (for admins, see also $_CONF['admin_html']).
3535  *
3536  * @param    string  $permissions    comma-separated list of rights which identify the current user as an "Admin"
3537  * @param    boolean $list_only      true = return only the list of HTML tags
3538  * @return   string  HTML <span> enclosed string
3539  * @see function COM_checkHTML
3540  */
3541  function COM_allowedHTML( $permissions = 'story.edit', $list_only = false )
3542  {
3543      global $_CONF, $LANG01;
3544  
3545      $retval = '';
3546  
3547      if( isset( $_CONF['skip_html_filter_for_root'] ) &&
3548               ( $_CONF['skip_html_filter_for_root'] == 1 ) &&
3549              SEC_inGroup( 'Root' ))
3550      {
3551          if( !$list_only )
3552          {
3553              $retval .= '<span class="warningsmall">' . $LANG01[123] . '</span>';
3554          }
3555  
3556          return $retval;
3557      }
3558  
3559      if( !$list_only )
3560      {
3561          $retval .= '<span class="warningsmall">' . $LANG01[31] . ' ';
3562      }
3563  
3564      $allow_page_break = false;
3565      if( empty( $permissions ) || !SEC_hasRights( $permissions ) ||
3566              empty( $_CONF['admin_html'] ))
3567      {
3568          $html = $_CONF['user_html'];
3569      }
3570      else
3571      {
3572          $html = array_merge_recursive( $_CONF['user_html'],
3573                                         $_CONF['admin_html'] );
3574          if( $_CONF['allow_page_breaks'] == 1 )
3575          {
3576              $perms = explode( ',', $permissions );
3577              foreach( $perms as $p )
3578              {
3579                  if( substr( $p, 0, 6 ) == 'story.' )
3580                  {
3581                      $allow_page_break = true;
3582                      break;
3583                  }
3584              }
3585          }
3586      }
3587  
3588      foreach( $html as $tag => $attr )
3589      {
3590          $retval .= '&lt;' . $tag . '&gt;, ';
3591      }
3592  
3593      $retval .= '[code]';
3594  
3595      if( $allow_page_break )
3596      {
3597          $retval .= ', [page_break]';
3598      }
3599  
3600      // list autolink tags
3601      $autotags = PLG_collectTags();
3602      foreach( $autotags as $tag => $module )
3603      {
3604          $retval .= ', [' . $tag . ':]';
3605      }
3606  
3607      if( !$list_only )
3608      {
3609          $retval .= '</span>';
3610      }
3611  
3612      return $retval;
3613  }
3614  
3615  /**
3616  * Return the password for the given username
3617  *
3618  * Fetches a password for the given user
3619  *
3620  * @param    string  $loginname  username to get password for
3621  * @return   string              Password or ''
3622  *
3623  */
3624  
3625  function COM_getPassword( $loginname )
3626  {
3627      global $_TABLES, $LANG01;
3628  
3629      $result = DB_query( "SELECT passwd FROM {$_TABLES['users']} WHERE username='$loginname'" );
3630      $tmp = DB_error();
3631      $nrows = DB_numRows( $result );
3632  
3633      if(( $tmp == 0 ) && ( $nrows == 1 ))
3634      {
3635          $U = DB_fetchArray( $result );
3636          return $U['passwd'];
3637      }
3638      else
3639      {
3640          $tmp = $LANG01[32] . ": '" . $loginname . "'";
3641          COM_errorLog( $tmp, 1 );
3642      }
3643  
3644      return '';
3645  }
3646  
3647  
3648  /**
3649  * Return the username or fullname for the passed member id (uid)
3650  *
3651  * Allows the siteAdmin to determine if loginname (username) or fullname
3652  * should be displayed.
3653  *
3654  * @param    int  $uid  site member id
3655  * @param    string  $username   Username, if this is set no lookup is done.
3656  * @param    string  $fullname   Users full name.
3657  * @param    string  $service    Remote login service.
3658  * @return   string  Username, fullname or username@Service
3659  *
3660  */
3661  function COM_getDisplayName( $uid = '', $username='', $fullname='', $remoteusername='', $remoteservice='' )
3662  {
3663      global $_CONF, $_TABLES, $_USER;
3664  
3665      if ($uid == '')
3666      {
3667          if( empty( $_USER['uid'] ) || ( $_USER['uid'] <= 1 ))
3668          {
3669              $uid = 1;
3670          }
3671          else
3672          {
3673              $uid = $_USER['uid'];
3674          }
3675      }
3676  
3677      if( empty( $username ))
3678      {
3679          $query = DB_query( "SELECT username, fullname, remoteusername, remoteservice FROM {$_TABLES['users']} WHERE uid='$uid'" );
3680          list( $username, $fullname, $remoteusername, $remoteservice ) = DB_fetchArray( $query );
3681      }
3682  
3683      if( !empty( $fullname ) && ($_CONF['show_fullname'] == 1 ))
3684      {
3685          return $fullname;
3686      }
3687      else if( $_CONF['remoteauthentication'] && $_CONF['show_servicename'] &&
3688                      !empty( $remoteusername ))
3689      {
3690          return "$remoteusername@$remoteservice";
3691      }
3692  
3693      return $username;
3694  }
3695  
3696  
3697  /**
3698  * Adds a hit to the system
3699  *
3700  * This function is called in the footer of every page and is used to
3701  * track the number of hits to the Geeklog system.  This information is
3702  * shown on stats.php
3703  *
3704  */
3705  
3706  function COM_hit()
3707  {
3708      global $_TABLES;
3709  
3710      DB_query( "UPDATE {$_TABLES['vars']} SET value = value + 1 WHERE name = 'totalhits'" );
3711  }
3712  
3713  /**
3714  * This will email new stories in the topics that the user is interested in
3715  *
3716  * In account information the user can specify which topics for which they
3717  * will receive any new article for in a daily digest.
3718  *
3719  * @return   void
3720  */
3721  
3722  function COM_emailUserTopics()
3723  {
3724      global $_CONF, $_TABLES, $LANG08, $LANG24;
3725  
3726      $subject = strip_tags( $_CONF['site_name'] . $LANG08[30] . strftime( '%Y-%m-%d', time() ));
3727  
3728      $authors = array();
3729  
3730      // Get users who want stories emailed to them
3731      $usersql = "SELECT username,email,etids,{$_TABLES['users']}.uid AS uuid "
3732          . "FROM {$_TABLES['users']}, {$_TABLES['userindex']} "
3733          . "WHERE {$_TABLES['users']}.uid > 1 AND {$_TABLES['userindex']}.uid = {$_TABLES['users']}.uid AND (etids <> '-' OR etids IS NULL) ORDER BY {$_TABLES['users']}.uid";
3734  
3735      $users = DB_query( $usersql );
3736      $nrows = DB_numRows( $users );
3737  
3738      $lastrun = DB_getItem( $_TABLES['vars'], 'value', "name = 'lastemailedstories'" );
3739  
3740      // For each user, pull the stories they want and email it to them
3741      for( $x = 1; $x <= $nrows; $x++ )
3742      {
3743          $U = DB_fetchArray( $users );
3744  
3745          $storysql = array();
3746          $storysql['mysql'] = "SELECT sid,uid,date AS day,title,introtext,bodytext";
3747  
3748          $storysql['mssql'] = "SELECT sid,uid,date AS day,title,CAST(introtext AS text) AS introtext,CAST(bodytext AS text) AS introtext";
3749  
3750          $commonsql = " FROM {$_TABLES['stories']} WHERE draft_flag = 0 AND date <= NOW() AND date >= '{$lastrun}'";
3751  
3752          $topicsql = "SELECT tid FROM {$_TABLES['topics']}"
3753                    . COM_getPermSQL( 'WHERE', $U['uuid'] );
3754          $tresult = DB_query( $topicsql );
3755          $trows = DB_numRows( $tresult );
3756  
3757          if( $trows == 0 )
3758          {
3759              // this user doesn't seem to have access to any topics ...
3760              continue;
3761          }
3762  
3763          $TIDS = array();
3764          for( $i = 1; $i <= $trows; $i++ )
3765          {
3766              $T = DB_fetchArray( $tresult );
3767              $TIDS[] = $T['tid'];
3768          }
3769  
3770          if( !empty( $U['etids'] ))
3771          {
3772              $ETIDS = explode( ' ', $U['etids'] );
3773              $TIDS = array_intersect( $TIDS, $ETIDS );
3774          }
3775  
3776          if( sizeof( $TIDS ) > 0)
3777          {
3778              $commonsql .= " AND (tid IN ('" . implode( "','", $TIDS ) . "'))";
3779          }
3780  
3781          $commonsql .= COM_getPermSQL( 'AND', $U['uuid'] );
3782          $commonsql .= ' ORDER BY featured DESC, date DESC';
3783  
3784          $storysql['mysql'] .= $commonsql;
3785          $storysql['mssql'] .= $commonsql;
3786  
3787          $stories = DB_query( $storysql );
3788          $nsrows = DB_numRows( $stories );
3789  
3790          if( $nsrows == 0 )
3791          {
3792              // If no new stories where pulled for this user, continue with next
3793              continue;
3794          }
3795  
3796          $mailtext = $LANG08[29] . strftime( $_CONF['shortdate'], time() ) . "\n";
3797  
3798          for( $y = 0; $y < $nsrows; $y++ )
3799          {
3800              // Loop through stories building the requested email message
3801              $S = DB_fetchArray( $stories );
3802  
3803              $mailtext .= "\n------------------------------\n\n";
3804              $mailtext .= "$LANG08[31]: "
3805                  . COM_undoSpecialChars( stripslashes( $S['title'] )) . "\n";
3806              if( $_CONF['contributedbyline'] == 1 )
3807              {
3808                  if( empty( $authors[$S['uid']] ))
3809                  {
3810                      $storyauthor = COM_getDisplayName ($S['uid']);
3811                      $authors[$S['uid']] = $storyauthor;
3812                  }
3813                  else
3814                  {
3815                      $storyauthor = $authors[$S['uid']];
3816                  }
3817                  $mailtext .= "$LANG24[7]: " . $storyauthor . "\n";
3818              }
3819  
3820              $mailtext .= "$LANG08[32]: " . strftime( $_CONF['date'], strtotime( $S['day' ])) . "\n\n";
3821  
3822              if( $_CONF['emailstorieslength'] > 0 )
3823              {
3824                  $storytext = COM_undoSpecialChars( strip_tags( PLG_replaceTags( stripslashes( $S['introtext'] ))));
3825  
3826                  if( $_CONF['emailstorieslength'] > 1 )
3827                  {
3828                      $storytext = COM_truncate( $storytext,
3829                                      $_CONF['emailstorieslength'], '...' );
3830                  }
3831  
3832                  $mailtext .= $storytext . "\n\n";
3833              }
3834  
3835              $mailtext .= $LANG08[33] . ' ' . COM_buildUrl( $_CONF['site_url']
3836                        . '/article.php?story=' . $S['sid'] ) . "\n";
3837          }
3838  
3839          $mailtext .= "\n------------------------------\n";
3840          $mailtext .= "\n$LANG08[34]\n";
3841          $mailtext .= "\n------------------------------\n";
3842  
3843          $mailto = $U['username'] . ' <' . $U['email'] . '>';
3844  
3845          COM_mail( $mailto, $subject, $mailtext );
3846      }
3847  
3848      DB_query( "UPDATE {$_TABLES['vars']} SET value = NOW() WHERE name = 'lastemailedstories'" );
3849  }
3850  
3851  /**
3852  * Shows any new information in a block
3853  *
3854  * Return the HTML that shows any new stories, comments, etc
3855  *
3856  * @param    string  $help   Help file for block
3857  * @param    string  $title  Title used in block header
3858  * @return   string  Return the HTML that shows any new stories, comments, etc
3859  *
3860  */
3861  
3862  function COM_whatsNewBlock( $help = '', $title = '' )
3863  {
3864      global $_CONF, $_TABLES, $_USER, $LANG01, $LANG_WHATSNEW, $page, $newstories;
3865  
3866      $retval = COM_startBlock( $title, $help,
3867                         COM_getBlockTemplate( 'whats_new_block', 'header' ));
3868  
3869      $topicsql = '';
3870      if(( $_CONF['hidenewstories'] == 0 ) || ( $_CONF['hidenewcomments'] == 0 )
3871              || ( $_CONF['trackback_enabled']
3872              && ( $_CONF['hidenewtrackbacks'] == 0 )))
3873      {
3874          $topicsql = COM_getTopicSql ('AND', 0, $_TABLES['stories']);
3875      }
3876  
3877      if( $_CONF['hidenewstories'] == 0 )
3878      {
3879          $archsql = '';
3880          $archivetid = DB_getItem( $_TABLES['topics'], 'tid', "archive_flag=1" );
3881          if( !empty( $archivetid ))
3882          {
3883              $archsql = " AND (tid <> '" . addslashes( $archivetid ) . "')";
3884          }
3885  
3886          // Find the newest stories
3887          $sql = "SELECT COUNT(*) AS count FROM {$_TABLES['stories']} WHERE (date >= (date_sub(NOW(), INTERVAL {$_CONF['newstoriesinterval']} SECOND))) AND (date <= NOW()) AND (draft_flag = 0)" . $archsql . COM_getPermSQL( 'AND' ) . $topicsql . COM_getLangSQL( 'sid', 'AND' );
3888          $result = DB_query( $sql );
3889          $A = DB_fetchArray( $result );
3890          $nrows = $A['count'];
3891  
3892          if( empty( $title ))
3893          {
3894              $title = DB_getItem( $_TABLES['blocks'], 'title', "name='whats_new_block'" );
3895          }
3896  
3897          // Any late breaking news stories?
3898          $retval .= '<h3>' . $LANG01[99] . '</h3>';
3899  
3900          if( $nrows > 0 )
3901          {
3902              $newmsg = COM_formatTimeString( $LANG_WHATSNEW['new_string'],
3903                          $_CONF['newstoriesinterval'], $LANG01[11], $nrows);
3904  
3905              if( $newstories && ( $page < 2 ))
3906              {
3907                  $retval .= $newmsg . '<br>';
3908              }
3909              else
3910              {
3911                  $retval .= '<a href="' . $_CONF['site_url']
3912                      . '/index.php?display=new">' . $newmsg . '</a><br>';
3913              }
3914          }
3915          else
3916          {
3917              $retval .= $LANG01[100] . '<br>';
3918          }
3919  
3920          if(( $_CONF['hidenewcomments'] == 0 ) || ( $_CONF['trackback_enabled']
3921                  && ( $_CONF['hidenewtrackbacks'] == 0 ))
3922                  || ( $_CONF['hidenewplugins'] == 0 ))
3923          {
3924              $retval .= '<br>';
3925          }
3926      }
3927  
3928      if( $_CONF['hidenewcomments'] == 0 )
3929      {
3930          // Go get the newest comments
3931          $retval .= '<h3>' . $LANG01[83] . ' <small>'
3932                  . COM_formatTimeString( $LANG_WHATSNEW['new_last'],
3933                                          $_CONF['newcommentsinterval'] )
3934                  . '</small></h3>';
3935  
3936          $stwhere = '';
3937  
3938          if( !empty( $_USER['uid'] ))
3939          {
3940              $stwhere .= "({$_TABLES['stories']}.owner_id IS NOT NULL AND {$_TABLES['stories']}.perm_owner IS NOT NULL) OR ";
3941              $stwhere .= "({$_TABLES['stories']}.group_id IS NOT NULL AND {$_TABLES['stories']}.perm_group IS NOT NULL) OR ";
3942              $stwhere .= "({$_TABLES['stories']}.perm_members IS NOT NULL)";
3943          }
3944          else
3945          {
3946              $stwhere .= "({$_TABLES['stories']}.perm_anon IS NOT NULL)";
3947          }
3948          $sql = "SELECT DISTINCT COUNT(*) AS dups, type, {$_TABLES['stories']}.title, {$_TABLES['stories']}.sid, max({$_TABLES['comments']}.date) AS lastdate FROM {$_TABLES['comments']} LEFT JOIN {$_TABLES['stories']} ON (({$_TABLES['stories']}.sid = {$_TABLES['comments']}.sid)" . COM_getPermSQL( 'AND', 0, 2, $_TABLES['stories'] ) . " AND ({$_TABLES['stories']}.draft_flag = 0) AND ({$_TABLES['stories']}.commentcode = 0)" . $topicsql . COM_getLangSQL( 'sid', 'AND', $_TABLES['stories'] ) . ") WHERE ({$_TABLES['comments']}.date >= (DATE_SUB(NOW(), INTERVAL {$_CONF['newcommentsinterval']} SECOND))) AND ((({$stwhere}))) GROUP BY {$_TABLES['comments']}.sid,type, {$_TABLES['stories']}.title, {$_TABLES['stories']}.title, {$_TABLES['stories']}.sid ORDER BY 5 DESC LIMIT 15";
3949  
3950          $result = DB_query( $sql );
3951  
3952          $nrows = DB_numRows( $result );
3953  
3954          if( $nrows > 0 )
3955          {
3956              $newcomments = array();
3957  
3958              for( $x = 0; $x < $nrows; $x++ )
3959              {
3960                  $A = DB_fetchArray( $result );
3961  
3962                  if(( $A['type'] == 'article' ) || empty( $A['type'] ))
3963                  {
3964                      $urlstart = '<a href="' . COM_buildUrl( $_CONF['site_url']
3965                          . '/article.php?story=' . $A['sid'] ) . '#comments' . '"';
3966                  }
3967  
3968                  $title = COM_undoSpecialChars( stripslashes( $A['title'] ));
3969                  $titletouse = COM_truncate( $title, $_CONF['title_trim_length'],
3970                                              '...' );
3971  
3972                  if( $title != $titletouse )
3973                  {
3974                      $urlstart .= ' title="' . htmlspecialchars( $title ) . '">';
3975                  }
3976                  else
3977                  {
3978                      $urlstart .= '>';
3979                  }
3980  
3981                  $acomment = str_replace( '$', '&#36;', $titletouse );
3982                  $acomment = str_replace( ' ', '&nbsp;', $acomment );
3983  
3984                  if( $A['dups'] > 1 )
3985                  {
3986                      $acomment .= ' [+' . $A['dups'] . ']';
3987                  }
3988  
3989                  $newcomments[] = $urlstart . $acomment . '</a>';
3990              }
3991  
3992              $retval .= COM_makeList( $newcomments, 'list-new-comments' );
3993          }
3994          else
3995          {
3996              $retval .= $LANG01[86] . '<br>' . LB;
3997          }
3998          if(( $_CONF['hidenewplugins'] == 0 )
3999                  || ( $_CONF['trackback_enabled']
4000                  && ( $_CONF['hidenewtrackbacks'] == 0 )))
4001          {
4002              $retval .= '<br>';
4003          }
4004      }
4005  
4006      if( $_CONF['trackback_enabled'] && ( $_CONF['hidenewtrackbacks'] == 0 ))
4007      {
4008          $retval .= '<h3>' . $LANG01[114] . ' <small>'
4009                  . COM_formatTimeString( $LANG_WHATSNEW['new_last'],
4010                                          $_CONF['newtrackbackinterval'] )
4011                  . '</small></h3>';
4012  
4013          $sql = "SELECT DISTINCT COUNT(*) AS count,{$_TABLES['stories']}.title,t.sid,max(t.date) AS lastdate FROM {$_TABLES['trackback']} AS t,{$_TABLES['stories']} WHERE (t.type = 'article') AND (t.sid = {$_TABLES['stories']}.sid) AND (t.date >= (DATE_SUB(NOW(), INTERVAL {$_CONF['newtrackbackinterval']} SECOND)))" . COM_getPermSQL( 'AND', 0, 2, $_TABLES['stories'] ) . " AND ({$_TABLES['stories']}.draft_flag = 0) AND ({$_TABLES['stories']}.trackbackcode = 0)" . $topicsql . COM_getLangSQL( 'sid', 'AND', $_TABLES['stories'] ) . " GROUP BY t.sid, {$_TABLES['stories']}.title ORDER BY lastdate DESC LIMIT 15";
4014          $result = DB_query( $sql );
4015  
4016          $nrows = DB_numRows( $result );
4017          if( $nrows > 0 )
4018          {
4019              $newcomments = array();
4020  
4021              for( $i = 0; $i < $nrows; $i++ )
4022              {
4023                  $A = DB_fetchArray( $result );
4024  
4025                  $urlstart = '<a href="' . COM_buildUrl( $_CONF['site_url']
4026                      . '/article.php?story=' . $A['sid'] ) . '#trackback' . '"';
4027  
4028                  $title = COM_undoSpecialChars( stripslashes( $A['title'] ));
4029                  $titletouse = COM_truncate( $title, $_CONF['title_trim_length'],
4030                                              '...' );
4031  
4032                  if( $title != $titletouse )
4033                  {
4034                      $urlstart .= ' title="' . htmlspecialchars( $title ) . '">';
4035                  }
4036                  else
4037                  {
4038                      $urlstart .= '>';
4039                  }
4040  
4041                  $acomment = str_replace( '$', '&#36;', $titletouse );
4042                  $acomment = str_replace( ' ', '&nbsp;', $acomment );
4043  
4044                  if( $A['count'] > 1 )
4045                  {
4046                      $acomment .= ' [+' . $A['count'] . ']';
4047                  }
4048  
4049                  $newcomments[] = $urlstart . $acomment . '</a>';
4050              }
4051  
4052              $retval .= COM_makeList( $newcomments, 'list-new-trackbacks' );
4053          }
4054          else
4055          {
4056              $retval .= $LANG01[115] . '<br>' . LB;
4057          }
4058          if( $_CONF['hidenewplugins'] == 0 )
4059          {
4060              $retval .= '<br>';
4061          }
4062      }
4063  
4064      if( $_CONF['hidenewplugins'] == 0 )
4065      {
4066          list( $headlines, $smallheadlines, $content ) = PLG_getWhatsNew();
4067          $plugins = sizeof( $headlines );
4068          if( $plugins > 0 )
4069          {
4070              for( $i = 0; $i < $plugins; $i++ )
4071              {
4072                  $retval .= '<h3>' . $headlines[$i] . ' <small>'
4073                          . $smallheadlines[$i] . '</small></h3>';
4074                  if( is_array( $content[$i] ))
4075                  {
4076                      $retval .= COM_makeList( $content[$i], 'list-new-plugins' );
4077                  }
4078                  else
4079                  {
4080                      $retval .= $content[$i];
4081                  }
4082  
4083                  if( $i + 1 < $plugins )
4084                  {
4085                      $retval .= '<br>';
4086                  }
4087              }
4088          }
4089      }
4090  
4091      $retval .= COM_endBlock( COM_getBlockTemplate( 'whats_new_block', 'footer' ));
4092  
4093      return $retval;
4094  }
4095  
4096  /**
4097  * Creates the string that indicates the timespan in which new items were found
4098  *
4099  * @param    string  $time_string    template string
4100  * @param    int     $time           number of seconds in which results are found
4101  * @param    string  $type           type (translated string) of new item
4102  * @param    int     $amount         amount of things that have been found.
4103  */
4104  function COM_formatTimeString( $time_string, $time, $type = '', $amount = 0 )
4105  {
4106      global $LANG_WHATSNEW;
4107  
4108      $retval = $time_string;
4109  
4110      // This is the amount you have to divide the previous by to get the
4111      // different time intervals: hour, day, week, months
4112      $time_divider = array( 60, 60, 24, 7, 30 );
4113  
4114      // These are the respective strings to the numbers above. They have to match
4115      // the strings in $LANG_WHATSNEW (i.e. these are the keys for the array -
4116      // the actual text strings are taken from the language file).
4117      $time_description  = array( 'minute',  'hour',  'day',  'week',  'month'  );
4118      $times_description = array( 'minutes', 'hours', 'days', 'weeks', 'months' );
4119  
4120      for( $s = 0; $s < count( $time_divider ); $s++ )
4121      {
4122          $time = $time / $time_divider[$s];
4123          if( $time < $time_divider[$s + 1] )
4124          {
4125              if( $time == 1 )
4126              {
4127                  if( $s == 0 )
4128                  {
4129                      $time_str = $time_description[$s];
4130                  }
4131                  else // go back to the previous unit, e.g. 1 day -> 24 hours
4132                  {
4133                      $time_str = $times_description[$s - 1];
4134                      $time *= $time_divider[$s];
4135                  }
4136              }
4137              else
4138              {
4139                  $time_str = $times_description[$s];
4140              }
4141              $fields = array( '%n', '%i', '%t', '%s' );
4142              $values = array( $amount, $type, $time, $LANG_WHATSNEW[$time_str] );
4143              $retval = str_replace( $fields, $values, $retval );
4144              break;
4145          }
4146      }
4147  
4148      return $retval;
4149  }
4150  
4151  
4152  /**
4153  * Displays a message on the webpage
4154  *
4155  * Pulls $msg off the URL string and gets the corresponding message and returns
4156  * it for display on the calling page
4157  *
4158  * @param      int     $msg        ID of message to show
4159  * @param      string  $plugin     Optional Name of plugin to lookup plugin defined message
4160  * @return     string  HTML block with message
4161  */
4162  
4163  function COM_showMessage( $msg, $plugin='' )
4164  {
4165      global $_CONF, $MESSAGE, $_IMAGE_TYPE;
4166  
4167      $retval = '';
4168  
4169      if( $msg > 0 )
4170      {
4171          if( !empty( $plugin ))
4172          {
4173              $var = 'PLG_' . $plugin . '_MESSAGE' . $msg;
4174              global $$var;
4175              if( isset( $$var ))
4176              {
4177                  $message = $$var;
4178              }
4179              else
4180              {
4181                  $message = sprintf( $MESSAGE[61], $plugin );
4182                  COM_errorLog ($MESSAGE[61]. ": " . $var,1);
4183              }
4184          }
4185          else
4186          {
4187              $message = $MESSAGE[$msg];
4188          }
4189  
4190          $timestamp = strftime( $_CONF['daytime'] );
4191          $retval .= COM_startBlock( $MESSAGE[40] . ' - ' . $timestamp, '',
4192                             COM_getBlockTemplate( '_msg_block', 'header' ))
4193              . '<p style="padding:5px"><img src="' . $_CONF['layout_url']
4194              . '/images/sysmessage.' . $_IMAGE_TYPE . '" border="0" align="left"'
4195              . ' alt="" style="padding-right:5px; padding-bottom:3px">'
4196              . $message . '</p>'
4197              . COM_endBlock( COM_getBlockTemplate( '_msg_block', 'footer' ));
4198      }
4199  
4200      return $retval;
4201  }
4202  
4203  
4204  /**
4205  * Prints Google(tm)-like paging navigation
4206  *
4207  * @param        string      $base_url       base url to use for all generated links
4208  * @param        int         $curpage        current page we are on
4209  * @param        int         $num_pages      Total number of pages
4210  * @param        string      $page_str       page-variable name AND '='
4211  * @param        bool        $do_rewrite     if true, url-rewriting is respected
4212  * @param        string      $msg            to be displayed with the navigation
4213  * @param        string      $open_ended     replace next/last links with this
4214  * @return   string   HTML formatted widget
4215  */
4216  function COM_printPageNavigation( $base_url, $curpage, $num_pages,
4217                                    $page_str='page=', $do_rewrite=false, $msg='',
4218                                    $open_ended = '')
4219  {
4220      global $LANG05;
4221  
4222      $retval = '';
4223  
4224      if( $num_pages < 2 )
4225      {
4226          return;
4227      }
4228  
4229      if( !$do_rewrite )
4230      {
4231          $hasargs = strstr( $base_url, '?' );
4232          if( $hasargs )
4233          {
4234              $sep = '&amp;';
4235          }
4236          else
4237          {
4238              $sep = '?';
4239          }
4240      }
4241      else
4242      {
4243          $sep = '/';
4244          $page_str = '';
4245      }
4246  
4247      if( $curpage > 1 )
4248      {
4249          $retval .= '<a href="' . $base_url . '">' . $LANG05[7] . '</a> | ';
4250          $pg = '';
4251          if( ( $curpage - 1 ) > 1 )
4252          {
4253              $pg = $sep . $page_str . ( $curpage - 1 );
4254          }
4255          $retval .= '<a href="' . $base_url . $pg . '">' . $LANG05[6]
4256                  . '</a> | ';
4257      }
4258      else
4259      {
4260          $retval .= $LANG05[7] . ' | ' ;
4261          $retval .= $LANG05[6] . ' | ' ;
4262      }
4263  
4264      for( $pgcount = ( $curpage - 10 ); ( $pgcount <= ( $curpage + 9 )) AND ( $pgcount <= $num_pages ); $pgcount++ )
4265      {
4266          if( $pgcount <= 0 )
4267          {
4268              $pgcount = 1;
4269          }
4270  
4271          if( $pgcount == $curpage )
4272          {
4273              $retval .= '<b>' . $pgcount . '</b> ';
4274          }
4275          else
4276          {
4277              $pg = '';
4278              if( $pgcount > 1 )
4279              {
4280                  $pg = $sep . $page_str . $pgcount;
4281              }
4282              $retval .= '<a href="' . $base_url . $pg . '">' . $pgcount
4283                      . '</a> ';
4284          }
4285      }
4286  
4287      if( !empty( $open_ended ))
4288      {
4289          $retval .= '| ' . $open_ended;
4290      }
4291      else if( $curpage == $num_pages )
4292      {
4293          $retval .= '| ' . $LANG05[5] . ' ';
4294          $retval .= '| ' . $LANG05[8];
4295      }
4296      else
4297      {
4298          $retval .= '| <a href="' . $base_url . $sep . $page_str
4299                  . ( $curpage + 1 ) . '">' . $LANG05[5] . '</a> ';
4300          $retval .= '| <a href="' . $base_url . $sep . $page_str . $num_pages
4301                  . '">' . $LANG05[8] . '</a>';
4302      }
4303  
4304      if( !empty( $retval ))
4305      {
4306          if( !empty( $msg ))
4307          {
4308              $msg .=  ' ';
4309          }
4310          $retval = '<div class="pagenav">' . $msg . $retval . '</div>';
4311      }
4312  
4313      return $retval;
4314  }
4315  
4316  /**
4317  * Returns formatted date/time for user
4318  *
4319  * This function COM_takes a date in either unixtimestamp or in english and
4320  * formats it to the users preference.  If the user didn't specify a format
4321  * the format in the config file is used.  This returns an array where array[0]
4322  * is the formatted date and array[1] is the unixtimestamp
4323  *
4324  * @param        string      $date       date to format, otherwise we format current date/time
4325  * @return   array   array[0] is the formatted date and array[1] is the unixtimestamp.
4326  */
4327  
4328  function COM_getUserDateTimeFormat( $date='' )
4329  {
4330      global $_TABLES, $_USER, $_CONF;
4331  
4332      // Get display format for time
4333  
4334      if( !empty( $_USER['uid'] ) && ( $_USER['uid'] > 1 ))
4335      {
4336          if( empty( $_USER['format'] ))
4337          {
4338              $dateformat = $_CONF['date'];
4339          }
4340          else
4341          {
4342              $dateformat = $_USER['format'];
4343          }
4344      }
4345      else
4346      {
4347          $dateformat = $_CONF['date'];
4348      }
4349  
4350      if( empty( $date ))
4351      {
4352          // Date is empty, get current date/time
4353          $stamp = time();
4354      }
4355      else if( is_numeric( $date ))
4356      {
4357          // This is a timestamp
4358          $stamp = $date;
4359      }
4360      else
4361      {
4362          // This is a string representation of a date/time
4363          $stamp = strtotime( $date );
4364      }
4365  
4366      // Format the date
4367  
4368      $date = strftime( $dateformat, $stamp );
4369  
4370      return array( $date, $stamp );
4371  }
4372  
4373  /**
4374  * Returns user-defined cookie timeout
4375  *
4376  * In account preferences users can specify when their long-term cookie expires.
4377  * This function returns that value.
4378  *
4379  * @return   int Cookie time out value in seconds
4380  */
4381  
4382  function COM_getUserCookieTimeout()
4383  {
4384      global $_TABLES, $_USER, $_CONF;
4385  
4386      if( empty( $_USER ))
4387      {
4388          return;
4389      }
4390  
4391      $timeoutvalue = DB_getItem( $_TABLES['users'], 'cookietimeout', "uid = {$_USER['uid']}" );
4392  
4393      if( empty( $timeoutvalue ))
4394      {
4395          $timeoutvalue = 0;
4396      }
4397  
4398      return $timeoutvalue;
4399  }
4400  
4401  /**
4402  * Shows who is online in slick little block
4403  * @return   string  HTML string of online users seperated by line breaks.
4404  */
4405  
4406  function phpblock_whosonline()
4407  {
4408      global $_CONF, $_TABLES, $_USER, $LANG01, $_IMAGE_TYPE;
4409  
4410      $retval = '';
4411  
4412      $expire_time = time() - $_CONF['whosonline_threshold'];
4413  
4414      $byname = 'username';
4415      if( $_CONF['show_fullname'] == 1 )
4416      {
4417          $byname .= ',fullname';
4418      }
4419      if( $_CONF['remoteauthentication'] )
4420      {
4421          $byname .= ',remoteusername,remoteservice';
4422      }
4423  
4424      $result = DB_query( "SELECT DISTINCT {$_TABLES['sessions']}.uid,{$byname},photo,showonline FROM {$_TABLES['sessions']},{$_TABLES['users']},{$_TABLES['userprefs']} WHERE {$_TABLES['users']}.uid = {$_TABLES['sessions']}.uid AND {$_TABLES['users']}.uid = {$_TABLES['userprefs']}.uid AND start_time >= $expire_time AND {$_TABLES['sessions']}.uid <> 1 ORDER BY {$byname}" );
4425      $nrows = DB_numRows( $result );
4426  
4427      $num_anon = 0;
4428      $num_reg  = 0;
4429  
4430      for( $i = 0; $i < $nrows; $i++ )
4431      {
4432          $A = DB_fetchArray( $result );
4433  
4434          if( $A['showonline'] == 1 )
4435          {
4436              $fullname = '';
4437              if( $_CONF['show_fullname'] == 1 )
4438              {
4439                  $fullname = $A['fullname'];
4440              }
4441              if( $_CONF['remoteauthentication'] )
4442              {
4443                  $username = COM_getDisplayName( $A['uid'], $A['username'],
4444                          $fullname, $A['remoteusername'], $A['remoteservice'] );
4445              }
4446              else
4447              {
4448                  $username = COM_getDisplayName( $A['uid'], $A['username'],
4449                                                  $fullname );
4450              }
4451              $retval .= '<a href="' . $_CONF['site_url']
4452                      . '/users.php?mode=profile&amp;uid=' . $A['uid'] . '">'
4453                      . $username . '</a>';
4454  
4455              if( !empty( $A['photo'] ) AND $_CONF['allow_user_photo'] == 1)
4456              {
4457                  $retval .= '&nbsp;<a href="' . $_CONF['site_url']
4458                          . '/users.php?mode=profile&amp;uid=' . $A['uid']
4459                          . '"><img src="' . $_CONF['layout_url']
4460                          . '/images/smallcamera.' . $_IMAGE_TYPE
4461                          . '" border="0" alt=""></a>';
4462              }
4463              $retval .= '<br>';
4464              $num_reg++;
4465          }
4466          else
4467          {
4468              // this user does not want to show up in Who's Online
4469              $num_anon++; // count as anonymous
4470          }
4471      }
4472  
4473      $result = DB_query( "SELECT DISTINCT uid,remote_ip FROM {$_TABLES['sessions']} WHERE uid = 1" );
4474      $num_anon += DB_numRows( $result );
4475  
4476      if(( $_CONF['whosonline_anonymous'] == 1 ) &&
4477              ( empty( $_USER['uid'] ) || ( $_USER['uid'] == 1 )))
4478      {
4479          // note that we're overwriting the contents of $retval here
4480          if( $num_reg > 0 )
4481          {
4482              $retval = $LANG01[112] . ': ' . $num_reg . '<br>';
4483          }
4484          else
4485          {
4486              $retval = '';
4487          }
4488      }
4489  
4490      if( $num_anon > 0 )
4491      {
4492          $retval .= $LANG01[41] . ': ' . $num_anon . '<br>';
4493      }
4494  
4495      return $retval;
4496  }
4497  
4498  /**
4499  * Gets the <option> values for calendar months
4500  *
4501  * @param        string      $selected       Selected month
4502  * @see function COM_getDayFormOptions
4503  * @see function COM_getYearFormOptions
4504  * @see function COM_getHourFormOptions
4505  * @see function COM_getMinuteFormOptions
4506  * @return   string  HTML Months as option values
4507  */
4508  
4509  function COM_getMonthFormOptions( $selected = '' )
4510  {
4511      global $LANG_MONTH;
4512  
4513      $month_options = '';
4514  
4515      for( $i = 1; $i <= 12; $i++ )
4516      {
4517          $mval = $i;
4518          $month_options .= '<option value="' . $mval . '"';
4519  
4520          if( $i == $selected )
4521          {
4522              $month_options .= ' selected="selected"';
4523          }
4524  
4525          $month_options .= '>' . $LANG_MONTH[$mval] . '</option>';
4526      }
4527  
4528      return $month_options;
4529  }
4530  
4531  /**
4532  * Gets the <option> values for calendar days
4533  *
4534  * @param        string      $selected       Selected day
4535  * @see function COM_getMonthFormOptions
4536  * @see function COM_getYearFormOptions
4537  * @see function COM_getHourFormOptions
4538  * @see function COM_getMinuteFormOptions
4539  * @return string HTML days as option values
4540  */
4541  
4542  function COM_getDayFormOptions( $selected = '' )
4543  {
4544      $day_options = '';
4545  
4546      for( $i = 1; $i <= 31; $i++ )
4547      {
4548          if( $i < 10 )
4549          {
4550              $dval = '0' . $i;
4551          }
4552          else
4553          {
4554              $dval = $i;
4555          }
4556  
4557          $day_options .= '<option value="' . $dval . '"';
4558  
4559          if( $i == $selected )
4560          {
4561              $day_options .= ' selected="selected"';
4562          }
4563  
4564          $day_options .= '>' . $dval . '</option>';
4565      }
4566  
4567      return $day_options;
4568  }
4569  
4570  /**
4571  * Gets the <option> values for calendar years
4572  *
4573  * Returns Option list Containing 5 years starting with current
4574  * unless @selected is < current year then starts with @selected
4575  *
4576  * @param        string      $selected       Selected year
4577  * @see function COM_getMonthFormOptions
4578  * @see function COM_getDayFormOptions
4579  * @see function COM_getHourFormOptions
4580  * @see function COM_getMinuteFormOptions
4581  * @return string  HTML years as option values
4582  */
4583  
4584  function COM_getYearFormOptions( $selected = '' )
4585  {
4586      $year_options = '';
4587      $cur_year = date( 'Y', time() );
4588      $start_year = $cur_year;
4589  
4590      if( !empty( $selected ))
4591      {
4592          if( $selected < $cur_year )
4593          {
4594              $start_year = $selected;
4595          }
4596      }
4597  
4598      for( $i = $start_year - 1; $i <= $cur_year + 5; $i++ )
4599      {
4600          $year_options .= '<option value="' . $i . '"';
4601  
4602          if( $i == $selected )
4603          {
4604              $year_options .= ' selected="selected"';
4605          }
4606  
4607          $year_options .= '>' . $i . '</option>';
4608      }
4609  
4610      return $year_options;
4611  }
4612  
4613  /**
4614  * Gets the <option> values for clock hours
4615  *
4616  * @param    string  $selected   Selected hour
4617  * @param    int     $mode       12 or 24 hour mode
4618  * @return   string              HTML string of options
4619  * @see function COM_getMonthFormOptions
4620  * @see function COM_getDayFormOptions
4621  * @see function COM_getYearFormOptions
4622  * @see function COM_getMinuteFormOptions
4623  */
4624  
4625  function COM_getHourFormOptions( $selected = '', $mode = 12 )
4626  {
4627      $hour_options = '';
4628  
4629      if( $mode == 12 )
4630      {
4631          for( $i = 1; $i <= 11; $i++ )
4632          {
4633              if( $i < 10 )
4634              {
4635                  $hval = '0' . $i;
4636              }
4637              else
4638              {
4639                  $hval = $i;
4640              }
4641  
4642              if( $i == 1 )
4643              {
4644                  $hour_options .= '<option value="12"';
4645  
4646                  if( $selected == 12 )
4647                  {
4648                      $hour_options .= ' selected="selected"';
4649                  }
4650  
4651                  $hour_options .= '>12</option>';
4652              }
4653  
4654              $hour_options .= '<option value="' . $hval . '"';
4655  
4656              if( $selected == $i )
4657              {
4658                  $hour_options .= ' selected="selected"';
4659              }
4660  
4661              $hour_options .= '>' . $i . '</option>';
4662          }
4663      }
4664      else // if( $mode == 24 )
4665      {
4666          for( $i = 0; $i < 24; $i++ )
4667          {
4668              if( $i < 10 )
4669              {
4670                  $hval = '0' . $i;
4671              }
4672              else
4673              {
4674                  $hval = $i;
4675              }
4676  
4677              $hour_options .= '<option value="' . $hval . '"';
4678  
4679              if( $selected == $i )
4680              {
4681                  $hour_options .= ' selected="selected"';
4682              }
4683  
4684              $hour_options .= '>' . $i . '</option>';
4685          }
4686      }
4687  
4688      return $hour_options;
4689  }
4690  
4691  /**
4692  * Gets the <option> values for clock minutes
4693  *
4694  * @param    string      $selected   Selected minutes
4695  * @param    integer     $step       number of minutes between options, e.g. 15
4696  * @see function COM_getMonthFormOptions
4697  * @see function COM_getDayFormOptions
4698  * @see function COM_getHourFormOptions
4699  * @see function COM_getYearFormOptions
4700  * @return string  HTML of option minutes
4701  */
4702  
4703  function COM_getMinuteFormOptions( $selected = '', $step = 1 )
4704  {
4705      $minute_options = '';
4706  
4707      if(( $step < 1 ) || ( $step > 30 ))
4708      {
4709          $step = 1;
4710      }
4711  
4712      for( $i = 0; $i <= 59; $i += $step )
4713      {
4714          if( $i < 10 )
4715          {
4716              $mval = '0' . $i;
4717          }
4718          else
4719          {
4720              $mval = $i;
4721          }
4722  
4723          $minute_options .= '<option value="' . $mval . '"';
4724  
4725          if( $selected == $i )
4726          {
4727              $minute_options .= ' selected="selected"';
4728          }
4729  
4730          $minute_options .= '>' . $mval . '</option>';
4731      }
4732  
4733      return $minute_options;
4734  }
4735  
4736  /**
4737  * for backward compatibility only
4738  * - this function should always have been called COM_getMinuteFormOptions
4739  *
4740  */
4741  function COM_getMinuteOptions( $selected = '', $step = 1 )
4742  {
4743      return COM_getMinuteFormOptions( $selected, $step );
4744  }
4745  
4746  /**
4747  * Create an am/pm selector dropdown menu
4748  *
4749  * @param    string  $name       name of the <select>
4750  * @param    string  $selected   preselection: 'am' or 'pm'
4751  * @return   string  HTML for the dropdown; empty string in 24 hour mode
4752  *
4753  */
4754  function COM_getAmPmFormSelection( $name, $selected = '' )
4755  {
4756      global $_CONF;
4757  
4758      $retval = '';
4759  
4760      if( isset( $_CONF['hour_mode'] ) && ( $_CONF['hour_mode'] == 24 ))
4761      {
4762          $retval = '';
4763      }
4764      else
4765      {
4766          if( empty( $selected ))
4767          {
4768              $selected = date( 'a' );
4769          }
4770  
4771          $retval .= '<select name="' . $name . '">' . LB;
4772          $retval .= '<option value="am"';
4773          if( $selected == 'am' )
4774          {
4775              $retval .= ' selected="selected"';
4776          }
4777          $retval .= '>am</option>' . LB . '<option value="pm"';
4778          if( $selected == 'pm' )
4779          {
4780              $retval .= ' selected="selected"';
4781          }
4782          $retval .= '>pm</option>' . LB . '</select>' . LB;
4783      }
4784  
4785      return $retval;
4786  }
4787  
4788  /**
4789  * Creates an HTML unordered list from the given array.
4790  * It formats one list item per array element, using the list.thtml
4791  * and listitem.thtml templates.
4792  *
4793  * @param        array       $listofitems        Items to list out
4794  * @return   string  HTML unordered list of array items
4795  */
4796  
4797  function COM_makeList( $listofitems, $classname = '' )
4798  {
4799      global $_CONF;
4800  
4801      $list = new Template( $_CONF['path_layout'] );
4802      $list->set_file( array( 'list'     => 'list.thtml',
4803                              'listitem' => 'listitem.thtml' ));
4804      $list->set_var( 'site_url', $_CONF['site_url'] );
4805      $list->set_var( 'layout_url', $_CONF['layout_url'] );
4806      if( empty( $classname ))
4807      {
4808          $list->set_var( 'list_class', '' );
4809          $list->set_var( 'list_class_name', '' );
4810      }
4811      else
4812      {
4813          $list->set_var( 'list_class', 'class="' . $classname . '"' );
4814          $list->set_var( 'list_class_name', $classname );
4815      }
4816  
4817      foreach( $listofitems as $oneitem )
4818      {
4819          $list->set_var( 'list_item', $oneitem );
4820          $list->parse( 'list_items', 'listitem', true );
4821      }
4822  
4823      $list->parse( 'newlist', 'list', true );
4824  
4825      return $list->finish( $list->get_var( 'newlist' ));
4826  }
4827  
4828  /**
4829  * Check if speed limit applies for current IP address.
4830  *
4831  * @param type   string   type of speed limit to check, e.g. 'submit', 'comment'
4832  * @param max    int      max number of allowed tries within speed limit
4833  * @return       int      0 = does not apply, else: seconds since last post
4834  */
4835  function COM_checkSpeedlimit( $type = 'submit', $max = 1 )
4836  {
4837      global $_TABLES;
4838  
4839      $last = 0;
4840  
4841      $res  = DB_query( "SELECT date FROM {$_TABLES['speedlimit']} WHERE (type = '$type') AND (ipaddress = '{$_SERVER['REMOTE_ADDR']}') ORDER BY date ASC" );
4842  
4843      // If the number of allowed tries has not been reached,
4844      // return 0 (didn't hit limit)
4845      if( DB_numRows( $res ) < $max )
4846      {
4847          return $last;
4848      }
4849  
4850      list( $date ) = DB_fetchArray( $res );
4851  
4852      if( !empty( $date ))
4853      {
4854          $last = time() - $date;
4855          if( $last == 0 )
4856          {
4857              // just in case someone manages to submit something in < 1 sec.
4858              $last = 1;
4859          }
4860      }
4861  
4862      return $last;
4863  }
4864  
4865  /**
4866  * Store post info for current IP address.
4867  *
4868  * @param type   string   type of speed limit, e.g. 'submit', 'comment'
4869  *
4870  */
4871  function COM_updateSpeedlimit( $type = 'submit' )
4872  {
4873      global $_TABLES;
4874  
4875      DB_save( $_TABLES['speedlimit'], 'ipaddress,date,type',
4876               "'{$_SERVER['REMOTE_ADDR']}',unix_timestamp(),'$type'" );
4877  }
4878  
4879  /**
4880  * Clear out expired speed limits, i.e. entries older than 'x' seconds
4881  *
4882  * @param speedlimit   int      number of seconds
4883  * @param type         string   type of speed limit, e.g. 'submit', 'comment'
4884  *
4885  */
4886  function COM_clearSpeedlimit( $speedlimit = 60, $type = '' )
4887  {
4888      global $_TABLES;
4889  
4890      $sql = "DELETE FROM {$_TABLES['speedlimit']} WHERE ";
4891      if( !empty( $type ))
4892      {
4893          $sql .= "(type = '$type') AND ";
4894      }
4895      $sql .= "(date < unix_timestamp() - $speedlimit)";
4896      DB_query( $sql );
4897  }
4898  
4899  /**
4900  * Wrapper function for URL class so as to not confuse people as this will
4901  * eventually get used all over the place
4902  *
4903  * This function returns a crawler friendly URL (if possible)
4904  *
4905  * @param        string      $url        URL to try to build crawler friendly URL for
4906  * @return   string      Rewritten URL
4907  */
4908  
4909  function COM_buildURL( $url )
4910  {
4911      global $_URL;
4912  
4913      return $_URL->buildURL( $url );
4914  }
4915  
4916  /**
4917  * Wrapper function for URL class so as to not confuse people
4918  *
4919  * This function sets the name of the arguments found in url
4920  *
4921  * @param    array   $names  Names of arguments in query string to assign to values
4922  * @return   boolean         True if successful
4923  */
4924  
4925  function COM_setArgNames( $names )
4926  {
4927      global $_URL;
4928  
4929      return $_URL->setArgNames( $names );
4930  }
4931  
4932  /**
4933  * Wrapper function for URL class
4934  *
4935  * returns value for specified argument
4936  *
4937  * @param        string      $name       argument to get value for
4938  * @return   string     Argument value
4939  */
4940  
4941  function COM_getArgument( $name )
4942  {
4943      global $_URL;
4944  
4945      return $_URL->getArgument( $name );
4946  }
4947  
4948  /**
4949  * Occurences / time
4950  *
4951  * This will take a number of occurrences, and number of seconds for the time span and return
4952  * the smallest #/time interval
4953  *
4954  * @param    int     $occurrences        how many occurrences during time interval
4955  * @param    int     $timespan           time interval in seconds
4956  * @return   int Seconds per interval
4957  */
4958  
4959  function COM_getRate( $occurrences, $timespan )
4960  {
4961      // want to define some common time words (yes, dirk, i need to put this in LANG)
4962      // time words and their value in seconds
4963      // week is 7 * day, month is 30 * day, year is 365.25 * day
4964  
4965      $common_time = array(
4966          "second" => 1,
4967          "minute" => 60,
4968          "hour"   => 3600,
4969          "day"    => 86400,
4970          "week"   => 604800,
4971          "month"  => 2592000,
4972          "year"   => 31557600
4973          );
4974  
4975      if( $occurrences != 0 )
4976      {
4977          $rate = ( int )( $timespan / $occurrences );
4978          $adjustedRate = $occurrences + 1;
4979          $time_unit = 'second';
4980  
4981          $found_one = false;
4982  
4983          foreach( $common_time as $unit=>$seconds )
4984          {
4985              if( $rate > $seconds )
4986              {
4987                  $foo = ( int )(( $rate / $seconds ) + .5 );
4988  
4989                  if(( $foo < $occurrences ) && ( $foo > 0 ))
4990                  {
4991                      $adjustedRate = $foo;
4992                      $time_unit = $unit;
4993                  }
4994              }
4995          }
4996  
4997          $singular = '1 shout every ' . $adjustedRate . ' ' . $time_unit;
4998  
4999          if( $adjustedRate > 1 )
5000          {
5001              $singular .= 's';
5002          }
5003      }
5004      else
5005      {
5006          $singular = 'No events';
5007      }
5008  
5009      return $singular;
5010  }
5011  
5012  /**
5013  * Return SQL expression to check for permissions.
5014  *
5015  * Creates part of an SQL expression that can be used to request items with the
5016  * standard set of Geeklog permissions.
5017  *
5018  * @param        string      $type     part of the SQL expr. e.g. 'WHERE', 'AND'
5019  * @param        int         $u_id     user id or 0 = current user
5020  * @param        int         $access   access to check for (2=read, 3=r&write)
5021  * @param        string      $table    table name if ambiguous (e.g. in JOINs)
5022  * @return       string      SQL expression string (may be empty)
5023  *
5024  */
5025  function COM_getPermSQL( $type = 'WHERE', $u_id = 0, $access = 2, $table = '' )
5026  {
5027      global $_USER, $_GROUPS;
5028  
5029      if( !empty( $table ))
5030      {
5031          $table .= '.';
5032      }
5033      if( $u_id <= 0)
5034      {
5035          if( empty( $_USER['uid'] ))
5036          {
5037              $uid = 1;
5038          }
5039          else
5040          {
5041              $uid = $_USER['uid'];
5042          }
5043      }
5044      else
5045      {
5046          $uid = $u_id;
5047      }
5048  
5049      $UserGroups = array();
5050      if(( empty( $_USER['uid'] ) && ( $uid == 1 )) || ( $uid == $_USER['uid'] ))
5051      {
5052          if( empty( $_GROUPS ))
5053          {
5054              $_GROUPS = SEC_getUserGroups( $uid );
5055          }
5056          $UserGroups = $_GROUPS;
5057      }
5058      else
5059      {
5060          $UserGroups = SEC_getUserGroups( $uid );
5061      }
5062  
5063      if( empty( $UserGroups ))
5064      {
5065          // this shouldn't really happen, but if it does, handle user
5066          // like an anonymous user
5067          $uid = 1;
5068      }
5069  
5070      if( SEC_inGroup( 'Root', $uid ))
5071      {
5072          return '';
5073      }
5074  
5075      $sql = ' ' . $type . ' (';
5076  
5077      if( $uid > 1 )
5078      {
5079          $sql .= "(({$table}owner_id = '{$uid}') AND ({$table}perm_owner >= $access)) OR ";
5080  
5081          $sql .= "(({$table}group_id IN (" . implode( ',', $UserGroups )
5082               . ")) AND ({$table}perm_group >= $access)) OR ";
5083          $sql .= "({$table}perm_members >= $access)";
5084      }
5085      else
5086      {
5087          $sql .= "{$table}perm_anon >= $access";
5088      }
5089  
5090      $sql .= ')';
5091  
5092      return $sql;
5093  }
5094  
5095  /**
5096  * Return SQL expression to check for allowed topics.
5097  *
5098  * Creates part of an SQL expression that can be used to only request stories
5099  * from topics to which the user has access to.
5100  *
5101  * Note that this function does an SQL request, so you should cache
5102  * the resulting SQL expression if you need it more than once.
5103  *
5104  * @param    string  $type   part of the SQL expr. e.g. 'WHERE', 'AND'
5105  * @param    int     $u_id   user id or 0 = current user
5106  * @param    string  $table  table name if ambiguous (e.g. in JOINs)
5107  * @return   string          SQL expression string (may be empty)
5108  *
5109  */
5110  function COM_getTopicSQL( $type = 'WHERE', $u_id = 0, $table = '' )
5111  {
5112      global $_TABLES, $_USER, $_GROUPS;
5113  
5114      $topicsql = ' ' . $type . ' ';
5115  
5116      if( !empty( $table ))
5117      {
5118          $table .= '.';
5119      }
5120  
5121      $UserGroups = array();
5122      if(( $u_id <= 0 ) || ( $u_id == $_USER['uid'] ))
5123      {
5124          if( isset( $_USER['uid'] ))
5125          {
5126              $uid = $_USER['uid'];
5127          }
5128          else
5129          {
5130              $uid = 1;
5131          }
5132          $UserGroups = $_GROUPS;
5133      }
5134      else
5135      {
5136          $uid = $u_id;
5137          $UserGroups = SEC_getUserGroups( $uid );
5138      }
5139  
5140      if( empty( $UserGroups ))
5141      {
5142          // this shouldn't really happen, but if it does, handle user
5143          // like an anonymous user
5144          $uid = 1;
5145      }
5146  
5147      if( SEC_inGroup( 'Root', $uid ))
5148      {
5149          return '';
5150      }
5151  
5152      $result = DB_query( "SELECT tid FROM {$_TABLES['topics']}"
5153                          . COM_getPermSQL( 'WHERE', $uid ));
5154      $tids = array();
5155      while( $T = DB_fetchArray( $result ))
5156      {
5157          $tids[] = $T['tid'];
5158      }
5159  
5160      if( sizeof( $tids ) > 0 )
5161      {
5162          $topicsql .= "({$table}tid IN ('" . implode( "','", $tids ) . "'))";
5163      }
5164      else
5165      {
5166          $topicsql .= '0';
5167      }
5168  
5169      return $topicsql;
5170  }
5171  
5172  /**
5173  * Strip slashes from a string only when magic_quotes_gpc = on.
5174  *
5175  * @param   string  $text  The text
5176  * @return  string  The text, possibly without slashes.
5177  */
5178  function COM_stripslashes( $text )
5179  {
5180      if( get_magic_quotes_gpc() == 1 )
5181      {
5182          return( stripslashes( $text ));
5183      }
5184  
5185      return( $text );
5186  }
5187  
5188  /**
5189  * Filter parameters passed per GET (URL) or POST.
5190  *
5191  * @param    string    $parameter   the parameter to test
5192  * @param    boolean   $isnumeric   true if $parameter is supposed to be numeric
5193  * @return   string    the filtered parameter (may now be empty or 0)
5194  *
5195  */
5196  function COM_applyFilter( $parameter, $isnumeric = false )
5197  {
5198      $log_manipulation = false; // set to true to log when the filter applied
5199  
5200      $p = COM_stripslashes( $parameter );
5201      $p = strip_tags( $p );
5202      $p = COM_killJS( $p ); // doesn't help a lot right now, but still ...
5203  
5204      if( $isnumeric )
5205      {
5206          // Note: PHP's is_numeric() accepts values like 4e4 as numeric
5207          if( !is_numeric( $p ) || ( preg_match( '/^-?\d+$/', $p ) == 0 ))
5208          {
5209              $p = 0;
5210          }
5211      }
5212      else
5213      {
5214          $p = preg_replace( '/\/\*.*/', '', $p );
5215          $pa = explode( "'", $p );
5216          $pa = explode( '"', $pa[0] );
5217          $pa = explode( '`', $pa[0] );
5218          $pa = explode( ';', $pa[0] );
5219          $pa = explode( ',', $pa[0] );
5220          $pa = explode( '\\', $pa[0] );
5221          $p = $pa[0];
5222      }
5223  
5224      if( $log_manipulation )
5225      {
5226          if( strcmp( $p, $parameter ) != 0 )
5227          {
5228              COM_errorLog( "Filter applied: >> $parameter << filtered to $p [IP {$_SERVER['REMOTE_ADDR']}]", 1);
5229          }
5230      }
5231  
5232      return $p;
5233  }
5234  
5235  /**
5236  * Sanitize a URL
5237  *
5238  * @param    string  $url                URL to sanitized
5239  * @param    array   $allowed_protocols  array of allowed protocols
5240  * @param    string  $default_protocol   replacement protocol (default: http)
5241  * @return   string                      sanitized URL
5242  *
5243  */
5244  function COM_sanitizeUrl( $url, $allowed_protocols = '', $default_protocol = '' )
5245  {
5246      global $_CONF;
5247  
5248      if( empty( $allowed_protocols ))
5249      {
5250          $allowed_protocols = $_CONF['allowed_protocols'];
5251      }
5252      else if( !is_array( $allowed_protocols ))
5253      {
5254          $allowed_protocols = array( $allowed_protocols );
5255      }
5256  
5257      if( empty( $default_protocol ))
5258      {
5259          $default_protocol = 'http:';
5260      }
5261      else if( substr( $default_protocol, -1 ) != ':' )
5262      {
5263          $default_protocol .= ':';
5264      }
5265  
5266      $url = strip_tags( $url );
5267      if( !empty( $url ))
5268      {
5269          $pos = MBYTE_strpos( $url, ':' );
5270          if( $pos === false )
5271          {
5272              $url = $default_protocol . '//' . $url;
5273          }
5274          else
5275          {
5276              $protocol = MBYTE_substr( $url, 0, $pos + 1 );
5277              $found_it = false;
5278              foreach( $allowed_protocols as $allowed )
5279              {
5280                  if( substr( $allowed, -1 ) != ':' )
5281                  {
5282                      $allowed .= ':';
5283                  }
5284                  if( $protocol == $allowed )
5285                  {
5286                      $found_it = true;
5287                      break;
5288                  }
5289              }
5290              if( !$found_it )
5291              {
5292                  $url = $default_protocol . MBYTE_substr( $url, $pos + 1 );
5293              }
5294          }
5295      }
5296  
5297      return $url;
5298  }
5299  
5300  /**
5301  * Detect links in a plain-ascii text and turn them into clickable links.
5302  * Will detect links starting with "http:", "https:", "ftp:", and "www.".
5303  *
5304  * Derived from a newsgroup posting by Andreas Schwarz in
5305  * news:de.comp.lang.php <aieq4p$12jn2i$3@ID-16486.news.dfncis.de>
5306  *
5307  * @param    string    $text     the (plain-ascii) text string
5308  * @return   string    the same string, with links enclosed in <a>...</a> tags
5309  *
5310  */
5311  function COM_makeClickableLinks( $text )
5312  {
5313      $text = preg_replace( '/([^"]?)((((ht|f)tps?):(\/\/)|www\.)[a-z0-9%&_\-\+,;=:@~#\/.\?\[\]]+(\/|[+0-9a-z]))/is', '\\1<a href="\\2">\\2</a>', $text );
5314      $text = str_replace( '<a href="www', '<a href="http://www', $text );
5315  
5316      return $text;
5317  }
5318  
5319  /**
5320  * Undo the conversion of URLs to clickable links (in plain text posts),
5321  * e.g. so that we can present the user with the post as they entered them.
5322  *
5323  * @param    string  $txt    story text
5324  * @param    string          story text without links
5325  *
5326  */
5327  function COM_undoClickableLinks( $text )
5328  {
5329      $text = preg_replace( '/<a href="[^"]*">([^<]*)<\/a>/', '\1', $text );
5330  
5331      return $text;
5332  }
5333  
5334  /**
5335  * Highlight the words from a search query in a given text string.
5336  *
5337  * @param    string  $text   the text
5338  * @param    string  $query  the search query
5339  * @return   string          the text with highlighted search words
5340  *
5341  */
5342  function COM_highlightQuery( $text, $query )
5343  {
5344      $query = str_replace( '+', ' ', $query );
5345  
5346      // escape all the other PCRE special characters
5347      $query = preg_quote( $query );
5348  
5349      // ugly workaround:
5350      // Using the /e modifier in preg_replace will cause all double quotes to
5351      // be returned as \" - so we replace all \" in the result with unescaped
5352      // double quotes. Any actual \" in the original text therefore have to be
5353      // turned into \\" first ...
5354      $text = str_replace( '\\"', '\\\\"', $text );
5355  
5356      $mywords = explode( ' ', $query );
5357      foreach( $mywords as $searchword )
5358      {
5359          if( !empty( $searchword ))
5360          {
5361              $searchword = preg_quote( str_replace( "'", "\'", $searchword ));
5362              $text = preg_replace( '/(\>(((?>[^><]+)|(?R))*)\<)/ie', "preg_replace('/(?>$searchword+)/i','<span class=\"highlight\">$searchword</span>','\\0')", '<!-- x -->' . $text . '<!-- x -->' );
5363          }
5364      }
5365  
5366      // ugly workaround, part 2
5367      $text = str_replace( '\\"', '"', $text );
5368  
5369      return $text;
5370  }
5371  
5372  /**
5373  * Determines the difference between two dates.
5374  *
5375  * This will takes either unixtimestamps or English dates as input and will
5376  * automatically do the date diff on the more recent of the two dates (e.g. the
5377  * order of the two dates given doesn't matter).
5378  *
5379  * @author Tony Bibbs <tony.bibbs@iowa.gov
5380  * @access public
5381  * @param string $interval Can be:
5382  * y = year
5383  * m = month
5384  * w = week
5385  * h = hours
5386  * i = minutes
5387  * s = seconds
5388  * @param string|int $date1 English date (e.g. 10 Dec 2004) or unixtimestamp
5389  * @param string|int $date2 English date (e.g. 10 Dec 2004) or unixtimestamp
5390  * @return int Difference of the two dates in the unit of time indicated by the interval
5391  *
5392  */
5393  function COM_dateDiff( $interval, $date1, $date2 )
5394  {
5395      // Convert dates to timestamps, if needed.
5396      if( !is_numeric( $date1 ))
5397      {
5398          $date1 = strtotime( $date1 );
5399      }
5400  
5401      if( !is_numeric( $date2 ))
5402      {
5403          $date2 = strtotime( $date2 );
5404      }
5405  
5406      // Function roughly equivalent to the ASP "DateDiff" function
5407      if( $date2 > $date1 )
5408      {
5409          $seconds = $date2 - $date1;
5410      }
5411      else
5412      {
5413          $seconds = $date1 - $date2;
5414      }
5415  
5416      switch( $interval )
5417      {
5418          case "y":
5419              list($year1, $month1, $day1) = split('-', date('Y-m-d', $date1));
5420              list($year2, $month2, $day2) = split('-', date('Y-m-d', $date2));
5421              $time1 = (date('H',$date1)*3600) + (date('i',$date1)*60) + (date('s',$date1));
5422              $time2 = (date('H',$date2)*3600) + (date('i',$date2)*60) + (date('s',$date2));
5423              $diff = $year2 - $year1;
5424              if($month1 > $month2) {
5425                  $diff -= 1;
5426              } elseif($month1 == $month2) {
5427                  if($day1 > $day2) {
5428                      $diff -= 1;
5429                  } elseif($day1 == $day2) {
5430                      if($time1 > $time2) {
5431                          $diff -= 1;
5432                      }
5433                  }
5434              }
5435              break;
5436          case "m":
5437              list($year1, $month1, $day1) = split('-', date('Y-m-d', $date1));
5438              list($year2, $month2, $day2) = split('-', date('Y-m-d', $date2));
5439              $time1 = (date('H',$date1)*3600) + (date('i',$date1)*60) + (date('s',$date1));
5440              $time2 = (date('H',$date2)*3600) + (date('i',$date2)*60) + (date('s',$date2));
5441              $diff = ($year2 * 12 + $month2) - ($year1 * 12 + $month1);
5442              if($day1 > $day2) {
5443                  $diff -= 1;
5444              } elseif($day1 == $day2) {
5445                  if($time1 > $time2) {
5446                      $diff -= 1;
5447                  }
5448              }
5449              break;
5450          case "w":
5451              // Only simple seconds calculation needed from here on
5452              $diff = floor($seconds / 604800);
5453              break;
5454           case "d":
5455              $diff = floor($seconds / 86400);
5456              break;
5457          case "h":
5458              $diff = floor($seconds / 3600);
5459              break;
5460          case "i":
5461              $diff = floor($seconds / 60);
5462              break;
5463          case "s":
5464              $diff = $seconds;
5465              break;
5466      }
5467  
5468      return $diff;
5469  }
5470  
5471  /**
5472  * Try to figure out our current URL, including all parameters.
5473  *
5474  * This is an ugly hack since there's no single variable that returns what
5475  * we want and the variables used here may not be available on all servers
5476  * and / or setups.
5477  *
5478  * Seems to work on Apache (1.3.x and 2.x), IIS, and Zeus ...
5479  *
5480  * @return   string  complete URL, e.g. 'http://www.example.com/blah.php?foo=bar'
5481  *
5482  */
5483  function COM_getCurrentURL()
5484  {
5485      global $_CONF;
5486  
5487      $thisUrl = '';
5488  
5489      if( empty( $_SERVER['SCRIPT_URI'] ))
5490      {
5491          if( !empty( $_SERVER['DOCUMENT_URI'] ))
5492          {
5493              $thisUrl = $_SERVER['DOCUMENT_URI'];
5494          }
5495      }
5496      else
5497      {
5498          $thisUrl = $_SERVER['SCRIPT_URI'];
5499      }
5500      if( !empty( $thisUrl ) && !empty( $_SERVER['QUERY_STRING'] ))
5501      {
5502          $thisUrl .= '?' . $_SERVER['QUERY_STRING'];
5503      }
5504      if( empty( $thisUrl ))
5505      {
5506          $requestUri = $_SERVER['REQUEST_URI'];
5507          if( empty( $_SERVER['REQUEST_URI'] ))
5508          {
5509              // on a Zeus webserver, prefer PATH_INFO over SCRIPT_NAME
5510              if( empty( $_SERVER['PATH_INFO'] ))
5511              {
5512                  $requestUri = $_SERVER['SCRIPT_NAME'];
5513              }
5514              else
5515              {
5516                  $requestUri = $_SERVER['PATH_INFO'];
5517              }
5518              if( !empty( $_SERVER['QUERY_STRING'] ))
5519              {
5520                  $requestUri .= '?' . $_SERVER['QUERY_STRING'];
5521              }
5522          }
5523  
5524          $firstslash = strpos( $_CONF['site_url'], '/' );
5525          if( $firstslash === false )
5526          {
5527              // special case - assume it's okay
5528              $thisUrl = $_CONF['site_url'] . $requestUri;
5529          }
5530          else if( $firstslash + 1 == strrpos( $_CONF['site_url'], '/' ))
5531          {
5532              // site is in the document root
5533              $thisUrl = $_CONF['site_url'] . $requestUri;
5534          }
5535          else
5536          {
5537              // extract server name first
5538              $pos = strpos( $_CONF['site_url'], '/', $firstslash + 2 );
5539              $thisUrl = substr( $_CONF['site_url'], 0, $pos ) . $requestUri;
5540          }
5541      }
5542  
5543      return $thisUrl;
5544  }
5545  
5546  /**
5547  * Check if we're on Geeklog's index page.
5548  *
5549  * See if we're on the main index page (first page, no topics selected).
5550  *
5551  * @return   bool    true = we're on the frontpage, false = we're not
5552  *
5553  */
5554  function COM_onFrontpage()
5555  {
5556      global $_CONF, $topic, $page, $newstories;
5557  
5558      // Note: We can't use $PHP_SELF here since the site may not be in the
5559      // DocumentRoot
5560      $onFrontpage = false;
5561  
5562      // on a Zeus webserver, prefer PATH_INFO over SCRIPT_NAME
5563      if( empty( $_SERVER['PATH_INFO'] ))
5564      {
5565          $scriptName = $_SERVER['SCRIPT_NAME'];
5566      }
5567      else
5568      {
5569          $scriptName = $_SERVER['PATH_INFO'];
5570      }
5571  
5572      preg_match( '/\/\/[^\/]*(.*)/', $_CONF['site_url'], $pathonly );
5573      if(( $scriptName == $pathonly[1] . '/index.php' ) &&
5574              empty( $topic ) && ( $page == 1 ) && !$newstories )
5575      {
5576          $onFrontpage = true;
5577      }
5578  
5579      return $onFrontpage;
5580  }
5581  
5582  /**
5583  * Check if we're on Geeklog's index page [deprecated]
5584  *
5585  * Note that this function returns FALSE when we're on the index page. Due to
5586  * the inverted return values, it has been deprecated and is only provided for
5587  * backward compatibility - use COM_onFrontpage() instead.
5588  *
5589  * @see COM_onFrontpage
5590  *
5591  */
5592  function COM_isFrontpage()
5593  {
5594      return !COM_onFrontpage();
5595  }
5596  
5597  /**
5598  * Ensure an ID contains only alphanumeric characters, dots, dashes, or underscores
5599  *
5600  * @param    string  $id     the ID to sanitize
5601  * @param    boolean $new_id true = create a new ID in case we end up with an empty string
5602  * @return   string          the sanitized ID
5603  */
5604  function COM_sanitizeID( $id, $new_id = true )
5605  {
5606      $id = str_replace( ' ', '', $id );
5607      $id = str_replace( array( '/', '\\', ':', '+' ), '-', $id );
5608      $id = preg_replace( '/[^a-zA-Z0-9\-_\.]/', '', $id );
5609      if( empty( $id ) && $new_id )
5610      {
5611          $id = COM_makesid();
5612      }
5613  
5614      return $id;
5615  }
5616  
5617  /** Converts a number for output into a formatted number with thousands-
5618  *         separator, comma-separator and fixed decimals if necessary
5619  *
5620  *        @param        float        $number        Number that will be formatted
5621  *        @return        string                        formatted number
5622  */
5623  function COM_numberFormat( $number )
5624  {
5625      global $_CONF;
5626  
5627      if( $number - abs( $number ) > 0 ) // number has decimals
5628      {
5629          $dc = $_CONF['decimal_count'];
5630      }
5631      else
5632      {
5633          $dc = 0;
5634      }
5635      $ts = $_CONF['thousand_separator'];
5636      $ds = $_CONF['decimal_separator'];
5637  
5638      return number_format( $number, $dc, $ds, $ts );
5639  }
5640  
5641  /**
5642  * Convert a text based date YYYY-MM-DD to a unix timestamp integer value
5643  *
5644  * @param    string  $date   Date in the format YYYY-MM-DD
5645  * @param    string  $time   Option time in the format HH:MM::SS
5646  * @return   int             UNIX Timestamp
5647  */
5648  function COM_convertDate2Timestamp( $date, $time = '' )
5649  {
5650      $atoks = array();
5651      $btoks = array();
5652  
5653      // Breakup the string using either a space, fwd slash, dash, bkwd slash or
5654      // colon as a delimiter
5655      $atok = strtok( $date, ' /-\\:' );
5656      while( $atok !== FALSE )
5657      {
5658          $atoks[] = $atok;
5659          $atok = strtok( ' /-\\:' );  // get the next token
5660      }
5661  
5662      for( $i = 0; $i < 3; $i++ )
5663      {
5664          if( !isset( $atoks[$i] ) || !is_numeric( $atoks[$i] ))
5665          {
5666              $atoks[$i] = 0;
5667          }
5668      }
5669  
5670      if( $time == '' )
5671      {
5672          $timestamp = mktime( 0, 0, 0, $atoks[1], $atoks[2], $atoks[0] );
5673      }
5674      else
5675      {
5676          $btok = strtok( $time, ' /-\\:' );
5677          while( $btok !== FALSE )
5678          {
5679              $btoks[] = $btok;
5680              $btok = strtok( ' /-\\:' );
5681          }
5682  
5683          for( $i = 0; $i < 3; $i++ )
5684          {
5685              if( !isset( $btoks[$i] ) || !is_numeric( $btoks[$i] ))
5686              {
5687                  $btoks[$i] = 0;
5688              }
5689          }
5690  
5691          $timestamp = mktime( $btoks[0], $btoks[1], $btoks[2],
5692                               $atoks[1], $atoks[2], $atoks[0] );
5693      }
5694  
5695      return $timestamp;
5696  }
5697  
5698  /**
5699  * Get the HTML for an image with height & width
5700  *
5701  * @param    string  $file   full path to the file
5702  * @return   string          html that will be included in the img-tag
5703  */
5704  function COM_getImgSizeAttributes( $file )
5705  {
5706      $sizeattributes = '';
5707  
5708      if( file_exists( $file ))
5709      {
5710          $dimensions = getimagesize( $file );
5711          if( !empty( $dimensions[0] ) AND !empty( $dimensions[1] ))
5712          {
5713              $sizeattributes = 'width="' . $dimensions[0]
5714                              . '" height="' . $dimensions[1] . '" ';
5715          }
5716      }
5717  
5718      return $sizeattributes;
5719  }
5720  
5721  /**
5722  * Display a message and abort
5723  *
5724  * @param    int     $msg            message number
5725  * @param    string  $plugin         plugin name, if applicable
5726  * @param    int     $http_status    HTTP status code to send with the message
5727  * @param    string  $http_text      Textual version of the HTTP status code
5728  *
5729  * @note Displays the message and aborts the script.
5730  *
5731  */
5732  function COM_displayMessageAndAbort( $msg, $plugin = '', $http_status = 200, $http_text = 'OK')
5733  {
5734      $display = COM_siteHeader( 'menu' )
5735               . COM_showMessage( $msg, $plugin )
5736               . COM_siteFooter( true );
5737  
5738      if( $http_status != 200 )
5739      {
5740          header( "HTTP/1.1 $http_status $http_text" );
5741          header( "Status: $http_status $http_text" );
5742      }
5743      echo $display;
5744      exit;
5745  }
5746  
5747  /**
5748  * Return full URL of a topic icon
5749  *
5750  * @param    string  $imageurl   (relative) topic icon URL
5751  * @return   string              Full URL
5752  *
5753  */
5754  function COM_getTopicImageUrl( $imageurl )
5755  {
5756      global $_CONF, $_THEME_URL;
5757  
5758      $iconurl = '';
5759  
5760      if( !empty( $imageurl ))
5761      {
5762          if( isset( $_THEME_URL ))
5763          {
5764              $iconurl = $_THEME_URL . $imageurl;
5765          }
5766          else
5767          {
5768              $stdImageLoc = true;
5769              if( !strstr( $_CONF['path_images'], $_CONF['path_html'] ))
5770              {
5771                  $stdImageLoc = false;
5772              }
5773  
5774              if( $stdImageLoc )
5775              {
5776                  $iconurl = $_CONF['site_url'] . $imageurl;
5777              }
5778              else
5779              {
5780                  $t = explode( '/', $imageurl );
5781                  $topicicon = $t[count( $t ) - 1];
5782                  $iconurl = $_CONF['site_url']
5783                           . '/getimage.php?mode=topics&amp;image=' . $topicicon;
5784              }
5785          }
5786      }
5787  
5788      return $iconurl;
5789  }
5790  
5791  /**
5792  * Try to determine the user's preferred language by looking at the
5793  * "Accept-Language" header sent by their browser (assuming they bothered
5794  * to select a preferred language there).
5795  *
5796  * @return   string  name of the language file to use or an empty string
5797  *
5798  * Bugs: Does not take the quantity ('q') parameter into account, but only
5799  *       looks at the order of language codes.
5800  *
5801  * Sample header: Accept-Language: en-us,en;q=0.7,de-de;q=0.3
5802  *
5803  */
5804  function COM_getLanguageFromBrowser()
5805  {
5806      global $_CONF;
5807  
5808      $retval = '';
5809  
5810      if( isset( $_SERVER['HTTP_ACCEPT_LANGUAGE'] ))
5811      {
5812          $accept = explode( ',', $_SERVER['HTTP_ACCEPT_LANGUAGE'] );
5813          foreach( $accept as $l )
5814          {
5815              $l = explode( ';', trim( $l ));
5816              $l = $l[0];
5817              if( array_key_exists( $l, $_CONF['language_files'] ))
5818              {
5819                  $retval = $_CONF['language_files'][$l];
5820                  break;
5821              }
5822              else
5823              {
5824                  $l = explode( '-', $l );
5825                  $l = $l[0];
5826                  if( array_key_exists( $l, $_CONF['language_files'] ))
5827                  {
5828                      $retval = $_CONF['language_files'][$l];
5829                      break;
5830                  }
5831              }
5832          }
5833  
5834      }
5835  
5836      return $retval;
5837  }
5838  
5839  /**
5840  * Determine current language
5841  *
5842  * @return   string  name of the language file (minus the '.php' extension)
5843  *
5844  */
5845  function COM_getLanguage()
5846  {
5847      global $_CONF, $_USER;
5848  
5849      $langfile = '';
5850  
5851      if( !empty( $_USER['language'] ))
5852      {
5853          $langfile = $_USER['language'];
5854      }
5855      else if( !empty( $_COOKIE[$_CONF['cookie_language']] ))
5856      {
5857          $langfile = $_COOKIE[$_CONF['cookie_language']];
5858      }
5859      else
5860      {
5861          $langfile = COM_getLanguageFromBrowser();
5862      }
5863  
5864      $langfile = preg_replace( '/[^a-z0-9\-_]/', '', $langfile );
5865      if( !empty( $langfile ))
5866      {
5867          if( is_file( $_CONF['path_language'] . $langfile . '.php' ))
5868          {
5869              return $langfile;
5870          }
5871      }
5872  
5873      // if all else fails, return the default language
5874      return $_CONF['language'];
5875  }
5876  
5877  /**
5878  * Determine the ID to use for the current language
5879  *
5880  * The $_CONF['language_files'] array maps language IDs to language file names.
5881  * This function returns the language ID for a certain language file, to be
5882  * used in language-dependent URLs.
5883  *
5884  * @param    string  $language   current language file name (optional)
5885  * @return   string              language ID, e.g 'en'; empty string on error
5886  *
5887  */
5888  function COM_getLanguageId( $language = '' )
5889  {
5890      global $_CONF;
5891  
5892      if( empty( $language ))
5893      {
5894          $language = COM_getLanguage();
5895      }
5896  
5897      $lang_id = array_search( $language, $_CONF['language_files'] );
5898      if( $lang_id === false)
5899      {
5900          // that looks like a misconfigured $_CONF['language_files'] array ...
5901          COM_errorLog( 'Language "' . $language . '" not found in $_CONF[\'language_files\'] array!' );
5902  
5903          $lang_id = ''; // not much we can do here ...
5904      }
5905  
5906      return $lang_id;
5907  }
5908  
5909  /**
5910  * Return SQL expression to request language-specific content
5911  *
5912  * Creates part of an SQL expression that can be used to request items in the
5913  * current language only.
5914  *
5915  * @param    string  $field  name of the "id" field, e.g. 'sid' for stories
5916  * @param    string  $type   part of the SQL expression, e.g. 'WHERE', 'AND'
5917  * @param    string  $table  table name if ambiguous, e.g. in JOINs
5918  * @return   string          SQL expression string (may be empty)
5919  *
5920  */
5921  function COM_getLangSQL( $field, $type = 'WHERE', $table = '' )
5922  {
5923      global $_CONF;
5924  
5925      $sql = '';
5926  
5927      if( isset( $_CONF['languages'] ) && isset( $_CONF['language_files'] ))
5928      {
5929          if( !empty( $table ))
5930          {
5931              $table .= '.';
5932          }
5933  
5934          $lang_id = COM_getLanguageId();
5935  
5936          if( !empty( $lang_id ))
5937          {
5938              $sql = ' ' . $type . " ({$table}$field LIKE '%_$lang_id')";
5939          }
5940      }
5941  
5942      return $sql;
5943  }
5944  
5945  /**
5946  * Provides a drop-down menu (or simple link, if you only have two languages)
5947  * to switch languages. This can be used as a PHP block or called from within
5948  * your theme's header.thtml: <?php print phpblock_switch_language(); ?>
5949  *
5950  * @return   string  HTML for drop-down or link to switch languages
5951  *
5952  */
5953  function phpblock_switch_language()
5954  {
5955      global $_CONF;
5956  
5957      $retval = '';
5958  
5959      if( !isset( $_CONF['languages'] ) || !isset( $_CONF['language_files'] ) ||
5960            ( count( $_CONF['languages'] ) != count( $_CONF['language_files'] )))
5961      {
5962          return $retval;
5963      }
5964  
5965      $lang = COM_getLanguage();
5966      $langId = COM_getLanguageId( $lang );
5967  
5968      if( count( $_CONF['languages'] ) == 2 )
5969      {
5970          foreach( $_CONF['languages'] as $key => $value )
5971          {
5972              if( $key != $langId )
5973              {
5974                  $newLang = $value;
5975                  $newLangId = $key;
5976                  break;
5977              }
5978          }
5979  
5980          $switchUrl = COM_buildUrl( $_CONF['site_url'] . '/switchlang.php?lang='
5981                                     . $newLangId );
5982          $retval .= '<a href="' . $switchUrl . '">' . $newLang . '</a>';
5983      }
5984      else
5985      {
5986          $retval .= '<form name="change" action="'. $_CONF['site_url']
5987                  . '/switchlang.php" method="GET">' . LB;
5988          $retval .= '<input type="hidden" name="oldlang" value="' . $langId
5989                  . '">' . LB;
5990  
5991          $retval .= '<select onchange="change.submit()" name="lang">';
5992          foreach( $_CONF['languages'] as $key => $value )
5993          {
5994              if( $lang == $_CONF['language_files'][$key] )
5995              {
5996                  $selected = ' selected="selected"';
5997              }
5998              else
5999              {
6000                  $selected = '';
6001              }
6002              $retval .= '<option value="' . $key . '"' . $selected . '>'
6003                      . $value . '</option>' . LB;
6004          }
6005          $retval .= '</select>' . LB;
6006          $retval .= '</form>' . LB;
6007      }
6008  
6009      return $retval;
6010  }
6011  
6012  /**
6013  * Switch locale settings
6014  *
6015  * When multi-language support is enabled, allow overwriting the default locale
6016  * settings with language-specific settings (date format, etc.). So in addition
6017  * to $_CONF['date'] you can have a $_CONF['date_en'], $_CONF['date_de'], etc.
6018  *
6019  */
6020  function COM_switchLocaleSettings()
6021  {
6022      global $_CONF;
6023  
6024      if( isset( $_CONF['languages'] ) && isset( $_CONF['language_files'] ))
6025      {
6026          $overridables = array
6027          (
6028            'locale',
6029            'date', 'daytime', 'shortdate', 'dateonly', 'timeonly',
6030            'week_start', 'hour_mode',
6031            'thousand_separator', 'decimal_separator'
6032          );
6033  
6034          $langId = COM_getLanguageId();
6035          foreach( $overridables as $option )
6036          {
6037              if( isset( $_CONF[$option . '_' . $langId] ))
6038              {
6039                  $_CONF[$option] = $_CONF[$option . '_' . $langId];
6040              }
6041          }
6042      }
6043  }
6044  
6045  /**
6046  * Truncate a string
6047  *
6048  * Truncates a string to a max. length and optionally adds a filler string,
6049  * e.g. '...', to indicate the truncation.
6050  * This function is multi-byte string aware, based on a patch by Yusuke Sakata.
6051  *
6052  * @param    string  $text   the text string to truncate
6053  * @param    int     $maxlen max. number of characters in the truncated string
6054  * @param    string  $filler optional filler string, e.g. '...'
6055  * @return   string          truncated string
6056  *
6057  * @note The truncated string may be shorter but will never be longer than
6058  *       $maxlen characters, i.e. the $filler string is taken into account.
6059  *
6060  */
6061  function COM_truncate( $text, $maxlen, $filler = '' )
6062  {
6063      $newlen = $maxlen - MBYTE_strlen( $filler );
6064      $len = MBYTE_strlen( $text );
6065      if( $len > $maxlen )
6066      {
6067          $text = MBYTE_substr( $text, 0, $newlen ) . $filler;
6068      }
6069  
6070      return $text;
6071  }
6072  
6073  /**
6074    * Handle errors.
6075    *
6076    * This function will handle all PHP errors thrown at it, without exposing
6077    * paths, and hopefully, providing much more information to Root Users than
6078    * the default white error page.
6079    *
6080    * This function will call out to CUSTOM_handleError if it exists, but, be
6081    * advised, only override this function with a very, very stable function. I'd
6082    * suggest one that outputs some static, basic HTML.
6083    *
6084    * The PHP feature that allows us to do so is documented here:
6085    * http://uk2.php.net/manual/en/function.set-error-handler.php
6086    *
6087    * @param  int     $errno      Error Number.
6088    * @param  string  $errstr     Error Message.
6089    * @param  string  $errfile    The file the error was raised in.
6090    * @param  int     $errline    The line of the file that the error was raised at.
6091    * @param  array   $errcontext An array that points to the active symbol table at the point the error occurred.
6092    */
6093  function COM_handleError($errno, $errstr, $errfile='', $errline=0, $errcontext='')
6094  {
6095      global $_CONF, $_USER;
6096  
6097      // Handle @ operator
6098      if( error_reporting() == 0 )
6099      {
6100          return;
6101      }
6102  
6103      /* If in PHP4, then respect error_reporting */
6104      if( (PHP_VERSION < 5) && (($errno & error_reporting()) == 0) ) return;
6105  
6106      /*
6107       * If we have a root user, then output detailed error message:
6108       */
6109      if( ( is_array($_USER) && function_exists('SEC_inGroup') ) || $_CONF['rootdebug'] )
6110      {
6111          if($_CONF['rootdebug'] || SEC_inGroup('Root'))
6112          {
6113              echo("
6114                  An error has occurred:<br/>
6115                  $errno - $errstr @ $errfile line $errline<br/>
6116              <pre>");
6117              ob_start();
6118              var_dump($errcontext);
6119              $errcontext = htmlspecialchars(ob_get_contents());
6120              ob_end_clean();
6121              echo("$errcontext</pre>
6122              (This text is only displayed to users in the group 'Root')
6123              ");
6124              exit;
6125          }
6126      }
6127  
6128      /* If there is a custom error handler, fail over to that, but only
6129       * if the error wasn't in lib-custom.php
6130       */
6131      if( is_array($_CONF) && !(strstr($errfile, 'lib-custom.php')))
6132      {
6133          if( array_key_exists('path_system', $_CONF) )
6134          {
6135              require_once($_CONF['path_system'].'lib-custom.php');
6136              if( function_exists('CUSTOM_handleError') )
6137              {
6138                  CUSTOM_handleError($errno, $errstr, $errfile, $errline, $errcontext);
6139                  exit;
6140              }
6141          }
6142      }
6143  
6144      /* Does the theme implement an error message html file? */
6145      if(file_exists($_CONF['path_layout'].'errormessage.html'))
6146      {
6147          // NOTE: NOT A TEMPLATE! JUST HTML!
6148          include($_CONF['path_layout'].'errormessage.html');
6149      } else {
6150          /* Otherwise, display simple error message */
6151          echo("
6152          <html>
6153              <head>
6154                  <title>{$_CONF['site_name']} - An Error Occurred</title>
6155              </head>
6156              <body>
6157              <div style=\"width: 100%; text-align: center;\">
6158              Unfortunately, an error has occurred rendering this page. Please try
6159              again later.
6160              </div>
6161              </body>
6162          </html>
6163          ");
6164      }
6165  
6166      exit;
6167  }
6168  
6169  // Now include all plugin functions
6170  foreach( $_PLUGINS as $pi_name )
6171  {
6172      require_once( $_CONF['path'] . 'plugins/' . $pi_name . '/functions.inc' );
6173  }
6174  
6175  // Check and see if any plugins (or custom functions)
6176  // have scheduled tasks to perform
6177  if( $_CONF['cron_schedule_interval'] > 0 )
6178  {
6179      if(( DB_getItem( $_TABLES['vars'], 'value', "name='last_scheduled_run'" )
6180              + $_CONF['cron_schedule_interval'] ) <= time())
6181      {
6182          DB_query( "UPDATE {$_TABLES['vars']} SET value=UNIX_TIMESTAMP() WHERE name='last_scheduled_run'" );
6183          PLG_runScheduledTask();
6184      }
6185  }
6186  
6187  ?>


Généré le : Wed Nov 21 12:27:40 2007 par Balluche grâce à PHPXref 0.7
  Clicky Web Analytics