includes/paths.php
changeset 1227 bdac73ed481e
parent 1157 e154e8176700
child 1252 e34c23a35dc9
equal deleted inserted replaced
1226:de56132c008d 1227:bdac73ed481e
    16  * @see http://enanocms.org/Help:API_Documentation
    16  * @see http://enanocms.org/Help:API_Documentation
    17  */
    17  */
    18  
    18  
    19 class pathManager
    19 class pathManager
    20 {
    20 {
    21   public $title, $pages, $custom_page, $cpage, $page, $fullpage, $page_exists, $page_id, $namespace, $nslist, $admin_tree, $wiki_mode, $page_protected, $template_cache, $external_api_page;
    21 	public $title, $pages, $custom_page, $cpage, $page, $fullpage, $page_exists, $page_id, $namespace, $nslist, $admin_tree, $wiki_mode, $page_protected, $template_cache, $external_api_page;
    22   
    22 	
    23   /**
    23 	/**
    24    * List of custom processing functions for namespaces. This is protected so trying to do anything with it will throw an error.
    24  	* List of custom processing functions for namespaces. This is protected so trying to do anything with it will throw an error.
    25    * @access private
    25  	* @access private
    26    * @var array
    26  	* @var array
    27    */
    27  	*/
    28   
    28 	
    29   protected $namespace_processors;
    29 	protected $namespace_processors;
    30   
    30 	
    31   function __construct()
    31 	function __construct()
    32   {
    32 	{
    33     global $db, $session, $paths, $template, $plugins; // Common objects
    33 		global $db, $session, $paths, $template, $plugins; // Common objects
    34     
    34 		
    35     $GLOBALS['paths'] =& $this;
    35 		$GLOBALS['paths'] =& $this;
    36     $this->pages = Array();
    36 		$this->pages = Array();
    37     
    37 		
    38     // DEFINE NAMESPACES HERE
    38 		// DEFINE NAMESPACES HERE
    39     // The key names should NOT EVER be changed, or Enano will be very broken
    39 		// The key names should NOT EVER be changed, or Enano will be very broken
    40     $namespace_delimiter = ( defined('WINDOWS_MOD_REWRITE_WORKAROUNDS') ) ? '.' : ':';
    40 		$namespace_delimiter = ( defined('WINDOWS_MOD_REWRITE_WORKAROUNDS') ) ? '.' : ':';
    41     $this->nslist = Array(
    41 		$this->nslist = Array(
    42       'Article'  => '',
    42 			'Article'  => '',
    43       'User'     => 'User' . $namespace_delimiter,
    43 			'User'     => 'User' . $namespace_delimiter,
    44       'File'     => 'File' . $namespace_delimiter,
    44 			'File'     => 'File' . $namespace_delimiter,
    45       'Help'     => 'Help' . $namespace_delimiter,
    45 			'Help'     => 'Help' . $namespace_delimiter,
    46       'Admin'    => 'Admin' . $namespace_delimiter,
    46 			'Admin'    => 'Admin' . $namespace_delimiter,
    47       'Special'  => 'Special' . $namespace_delimiter,
    47 			'Special'  => 'Special' . $namespace_delimiter,
    48       'System'   => 'Enano' . $namespace_delimiter,
    48 			'System'   => 'Enano' . $namespace_delimiter,
    49       'Template' => 'Template' . $namespace_delimiter,
    49 			'Template' => 'Template' . $namespace_delimiter,
    50       'Category' => 'Category' . $namespace_delimiter,
    50 			'Category' => 'Category' . $namespace_delimiter,
    51       'API'      => 'SystemAPI' . $namespace_delimiter,
    51 			'API'      => 'SystemAPI' . $namespace_delimiter,
    52       'Project'  => sanitize_page_id(getConfig('site_name')) . $namespace_delimiter,
    52 			'Project'  => sanitize_page_id(getConfig('site_name')) . $namespace_delimiter,
    53       );
    53 			);
    54     
    54 		
    55     // ACL types
    55 		// ACL types
    56     // These can also be added from within plugins
    56 		// These can also be added from within plugins
    57     
    57 		
    58     $session->register_acl_type('read',                   AUTH_ALLOW,    'perm_read');
    58 		$session->register_acl_type('read',                   AUTH_ALLOW,    'perm_read');
    59     $session->register_acl_type('post_comments',          AUTH_ALLOW,    'perm_post_comments',          Array('read'),                                            'Article|User|Project|Template|File|Help|System|Category');
    59 		$session->register_acl_type('post_comments',          AUTH_ALLOW,    'perm_post_comments',          Array('read'),                                            'Article|User|Project|Template|File|Help|System|Category');
    60     $session->register_acl_type('edit_comments',          AUTH_ALLOW,    'perm_edit_comments',          Array('post_comments'),                                   'Article|User|Project|Template|File|Help|System|Category');
    60 		$session->register_acl_type('edit_comments',          AUTH_ALLOW,    'perm_edit_comments',          Array('post_comments'),                                   'Article|User|Project|Template|File|Help|System|Category');
    61     $session->register_acl_type('edit_page',              AUTH_WIKIMODE, 'perm_edit_page',              Array('view_source'),                                     'Article|User|Project|Template|File|Help|System|Category');
    61 		$session->register_acl_type('edit_page',              AUTH_WIKIMODE, 'perm_edit_page',              Array('view_source'),                                     'Article|User|Project|Template|File|Help|System|Category');
    62     $session->register_acl_type('edit_wysiwyg',           AUTH_ALLOW,    'perm_edit_wysiwyg',           Array(),                                                  'Article|User|Project|Template|File|Help|System|Category');
    62 		$session->register_acl_type('edit_wysiwyg',           AUTH_ALLOW,    'perm_edit_wysiwyg',           Array(),                                                  'Article|User|Project|Template|File|Help|System|Category');
    63     $session->register_acl_type('view_source',            AUTH_WIKIMODE, 'perm_view_source',            Array('read'),                                            'Article|User|Project|Template|File|Help|System|Category'); // Only used if the page is protected
    63 		$session->register_acl_type('view_source',            AUTH_WIKIMODE, 'perm_view_source',            Array('read'),                                            'Article|User|Project|Template|File|Help|System|Category'); // Only used if the page is protected
    64     $session->register_acl_type('mod_comments',           AUTH_DISALLOW, 'perm_mod_comments',           Array('edit_comments'),                                   'Article|User|Project|Template|File|Help|System|Category');
    64 		$session->register_acl_type('mod_comments',           AUTH_DISALLOW, 'perm_mod_comments',           Array('edit_comments'),                                   'Article|User|Project|Template|File|Help|System|Category');
    65     $session->register_acl_type('history_view',           AUTH_WIKIMODE, 'perm_history_view',           Array('read'),                                            'Article|User|Project|Template|File|Help|System|Category');
    65 		$session->register_acl_type('history_view',           AUTH_WIKIMODE, 'perm_history_view',           Array('read'),                                            'Article|User|Project|Template|File|Help|System|Category');
    66     $session->register_acl_type('history_rollback',       AUTH_DISALLOW, 'perm_history_rollback',       Array('history_view'),                                    'Article|User|Project|Template|File|Help|System|Category');
    66 		$session->register_acl_type('history_rollback',       AUTH_DISALLOW, 'perm_history_rollback',       Array('history_view'),                                    'Article|User|Project|Template|File|Help|System|Category');
    67     $session->register_acl_type('history_rollback_extra', AUTH_DISALLOW, 'perm_history_rollback_extra', Array('history_rollback'),                                'Article|User|Project|Template|File|Help|System|Category');
    67 		$session->register_acl_type('history_rollback_extra', AUTH_DISALLOW, 'perm_history_rollback_extra', Array('history_rollback'),                                'Article|User|Project|Template|File|Help|System|Category');
    68     $session->register_acl_type('protect',                AUTH_DISALLOW, 'perm_protect',                Array('read'),                                            'Article|User|Project|Template|File|Help|System|Category');
    68 		$session->register_acl_type('protect',                AUTH_DISALLOW, 'perm_protect',                Array('read'),                                            'Article|User|Project|Template|File|Help|System|Category');
    69     $session->register_acl_type('rename',                 AUTH_WIKIMODE, 'perm_rename',                 Array('read'),                                            'Article|User|Project|Template|File|Help|System|Category');
    69 		$session->register_acl_type('rename',                 AUTH_WIKIMODE, 'perm_rename',                 Array('read'),                                            'Article|User|Project|Template|File|Help|System|Category');
    70     $session->register_acl_type('clear_logs',             AUTH_DISALLOW, 'perm_clear_logs',             Array('read', 'protect', 'even_when_protected'),          'Article|User|Project|Template|File|Help|System|Category');
    70 		$session->register_acl_type('clear_logs',             AUTH_DISALLOW, 'perm_clear_logs',             Array('read', 'protect', 'even_when_protected'),          'Article|User|Project|Template|File|Help|System|Category');
    71     $session->register_acl_type('vote_delete',            AUTH_ALLOW,    'perm_vote_delete',            Array('read'),                                            'Article|User|Project|Template|File|Help|System|Category');
    71 		$session->register_acl_type('vote_delete',            AUTH_ALLOW,    'perm_vote_delete',            Array('read'),                                            'Article|User|Project|Template|File|Help|System|Category');
    72     $session->register_acl_type('vote_reset',             AUTH_DISALLOW, 'perm_vote_reset',             Array('read'),                                            'Article|User|Project|Template|File|Help|System|Category');
    72 		$session->register_acl_type('vote_reset',             AUTH_DISALLOW, 'perm_vote_reset',             Array('read'),                                            'Article|User|Project|Template|File|Help|System|Category');
    73     $session->register_acl_type('delete_page',            AUTH_DISALLOW, 'perm_delete_page',            Array(),                                                  'Article|User|Project|Template|File|Help|System|Category');
    73 		$session->register_acl_type('delete_page',            AUTH_DISALLOW, 'perm_delete_page',            Array(),                                                  'Article|User|Project|Template|File|Help|System|Category');
    74     $session->register_acl_type('tag_create',             AUTH_ALLOW,    'perm_tag_create',             Array('read'),                                            'Article|User|Project|Template|File|Help|System|Category');
    74 		$session->register_acl_type('tag_create',             AUTH_ALLOW,    'perm_tag_create',             Array('read'),                                            'Article|User|Project|Template|File|Help|System|Category');
    75     $session->register_acl_type('tag_delete_own',         AUTH_ALLOW,    'perm_tag_delete_own',         Array('read', 'tag_create'),                              'Article|User|Project|Template|File|Help|System|Category');
    75 		$session->register_acl_type('tag_delete_own',         AUTH_ALLOW,    'perm_tag_delete_own',         Array('read', 'tag_create'),                              'Article|User|Project|Template|File|Help|System|Category');
    76     $session->register_acl_type('tag_delete_other',       AUTH_DISALLOW, 'perm_tag_delete_other',       Array('read'),                                            'Article|User|Project|Template|File|Help|System|Category');
    76 		$session->register_acl_type('tag_delete_other',       AUTH_DISALLOW, 'perm_tag_delete_other',       Array('read'),                                            'Article|User|Project|Template|File|Help|System|Category');
    77     $session->register_acl_type('set_wiki_mode',          AUTH_DISALLOW, 'perm_set_wiki_mode',          Array('read'),                                            'Article|User|Project|Template|File|Help|System|Category');
    77 		$session->register_acl_type('set_wiki_mode',          AUTH_DISALLOW, 'perm_set_wiki_mode',          Array('read'),                                            'Article|User|Project|Template|File|Help|System|Category');
    78     $session->register_acl_type('password_set',           AUTH_DISALLOW, 'perm_password_set',           Array('read'),                                            'Article|User|Project|Template|File|Help|System|Category');
    78 		$session->register_acl_type('password_set',           AUTH_DISALLOW, 'perm_password_set',           Array('read'),                                            'Article|User|Project|Template|File|Help|System|Category');
    79     $session->register_acl_type('password_reset',         AUTH_DISALLOW, 'perm_password_reset',         Array('read'),                                            'Article|User|Project|Template|File|Help|System|Category');
    79 		$session->register_acl_type('password_reset',         AUTH_DISALLOW, 'perm_password_reset',         Array('read'),                                            'Article|User|Project|Template|File|Help|System|Category');
    80     $session->register_acl_type('mod_misc',               AUTH_DISALLOW, 'perm_mod_misc',               Array(),                                                  'All');
    80 		$session->register_acl_type('mod_misc',               AUTH_DISALLOW, 'perm_mod_misc',               Array(),                                                  'All');
    81     $session->register_acl_type('edit_cat',               AUTH_WIKIMODE, 'perm_edit_cat',               Array('read'),                                            'Article|User|Project|Template|File|Help|System|Category');
    81 		$session->register_acl_type('edit_cat',               AUTH_WIKIMODE, 'perm_edit_cat',               Array('read'),                                            'Article|User|Project|Template|File|Help|System|Category');
    82     $session->register_acl_type('even_when_protected',    AUTH_DISALLOW, 'perm_even_when_protected',    Array('edit_page', 'rename', 'mod_comments', 'edit_cat'), 'Article|User|Project|Template|File|Help|System|Category');
    82 		$session->register_acl_type('even_when_protected',    AUTH_DISALLOW, 'perm_even_when_protected',    Array('edit_page', 'rename', 'mod_comments', 'edit_cat'), 'Article|User|Project|Template|File|Help|System|Category');
    83     $session->register_acl_type('create_page',            AUTH_WIKIMODE, 'perm_create_page',            Array(),                                                  'All');
    83 		$session->register_acl_type('create_page',            AUTH_WIKIMODE, 'perm_create_page',            Array(),                                                  'All');
    84     $session->register_acl_type('upload_files',           AUTH_DISALLOW, 'perm_upload_files',           Array('create_page'),                                     'All');
    84 		$session->register_acl_type('upload_files',           AUTH_DISALLOW, 'perm_upload_files',           Array('create_page'),                                     'All');
    85     $session->register_acl_type('upload_new_version',     AUTH_WIKIMODE, 'perm_upload_new_version',     Array('upload_files'),                                    'All');
    85 		$session->register_acl_type('upload_new_version',     AUTH_WIKIMODE, 'perm_upload_new_version',     Array('upload_files'),                                    'All');
    86     $session->register_acl_type('html_in_pages',          AUTH_DISALLOW, 'perm_html_in_pages',          Array('edit_page'),                                       'Article|User|Project|Template|File|Help|System|Category|Admin');
    86 		$session->register_acl_type('html_in_pages',          AUTH_DISALLOW, 'perm_html_in_pages',          Array('edit_page'),                                       'Article|User|Project|Template|File|Help|System|Category|Admin');
    87     $session->register_acl_type('php_in_pages',           AUTH_DISALLOW, 'perm_php_in_pages',           Array('edit_page', 'html_in_pages'),                      'Article|User|Project|Template|File|Help|System|Category|Admin');
    87 		$session->register_acl_type('php_in_pages',           AUTH_DISALLOW, 'perm_php_in_pages',           Array('edit_page', 'html_in_pages'),                      'Article|User|Project|Template|File|Help|System|Category|Admin');
    88     $session->register_acl_type('custom_user_title',      AUTH_DISALLOW, 'perm_custom_user_title',      Array(),                                                  'User|Special');
    88 		$session->register_acl_type('custom_user_title',      AUTH_DISALLOW, 'perm_custom_user_title',      Array(),                                                  'User|Special');
    89     $session->register_acl_type('edit_acl',               AUTH_DISALLOW, 'perm_edit_acl',               Array());
    89 		$session->register_acl_type('edit_acl',               AUTH_DISALLOW, 'perm_edit_acl',               Array());
    90     
    90 		
    91     // DO NOT add new admin pages here! Use a plugin to call $paths->addAdminNode();
    91 		// DO NOT add new admin pages here! Use a plugin to call $paths->addAdminNode();
    92     $this->addAdminNode('adm_cat_general',    'adm_page_general_config', 'GeneralConfig',          array(2, 2));
    92 		$this->addAdminNode('adm_cat_general',    'adm_page_general_config', 'GeneralConfig',          array(2, 2));
    93     $this->addAdminNode('adm_cat_general',    'adm_page_file_uploads',   'UploadConfig',           array(2, 5));
    93 		$this->addAdminNode('adm_cat_general',    'adm_page_file_uploads',   'UploadConfig',           array(2, 5));
    94     $this->addAdminNode('adm_cat_general',    'adm_page_file_types',     'UploadAllowedMimeTypes', array(1, 5));
    94 		$this->addAdminNode('adm_cat_general',    'adm_page_file_types',     'UploadAllowedMimeTypes', array(1, 5));
    95     $this->addAdminNode('adm_cat_content',    'adm_page_manager',        'PageManager',            array(1, 4));
    95 		$this->addAdminNode('adm_cat_content',    'adm_page_manager',        'PageManager',            array(1, 4));
    96     $this->addAdminNode('adm_cat_content',    'adm_page_editor',         'PageEditor',             array(3, 3));
    96 		$this->addAdminNode('adm_cat_content',    'adm_page_editor',         'PageEditor',             array(3, 3));
    97     $this->addAdminNode('adm_cat_content',    'adm_page_pg_groups',      'PageGroups',             array(4, 3));
    97 		$this->addAdminNode('adm_cat_content',    'adm_page_pg_groups',      'PageGroups',             array(4, 3));
    98     $this->addAdminNode('adm_cat_appearance', 'adm_page_themes',         'ThemeManager',           array(4, 4));
    98 		$this->addAdminNode('adm_cat_appearance', 'adm_page_themes',         'ThemeManager',           array(4, 4));
    99     $this->addAdminNode('adm_cat_appearance', 'adm_page_plugins',        'PluginManager',          array(2, 4));
    99 		$this->addAdminNode('adm_cat_appearance', 'adm_page_plugins',        'PluginManager',          array(2, 4));
   100     $this->addAdminNode('adm_cat_appearance', 'adm_page_db_backup',      'DBBackup',               array(1, 2));
   100 		$this->addAdminNode('adm_cat_appearance', 'adm_page_db_backup',      'DBBackup',               array(1, 2));
   101     $this->addAdminNode('adm_cat_appearance', 'adm_page_lang_manager',   'LangManager',            array(1, 3));
   101 		$this->addAdminNode('adm_cat_appearance', 'adm_page_lang_manager',   'LangManager',            array(1, 3));
   102     $this->addAdminNode('adm_cat_appearance', 'adm_page_cache_manager',  'CacheManager',           array(3, 1));
   102 		$this->addAdminNode('adm_cat_appearance', 'adm_page_cache_manager',  'CacheManager',           array(3, 1));
   103     $this->addAdminNode('adm_cat_users',      'adm_page_users',          'UserManager',            array(3, 5));
   103 		$this->addAdminNode('adm_cat_users',      'adm_page_users',          'UserManager',            array(3, 5));
   104     $this->addAdminNode('adm_cat_users',      'adm_page_user_groups',    'GroupManager',           array(3, 2));
   104 		$this->addAdminNode('adm_cat_users',      'adm_page_user_groups',    'GroupManager',           array(3, 2));
   105     $this->addAdminNode('adm_cat_users',      'adm_page_coppa',          'COPPA',                  array(4, 1));
   105 		$this->addAdminNode('adm_cat_users',      'adm_page_coppa',          'COPPA',                  array(4, 1));
   106     $this->addAdminNode('adm_cat_users',      'adm_page_mass_email',     'MassEmail',              array(2, 3));
   106 		$this->addAdminNode('adm_cat_users',      'adm_page_mass_email',     'MassEmail',              array(2, 3));
   107     $this->addAdminNode('adm_cat_users',      'adm_page_user_ranks',     'UserRanks',              array(4, 5));
   107 		$this->addAdminNode('adm_cat_users',      'adm_page_user_ranks',     'UserRanks',              array(4, 5));
   108     $this->addAdminNode('adm_cat_security',   'adm_page_security_log',   'SecurityLog',            array(3, 4));
   108 		$this->addAdminNode('adm_cat_security',   'adm_page_security_log',   'SecurityLog',            array(3, 4));
   109     $this->addAdminNode('adm_cat_security',   'adm_page_ban_control',    'BanControl',             array(2, 1));
   109 		$this->addAdminNode('adm_cat_security',   'adm_page_ban_control',    'BanControl',             array(2, 1));
   110     
   110 		
   111     $code = $plugins->setHook('acl_rule_init');
   111 		$code = $plugins->setHook('acl_rule_init');
   112     foreach ( $code as $cmd )
   112 		foreach ( $code as $cmd )
   113     {
   113 		{
   114       eval($cmd);
   114 			eval($cmd);
   115     }
   115 		}
   116     
   116 		
   117     $this->wiki_mode = ( getConfig('wiki_mode') == '1' ) ? 1 : 0;
   117 		$this->wiki_mode = ( getConfig('wiki_mode') == '1' ) ? 1 : 0;
   118     $this->template_cache = Array();
   118 		$this->template_cache = Array();
   119   }
   119 	}
   120   
   120 	
   121   function init($title)
   121 	function init($title)
   122   {
   122 	{
   123     global $db, $session, $paths, $template, $plugins; // Common objects
   123 		global $db, $session, $paths, $template, $plugins; // Common objects
   124     global $lang;
   124 		global $lang;
   125     global $cache;
   125 		global $cache;
   126     
   126 		
   127     $code = $plugins->setHook('paths_init_before');
   127 		$code = $plugins->setHook('paths_init_before');
   128     foreach ( $code as $cmd )
   128 		foreach ( $code as $cmd )
   129     {
   129 		{
   130       eval($cmd);
   130 			eval($cmd);
   131     }
   131 		}
   132     
   132 		
   133     if ( defined('ENANO_INTERFACE_INDEX') || defined('ENANO_INTERFACE_AJAX') || defined('IN_ENANO_UPGRADE') )
   133 		if ( defined('ENANO_INTERFACE_INDEX') || defined('ENANO_INTERFACE_AJAX') || defined('IN_ENANO_UPGRADE') )
   134     {
   134 		{
   135       if ( empty($title) )
   135 			if ( empty($title) )
   136         $title = get_title();
   136 				$title = get_title();
   137       
   137 			
   138       if ( empty($title) && !have_blank_urlname_page() )
   138 			if ( empty($title) && !have_blank_urlname_page() )
   139       {
   139 			{
   140         $this->main_page();
   140 				$this->main_page();
   141       }
   141 			}
   142       if ( strstr($title, ' ') || strstr($title, '+') || strstr($title, '%20') )
   142 			if ( strstr($title, ' ') || strstr($title, '+') || strstr($title, '%20') )
   143       {
   143 			{
   144         $title = sanitize_page_id($title);
   144 				$title = sanitize_page_id($title);
   145         redirect(makeUrl($title), '', '', 0);
   145 				redirect(makeUrl($title), '', '', 0);
   146       }
   146 			}
   147       $title = sanitize_page_id($title);
   147 			$title = sanitize_page_id($title);
   148       // We've got the title, pull the namespace from it
   148 			// We've got the title, pull the namespace from it
   149       $namespace = 'Article';
   149 			$namespace = 'Article';
   150       $page_id = $title;
   150 			$page_id = $title;
   151       foreach ( $this->nslist as $ns => $prefix )
   151 			foreach ( $this->nslist as $ns => $prefix )
   152       {
   152 			{
   153         $prefix_len = strlen($prefix);
   153 				$prefix_len = strlen($prefix);
   154         if ( substr($title, 0, $prefix_len) == $prefix )
   154 				if ( substr($title, 0, $prefix_len) == $prefix )
   155         {
   155 				{
   156           $page_id = substr($title, $prefix_len);
   156 					$page_id = substr($title, $prefix_len);
   157           $namespace = $ns;
   157 					$namespace = $ns;
   158         }
   158 				}
   159       }
   159 			}
   160       $this->namespace = $namespace;
   160 			$this->namespace = $namespace;
   161       $this->fullpage = $title;
   161 			$this->fullpage = $title;
   162       if ( $namespace == 'Special' || $namespace == 'Admin' )
   162 			if ( $namespace == 'Special' || $namespace == 'Admin' )
   163       {
   163 			{
   164         list($page_id) = explode('/', $page_id);
   164 				list($page_id) = explode('/', $page_id);
   165       }
   165 			}
   166       $this->page = $this->nslist[$namespace] . $page_id;
   166 			$this->page = $this->nslist[$namespace] . $page_id;
   167       $this->page_id = $page_id;
   167 			$this->page_id = $page_id;
   168       // die("All done setting parameters. What we've got:<br/>namespace: $namespace<br/>fullpage: $this->fullpage<br/>page: $this->page<br/>page_id: $this->page_id");
   168 			// die("All done setting parameters. What we've got:<br/>namespace: $namespace<br/>fullpage: $this->fullpage<br/>page: $this->page<br/>page_id: $this->page_id");
   169     }
   169 		}
   170     else
   170 		else
   171     {
   171 		{
   172       // Starting up Enano with the API from a page that wants to do its own thing. Generate
   172 			// Starting up Enano with the API from a page that wants to do its own thing. Generate
   173       // metadata for an anonymous page and avoid redirection at all costs.
   173 			// metadata for an anonymous page and avoid redirection at all costs.
   174       if ( isset($GLOBALS['title']) )
   174 			if ( isset($GLOBALS['title']) )
   175       {
   175 			{
   176         $title =& $GLOBALS['title'];
   176 				$title =& $GLOBALS['title'];
   177       }
   177 			}
   178       else
   178 			else
   179       {
   179 			{
   180         $title = basename($_SERVER['SCRIPT_NAME']);
   180 				$title = basename($_SERVER['SCRIPT_NAME']);
   181       }
   181 			}
   182       $base_uri = scriptPath == '' ? ltrim($_SERVER['SCRIPT_NAME'], '/') : str_replace( scriptPath . '/', '', $_SERVER['SCRIPT_NAME'] );
   182 			$base_uri = scriptPath == '' ? ltrim($_SERVER['SCRIPT_NAME'], '/') : str_replace( scriptPath . '/', '', $_SERVER['SCRIPT_NAME'] );
   183       
   183 			
   184       $this->page = $this->nslist['API'] . sanitize_page_id($base_uri);
   184 			$this->page = $this->nslist['API'] . sanitize_page_id($base_uri);
   185       $this->fullpage = $this->nslist['API'] . sanitize_page_id($base_uri);
   185 			$this->fullpage = $this->nslist['API'] . sanitize_page_id($base_uri);
   186       $this->namespace = 'API';
   186 			$this->namespace = 'API';
   187       $this->cpage = array(
   187 			$this->cpage = array(
   188           'name' => $title,
   188 					'name' => $title,
   189           'urlname' => sanitize_page_id($base_uri),
   189 					'urlname' => sanitize_page_id($base_uri),
   190           'namespace' => 'API',
   190 					'namespace' => 'API',
   191           'special' => 1,
   191 					'special' => 1,
   192           'visible' => 1,
   192 					'visible' => 1,
   193           'comments_on' => 1,
   193 					'comments_on' => 1,
   194           'protected' => 1,
   194 					'protected' => 1,
   195           'delvotes' => 0,
   195 					'delvotes' => 0,
   196           'delvote_ips' => '',
   196 					'delvote_ips' => '',
   197           'page_format' => getConfig('default_page_format', 'wikitext')
   197 					'page_format' => getConfig('default_page_format', 'wikitext')
   198         );
   198 				);
   199       $this->external_api_page = true;
   199 			$this->external_api_page = true;
   200       $code = $plugins->setHook('paths_external_api_page');
   200 			$code = $plugins->setHook('paths_external_api_page');
   201       foreach ( $code as $cmd )
   201 			foreach ( $code as $cmd )
   202       {
   202 			{
   203         eval($cmd);
   203 				eval($cmd);
   204       }
   204 			}
   205     }
   205 		}
   206     
   206 		
   207     $this->page = sanitize_page_id($this->page);
   207 		$this->page = sanitize_page_id($this->page);
   208     $this->fullpage = sanitize_page_id($this->fullpage);
   208 		$this->fullpage = sanitize_page_id($this->fullpage);
   209     
   209 		
   210     if(isset($this->pages[$this->page]))
   210 		if(isset($this->pages[$this->page]))
   211     {
   211 		{
   212       $this->page_exists = true;
   212 			$this->page_exists = true;
   213       $this->cpage = $this->pages[$this->page];
   213 			$this->cpage = $this->pages[$this->page];
   214       $this->page_id =& $this->cpage['urlname_nons'];
   214 			$this->page_id =& $this->cpage['urlname_nons'];
   215       $this->namespace = $this->cpage['namespace'];
   215 			$this->namespace = $this->cpage['namespace'];
   216       if(!isset($this->cpage['wiki_mode'])) $this->cpage['wiki_mode'] = 2;
   216 			if(!isset($this->cpage['wiki_mode'])) $this->cpage['wiki_mode'] = 2;
   217       
   217 			
   218       // Determine the wiki mode for this page, now that we have this->cpage established
   218 			// Determine the wiki mode for this page, now that we have this->cpage established
   219       if($this->cpage['wiki_mode'] == 2)
   219 			if($this->cpage['wiki_mode'] == 2)
   220       {
   220 			{
   221         $this->wiki_mode = (int)getConfig('wiki_mode');
   221 				$this->wiki_mode = (int)getConfig('wiki_mode');
   222       }
   222 			}
   223       else
   223 			else
   224       {
   224 			{
   225         $this->wiki_mode = $this->cpage['wiki_mode'];
   225 				$this->wiki_mode = $this->cpage['wiki_mode'];
   226       }
   226 			}
   227       // Allow the user to create/modify his user page uncondtionally (admins can still protect the page)
   227 			// Allow the user to create/modify his user page uncondtionally (admins can still protect the page)
   228       if($this->page == $this->nslist['User'].str_replace(' ', '_', $session->username))
   228 			if($this->page == $this->nslist['User'].str_replace(' ', '_', $session->username))
   229       {
   229 			{
   230         $this->wiki_mode = true;
   230 				$this->wiki_mode = true;
   231       }
   231 			}
   232       // And above all, if the site requires wiki mode to be off for non-logged-in users, disable it now
   232 			// And above all, if the site requires wiki mode to be off for non-logged-in users, disable it now
   233       if(getConfig('wiki_mode_require_login')=='1' && !$session->user_logged_in)
   233 			if(getConfig('wiki_mode_require_login')=='1' && !$session->user_logged_in)
   234       {
   234 			{
   235         $this->wiki_mode = false;
   235 				$this->wiki_mode = false;
   236       }
   236 			}
   237       if($this->cpage['protected'] == 2)
   237 			if($this->cpage['protected'] == 2)
   238       {
   238 			{
   239         // The page is semi-protected, determine permissions
   239 				// The page is semi-protected, determine permissions
   240         if($session->user_logged_in && $session->reg_time + 60*60*24*4 < time()) 
   240 				if($session->user_logged_in && $session->reg_time + 60*60*24*4 < time()) 
   241         {
   241 				{
   242           $this->page_protected = 0;
   242 					$this->page_protected = 0;
   243         }
   243 				}
   244         else
   244 				else
   245         {
   245 				{
   246           $this->page_protected = 1;
   246 					$this->page_protected = 1;
   247         }
   247 				}
   248       }
   248 			}
   249       else
   249 			else
   250       {
   250 			{
   251         $this->page_protected = $this->cpage['protected'];
   251 				$this->page_protected = $this->cpage['protected'];
   252       }
   252 			}
   253     }
   253 		}
   254     else
   254 		else
   255     {
   255 		{
   256       $this->page_exists = false;
   256 			$this->page_exists = false;
   257       $page_name = dirtify_page_id($this->page);
   257 			$page_name = dirtify_page_id($this->page);
   258       $page_name = str_replace('_', ' ', $page_name);
   258 			$page_name = str_replace('_', ' ', $page_name);
   259       
   259 			
   260       $pid_cleaned = sanitize_page_id($this->page);
   260 			$pid_cleaned = sanitize_page_id($this->page);
   261       if ( $pid_cleaned != $this->page )
   261 			if ( $pid_cleaned != $this->page )
   262       {
   262 			{
   263         redirect(makeUrl($pid_cleaned), 'Sanitizer message', 'page id sanitized', 0);
   263 				redirect(makeUrl($pid_cleaned), 'Sanitizer message', 'page id sanitized', 0);
   264       }
   264 			}
   265       
   265 			
   266       if ( !is_array($this->cpage) )
   266 			if ( !is_array($this->cpage) )
   267       {
   267 			{
   268         $this->cpage = Array(
   268 				$this->cpage = Array(
   269           'name' => $page_name,
   269 					'name' => $page_name,
   270           'urlname' => $this->page,
   270 					'urlname' => $this->page,
   271           'namespace' => 'Article',
   271 					'namespace' => 'Article',
   272           'special' => 0,
   272 					'special' => 0,
   273           'visible' => 0,
   273 					'visible' => 0,
   274           'comments_on' => 1,
   274 					'comments_on' => 1,
   275           'protected' => 0,
   275 					'protected' => 0,
   276           'delvotes' => 0,
   276 					'delvotes' => 0,
   277           'delvote_ips' => '',
   277 					'delvote_ips' => '',
   278           'wiki_mode' => 2,
   278 					'wiki_mode' => 2,
   279           'page_format' => getConfig('default_page_format', 'wikitext')
   279 					'page_format' => getConfig('default_page_format', 'wikitext')
   280           );
   280 					);
   281       }
   281 			}
   282       // Look for a namespace prefix in the urlname, and assign a different namespace, if necessary
   282 			// Look for a namespace prefix in the urlname, and assign a different namespace, if necessary
   283       $k = array_keys($this->nslist);
   283 			$k = array_keys($this->nslist);
   284       for($i=0;$i<sizeof($this->nslist);$i++)
   284 			for($i=0;$i<sizeof($this->nslist);$i++)
   285       {
   285 			{
   286         $ln = strlen($this->nslist[$k[$i]]);
   286 				$ln = strlen($this->nslist[$k[$i]]);
   287         if( substr($this->page, 0, $ln) == $this->nslist[$k[$i]] )
   287 				if( substr($this->page, 0, $ln) == $this->nslist[$k[$i]] )
   288         {
   288 				{
   289           $this->cpage['namespace'] = $k[$i];
   289 					$this->cpage['namespace'] = $k[$i];
   290           $this->cpage['urlname_nons'] = substr($this->page, strlen($this->nslist[$this->cpage['namespace']]), strlen($this->page));
   290 					$this->cpage['urlname_nons'] = substr($this->page, strlen($this->nslist[$this->cpage['namespace']]), strlen($this->page));
   291           if(!isset($this->cpage['wiki_mode'])) 
   291 					if(!isset($this->cpage['wiki_mode'])) 
   292           {
   292 					{
   293             $this->cpage['wiki_mode'] = 2;
   293 						$this->cpage['wiki_mode'] = 2;
   294           }
   294 					}
   295         }
   295 				}
   296       }
   296 			}
   297       $this->namespace = $this->cpage['namespace'];
   297 			$this->namespace = $this->cpage['namespace'];
   298       $this->page_id =& $this->cpage['urlname_nons'];
   298 			$this->page_id =& $this->cpage['urlname_nons'];
   299       
   299 			
   300       if($this->namespace=='System') 
   300 			if($this->namespace=='System') 
   301       {
   301 			{
   302         $this->cpage['protected'] = 1;
   302 				$this->cpage['protected'] = 1;
   303       }
   303 			}
   304       if($this->namespace == 'Special' && !$this->external_api_page)
   304 			if($this->namespace == 'Special' && !$this->external_api_page)
   305       {
   305 			{
   306         // Can't load nonexistent pages
   306 				// Can't load nonexistent pages
   307         if( is_string(get_main_page()) )
   307 				if( is_string(get_main_page()) )
   308         {
   308 				{
   309           $main_page = makeUrl(get_main_page());
   309 					$main_page = makeUrl(get_main_page());
   310         }
   310 				}
   311         else
   311 				else
   312         {
   312 				{
   313           $main_page = makeUrl($this->pages[0]['urlname']);
   313 					$main_page = makeUrl($this->pages[0]['urlname']);
   314         }
   314 				}
   315         redirect($main_page, $lang->get('page_msg_special_404_title'), $lang->get('page_msg_special_404_body', array('sp_link' => makeUrlNS('Special', 'SpecialPages'))), 15);
   315 				redirect($main_page, $lang->get('page_msg_special_404_title'), $lang->get('page_msg_special_404_body', array('sp_link' => makeUrlNS('Special', 'SpecialPages'))), 15);
   316         exit;
   316 				exit;
   317       }
   317 			}
   318       // Allow the user to create/modify his user page uncondtionally (admins can still protect the page)
   318 			// Allow the user to create/modify his user page uncondtionally (admins can still protect the page)
   319       if($this->page == $this->nslist['User'].str_replace(' ', '_', $session->username)) 
   319 			if($this->page == $this->nslist['User'].str_replace(' ', '_', $session->username)) 
   320       {
   320 			{
   321         $this->wiki_mode = true;
   321 				$this->wiki_mode = true;
   322       }
   322 			}
   323     }
   323 		}
   324     // This is used in the admin panel to keep track of form submission targets
   324 		// This is used in the admin panel to keep track of form submission targets
   325     $this->cpage['module'] = $this->cpage['urlname'];
   325 		$this->cpage['module'] = $this->cpage['urlname'];
   326     
   326 		
   327     $this->cpage['require_admin'] = ( $this->cpage['namespace'] === 'Admin' );
   327 		$this->cpage['require_admin'] = ( $this->cpage['namespace'] === 'Admin' );
   328     
   328 		
   329     // Page is set up, call any hooks
   329 		// Page is set up, call any hooks
   330     $code = $plugins->setHook('page_set');
   330 		$code = $plugins->setHook('page_set');
   331     foreach ( $code as $cmd )
   331 		foreach ( $code as $cmd )
   332     {
   332 		{
   333       eval($cmd);
   333 			eval($cmd);
   334     }
   334 		}
   335    
   335  	
   336     profiler_log('Paths and CMS core initted');
   336 		profiler_log('Paths and CMS core initted');
   337     $session->init_permissions();
   337 		$session->init_permissions();
   338   }
   338 	}
   339   
   339 	
   340   /**
   340 	/**
   341    * Fetch cdata (metadata) for a page.
   341  	* Fetch cdata (metadata) for a page.
   342    * @param string Page ID
   342  	* @param string Page ID
   343    * @param string Namespace
   343  	* @param string Namespace
   344    * @return array
   344  	* @return array
   345    */
   345  	*/
   346   
   346 	
   347   function get_cdata($page_id, $namespace)
   347 	function get_cdata($page_id, $namespace)
   348   {
   348 	{
   349     global $db, $session, $paths, $template, $plugins; // Common objects
   349 		global $db, $session, $paths, $template, $plugins; // Common objects
   350     
   350 		
   351     $pathskey = $this->get_pathskey($page_id, $namespace);
   351 		$pathskey = $this->get_pathskey($page_id, $namespace);
   352     if ( isset($this->pages[$pathskey]) )
   352 		if ( isset($this->pages[$pathskey]) )
   353       return $this->pages[$pathskey];
   353 			return $this->pages[$pathskey];
   354     
   354 		
   355     $page = namespace_factory($page_id, $namespace);
   355 		$page = namespace_factory($page_id, $namespace);
   356     $cdata = $page->get_cdata();
   356 		$cdata = $page->get_cdata();
   357     
   357 		
   358     $this->pages[$pathskey] = $cdata;
   358 		$this->pages[$pathskey] = $cdata;
   359     return $cdata;
   359 		return $cdata;
   360   }
   360 	}
   361   
   361 	
   362   /**
   362 	/**
   363    * For a given page ID and namespace, generate a flat string that can be used to access $paths->pages.
   363  	* For a given page ID and namespace, generate a flat string that can be used to access $paths->pages.
   364    * @param string Page ID
   364  	* @param string Page ID
   365    * @param string Namespace
   365  	* @param string Namespace
   366    */
   366  	*/
   367   
   367 	
   368   function get_pathskey($page_id, $namespace)
   368 	function get_pathskey($page_id, $namespace)
   369   {
   369 	{
   370     return ( isset($this->nslist[$namespace]) ) ? "{$this->nslist[$namespace]}{$page_id}" : "{$namespace}:{$page_id}";
   370 		return ( isset($this->nslist[$namespace]) ) ? "{$this->nslist[$namespace]}{$page_id}" : "{$namespace}:{$page_id}";
   371   }
   371 	}
   372   
   372 	
   373   function add_page($flags)
   373 	function add_page($flags)
   374   {
   374 	{
   375     global $lang;
   375 		global $lang;
   376     $flags['urlname_nons'] = $flags['urlname'];
   376 		$flags['urlname_nons'] = $flags['urlname'];
   377     $flags['urlname'] = $this->nslist[$flags['namespace']] . $flags['urlname']; // Applies the User:/File:/etc prefixes to the URL names
   377 		$flags['urlname'] = $this->nslist[$flags['namespace']] . $flags['urlname']; // Applies the User:/File:/etc prefixes to the URL names
   378     
   378 		
   379     if ( is_object($lang) )
   379 		if ( is_object($lang) )
   380     {
   380 		{
   381       if ( preg_match('/^[a-z0-9]+_[a-z0-9_]+$/', $flags['name']) )
   381 			if ( preg_match('/^[a-z0-9]+_[a-z0-9_]+$/', $flags['name']) )
   382         $flags['name'] = $lang->get($flags['name']);
   382 				$flags['name'] = $lang->get($flags['name']);
   383     }
   383 		}
   384     
   384 		
   385     $flags['require_admin'] = ( $flags['namespace'] === 'Admin' );
   385 		$flags['require_admin'] = ( $flags['namespace'] === 'Admin' );
   386     $flags['page_exists'] = true;
   386 		$flags['page_exists'] = true;
   387     
   387 		
   388     $this->pages[$flags['urlname']] = $flags;
   388 		$this->pages[$flags['urlname']] = $flags;
   389   }
   389 	}
   390   
   390 	
   391   function main_page()
   391 	function main_page()
   392   {
   392 	{
   393     if( is_string(get_main_page()) )
   393 		if( is_string(get_main_page()) )
   394     {
   394 		{
   395       $main_page = makeUrl(get_main_page());
   395 			$main_page = makeUrl(get_main_page());
   396     }
   396 		}
   397     else
   397 		else
   398     {
   398 		{
   399       $main_page = makeUrl($this->pages[0]['urlname']);
   399 			$main_page = makeUrl($this->pages[0]['urlname']);
   400     }
   400 		}
   401     redirect($main_page, 'Redirecting...', 'Invalid request, redirecting to main page', 0);
   401 		redirect($main_page, 'Redirecting...', 'Invalid request, redirecting to main page', 0);
   402     exit;
   402 		exit;
   403   }
   403 	}
   404   
   404 	
   405   function sysmsg($n)
   405 	function sysmsg($n)
   406   {
   406 	{
   407     global $db, $session, $paths, $template, $plugins; // Common objects
   407 		global $db, $session, $paths, $template, $plugins; // Common objects
   408     static $sm_cache = array();
   408 		static $sm_cache = array();
   409     
   409 		
   410     if ( isset($sm_cache[$n]) )
   410 		if ( isset($sm_cache[$n]) )
   411       return $sm_cache[$n];
   411 			return $sm_cache[$n];
   412     
   412 		
   413     // sometimes this gets called during die_semicritical()...
   413 		// sometimes this gets called during die_semicritical()...
   414     if ( !is_object($db) )
   414 		if ( !is_object($db) )
   415       return false;
   415 			return false;
   416     
   416 		
   417     if ( !@$db->_conn )
   417 		if ( !@$db->_conn )
   418       return false;
   418 			return false;
   419     
   419 		
   420     $q = $db->sql_query('SELECT page_text, char_tag FROM '.table_prefix.'page_text WHERE page_id=\''.$db->escape(sanitize_page_id($n)).'\' AND namespace=\'System\'');
   420 		$q = $db->sql_query('SELECT page_text, char_tag FROM '.table_prefix.'page_text WHERE page_id=\''.$db->escape(sanitize_page_id($n)).'\' AND namespace=\'System\'');
   421     if( !$q )
   421 		if( !$q )
   422     {
   422 		{
   423       $db->_die('Error during generic selection of system page data.');
   423 			$db->_die('Error during generic selection of system page data.');
   424     }
   424 		}
   425     if($db->numrows() < 1)
   425 		if($db->numrows() < 1)
   426     {
   426 		{
   427       return false;
   427 			return false;
   428       //$db->_die('Error during generic selection of system page data: there were no rows in the text table that matched the page text query.');
   428 			//$db->_die('Error during generic selection of system page data: there were no rows in the text table that matched the page text query.');
   429     }
   429 		}
   430     $r = $db->fetchrow();
   430 		$r = $db->fetchrow();
   431     $db->free_result();
   431 		$db->free_result();
   432     $message = $r['page_text'];
   432 		$message = $r['page_text'];
   433     
   433 		
   434     $message = preg_replace('/<noinclude>(.*?)<\/noinclude>/is', '', $message);
   434 		$message = preg_replace('/<noinclude>(.*?)<\/noinclude>/is', '', $message);
   435     $message = preg_replace('/<nodisplay>(.*?)<\/nodisplay>/is', '\\1', $message);
   435 		$message = preg_replace('/<nodisplay>(.*?)<\/nodisplay>/is', '\\1', $message);
   436     
   436 		
   437     $sm_cache[$n] = $message;
   437 		$sm_cache[$n] = $message;
   438     
   438 		
   439     return $message;
   439 		return $message;
   440   }
   440 	}
   441   function get_pageid_from_url()
   441 	function get_pageid_from_url()
   442   {
   442 	{
   443     return get_title(true, true);
   443 		return get_title(true, true);
   444   }
   444 	}
   445   // Parses a (very carefully formed) array into Javascript code compatible with the Tigra Tree Menu used in the admin menu
   445 	// Parses a (very carefully formed) array into Javascript code compatible with the Tigra Tree Menu used in the admin menu
   446   function parseAdminTree() 
   446 	function parseAdminTree() 
   447   {
   447 	{
   448     global $lang;
   448 		global $lang;
   449     
   449 		
   450     $k = array_keys($this->admin_tree);
   450 		$k = array_keys($this->admin_tree);
   451     $i = 0;
   451 		$i = 0;
   452     $ret = '';
   452 		$ret = '';
   453     $icon = $this->make_sprite_icon(4, 2);
   453 		$icon = $this->make_sprite_icon(4, 2);
   454     $ret .= "var TREE_ITEMS = ";
   454 		$ret .= "var TREE_ITEMS = ";
   455     $tree = array(
   455 		$tree = array(
   456         array($icon . $lang->get('adm_btn_home'), "javascript:ajaxPage('{$this->nslist['Admin']}Home');")
   456 				array($icon . $lang->get('adm_btn_home'), "javascript:ajaxPage('{$this->nslist['Admin']}Home');")
   457       );
   457 			);
   458     
   458 		
   459     $root =& $tree[0];
   459 		$root =& $tree[0];
   460     
   460 		
   461     foreach($k as $key)
   461 		foreach($k as $key)
   462     {
   462 		{
   463       $i++;
   463 			$i++;
   464       $name = $lang->get($key);
   464 			$name = $lang->get($key);
   465       $group = array($name, "javascript:trees[0].toggle($i)");
   465 			$group = array($name, "javascript:trees[0].toggle($i)");
   466       
   466 			
   467       foreach($this->admin_tree[$key] as $nodeid => $c)
   467 			foreach($this->admin_tree[$key] as $nodeid => $c)
   468       {
   468 			{
   469         $i++;
   469 				$i++;
   470         $name = $lang->get($c['name']);
   470 				$name = $lang->get($c['name']);
   471         if ( $c['icon'] && $c['icon'] != cdnPath . '/images/spacer.gif' )
   471 				if ( $c['icon'] && $c['icon'] != cdnPath . '/images/spacer.gif' )
   472         {
   472 				{
   473           if ( is_array($c['icon']) )
   473 					if ( is_array($c['icon']) )
   474           {
   474 					{
   475             // this is a sprite reference
   475 						// this is a sprite reference
   476             list($ix, $iy) = $c['icon'];
   476 						list($ix, $iy) = $c['icon'];
   477             $icon = $this->make_sprite_icon($ix, $iy);
   477 						$icon = $this->make_sprite_icon($ix, $iy);
   478           }
   478 					}
   479           else
   479 					else
   480           {
   480 					{
   481             $icon = "<img alt=\"\" src=\"{$c['icon']}\" style=\"border-width: 0; margin-right: 3px;\" /> ";
   481 						$icon = "<img alt=\"\" src=\"{$c['icon']}\" style=\"border-width: 0; margin-right: 3px;\" /> ";
   482           }
   482 					}
   483         }
   483 				}
   484         else
   484 				else
   485         {
   485 				{
   486           $icon = '';
   486 					$icon = '';
   487         }
   487 				}
   488         $group[] = array("$icon$name", "javascript:ajaxPage('{$this->nslist['Admin']}{$c['pageid']}');");
   488 				$group[] = array("$icon$name", "javascript:ajaxPage('{$this->nslist['Admin']}{$c['pageid']}');");
   489       }
   489 			}
   490       
   490 			
   491       $root[] = $group;
   491 			$root[] = $group;
   492     }
   492 		}
   493     $icon = $this->make_sprite_icon(1, 1);
   493 		$icon = $this->make_sprite_icon(1, 1);
   494     $root[] = array(
   494 		$root[] = array(
   495         $icon . $lang->get('adm_btn_logout'),
   495 				$icon . $lang->get('adm_btn_logout'),
   496         "javascript:ajaxPage('{$this->nslist['Admin']}AdminLogout');"
   496 				"javascript:ajaxPage('{$this->nslist['Admin']}AdminLogout');"
   497       );
   497 			);
   498     $root[] = array(
   498 		$root[] = array(
   499         "<span id=\"keepalivestat\">" . $lang->get('adm_btn_keepalive_loading') . "</span>",
   499 				"<span id=\"keepalivestat\">" . $lang->get('adm_btn_keepalive_loading') . "</span>",
   500         "javascript:ajaxToggleKeepalive();",
   500 				"javascript:ajaxToggleKeepalive();",
   501         array(
   501 				array(
   502             $lang->get('adm_btn_keepalive_about'),
   502 						$lang->get('adm_btn_keepalive_about'),
   503             "javascript:aboutKeepAlive();"
   503 						"javascript:aboutKeepAlive();"
   504           )
   504 					)
   505       );
   505 			);
   506     
   506 		
   507     $ret .= enano_json_encode($tree) . ';';
   507 		$ret .= enano_json_encode($tree) . ';';
   508     
   508 		
   509     // 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*
   509 		// 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*
   510     // $ret .= "    ['(debug) Clear menu bitfield', 'javascript:createCookie(\\'admin_menu_state\\', \\'1\\', 365);'],\n";
   510 		// $ret .= "    ['(debug) Clear menu bitfield', 'javascript:createCookie(\\'admin_menu_state\\', \\'1\\', 365);'],\n";
   511     return $ret;
   511 		return $ret;
   512   }
   512 	}
   513   
   513 	
   514   /**
   514 	/**
   515    * Internal function to generate HTML code for an icon in the admin panel tree which is sprited.
   515  	* Internal function to generate HTML code for an icon in the admin panel tree which is sprited.
   516    * @param int X index of icon
   516  	* @param int X index of icon
   517    * @param int Y index of icon
   517  	* @param int Y index of icon
   518    * @return string
   518  	* @return string
   519    */
   519  	*/
   520   
   520 	
   521   function make_sprite_icon($ix, $iy)
   521 	function make_sprite_icon($ix, $iy)
   522   {
   522 	{
   523     $xpos = 16 * ( $ix - 1 );
   523 		$xpos = 16 * ( $ix - 1 );
   524     $ypos = 16 * ( $iy - 1 );
   524 		$ypos = 16 * ( $iy - 1 );
   525     return "<img alt=\"\" src=\"" . cdnPath . "/images/spacer.gif\" class=\"adminiconsprite\" style=\"border-width: 0; margin-right: 3px; background-position: -{$xpos}px -{$ypos}px;\" /> ";
   525 		return "<img alt=\"\" src=\"" . cdnPath . "/images/spacer.gif\" class=\"adminiconsprite\" style=\"border-width: 0; margin-right: 3px; background-position: -{$xpos}px -{$ypos}px;\" /> ";
   526   }
   526 	}
   527   
   527 	
   528   /**
   528 	/**
   529    * Creates a new entry in the administration panel's navigation tree.
   529  	* Creates a new entry in the administration panel's navigation tree.
   530    * @param string Section name - if this is a language string identifier, it will be sent through $lang->get()
   530  	* @param string Section name - if this is a language string identifier, it will be sent through $lang->get()
   531    * @param string The title of the page, also may be a language string identifier
   531  	* @param string The title of the page, also may be a language string identifier
   532    * @param string The page ID of the admin page, the namespace Admin is assumed
   532  	* @param string The page ID of the admin page, the namespace Admin is assumed
   533    * @param string Optional. The path to a 16x16 image that will be displayed as the icon for this admin page
   533  	* @param string Optional. The path to a 16x16 image that will be displayed as the icon for this admin page
   534    */
   534  	*/
   535   
   535 	
   536   function addAdminNode($section, $page_title, $url, $icon = false)
   536 	function addAdminNode($section, $page_title, $url, $icon = false)
   537   {
   537 	{
   538     if ( !$icon )
   538 		if ( !$icon )
   539     {
   539 		{
   540       $icon = cdnPath . '/images/spacer.gif';
   540 			$icon = cdnPath . '/images/spacer.gif';
   541     }
   541 		}
   542     if(!isset($this->admin_tree[$section]))
   542 		if(!isset($this->admin_tree[$section]))
   543     {
   543 		{
   544       $this->admin_tree[$section] = Array();
   544 			$this->admin_tree[$section] = Array();
   545     }
   545 		}
   546     $this->admin_tree[$section][] = Array(
   546 		$this->admin_tree[$section][] = Array(
   547         'name' => $page_title,
   547 				'name' => $page_title,
   548         'pageid' => $url,
   548 				'pageid' => $url,
   549         'icon' => $icon
   549 				'icon' => $icon
   550       );
   550 			);
   551   }
   551 	}
   552   function getParam($id = 0)
   552 	function getParam($id = 0)
   553   {
   553 	{
   554     $title = $this->fullpage;
   554 		$title = $this->fullpage;
   555     list(, $ns) = RenderMan::strToPageID($title);
   555 		list(, $ns) = RenderMan::strToPageID($title);
   556     $title = substr($title, strlen($this->nslist[$ns]));
   556 		$title = substr($title, strlen($this->nslist[$ns]));
   557     $regex = '/^' . str_replace('/', '\\/', preg_quote($this->nslist[$ns])) . '\\/?/';
   557 		$regex = '/^' . str_replace('/', '\\/', preg_quote($this->nslist[$ns])) . '\\/?/';
   558     $title = preg_replace($regex, '', $title);
   558 		$title = preg_replace($regex, '', $title);
   559     $title = explode('/', $title);
   559 		$title = explode('/', $title);
   560     $id = $id + 1;
   560 		$id = $id + 1;
   561     return ( isset($title[$id]) ) ? $title[$id] : false;
   561 		return ( isset($title[$id]) ) ? $title[$id] : false;
   562   }
   562 	}
   563   
   563 	
   564   function getAllParams()
   564 	function getAllParams()
   565   {
   565 	{
   566     $title = $this->fullpage;
   566 		$title = $this->fullpage;
   567     $regex = '/^' . str_replace('/', '\\/', preg_quote($this->nslist[$this->namespace])) . '\\/?/';
   567 		$regex = '/^' . str_replace('/', '\\/', preg_quote($this->nslist[$this->namespace])) . '\\/?/';
   568     $title = preg_replace($regex, '', $title);
   568 		$title = preg_replace($regex, '', $title);
   569     $title = explode('/', $title);
   569 		$title = explode('/', $title);
   570     unset($title[0]);
   570 		unset($title[0]);
   571     return implode('/', $title);
   571 		return implode('/', $title);
   572   }
   572 	}
   573   
   573 	
   574   /**
   574 	/**
   575    * Creates a new namespace in memory
   575  	* Creates a new namespace in memory
   576    * @param string $id the namespace ID
   576  	* @param string $id the namespace ID
   577    * @param string $prefix the URL prefix, must not be blank or already used
   577  	* @param string $prefix the URL prefix, must not be blank or already used
   578    * @return bool true on success false on failure
   578  	* @return bool true on success false on failure
   579    */
   579  	*/
   580   
   580 	
   581   function create_namespace($id, $prefix)
   581 	function create_namespace($id, $prefix)
   582   {
   582 	{
   583     if(in_array($prefix, $this->nslist))
   583 		if(in_array($prefix, $this->nslist))
   584     {
   584 		{
   585       // echo '<b>Warning:</b> pathManager::create_namespace: Prefix "'.$prefix.'" is already taken<br />';
   585 			// echo '<b>Warning:</b> pathManager::create_namespace: Prefix "'.$prefix.'" is already taken<br />';
   586       return false;
   586 			return false;
   587     }
   587 		}
   588     if( isset($this->nslist[$id]) )
   588 		if( isset($this->nslist[$id]) )
   589     {
   589 		{
   590       // echo '<b>Warning:</b> pathManager::create_namespace: Namespace ID "'.$prefix.'" is already taken<br />';
   590 			// echo '<b>Warning:</b> pathManager::create_namespace: Namespace ID "'.$prefix.'" is already taken<br />';
   591       return false;
   591 			return false;
   592     }
   592 		}
   593     $this->nslist[$id] = $prefix;
   593 		$this->nslist[$id] = $prefix;
   594   }
   594 	}
   595   
   595 	
   596   /**
   596 	/**
   597    * Deprecated.
   597  	* Deprecated.
   598    */
   598  	*/
   599   
   599 	
   600   function update_metadata_cache()
   600 	function update_metadata_cache()
   601   {
   601 	{
   602     global $db, $session, $paths, $template, $plugins; // Common objects
   602 		global $db, $session, $paths, $template, $plugins; // Common objects
   603     
   603 		
   604     return false;
   604 		return false;
   605   }
   605 	}
   606   
   606 	
   607   /**
   607 	/**
   608    * Takes a result row from the pages table and calculates correct values for it.
   608  	* Takes a result row from the pages table and calculates correct values for it.
   609    * @param array
   609  	* @param array
   610    * @return array
   610  	* @return array
   611    */
   611  	*/
   612   
   612 	
   613   function calculate_metadata_from_row($r)
   613 	function calculate_metadata_from_row($r)
   614   {
   614 	{
   615     return Namespace_Default::bake_cdata($r);
   615 		return Namespace_Default::bake_cdata($r);
   616   }
   616 	}
   617   
   617 	
   618   /**
   618 	/**
   619    * Registers a handler to manually process a namespace instead of the default PageProcessor behavior.
   619  	* Registers a handler to manually process a namespace instead of the default PageProcessor behavior.
   620    * The first and only parameter passed to the processing function will be the PageProcessor instance.
   620  	* The first and only parameter passed to the processing function will be the PageProcessor instance.
   621    * @param string Namespace to process
   621  	* @param string Namespace to process
   622    * @param mixed Function address. Either a function name or an array of the form array(0 => mixed (string:class name or object), 1 => string:method)
   622  	* @param mixed Function address. Either a function name or an array of the form array(0 => mixed (string:class name or object), 1 => string:method)
   623    */
   623  	*/
   624   
   624 	
   625   function register_namespace_processor($namespace, $function)
   625 	function register_namespace_processor($namespace, $function)
   626   {
   626 	{
   627     if ( isset($this->namespace_processors[$namespace]) )
   627 		if ( isset($this->namespace_processors[$namespace]) )
   628     {
   628 		{
   629       $processorname = ( is_string($this->namespace_processors[$namespace]) ) ?
   629 			$processorname = ( is_string($this->namespace_processors[$namespace]) ) ?
   630         $this->namespace_processors[$namespace] :
   630 				$this->namespace_processors[$namespace] :
   631         ( is_object($this->namespace_processors[$namespace][0]) ? get_class($this->namespace_processors[$namespace][0]) : $this->namespace_processors[$namespace][0] ) . '::' .
   631 				( is_object($this->namespace_processors[$namespace][0]) ? get_class($this->namespace_processors[$namespace][0]) : $this->namespace_processors[$namespace][0] ) . '::' .
   632           $this->namespace_processors[$namespace][1];
   632 					$this->namespace_processors[$namespace][1];
   633           
   633 					
   634       trigger_error("Namespace \"$namespace\" is already being processed by $processorname - replacing caller", E_USER_WARNING);
   634 			trigger_error("Namespace \"$namespace\" is already being processed by $processorname - replacing caller", E_USER_WARNING);
   635     }
   635 		}
   636     if ( !is_string($function) )
   636 		if ( !is_string($function) )
   637     {
   637 		{
   638       if ( !is_array($function) )
   638 			if ( !is_array($function) )
   639         return false;
   639 				return false;
   640       if ( count($function) != 2 )
   640 			if ( count($function) != 2 )
   641         return false;
   641 				return false;
   642       if ( !is_string($function[0]) && !is_object($function[0]) )
   642 			if ( !is_string($function[0]) && !is_object($function[0]) )
   643         return false;
   643 				return false;
   644       if ( !is_string($function[1]) )
   644 			if ( !is_string($function[1]) )
   645         return false;
   645 				return false;
   646     }
   646 		}
   647     
   647 		
   648     // security: don't allow Special or Admin namespaces to be overridden
   648 		// security: don't allow Special or Admin namespaces to be overridden
   649     if ( $namespace == 'Special' || $namespace == 'Admin' )
   649 		if ( $namespace == 'Special' || $namespace == 'Admin' )
   650     {
   650 		{
   651       trigger_error("Security manager denied attempt to override processor for $namespace", E_USER_ERROR);
   651 			trigger_error("Security manager denied attempt to override processor for $namespace", E_USER_ERROR);
   652     }
   652 		}
   653     
   653 		
   654     $this->namespace_processors[$namespace] = $function;
   654 		$this->namespace_processors[$namespace] = $function;
   655   }
   655 	}
   656   
   656 	
   657   /**
   657 	/**
   658    * Returns a namespace processor if one exists, otherwise returns false.
   658  	* Returns a namespace processor if one exists, otherwise returns false.
   659    * @param string Namespace
   659  	* @param string Namespace
   660    * @return mixed
   660  	* @return mixed
   661    */
   661  	*/
   662   
   662 	
   663   function get_namespace_processor($namespace)
   663 	function get_namespace_processor($namespace)
   664   {
   664 	{
   665     return ( isset($this->namespace_processors[$namespace]) ) ? $this->namespace_processors[$namespace] : false;
   665 		return ( isset($this->namespace_processors[$namespace]) ) ? $this->namespace_processors[$namespace] : false;
   666   }
   666 	}
   667   
   667 	
   668   /**
   668 	/**
   669    * Fetches the page texts for searching
   669  	* Fetches the page texts for searching
   670    */
   670  	*/
   671    
   671  	
   672   function fetch_page_search_texts()
   672 	function fetch_page_search_texts()
   673   {
   673 	{
   674     global $db, $session, $paths, $template, $plugins; // Common objects
   674 		global $db, $session, $paths, $template, $plugins; // Common objects
   675     $texts = Array();
   675 		$texts = Array();
   676     $q = $db->sql_query('SELECT t.page_id,t.namespace,t.page_text,t.char_tag FROM '.table_prefix.'page_text AS t
   676 		$q = $db->sql_query('SELECT t.page_id,t.namespace,t.page_text,t.char_tag FROM '.table_prefix.'page_text AS t
   677                            LEFT JOIN '.table_prefix.'pages AS p
   677  													LEFT JOIN '.table_prefix.'pages AS p
   678                              ON t.page_id=p.urlname
   678  														ON t.page_id=p.urlname
   679                            WHERE p.namespace=t.namespace
   679  													WHERE p.namespace=t.namespace
   680                              AND ( p.password=\'\' OR p.password=\'da39a3ee5e6b4b0d3255bfef95601890afd80709\' )
   680  														AND ( p.password=\'\' OR p.password=\'da39a3ee5e6b4b0d3255bfef95601890afd80709\' )
   681                              AND p.visible=1;'); // Only indexes "visible" pages
   681  														AND p.visible=1;'); // Only indexes "visible" pages
   682     
   682 		
   683     if( !$q )
   683 		if( !$q )
   684     {
   684 		{
   685       return false;
   685 			return false;
   686     }
   686 		}
   687     while($row = $db->fetchrow())
   687 		while($row = $db->fetchrow())
   688     {
   688 		{
   689       $pid = $this->nslist[$row['namespace']] . $row['page_id'];
   689 			$pid = $this->nslist[$row['namespace']] . $row['page_id'];
   690       $texts[$pid] = $row['page_text'];
   690 			$texts[$pid] = $row['page_text'];
   691     }
   691 		}
   692     $db->free_result();
   692 		$db->free_result();
   693     
   693 		
   694     return $texts;
   694 		return $texts;
   695   }
   695 	}
   696   
   696 	
   697   /**
   697 	/**
   698    * Generates an SQL query to grab all of the text
   698  	* Generates an SQL query to grab all of the text
   699    */
   699  	*/
   700    
   700  	
   701   function fetch_page_search_resource()
   701 	function fetch_page_search_resource()
   702   {
   702 	{
   703     global $db, $session, $paths, $template, $plugins; // Common objects
   703 		global $db, $session, $paths, $template, $plugins; // Common objects
   704     // sha1('') returns "da39a3ee5e6b4b0d3255bfef95601890afd80709"
   704 		// sha1('') returns "da39a3ee5e6b4b0d3255bfef95601890afd80709"
   705     
   705 		
   706     $concat_column = ( ENANO_DBLAYER == 'MYSQL' ) ?
   706 		$concat_column = ( ENANO_DBLAYER == 'MYSQL' ) ?
   707       'CONCAT(\'ns=\',t.namespace,\';pid=\',t.page_id)' :
   707 			'CONCAT(\'ns=\',t.namespace,\';pid=\',t.page_id)' :
   708       "'ns=' || t.namespace || ';pid=' || t.page_id";
   708 			"'ns=' || t.namespace || ';pid=' || t.page_id";
   709     
   709 		
   710     $texts = 'SELECT t.page_text, ' . $concat_column . ' AS page_idstring, t.page_id, t.namespace FROM '.table_prefix.'page_text AS t
   710 		$texts = 'SELECT t.page_text, ' . $concat_column . ' AS page_idstring, t.page_id, t.namespace FROM '.table_prefix.'page_text AS t
   711                            LEFT JOIN '.table_prefix.'pages AS p
   711  													LEFT JOIN '.table_prefix.'pages AS p
   712                              ON ( t.page_id=p.urlname AND t.namespace=p.namespace )
   712  														ON ( t.page_id=p.urlname AND t.namespace=p.namespace )
   713                            WHERE p.namespace=t.namespace
   713  													WHERE p.namespace=t.namespace
   714                              AND ( p.password=\'\' OR p.password=\'da39a3ee5e6b4b0d3255bfef95601890afd80709\' )
   714  														AND ( p.password=\'\' OR p.password=\'da39a3ee5e6b4b0d3255bfef95601890afd80709\' )
   715                              AND p.visible=1;'; // Only indexes "visible" pages
   715  														AND p.visible=1;'; // Only indexes "visible" pages
   716     return $texts;
   716 		return $texts;
   717   }
   717 	}
   718   
   718 	
   719   /**
   719 	/**
   720    * Builds a word list for search indexing.
   720  	* Builds a word list for search indexing.
   721    * @param string Text to index
   721  	* @param string Text to index
   722    * @param string Page ID of the page being indexed
   722  	* @param string Page ID of the page being indexed
   723    * @param string Title of the page being indexed
   723  	* @param string Title of the page being indexed
   724    * @return array List of words
   724  	* @return array List of words
   725    */
   725  	*/
   726   
   726 	
   727   function calculate_word_list($text, $page_id, $page_name)
   727 	function calculate_word_list($text, $page_id, $page_name)
   728   {
   728 	{
   729     $page_id = dirtify_page_id($page_id);
   729 		$page_id = dirtify_page_id($page_id);
   730     $text = preg_replace('/[^a-z0-9\']/i', ' ', $text);
   730 		$text = preg_replace('/[^a-z0-9\']/i', ' ', $text);
   731     $page_id = preg_replace('/[^a-z0-9\']/i', ' ', $page_id);
   731 		$page_id = preg_replace('/[^a-z0-9\']/i', ' ', $page_id);
   732     $page_name = preg_replace('/[^a-z0-9\']/i', ' ', $page_name);
   732 		$page_name = preg_replace('/[^a-z0-9\']/i', ' ', $page_name);
   733     $text .= " $page_id $page_name";
   733 		$text .= " $page_id $page_name";
   734     $text = explode(' ', $text);
   734 		$text = explode(' ', $text);
   735     foreach ( $text as $i => &$word )
   735 		foreach ( $text as $i => &$word )
   736     {
   736 		{
   737       if ( strstr($word, "''") )
   737 			if ( strstr($word, "''") )
   738         $word = preg_replace("/[']{2,}/", '', $word);
   738 				$word = preg_replace("/[']{2,}/", '', $word);
   739       if ( strlen($word) < 2 )
   739 			if ( strlen($word) < 2 )
   740         unset($text[$i]);
   740 				unset($text[$i]);
   741     }
   741 		}
   742     $text = array_unique(array_values($text));
   742 		$text = array_unique(array_values($text));
   743     // for debugging purposes (usually XSS safe because of character stripping)
   743 		// for debugging purposes (usually XSS safe because of character stripping)
   744     // echo ' ' . implode(' ', $text) . '<br />';
   744 		// echo ' ' . implode(' ', $text) . '<br />';
   745     return $text;
   745 		return $text;
   746   }
   746 	}
   747   
   747 	
   748   /**
   748 	/**
   749    * Rebuilds the site's entire search index. Considerably more exciting if run from the command line.
   749  	* Rebuilds the site's entire search index. Considerably more exciting if run from the command line.
   750    * @param bool If true, verbose output.
   750  	* @param bool If true, verbose output.
   751    * @param bool If true, verbose + debugging output.
   751  	* @param bool If true, verbose + debugging output.
   752    */
   752  	*/
   753   
   753 	
   754   function rebuild_search_index($verbose = false, $debug = false)
   754 	function rebuild_search_index($verbose = false, $debug = false)
   755   {
   755 	{
   756     global $db, $session, $paths, $template, $plugins; // Common objects
   756 		global $db, $session, $paths, $template, $plugins; // Common objects
   757     require_once(ENANO_ROOT . '/includes/search.php');
   757 		require_once(ENANO_ROOT . '/includes/search.php');
   758     
   758 		
   759     $progress = false;
   759 		$progress = false;
   760     if ( class_exists('ProgressBar') )
   760 		if ( class_exists('ProgressBar') )
   761     {
   761 		{
   762       // CLI only.
   762 			// CLI only.
   763       $progress = new ProgressBar('Rebuilding search index: [', ']', 'Initializing...', 'green', 'blue', 'white', 'yellow');
   763 			$progress = new ProgressBar('Rebuilding search index: [', ']', 'Initializing...', 'green', 'blue', 'white', 'yellow');
   764       $verbose = false;
   764 			$verbose = false;
   765       $debug = false;
   765 			$debug = false;
   766       $progress->start();
   766 			$progress->start();
   767     }
   767 		}
   768     
   768 		
   769     @set_time_limit(0);
   769 		@set_time_limit(0);
   770     
   770 		
   771     $q = $db->sql_query('DELETE FROM ' . table_prefix . 'search_index;');
   771 		$q = $db->sql_query('DELETE FROM ' . table_prefix . 'search_index;');
   772     if ( !$q )
   772 		if ( !$q )
   773       $db->_die();
   773 			$db->_die();
   774     
   774 		
   775     $sha1_blank = sha1('');
   775 		$sha1_blank = sha1('');
   776     
   776 		
   777     //
   777 		//
   778     // Index $pages_in_batch pages at a time
   778 		// Index $pages_in_batch pages at a time
   779     //
   779 		//
   780     $pages_in_batch = 15;
   780 		$pages_in_batch = 15;
   781     
   781 		
   782     // First find out how many pages there are
   782 		// First find out how many pages there are
   783     $q = $db->sql_query('SELECT COUNT(p.urlname) AS num_pages FROM ' . table_prefix . "page_text AS t\n"
   783 		$q = $db->sql_query('SELECT COUNT(p.urlname) AS num_pages FROM ' . table_prefix . "page_text AS t\n"
   784                       . "  LEFT JOIN " . table_prefix . "pages AS p\n"
   784 											. "  LEFT JOIN " . table_prefix . "pages AS p\n"
   785                       . "    ON ( p.urlname = t.page_id AND p.namespace = t.namespace )\n"
   785 											. "    ON ( p.urlname = t.page_id AND p.namespace = t.namespace )\n"
   786                       . "  WHERE ( p.password = '' OR p.password = '$sha1_blank' )\n"
   786 											. "  WHERE ( p.password = '' OR p.password = '$sha1_blank' )\n"
   787                       . "    AND ( p.visible = 1 );");
   787 											. "    AND ( p.visible = 1 );");
   788     if ( !$q )
   788 		if ( !$q )
   789       $db->_die();
   789 			$db->_die();
   790     
   790 		
   791     list($num_pages) = $db->fetchrow_num();
   791 		list($num_pages) = $db->fetchrow_num();
   792     $num_pages = intval($num_pages);
   792 		$num_pages = intval($num_pages);
   793     $loops = ceil($num_pages / $pages_in_batch);
   793 		$loops = ceil($num_pages / $pages_in_batch);
   794     $master_word_list = array();
   794 		$master_word_list = array();
   795     $stopwords = get_stopwords();
   795 		$stopwords = get_stopwords();
   796     
   796 		
   797     for ( $j = 0; $j < $loops; )
   797 		for ( $j = 0; $j < $loops; )
   798     {
   798 		{
   799       $offset = $j * $pages_in_batch;
   799 			$offset = $j * $pages_in_batch;
   800       
   800 			
   801       $j++;
   801 			$j++;
   802       
   802 			
   803       if ( $verbose && $debug )
   803 			if ( $verbose && $debug )
   804       {
   804 			{
   805         echo "Running indexing round $j of $loops (offset $offset)\n" . ( isset($_SERVER['REQUEST_URI']) ? '<br />' : '' );
   805 				echo "Running indexing round $j of $loops (offset $offset)\n" . ( isset($_SERVER['REQUEST_URI']) ? '<br />' : '' );
   806       }
   806 			}
   807       
   807 			
   808       // this is friendly to both MySQL and PostgreSQL.
   808 			// this is friendly to both MySQL and PostgreSQL.
   809       $texts = $db->sql_query('SELECT p.name, p.visible, t.page_id, t.namespace, t.page_text FROM ' . table_prefix . "page_text AS t\n"
   809 			$texts = $db->sql_query('SELECT p.name, p.visible, t.page_id, t.namespace, t.page_text FROM ' . table_prefix . "page_text AS t\n"
   810                             . "  LEFT JOIN " . table_prefix . "pages AS p\n"
   810 														. "  LEFT JOIN " . table_prefix . "pages AS p\n"
   811                             . "    ON ( p.urlname = t.page_id AND p.namespace = t.namespace )\n"
   811 														. "    ON ( p.urlname = t.page_id AND p.namespace = t.namespace )\n"
   812                             . "  WHERE ( p.password = '' OR p.password = '$sha1_blank' )\n"
   812 														. "  WHERE ( p.password = '' OR p.password = '$sha1_blank' )\n"
   813                             . "    AND ( p.visible = 1 )\n"
   813 														. "    AND ( p.visible = 1 )\n"
   814                             . "  LIMIT $pages_in_batch OFFSET $offset;", false);
   814 														. "  LIMIT $pages_in_batch OFFSET $offset;", false);
   815       if ( !$texts )
   815 			if ( !$texts )
   816         $db->_die();
   816 				$db->_die();
   817       
   817 			
   818       $k = $offset;
   818 			$k = $offset;
   819       
   819 			
   820       if ( $row = $db->fetchrow($texts) )
   820 			if ( $row = $db->fetchrow($texts) )
   821       {
   821 			{
   822         do
   822 				do
   823         {
   823 				{
   824           $k++;
   824 					$k++;
   825           if ( $verbose )
   825 					if ( $verbose )
   826           {
   826 					{
   827             $mu = memory_get_usage();
   827 						$mu = memory_get_usage();
   828             echo "  Indexing page $k of $num_pages: {$row['namespace']}:{$row['page_id']}";
   828 						echo "  Indexing page $k of $num_pages: {$row['namespace']}:{$row['page_id']}";
   829             if ( $debug )
   829 						if ( $debug )
   830               echo ", mem = $mu...";
   830 							echo ", mem = $mu...";
   831             flush();
   831 						flush();
   832           }
   832 					}
   833           else if ( is_object($progress) )
   833 					else if ( is_object($progress) )
   834           {
   834 					{
   835             $progress->update_text_quiet("$k/$num_pages {$row['namespace']}:{$row['page_id']}");
   835 						$progress->update_text_quiet("$k/$num_pages {$row['namespace']}:{$row['page_id']}");
   836             $progress->set($k, $num_pages);
   836 						$progress->set($k, $num_pages);
   837           }
   837 					}
   838           
   838 					
   839           // skip this page if it's not supposed to be indexed
   839 					// skip this page if it's not supposed to be indexed
   840           if ( $row['visible'] == 0 )
   840 					if ( $row['visible'] == 0 )
   841           {
   841 					{
   842             if ( $verbose )
   842 						if ( $verbose )
   843             {
   843 						{
   844               echo "skipped";
   844 							echo "skipped";
   845               if ( isset($_SERVER['REQUEST_URI']) )
   845 							if ( isset($_SERVER['REQUEST_URI']) )
   846                 echo '<br />';
   846 								echo '<br />';
   847               echo "\n";
   847 							echo "\n";
   848             }
   848 						}
   849             continue;
   849 						continue;
   850           }
   850 					}
   851           
   851 					
   852           // Indexing identifier for the page in the DB
   852 					// Indexing identifier for the page in the DB
   853           $page_uniqid = "ns={$row['namespace']};pid=" . sanitize_page_id($row['page_id']);
   853 					$page_uniqid = "ns={$row['namespace']};pid=" . sanitize_page_id($row['page_id']);
   854           $page_uniqid = $db->escape($page_uniqid);
   854 					$page_uniqid = $db->escape($page_uniqid);
   855           
   855 					
   856           // List of words on the page
   856 					// List of words on the page
   857           $wordlist = $this->calculate_word_list($row['page_text'], $row['page_id'], $row['name']);
   857 					$wordlist = $this->calculate_word_list($row['page_text'], $row['page_id'], $row['name']);
   858           
   858 					
   859           // Index calculation complete -- run inserts
   859 					// Index calculation complete -- run inserts
   860           $inserts = array();
   860 					$inserts = array();
   861           foreach ( $wordlist as $word )
   861 					foreach ( $wordlist as $word )
   862           {
   862 					{
   863             if ( in_array($word, $stopwords) || strval(intval($word)) === $word || strlen($word) < 3 )
   863 						if ( in_array($word, $stopwords) || strval(intval($word)) === $word || strlen($word) < 3 )
   864               continue;
   864 							continue;
   865             $word_db = $db->escape($word);
   865 						$word_db = $db->escape($word);
   866             $word_db_lc = $db->escape(strtolower($word));
   866 						$word_db_lc = $db->escape(strtolower($word));
   867             if ( !in_array($word, $master_word_list) )
   867 						if ( !in_array($word, $master_word_list) )
   868             {
   868 						{
   869               $inserts[] = "( '$word_db', '$word_db_lc', '$page_uniqid' )";
   869 							$inserts[] = "( '$word_db', '$word_db_lc', '$page_uniqid' )";
   870             }
   870 						}
   871             else
   871 						else
   872             {
   872 						{
   873               if ( $verbose && $debug )
   873 							if ( $verbose && $debug )
   874                 echo '.';
   874 								echo '.';
   875               $pid_col = ( ENANO_DBLAYER == 'MYSQL' ) ?
   875 							$pid_col = ( ENANO_DBLAYER == 'MYSQL' ) ?
   876                           "CONCAT( page_names, ',$page_uniqid' )":
   876 													"CONCAT( page_names, ',$page_uniqid' )":
   877                           "page_names || ',$page_uniqid'";
   877 													"page_names || ',$page_uniqid'";
   878               $q = $db->sql_query('UPDATE ' . table_prefix . "search_index SET page_names = $pid_col WHERE word = '$word_db';", false);
   878 							$q = $db->sql_query('UPDATE ' . table_prefix . "search_index SET page_names = $pid_col WHERE word = '$word_db';", false);
   879               if ( !$q )
   879 							if ( !$q )
   880                 $db->_die();
   880 								$db->_die();
   881             }
   881 						}
   882           }
   882 					}
   883           if ( count($inserts) > 0 )
   883 					if ( count($inserts) > 0 )
   884           {
   884 					{
   885             if ( $verbose && $debug )
   885 						if ( $verbose && $debug )
   886               echo 'i';
   886 							echo 'i';
   887             $inserts = implode(",\n  ", $inserts);
   887 						$inserts = implode(",\n  ", $inserts);
   888             $q = $db->sql_query('INSERT INTO ' . table_prefix . "search_index(word, word_lcase, page_names) VALUES\n  $inserts;", false);
   888 						$q = $db->sql_query('INSERT INTO ' . table_prefix . "search_index(word, word_lcase, page_names) VALUES\n  $inserts;", false);
   889             if ( !$q )
   889 						if ( !$q )
   890               $db->_die();
   890 							$db->_die();
   891           }
   891 					}
   892           
   892 					
   893           $master_word_list = array_unique(array_merge($master_word_list, $wordlist));
   893 					$master_word_list = array_unique(array_merge($master_word_list, $wordlist));
   894           if ( $verbose )
   894 					if ( $verbose )
   895           {
   895 					{
   896             if ( isset($_SERVER['REQUEST_URI']) )
   896 						if ( isset($_SERVER['REQUEST_URI']) )
   897               echo '<br />';
   897 							echo '<br />';
   898             echo "\n";
   898 						echo "\n";
   899           }
   899 					}
   900           unset($inserts, $wordlist, $page_uniqid, $word_db, $q, $word, $row);
   900 					unset($inserts, $wordlist, $page_uniqid, $word_db, $q, $word, $row);
   901         }
   901 				}
   902         while ( $row = $db->fetchrow($texts) );
   902 				while ( $row = $db->fetchrow($texts) );
   903       }
   903 			}
   904       $db->free_result($texts);
   904 			$db->free_result($texts);
   905     }
   905 		}
   906     if ( $verbose )
   906 		if ( $verbose )
   907     {
   907 		{
   908       echo "Indexing complete.";
   908 			echo "Indexing complete.";
   909       if ( isset($_SERVER['REQUEST_URI']) )
   909 			if ( isset($_SERVER['REQUEST_URI']) )
   910         echo '<br />';
   910 				echo '<br />';
   911       echo "\n";
   911 			echo "\n";
   912     }
   912 		}
   913     else if ( is_object($progress) )
   913 		else if ( is_object($progress) )
   914     {
   914 		{
   915       $progress->update_text('Complete.');
   915 			$progress->update_text('Complete.');
   916       $progress->end();
   916 			$progress->end();
   917     }
   917 		}
   918     return true;
   918 		return true;
   919   }
   919 	}
   920   
   920 	
   921   /**
   921 	/**
   922    * Partially rebuilds the search index, removing/inserting entries only for the current page
   922  	* Partially rebuilds the search index, removing/inserting entries only for the current page
   923    * @param string $page_id
   923  	* @param string $page_id
   924    * @param string $namespace
   924  	* @param string $namespace
   925    */
   925  	*/
   926   
   926 	
   927   function rebuild_page_index($page_id, $namespace)
   927 	function rebuild_page_index($page_id, $namespace)
   928   {
   928 	{
   929     global $db, $session, $paths, $template, $plugins; // Common objects
   929 		global $db, $session, $paths, $template, $plugins; // Common objects
   930     require_once(ENANO_ROOT . '/includes/search.php');
   930 		require_once(ENANO_ROOT . '/includes/search.php');
   931     
   931 		
   932     if(!$db->sql_query('SELECT page_text FROM '.table_prefix.'page_text
   932 		if(!$db->sql_query('SELECT page_text FROM '.table_prefix.'page_text
   933       WHERE page_id=\''.$db->escape($page_id).'\' AND namespace=\''.$db->escape($namespace).'\';'))
   933 			WHERE page_id=\''.$db->escape($page_id).'\' AND namespace=\''.$db->escape($namespace).'\';'))
   934     {
   934 		{
   935       return $db->get_error();
   935 			return $db->get_error();
   936     }
   936 		}
   937     if ( $db->numrows() < 1 )
   937 		if ( $db->numrows() < 1 )
   938       return 'E: No rows';
   938 			return 'E: No rows';
   939     $idstring = $this->nslist[$namespace] . sanitize_page_id($page_id);
   939 		$idstring = $this->nslist[$namespace] . sanitize_page_id($page_id);
   940     if ( !isset($this->pages[$idstring]) )
   940 		if ( !isset($this->pages[$idstring]) )
   941     {
   941 		{
   942       return 'E: Can\'t find page metadata';
   942 			return 'E: Can\'t find page metadata';
   943     }
   943 		}
   944     $row = $db->fetchrow();
   944 		$row = $db->fetchrow();
   945     $db->free_result();
   945 		$db->free_result();
   946     $search = new Searcher();
   946 		$search = new Searcher();
   947     
   947 		
   948     // if the page shouldn't be indexed, send a blank set of strings to the indexing engine
   948 		// if the page shouldn't be indexed, send a blank set of strings to the indexing engine
   949     if ( $this->pages[$idstring]['visible'] == 0 )
   949 		if ( $this->pages[$idstring]['visible'] == 0 )
   950     {
   950 		{
   951       $search->buildIndex(Array("ns={$namespace};pid={$page_id}"=>''));
   951 			$search->buildIndex(Array("ns={$namespace};pid={$page_id}"=>''));
   952     }
   952 		}
   953     else
   953 		else
   954     {
   954 		{
   955       $search->buildIndex(Array("ns={$namespace};pid={$page_id}"=>$row['page_text'] . ' ' . $this->pages[$idstring]['name']));
   955 			$search->buildIndex(Array("ns={$namespace};pid={$page_id}"=>$row['page_text'] . ' ' . $this->pages[$idstring]['name']));
   956     }
   956 		}
   957     
   957 		
   958     $new_index = $search->index;
   958 		$new_index = $search->index;
   959     
   959 		
   960     if ( count($search->index) == 0 )
   960 		if ( count($search->index) == 0 )
   961       // o_O
   961 			// o_O
   962       // nothing indexed.
   962 			// nothing indexed.
   963       return true;
   963 			return true;
   964     
   964 		
   965     if ( ENANO_DBLAYER == 'MYSQL' )
   965 		if ( ENANO_DBLAYER == 'MYSQL' )
   966     {
   966 		{
   967       $keys = array_keys($search->index);
   967 			$keys = array_keys($search->index);
   968       foreach($keys as $i => $k)
   968 			foreach($keys as $i => $k)
   969       {
   969 			{
   970         $c =& $keys[$i];
   970 				$c =& $keys[$i];
   971         $c = hexencode($c, '', '');
   971 				$c = hexencode($c, '', '');
   972       }
   972 			}
   973       $keys = "word=0x" . implode ( " OR word=0x", $keys ) . "";
   973 			$keys = "word=0x" . implode ( " OR word=0x", $keys ) . "";
   974     }
   974 		}
   975     else
   975 		else
   976     {
   976 		{
   977       $keys = array_keys($search->index);
   977 			$keys = array_keys($search->index);
   978       foreach($keys as $i => $k)
   978 			foreach($keys as $i => $k)
   979       {
   979 			{
   980         $c =& $keys[$i];
   980 				$c =& $keys[$i];
   981         $c = $db->escape($c);
   981 				$c = $db->escape($c);
   982       }
   982 			}
   983       $keys = "word='" . implode ( "' OR word='", $keys ) . "'";
   983 			$keys = "word='" . implode ( "' OR word='", $keys ) . "'";
   984     }
   984 		}
   985     
   985 		
   986     $query = $db->sql_query('SELECT word,page_names FROM '.table_prefix.'search_index WHERE '.$keys.';');
   986 		$query = $db->sql_query('SELECT word,page_names FROM '.table_prefix.'search_index WHERE '.$keys.';');
   987     
   987 		
   988     while($row = $db->fetchrow())
   988 		while($row = $db->fetchrow())
   989     {
   989 		{
   990       $row['word'] = rtrim($row['word'], "\0");
   990 			$row['word'] = rtrim($row['word'], "\0");
   991       $new_index[ $row['word'] ] = $row['page_names'] . ',' . $search->index[ $row['word'] ];
   991 			$new_index[ $row['word'] ] = $row['page_names'] . ',' . $search->index[ $row['word'] ];
   992     }
   992 		}
   993     $db->free_result();
   993 		$db->free_result();
   994     
   994 		
   995     $db->sql_query('DELETE FROM '.table_prefix.'search_index WHERE '.$keys.';');
   995 		$db->sql_query('DELETE FROM '.table_prefix.'search_index WHERE '.$keys.';');
   996     
   996 		
   997     $secs = Array();
   997 		$secs = Array();
   998     $q = 'INSERT INTO '.table_prefix.'search_index(word,word_lcase,page_names) VALUES';
   998 		$q = 'INSERT INTO '.table_prefix.'search_index(word,word_lcase,page_names) VALUES';
   999     foreach($new_index as $word => $pages)
   999 		foreach($new_index as $word => $pages)
  1000     {
  1000 		{
  1001       $secs[] = '(\''.$db->escape($word).'\', \'' . $db->escape(strtolower($word)) . '\', \''.$db->escape($pages).'\')';
  1001 			$secs[] = '(\''.$db->escape($word).'\', \'' . $db->escape(strtolower($word)) . '\', \''.$db->escape($pages).'\')';
  1002     }
  1002 		}
  1003     $q .= implode(',', $secs);
  1003 		$q .= implode(',', $secs);
  1004     unset($secs);
  1004 		unset($secs);
  1005     $q .= ';';
  1005 		$q .= ';';
  1006     if(!$db->check_query($q))
  1006 		if(!$db->check_query($q))
  1007     {
  1007 		{
  1008       die('BUG: PathManager::rebuild_page_index: Query rejected by SQL parser:<pre>'.$q.'</pre>');
  1008 			die('BUG: PathManager::rebuild_page_index: Query rejected by SQL parser:<pre>'.$q.'</pre>');
  1009     }
  1009 		}
  1010     $result = $db->sql_query($q);
  1010 		$result = $db->sql_query($q);
  1011     if($result)
  1011 		if($result)
  1012       return true;
  1012 			return true;
  1013     else
  1013 		else
  1014       $db->_die('The search index was trying to rebuild itself when the error occured.');
  1014 			$db->_die('The search index was trying to rebuild itself when the error occured.');
  1015     
  1015 		
  1016   }
  1016 	}
  1017   
  1017 	
  1018   /**
  1018 	/**
  1019    * Returns a list of groups that a given page is a member of.
  1019  	* Returns a list of groups that a given page is a member of.
  1020    * @param string Page ID
  1020  	* @param string Page ID
  1021    * @param string Namespace
  1021  	* @param string Namespace
  1022    * @return array
  1022  	* @return array
  1023    */
  1023  	*/
  1024   
  1024 	
  1025   function get_page_groups($page_id, $namespace)
  1025 	function get_page_groups($page_id, $namespace)
  1026   {
  1026 	{
  1027     global $db, $session, $paths, $template, $plugins; // Common objects
  1027 		global $db, $session, $paths, $template, $plugins; // Common objects
  1028     
  1028 		
  1029     static $cache = array();
  1029 		static $cache = array();
  1030     
  1030 		
  1031     if ( count($cache) == 0 )
  1031 		if ( count($cache) == 0 )
  1032     {
  1032 		{
  1033       foreach ( $this->nslist as $key => $_ )
  1033 			foreach ( $this->nslist as $key => $_ )
  1034       {
  1034 			{
  1035         $cache[$key] = array();
  1035 				$cache[$key] = array();
  1036       }
  1036 			}
  1037     }
  1037 		}
  1038     
  1038 		
  1039     if ( !isset($this->nslist[$namespace]) )
  1039 		if ( !isset($this->nslist[$namespace]) )
  1040       die('$paths->get_page_groups(): HACKING ATTEMPT: namespace "'. htmlspecialchars($namespace) .'" doesn\'t exist');
  1040 			die('$paths->get_page_groups(): HACKING ATTEMPT: namespace "'. htmlspecialchars($namespace) .'" doesn\'t exist');
  1041     
  1041 		
  1042     $page_id_unescaped = $paths->nslist[$namespace] .
  1042 		$page_id_unescaped = $paths->nslist[$namespace] .
  1043                          dirtify_page_id($page_id);
  1043  												dirtify_page_id($page_id);
  1044     $page_id_str       = $paths->nslist[$namespace] .
  1044 		$page_id_str       = $paths->nslist[$namespace] .
  1045                          sanitize_page_id($page_id);
  1045  												sanitize_page_id($page_id);
  1046     
  1046 		
  1047     $page_id = $db->escape(sanitize_page_id($page_id));
  1047 		$page_id = $db->escape(sanitize_page_id($page_id));
  1048     
  1048 		
  1049     if ( isset($cache[$namespace][$page_id]) )
  1049 		if ( isset($cache[$namespace][$page_id]) )
  1050     {
  1050 		{
  1051       return $cache[$namespace][$page_id];
  1051 			return $cache[$namespace][$page_id];
  1052     }
  1052 		}
  1053     
  1053 		
  1054     $group_list = array();
  1054 		$group_list = array();
  1055     
  1055 		
  1056     // What linked categories have this page?
  1056 		// What linked categories have this page?
  1057     $q = $db->sql_unbuffered_query('SELECT g.pg_id, g.pg_type, g.pg_target FROM '.table_prefix.'page_groups AS g
  1057 		$q = $db->sql_unbuffered_query('SELECT g.pg_id, g.pg_type, g.pg_target FROM '.table_prefix.'page_groups AS g
  1058   LEFT JOIN '.table_prefix.'categories AS c
  1058 	LEFT JOIN '.table_prefix.'categories AS c
  1059     ON ( ( c.category_id = g.pg_target AND g.pg_type = ' . PAGE_GRP_CATLINK . ' ) OR c.category_id IS NULL )
  1059 		ON ( ( c.category_id = g.pg_target AND g.pg_type = ' . PAGE_GRP_CATLINK . ' ) OR c.category_id IS NULL )
  1060   LEFT JOIN '.table_prefix.'page_group_members AS m
  1060 	LEFT JOIN '.table_prefix.'page_group_members AS m
  1061     ON ( ( g.pg_id = m.pg_id AND g.pg_type = ' . PAGE_GRP_NORMAL . ' ) OR ( m.pg_id IS NULL ) )
  1061 		ON ( ( g.pg_id = m.pg_id AND g.pg_type = ' . PAGE_GRP_NORMAL . ' ) OR ( m.pg_id IS NULL ) )
  1062   LEFT JOIN '.table_prefix.'tags AS t
  1062 	LEFT JOIN '.table_prefix.'tags AS t
  1063     ON ( ( t.tag_name = g.pg_target AND pg_type = ' . PAGE_GRP_TAGGED . ' ) OR t.tag_name IS NULL )
  1063 		ON ( ( t.tag_name = g.pg_target AND pg_type = ' . PAGE_GRP_TAGGED . ' ) OR t.tag_name IS NULL )
  1064   WHERE
  1064 	WHERE
  1065     ( c.page_id=\'' . $page_id . '\' AND c.namespace=\'' . $namespace . '\' ) OR
  1065 		( c.page_id=\'' . $page_id . '\' AND c.namespace=\'' . $namespace . '\' ) OR
  1066     ( t.page_id=\'' . $page_id . '\' AND t.namespace=\'' . $namespace . '\' ) OR
  1066 		( t.page_id=\'' . $page_id . '\' AND t.namespace=\'' . $namespace . '\' ) OR
  1067     ( m.page_id=\'' . $page_id . '\' AND m.namespace=\'' . $namespace . '\' ) OR
  1067 		( m.page_id=\'' . $page_id . '\' AND m.namespace=\'' . $namespace . '\' ) OR
  1068     ( g.pg_type = ' . PAGE_GRP_REGEX . ' );');
  1068 		( g.pg_type = ' . PAGE_GRP_REGEX . ' );');
  1069     if ( !$q )
  1069 		if ( !$q )
  1070       $db->_die();
  1070 			$db->_die();
  1071     
  1071 		
  1072     while ( $row = $db->fetchrow() )
  1072 		while ( $row = $db->fetchrow() )
  1073     {
  1073 		{
  1074       if ( $row['pg_type'] == PAGE_GRP_REGEX )
  1074 			if ( $row['pg_type'] == PAGE_GRP_REGEX )
  1075       {
  1075 			{
  1076         //echo "&lt;debug&gt; matching page " . htmlspecialchars($page_id_unescaped) . " against regex <tt>" . htmlspecialchars($row['pg_target']) . "</tt>.";
  1076 				//echo "&lt;debug&gt; matching page " . htmlspecialchars($page_id_unescaped) . " against regex <tt>" . htmlspecialchars($row['pg_target']) . "</tt>.";
  1077         if ( @preg_match($row['pg_target'], $page_id_unescaped) || @preg_match($row['pg_target'], $page_id_str) )
  1077 				if ( @preg_match($row['pg_target'], $page_id_unescaped) || @preg_match($row['pg_target'], $page_id_str) )
  1078         {
  1078 				{
  1079           //echo "..matched";
  1079 					//echo "..matched";
  1080           $group_list[] = $row['pg_id'];
  1080 					$group_list[] = $row['pg_id'];
  1081         }
  1081 				}
  1082         //echo "<br />";
  1082 				//echo "<br />";
  1083       }
  1083 			}
  1084       else
  1084 			else
  1085       {
  1085 			{
  1086         $group_list[] = $row['pg_id'];
  1086 				$group_list[] = $row['pg_id'];
  1087       }
  1087 			}
  1088     }
  1088 		}
  1089     
  1089 		
  1090     $db->free_result();
  1090 		$db->free_result();
  1091     
  1091 		
  1092     $cache[$namespace][$page_id] = $group_list;
  1092 		$cache[$namespace][$page_id] = $group_list;
  1093     
  1093 		
  1094     return $group_list;
  1094 		return $group_list;
  1095     
  1095 		
  1096   }
  1096 	}
  1097   
  1097 	
  1098 }
  1098 }
  1099 
  1099 
  1100 /**
  1100 /**
  1101  * Register a special page.
  1101  * Register a special page.
  1102  * @param string urlname of the page ("Administration" in "Special:Administration")
  1102  * @param string urlname of the page ("Administration" in "Special:Administration")
  1104  * @param bool If true, page is visible (shown in lists/search). Otherwise, hidden. Defaults to true.
  1104  * @param bool If true, page is visible (shown in lists/search). Otherwise, hidden. Defaults to true.
  1105  */
  1105  */
  1106 
  1106 
  1107 function register_special_page($urlname, $name, $visible = true)
  1107 function register_special_page($urlname, $name, $visible = true)
  1108 {
  1108 {
  1109   global $paths;
  1109 	global $paths;
  1110   
  1110 	
  1111   return $paths->add_page(Array(
  1111 	return $paths->add_page(Array(
  1112       'name' => $name,
  1112 			'name' => $name,
  1113       'urlname' => $urlname,
  1113 			'urlname' => $urlname,
  1114       'namespace' => 'Special',
  1114 			'namespace' => 'Special',
  1115       'special' => 0,
  1115 			'special' => 0,
  1116       'visible' => $visible ? 1 : 0,
  1116 			'visible' => $visible ? 1 : 0,
  1117       'comments_on' => 0,
  1117 			'comments_on' => 0,
  1118       'protected' => 1,
  1118 			'protected' => 1,
  1119       'delvotes' => 0,
  1119 			'delvotes' => 0,
  1120       'delvote_ips' => '',
  1120 			'delvote_ips' => '',
  1121     ));
  1121 		));
  1122 }
  1122 }
  1123 
  1123 
  1124 ?>
  1124 ?>