WackoWiki PHP Cross Reference Collaborative Wikis

Source: /classes/wacko.php - 6568 lines - 175990 bytes - Summary - Text - Print

   1  <?php
   2  
   3  if (!defined('IN_WACKO'))
   4  {
   5      exit('No direct script access allowed');
   6  }
   7  
   8  // engine class
   9  class Wacko
  10  {
  11      // VARIABLES
  12      var $config                    = array();
  13      var $dblink;
  14      var $page;
  15      var $tag;
  16      var $charset;
  17      var $supertag;
  18      var $forum;
  19      var $categories;
  20      var $iswatched;
  21      var $query_time;
  22      var $query_log                = array();
  23      var $inter_wiki                = array();
  24      var $_acl                    = array();
  25      var $acl_cache                = array();
  26      var $context                = array();
  27      var $current_context        = 0;
  28      var $page_meta                = 'page_id, owner_id, user_id, tag, supertag, created, modified, edit_note, minor_edit, latest, handler, comment_on_id, lang, title, keywords, description';
  29      var $first_inclusion        = array();    // for backlinks
  30      var $format_safe            = true;        //for htmlspecialchars() in pre_link
  31      var $unicode_entities        = array();    //common unicode array
  32      var $timer;
  33      var $toc_context            = array();
  34      var $search_engines            = array('bot', 'rambler', 'yandex', 'crawl', 'search', 'archiver', 'slurp', 'aport', 'crawler', 'google', 'inktomi', 'spider', );
  35      var $_lang_list                = null;
  36      var $languages                = null;
  37      var $translations            = null;
  38      var $wanted_cache            = null;
  39      var $page_cache                = null;
  40      var $_formatter_noautolinks    = null;
  41      var $numerate_links            = null;
  42      var $post_wacko_action        = null;
  43      var $_userhost                = null;
  44      var $paragrafica_styles        = array(
  45          'before'    => array(
  46                          '_before'    => '',
  47                          '_after'    => '',
  48                          'before'    => '<span class="pmark">[##]</span><br />',
  49                          'after'        => ''),
  50          'after'        => array(
  51                          '_before'    => '',
  52                          '_after'    => '',
  53                          'before'    => '',
  54                          'after'        => '<span class="pmark">[##]</span>'),
  55          'right'        => array(
  56                          '_before'    => '<div class="pright"><div class="p-">&nbsp;<span class="pmark">[##]</span></div><div class="pbody-">',
  57                          '_after'    => '</div></div>',
  58                          'before'    => '',
  59                          'after'        => ''),
  60          'left'        => array(
  61                          '_before'    => '<div class="pleft"><div class="p-"><span class="pmark">[##]</span>&nbsp;</div><div class="pbody-">',
  62                          '_after'    => '</div></div>',
  63                          'before'    => '',
  64                          'after'        => ''),
  65      );
  66      var $paragrafica_patches = array(
  67          'before'    => array('before'),
  68          'after'        => array('after'),
  69          'right'        => array('_before'),
  70          'left'        => array('_before'),
  71      );
  72      var $translit_macros = array(
  73          '' => 'wiki', '' => 'wacko', '' => 'web'
  74      );
  75  
  76      // CONSTRUCTOR
  77  	function __construct($config, $dblink)
  78      {
  79          $this->timer    = $this->get_micro_time();
  80          $this->config    = $config;
  81          $this->dblink    = $dblink;
  82  
  83          $this->charset    = $this->get_charset();
  84      }
  85  
  86      // DATABASE
  87  	function sql_query($query, $debug = 0)
  88      {
  89          if ($debug)
  90          {
  91              echo "(QUERY: $query)";
  92          }
  93  
  94          if ($this->config['debug'] >= 2)
  95          {
  96              $start = $this->get_micro_time();
  97          }
  98  
  99          $result = sql_query($this->dblink, $query, $this->config['debug']);
 100  
 101          if ($this->config['debug'] >= 2)
 102          {
 103              $time = $this->get_micro_time() - $start;
 104              $this->query_time += $time;
 105  
 106              if ($this->config['debug'] >= 3)
 107              {
 108                  $this->query_log[] = array(
 109                      'query'        => $query,
 110                      'time'        => $time
 111                  );
 112              }
 113          }
 114  
 115          return $result;
 116      }
 117  
 118  	function load_all($query, $docache = 0)
 119      {
 120          $data    = array();
 121  
 122          // retrieving from cache
 123          if ($this->config['cache_sql'] && $docache)
 124          {
 125              if ($data = $this->cache->load_sql($query))
 126              {
 127                  return $data;
 128              }
 129          }
 130  
 131          // retrieving from db
 132          if ($r = $this->sql_query($query))
 133          {
 134              while ($row = fetch_assoc($r))
 135              {
 136                  $data[] = $row;
 137              }
 138  
 139              free_result($r);
 140          }
 141  
 142          // saving to cache
 143          if ($this->config['cache_sql'] && $docache)
 144          {
 145              $this->cache->save_sql($query, $data);
 146          }
 147  
 148          if (isset($data))
 149          {
 150              return $data;
 151          }
 152          else
 153          {
 154              return null;
 155          }
 156      }
 157  
 158  	function load_single($query, $docache = 0)
 159      {
 160          if ($data = $this->load_all($query, $docache))
 161  
 162              if (isset($data))
 163              {
 164                  return $data[0];
 165              }
 166              else
 167              {
 168                  return null;
 169              }
 170      }
 171  
 172      // MISC
 173  	function get_micro_time()
 174      {
 175          list($usec, $sec) = explode(' ', microtime());
 176          return ((float)$usec + (float)$sec);
 177      }
 178  
 179  	function get_page_tag($page_id = 0)
 180      {
 181          $page = $this->load_single(
 182              "SELECT tag ".
 183              "FROM ".$this->config['table_prefix']."page ".
 184              "WHERE page_id = '".quote($this->dblink, $page_id)."' ".
 185              "LIMIT 1");
 186  
 187          return $page['tag'];
 188      }
 189  
 190  	function get_page_id($tag = '')
 191      {
 192          if(!$tag)
 193          {
 194              return $this->page['page_id'];
 195          }
 196          else
 197          //Soon we'll need to have page_id when saving a new page to continue working with $page_id instead of $tag
 198          {
 199              if (!isset($this->page_id_cache[$tag]))
 200              {
 201                  // Returns Array ( [id] => Value )
 202                  $get_page_id = $this->load_single(
 203                      "SELECT page_id ".
 204                      "FROM ".$this->config['table_prefix']."page ".
 205                      "WHERE tag = '".quote($this->dblink, $tag)."' ".
 206                      "LIMIT 1");
 207  
 208                  // Get page_ID value
 209                  $new_page_id = $get_page_id['page_id'];
 210  
 211                  $this->page_id_cache[$tag] = $new_page_id;
 212              }
 213              else
 214              {
 215                  $new_page_id = $this->page_id_cache[$tag];
 216              }
 217  
 218              return $new_page_id;
 219          }
 220      }
 221  
 222  	function get_wacko_version()
 223      {
 224          return WACKO_VERSION;
 225      }
 226  
 227      // checks if the parameter is an empty string or a string containing only whitespace
 228  	function is_blank( $variable )
 229      {
 230          if( trim( $variable ) == '' )
 231          {
 232              return true;
 233          }
 234  
 235          return false;
 236      }
 237  
 238  	function check_file_exists($file_name, $unwrapped_tag = '' )
 239      {
 240          if ($unwrapped_tag == '')
 241          {
 242              $page_id = 0;
 243          }
 244          else
 245          {
 246              $page        = $this->load_page($unwrapped_tag, 0, '', LOAD_CACHE, LOAD_META);
 247              $page_id    = $page['page_id'];
 248  
 249              if (!$page_id)
 250              {
 251                  return false;
 252              }
 253          }
 254  
 255          $file = (isset($this->files_cache[$page_id][$file_name]) ? $this->files_cache[$page_id][$file_name] : '');
 256  
 257          if (!$file)
 258          {
 259              $file = $this->load_single(
 260                  "SELECT upload_id, user_id, file_name, file_size, lang, file_description, picture_w, picture_h, file_ext ".
 261                  "FROM ".$this->config['table_prefix']."upload ".
 262                  "WHERE page_id = '".quote($this->dblink, $page_id)."' ".
 263                      "AND file_name = '".quote($this->dblink, $file_name)."' ".
 264                  "LIMIT 1");
 265  
 266              if (count($file) == 0)
 267              {
 268                  return false;
 269              }
 270  
 271              $this->files_cache[$page_id][$file_name] = $file;
 272          }
 273  
 274          return $file;
 275      }
 276  
 277  	function available_themes()
 278      {
 279          $handle    = opendir('themes');
 280  
 281          while (false !== ($file = readdir($handle)))
 282          {
 283              if ($file != '.' && $file != '..' && is_dir('themes/'.$file) && $file != '_common')
 284              {
 285                  $themelist[] = $file;
 286              }
 287          }
 288  
 289          closedir($handle);
 290          sort($themelist, SORT_STRING);
 291  
 292          if ($allow = trim($this->config['allow_themes']))
 293          {
 294              $ath = explode(',', $allow);
 295  
 296              if (is_array($ath) && $ath[0])
 297              {
 298                  $themelist = array_intersect ($ath, $themelist);
 299              }
 300          }
 301  
 302          return $themelist;
 303      }
 304  
 305      // TIME FUNCTIONS
 306  	function get_time_tz($time)
 307      {
 308          $user            = $this->get_user();
 309          $zone_offset    = ($user['timezone'] * 3600) + ($user['dst'] * 3600);
 310          $tz_time        = $time + $zone_offset - date('Z');
 311  
 312          return $tz_time;
 313      }
 314  
 315  	function get_time_string_formatted($time)
 316      {
 317          $tz_time = $this->get_time_tz( strtotime($time) );
 318  
 319          return date($this->config['date_format'].' '.
 320              $this->config['time_format_seconds'], $tz_time);
 321      }
 322  
 323  	function get_unix_time_formatted($time)
 324      {
 325          $tz_time = $this->get_time_tz($time);
 326  
 327          return date($this->config['date_format'].' '.
 328              $this->config['time_format_seconds'], $tz_time);
 329      }
 330  
 331  	function get_page_time_formatted()
 332      {
 333          return $this->get_time_string_formatted($this->page['modified']);
 334      }
 335  
 336      // LANG FUNCTIONS
 337  	function set_translation($lang)
 338      {
 339          $this->resource = & $this->translations[$lang];
 340      }
 341  
 342  	function set_language($lang)
 343      {
 344          $this->load_translation($lang);
 345          $this->language = &$this->languages[$lang];
 346  
 347          setlocale(LC_CTYPE, $this->language['locale']);
 348  
 349          $this->language['locale']        = setlocale(LC_CTYPE, 0);
 350          $this->language['UPPER']        = '['.$this->language['UPPER_P'].']';
 351          $this->language['UPPERNUM']        = '[0-9'.$this->language['UPPER_P'].']';
 352          $this->language['LOWER']        = '['.$this->language['LOWER_P'].']';
 353          $this->language['ALPHA']        = '['.$this->language['ALPHA_P'].']';
 354          $this->language['ALPHANUM']        = '[0-9'.$this->language['ALPHA_P'].']';
 355          $this->language['ALPHANUM_P']    = '0-9'.$this->language['ALPHA_P'];
 356  
 357          // set charset
 358          #$this->charset = $this->language['charset'];
 359      }
 360  
 361  	function load_translation($lang)
 362      {
 363          if (!isset($this->translations[$lang]))
 364          {
 365              $resourcefile = 'lang/wacko.'.$lang.'.php';
 366  
 367              if (@file_exists($resourcefile))
 368              {
 369                  include($resourcefile);
 370              }
 371  
 372              // wacko.all
 373              $resourcefile = 'lang/wacko.all.php';
 374  
 375              if (!$this->translations['all'])
 376              {
 377                  if (@file_exists($resourcefile))
 378                  {
 379                      include($resourcefile);
 380                  }
 381  
 382                  $this->translations['all'] = & $wacko_all_resource;
 383              }
 384  
 385              if (!isset($wacko_translation))
 386              {
 387                  $wacko_translation = array();
 388              }
 389  
 390              $wacko_resource = array_merge($wacko_translation, $this->translations['all']);
 391  
 392              // theme
 393              $resourcefile = 'themes/'.$this->config['theme'].'/lang/wacko.'.$lang.'.php';
 394  
 395              if (@file_exists($resourcefile))
 396              {
 397                  include($resourcefile);
 398              }
 399              if (!isset($theme_translation))
 400              {
 401                  $theme_translation = '';
 402              }
 403  
 404              $wacko_resource = array_merge((array)$wacko_resource, (array)$theme_translation);
 405  
 406              // wacko.all theme
 407              $resourcefile = 'themes/'.$this->config['theme'].'/lang/wacko.all.php';
 408  
 409              if (@file_exists($resourcefile))
 410              {
 411                  include($resourcefile);
 412              }
 413  
 414              $wacko_resource = array_merge((array)$wacko_resource, (array)$theme_translation);
 415  
 416              $this->translations[$lang] = $wacko_resource;
 417              $this->load_lang($lang);
 418          }
 419      }
 420  
 421  	function load_lang($lang)
 422      {
 423          $wacko_language = '';
 424  
 425          if (!isset($this->languages[$lang]))
 426          {
 427              $resourcefile = 'lang/lang.'.$lang.'.php';
 428  
 429              if (@file_exists($resourcefile))
 430              {
 431                  include($resourcefile);
 432              }
 433  
 434              $this->languages[$lang] = $wacko_language;
 435              $ue = array();
 436              $ue = @array_flip($wacko_language['unicode_entities']);
 437  
 438              if (!isset($ue))
 439              {
 440                  $ue = array();
 441              }
 442  
 443              $this->unicode_entities = array_merge($this->unicode_entities, (array)$ue);
 444              unset($this->unicode_entities[0]);
 445          }
 446      }
 447  
 448  	function load_all_languages()
 449      {
 450          if (!$this->config['multilanguage'])
 451          {
 452              return;
 453          }
 454  
 455          $langs = $this->available_languages();
 456  
 457          foreach ($langs as $lang)
 458          {
 459              $this->load_lang($lang);
 460          }
 461      }
 462  
 463  	function available_languages()
 464      {
 465          if (!$this->_lang_list)
 466          {
 467              $handle = opendir('lang');
 468  
 469              while (false !== ($file = readdir($handle)))
 470              {
 471                  if ($file != '.'
 472                  && $file != '..'
 473                  && $file != 'wacko.all.php'
 474                  && !is_dir('lang/'.$file)
 475                  && 1 == preg_match('/^wacko\.(.*?)\.php$/', $file, $match))
 476                  {
 477                      $lang_list[] = $match[1];
 478                  }
 479              }
 480  
 481              closedir($handle);
 482              sort($lang_list, SORT_STRING);
 483              $this->_lang_list = $lang_list;
 484          }
 485  
 486          return $this->_lang_list;
 487      }
 488  
 489  	function user_agent_language()
 490      {
 491          $lang = '';
 492  
 493          if ($this->config['multilanguage'])
 494          {
 495              if(isset($_SERVER['HTTP_ACCEPT_LANGUAGE']))
 496              {
 497                  $this->user_lang = $lang = strtolower(substr($_SERVER['HTTP_ACCEPT_LANGUAGE'], 0, 2));
 498  
 499                  // Check whether we have language files for this language
 500                  if(!in_array($this->user_lang, $this->available_languages()))
 501                  {
 502                      // The HTTP_ACCEPT_LANGUAGE language doesn't have any language files so use the admin set language instead
 503                      $this->user_lang = $lang = $this->config['language'];
 504                  }
 505              }
 506              else
 507              {
 508                  $this->user_lang = $lang = $this->config['language'];
 509              }
 510          }
 511          else if (!$lang)
 512          {
 513              $this->user_lang = $lang = $this->config['language'];
 514          }
 515  
 516          return $lang;
 517      }
 518  
 519  	function get_translation($name, $lang = '', $dounicode = true)
 520      {
 521          if (!$this->config['multilanguage'])
 522          {
 523              return $this->resource[$name];
 524          }
 525  
 526          if (!$lang && (isset($this->user_lang) && $this->user_lang != $this->page_lang))
 527          {
 528              $lang = $this->user_lang;
 529          }
 530  
 531          if ($lang != '')
 532          {
 533              $this->load_translation($lang);
 534  
 535              if (isset($this->translations[$lang][$name]))
 536              {
 537                  return (is_array($this->translations[$lang][$name]))
 538                      ? $this->translations[$lang][$name]
 539                      : ($dounicode
 540                          ? $this->do_unicode_entities($this->translations[$lang][$name], $lang)
 541                          : $this->translations[$lang][$name]);
 542              }
 543          }
 544  
 545          if (isset($this->resource[$name]))
 546          {
 547              return $this->resource[$name];
 548          }
 549      }
 550  
 551  	function format_translation($name, $lang = '')
 552      {
 553          $string = $this->get_translation($name, $lang, false);
 554          $this->format_safe = false;
 555          $string = $this->format($string);
 556          $this->format_safe = true;
 557          return $string;
 558      }
 559  
 560  	function determine_lang()
 561      {
 562          $lang_list = $this->available_languages();
 563  
 564          //!!!! wrong code, maybe!
 565          if ((isset($this->method) && $this->method == 'edit') && (isset($_GET['add']) && $_GET['add'] == 1))
 566          {
 567              if (isset($_REQUEST['lang']) && in_array($_REQUEST['lang'], $lang_list))
 568              {
 569                  $lang = $_REQUEST['lang'];
 570              }
 571              else
 572              {
 573                  $lang = $this->user_lang;
 574              }
 575          }
 576          else
 577          {
 578              $lang = (isset($this->page_lang) ? $this->page_lang : null);
 579          }
 580  
 581          return $lang;
 582      }
 583  
 584  	function set_page_lang($lang)
 585      {
 586          if (!$lang)
 587          {
 588              return false;
 589          }
 590  
 591          $this->page_lang = $lang;
 592          $this->set_language($lang);
 593          return true;
 594      }
 595  
 596  	function get_charset()
 597      {
 598          $lang = $this->determine_lang();
 599          $this->load_translation($lang);
 600  
 601          if (isset($this->languages[$lang]['charset']))
 602          {
 603              #$this->charset    = $this->languages[$lang]['charset'];
 604              #$this->debug_print_r($this->languages[$lang]['charset']);
 605              return $this->languages[$lang]['charset'];
 606          }
 607          else
 608          {
 609              null;
 610          }
 611      }
 612  
 613  	function do_unicode_entities($string, $lang)
 614      {
 615          if (!$this->config['multilanguage'])
 616          {
 617              return $string;
 618          }
 619  
 620          $_lang = $this->determine_lang();
 621  
 622          if ($lang == $_lang)
 623          {
 624              return $string;
 625          }
 626  
 627          $this->load_translation($lang);
 628  
 629          if (is_array($this->languages[$lang]['unicode_entities']))
 630          {
 631              return @strtr($string, $this->languages[$lang]['unicode_entities']);
 632          }
 633          else
 634          {
 635              return $string;
 636          }
 637      }
 638  
 639  	function try_utf_decode ($string)
 640      {
 641          $t1 = $this->utf8_to_unicode_entities($string);
 642          $t2 = @strtr($t1, $this->unicode_entities);
 643  
 644          if (!preg_match('/\&\#[0-9]+\;/', $t2))
 645          {
 646              $string = $t2;
 647          }
 648  
 649          return $string;
 650      }
 651  
 652  	function utf8_to_unicode_entities($source)
 653      {
 654          // array used to figure what number to decrement from character order value
 655          // according to number of characters used to map unicode to ascii by utf-8
 656          $decrement[4] = 240;
 657          $decrement[3] = 224;
 658          $decrement[2] = 192;
 659          $decrement[1] = 0;
 660  
 661          // the number of bits to shift each char_num by
 662          $shift[1][0] = 0;
 663          $shift[2][0] = 6;
 664          $shift[2][1] = 0;
 665          $shift[3][0] = 12;
 666          $shift[3][1] = 6;
 667          $shift[3][2] = 0;
 668          $shift[4][0] = 18;
 669          $shift[4][1] = 12;
 670          $shift[4][2] = 6;
 671          $shift[4][3] = 0;
 672  
 673          $pos            = 0;
 674          $len            = strlen ($source);
 675          $encoded_string    = '';
 676  
 677          while ($pos < $len)
 678          {
 679              $ascii_pos = ord (substr ($source, $pos, 1));
 680  
 681              if (($ascii_pos >= 240) && ($ascii_pos <= 255))
 682              {
 683                  // 4 chars representing one unicode character
 684                  $this_letter = substr ($source, $pos, 4);
 685                  $pos += 4;
 686              }
 687              else if (($ascii_pos >= 224) && ($ascii_pos <= 239))
 688              {
 689                  // 3 chars representing one unicode character
 690                  $this_letter = substr ($source, $pos, 3);
 691                  $pos += 3;
 692              }
 693              else if (($ascii_pos >= 192) && ($ascii_pos <= 223))
 694              {
 695                  // 2 chars representing one unicode character
 696                  $this_letter = substr ($source, $pos, 2);
 697                  $pos += 2;
 698              }
 699              else
 700              {
 701                  // 1 char (lower ascii)
 702                  $this_letter = substr ($source, $pos, 1);
 703                  $pos += 1;
 704              }
 705  
 706              // process the string representing the letter to a unicode entity
 707              $this_len = strlen ($this_letter);
 708  
 709              if ($this_len > 1)
 710              {
 711                  $this_pos        = 0;
 712                  $decimal_code    = 0;
 713  
 714                  while ($this_pos < $this_len)
 715                  {
 716                      $this_char_ord = ord (substr ($this_letter, $this_pos, 1));
 717  
 718                      if ($this_pos == 0)
 719                      {
 720                          $char_num = intval ($this_char_ord - $decrement[$this_len]);
 721                          $decimal_code += ($char_num << $shift[$this_len][$this_pos]);
 722                      }
 723                      else
 724                      {
 725                          $char_num = intval ($this_char_ord - 128);
 726                          $decimal_code += ($char_num << $shift[$this_len][$this_pos]);
 727                      }
 728  
 729                      $this_pos++;
 730                  }
 731  
 732                  $encoded_letter = '&#'. $decimal_code . ';';
 733              }
 734              else
 735              {
 736                  $encoded_letter = $this_letter;
 737              }
 738  
 739              $encoded_string .= $encoded_letter;
 740          }
 741  
 742          return $encoded_string;
 743      }
 744  
 745      // PAGES
 746  	function translit($tag, $strtolow = TRAN_LOWERCASE, $donotload = TRAN_LOAD)
 747      {
 748          // Lookup transliteration result in the cache and return it if found
 749          static $translit_cache;
 750          $cach_key = $tag.$strtolow.$donotload;
 751  
 752          if (isset($translit_cache[$cach_key]))
 753          {
 754              return $translit_cache[$cach_key];
 755          }
 756  
 757          $_lang = null;
 758  
 759          if (!$this->config['multilanguage'])
 760          {
 761              $donotload = 1;
 762          }
 763  
 764          if (!$donotload)
 765          {
 766              if ($page = $this->load_page($tag, 0, '', LOAD_CACHE, LOAD_META))
 767              {
 768                  $_lang = $this->language['code'];
 769  
 770                  if (isset($page['lang']))
 771                  {
 772                      $lang = $page['lang'];
 773                  }
 774                  else
 775                  {
 776                      $lang = $this->config['language'];
 777                  }
 778  
 779                  $this->set_language($lang);
 780              }
 781          }
 782  
 783          $tag    = str_replace('//',        '/',    $tag);
 784          $tag    = str_replace('-',        '',        $tag);
 785          $tag    = str_replace(' ',        '',        $tag);
 786          $tag    = str_replace("'",        '_',    $tag);
 787          $_tag    = strtolower($tag);
 788  
 789          if ($strtolow)
 790          {
 791              $tag = @strtr($_tag, $this->translit_macros);
 792          }
 793          else
 794          {
 795              foreach($this->translit_macros as $macro => $value)
 796              {
 797                  while (($pos = strpos($_tag, $macro)) !== false)
 798                  {
 799                      $_tag    = substr_replace($_tag, $value, $pos, strlen($macro));
 800                      $tag    = substr_replace($tag, ucfirst($value), $pos, strlen($macro));
 801                  }
 802              }
 803          }
 804  
 805          $tag = @strtr($tag, $this->language['TranslitLettersFrom'], $this->language['TranslitLettersTo']);
 806          $tag = @strtr($tag, $this->language['TranslitBiLetters']);
 807  
 808          if ($strtolow)
 809          {
 810              $tag = strtolower($tag);
 811          }
 812  
 813          if ($_lang)
 814          {
 815              $this->set_language($_lang);
 816          }
 817  
 818          $result = rtrim($tag, '/');
 819  
 820          // Put transliteration result in the cache
 821          $translit_cache[$cach_key] = $result;
 822  
 823          return $result;
 824      }
 825  
 826  	function get_keywords()
 827      {
 828          $meta_keywords = '';
 829  
 830          if (isset($this->page['keywords']))
 831          {
 832              $meta_keywords = $this->page['keywords'];
 833          }
 834          else if ($this->config['meta_keywords'])
 835          {
 836              $meta_keywords = $this->config['meta_keywords'];
 837          }
 838  
 839          // add assigned categories
 840          if (isset($this->categories))
 841          {
 842              if (!empty($meta_keywords))
 843              {
 844                  $meta_keywords .= ', ';
 845              }
 846  
 847              $meta_keywords .= strtolower(implode(', ', $this->categories));
 848          }
 849  
 850          return htmlspecialchars($meta_keywords, ENT_COMPAT | ENT_HTML401, HTML_ENTITIES_CHARSET);
 851      }
 852  
 853  	function get_description()
 854      {
 855          $meta_description = '';
 856  
 857          if ($this->page['description'])
 858          {
 859              $meta_description = $this->page['description'];
 860          }
 861          else if ($this->config['meta_description'])
 862          {
 863              $meta_description = $this->config['meta_description'];
 864          }
 865  
 866          return htmlspecialchars($meta_description, ENT_COMPAT | ENT_HTML401, HTML_ENTITIES_CHARSET);
 867      }
 868  
 869      // wrapper for old_load_page
 870  	function load_page($tag, $page_id = 0, $revision_id = '', $cache = LOAD_CACHE, $metadata_only = LOAD_ALL, $deleted = 0)
 871      {
 872          $page = '';
 873  
 874          if ($page_id != 0)
 875          {
 876              if ($this->get_cached_wanted_page('', $page_id) == 1)
 877              {
 878                  return '';
 879              }
 880          }
 881          else
 882          {
 883              if ($this->get_cached_wanted_page($tag) == 1)
 884              {
 885                  return '';
 886              }
 887          }
 888  
 889          // 1. search for page_id (... is preferred, $supertag next)
 890          if ($page_id != 0)
 891          {
 892              $page = $this->old_load_page('', $page_id, $revision_id, $cache, false, $metadata_only, $deleted);
 893          }
 894  
 895          // 2. search for supertag
 896          if (!$page)
 897          {
 898              $page = $this->old_load_page($this->translit($tag, TRAN_LOWERCASE, TRAN_DONTLOAD), 0, $revision_id, $cache, true, $metadata_only, $deleted);
 899          }
 900  
 901          // 3. if not found, search for tag
 902          if (!$page)
 903          {
 904              $page = $this->old_load_page($tag, 0, $revision_id, $cache, false, $metadata_only, $deleted);
 905          }
 906  
 907          // 4. still nothing? file under wanted
 908          if (!$page)
 909          {
 910              ($page_id != 0
 911                  ? $this->cache_wanted_page('', $page_id)
 912                  : $this->cache_wanted_page($tag)
 913              );
 914          }
 915  
 916          return $page;
 917      }
 918  
 919  	function old_load_page($tag, $page_id = 0, $revision_id = '', $cache = 1, $supertagged = false, $metadata_only = 0, $deleted = 0)
 920      {
 921          $supertag = '';
 922          $cached_page = '';
 923  
 924          if ($page_id == 0 && $tag == '')
 925          {
 926              return '';
 927          }
 928  
 929          $page = null;
 930  
 931          if ($page_id == 0)
 932          {
 933              (!$supertagged
 934                  ? $supertag = $this->translit($tag, TRAN_LOWERCASE, TRAN_DONTLOAD)
 935                  : $supertag = $tag
 936              );
 937          }
 938  
 939          // retrieve from cache
 940          if (!$revision_id && $cache && ($cached_page = $this->get_cached_page($supertag, $page_id, $metadata_only)))
 941          {
 942              $page = $cached_page;
 943          }
 944  
 945          // load page
 946          if ($metadata_only)
 947          {
 948              $what_p = 'p.page_id, p.owner_id, p.user_id, p.tag, p.supertag, p.title, p.created, p.modified, p.formatting, p.edit_note, p.minor_edit, p.reviewed, p.latest, p.handler, p.comment_on_id, p.lang, p.keywords, p.description, p.noindex, p.deleted, u.user_name, o.user_name AS owner_name';
 949              $what_r = 'p.page_id, p.owner_id, p.user_id, p.tag, p.supertag, p.title, p.created, p.modified, p.formatting, p.edit_note, p.minor_edit, p.reviewed, p.latest, p.handler, p.comment_on_id, p.lang, p.keywords, p.description, s.noindex, p.deleted, u.user_name, o.user_name AS owner_name';
 950          }
 951          else
 952          {
 953              $what_p = 'p.*, u.user_name, o.user_name AS owner_name';
 954              $what_r = 'p.page_id, p.owner_id, p.user_id, p.tag, p.supertag, p.title, p.created, p.modified, p.body, p.body_r, p.formatting, p.edit_note, p.minor_edit, p.reviewed, p.reviewed_time, p.reviewer_id, p.ip, p.latest, p.deleted, p.handler, p.comment_on_id, p.lang, p.description, p.keywords, s.footer_comments, s.footer_files, s.footer_rating, s.hide_toc, s.hide_index, s.tree_level, s.allow_rawhtml, s.disable_safehtml, s.noindex, s.theme, u.user_name, o.user_name AS owner_name';
 955          }
 956  
 957          //
 958          $settings = '';
 959  
 960          if (!$page)
 961          {
 962              if ($supertagged || $page_id)
 963              {
 964                  $page = $this->load_single(
 965                      "SELECT ".$what_p." ".
 966                      "FROM ".$this->config['table_prefix']."page p ".
 967                          "LEFT JOIN ".$this->config['table_prefix']."user o ON (p.owner_id = o.user_id) ".
 968                          "LEFT JOIN ".$this->config['table_prefix']."user u ON (p.user_id = u.user_id) ".
 969                      "WHERE ".( $page_id != 0
 970                          ? "page_id  = '".quote($this->dblink, $page_id)."' "
 971                          : "supertag = '".quote($this->dblink, $supertag)."' " ).
 972                          ( $deleted != 1
 973                              ? "AND p.deleted <> '1' "
 974                              : "").
 975                      "LIMIT 1");
 976  
 977                  $owner_id = $page['owner_id'];
 978  
 979                  if ($revision_id && $revision_id != $page['page_id'])
 980                  {
 981                      $this->cache_page($page, $page_id, $metadata_only);
 982  
 983                      $page = $this->load_single(
 984                          "SELECT p.revision_id, ".$what_r." ".
 985                          "FROM ".$this->config['table_prefix']."revision p ".
 986                              "LEFT JOIN ".$this->config['table_prefix']."user o ON (p.owner_id = o.user_id) ".
 987                              "LEFT JOIN ".$this->config['table_prefix']."user u ON (p.user_id = u.user_id) ".
 988                              "LEFT JOIN ".$this->config['table_prefix']."page s ON (p.page_id = s.page_id) ".
 989                          "WHERE ".( $page_id != 0
 990                              ? "p.page_id  = '".quote($this->dblink, $page_id)."' "
 991                              : "p.supertag = '".quote($this->dblink, $supertag)."' " ).
 992                              ( $deleted != 1
 993                                  ? "AND p.deleted <> '1' "
 994                                  : "").
 995                              "AND revision_id = '".quote($this->dblink, $revision_id)."' ".
 996                          "LIMIT 1");
 997  
 998                      $page['owner_id'] = $owner_id;
 999                  }
1000              }
1001              else if (!preg_match('/[^'.$this->language['ALPHANUM_P'].'\_\-]/', $tag))
1002              {
1003                  $page = $this->load_single(
1004                      "SELECT ".$what_p." ".
1005                      "FROM ".$this->config['table_prefix']."page p ".
1006                          "LEFT JOIN ".$this->config['table_prefix']."user o ON (p.owner_id = o.user_id) ".
1007                          "LEFT JOIN ".$this->config['table_prefix']."user u ON (p.user_id = u.user_id) ".
1008                      "WHERE tag = '".quote($this->dblink, $tag)."' ".
1009                          ( $deleted != 1
1010                              ? "AND p.deleted <> '1' "
1011                              : "").
1012                      "LIMIT 1");
1013  
1014                  $owner_id = $page['owner_id'];
1015  
1016                  if ($revision_id && $revision_id != $page['page_id'])
1017                  {
1018                      $this->cache_page($page, $page_id, $metadata_only);
1019  
1020                      $page = $this->load_single(
1021                          "SELECT ".$what_r." ".
1022                          "FROM ".$this->config['table_prefix']."revision p ".
1023                              "LEFT JOIN ".$this->config['table_prefix']."user o ON (p.owner_id = o.user_id) ".
1024                              "LEFT JOIN ".$this->config['table_prefix']."user u ON (p.user_id = u.user_id) ".
1025                              "LEFT JOIN ".$this->config['table_prefix']."page s ON (p.page_id = s.page_id) ".
1026                          "WHERE p.tag = '".quote($this->dblink, $tag)."' ".
1027                              ( $deleted != 1
1028                                  ? "AND p.deleted <> '1' "
1029                                  : "").
1030                              "AND revision_id = '".quote($this->dblink, $revision_id)."' ".
1031                          "LIMIT 1");
1032  
1033                      $page['owner_id'] = $owner_id;
1034                  }
1035              }
1036          }
1037  
1038          // cache result
1039          if (!$revision_id && !$cached_page)
1040          {
1041              $this->cache_page($page, $page_id, $metadata_only);
1042          }
1043  
1044          return $page;
1045      }
1046  
1047  	function get_cached_page($supertag, $page_id = 0, $metadata_only = 0)
1048      {
1049          if ($page_id != 0)
1050          {
1051              if (isset($this->page_cache['page_id'][$page_id]))
1052              {
1053                  if ($this->page_cache['page_id'][$page_id]['mdonly'] == 0 || $metadata_only == $this->page_cache['page_id'][$page_id]['mdonly'])
1054                  {
1055                      return $this->page_cache['page_id'][$page_id];
1056                  }
1057              }
1058              else
1059              {
1060                  return false;
1061              }
1062          }
1063          else
1064          {
1065              if (isset($this->page_cache['supertag'][$supertag]))
1066              {
1067                  if ($this->page_cache['supertag'][$supertag]['mdonly'] == 0 || $metadata_only == $this->page_cache['supertag'][$supertag]['mdonly'])
1068                  {
1069                      return $this->page_cache['supertag'][$supertag];
1070                  }
1071              }
1072              else
1073              {
1074                  return false;
1075              }
1076          }
1077      }
1078  
1079  	function cache_page($page, $page_id = 0, $metadata_only = 0)
1080      {
1081          if ($page_id != 0)
1082          {
1083              $this->page_cache['page_id'][$page['page_id']]                = $page;
1084              $this->page_cache['page_id'][$page['page_id']]['mdonly']    = $metadata_only;
1085          }
1086          else
1087          {
1088              if (!$page['supertag'])
1089              {
1090                  $page['supertag'] = $this->translit($page['tag'], TRAN_LOWERCASE, TRAN_DONTLOAD);
1091              }
1092  
1093              $this->page_cache['supertag'][$page['supertag']]            = $page;
1094              $this->page_cache['supertag'][$page['supertag']]['mdonly']    = $metadata_only;
1095          }
1096      }
1097  
1098  	function cache_wanted_page($tag, $page_id = 0, $check = 0)
1099      {
1100          if ($check == 0)
1101          {
1102              ($page_id != 0
1103                  ? $this->wanted_cache['page_id'][$page_id] = 1
1104                  : $this->wanted_cache['tag'][$this->language['code']][$tag] = 1
1105              );
1106  
1107          }
1108          else if ($this->old_load_page($tag, $page_id, '', 1, false, 1) == '')
1109          {
1110              ($page_id != 0
1111                  ? $this->wanted_cache['page_id'][$page_id] = 1
1112                  : $this->wanted_cache['tag'][$this->language['code']][$tag] = 1
1113              );
1114          }
1115      }
1116  
1117  	function clear_cache_wanted_page($tag, $page_id = 0)
1118      {
1119          ($page_id != 0
1120              ? $this->wanted_cache['page_id'][$page_id] = 0
1121              : $this->wanted_cache['tag'][$this->language['code']][$tag] = 0
1122          );
1123      }
1124  
1125  	function get_cached_wanted_page($tag, $page_id = 0)
1126      {
1127          if ($page_id != 0)
1128          {
1129              if (isset( $this->wanted_cache['page_id'][$page_id] ))
1130              {
1131                  return $this->wanted_cache['page_id'][$page_id];
1132              }
1133              else
1134              {
1135                  return '';
1136              }
1137          }
1138          else
1139          {
1140              if (isset( $this->wanted_cache['tag'][$this->language['code']][$tag] ))
1141              {
1142                  return $this->wanted_cache['tag'][$this->language['code']][$tag];
1143              }
1144              else
1145              {
1146                  return '';
1147              }
1148          }
1149      }
1150  
1151  	function cache_links()
1152      {
1153          $pages    = '';
1154          $acl    = '';
1155          $lang    = '';
1156          $user    = $this->get_user();
1157          $cl        = 0;
1158  
1159          // get links
1160          if ($links = $this->load_all(
1161              "SELECT to_tag ".
1162              "FROM ".$this->config['table_prefix']."link ".
1163              "WHERE from_page_id = '".quote($this->dblink, $this->page['page_id'])."'"))
1164          {
1165              $cl = count($links);
1166  
1167              for ($i = 0; $i < $cl; $i++)
1168              {
1169                  $pages[] = $links[$i]['to_tag'];
1170              }
1171          }
1172  
1173          // get lang
1174          if(isset($user['lang']))
1175          {
1176              $lang = $user['lang'];
1177          }
1178          else if (!empty($this->config['multilanguage']))
1179          {
1180              $lang = $this->user_agent_language();
1181          }
1182          else
1183          {
1184              $lang = $this->config['language'];
1185          }
1186  
1187          // get menu items
1188          if ($menu_items = $this->load_all(
1189              "SELECT DISTINCT p.tag ".
1190              "FROM ".$this->config['table_prefix']."menu b ".
1191                  "LEFT JOIN ".$this->config['table_prefix']."page p ON (b.page_id = p.page_id) ".
1192              "WHERE (b.user_id IN ( '".quote($this->dblink, $this->get_user_id('System'))."' ) ".
1193                  ($lang
1194                      ? "AND b.lang = '".quote($this->dblink, $lang)."' "
1195                      : "").
1196                      ") ".
1197                  ($user
1198                      ? "OR (b.user_id IN ( '".quote($this->dblink, $user['user_id'])."' )) "
1199                      : "").
1200              "", 1))
1201          {
1202              foreach ($menu_items as $item)
1203              {
1204                  $pages[] = $item['tag'];
1205  
1206              }
1207          }
1208  
1209          $pages[]    = $this->config['users_page'].'/'.$user['user_name'];
1210          $pages[]    = $this->config['users_page'];
1211          $pages[]    = $this->tag;
1212  
1213          $pages        = array_unique($pages);
1214          $spages        = $pages;
1215          $spages_str    = '';
1216          $pages_str    = '';
1217  
1218          foreach ($pages as $page)
1219          {
1220              if ($page != '')
1221              {
1222                  $spages_str    .= "'".quote($this->dblink, $this->translit($page, TRAN_LOWERCASE, TRAN_DONTLOAD))."', ";
1223                  $pages_str    .= "'".quote($this->dblink, $page)."', ";
1224              }
1225          }
1226  
1227          $spages_str    = substr($spages_str, 0, strlen($spages_str) - 2);
1228          $pages_str    = substr($pages_str, 0, strlen($pages_str) - 2);
1229  
1230          if ($links = $this->load_all(
1231          "SELECT ".$this->page_meta." ".
1232          "FROM ".$this->config['table_prefix']."page ".
1233          "WHERE supertag IN (".$spages_str.")", 1))
1234          {
1235              for ($i = 0; $i < count($links); $i++)
1236              {
1237                  $this->cache_page($links[$i], 0, 1);
1238                  $exists[] = $links[$i]['supertag'];
1239              }
1240          }
1241  
1242          $notexists = @array_values(@array_diff($spages, $exists));
1243  
1244          for ($i = 0; $i < count($notexists); $i++)
1245          {
1246              $this->cache_wanted_page($pages[array_search($notexists[$i], $spages)], 0, 1);
1247              $this->cache_acl($this->get_page_id($notexists[$i]), 'read', 1, $acl);
1248          }
1249  
1250          if ($read_acls = $this->load_all(
1251          "SELECT a.* FROM ".$this->config['table_prefix']."acl a ".
1252              "INNER JOIN ".$this->config['table_prefix']."page p ON (p.page_id = a.page_id) ".
1253          "WHERE BINARY p.tag IN (".$pages_str.") AND a.privilege = 'read'", 1))
1254          {
1255              for ($i = 0; $i < count($read_acls); $i++)
1256              {
1257                  $this->cache_acl($read_acls[$i]['page_id'], 'read', 1, $read_acls[$i]);
1258              }
1259          }
1260      }
1261  
1262  	function set_page($page)
1263      {
1264          $lang_list    = $this->available_languages();
1265          $this->page    = $page;
1266  
1267          if ($this->page['tag'])
1268          {
1269              $this->tag = $this->page['tag'];
1270          }
1271  
1272          if ($page['lang'])
1273          {
1274              $this->page_lang = $page['lang'];
1275          }
1276          else if (isset($_REQUEST['add']) && isset($_REQUEST['lang']) && in_array($_REQUEST['lang'], $lang_list))
1277          {
1278              $this->page_lang = $_REQUEST['lang'];
1279          }
1280          else if (isset($_REQUEST['add']))
1281          {
1282              $this->page_lang = $this->user_lang;
1283          }
1284          else
1285          {
1286              $this->page_lang = $this->config['language'];
1287          }
1288      }
1289  
1290      // STANDARD QUERIES
1291  	function load_revisions($page_id, $minor_edit = '', $deleted = 0)
1292      {
1293          $page_meta = 'p.page_id, p.owner_id, p.user_id, p.tag, p.supertag, p.modified, p.edit_note, p.minor_edit, p.reviewed, p.latest, p.comment_on_id, p.title, u.user_name, o.user_name as reviewer ';
1294  
1295          $revisions = $this->load_all(
1296              "SELECT p.revision_id AS revision_m_id, ".$page_meta." ".
1297              "FROM ".$this->config['table_prefix']."revision p ".
1298                  "LEFT JOIN ".$this->config['table_prefix']."user u ON (p.user_id = u.user_id) ".
1299                  "LEFT JOIN ".$this->config['table_prefix']."user o ON (p.reviewer_id = o.user_id) ".
1300              "WHERE p.page_id = '".quote($this->dblink, $page_id)."' ".
1301                  ($minor_edit
1302                      ? "AND p.minor_edit = '0' "
1303                      : "").
1304                  ($deleted != 1
1305                      ? "AND p.deleted <> '1' "
1306                      : "").
1307              "ORDER BY p.modified DESC");
1308  
1309          if ($revisions == true)
1310          {
1311              if ($cur = $this->load_single(
1312                  "SELECT p.page_id AS revision_m_id, ".$page_meta." ".
1313                  "FROM ".$this->config['table_prefix']."page p ".
1314                      "LEFT JOIN ".$this->config['table_prefix']."user u ON (p.user_id = u.user_id) ".
1315                      "LEFT JOIN ".$this->config['table_prefix']."user o ON (p.reviewer_id = o.user_id) ".
1316                  "WHERE p.page_id = '".quote($this->dblink, $page_id)."' ".
1317                      ($minor_edit
1318                          ? "AND p.minor_edit = '0' "
1319                          : "").
1320                      ($deleted != 1
1321                          ? "AND p.deleted <> '1' "
1322                          : "").
1323                  "ORDER BY p.modified DESC ".
1324                  "LIMIT 1"))
1325              {
1326                  array_unshift($revisions, $cur);
1327              }
1328          }
1329          else
1330          {
1331              $revisions = $this->load_all(
1332                  "SELECT p.page_id AS revision_m_id, ".$page_meta." ".
1333                  "FROM ".$this->config['table_prefix']."page p ".
1334                      "LEFT JOIN ".$this->config['table_prefix']."user u ON (p.user_id = u.user_id) ".
1335                      "LEFT JOIN ".$this->config['table_prefix']."user o ON (p.reviewer_id = o.user_id) ".
1336                  "WHERE p.page_id = '".quote($this->dblink, $page_id)."' ".
1337                      ($deleted != 1
1338                          ? "AND p.deleted <> '1' "
1339                          : "").
1340                  "ORDER BY p.modified DESC ".
1341                  "LIMIT 1");
1342          }
1343  
1344          return $revisions;
1345      }
1346  
1347  	function load_pages_linking_to($tag, $for = '')
1348      {
1349          return $this->load_all(
1350              "SELECT p.page_id, p.tag AS tag, p.title ".
1351              "FROM ".$this->config['table_prefix']."link l ".
1352                  "INNER JOIN ".$this->config['table_prefix']."page p ON (p.page_id = l.from_page_id) ".
1353              "WHERE ".($for
1354                  ? "p.tag LIKE '".quote($this->dblink, $for)."/%' AND "
1355                  : "").
1356                  "(l.to_supertag = '".quote($this->dblink, $this->translit($tag))."')".
1357              " ORDER BY tag", 1);
1358      }
1359  
1360  	function load_recently_changed($limit = 100, $for = '', $from = '', $minor_edit = '', $default_pages = false, $deleted = 0)
1361      {
1362          $limit = (int)$limit;
1363  
1364          // count pages
1365          $count_pages = $this->load_all(
1366              "SELECT p.page_id, u.user_name ".
1367              "FROM ".$this->config['table_prefix']."page p ".
1368                  "LEFT JOIN ".$this->config['table_prefix']."user u ON (p.user_id = u.user_id) ".
1369              "WHERE p.comment_on_id = '0' ".
1370                  ($from
1371                      ? "AND p.modified <= '".quote($this->dblink, $from)." 23:59:59'"
1372                      : "").
1373                  ($for
1374                      ? "AND p.supertag LIKE '".quote($this->dblink, $this->translit($for))."/%' "
1375                      : "").
1376                  ($minor_edit
1377                      ? "AND p.minor_edit = '0' "
1378                      : "").
1379                  ($deleted != 1
1380                      ? "AND p.deleted <> '1' "
1381                      : "").
1382                  ($default_pages == false
1383                      ? "AND (u.account_type = '0' OR p.user_id = '0') "
1384                      : "")
1385              );
1386  
1387          $count        = count($count_pages);
1388          $pagination = $this->pagination($count, $limit);
1389  
1390          if ($pages = $this->load_all(
1391          "SELECT p.page_id, p.owner_id, p.tag, p.supertag, p.title, p.created, p.modified, p.edit_note, p.minor_edit, p.reviewed, p.latest, p.handler, p.comment_on_id, p.lang, u.user_name ".
1392          "FROM ".$this->config['table_prefix']."page p ".
1393              "LEFT JOIN ".$this->config['table_prefix']."user u ON (p.user_id = u.user_id) ".
1394          "WHERE p.comment_on_id = '0' ".
1395              ($from
1396                  ? "AND p.modified <= '".quote($this->dblink, $from)." 23:59:59'"
1397                  : "").
1398              ($for
1399                  ? "AND p.supertag LIKE '".quote($this->dblink, $this->translit($for))."/%' "
1400                  : "").
1401              ($minor_edit
1402                  ? "AND p.minor_edit = '0' "
1403                  : "").
1404              ($deleted != 1
1405                  ? "AND p.deleted <> '1' "
1406                  : "").
1407              ($default_pages == false
1408                  ? "AND (u.account_type = '0' OR p.user_id = '0') "
1409                  : "").
1410          "ORDER BY p.modified DESC ".
1411          "LIMIT {$pagination['offset']}, {$limit}", 1))
1412          {
1413              foreach ($pages as $page)
1414              {
1415                  $this->cache_page($page, 0, 1);
1416              }
1417  
1418              if ($read_acls = $this->load_all(
1419              "SELECT a.* ".
1420              "FROM ".$this->config['table_prefix']."acl a ".
1421                  "INNER JOIN ".$this->config['table_prefix']."page p ON (a.page_id = p.page_id) ".
1422              "WHERE p.comment_on_id = '0' ".
1423                  "AND a.page_id = p.page_id ".
1424                  ($for
1425                      ? "AND p.supertag LIKE '".quote($this->dblink, $this->translit($for))."/%' "
1426                      : '').
1427              "AND a.privilege = 'read' ".
1428              "ORDER BY modified DESC ".
1429              "LIMIT {$limit}", 1))
1430              {
1431                  for ($i = 0; $i < count($read_acls); $i++)
1432                  {
1433                      $this->cache_acl($read_acls[$i]['page_id'], 'read', 1,$read_acls[$i]);
1434                  }
1435              }
1436  
1437              return array($pages, $pagination);
1438          }
1439      }
1440  
1441  	function load_recently_comment($limit = 100, $for = '', $deleted = 0)
1442      {
1443          $limit = (int) $limit;
1444  
1445          if ($pages = $this->load_all(
1446          "SELECT c.page_id, c.owner_id, c.tag, c.supertag, c.title, c.created, c.modified, c.edit_note, c.minor_edit, c.latest, c.handler, c.comment_on_id, c.lang, c.body_r, u.user_name, p.title AS page_title, p.tag AS page_tag ".
1447          "FROM ".$this->config['table_prefix']."page c ".
1448              "LEFT JOIN ".$this->config['table_prefix']."user u ON (c.user_id = u.user_id) ".
1449              "LEFT JOIN ".$this->config['table_prefix']."page p ON (c.comment_on_id = p.page_id) ".
1450          "WHERE c.comment_on_id <> '0' ".
1451              ($for
1452                  ? "AND p.supertag LIKE '".quote($this->dblink, $this->translit($for))."/%' "
1453                  : "").
1454              ($deleted != 1
1455                  ? "AND p.deleted <> '1' "
1456                  : "").
1457          "ORDER BY c.modified DESC ".
1458          "LIMIT ".$limit))
1459          {
1460              #$count        = count($pages['page_id']);
1461              #$pagination = $this->pagination($count, $limit);
1462  
1463              foreach ($pages as $page)
1464              {
1465                  $this->cache_page($page, 0, 1);
1466              }
1467  
1468              if ($read_acls = $this->load_all(
1469              "SELECT a.* ".
1470              "FROM ".$this->config['table_prefix']."acl a ".
1471                  "INNER JOIN ".$this->config['table_prefix']."page p ON (a.page_id = p.page_id) ".
1472              "WHERE p.comment_on_id = '0' ".
1473                  "AND a.page_id = p.page_id ".
1474                      ($for
1475                          ? "AND p.supertag LIKE '".quote($this->dblink, $this->translit($for))."/%' "
1476                          : "").
1477                  "AND a.privilege = 'read' ".
1478              "ORDER BY modified DESC ".
1479              "LIMIT {$limit}"))
1480              {
1481                  for ($i = 0; $i < count($read_acls); $i++)
1482                  {
1483                      $this->cache_acl($read_acls[$i]['page_id'], 'read', 1, $read_acls[$i]);
1484                  }
1485              }
1486  
1487              return $pages;
1488          }
1489      }
1490  
1491  	function load_recently_deleted($limit = 1000, $cache = 1)
1492      {
1493          $meta = 'p.page_id, p.owner_id, p.user_id, p.tag, p.supertag, p.created, p.modified, p.edit_note, p.minor_edit, p.latest, p.handler, p.comment_on_id, p.lang, p.title, p.keywords, p.description';
1494  
1495          return $this->load_all(
1496              "SELECT {$meta} ".
1497              "FROM {$this->config['table_prefix']}page p ".
1498              "WHERE p.deleted = '1' ".
1499              "ORDER BY p.modified DESC, p.tag ASC ".
1500              ( $limit > 0
1501                  ? "LIMIT $limit"
1502                  : ''
1503              ), $cache);
1504      }
1505  
1506  	function load_categories($tag, $page_id = 0)
1507      {
1508          $categories = $this->load_all(
1509              "SELECT c.category_id, c.category ".
1510              "FROM {$this->config['table_prefix']}category c ".
1511                  "INNER JOIN {$this->config['table_prefix']}category_page cp ON (c.category_id = cp.category_id) ".
1512              "WHERE ".( $page_id != 0
1513                  ? "cp.page_id  = '".quote($this->dblink, $page_id)."' "
1514                  : "cp.supertag = '".quote($this->dblink, $supertag)."' " )
1515              );
1516  
1517          return $categories;
1518      }
1519  
1520  	function get_parent_list()
1521      {}
1522  
1523  	function get_sibling_list()
1524      {}
1525  
1526  	function get_child_list()
1527      {}
1528  
1529  	function bad_words($text)
1530      {
1531          /*
1532          ANTISPAM
1533  
1534          We load in the external antispam.conf file and then search the entire body content for each of the
1535          words defined as spam.  If we find any then we return from the function, not saving the changes.
1536          See bug#188 - Enhanced Spam filtering
1537          */
1538          $this->spam = file('config/antispam.conf', 1);
1539  
1540          if ($this->config['spam_filter'] && is_array($this->spam))
1541          {
1542              foreach ($this->spam as $spam)
1543              {
1544                  if (strpos($text, trim($spam))!== false)
1545                  {
1546                      $this->set_message('Error: Identified Potential Spam: '.$spam) ; // TODO: localize
1547                      return true;
1548                  }
1549              }
1550          }
1551      }
1552  
1553      // MAILER
1554      // $email_to            - recipient address
1555      // $subject, $message    - self-explaining
1556      // $email_from            - place specific address into the 'From:' field
1557      // $charset                - send message in specific charset (w/o actual re-encoding)
1558      // $xtra_headers        - (array) insert additional mail headers
1559      // $supress_tls            - don't change all http links to https links in the message body
1560  	function send_mail($email_to, $subject, $body, $email_from = '', $charset = '', $xtra_headers = '', $supress_tls = false)
1561      {
1562          if ($this->config['enable_email'] == false || ( !$email_to || !$subject || !$body) )
1563          {
1564              return;
1565          }
1566  
1567          if (empty($charset))
1568          {
1569              $charset = $this->get_charset();
1570          }
1571  
1572          $name_to        = '';
1573          $email_from        = $this->config['admin_email'];
1574          $name_from        = $this->config['email_from'];
1575  
1576          // in tls mode substitute protocol name in links substrings
1577          if ($this->config['tls'] == true && $supress_tls === false)
1578          {
1579              $body = str_replace('http://', 'https://'.($this->config['tls_proxy'] ? $this->config['tls_proxy'].'/' : ''), $body);
1580          }
1581  
1582          // use phpmailer class
1583          if ($this->config['phpmailer'] == true)
1584          {
1585              // $this->config['phpMailer_method']
1586              $this->use_class('email');
1587              $email = new email($this);
1588              $email->php_mailer($email_to, $name_to, $email_from, $name_from, $subject, $body, $charset, $xtra_headers);
1589          }
1590          else
1591          {
1592              // use mail() function
1593              $headers = 'From: =?'. $charset ."?B?". base64_encode($this->config['site_name']) ."?= <".$this->config['admin_email'].">\r\n";
1594              $headers .= "X-Mailer: PHP/".phpversion()."\r\n"; //mailer
1595              $headers .= "X-Priority: 3\r\n"; //1 UrgentMessage, 3 Normal
1596              $headers .= "X-Wacko: ".$this->config['base_url']."\r\n";
1597              $headers .= "Content-Type: text/plain; charset=".$charset."\r\n";
1598              $headers .= ( is_array($xtra_headers) ? implode("\n", $xtra_headers)."\n" : '' );    // additional headers
1599              $subject = ($subject ? "=?".$charset."?B?" . base64_encode($subject) . "?=" : '');
1600  
1601              $body = wordwrap($body, 74, "\n", 0);
1602              @mail($email_to, $subject, $body, $headers);
1603          }
1604      }
1605  
1606      // PAGE SAVING ROUTINE
1607      // $tag                - page address
1608      // $title            - page name (metadata)
1609      // $body            - page body (plain text)
1610      // $edit_note        - edit summary
1611      // $minor_edit        - minor edit
1612      // $comment_on_id    - commented page id
1613      // $lang            - page language
1614      // $mute            - supress email reminders and xml rss recompilation
1615      // $user_name        - attach guest pseudonym
1616      // $user_page        - user is page owner
1617  	function save_page($tag, $title = '', $body, $edit_note = '', $minor_edit = 0, $reviewed = 0, $comment_on_id = 0, $lang = '', $mute = false, $user_name = false, $user_page = false)
1618      {
1619          $desc = '';
1620          // user data
1621          $ip = $this->get_user_ip();
1622  
1623          if ($user_name == '')
1624          {
1625              $user_name = GUEST;
1626          }
1627  
1628          if ($user_name && $user_name != GUEST)
1629          {
1630              $owner_id    = $user_id    = $this->get_user_id($user_name);
1631              $reg        = true;
1632          }
1633          // current user is owner; if user is logged in! otherwise, no owner.
1634          else if ($this->get_user_name())
1635          {
1636              $user_name    = $this->get_user_name();
1637              $owner_id    = $user_id    = $this->get_user_id();
1638              $reg        = true;
1639          }
1640          else if ($this->forum === true || $comment_on_id)
1641          {
1642              $owner_id    = 0; // GUEST
1643              $reg        = false;
1644          }
1645          else
1646          {
1647              $owner_id    = 0;
1648              $reg        = false;
1649          }
1650  
1651          $page_id = $this->get_page_id($tag);
1652  
1653  
1654          //    Check for bad words.  If we find any then we return from the function, not saving the changes. See bug#188 - Enhanced Spam filtering
1655          if ($this->bad_words($body))
1656          {
1657              return;
1658          }
1659  
1660  
1661          // write tag
1662          if(isset($_POST['tag']))
1663          {
1664              $this->tag        = $tag = $_POST['tag'];
1665              $this->supertag    = $this->translit($tag);
1666          }
1667  
1668          if (!$this->translit($tag))
1669          {
1670              return;
1671          }
1672  
1673          // cache handling
1674          if ($this->config['cache'])
1675          {
1676              // page cache
1677              if ($comment_on_id)
1678              {
1679                  $this->cache->invalidate_page_cache($this->get_page_tag($comment_on_id));
1680              }
1681              else
1682              {
1683                  $this->cache->invalidate_page_cache($this->tag);
1684                  $this->cache->invalidate_page_cache($this->supertag);
1685              }
1686  
1687              // SQL queries cache
1688              if ($this->config['cache_sql'])
1689              {
1690                  $this->cache->invalidate_sql_cache();
1691              }
1692          }
1693  
1694          // check privileges
1695          if ( ($this->page && $this->has_access('write', $page_id))
1696              || (!$this->page && $this->has_access('create', '', $user_name)) // TODO: (!$this->page && $this->has_access('create', $tag))
1697              || ($comment_on_id && $this->has_access('comment', $comment_on_id))
1698              || $user_page == true)
1699          {
1700              // for forum topic prepare description
1701              if (!$comment_on_id && $this->forum)
1702              {
1703                  $desc = $this->format(substr($body, 0, 500), 'cleanwacko');
1704                  $desc = (strlen($desc) > 240 ? substr($desc, 0, 240).'[..]' : $desc.' [..]');
1705              }
1706  
1707              // preformatter (macros and such)
1708              $body = $this->format($body, 'pre_wacko');
1709  
1710              // making page body components
1711              $body_r = $this->format($body, 'wacko');
1712  
1713              if ($this->config['paragrafica'] && !$comment_on_id)
1714              {
1715                  $body_r        = $this->format($body_r, 'paragrafica');
1716                  $body_toc    = $this->body_toc;
1717              }
1718  
1719              // review
1720              if (isset($reviewed))
1721              {
1722                  $reviewer_id    = $user_id;
1723              }
1724  
1725              // PAGE DOESN'T EXISTS, SAVING A NEW PAGE
1726              if (!$old_page = $this->load_page('', $page_id))
1727              {
1728                  if (empty($lang))
1729                  {
1730                      $lang_list = $this->available_languages();
1731  
1732                      if ($_REQUEST['lang'] && in_array($_REQUEST['lang'], $lang_list))
1733                      {
1734                          $lang = $_REQUEST['lang'];
1735                      }
1736                      else
1737                      {
1738                          $lang = $this->user_lang;
1739                      }
1740                  }
1741  
1742                  if (!$lang)
1743                  {
1744                      $lang = $this->config['language'];
1745                  }
1746  
1747                  $this->set_language($lang);
1748  
1749                  // getting title
1750                  if ($title == '')
1751                  {
1752                      if ($comment_on_id == true)
1753                      {
1754                          $title = $this->get_translation('Comment').' '.substr($tag, 7);
1755                      }
1756                      else
1757                      {
1758                          $title = $this->get_page_title($tag);
1759                      }
1760                  }
1761  
1762                  // create appropriate acls
1763                  if (strstr($this->context[$this->current_context], '/') && !$comment_on_id)
1764                  {
1765                      $root            = preg_replace( '/^(.*)\\/([^\\/]+)$/', '$1', $this->context[$this->current_context] );
1766                      $root_id        = $this->get_page_id($root);
1767                      $write_acl        = $this->load_acl($this->get_page_id($root), 'write');
1768  
1769                      while ($write_acl['default'] == 1)
1770                      {
1771                          $_root        = $root;
1772                          $root        = preg_replace( '/^(.*)\\/([^\\/]+)$/', '$1', $root );
1773  
1774                          if ($root == $_root)
1775                          {
1776                              break;
1777                          }
1778  
1779                          $root_id    = $this->get_page_id($root); // do we need this?
1780                          $write_acl    = $this->load_acl($root_id, 'write');
1781                      }
1782  
1783                      $write_acl        = $write_acl['list'];
1784                      $read_acl        = $this->load_acl($root_id, 'read');
1785                      $read_acl        = $read_acl['list'];
1786                      $comment_acl    = $this->load_acl($root_id, 'comment');
1787                      $comment_acl    = $comment_acl['list'];
1788                      $create_acl        = $this->load_acl($root_id, 'create');
1789                      $create_acl        = $create_acl['list'];
1790                      $upload_acl        = $this->load_acl($root_id, 'upload');
1791                      $upload_acl        = $upload_acl['list'];
1792  
1793                      // forum topic privileges
1794                      if ($this->forum === true)
1795                      {
1796                          $write_acl        = '';
1797                          $comment_acl    = '*';
1798                          $create_acl        = '';
1799                          $upload_acl        = '';
1800                      }
1801                  }
1802                  else if ($comment_on_id)
1803                  {
1804                      // Give comments the same read rights as their parent page
1805                      $read_acl        = $this->load_acl($comment_on_id, 'read');
1806                      $read_acl        = $read_acl['list'];
1807                      $write_acl        = '';
1808                      $comment_acl    = '';
1809                      $create_acl        = '';
1810                      $upload_acl        = '';
1811                  }
1812                  else
1813                  {
1814                      $read_acl        = $this->config['default_read_acl'];
1815                      $write_acl        = $this->config['default_write_acl'];
1816                      $comment_acl    = $this->config['default_comment_acl'];
1817                      $create_acl        = $this->config['default_create_acl'];
1818                      $upload_acl        = $this->config['default_upload_acl'];
1819                  }
1820  
1821                  // determine the depth
1822                  $_depth_array    = explode('/', $tag);
1823                  $depth            = count($_depth_array);
1824  
1825                  $this->sql_query(
1826                      "INSERT INTO ".$this->config['table_prefix']."page SET ".
1827                          "comment_on_id     = '".quote($this->dblink, $comment_on_id)."', ".
1828                          (!$comment_on_id ? "description = '".quote($this->dblink, $desc)."', " : "").
1829                          "created        = NOW(), ".
1830                          "modified        = NOW(), ".
1831                          "commented        = NOW(), ".
1832                          "depth            = '".quote($this->dblink, $depth)."', ".
1833                          "owner_id        = '".quote($this->dblink, $owner_id)."', ".
1834                          "user_id        = '".quote($this->dblink, $user_id)."', ".
1835                          "ip                = '".quote($this->dblink, $ip)."', ".
1836                          "latest            = '1', ".
1837                          "tag            = '".quote($this->dblink, $tag)."', ".
1838                          "supertag        = '".quote($this->dblink, $this->translit($tag))."', ".
1839                          "body            = '".quote($this->dblink, $body)."', ".
1840                          "body_r            = '".quote($this->dblink, $body_r)."', ".
1841                          "body_toc        = '".quote($this->dblink, $body_toc)."', ".
1842                          "edit_note        = '".quote($this->dblink, $edit_note)."', ".
1843                          "minor_edit        = '".quote($this->dblink, $minor_edit)."', ".
1844                          (isset($reviewed)
1845                              ?    "reviewed        = '".quote($this->dblink, $reviewed)."', ".
1846                                  "reviewed_time    = NOW(), ".
1847                                  "reviewer_id    = '".quote($this->dblink, $reviewer_id)."', "
1848                              :    "").
1849                          "lang            = '".quote($this->dblink, $lang)."', ".
1850                          "title            = '".quote($this->dblink, $title)."'");
1851  
1852                  // IMPORTANT! lookup newly created page_id
1853                  $page_id = $this->get_page_id($tag);
1854  
1855                  // saving acls
1856                  $this->save_acl($page_id, 'write',        $write_acl);
1857                  $this->save_acl($page_id, 'read',        $read_acl);
1858                  $this->save_acl($page_id, 'comment',    $comment_acl);
1859                  $this->save_acl($page_id, 'create',        $create_acl);
1860                  $this->save_acl($page_id, 'upload',        $upload_acl);
1861  
1862                  // counters
1863                  if ($comment_on_id)
1864                  {
1865                      // updating comments count for commented page
1866                      $this->sql_query(
1867                          "UPDATE {$this->config['table_prefix']}page SET ".
1868                              "comments    = '".(int)$this->count_comments($comment_on_id)."', ".
1869                              "commented    = NOW() ".
1870                          "WHERE page_id = '".quote($this->dblink, $comment_on_id)."' ".
1871                          "LIMIT 1");
1872  
1873                      // update user comments count
1874                      $this->sql_query(
1875                          "UPDATE {$this->config['user_table']} ".
1876                          "SET total_comments = total_comments + 1 ".
1877                          "WHERE user_id = '".quote($this->dblink, $owner_id)."' ".
1878                          "LIMIT 1");
1879                  }
1880                  else
1881                  {
1882                      // update user pages count
1883                      $this->sql_query(
1884                          "UPDATE {$this->config['user_table']} ".
1885                          "SET total_pages = total_pages + 1 ".
1886                          "WHERE user_id = '".quote($this->dblink, $owner_id)."' ".
1887                          "LIMIT 1");
1888                  }
1889  
1890                  // set watch
1891                  if (!$this->config['disable_autosubscribe'] && !$comment_on_id)
1892                  {
1893                      // subscribe the author
1894                      if ($reg === true)
1895                      {
1896                          $this->set_watch($user_id, $page_id);
1897                      }
1898  
1899                      // subscribe & notify moderators
1900                      if (is_array($this->config['aliases']))
1901                      {
1902                          $list        = $this->config['aliases'];
1903                          $moderators    = explode("\n", $list['Moderator']);
1904  
1905                          if (!$mute) foreach ($moderators as $moderator)
1906                          {
1907                              if ($user_name != $moderator)
1908                              {
1909                                  $moderator_id = $this->get_user_id($moderator);
1910  
1911                                  $_user = $this->load_single(
1912                                      "SELECT u.email, p.lang, u.email_confirm, u.enabled, p.send_watchmail ".
1913                                      "FROM " .$this->config['user_table']." u ".
1914                                          "LEFT JOIN ".$this->config['table_prefix']."user_setting p ON (u.user_id = p.user_id) ".
1915                                      "WHERE u.user_id = '".quote($this->dblink, $moderator_id)."' ".
1916                                      "LIMIT 1");
1917  
1918                                  if ($this->config['enable_email'] == true && $this->config['enable_email_notification'] == true && $_user['enabled'] == true && $_user['email_confirm'] == '' && $_user['send_watchmail'] != 0)
1919                                  {
1920                                      $subject = $this->config['site_name'].'. '.$this->get_translation('NewPageCreatedSubj')." '$title'";
1921                                      $body = $this->get_translation('EmailHello'). $this->get_translation('EmailModerator').$moderator.".\n\n".
1922                                              str_replace('%1', ( $user_name == GUEST ? $this->get_translation('Guest') : $user_name ), $this->get_translation('NewPageCreatedBody'))."\n".
1923                                              "'$title'\n".
1924                                              $this->href('', $tag)."\n\n".
1925                                              $this->get_translation('EmailGoodbye')."\n".
1926                                              $this->config['site_name']."\n".
1927                                              $this->config['base_url'];
1928  
1929                                      $this->send_mail($_user['email'], $subject, $body);
1930                                      $this->set_watch($moderator_id, $page_id);
1931                                  }
1932                              }
1933                          }
1934  
1935                          unset($list, $moderators, $moderator, $moderator_id);
1936                      }
1937                  }
1938  
1939                  if ($comment_on_id)
1940                  {
1941                      // notifying watchers
1942                      $title        = $this->get_page_title(0, $comment_on_id);
1943                      $watchers    = $this->load_all(
1944                                      "SELECT DISTINCT w.user_id, u.user_name ".
1945                                      "FROM ".$this->config['table_prefix']."watch w ".
1946                                          "LEFT JOIN ".$this->config['table_prefix']."user u ON (w.user_id = u.user_id) ".
1947                                      "WHERE w.page_id = '".quote($this->dblink, $comment_on_id)."'");
1948  
1949                      if ($watchers && !$mute)
1950                      {
1951                          foreach ($watchers as $watcher)
1952                          {
1953                              if ($watcher['user_id'] != $user_id && $watcher['user_name'] != GUEST)
1954                              {
1955                                  // assert that user has no comments pending...
1956                                  $pending = $this->load_single(
1957                                      "SELECT comment_id ".
1958                                      "FROM {$this->config['table_prefix']}watch ".
1959                                      "WHERE page_id = '".quote($this->dblink, $comment_on_id)."' ".
1960                                          "AND user_id = '".quote($this->dblink, $watcher['user_id'])."' ".
1961                                      "LIMIT 1");
1962  
1963                                  // ...and add one if so
1964                                  if ($pending['comment_id'] == false)
1965                                  {
1966                                      $this->sql_query(
1967                                          "UPDATE {$this->config['table_prefix']}watch ".
1968                                          "SET comment_id = '".quote($this->dblink, $page_id)."' ".
1969                                          "WHERE page_id = '".quote($this->dblink, $comment_on_id)."' ".
1970                                              "AND user_id = '".quote($this->dblink, $watcher['user_id'])."'");
1971                                  }
1972                                  else
1973                                  {
1974                                      continue;    // skip current watcher
1975                                  }
1976  
1977                                  if ($this->has_access('read', $comment_on_id, $watcher['user_name']))
1978                                  {
1979                                      $_user = $this->load_single(
1980                                          "SELECT u.email, p.lang, u.email_confirm, u.enabled, p.send_watchmail ".
1981                                          "FROM " .$this->config['user_table']." u ".
1982                                              "LEFT JOIN ".$this->config['table_prefix']."user_setting p ON (u.user_id = p.user_id) ".
1983                                          "WHERE u.user_id = '".quote($this->dblink, $watcher['user_id'])."' ".
1984                                          "LIMIT 1");
1985  
1986                                      if ($this->config['enable_email'] == true && $this->config['enable_email_notification'] == true && $_user['enabled'] == true && $_user['email_confirm'] == '' && $_user['send_watchmail'] != 0)
1987                                      {
1988                                          $lang = $_user['lang'];
1989                                          $this->load_translation($lang);
1990                                          $this->set_translation ($lang);
1991                                          $this->set_language ($lang);
1992  
1993                                          $subject = '['.$this->config['site_name'].'] '.$this->get_translation('CommentForWatchedPage', $lang)."'".$title."'";
1994                                          $body = $this->get_translation('EmailHello', $lang). $watcher['user_name'].",\n\n".
1995                                                  ($user_name == GUEST ? $this->get_translation('Guest') : $user_name).
1996                                                  $this->get_translation('SomeoneCommented', $lang)."\n".
1997                                                  $this->href('', $this->get_page_tag($comment_on_id), '')."\n\n".
1998                                                  "----------------------------------------------------------------------\n\n".
1999                                                  $body."\n\n".
2000                                                  "----------------------------------------------------------------------\n\n".
2001                                                  $this->get_translation('EmailGoodbye', $lang)."\n".
2002                                                  $this->config['site_name']."\n".
2003                                                  $this->config['base_url'];
2004  
2005                                          $this->send_mail($_user['email'], $subject, $body);
2006                                      }
2007                                  }
2008                                  else
2009                                  {
2010                                      $this->clear_watch($watcher['user_id'], $comment_on_id);
2011                                  } // end of has_access
2012                              }
2013                          }// end of watchers
2014                      }
2015  
2016                      $this->load_translation($this->user_lang);
2017                      $this->set_translation($this->user_lang);
2018                      $this->set_language($this->user_lang);
2019                  } // end of comment_on
2020              } // end of new page
2021              // RESAVING AN OLD PAGE, CREATING REVISION
2022              else
2023              {
2024                  $this->set_language($this->page_lang);
2025  
2026                  // aha! page isn't new. keep owner!
2027                  $owner_id = $old_page['owner_id'];
2028  
2029                  // only if page has been actually changed
2030                  if ($old_page['body'] != $body || $old_page['title'] != $title)
2031                  {
2032                      // Dont save revisions for comments.  Personally I think we should.
2033                      if (!$old_page['comment_on_id'])
2034                      {
2035                          $this->save_revision($old_page);
2036                      }
2037  
2038                      // update current page copy
2039                      $this->sql_query(
2040                          "UPDATE ".$this->config['table_prefix']."page SET ".
2041                              "comment_on_id    = '".quote($this->dblink, $comment_on_id)."', ".
2042                              "modified        = NOW(), ".
2043                              "created        = '".quote($this->dblink, $old_page['created'])."', ".
2044                              "owner_id        = '".quote($this->dblink, $owner_id)."', ".
2045                              "user_id        = '".quote($this->dblink, $user_id)."', ".
2046                              "latest            = '2', ".
2047                              "description    = '".quote($this->dblink, ($old_page['comment_on_id'] || $old_page['description'] ? $old_page['description'] : $desc ))."', ".
2048                              "supertag        = '".quote($this->dblink, $this->translit($tag))."', ".
2049                              "body            = '".quote($this->dblink, $body)."', ".
2050                              "body_r            = '".quote($this->dblink, $body_r)."', ".
2051                              "body_toc        = '".quote($this->dblink, $body_toc)."', ".
2052                              "edit_note        = '".quote($this->dblink, $edit_note)."', ".
2053                              "minor_edit        = '".quote($this->dblink, $minor_edit)."', ".
2054                              (isset($reviewed)
2055                                  ?    "reviewed        = '".quote($this->dblink, $reviewed)."', ".
2056                                      "reviewed_time    = NOW(), ".
2057                                      "reviewer_id    = '".quote($this->dblink, $reviewer_id)."', "
2058                                  :    "").
2059                              "title            = '".quote($this->dblink, $title)."' ".
2060                          "WHERE tag = '".quote($this->dblink, $tag)."' ".
2061                          "LIMIT 1");
2062                  }
2063  
2064                  // Since there's no revision history for comments it's pointless to do the following for them.
2065                  if (!$comment_on_id)
2066                  {
2067                      // revisions diff
2068                      $page = $this->load_single(
2069                          "SELECT revision_id ".
2070                          "FROM ".$this->config['table_prefix']."revision ".
2071                          "WHERE tag = '".quote($this->dblink, $tag)."' ".
2072                          "ORDER BY modified DESC ".
2073                          "LIMIT 1");
2074  
2075                      $_GET['a']            = -1;
2076                      $_GET['b']            = $page['revision_id'];
2077                      $_GET['diffmode']    = 1;
2078                      $diff                = $this->include_buffered('handlers/page/diff.php', 'oops', array('source' => 1));
2079  
2080                      // notifying watchers
2081                      $title                = $this->get_page_title(0, $page_id);
2082  
2083                      $watchers    = $this->load_all(
2084                          "SELECT DISTINCT w.user_id, u.user_name ".
2085                          "FROM ".$this->config['table_prefix']."watch w ".
2086                              "LEFT JOIN ".$this->config['table_prefix']."user u ON (w.user_id = u.user_id) ".
2087                          "WHERE w.page_id = '".quote($this->dblink, $page_id)."'");
2088  
2089                      if ($watchers && !$mute)
2090                      {
2091                          foreach ($watchers as $watcher)
2092                          {
2093                              if ($watcher['user_id'] !=  $user_id)
2094                              {
2095                                  if ($this->has_access('read', $page_id, $watcher['user_name']))
2096                                  {
2097                                      $_user = $this->load_single(
2098                                          "SELECT u.email, p.lang, u.email_confirm, u.enabled, p.send_watchmail ".
2099                                          "FROM " .$this->config['user_table']." u ".
2100                                              "LEFT JOIN ".$this->config['table_prefix']."user_setting p ON (u.user_id = p.user_id) ".
2101                                          "WHERE u.user_id = '".quote($this->dblink, $watcher['user_id'])."' ".
2102                                          "LIMIT 1");
2103  
2104                                      if ($this->config['enable_email'] == true && $this->config['enable_email_notification'] == true && $_user['enabled'] == true && $_user['email_confirm'] == '' && $_user['send_watchmail'] != 0)
2105                                      {
2106                                          $lang = $_user['lang'];
2107                                          $this->load_translation($lang);
2108                                          $this->set_translation ($lang);
2109                                          $this->set_language ($lang);
2110  
2111                                          $subject = '['.$this->config['site_name'].'] '.$this->get_translation('WatchedPageChanged', $lang)."'".$tag."'";
2112                                          $body = $this->get_translation('EmailHello', $lang). $watcher['user_name'].",\n\n".
2113                                                  ($user_name == GUEST ? $this->get_translation('Guest') : $user_name).
2114                                                  $this->get_translation('SomeoneChangedThisPage', $lang)."\n".
2115                                                  (isset($title) ? $title : $tag)."\n".
2116                                                  $this->href('', $tag)."\n\n".
2117                                                  "======================================================================".
2118                                                  $this->format($diff, 'html2mail').
2119                                                  "\n======================================================================\n\n".
2120                                                  $this->get_translation('EmailGoodbye', $lang)."\n".
2121                                                  $this->config['site_name']."\n".
2122                                                  $this->config['base_url'];
2123  
2124                                          $this->send_mail($_user['email'], $subject, $body);
2125                                      }
2126                                  } // end of has_access()
2127                              } // end of watchers
2128                          }
2129  
2130                          $this->load_translation($this->user_lang);
2131                          $this->set_translation ($this->user_lang);
2132                          $this->set_language ($this->user_lang);
2133                      }
2134                  } // end of new != old
2135              } // end of existing page
2136          }
2137  
2138          // writing xmls
2139          if ($mute === false)
2140          {
2141              if (!isset($old_page['comment_on_id']) || !$comment_on_id)
2142              {
2143                  $this->use_class('rss');
2144                  $xml = new rss($this);
2145  
2146                  if ($this->config['enable_feeds'])
2147                  {
2148                      $xml->changes();
2149                      $xml->comments();
2150  
2151                      if ($this->config['news_cluster'])
2152                      {
2153                          if (substr($this->tag, 0, strlen($this->config['news_cluster'].'/')) == $this->config['news_cluster'].'/')
2154                          {
2155                              $xml->news();
2156                          }
2157                      }
2158                  }
2159  
2160                  // TODO: add time parameter as config value xml_sitemap_ttl
2161                  if($this->config['xml_sitemap'])
2162                  {
2163                      $xml->site_map();
2164                  }
2165  
2166                  unset($xml);
2167              }
2168          }
2169  
2170          return $body_r;
2171      }
2172  
2173      // create revision of a given page
2174  	function save_revision($old_page)
2175      {
2176          if (!$old_page)
2177          {
2178              return false;
2179          }
2180  
2181          // prepare input
2182          foreach ($old_page as $key => $val)
2183          {
2184              $old_page[$key] = quote($this->dblink, $old_page[$key]);
2185          }
2186  
2187          // get new version_id
2188          $_old_version = $this->load_single(
2189              "SELECT version_id ".
2190              "FROM {$this->config['table_prefix']}revision ".
2191              "WHERE page_id = '".quote($this->dblink, $old_page['page_id'])."' ".
2192              "ORDER BY version_id DESC ".
2193              "LIMIT 1");
2194  
2195          $version_id = $_old_version['version_id'] + 1;
2196  
2197          // move revision
2198          $this->sql_query(
2199              "INSERT INTO {$this->config['table_prefix']}revision SET ".
2200                  "page_id        = '{$old_page['page_id']}', ".
2201                  "version_id        = '{$version_id}', ".
2202                  "tag            = '{$old_page['tag']}', ".
2203                  "modified        = '{$old_page['modified']}', ".
2204                  "body            = '{$old_page['body']}', ".
2205                  "formatting        = '{$old_page['formatting']}', ".
2206                  "edit_note        = '{$old_page['edit_note']}', ".
2207                  "minor_edit        = '{$old_page['minor_edit']}', ".
2208                  "reviewed        = '{$old_page['reviewed']}', ".
2209                  "reviewed_time    = '{$old_page['reviewed_time']}', ".
2210                  "reviewer_id    = '{$old_page['reviewer_id']}', ".
2211                  "ip                = '{$old_page['ip']}', ".
2212                  "owner_id        = '{$old_page['owner_id']}', ".
2213                  "user_id        = '{$old_page['user_id']}', ".
2214                  "latest            = '0', ".
2215                  "handler        = '{$old_page['handler']}', ".
2216                  "comment_on_id    = '{$old_page['comment_on_id']}', ".
2217                  "supertag        = '{$old_page['supertag']}', ".
2218                  "title            = '{$old_page['title']}', ".
2219                  "keywords        = '{$old_page['keywords']}', ".
2220                  "description    = '{$old_page['description']}'");
2221  
2222          // update user statistics for revisions made
2223          if ($user = $this->get_user())
2224          {
2225              $this->sql_query(
2226                  "UPDATE {$this->config['user_table']} ".
2227                  "SET total_revisions = total_revisions + 1 ".
2228                  "WHERE user_id = '".quote($this->dblink, $user['user_id'])."' ".
2229                  "LIMIT 1");
2230          }
2231      }
2232  
2233      // COOKIES
2234  	function set_session_cookie($name, $value, $dummy = null, $secure = 0, $httponly = 1)
2235      {
2236          setcookie($this->config['cookie_prefix'].$name.'_'.$this->config['cookie_hash'], $value, 0, $this->config['cookie_path'], '', ( $secure ? true : false ), ( $httponly ? true : false ));
2237          $_COOKIE[$this->config['cookie_prefix'].$name.'_'.$this->config['cookie_hash']] = $value;
2238      }
2239  
2240  	function set_persistent_cookie($name, $value, $days = 0, $secure = 0, $httponly = 1)
2241      {
2242          // set to default if no pediod given
2243          if ($days == 0)
2244          {
2245              $days = $this->config['session_expiration'];
2246          }
2247  
2248          setcookie($this->config['cookie_prefix'].$name.'_'.$this->config['cookie_hash'], $value, time() + $days * 24 * 3600, $this->config['cookie_path'], '', ( $secure ? true : false ), ( $httponly ? true : false ));
2249          $_COOKIE[$this->config['cookie_prefix'].$name.'_'.$this->config['cookie_hash']] = $value;
2250      }
2251  
2252  	function delete_cookie($name, $prefix = true, $postfix = false)
2253      {
2254          ($prefix == true
2255              ? $prefix    = $this->config['cookie_prefix']
2256              : $prefix    = ''
2257          );
2258  
2259          ($postfix == true
2260              ? $cookie_hash    = '_'.$this->config['cookie_hash']
2261              : $cookie_hash    = ''
2262          );
2263  
2264          $cookie_path    = $this->config['cookie_path'];
2265  
2266          setcookie($prefix.$name.$cookie_hash, '', 1, $cookie_path, '');
2267          $_COOKIE[$prefix.$name.$cookie_hash] = '';
2268      }
2269  
2270  	function get_cookie($name)
2271      {
2272          if (isset($_COOKIE[$this->config['cookie_prefix'].$name.'_'.$this->config['cookie_hash']]))
2273          {
2274              return $_COOKIE[$this->config['cookie_prefix'].$name.'_'.$this->config['cookie_hash']];
2275          }
2276      }
2277  
2278      // HTTP/REQUEST/LINK RELATED
2279  	function set_message($message)
2280      {
2281          $_SESSION[$this->config['session_prefix'].'_'.'message'] = $message;
2282      }
2283  
2284  	function get_message()
2285      {
2286          if (isset($_SESSION[$this->config['session_prefix'].'_'.'message']))
2287          {
2288              $message = $_SESSION[$this->config['session_prefix'].'_'.'message'];
2289              // reset message
2290              $_SESSION[$this->config['session_prefix'].'_'.'message'] = '';
2291  
2292              return $message;
2293          }
2294          else
2295          {
2296              return null;
2297          }
2298      }
2299  
2300  	function show_message($message, $type='info')
2301      {
2302          // TODO: filter and sanitize ..
2303          echo '<div class="'.$type.'">'.$message."</div>\n";
2304      }
2305  
2306  	function redirect($url, $permanent = false)
2307      {
2308          if (!headers_sent())
2309          {
2310              // Make sure no &amp;'s are in, this will break the redirect
2311              $url = str_replace('&amp;', '&', $url);
2312  
2313              if ($permanent)
2314              {
2315                  header('HTTP/1.1 301 Moved Permanently');
2316              }
2317  
2318              header('Location: ' . $url);
2319              exit();
2320          }
2321      }
2322  
2323      // Set security headers (frame busting, clickjacking/XSS/CSRF protection)
2324  	function http_security_headers()
2325      {
2326          if ($this->config['enable_security_headers'])
2327          {
2328              if ( !headers_sent() )
2329              {
2330                  #    if (isset($this->config['x_frame_option']))
2331                  header( 'X-Frame-Options: DENY' ); // or SAMEORIGIN
2332                  #    if (isset($this->config['x_csp']))
2333                  header( "X-Content-Security-Policy: allow 'self'; script-src 'self'; options inline-script; img-src *;" );
2334  
2335                  if ( isset( $_SERVER['HTTPS'] ) && ( $_SERVER['HTTPS'] != 'off' ) )
2336                  {
2337                      header( 'Strict-Transport-Security: max-age=7776000' );
2338                  }
2339              }
2340          }
2341      }
2342  
2343  	function no_cache()
2344      {
2345          if ( !headers_sent() )
2346          {
2347              header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');                // Date in the past
2348              header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT');        // always modified
2349              header('Cache-Control: no-store, no-cache, must-revalidate');    // HTTP 1.1
2350              header('Cache-Control: post-check=0, pre-check=0', false);
2351              header('Pragma: no-cache');                                        // HTTP 1.0
2352          }
2353      }
2354  
2355  	function unwrap_link($tag)
2356      {
2357          if ($tag == '/')
2358          {
2359              return '';
2360          }
2361          if ($tag == '!')
2362          {
2363              return $this->context[$this->current_context];
2364          }
2365  
2366          $new_tag = $tag;
2367  
2368          if (isset($this->context[$this->current_context]) && strstr($this->context[$this->current_context], '/'))
2369          {
2370              $root    = preg_replace('/^(.*)\\/([^\\/]+)$/', '$1', $this->context[$this->current_context]);
2371          }
2372          else
2373          {
2374              $root    = '';
2375          }
2376  
2377          if (preg_match('/^\.\/(.*)$/', $tag, $matches))
2378          {
2379              $root    = '';
2380          }
2381          else if (preg_match('/^\/(.*)$/', $tag, $matches))
2382          {
2383              $root        = '';
2384              $new_tag    = $matches[1];
2385          }
2386          else if (preg_match('/^\!\/(.*)$/', $tag, $matches))
2387          {
2388              $root        = $this->context[$this->current_context];
2389              $new_tag    = $matches[1];
2390          }
2391          else if (preg_match('/^\.\.\/(.*)$/', $tag, $matches))
2392          {
2393              $new_tag    = $matches[1];
2394  
2395              if (strstr($root, '/'))
2396              {
2397                  $root    = preg_replace('/^(.*)\\/([^\\/]+)$/', '$1', $root);
2398              }
2399              else
2400              {
2401                  $root    = '';
2402              }
2403          }
2404  
2405          if ($root != '')
2406          {
2407              $new_tag = '/'.$new_tag;
2408          }
2409  
2410          $tag = $root.$new_tag;
2411          $tag = str_replace('//', '/', $tag);
2412  
2413          return $tag;
2414      }
2415  
2416      // returns just PageName[/method].
2417  	function mini_href($method = '', $tag = '', $addpage = 0)
2418      {
2419          if (!$tag = trim($tag))
2420          {
2421              $tag = $this->tag;
2422          }
2423          if (!$addpage)
2424          {
2425              $tag = $this->slim_url($tag);
2426          }
2427          // if (!$addpage)        $tag = $this->translit($tag);
2428  
2429          $tag = trim($tag, '/.');
2430          // $tag = str_replace(array('%2F', '%3F', '%3D'), array('/', '?', '='), rawurlencode($tag));
2431  
2432          return $tag.($method ? '/'.$method : '');
2433      }
2434  
2435      // returns the full url to a page/method.
2436  	function href($method = '', $tag = '', $params = '', $addpage = 0, $anchor = '')
2437      {
2438          $href = $this->config['base_url'].( $this->config['rewrite_mode'] ? '' : '?page=' ).$this->mini_href($method, $tag, $addpage);
2439  
2440          if ($addpage)
2441          {
2442              $params = 'add=1'.($params ? '&amp;'.$params : '');
2443          }
2444  
2445          if ($params)
2446          {
2447              $href .= ($this->config['rewrite_mode'] ? '?' : '&amp;').$params;
2448          }
2449  
2450          if ($anchor)
2451          {
2452              $href .= '#'.$anchor;
2453          }
2454  
2455          return $href;
2456      }
2457  
2458  	function slim_url($text)
2459      {
2460          $text = $this->translit($text, TRAN_DONTCHANGE); // TODO: set config option ?
2461          $text = str_replace('_', "'", $text);
2462  
2463          if ($this->config['urls_underscores'] == 1)
2464          {
2465              $text = preg_replace('/('.$this->language['ALPHANUM'].')('.$this->language['UPPERNUM'].')/', '\\1\\2', $text);
2466              $text = preg_replace('/('.$this->language['UPPERNUM'].')('.$this->language['UPPERNUM'].')/', '\\1\\2', $text);
2467              $text = preg_replace('/('.$this->language['UPPER'].')(?='.$this->language['UPPER'].''.$this->language['UPPERNUM'].')/', '\\1', $text);
2468              $text = preg_replace('/('.$this->language['UPPER'].')(?='.$this->language['UPPER'].'\/)/', '\\1', $text);
2469              $text = preg_replace('/('.$this->language['UPPERNUM'].')('.$this->language['UPPERNUM'].')($|\b)/', '\\1\\2', $text);
2470              $text = preg_replace('/\/('.$this->language['UPPERNUM'].')/', '/\\1', $text);
2471              $text = str_replace('', '_', $text);
2472          }
2473  
2474          return $text;
2475      }
2476  
2477  	function compose_link_to_page($tag, $method = '', $text = '', $track = 1, $title = '')
2478      {
2479          if (!$text)
2480          {
2481              $text = $this->add_spaces($tag);
2482          }
2483  
2484          //$text = htmlentities($text, ENT_COMPAT | ENT_HTML401, HTML_ENTITIES_CHARSET);
2485          if (isset($_SESSION[$this->config['session_prefix'].'_'.'linktracking']) && $track)
2486          {
2487              $this->track_link_to($tag);
2488          }
2489  
2490          return '<a href="'.$this->href($method, $tag).'"'.($title ? ' title="'.$title.'"' : '').'>'.$text.'</a>';
2491      }
2492  
2493      // preparing links to save them to body_r
2494  	function pre_link($tag, $text = '', $track = 1, $imgurl = 0)
2495      {
2496          // if (!$text) $text = $this->add_spaces($tag);
2497  
2498          if (preg_match('/^[\!\.'.$this->language['ALPHANUM_P'].']+$/', $tag))
2499          {
2500              if (isset($_SESSION[$this->config['session_prefix'].'_'.'linktracking']) && $track)
2501              {
2502                  // it's a Wiki link!
2503                  $this->track_link_to($this->unwrap_link( $tag ));
2504              }
2505          }
2506  
2507          $text = str_replace('%20', ' ', urldecode($text));
2508  
2509          if ($imgurl == 1)
2510          {
2511              return '<!--imglink:begin-->'.str_replace(' ', '%20', urldecode($tag)).' =='.$text.'<!--imglink:end-->';
2512          }
2513          else
2514          {
2515              return '<!--link:begin-->'.str_replace(' ', '%20', urldecode($tag))." ==".($this->format_safe ? str_replace('>', "&gt;", str_replace('<', "&lt;", $text)) : $text).'<!--link:end-->';
2516          }
2517      }
2518  
2519  	function link($tag, $method = '', $text = '', $title = '', $track = 1, $safe = 0, $link_lang = '', $anchor_link = 1)
2520      {
2521          $class        = '';
2522          $icon        = '';
2523          $lang        = '';
2524          $desc        = '';
2525          $url        = '';
2526          $img_link    = false;
2527          $text        = str_replace('"', '&quot;', $text);
2528  
2529          if (!$safe)
2530          {
2531              $text = htmlspecialchars($text, ENT_NOQUOTES, HTML_ENTITIES_CHARSET);
2532          }
2533  
2534          if ($link_lang)
2535          {
2536              $this->set_language($link_lang);
2537          }
2538  
2539          if (preg_match('/^[\.\-'.$this->language['ALPHANUM_P'].']+\.(gif|jpg|jpe|jpeg|png)$/i', $text))
2540          {
2541              $img_link = $this->config['base_url'].'/images/'.$text;
2542          }
2543          else if (preg_match('/^(http|https|ftp):\/\/([^\\s\"<>]+)\.(gif|jpg|jpe|jpeg|png)$/i', preg_replace('/<\/?nobr>/', '', $text)))
2544          {
2545              $img_link = $text = preg_replace('/(<|\&lt\;)\/?span( class\=\"nobr\")?(>|\&gt\;)/', '', $text);
2546          }
2547  
2548          if (preg_match('/^(mailto[:])?[^\\s\"<>&\:]+\@[^\\s\"<>&\:]+\.[^\\s\"<>&\:]+$/', $tag, $matches))
2549          {
2550              // this is a valid Email
2551              $url    = (isset($matches[1]) && $matches[1] == 'mailto:' ? $tag : 'mailto:'.$tag);
2552              $title    = $this->get_translation('EmailLink');
2553              $icon    = $this->get_translation('emailicon');
2554              $tpl    = 'email';
2555          }
2556          else if (preg_match('/^(xmpp[:])?[^\\s\"<>&\:]+\@[^\\s\"<>&\:]+\.[^\\s\"<>&\:]+$/', $tag, $matches))
2557          {
2558              // this is a valid XMPP address
2559              $url    = (isset($matches[1]) && $matches[1] == 'xmpp:' ? $tag : 'xmpp:'.$tag);
2560              $title    = $this->get_translation('JabberLink');
2561              $icon    = $this->get_translation('jabbericon');
2562              $tpl    = 'jabber';
2563          }
2564          else if (preg_match('/^#/', $tag))
2565          {
2566              // html-anchor
2567              $url    = $tag;
2568              $tpl    = 'anchor';
2569          }
2570          else if (preg_match('/^(http|https|ftp|file):\/\/([^\\s\"<>]+)\.(gif|jpg|jpe|jpeg|png)$/i', $tag))
2571          {
2572              // external image
2573              $text    = preg_replace('/(<|\&lt\;)\/?span( class\=\"nobr\")?(>|\&gt\;)/', '', $text);
2574  
2575              if ($text == $tag)
2576              {
2577                  return '<img src="'.str_replace('&', '&amp;', str_replace('&amp;', '&', $tag)).'" '.($text ? 'alt="'.$text.'" title="'.$text.'"' : '').' />';
2578              }
2579              else
2580              {
2581                  $url    = str_replace('&', '&amp;', str_replace('&amp;', '&', $tag));
2582                  $title    = $this->get_translation('OuterLink2');
2583                  $icon    = $this->get_translation('outericon');
2584                  $tpl    = 'outerlink';
2585              }
2586          }
2587          else if (preg_match('/^(http|https|ftp|file):\/\/([^\\s\"<>]+)\.(rpm|gz|tgz|zip|rar|exe|doc|xls|ppt|tgz|bz2|7z)$/', $tag))
2588          {
2589              // this is a file link
2590              $url    = str_replace('&', '&amp;', str_replace('&amp;', '&', $tag));
2591              $title    = $this->get_translation('FileLink');
2592              $icon    = $this->get_translation('fileicon');
2593              $tpl    = 'file';
2594          }
2595          else if (preg_match('/^(http|https|ftp|file):\/\/([^\\s\"<>]+)\.(pdf)$/', $tag))
2596          {
2597              // this is a PDF link
2598              $url    = str_replace('&', '&amp;', str_replace('&amp;', '&', $tag));
2599              $title    = $this->get_translation('PDFLink');
2600              $icon    = $this->get_translation('pdficon');
2601              $tpl    = 'file';
2602          }
2603          else if (preg_match('/^(http|https|ftp|file):\/\/([^\\s\"<>]+)\.(rdf)$/', $tag))
2604          {
2605              // this is a RDF link
2606              $url    = str_replace('&', '&amp;', str_replace('&amp;', '&', $tag));
2607              $title    = $this->get_translation('RDFLink');
2608              $icon    = $this->get_translation('rdficon');
2609              $tpl    = 'file';
2610          }
2611          else if (preg_match('/^(http|https|ftp|file|nntp|telnet):\/\/([^\\s\"<>]+)$/', $tag))
2612          {
2613              // this is a valid external URL
2614              $url    = str_replace('&', '&amp;', str_replace('&amp;', '&', $tag));
2615              $tpl    = 'outerlink';
2616  
2617              if (!stristr($tag, $this->config['base_url']))
2618              {
2619                  $title    = $this->get_translation('OuterLink2');
2620                  $icon    = $this->get_translation('outericon');
2621              }
2622          }
2623          else if (preg_match('/^(_?)file:([^\\s\"<>\(\)]+)$/', $tag, $matches))
2624          {
2625              // this is a file:
2626              $noimg    = $matches[1];
2627              $thing    = $matches[2];
2628              $arr    = explode('/', $thing);
2629  
2630              if (count($arr) == 1) // file:some.zip
2631              {
2632                  //try to find in global storage and return if success
2633                  $desc = $this->check_file_exists($thing);
2634  
2635                  if (is_array($desc))
2636                  {
2637                      $title    = $desc['file_description'].' ('.$this->binary_multiples($desc['file_size'], false, true, true).')';
2638                      $alt    = $desc['file_description'];
2639                      $url    = $this->config['base_url'].$this->config['upload_path'].'/'.$thing;
2640  
2641                      if ($desc['file_ext'] == 'pdf')
2642                      {
2643                          $icon    = $this->get_translation('pdficon');
2644                      }
2645                      else if ($desc['file_ext'] == 'txt')
2646                      {
2647                          $icon    = $this->get_translation('texticon');
2648                      }
2649                      else if ($desc['file_ext'] == 'odt')
2650                      {
2651                          $icon    = $this->get_translation('odticon');
2652                      }
2653                      else if ($desc['file_ext'] == 'png' || $desc['file_ext'] == 'gif' || $desc['file_ext'] == 'jpg')
2654                      {
2655                          $icon    = $this->get_translation('imageicon');
2656                      }
2657                      else
2658                      {
2659                          $icon    = $this->get_translation('fileicon');
2660                      }
2661  
2662                      $img_link    = false;
2663                      $tpl        = 'localfile';
2664  
2665                      if ($desc['picture_w'] && !$noimg)
2666                      {
2667                          if (!$text)
2668                          {
2669                              $text = $title;
2670                          }
2671  
2672                          return '<img src="'.$this->config['base_url'].$this->config['upload_path'].'/'.$thing.'" '.($text ? 'alt="'.$alt.'" title="'.$text.'"' : '').' width="'.$desc['picture_w'].'" height="'.$desc['picture_h'].'" />';
2673                      }
2674                  }
2675  
2676                  unset($desc);
2677              }
2678  
2679              if (count($arr) == 2 && $arr[0] == '')    // file:/some.zip
2680              {
2681                  //try to find in global storage and return if success
2682                  $desc = $this->check_file_exists($arr[1]);
2683  
2684                  if (is_array($desc))
2685                  {
2686                      $title    = $desc['file_description'].' ('.$this->binary_multiples($desc['file_size'], false, true, true).')';
2687                      $alt    = $desc['file_description'];
2688                      $url    = $this->config['base_url'].$this->config['upload_path'].$thing;
2689  
2690                      if ($desc['file_ext'] == 'pdf')
2691                      {
2692                          $icon    = $this->get_translation('pdficon');
2693                      }
2694                      else if ($desc['file_ext'] == 'txt')
2695                      {
2696                          $icon    = $this->get_translation('texticon');
2697                      }
2698                      else if ($desc['file_ext'] == 'odt')
2699                      {
2700                          $icon    = $this->get_translation('odticon');
2701                      }
2702                      else if ($desc['file_ext'] == 'png' || $desc['file_ext'] == 'gif' || $desc['file_ext'] == 'jpg')
2703                      {
2704                          $icon    = $this->get_translation('imageicon');
2705                      }
2706                      else
2707                      {
2708                          $icon    = $this->get_translation('fileicon');
2709                      }
2710  
2711                      $img_link    = false;
2712                      $tpl        = 'localfile';
2713  
2714                      if ($desc['picture_w'] && !$noimg)
2715                      {
2716                          if (!$text)
2717                          {
2718                              $text = $title;
2719                          }
2720  
2721                          return '<img src="'.$this->config['base_url'].$this->config['upload_path'].'/'.$thing.'" '.($text ? 'alt="'.$alt.'" title="'.$text.'"' : '').' width="'.$desc['picture_w'].'" height="'.$desc['picture_h'].'" />';
2722                      }
2723                  }
2724                  else    //404
2725                  {
2726                      $tpl    = 'wlocalfile';
2727                      $title    = '404: /'.$this->config['upload_path'].$thing;
2728                      $url    = '404';
2729                  }
2730  
2731                  unset($desc);
2732              }
2733  
2734              if (!$url)
2735              {
2736                  $file        = $arr[count($arr) - 1];
2737                  unset($arr[count($arr) - 1]);
2738                  $_page_tag    = implode('/', $arr);
2739  
2740                  if ($_page_tag == '')
2741                  {
2742                      $_page_tag = '!/';
2743                  }
2744  
2745                  //unwrap tag (check !/, ../ cases)
2746                  $page_tag    = rtrim($this->translit($this->unwrap_link($_page_tag)), './');
2747                  $page_id    = $this->get_page_id($page_tag);
2748  
2749                  //try to find in local $tag storage
2750                  $desc        = $this->check_file_exists($file, $page_tag);
2751  
2752                  if (is_array($desc))
2753                  {
2754                      //check 403 here!
2755                      if ($this->is_admin() || (
2756                      $desc['upload_id'] && (
2757                      $this->page['owner_id'] == $this->get_user_id())) || (
2758                      $this->has_access('read', $page_id)) || (
2759                      $desc['user_id'] == $this->get_user_id()))
2760                      {
2761                          $title        = $desc['file_description'].' ('.$this->binary_multiples($desc['file_size'], false, true, true).')';
2762                          $alt        = $desc['file_description'];
2763                          $url        = $this->href('file', trim($page_tag, '/')).($this->config['rewrite_mode'] ? '?' : '&amp;').'get='.$file;
2764                          $img_link    = false;
2765  
2766                          if ($desc['file_ext'] == 'pdf')
2767                          {
2768                              $icon    = $this->get_translation('pdficon');
2769                          }
2770                          else if ($desc['file_ext'] == 'txt')
2771                          {
2772                              $icon    = $this->get_translation('texticon');
2773                          }
2774                          else if ($desc['file_ext'] == 'odt')
2775                          {
2776                              $icon    = $this->get_translation('odticon');
2777                          }
2778                          else if ($desc['file_ext'] == 'png' || $desc['file_ext'] == 'gif' || $desc['file_ext'] == 'jpg')
2779                          {
2780                              $icon    = $this->get_translation('imageicon');
2781                          }
2782                          else
2783                          {
2784                              $icon    = $this->get_translation('fileicon');
2785                          }
2786  
2787                          $tpl    = 'localfile';
2788  
2789                          if ($desc['picture_w'] != 0 && !$noimg)
2790                          {
2791                              if (!$text)
2792                              {
2793                                  $text = $title;
2794                                  return '<img src="'.$this->href('file', trim($page_tag, '/')).($this->config['rewrite_mode'] ? '?' : '&amp;').'get='.$file.'" '.($text ? 'alt="'.$alt.'" title="'.$text.'"' : '').' width="'.$desc['picture_w'].'" height="'.$desc['picture_h'].'" />';
2795                              }
2796                              else
2797                              {
2798                                  return '<a href="'.$this->href('file', trim($page_tag, '/')).($this->config['rewrite_mode'] ? '?' : '&amp;').'get='.$file.'" title="'.$title.'">'.$text.'</a>';
2799                              }
2800                          }
2801                          /*
2802                          else
2803                          {
2804                              return '<a href="'.$this->href('file', trim($page_tag, '/')).($this->config['rewrite_mode'] ? '?' : '&amp;').'get='.$file.'" title="'.$title.'">'.$text.'</a>';
2805                          } */
2806  
2807                      }
2808                      else //403
2809                      {
2810                          $url        = $this->href('file', trim($page_tag, '/')).($this->config['rewrite_mode'] ? '?' : '&amp;').'get='.$file;
2811                          $icon        = $this->get_translation('lockicon');
2812                          $img_link    = false;
2813                          $tpl        = 'localfile';
2814                          $class        = 'denied';
2815                      }
2816                  }
2817                  else //404
2818                  {
2819                      $title    = '404: /'.trim($page_tag, '/').'/file'.($this->config['rewrite_mode'] ? '?' : '&amp;').'get='.$file;
2820                      $url    = '404';
2821                      $tpl    = 'wlocalfile';
2822                  }
2823  
2824                  unset($desc);
2825              }
2826              //forgot 'bout 403
2827          }
2828          else if ($this->config['disable_tikilinks'] != 1 && preg_match('/^('.$this->language['UPPER'].$this->language['LOWER'].$this->language['ALPHANUM'].'*)\.('.$this->language['ALPHA'].$this->language['ALPHANUM'].'+)$/s', $tag, $matches))
2829          {
2830              // it`s a Tiki link!
2831              $tag    = '/'.$matches[1].'/'.$matches[2];
2832  
2833              if (!$text)
2834              {
2835                  $text = $this->add_spaces($tag);
2836              }
2837  
2838              return $this->link($tag, $method, $text, $title, $track, 1);
2839          }
2840          else if (preg_match('/^([[:alnum:]]+)[:](['.$this->language['ALPHANUM_P'].'\-\_\.\+\&\=\#]*)$/', $tag, $matches))
2841          {
2842              // interwiki
2843              $parts    = explode('/', $matches[2]);
2844  
2845              for ($i = 0; $i < count($parts); $i++)
2846              {
2847                  $parts[$i] = str_replace('%23', '#', urlencode($parts[$i]));
2848              }
2849  
2850              if ($link_lang)
2851              {
2852                  $text    = $this->do_unicode_entities($text, $link_lang);
2853              }
2854  
2855              $url    = $this->get_inter_wiki_url($matches[1], implode('/', $parts));
2856              $icon    = $this->get_translation('iwicon');
2857              $tpl    = 'interwiki';
2858          }
2859          else if (preg_match('/^([\!\.\-'.$this->language['ALPHANUM_P'].']+)(\#['.$this->language['ALPHANUM_P'].'\_\-]+)?$/', $tag, $matches))
2860          {
2861              // it's a Wiki link!
2862              $tag    = $otag        = $matches[1];
2863              $untag    = $unwtag    = $this->unwrap_link($tag);
2864  
2865              $regex_handlers    = '/^(.*?)\/('.$this->config['standard_handlers'].')\/(.*)$/i';
2866              $ptag            = $this->translit($unwtag);
2867              $handler        = null;
2868  
2869              if (preg_match( $regex_handlers, '/'.$ptag.'/', $match ))
2870              {
2871                  $handler    = $match[2];
2872  
2873                  if (!isset($_ptag))
2874                  {
2875                      $_ptag = '';
2876                  }
2877  
2878                  $ptag        = $match[1];
2879                  $unwtag        = '/'.$unwtag.'/';
2880                  $co            = substr_count($_ptag, '/') - substr_count($ptag, '/');
2881  
2882                  for ($i = 0; $i < $co; $i++)
2883                  {
2884                      $unwtag    = substr($unwtag, 0, strrpos($unwtag, '/'));
2885                  }
2886  
2887                  if ($handler)
2888                  {
2889                      if (!isset($data))
2890                      {
2891                          $data = '';
2892                      }
2893  
2894                      $opar    = '/'.$untag.'/';
2895  
2896                      for ($i = 0; $i < substr_count($data, '/') + 2; $i++)
2897                      {
2898                          $opar = substr($opar, strpos($opar, '/') + 1);
2899                      }
2900  
2901                      $params = explode('/', $opar); //there're good params
2902                  }
2903              }
2904  
2905              $unwtag            = trim($unwtag, '/.');
2906              $unwtag            = str_replace('_', '', $unwtag);
2907  
2908              if ($handler)
2909              {
2910                  $method        = $handler;
2911              }
2912  
2913              $thispage        = $this->load_page($unwtag, 0, '', LOAD_CACHE, LOAD_META);
2914  
2915              if (!$thispage && $link_lang)
2916              {
2917                  $this->set_language($link_lang);
2918                  $lang        = $link_lang;
2919                  $thispage    = $this->load_page($unwtag, 0, '', LOAD_CACHE, LOAD_META);
2920              }
2921  
2922              if ($thispage)
2923              {
2924                  $_lang        = $this->language['code'];
2925  
2926                  if ($thispage['lang'])
2927                  {
2928                      $lang    = $thispage['lang'];
2929                  }
2930                  else
2931                  {
2932                      $lang    = $this->config['language'];
2933                  }
2934  
2935                  $this->set_language($lang);
2936                  $supertag    = $this->translit($untag);
2937              }
2938              else
2939              {
2940                  $supertag    = $this->translit($untag, TRAN_LOWERCASE, TRAN_DONTLOAD);
2941              }
2942  
2943              $aname = '';
2944  
2945              if (substr($tag, 0, 2) == '!/')
2946              {
2947                  $icon        = $this->get_translation('childicon');
2948                  $page0        = substr($tag, 2);
2949                  $page        = $this->add_spaces($page0);
2950                  $tpl        = 'childpage';
2951              }
2952              else if (substr($tag, 0, 3) == '../')
2953              {
2954                  $icon        = $this->get_translation('parenticon');
2955                  $page0        = substr($tag, 3);
2956                  $page        = $this->add_spaces($page0);
2957                  $tpl        = 'parentpage';
2958              }
2959              else if (substr($tag, 0, 1) == '/')
2960              {
2961                  $icon        = $this->get_translation('rooticon');
2962                  $page0        = substr($tag, 1);
2963                  $page        = $this->add_spaces($page0);
2964                  $tpl        = 'rootpage';
2965              }
2966              else
2967              {
2968                  $icon        = $this->get_translation('equalicon');
2969                  $page0        = $tag;
2970                  $page        = $this->add_spaces($page0);
2971                  $tpl        = 'equalpage';
2972              }
2973  
2974              if ($img_link)
2975              {
2976                  $text        = '<img src="'.$img_link.'" title="'.$text.'" />';
2977              }
2978  
2979              if ($text)
2980              {
2981                  if ($title)
2982                  {
2983                      // title="{title}" - alternate title is provided
2984                      $tpl        = 'descrpagealt';
2985                  }
2986                  else
2987                  {
2988                      // title="{pagepath}{page}"
2989                      $tpl        = 'descrpage';
2990                  }
2991  
2992                  $icon        = '';
2993              }
2994  
2995              $page_path        = substr($untag, 0, strlen($untag) - strlen($page0));
2996              $anchor            = isset($matches[2]) ? $matches[2] : '';
2997              $tag            = $unwtag;
2998  
2999              if (isset($_SESSION[$this->config['session_prefix'].'_'.'linktracking']) && $track)
3000              {
3001                  $this->track_link_to($tag);
3002              }
3003  
3004              if ($anchor_link && !isset($this->first_inclusion[$supertag]))
3005              {
3006                  $aname = 'name="'.$supertag.'"';
3007                  $this->first_inclusion[$supertag] = 1;
3008              }
3009  
3010              if ($thispage)
3011              {
3012                  $page_link    = $this->href($method, $thispage['tag']).($anchor ? $anchor : '');
3013                  $page_id    = $this->get_page_id($tag);
3014  
3015                  if ($this->config['hide_locked'])
3016                  {
3017                      $access        = $this->has_access('read', $page_id);
3018                  }
3019                  else
3020                  {
3021                      $access        = true;
3022  
3023                      if ($this->has_access('read', $page_id) == false)
3024                      {
3025                          $this->_acl['list'] = '';
3026                      }
3027                  }
3028  
3029                  if (!$access || $this->_acl['list'] == '')
3030                  {
3031                      $class        = 'denied';
3032                      $accicon    = $this->get_translation('lockicon');
3033                  }
3034                  else if ($this->_acl['list'] == '*')
3035                  {
3036                      $class        = '';
3037                      $accicon    = '';
3038                  }
3039                  else
3040                  {
3041                      $class        = 'customsec';
3042                      $accicon    = $this->get_translation('keyicon');
3043                  }
3044  
3045                  if ($text == trim($otag, '/') || $link_lang)
3046                  {
3047                      $text = $this->do_unicode_entities($text, $lang);
3048                  }
3049  
3050                  $page = $this->do_unicode_entities($page, $lang);
3051  
3052                  if (isset($_lang))
3053                  {
3054                      $this->set_language($_lang);
3055                  }
3056              }
3057              else
3058              {
3059                  $tpl        = (isset($this->method) && ($this->method == 'print' || $this->method == 'msword') ? 'p' : '') . 'w' . $tpl;
3060                  $page_link    = $this->href('edit', $tag, $lang ? 'lang='.$lang : '', 1);
3061                  $accicon    = $this->get_translation('wantedicon');
3062                  $title        = $this->get_translation('CreatePage');
3063  
3064                  if ($link_lang)
3065                  {
3066                      $text    = $this->do_unicode_entities($text, $link_lang);
3067                      $page    = $this->do_unicode_entities($page, $link_lang);
3068                  }
3069              }
3070  
3071              $icon            = str_replace('{theme}', $this->config['theme_url'], $icon);
3072              $accicon        = str_replace('{theme}', $this->config['theme_url'], $accicon);
3073              $res            = $this->get_translation('tpl.'.$tpl);
3074              $text            = trim($text);
3075  
3076              if ($res)
3077              {
3078                  if (isset($this->method) && $this->method == 'print')
3079                  {
3080                      $icon    = '';
3081                  }
3082  
3083                  //TODO: pagepath
3084                  $aname        = str_replace('/',            '.',        $aname);
3085                  $res        = str_replace('{aname}',    $aname,        $res);
3086                  $res        = str_replace('{icon}',        $icon,        $res);
3087                  $res        = str_replace('{accicon}',    $accicon,    $res);
3088                  $res        = str_replace('{class}',    $class,        $res);
3089                  $res        = str_replace('{title}',    $title,        $res);
3090                  $res        = str_replace('{pagelink}',    $page_link,    $res);
3091                  $res        = str_replace('{pagepath}',    $page_path,    $res);
3092                  $res        = str_replace('{page}',        $page,        $res);
3093                  $res        = str_replace('{text}',        $text,        $res);
3094  
3095                  if (!$text)
3096                  {
3097                      $text    = htmlspecialchars($tag, ENT_NOQUOTES, HTML_ENTITIES_CHARSET);
3098                  }
3099  
3100                  if ($this->config['youarehere_text'])
3101                  {
3102                      if (isset($this->context[$this->current_context]) && ($this->translit($tag) == $this->translit($this->context[$this->current_context])) )
3103                      {
3104                          $res    = str_replace('####', $text, $this->config['youarehere_text']);
3105                      }
3106                  }
3107  
3108                  // numerated wiki-links. initialize property as an array to make it work
3109                  if (is_array($this->numerate_links) && $page_link != $text && $title != $this->get_translation('CreatePage'))
3110                  {
3111                      if (!$refnum = (isset($this->numerate_links[$page_link]) ? $this->numerate_links[$page_link] : ''))
3112                      {
3113                          $refnum = '[link'.((string)count($this->numerate_links) + 1).']';
3114                          $this->numerate_links[$page_link] = $refnum;
3115                      }
3116                      $res .= '<sup class="refnum">'.$refnum.'</sup>';
3117                  }
3118  
3119                  return $res;
3120              }
3121  
3122              die ("ERROR: no link template '$tpl' found.");
3123          }
3124  
3125          if (!$text) $text    = htmlspecialchars($tag, ENT_NOQUOTES, HTML_ENTITIES_CHARSET);
3126  
3127          if ($url)
3128          {
3129              if ($img_link)
3130              {
3131                  $text        = '<img src="'.$img_link.'" title="'.$text.'" />';
3132              }
3133  
3134              $icon            = str_replace('{theme}', $this->config['theme_url'], $icon);
3135              $res            = $this->get_translation('tpl.'.$tpl);
3136  
3137              if ($res)
3138              {
3139                  if (!$class)
3140                  {
3141                      $class    = 'outerlink';
3142                  }
3143  
3144                  if (isset($this->method) && $this->method == 'print')
3145                  {
3146                      $icon    = '';
3147                  }
3148  
3149                  $res        = str_replace('{icon}',        $icon,    $res);
3150                  $res        = str_replace('{class}',    $class,    $res);
3151                  $res        = str_replace('{title}',    $title,    $res);
3152                  $res        = str_replace('{url}',        $url,    $res);
3153                  $res        = str_replace('{text}',        $text,    $res);
3154  
3155                  // numerated outer links and file links. initialize property as an array to make it work
3156                  if (is_array($this->numerate_links) && $url != $text && $url != '404' && $url != '403')
3157                  {
3158                      if (!$refnum = (isset($this->numerate_links[$url]) ? $this->numerate_links[$url] : ''))
3159                      {
3160                          $refnum = '[link'.((string)count($this->numerate_links) + 1).']';
3161                          $this->numerate_links[$url] = $refnum;
3162                      }
3163  
3164                      $res .= '<sup class="refnum">'.$refnum.'</sup>';
3165                  }
3166  
3167                  return $res;
3168              }
3169          }
3170  
3171          return $text;
3172      }
3173  
3174  	function add_spaces($text)
3175      {
3176          $show = 1;
3177  
3178          if ($user = $this->get_user())
3179          {
3180              $show = (isset($user['show_spaces']) ? $user['show_spaces'] : null);
3181          }
3182  
3183          if (!$show)
3184          {
3185              $show = $this->config['show_spaces'];
3186          }
3187  
3188          if ($show != 0)
3189          {
3190              $text = preg_replace('/('.$this->language['ALPHANUM'].')('.$this->language['UPPERNUM'].')/', '\\1&nbsp;\\2', $text);
3191              $text = preg_replace('/('.$this->language['UPPERNUM'].')('.$this->language['UPPERNUM'].')/', '\\1&nbsp;\\2', $text);
3192              $text = preg_replace('/('.$this->language['ALPHANUM'].')\//', '\\1&nbsp;/', $text);
3193              $text = preg_replace('/('.$this->language['UPPER'].')&nbsp;(?='.$this->language['UPPER'].'&nbsp;'.$this->language['UPPERNUM'].')/', '\\1', $text);
3194              $text = preg_replace('/('.$this->language['UPPER'].')&nbsp;(?='.$this->language['UPPER'].'&nbsp;\/)/', '\\1', $text);
3195              $text = preg_replace('/\/('.$this->language['ALPHANUM'].')/', '/&nbsp;\\1', $text);
3196              $text = preg_replace('/('.$this->language['UPPERNUM'].')&nbsp;('.$this->language['UPPERNUM'].')($|\b)/', '\\1\\2', $text);
3197              $text = preg_replace('/([0-9])('.$this->language['ALPHA'].')/', '\\1&nbsp;\\2', $text);
3198              $text = preg_replace('/('.$this->language['ALPHA'].')([0-9])/', '\\1&nbsp;\\2', $text);
3199              $text = preg_replace('/([0-9])&nbsp;(?=[0-9])/', '\\1', $text);
3200          }
3201  
3202          if (strpos($text, '/')   === 0)
3203          {
3204              $text = $this->get_translation('RootLinkIcon').substr($text, 1);
3205          }
3206  
3207          if (strpos($text, '!/')  === 0)
3208          {
3209              $text = $this->get_translation('SubLinkIcon').substr($text, 2);
3210          }
3211  
3212          if (strpos($text, '../') === 0)
3213          {
3214              $text = $this->get_translation('UpLinkIcon').substr($text, 3);
3215          }
3216  
3217          return $text;
3218      }
3219  
3220  	function add_spaces_title($text)
3221      {
3222          $text = preg_replace('/('.$this->language['ALPHANUM'].')('.$this->language['UPPERNUM'].')/', '\\1&nbsp;\\2', $text);
3223          $text = preg_replace('/('.$this->language['UPPERNUM'].')('.$this->language['UPPERNUM'].')/', '\\1&nbsp;\\2', $text);
3224          $text = preg_replace('/('.$this->language['ALPHANUM'].')\//', '\\1&nbsp;/', $text);
3225          $text = preg_replace('/('.$this->language['UPPER'].')&nbsp;(?='.$this->language['UPPER'].'&nbsp;'.$this->language['UPPERNUM'].')/', '\\1', $text);
3226          $text = preg_replace('/('.$this->language['UPPER'].')&nbsp;(?='.$this->language['UPPER'].'&nbsp;\/)/', '\\1', $text);
3227          $text = preg_replace('/\/('.$this->language['ALPHANUM'].')/', '/&nbsp;\\1', $text);
3228          $text = preg_replace('/('.$this->language['UPPERNUM'].')&nbsp;('.$this->language['UPPERNUM'].')($|\b)/', '\\1\\2', $text);
3229          $text = preg_replace('/([0-9])('.$this->language['ALPHA'].')/', '\\1&nbsp;\\2', $text);
3230          $text = preg_replace('/('.$this->language['ALPHA'].')([0-9])/', '\\1&nbsp;\\2', $text);
3231          #$text = preg_replace('/([0-9])&nbsp;(?=[0-9])/', '\\1', $text);
3232          $text = preg_replace('/([0-9])&nbsp;(?!'.$this->language['ALPHA'].')/', '\\1', $text);
3233          $text = preg_replace('/&nbsp;/', ' ', $text);
3234  
3235          if (strpos($text, '/')   === 0)
3236          {
3237              $text = $this->get_translation('RootLinkIcon').substr($text, 1);
3238          }
3239  
3240          if (strpos($text, '!/')  === 0)
3241          {
3242              $text = $this->get_translation('SubLinkIcon').substr($text, 2);
3243          }
3244  
3245          if (strpos($text, '../') === 0)
3246          {
3247              $text = $this->get_translation('UpLinkIcon').substr($text, 3);
3248          }
3249  
3250          return $text;
3251      }
3252  
3253  	function validate_reserved_words( $data )
3254      {
3255          $_data = $this->translit( $data );
3256          $_data = '/'.$_data.'/';
3257  
3258          // Find the string of text
3259          # $this->REGEX_WACKO_HANDLERS = '/^(.*?)\/'.$this->config['standard_handlers'].'\/(.*)$/i';
3260  
3261          // Find the word
3262          $this->REGEX_WACKO_HANDLERS = '/\b('.$this->config['standard_handlers'].')\b/i';
3263  
3264          if (preg_match( $this->REGEX_WACKO_HANDLERS, $_data, $match ))
3265          {
3266              return $message = $match[0];
3267          }
3268  
3269          /*
3270          if (preg_match( '/^\/[0-9]+/', $_data, $match ))
3271          {
3272              return "It is not possible to create pages, whose name consists of numbers or begins on them.";
3273              /// !!! to messageset, begins with 0-9
3274          }
3275          */
3276          return 0;
3277      }
3278  
3279  	function is_wiki_name($text)
3280      {
3281          return preg_match('/^'.$this->language['UPPER'].$this->language['LOWER'].'+'.$this->language['UPPERNUM'].$this->language['ALPHANUM'].'*$/', $text);
3282      }
3283  
3284  	function track_link_to($tag)
3285      {
3286          $this->linktable[] = $tag;
3287      }
3288  
3289  	function get_link_table()
3290      {
3291          return $this->linktable;
3292      }
3293  
3294  	function clear_link_table()
3295      {
3296          $this->linktable = array();
3297      }
3298  
3299  	function start_link_tracking()
3300      {
3301          $_SESSION[$this->config['session_prefix'].'_'.'linktracking'] = 1;
3302      }
3303  
3304  	function stop_link_tracking()
3305      {
3306          $_SESSION[$this->config['session_prefix'].'_'.'linktracking'] = 0;
3307      }
3308  
3309  	function write_link_table($from_page_id = '')
3310      {
3311          $query = '';
3312  
3313          // delete old link table
3314          if ($from_page_id == '')
3315          {
3316              $from_page_id = $this->page['page_id'];
3317          }
3318  
3319          $this->sql_query(
3320              "DELETE ".
3321              "FROM ".$this->config['table_prefix']."link ".
3322              "WHERE from_page_id = '".quote($this->dblink, $from_page_id)."'");
3323  
3324          if ($link_table = $this->get_link_table())
3325          {
3326              foreach ($link_table as $to_tag)
3327              {
3328                  $lower_to_tag = strtolower($to_tag);
3329  
3330                  if (!isset($written[$lower_to_tag]))
3331                  {
3332                      $query .= "('".quote($this->dblink, $from_page_id)."','".quote($this->dblink, $this->get_page_id($to_tag))."', '".quote($this->dblink, $to_tag)."', '".quote($this->dblink, $this->translit($to_tag))."'),";
3333                      $written[$lower_to_tag] = 1;
3334                  }
3335              }
3336  
3337              $this->sql_query(
3338                  "INSERT INTO ".$this->config['table_prefix']."link ".
3339                      "(from_page_id, to_page_id, to_tag, to_supertag) ".
3340                  "VALUES ".rtrim($query, ','));
3341          }
3342      }
3343  
3344      // INTERWIKI STUFF
3345  	function read_inter_wiki_config()
3346      {
3347          if ($lines = file('config/interwiki.conf'))
3348          {
3349              foreach ($lines as $line)
3350              {
3351                  if ($line = trim($line))
3352                  {
3353                      list($wiki_name, $wiki_url) = explode(' ', trim($line));
3354                      $this->inter_wiki[strtolower($wiki_name)] = $wiki_url;
3355                  }
3356              }
3357          }
3358      }
3359  
3360  	function get_inter_wiki_url($name, $tag)
3361      {
3362          $url = (isset($this->inter_wiki[strtolower($name)]) ? $this->inter_wiki[strtolower($name)] : '');
3363  
3364          if ($url)
3365          {
3366              // xhtmlisation
3367              $url = str_replace('&', '&amp;', $url);
3368  
3369              // tls'ing internal links
3370              if ($this->config['tls'] == true)
3371              {
3372                  if (isset($this->config['open_url']) && strpos($url, $this->config['open_url']) !== false)
3373                  {
3374                      $url = str_replace($this->config['open_url'], $this->config['base_url'], $url);
3375                  }
3376              }
3377  
3378              // translit
3379              if (strpos($url, $this->config['base_url']) !== false)
3380              {
3381                  $sub = substr($url, strlen($this->config['base_url']));
3382                  $url = $this->config['base_url'].$this->translit($sub);
3383              }
3384  
3385              // tagging
3386              if (strpos($url, '%s'))
3387              {
3388                  return str_replace('%s', $tag, $url);
3389              }
3390              else
3391              {
3392                  return $url.$tag;
3393              }
3394          }
3395      }
3396  
3397      // FORMS
3398  	function form_open($method = '', $tag = '', $form_method = 'post', $form_name = '', $form_more = '', $href_param = '')
3399      {
3400          if (!$form_method)
3401          {
3402              $form_method = 'post';
3403          }
3404  
3405          $add    = isset($_REQUEST['add']) ? $_REQUEST['add'] : '';
3406          $result    = '<form action="'.$this->href($method, $tag, $href_param, $add).'" '.$form_more.' method="'.$form_method.'" '.($form_name ? 'name="'.$form_name.'" ' : '').">\n";
3407  
3408          if (!$this->config['rewrite_mode'])
3409          {
3410              $result .= '<input type="hidden" name="page" value="'.$this->mini_href($method, $tag, $add)."\" />\n";
3411          }
3412  
3413          if ($this->config['tls'] == true)
3414          {
3415              $result = str_replace('http://', 'https://'.($this->config['tls_proxy'] ? $this->config['tls_proxy'].'/' : ''), $result);
3416          }
3417  
3418          return $result;
3419      }
3420  
3421  	function form_close()
3422      {
3423          return "</form>\n";
3424      }
3425  
3426      // REFERRERS
3427  	function log_referrer($page_id = '', $referrer = '')
3428      {
3429          // fill values
3430          if (!$page_id = trim($page_id))
3431          {
3432              $page_id = $this->page['page_id'];
3433          }
3434  
3435          if (!$referrer = trim($referrer))
3436          {
3437              $referrer = isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : '';
3438          }
3439  
3440          // check if it's coming from another site
3441          if ($referrer && !preg_match('/^'.preg_quote($this->config['base_url'], '/').'/', $referrer) && isset($_GET['sid']) === false) // TODO: isset($_GET['PHPSESSID']) === false
3442          {
3443              if (!preg_match('`^https?://`', $referrer))
3444              {
3445                  return;
3446              }
3447  
3448              $this->sql_query(
3449                  "INSERT INTO ".$this->config['table_prefix']."referrer SET ".
3450                      "page_id        = '".quote($this->dblink, $page_id)."', ".
3451                      "referrer        = '".quote($this->dblink, $referrer)."', ".
3452                      "referrer_time    = NOW()");
3453          }
3454      }
3455  
3456  	function load_referrers($page_id = null)
3457      {
3458          return $this->load_all(
3459              "SELECT ".
3460              (!isset($page_id)
3461                  ? "referrer, count(referrer) AS num "
3462                  : "page_id, referrer, count(referrer) AS num ").
3463              "FROM ".$this->config['table_prefix']."referrer ".
3464              (!is_null($page_id)
3465                  ? "WHERE page_id = '".quote($this->dblink, $page_id)."' "
3466                  : "").
3467              "GROUP BY referrer ".
3468              "ORDER BY num DESC");
3469      }
3470  
3471      // PLUGINS
3472  	function include_buffered($filename, $notfound_text = '', $vars = '', $path = '')
3473      {
3474          if ($path)
3475          {
3476              $dirs = explode(':', $path);
3477          }
3478          else
3479          {
3480              $dirs = array('');
3481          }
3482  
3483          foreach($dirs as $dir)
3484          {
3485              if ($dir)
3486              {
3487                  $dir .= '/';
3488              }
3489  
3490              $full_filename = $dir.$filename;
3491              $full_filename = trim($full_filename, './');
3492  
3493              if (@file_exists($full_filename))
3494              {
3495                  if (is_array($vars))
3496                  {
3497                      extract($vars, EXTR_SKIP);
3498                  }
3499  
3500                  ob_start();
3501                  include($full_filename);
3502                  $output = ob_get_contents();
3503                  ob_end_clean();
3504  
3505                  return $output;
3506              }
3507          }
3508  
3509          if ($notfound_text)
3510          {
3511              return $notfound_text;
3512          }
3513          else
3514          {
3515              return false;
3516          }
3517      }
3518  
3519  	function header($mod = '')
3520      {
3521          return $this->include_buffered('header'.$mod.'.php', $this->get_translation('ThemeCorrupt').': '.$this->config['theme'], '', 'themes/'.$this->config['theme'].'/appearance');
3522      }
3523  
3524  	function footer($mod = '')
3525      {
3526          return $this->include_buffered('footer'.$mod.'.php', $this->get_translation('ThemeCorrupt').': '.$this->config['theme'], '', 'themes/'.$this->config['theme'].'/appearance');
3527      }
3528  
3529  	function use_class($class_name, $class_dir = '', $file_name = '')
3530      {
3531          if (!class_exists($class_name))
3532          {
3533              if ($file_name == '')
3534              {
3535                  $file_name = strtolower($class_name);
3536              }
3537  
3538              if ($class_dir == '')
3539              {
3540                  $class_dir = $this->config['classes_path'];
3541              }
3542  
3543              $class_file = $class_dir.'/'.$file_name.'.php';
3544              $class_file = trim($class_file, './');
3545  
3546              if (!@is_readable($class_file))
3547              {
3548                  die('Cannot load class '.$class_name.'  from '. $class_file. ' ('.$class_dir.')');
3549              }
3550              else
3551              {
3552                  require_once($class_file);
3553              }
3554          }
3555      }
3556  
3557  	function action($action, $params = '', $force_link_tracking = 0)
3558      {
3559          $action = trim($action);
3560  
3561          if (!$force_link_tracking)
3562          {
3563              $this->stop_link_tracking();
3564          }
3565  
3566          $result = $this->include_buffered(strtolower($action).'.php', "<em>".$this->get_translation('UnknownAction')." \"$action\"</em>", $params, $this->config['action_path']);
3567  
3568          $this->start_link_tracking();
3569          $this->no_cache();
3570          return $result;
3571      }
3572  
3573  	function method($method)
3574      {
3575          if (!$handler = $this->page['handler'])
3576          {
3577              $handler = 'page';
3578          }
3579  
3580          $method_location = $handler.'/'.$method.'.php';
3581  
3582          return $this->include_buffered($method_location, "<em>Unknown method \"$method_location\"</em>", '', $this->config['handler_path']);
3583      }
3584  
3585      // wrapper for the next method
3586  	function format($text, $formatter = 'wiki', $options = '')
3587      {
3588          return $this->_format($text, $formatter, $options);
3589      }
3590  
3591  	function _format($text, $formatter, &$options)
3592      {
3593          $text = $this->include_buffered('formatters/'.$formatter.'.php', "<em>Formatter \"$formatter\" not found</em>", compact('text', 'options'));
3594  
3595          if ($formatter == 'wacko' && $this->config['default_typografica'])
3596          {
3597              $text = $this->include_buffered('formatters/typografica.php', "<em>Formatter \"$formatter\" not found</em>", compact('text'));
3598          }
3599  
3600          return $text;
3601      }
3602  
3603      // GROUPS
3604  	function load_usergroup($group_name, $group_id = 0)
3605      {
3606          $fiels_default    = 'g.*, u.user_name AS moderator';
3607  
3608          $usergroup = $this->load_single(
3609              "SELECT {$fiels_default} ".
3610              "FROM ".$this->config['table_prefix']."usergroup g ".
3611                  "LEFT JOIN ".$this->config['table_prefix']."user u ON (g.moderator = u.user_id) ".
3612              "WHERE ".( $group_id != 0
3613                  ? "g.group_id        = '".quote($this->dblink, $group_id)."' "
3614                  : "g.group_name        = '".quote($this->dblink, $group_name)."' ").
3615              "LIMIT 1");
3616  
3617          return $usergroup;
3618      }
3619  
3620      // USERS
3621      // check whether defined username is already registered.
3622      // we add appropriate (but not thorough) transliterations
3623      // to not allow too similiar names.
3624  	function user_name_exists($user_name)
3625      {
3626          if ($user_name == '')
3627          {
3628              return false;
3629          }
3630  
3631          // checking identical name only?
3632          if (!$this->config['antidupe'])
3633          {
3634              if ($this->load_single(
3635              "SELECT user_id FROM {$this->config['user_table']} ".
3636              "WHERE user_name = '".quote($this->dblink, $user_name)."' ".
3637              "LIMIT 1"))
3638              {
3639                  return true;
3640              }
3641              else
3642              {
3643                  return false;
3644              }
3645          }
3646  
3647          // substitutions table
3648          $table = array(
3649              'cyr' => '0I1',
3650              'lat' => 'ABCDEHKMOPTXYacekmnoprutxy6ll'
3651          );
3652  
3653          // splitting input name into array
3654          $user_name = preg_split('//', $user_name, -1, PREG_SPLIT_NO_EMPTY);
3655  
3656          // let's define characters positions and corresponding substitutions.
3657          // so we're constructing $p array with username chars needing
3658          // substitution positions as keys, and corresponding table positions
3659          // as array values
3660          $p = array();
3661  
3662          foreach ($user_name as $pos => &$char)
3663          {
3664              if (isset($p[$pos]) === false)
3665              {
3666                  if (false !== $sub = strpos($table['lat'], $char))
3667                  {
3668                      $p[$pos] = $sub;
3669                  }
3670                  else if (false !== $sub = strpos($table['cyr'], $char))
3671                  {
3672                      $p[$pos] = $sub;
3673                  }
3674              }
3675          }
3676  
3677          // exploding substitutions table into array
3678          foreach ($table as $key => &$val)
3679          {
3680              $table[$key] = preg_split('//', $table[$key], -1, PREG_SPLIT_NO_EMPTY);
3681          }
3682  
3683          // running through all chars positions needing replacement
3684          foreach ($p as $pos => $sub)
3685          {
3686              // what substitution character we have to use?
3687              if ($user_name[$pos] != $table['cyr'][$sub])
3688              {
3689                  // constructing cyrillic regexp addition
3690                  $user_name[$pos] = '['.$user_name[$pos].$table['cyr'][$sub].']';
3691              }
3692              else if ($user_name[$pos] != $table['lat'][$sub])
3693              {
3694                  // constructing latin regexp addition
3695                  $user_name[$pos] = '['.$user_name[$pos].$table['lat'][$sub].']';
3696              }
3697          }
3698  
3699          // checking database
3700          if ($this->load_single(
3701          "SELECT user_id FROM {$this->config['user_table']} ".
3702          "WHERE user_name REGEXP '".quote($this->dblink, implode('', $user_name))."' ".
3703          "LIMIT 1", 1))
3704          {
3705              return true;
3706          }
3707          else
3708          {
3709              return false;
3710          }
3711      }
3712  
3713      // check whether defined email is already in use.
3714      // Allow e-mail address re-use:
3715      // Different users can register with the same e-mail address.
3716  	function email_exists($email)
3717      {
3718          if ($email == '')
3719          {
3720              return false;
3721          }
3722  
3723          // checking identical name only?
3724          #if (!$this->config['allow_email_reuse'])
3725          #{
3726              if ($this->load_single(
3727                  "SELECT user_id FROM {$this->config['user_table']} ".
3728                  "WHERE email = '".quote($this->dblink, $email)."' ".
3729                  "LIMIT 1"))
3730              {
3731                  return true;
3732              }
3733              else
3734              {
3735                  return false;
3736              }
3737          #}
3738      }
3739  
3740  	function load_user($user_name, $user_id = 0, $password = 0, $session_data = false)
3741      {
3742          $fiels_default    = 'u.*, s.doubleclick_edit, s.show_comments, s.revisions_count, s.changes_count, s.lang, s.show_spaces, s.typografica, s.theme, s.autocomplete, s.numerate_links, s.dont_redirect, s.send_watchmail, s.show_files, s.allow_intercom, s.hide_lastsession, s.validate_ip, s.noid_pubs, s.session_expiration, s.timezone, s.dst';
3743          $fields_session    = 'u.user_id, u.user_name, u.real_name, u.password, u.salt,u.email, u.enabled, u.email_confirm, u.session_time, u.session_expire, u.last_mark, s.doubleclick_edit, s.show_comments, s.revisions_count, s.changes_count, s.lang, s.show_spaces, s.typografica, s.theme, s.autocomplete, s.numerate_links, s.dont_redirect, s.send_watchmail, s.show_files, s.allow_intercom, s.hide_lastsession, s.validate_ip, s.noid_pubs, s.session_expiration, s.timezone, s.dst';
3744  
3745          $user = $this->load_single(
3746              "SELECT ".($session_data
3747                  ? "{