includes/paths.php
changeset 1 fe660c52c48f
child 11 ccad6026a168
equal deleted inserted replaced
0:902822492a68 1:fe660c52c48f
       
     1 <?php
       
     2 
       
     3 /**
       
     4  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
       
     5  * Version 1.0 (Banshee)
       
     6  * Copyright (C) 2006-2007 Dan Fuhry
       
     7  * paths.php - The part of Enano that actually manages content. Everything related to page handling and namespaces is in here.
       
     8  *
       
     9  * This program is Free Software; you can redistribute and/or modify it under the terms of the GNU General Public License
       
    10  * as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
       
    11  *
       
    12  * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
       
    13  * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for details.
       
    14  *
       
    15  * @package Enano
       
    16  * @subpackage PathManager
       
    17  * @see http://enano.homelinux.org/Help:API_Documentation
       
    18  */
       
    19  
       
    20 class pathManager {
       
    21   var $pages, $custom_page, $cpage, $page, $fullpage, $page_exists, $namespace, $nslist, $admin_tree, $wiki_mode, $page_protected, $template_cache;
       
    22   function __construct()
       
    23   {
       
    24     global $db, $session, $paths, $template, $plugins; // Common objects
       
    25     
       
    26     $GLOBALS['paths'] =& $this;
       
    27     $this->pages = Array();
       
    28     
       
    29     dc_here('paths: setting up namespaces, admin nodes');
       
    30     
       
    31     // DEFINE NAMESPACES HERE
       
    32     // The key names should NOT EVER be changed, or Enano will be very broken
       
    33     $this->nslist = Array(
       
    34       'Article' =>'',
       
    35       'User'    =>'User:',
       
    36       'File'    =>'File:',
       
    37       'Help'    =>'Help:',
       
    38       'Admin'   =>'Admin:',
       
    39       'Special' =>'Special:',
       
    40       'System'  =>'Enano:',
       
    41       'Template'=>'Template:',
       
    42       'Category'=>'Category:',
       
    43       'Project' =>str_replace(' ', '_', getConfig('site_name')).':',
       
    44       );
       
    45     
       
    46     // ACL types
       
    47     // Note: you can set any of these to AUTH_DENY to universally and unconditionally deny access to the selected action.
       
    48     // These can also be added from within plugins
       
    49     
       
    50     $session->register_acl_type('read',                   AUTH_ALLOW,    'Read page(s)');
       
    51     $session->register_acl_type('post_comments',          AUTH_ALLOW,    'Post comments',                                                                                            Array('read'),                                            'Article|User|Project|Template|File|Help|System|Category');
       
    52     $session->register_acl_type('edit_comments',          AUTH_ALLOW,    'Edit own comments',                                                                                        Array('post_comments'),                                   'Article|User|Project|Template|File|Help|System|Category');
       
    53     $session->register_acl_type('edit_page',              AUTH_WIKIMODE, 'Edit page',                                                                                                Array('view_source'),                                     'Article|User|Project|Template|File|Help|System|Category');
       
    54     $session->register_acl_type('view_source',            AUTH_WIKIMODE, 'View source',                                                                                              Array('read'),                                            'Article|User|Project|Template|File|Help|System|Category'); // Only used if the page is protected
       
    55     $session->register_acl_type('mod_comments',           AUTH_DISALLOW, 'Moderate comments',                                                                                        Array('edit_comments'),                                   'Article|User|Project|Template|File|Help|System|Category');
       
    56     $session->register_acl_type('history_view',           AUTH_WIKIMODE, 'View history/diffs',                                                                                       Array('read'),                                            'Article|User|Project|Template|File|Help|System|Category');
       
    57     $session->register_acl_type('history_rollback',       AUTH_DISALLOW, 'Rollback history',                                                                                         Array('history_view'),                                    'Article|User|Project|Template|File|Help|System|Category');
       
    58     $session->register_acl_type('history_rollback_extra', AUTH_DISALLOW, 'Undelete page(s)',                                                                                         Array('history_rollback'),                                'Article|User|Project|Template|File|Help|System|Category');
       
    59     $session->register_acl_type('protect',                AUTH_DISALLOW, 'Protect page(s)',                                                                                          Array('read'),                                            'Article|User|Project|Template|File|Help|System|Category');
       
    60     $session->register_acl_type('rename',                 AUTH_WIKIMODE, 'Rename page(s)',                                                                                           Array('read'),                                            'Article|User|Project|Template|File|Help|System|Category');
       
    61     $session->register_acl_type('clear_logs',             AUTH_DISALLOW, 'Clear page logs (dangerous)',                                                                              Array('read', 'protect', 'even_when_protected'),          'Article|User|Project|Template|File|Help|System|Category');
       
    62     $session->register_acl_type('vote_delete',            AUTH_ALLOW,    'Vote to delete',                                                                                           Array('read'),                                            'Article|User|Project|Template|File|Help|System|Category');
       
    63     $session->register_acl_type('vote_reset',             AUTH_DISALLOW, 'Reset delete votes',                                                                                       Array('read'),                                            'Article|User|Project|Template|File|Help|System|Category');
       
    64     $session->register_acl_type('delete_page',            AUTH_DISALLOW, 'Delete page(s)',                                                                                           Array(),                                                  'Article|User|Project|Template|File|Help|System|Category');
       
    65     $session->register_acl_type('set_wiki_mode',          AUTH_DISALLOW, 'Set per-page wiki mode',                                                                                   Array('read'),                                            'Article|User|Project|Template|File|Help|System|Category');
       
    66     $session->register_acl_type('password_set',           AUTH_DISALLOW, 'Set password',                                                                                             Array('read'),                                            'Article|User|Project|Template|File|Help|System|Category');
       
    67     $session->register_acl_type('password_reset',         AUTH_DISALLOW, 'Disable/reset password',                                                                                   Array('read'),                                            'Article|User|Project|Template|File|Help|System|Category');
       
    68     $session->register_acl_type('mod_misc',               AUTH_DISALLOW, 'Super moderator (generate SQL backtraces, view IP addresses, and send large numbers of private messages)', Array(),                                                  'All');
       
    69     $session->register_acl_type('edit_cat',               AUTH_WIKIMODE, 'Edit categorization',                                                                                      Array('read'),                                            'Article|User|Project|Template|File|Help|System|Category');
       
    70     $session->register_acl_type('even_when_protected',    AUTH_DISALLOW, 'Allow editing, renaming, and categorization even when protected',                                          Array('edit_page', 'rename', 'mod_comments', 'edit_cat'), 'Article|User|Project|Template|File|Help|System|Category');
       
    71     $session->register_acl_type('upload_files',           AUTH_DISALLOW, 'Upload files',                                                                                             Array('create_page'),                                     'Article|User|Project|Template|File|Help|System|Category|Special');
       
    72     $session->register_acl_type('upload_new_version',     AUTH_WIKIMODE, 'Upload new versions of files',                                                                             Array('upload_files'),                                    'Article|User|Project|Template|File|Help|System|Category|Special');
       
    73     $session->register_acl_type('create_page',            AUTH_WIKIMODE, 'Create pages',                                                                                             Array(),                                                  'Article|User|Project|Template|File|Help|System|Category|Special');
       
    74     $session->register_acl_type('php_in_pages',           AUTH_DISALLOW, 'Embed PHP code in pages',                                                                                  Array('edit_page'),                                       'Article|User|Project|Template|File|Help|System|Category');
       
    75     $session->register_acl_type('edit_acl',               AUTH_DISALLOW, 'Edit access control lists', Array('read', 'post_comments', 'edit_comments', 'edit_page', 'view_source', 'mod_comments', 'history_view', 'history_rollback', 'history_rollback_extra', 'protect', 'rename', 'clear_logs', 'vote_delete', 'vote_reset', 'delete_page', 'set_wiki_mode', 'password_set', 'password_reset', 'mod_misc', 'edit_cat', 'even_when_protected', 'upload_files', 'upload_new_version', 'create_page', 'php_in_pages'));
       
    76     
       
    77     // DO NOT add new admin pages here! Use a plugin to call $paths->addAdminNode();
       
    78     $this->addAdminNode('General', 'General Configuration', 'GeneralConfig');
       
    79     $this->addAdminNode('General', 'File uploads', 'UploadConfig');
       
    80     $this->addAdminNode('General', 'Allowed file types', 'UploadAllowedMimeTypes');
       
    81     $this->addAdminNode('General', 'Manage Plugins', 'PluginManager');
       
    82     $this->addAdminNode('General', 'Backup database', 'DBBackup');
       
    83     $this->addAdminNode('Content', 'Manage Pages', 'PageManager');
       
    84     $this->addAdminNode('Content', 'Edit page content', 'PageEditor');
       
    85     $this->addAdminNode('Appearance', 'Manage themes', 'ThemeManager');
       
    86     $this->addAdminNode('Users', 'Manage users', 'UserManager');
       
    87     $this->addAdminNode('Users', 'Edit groups', 'GroupManager');
       
    88     $this->addAdminNode('Users', 'Ban control', 'BanControl');
       
    89     $this->addAdminNode('Users', 'Mass e-mail', 'MassEmail');
       
    90     
       
    91     $code = $plugins->setHook('acl_rule_init');
       
    92     foreach ( $code as $cmd )
       
    93     {
       
    94       eval($cmd);
       
    95     }
       
    96     
       
    97     $this->wiki_mode = (int)getConfig('wiki_mode')=='1';
       
    98     $this->template_cache = Array();
       
    99   }
       
   100   function pathManager()
       
   101   {
       
   102     $this->__construct();
       
   103   }
       
   104   function init()
       
   105   {
       
   106     global $db, $session, $paths, $template, $plugins; // Common objects
       
   107     
       
   108     dc_here('paths: selecting master page data');
       
   109     
       
   110     $code = $plugins->setHook('paths_init_before');
       
   111     foreach ( $code as $cmd )
       
   112     {
       
   113       eval($cmd);
       
   114     }
       
   115     
       
   116     $e = $db->sql_query('SELECT name,urlname,namespace,special,visible,comments_on,protected,delvotes,delvote_ips,wiki_mode,password FROM '.table_prefix.'pages ORDER BY name;');
       
   117     if( !$e )
       
   118     {
       
   119       $db->_die('The error seems to have occured while selecting the page information. File: includes/paths.php; line: '.__LINE__);
       
   120     }
       
   121     while($r = $db->fetchrow())
       
   122     {
       
   123       
       
   124       $r['urlname_nons'] = $r['urlname'];
       
   125       $r['urlname'] = $this->nslist[$r['namespace']] . $r['urlname']; // Applies the User:/File:/etc prefixes to the URL names
       
   126       
       
   127       if ( $r['delvotes'] == null)
       
   128       {
       
   129         $r['delvotes'] = 0;
       
   130       }
       
   131       if ( $r['protected'] == 0 || $r['protected'] == 1 )
       
   132       {
       
   133         $r['really_protected'] = (int)$r['protected'];
       
   134       }
       
   135       else if ( $r['protected'] == 2 && getConfig('wiki_mode') == '1')
       
   136       {
       
   137         $r['really_protected'] = 1;
       
   138       }
       
   139       else if ( $r['protected'] == 2 && getConfig('wiki_mode') == '0' )
       
   140       {
       
   141         $r['really_protected'] = 0;
       
   142       }
       
   143       
       
   144       $this->pages[$r['urlname']] = $r;
       
   145       $this->pages[] =& $this->pages[$r['urlname']];
       
   146       
       
   147     }
       
   148     $db->free_result();
       
   149     dc_here('paths: determining page ID');
       
   150     if( isset($_GET['title']) )
       
   151     {
       
   152       if ( $_GET['title'] == '' && getConfig('main_page') != '' )
       
   153       {
       
   154         $this->main_page();
       
   155       }
       
   156       if(strstr($_GET['title'], ' '))
       
   157       {
       
   158         $loc = urldecode(rawurldecode($_SERVER['REQUEST_URI']));
       
   159         $loc = str_replace(' ', '_', $loc);
       
   160         $loc = str_replace('+', '_', $loc);
       
   161         $loc = str_replace('%20', '_', $loc);
       
   162         redirect($loc, 'Redirecting...', 'Space detected in the URL, please wait whilst you are redirected', 0);
       
   163         exit;
       
   164       }
       
   165       $url_namespace_special = substr($_GET['title'], 0, strlen($this->nslist['Special']) );
       
   166       $url_namespace_template = substr($_GET['title'], 0, strlen($this->nslist['Template']) );
       
   167       if($url_namespace_special == $this->nslist['Special'] || $url_namespace_template == $this->nslist['Template'] )
       
   168       {
       
   169         $ex = explode('/', $_GET['title']);
       
   170         $this->page = $ex[0];
       
   171       }
       
   172       else
       
   173       {
       
   174         $this->page = $_GET['title'];
       
   175       }
       
   176       $this->fullpage = $_GET['title'];
       
   177     }
       
   178     elseif( isset($_SERVER['PATH_INFO']) )
       
   179     {
       
   180       $pi = explode('/', $_SERVER['PATH_INFO']);
       
   181       
       
   182       if( !isset($pi[1]) || (isset($pi[1]) && $pi[1] == '' && getConfig('main_page') != '') )
       
   183       {
       
   184         $this->main_page();
       
   185       }
       
   186       if( strstr($pi[1], ' ') )
       
   187       {
       
   188         $loc = str_replace(' ', '_', urldecode(rawurldecode($_SERVER['REQUEST_URI'])));
       
   189         $loc = str_replace('+', '_', $loc);
       
   190         $loc = str_replace('%20', '_', $loc);
       
   191         redirect($loc, 'Redirecting...', 'Please wait whilst you are redirected', 3);
       
   192         exit;
       
   193       }
       
   194       unset($pi[0]);
       
   195       if( substr($pi[1], 0, strlen($this->nslist['Special'])) == $this->nslist['Special'] || substr($pi[1], 0, strlen($this->nslist['Template'])) == $this->nslist['Template'] )
       
   196       {
       
   197         $pi2 = $pi[1];
       
   198       }
       
   199       else
       
   200       {
       
   201         $pi2 = implode('/', $pi);
       
   202       }
       
   203       $this->page = $pi2;
       
   204       $this->fullpage = implode('/', $pi);
       
   205     }
       
   206     else
       
   207     {
       
   208       $k = array_keys($_GET);
       
   209       foreach($k as $c)
       
   210       {
       
   211         if(substr($c, 0, 1) == '/')
       
   212         {
       
   213           $this->page = substr($c, 1, strlen($c));
       
   214           
       
   215           // Bugfix for apache somehow passing dots as underscores
       
   216           global $mime_types;
       
   217           
       
   218           $exts = array_keys($mime_types);
       
   219           $exts = '(' . implode('|', $exts) . ')';
       
   220           
       
   221           if ( preg_match( '#_'.$exts.'#i', $this->page ) )
       
   222           {
       
   223             $this->page = preg_replace( '#_'.$exts.'#i', '.\\1', $this->page );
       
   224           }
       
   225           
       
   226           $this->fullpage = $this->page;
       
   227           
       
   228           if(substr($this->page, 0, strlen($this->nslist['Special']))==$this->nslist['Special'] || substr($this->page, 0, strlen($this->nslist['Template']))==$this->nslist['Template'])
       
   229           {
       
   230             $ex = explode('/', $this->page);
       
   231             $this->page = $ex[0];
       
   232           }
       
   233           if(strstr($this->page, ' '))
       
   234           {
       
   235             $loc = str_replace(' ', '_', urldecode(rawurldecode($_SERVER['REQUEST_URI'])));
       
   236             $loc = str_replace('+', '_', $loc);
       
   237             $loc = str_replace('%20', '_', $loc);
       
   238             redirect($loc, 'Redirecting...', 'Space in the URL detected, please wait whilst you are redirected', 0);
       
   239             exit;
       
   240           }
       
   241           break;
       
   242         }
       
   243       }
       
   244       if(!$this->page && !($this->page == '' && getConfig('main_page') == ''))
       
   245       {
       
   246         $this->main_page();
       
   247       }
       
   248     }
       
   249     
       
   250     dc_here('paths: setting $paths->cpage');
       
   251     
       
   252     if(isset($this->pages[$this->page]))
       
   253     {
       
   254       dc_here('paths: page existence verified, our page ID is: '.$this->page);
       
   255       $this->page_exists = true;
       
   256       $this->cpage = $this->pages[$this->page];
       
   257       $this->namespace = $this->cpage['namespace'];
       
   258       if(!isset($this->cpage['wiki_mode'])) $this->cpage['wiki_mode'] = 2;
       
   259       
       
   260       // Determine the wiki mode for this page, now that we have this->cpage established
       
   261       if($this->cpage['wiki_mode'] == 2)
       
   262       {
       
   263         $this->wiki_mode = (int)getConfig('wiki_mode');
       
   264       }
       
   265       else
       
   266       {
       
   267         $this->wiki_mode = $this->cpage['wiki_mode'];
       
   268       }
       
   269       // Allow the user to create/modify his user page uncondtionally (admins can still protect the page)
       
   270       if($this->page == $this->nslist['User'].str_replace(' ', '_', $session->username))
       
   271       {
       
   272         $this->wiki_mode = true;
       
   273       }
       
   274       // And above all, if the site requires wiki mode to be off for non-logged-in users, disable it now
       
   275       if(getConfig('wiki_mode_require_login')=='1' && !$session->user_logged_in)
       
   276       {
       
   277         $this->wiki_mode = false;
       
   278       }
       
   279       if($this->cpage['protected'] == 2)
       
   280       {
       
   281         // The page is semi-protected, determine permissions
       
   282         if($session->user_logged_in && $session->reg_time + 60*60*24*4 < time()) 
       
   283         {
       
   284           $this->page_protected = 0;
       
   285         }
       
   286         else
       
   287         {
       
   288           $this->page_protected = 1;
       
   289         }
       
   290       }
       
   291       else
       
   292       {
       
   293         $this->page_protected = $this->cpage['protected'];
       
   294       }
       
   295     }
       
   296     else
       
   297     {
       
   298       dc_here('paths: page doesn\'t exist, creating new page in memory<br />our page ID is: '.$this->page);
       
   299       $this->page_exists = false;
       
   300       $this->cpage = Array(
       
   301         'name'=>str_replace('_', ' ', $this->page),
       
   302         'urlname'=>$this->page,
       
   303         'namespace'=>'Article',
       
   304         'special'=>0,
       
   305         'visible'=>0,
       
   306         'comments_on'=>1,
       
   307         'protected'=>0,
       
   308         'delvotes'=>0,
       
   309         'delvote_ips'=>'',
       
   310         'wiki_mode'=>2,
       
   311         );
       
   312       // Look for a namespace prefix in the urlname, and assign a different namespace, if necessary
       
   313       $k = array_keys($this->nslist);
       
   314       for($i=0;$i<sizeof($this->nslist);$i++)
       
   315       {
       
   316         $ln = strlen($this->nslist[$k[$i]]);
       
   317         if( substr($this->page, 0, $ln) == $this->nslist[$k[$i]] )
       
   318         {
       
   319           $this->cpage['namespace'] = $k[$i];
       
   320           $this->cpage['urlname_nons'] = substr($this->page, strlen($this->nslist[$this->cpage['namespace']]), strlen($this->page));
       
   321           if(!isset($this->cpage['wiki_mode'])) 
       
   322           {
       
   323             $this->cpage['wiki_mode'] = 2;
       
   324           }
       
   325         }
       
   326       }
       
   327       $this->namespace = $this->cpage['namespace'];
       
   328       
       
   329       if($this->namespace=='System') 
       
   330       {
       
   331         $this->cpage['protected'] = 1;
       
   332       }
       
   333       if($this->namespace=='Special')
       
   334       {
       
   335         // Can't load nonexistent pages
       
   336         $this->main_page();
       
   337       }
       
   338       // Allow the user to create/modify his user page uncondtionally (admins can still protect the page)
       
   339       if($this->page == $this->nslist['User'].str_replace(' ', '_', $session->username)) 
       
   340       {
       
   341         $this->wiki_mode = true;
       
   342       }
       
   343     }
       
   344     // This is used in the admin panel to keep track of form submission targets
       
   345     $this->cpage['module'] = $this->cpage['urlname'];
       
   346     
       
   347     // Page is set up, call any hooks
       
   348     $code = $plugins->setHook('page_set');
       
   349     foreach ( $code as $cmd )
       
   350     {
       
   351       eval($cmd);
       
   352     }
       
   353     
       
   354     $session->init_permissions();
       
   355   }
       
   356   
       
   357   function add_page($flags)
       
   358   {
       
   359     //dc_dump($flags, 'paths: page added by plugin:');
       
   360     $flags['urlname_nons'] = $flags['urlname'];
       
   361     $flags['urlname'] = $this->nslist[$flags['namespace']] . $flags['urlname']; // Applies the User:/File:/etc prefixes to the URL names
       
   362     $pages_len = sizeof($this->pages)/2;
       
   363     $this->pages[$pages_len] = $flags;
       
   364     $this->pages[$flags['urlname']] =& $this->pages[$pages_len];
       
   365   }
       
   366   
       
   367   function main_page()
       
   368   {
       
   369     if( is_string(getConfig('main_page')) )
       
   370     {
       
   371       header('Location: '.makeUrl(getConfig('main_page')));
       
   372       die('If you aren\'t redirected, <a href="' . makeUrl(getConfig('main_page')) . '">click here</a>.');
       
   373     }
       
   374     else
       
   375     {
       
   376       header('Location: '.makeUrl($this->pages[0]['urlname']));
       
   377       die('If you aren\'t redirected, <a href="' . makeUrl($this->pages[0]['urlname']) . '">click here</a>.');
       
   378     }
       
   379     exit;
       
   380   }
       
   381   
       
   382   function sysmsg($n)
       
   383   {
       
   384     global $db, $session, $paths, $template, $plugins; // Common objects
       
   385     dc_here('paths: system message requested: '.$n);
       
   386     $q = $db->sql_query('SELECT page_text, char_tag FROM '.table_prefix.'page_text WHERE page_id=\''.$db->escape($n).'\' AND namespace=\'System\'');
       
   387     if( !$q )
       
   388     {
       
   389       $db->_die('Error during generic selection of system page data.');
       
   390     }
       
   391     if($db->numrows() < 1)
       
   392     {
       
   393       return false;
       
   394       //$db->_die('Error during generic selection of system page data: there were no rows in the text table that matched the page text query.');
       
   395     }
       
   396     $r = $db->fetchrow();
       
   397     $db->free_result();
       
   398     $message = $r['page_text'];
       
   399     
       
   400     $message = preg_replace('/<noinclude>(.*?)<\/noinclude>/is', '', $message);
       
   401     
       
   402     return $message;
       
   403   }
       
   404   function get_pageid_from_url()
       
   405   {
       
   406     if(isset($_GET['title']))
       
   407     {
       
   408       if( $_GET['title'] == '' && getConfig('main_page') != '' )
       
   409       {
       
   410         $this->main_page();
       
   411       }
       
   412       if(strstr($_GET['title'], ' '))
       
   413       {
       
   414         $loc = urldecode(rawurldecode($_SERVER['REQUEST_URI']));
       
   415         $loc = str_replace(' ', '_', $loc);
       
   416         $loc = str_replace('+', '_', $loc);
       
   417         header('Location: '.$loc);
       
   418         exit;
       
   419       }
       
   420       $ret = $_GET['title'];
       
   421     }
       
   422     elseif(isset($_SERVER['PATH_INFO']))
       
   423     {
       
   424       $pi = explode('/', $_SERVER['PATH_INFO']);
       
   425       
       
   426       if(!isset($pi[1]) || (isset($pi[1]) && $pi[1] == ''))
       
   427       {
       
   428         return false;
       
   429       }
       
   430       
       
   431       if(strstr($pi[1], ' '))
       
   432       {
       
   433         $loc = urldecode(rawurldecode($_SERVER['REQUEST_URI']));
       
   434         $loc = str_replace(' ', '_', $loc);
       
   435         $loc = str_replace('+', '_', $loc);
       
   436         header('Location: '.$loc);
       
   437         exit;
       
   438       }
       
   439       if( !( substr($pi[1], 0, strlen($this->nslist['Special'])) == $this->nslist['Special'] ) )
       
   440       {
       
   441         unset($pi[0]);
       
   442         $pi[1] = implode('/', $pi);
       
   443       }
       
   444       $ret = $pi[1];
       
   445     }
       
   446     else
       
   447     {
       
   448       $k = array_keys($_GET);
       
   449       foreach($k as $c)
       
   450       {
       
   451         if(substr($c, 0, 1) == '/')
       
   452         {
       
   453           $ret = substr($c, 1, strlen($c));
       
   454           if(substr($ret, 0, strlen($this->nslist['Special'])) == $this->nslist['Special'] ||
       
   455              substr($ret, 0, strlen($this->nslist['Admin'])) == $this->nslist['Admin'])
       
   456           {
       
   457             $ret = explode('/', $ret);
       
   458             $ret = $ret[0];
       
   459           }
       
   460           break;
       
   461         }
       
   462       }
       
   463     }
       
   464     
       
   465     return ( isset($ret) ) ? $ret : false;
       
   466   }
       
   467   // Parses a (very carefully formed) array into Javascript code compatible with the Tigra Tree Menu used in the admin menu
       
   468   function parseAdminTree() 
       
   469   {
       
   470     $k = array_keys($this->admin_tree);
       
   471     $i = 0;
       
   472     $ret = '';
       
   473     $ret .= "var TREE_ITEMS = [\n  ['Administration panel home', 'javascript:ajaxPage(\'".$this->nslist['Admin']."Home\');',\n    ";
       
   474     foreach($k as $key)
       
   475     {
       
   476       $i++;
       
   477       $ret .= "['".$key."', 'javascript:trees[0].toggle($i)', \n";
       
   478       foreach($this->admin_tree[$key] as $c)
       
   479       {
       
   480         $i++;
       
   481         $ret .= "        ['".$c['name']."', 'javascript:ajaxPage(\\'".$this->nslist['Admin'].$c['pageid']."\\');'],\n";
       
   482       }
       
   483       $ret .= "      ],\n";
       
   484     }
       
   485     $ret .= "    ['Log out of admin panel', 'javascript:ajaxPage(\\'".$this->nslist['Admin']."AdminLogout\\');'],\n";
       
   486     // I used this while I painstakingly wrote the Runt code that auto-expands certain nodes based on the value of a bitfield stored in a cookie. *shudders*
       
   487     // $ret .= "    ['(debug) Clear menu bitfield', 'javascript:createCookie(\\'admin_menu_state\\', \\'1\\', 365);'],\n";
       
   488     $ret .= "]\n];";
       
   489     return $ret;
       
   490   }
       
   491   function addAdminNode($section, $page_title, $url)
       
   492   {
       
   493     if(!isset($this->admin_tree[$section]))
       
   494     {
       
   495       $this->admin_tree[$section] = Array();
       
   496     }
       
   497     $this->admin_tree[$section][] = Array(
       
   498         'name'=>$page_title,
       
   499         'pageid'=>$url
       
   500       );
       
   501   }
       
   502   function getParam($id = 0)
       
   503   {
       
   504     if(isset($_SERVER['PATH_INFO']))
       
   505     {
       
   506       $pi = explode('/', $_SERVER['PATH_INFO']);
       
   507       $id = $id + 2;
       
   508       return isset($pi[$id]) ? $pi[$id] : false;
       
   509     }
       
   510     else if( isset($_GET['title']) )
       
   511     {
       
   512       $pi = explode('/', $_GET['title']);
       
   513       $id = $id + 1;
       
   514       return isset($pi[$id]) ? $pi[$id] : false;
       
   515     }
       
   516     else
       
   517     {
       
   518       $k = array_keys($_GET);
       
   519       foreach($k as $c)
       
   520       {
       
   521         if(substr($c, 0, 1) == '/')
       
   522         {
       
   523           
       
   524           // Bugfix for apache somehow passing dots as underscores
       
   525           global $mime_types;
       
   526           $exts = array_keys($mime_types);
       
   527           $exts = '(' . implode('|', $exts) . ')';
       
   528           if ( preg_match( '#_'.$exts.'#i', $c ) )
       
   529             $c = preg_replace( '#_'.$exts.'#i', '.\\1', $c );
       
   530           
       
   531           $pi = explode('/', $c);
       
   532           $id = $id + 2;
       
   533           return isset($pi[$id]) ? $pi[$id] : false;
       
   534         }
       
   535       }
       
   536       return false;
       
   537     }
       
   538   }
       
   539   
       
   540   function getAllParams()
       
   541   {
       
   542     if(isset($_SERVER['PATH_INFO']))
       
   543     {
       
   544       $pi = explode('/', $_SERVER['PATH_INFO']);
       
   545       unset($pi[0], $pi[1]);
       
   546       return implode('/', $pi);
       
   547     }
       
   548     else if( isset($_GET['title']) )
       
   549     {
       
   550       $pi = explode('/', $_GET['title']);
       
   551       unset($pi[0]);
       
   552       return implode('/', $pi);
       
   553     }
       
   554     else
       
   555     {
       
   556       $k = array_keys($_GET);
       
   557       foreach($k as $c)
       
   558       {
       
   559         if(substr($c, 0, 1) == '/')
       
   560         {
       
   561           // Bugfix for apache somehow passing dots as underscores
       
   562           global $mime_types;
       
   563           $exts = array_keys($mime_types);
       
   564           $exts = '(' . implode('|', $exts) . ')';
       
   565           if ( preg_match( '#_'.$exts.'#i', $c ) )
       
   566             $c = preg_replace( '#_'.$exts.'#i', '.\\1', $c );
       
   567           
       
   568           $pi = explode('/', $c);
       
   569           unset($pi[0], $pi[1]);
       
   570           return implode('/', $pi);
       
   571         }
       
   572       }
       
   573       return false;
       
   574     }
       
   575   }
       
   576   
       
   577   /**
       
   578    * Creates a new namespace in memory
       
   579    * @param string $id the namespace ID
       
   580    * @param string $prefix the URL prefix, must not be blank or already used
       
   581    * @return bool true on success false on failure
       
   582    */
       
   583   
       
   584   function create_namespace($id, $prefix)
       
   585   {
       
   586     if(in_array($prefix, $this->nslist))
       
   587     {
       
   588       // echo '<b>Warning:</b> pathManager::create_namespace: Prefix "'.$prefix.'" is already taken<br />';
       
   589       return false;
       
   590     }
       
   591     if( isset($this->nslist[$id]) )
       
   592     {
       
   593       // echo '<b>Warning:</b> pathManager::create_namespace: Namespace ID "'.$prefix.'" is already taken<br />';
       
   594       return false;
       
   595     }
       
   596     $this->nslist[$id] = $prefix;
       
   597   }
       
   598   
       
   599   /**
       
   600    * Fetches the page texts for searching
       
   601    */
       
   602    
       
   603   function fetch_page_search_texts()
       
   604   {
       
   605     global $db, $session, $paths, $template, $plugins; // Common objects
       
   606     $texts = Array();
       
   607     $q = $db->sql_query('SELECT t.page_id,t.namespace,t.page_text,t.char_tag FROM '.table_prefix.'page_text AS t
       
   608                            LEFT JOIN '.table_prefix.'pages AS p
       
   609                              ON t.page_id=p.urlname
       
   610                            WHERE p.namespace=t.namespace
       
   611                              AND ( p.password=\'\' OR p.password=\'da39a3ee5e6b4b0d3255bfef95601890afd80709\' )
       
   612                              AND p.visible=1;'); // Only indexes "visible" pages
       
   613     
       
   614     if( !$q )
       
   615     {
       
   616       return false;
       
   617     }
       
   618     while($row = $db->fetchrow())
       
   619     {
       
   620       $pid = $this->nslist[$row['namespace']] . $row['page_id'];
       
   621       $texts[$pid] = $row['page_text'];
       
   622     }
       
   623     $db->free_result();
       
   624     
       
   625     return $texts;
       
   626   }
       
   627   
       
   628   /**
       
   629    * Fetches a MySQL search query to use for Searcher::searchMySQL()
       
   630    */
       
   631    
       
   632   function fetch_page_search_resource()
       
   633   {
       
   634     global $db, $session, $paths, $template, $plugins; // Common objects
       
   635     // sha1('') returns "da39a3ee5e6b4b0d3255bfef95601890afd80709"
       
   636     $texts = 'SELECT t.page_text,CONCAT(\'ns=\',t.namespace,\';pid=\',t.page_id) FROM '.table_prefix.'page_text AS t
       
   637                            LEFT JOIN '.table_prefix.'pages AS p
       
   638                              ON ( t.page_id=p.urlname AND t.namespace=p.namespace )
       
   639                            WHERE p.namespace=t.namespace
       
   640                              AND ( p.password=\'\' OR p.password=\'da39a3ee5e6b4b0d3255bfef95601890afd80709\' )
       
   641                              AND p.visible=1;'; // Only indexes "visible" pages
       
   642     return $texts;
       
   643   }
       
   644   
       
   645   /**
       
   646    * Rebuilds the search index
       
   647    */
       
   648    
       
   649   function rebuild_search_index()
       
   650   {
       
   651     global $db, $session, $paths, $template, $plugins; // Common objects
       
   652     $search = new Searcher();
       
   653     $texts = Array();
       
   654     $textq = $db->sql_unbuffered_query($this->fetch_page_search_resource());
       
   655     if(!$textq) $db->_die('');
       
   656     while($row = $db->fetchrow_num())
       
   657     {
       
   658       $texts[(string)$row[1]] = $row[0];
       
   659     }
       
   660     $search->buildIndex($texts);
       
   661     // echo '<pre>'.print_r($search->index, true).'</pre>';
       
   662     // return;
       
   663     $q = $db->sql_query('DELETE FROM '.table_prefix.'search_index');
       
   664     if(!$q) return false;
       
   665     $secs = Array();
       
   666     $q = 'INSERT INTO '.table_prefix.'search_index(word,page_names) VALUES';
       
   667     foreach($search->index as $word => $pages)
       
   668     {
       
   669       $secs[] = '(\''.$db->escape($word).'\', \''.$db->escape($pages).'\')';
       
   670     }
       
   671     $q .= implode(',', $secs);
       
   672     unset($secs);
       
   673     $q .= ';';
       
   674     $result = $db->sql_query($q);
       
   675     $db->free_result();
       
   676     if($result)
       
   677       return true;
       
   678     else
       
   679       $db->_die('The search index was trying to rebuild itself when the error occured.');
       
   680   }
       
   681   
       
   682   /**
       
   683    * Partially rebuilds the search index, removing/inserting entries only for the current page
       
   684    * @param string $page_id
       
   685    * @param string $namespace
       
   686    */
       
   687   
       
   688   function rebuild_page_index($page_id, $namespace)
       
   689   {
       
   690     global $db, $session, $paths, $template, $plugins; // Common objects
       
   691     if(!$db->sql_query('SELECT page_text FROM '.table_prefix.'page_text
       
   692       WHERE page_id=\''.$db->escape($page_id).'\' AND namespace=\''.$db->escape($namespace).'\';'))
       
   693     {
       
   694       return $db->get_error();
       
   695     }
       
   696     $row = $db->fetchrow();
       
   697     $db->free_result();
       
   698     $search = new Searcher();
       
   699     $search->buildIndex(Array("ns={$namespace};pid={$page_id}"=>$row['page_text']));
       
   700     $new_index = $search->index;
       
   701     
       
   702     $keys = array_keys($search->index);
       
   703     foreach($keys as $i => $k)
       
   704     {
       
   705       $c =& $keys[$i];
       
   706       $c = hexencode($c, '', '');
       
   707     }
       
   708     $keys = "word=0x" . implode ( " OR word=0x", $keys ) . "";
       
   709     
       
   710     // Zap the cache
       
   711     $cache = array_keys($search->index);
       
   712     if ( count($cache) < 1 )
       
   713     {
       
   714       return false;
       
   715     }
       
   716     $cache = "query LIKE '%" . implode ( "%' OR query LIKE '%", $cache ) . "%'";
       
   717     $db->sql_query('DELETE FROM '.table_prefix.'search_cache WHERE '.$cache);
       
   718     
       
   719     $query = $db->sql_query('SELECT word,page_names FROM '.table_prefix.'search_index WHERE '.$keys.';');
       
   720     
       
   721     while($row = $db->fetchrow())
       
   722     {
       
   723       $row['word'] = rtrim($row['word'], "\0");
       
   724       $new_index[ $row['word'] ] = $row['page_names'] . ',' . $search->index[ $row['word'] ];
       
   725     }
       
   726     $db->free_result();
       
   727     
       
   728     $db->sql_query('DELETE FROM '.table_prefix.'search_index WHERE '.$keys.';');
       
   729     
       
   730     $secs = Array();
       
   731     $q = 'INSERT INTO '.table_prefix.'search_index(word,page_names) VALUES';
       
   732     foreach($new_index as $word => $pages)
       
   733     {
       
   734       $secs[] = '(\''.$db->escape($word).'\', \''.$db->escape($pages).'\')';
       
   735     }
       
   736     $q .= implode(',', $secs);
       
   737     unset($secs);
       
   738     $q .= ';';
       
   739     if(!$db->check_query($q))
       
   740     {
       
   741       die('BUG: PathManager::rebuild_page_index: Query rejected by SQL parser:<pre>'.$q.'</pre>');
       
   742     }
       
   743     $result = $db->sql_query($q);
       
   744     if($result)
       
   745       return true;
       
   746     else
       
   747       $db->_die('The search index was trying to rebuild itself when the error occured.');
       
   748     
       
   749   }
       
   750   
       
   751   /**
       
   752    * Creates an instance of the Searcher class, including index info
       
   753    * @return object
       
   754    */
       
   755    
       
   756   function makeSearcher($match_case = false)
       
   757   {
       
   758     global $db, $session, $paths, $template, $plugins; // Common objects
       
   759     $search = new Searcher();
       
   760     $q = $db->sql_query('SELECT word,page_names FROM '.table_prefix.'search_index;');
       
   761     if(!$q)
       
   762     {
       
   763       echo $db->get_error();
       
   764       return false;
       
   765     }
       
   766     $idx = Array();
       
   767     while($row = $db->fetchrow($q))
       
   768     {
       
   769       $row['word'] = rtrim($row['word'], "\0");
       
   770       $idx[$row['word']] = $row['page_names'];
       
   771     }
       
   772     $db->free_result();
       
   773     $search->index = $idx;
       
   774     if($match_case)
       
   775       $search->match_case = true;
       
   776     return $search;
       
   777   }
       
   778   
       
   779   /**
       
   780    * Creates an associative array filled with the values of all the page titles
       
   781    * @return array
       
   782    */
       
   783    
       
   784   function get_page_titles()
       
   785   {
       
   786     $texts = Array();
       
   787     for ( $i = 0; $i < sizeof($this->pages) / 2; $i++ )
       
   788     {
       
   789       $texts[$this->pages[$i]['urlname']] = $this->pages[$i]['name'];
       
   790     }
       
   791     return $texts;
       
   792   }
       
   793   
       
   794   /**
       
   795    * Creates an instance of the Searcher class, including index info for page titles
       
   796    * @return object
       
   797    */
       
   798    
       
   799   function makeTitleSearcher($match_case = false)
       
   800   {
       
   801     global $db, $session, $paths, $template, $plugins; // Common objects
       
   802     $search = new Searcher();
       
   803     $texts = $this->get_page_titles();
       
   804     $search->buildIndex($texts);
       
   805     if($match_case)
       
   806       $search->match_case = true;
       
   807     return $search;
       
   808   }
       
   809   
       
   810 }
       
   811   
       
   812 ?>