# HG changeset patch # User Dan # Date 1215051355 14400 # Node ID 4f9bec0d65c1ea8a991a10a2458da57d2c1cdb31 # Parent 27377179fe58a4b32ba7a59ec496041d39520dd0 More optimization work. Moved special page init functions to common instead of common_post hook. Allowed paths to cache page metadata on filesystem. Phased out the redundancy in $paths->pages that paired a number with every urlname as foreach loops are allowed now (and have been for some time). Fixed missing includes for several functions. Rewrote str_replace_once to be a lot more efficient. diff -r 27377179fe58 -r 4f9bec0d65c1 ajax.php --- a/ajax.php Wed Jul 02 19:36:44 2008 -0400 +++ b/ajax.php Wed Jul 02 22:15:55 2008 -0400 @@ -436,7 +436,7 @@ $name = sanitize_page_id($name); $name = str_replace('_', ' ', $name); - for($i=0;$ipages)/2;$i++) + foreach ( $paths->pages as $i => $_ ) { if( ( preg_match('#'.preg_quote($name).'(.*)#i', $paths->pages[$i]['name']) || diff -r 27377179fe58 -r 4f9bec0d65c1 includes/common.php --- a/includes/common.php Wed Jul 02 19:36:44 2008 -0400 +++ b/includes/common.php Wed Jul 02 22:15:55 2008 -0400 @@ -378,6 +378,22 @@ // All checks passed! Start the main components up. $session->start(); + // Grab language strings from the database + $lang->fetch(); + profiler_log('Fetched language strings'); + + // Add all of our built in special pages + SpecialUserFuncs_paths_init(); + SpecialPageFuncs_paths_init(); + SpecialAdmin_paths_init(); + SpecialCSS_paths_init(); + SpecialUpDownload_paths_init(); + SpecialSearch_paths_init(); + PrivateMessages_paths_init(); + SpecialGroups_paths_init(); + SpecialRecentChanges_paths_init(); + profiler_log('Added special pages'); + // This is where plugins will want to add pages from 1.1.x on out. You can still add // pages at base_classes_initted but the titles won't be localized. This is because // the session manager has to be started before localization will work in the user's diff -r 27377179fe58 -r 4f9bec0d65c1 includes/functions.php --- a/includes/functions.php Wed Jul 02 19:36:44 2008 -0400 +++ b/includes/functions.php Wed Jul 02 22:15:55 2008 -0400 @@ -1948,6 +1948,9 @@ // Random seed for substitution $rand_seed = md5( sha1(microtime()) . mt_rand() ); + // We need MediaWiki + require_once(ENANO_ROOT . '/includes/wikiengine/Tables.php'); + // Strip out comments that are already escaped preg_match_all('/<!--(.*?)-->/', $html, $comment_match); $i = 0; @@ -2821,17 +2824,11 @@ function str_replace_once($needle, $thread, $haystack) { $needle_len = strlen($needle); - for ( $i = 0; $i < strlen($haystack); $i++ ) + if ( $pos = strstr($haystack, $needle) ) { - $test = substr($haystack, $i, $needle_len); - if ( $test == $needle ) - { - // Got it! - $upto = substr($haystack, 0, $i); - $from = substr($haystack, ( $i + $needle_len )); - $new_haystack = "{$upto}{$thread}{$from}"; - return $new_haystack; - } + $upto = substr($haystack, 0, ( strlen($haystack) - strlen($pos) )); + $from = substr($pos, $needle_len); + return "{$upto}{$thread}{$from}"; } return $haystack; } diff -r 27377179fe58 -r 4f9bec0d65c1 includes/lang.php --- a/includes/lang.php Wed Jul 02 19:36:44 2008 -0400 +++ b/includes/lang.php Wed Jul 02 22:15:55 2008 -0400 @@ -630,8 +630,8 @@ { return $string_id; } - profiler_log('Language(' . $this->lang_code . '): refetching due to missing string: ' . $string_id); $this->fetch(); + profiler_log('Language(' . $this->lang_code . '): refetched due to missing string: ' . $string_id); if ( isset($this->strings[$category]) && isset($this->strings[$category][$string_name]) ) { $found = true; diff -r 27377179fe58 -r 4f9bec0d65c1 includes/pageprocess.php --- a/includes/pageprocess.php Wed Jul 02 19:36:44 2008 -0400 +++ b/includes/pageprocess.php Wed Jul 02 22:15:55 2008 -0400 @@ -623,6 +623,9 @@ if ( !$q ) $db->_die('PageProcessor page creation - logging stage'); + // Update the cache + $paths->update_metadata_cache(); + // Page created. We're good! return true; } @@ -1125,7 +1128,7 @@ $text = '?>' . $text; $text = preg_replace('/(.*?)<\/nowiki>/s', '\\1', $text); } - // echo('
'.htmlspecialchars($text).'
'); + eval ( $text ); $code = $plugins->setHook('pageprocess_render_tail'); @@ -1354,7 +1357,14 @@ } // get the user's rank - $rank_data = $session->get_user_rank(intval($userdata['authoritative_uid'])); + if ( $user_exists ) + { + $rank_data = $session->get_user_rank(intval($userdata['authoritative_uid'])); + } + else + { + $rank_data = $session->get_user_rank(1); + } $this->header(); diff -r 27377179fe58 -r 4f9bec0d65c1 includes/pageutils.php --- a/includes/pageutils.php Wed Jul 02 19:36:44 2008 -0400 +++ b/includes/pageutils.php Wed Jul 02 22:15:55 2008 -0400 @@ -1307,7 +1307,7 @@ } $db->free_result(); $cat_all = Array(); - for($i=0;$ipages)/2;$i++) + foreach ( $paths->pages as $i => $_ ) { if($paths->pages[$i]['namespace']=='Category') $cat_all[] = $paths->pages[$i]; } @@ -1383,7 +1383,7 @@ $page_data =& $paths->pages[$paths->nslist[$namespace].$page_id]; $cat_all = Array(); - for($i=0;$ipages)/2;$i++) + foreach ( $paths->pages as $i => $_ ) { if($paths->pages[$i]['namespace']=='Category') $cat_all[] = $paths->pages[$i]; } diff -r 27377179fe58 -r 4f9bec0d65c1 includes/paths.php --- a/includes/paths.php Wed Jul 02 19:36:44 2008 -0400 +++ b/includes/paths.php Wed Jul 02 22:15:55 2008 -0400 @@ -116,6 +116,7 @@ $this->wiki_mode = ( getConfig('wiki_mode') == '1' ) ? 1 : 0; $this->template_cache = Array(); } + function parse_url($sanitize = true) { $title = ''; @@ -150,6 +151,7 @@ } return ( $sanitize ) ? sanitize_page_id($title) : $title; } + function init() { global $db, $session, $paths, $template, $plugins; // Common objects @@ -161,46 +163,38 @@ eval($cmd); } - $e = $db->sql_query('SELECT name,urlname,namespace,special,visible,comments_on,protected,delvotes,' . "\n" - . ' delvote_ips,wiki_mode,password FROM '.table_prefix.'pages ORDER BY name;'); - if( !$e ) + $cache_enable = ( getConfig('cache_thumbs') == '1' ); + $cache_file = ENANO_ROOT . '/cache/cache_page_meta.php'; + $cache_fresh = ( file_exists($cache_file) ) ? filemtime($cache_file) + 1800 >= time() : false; + if ( $cache_enable && $cache_fresh ) { - $db->_die('The error seems to have occured while selecting the page information. File: includes/paths.php; line: '.__LINE__); + require($cache_file); + if ( isset($page_cache) && is_array($page_cache) ) + { + $this->pages = array_merge($this->pages, $page_cache); + } } - while($r = $db->fetchrow()) + else { + $e = $db->sql_query('SELECT name,urlname,namespace,special,visible,comments_on,protected,delvotes,' . "\n" + . ' delvote_ips,wiki_mode,password FROM '.table_prefix.'pages ORDER BY name;'); - $r['urlname_nons'] = $r['urlname']; - if ( isset($this->nslist[$r['namespace']]) ) + if( !$e ) { - $r['urlname'] = $this->nslist[$r['namespace']] . $r['urlname']; // Applies the User:/File:/etc prefixes to the URL names + $db->_die('The error seems to have occured while selecting the page information. File: includes/paths.php; line: '.__LINE__); } - else + while($r = $db->fetchrow()) { - $ns_char = substr($this->nslist['Special'], -1); - $r['urlname'] = $r['namespace'] . $ns_char . $r['urlname']; + $r = $this->calculate_metadata_from_row($r); + + $this->pages[$r['urlname']] = $r; + $this->pages[] =& $this->pages[$r['urlname']]; } - if ( $r['delvotes'] == null) - { - $r['delvotes'] = 0; - } - if ( $r['protected'] == 0 || $r['protected'] == 1 ) - { - $r['really_protected'] = (int)$r['protected']; - } - else if ( $r['protected'] == 2 && getConfig('wiki_mode') == '1') + if ( $cache_enable ) { - $r['really_protected'] = 1; + $this->update_metadata_cache(); } - else if ( $r['protected'] == 2 && getConfig('wiki_mode') == '0' ) - { - $r['really_protected'] = 0; - } - - $this->pages[$r['urlname']] = $r; - $this->pages[] =& $this->pages[$r['urlname']]; - } $db->free_result(); if ( defined('ENANO_INTERFACE_INDEX') || defined('ENANO_INTERFACE_AJAX') || defined('IN_ENANO_UPGRADE') ) @@ -401,7 +395,6 @@ profiler_log('Paths and CMS core initted'); $session->init_permissions(); - profiler_log('Default ACL set retrieved'); } function add_page($flags) @@ -584,6 +577,86 @@ } /** + * Updates the cache containing all page metadata. + */ + + function update_metadata_cache() + { + global $db, $session, $paths, $template, $plugins; // Common objects + + $cache_output = <<sql_unbuffered_query('SELECT name,urlname,namespace,special,visible,comments_on,protected,delvotes,' . "\n" + . ' delvote_ips,wiki_mode,password FROM '.table_prefix.'pages ORDER BY name;'); + if ( !$e ) + $db->_die(); + + while ( $row = $db->fetchrow() ) + { + $row = $this->calculate_metadata_from_row($row); + $key = addslashes($row['urlname']); + $row = substr(preg_replace('/^/m', ' ', Language::var_export_string($row)), 2); + $cache_output .= "\n '$key' => $row,"; + } + + $cache_output .= "\n);\n"; + $cache_file = ENANO_ROOT . '/cache/cache_page_meta.php'; + + $fh = @fopen($cache_file, 'w'); + if ( !$fh ) + return false; + fwrite($fh, $cache_output); + fclose($fh); + + return true; + } + + /** + * Takes a result row from the pages table and calculates correct values for it. + * @param array + * @return array + */ + + function calculate_metadata_from_row($r) + { + $r['urlname_nons'] = $r['urlname']; + if ( isset($this->nslist[$r['namespace']]) ) + { + $r['urlname'] = $this->nslist[$r['namespace']] . $r['urlname']; // Applies the User:/File:/etc prefixes to the URL names + } + else + { + $ns_char = substr($this->nslist['Special'], -1); + $r['urlname'] = $r['namespace'] . $ns_char . $r['urlname']; + } + + if ( $r['delvotes'] == null) + { + $r['delvotes'] = 0; + } + if ( $r['protected'] == 0 || $r['protected'] == 1 ) + { + $r['really_protected'] = (int)$r['protected']; + } + else if ( $r['protected'] == 2 && getConfig('wiki_mode') == '1') + { + $r['really_protected'] = 1; + } + else if ( $r['protected'] == 2 && getConfig('wiki_mode') == '0' ) + { + $r['really_protected'] = 0; + } + return $r; + } + + /** * Registers a handler to manually process a namespace instead of the default PageProcessor behavior. * The first and only parameter passed to the processing function will be the PageProcessor instance. * @param string Namespace to process diff -r 27377179fe58 -r 4f9bec0d65c1 includes/plugins.php --- a/includes/plugins.php Wed Jul 02 19:36:44 2008 -0400 +++ b/includes/plugins.php Wed Jul 02 22:15:55 2008 -0400 @@ -288,89 +288,13 @@ // it's a PHP file, attempt to read metadata $fullpath = ENANO_ROOT . "/plugins/$dh"; - // first can we use cached info? - if ( isset($plugins_cache[$dh]) && $plugins_cache[$dh]['file md5'] === $this->md5_header($fullpath) ) - { - $plugin_meta = $plugins_cache[$dh]; - } - else + $plugin_meta = $this->get_plugin_info($fullpath); + + if ( is_array($plugin_meta) ) { - // the cache is out of date if we reached here -- regenerate - if ( $use_cache ) - $this->generate_plugins_cache(); - - // pass 1: try to read a !info block - $blockdata = $this->parse_plugin_blocks($fullpath, 'info'); - if ( empty($blockdata) ) - { - // no !info block, check for old header - $fh = @fopen($fullpath, 'r'); - if ( !$fh ) - // can't read, bail out - continue; - $plugin_data = array(); - for ( $i = 0; $i < 8; $i++ ) - { - $plugin_data[] = @fgets($fh, 8096); - } - // close our file handle - fclose($fh); - // is the header correct? - if ( trim($plugin_data[0]) != ' $value ) - { - $plugin_meta[ strtolower($key) ] = $value; - } - } + // all checks passed + $plugin_list[$dh] = $plugin_meta; } - if ( !isset($plugin_meta) || !is_array(@$plugin_meta) ) - { - // parsing didn't work. - continue; - } - // check for required keys - $required_keys = array('plugin name', 'plugin uri', 'description', 'author', 'version', 'author uri'); - foreach ( $required_keys as $key ) - { - if ( !isset($plugin_meta[$key]) ) - // not set, skip this plugin - continue 2; - } - // decide if it's a system plugin - $plugin_meta['system plugin'] = in_array($dh, $this->system_plugins); - // reset installed variable - $plugin_meta['installed'] = false; - $plugin_meta['status'] = 0; - // all checks passed - $plugin_list[$dh] = $plugin_meta; } } // gather info about installed plugins @@ -408,6 +332,103 @@ } /** + * Retrieves the metadata block from a plugin file + * @param string Path to plugin file (full path) + * @return array + */ + + function get_plugin_info($fullpath) + { + global $plugins_cache; + $dh = basename($fullpath); + + // first can we use cached info? + if ( isset($plugins_cache[$dh]) && $plugins_cache[$dh]['file md5'] === $this->md5_header($fullpath) ) + { + $plugin_meta = $plugins_cache[$dh]; + } + else + { + // the cache is out of date if we reached here -- regenerate + if ( $use_cache ) + $this->generate_plugins_cache(); + + // pass 1: try to read a !info block + $blockdata = $this->parse_plugin_blocks($fullpath, 'info'); + if ( empty($blockdata) ) + { + // no !info block, check for old header + $fh = @fopen($fullpath, 'r'); + if ( !$fh ) + // can't read, bail out + return false; + $plugin_data = array(); + for ( $i = 0; $i < 8; $i++ ) + { + $plugin_data[] = @fgets($fh, 8096); + } + // close our file handle + fclose($fh); + // is the header correct? + if ( trim($plugin_data[0]) != ' $value ) + { + $plugin_meta[ strtolower($key) ] = $value; + } + } + } + if ( !isset($plugin_meta) || !is_array(@$plugin_meta) ) + { + // parsing didn't work. + return false; + } + // check for required keys + $required_keys = array('plugin name', 'plugin uri', 'description', 'author', 'version', 'author uri'); + foreach ( $required_keys as $key ) + { + if ( !isset($plugin_meta[$key]) ) + // not set, skip this plugin + return false; + } + // decide if it's a system plugin + $plugin_meta['system plugin'] = in_array($dh, $this->system_plugins); + // reset installed variable + $plugin_meta['installed'] = false; + $plugin_meta['status'] = 0; + + return $plugin_meta; + } + + + /** * Attempts to cache plugin information in a file to speed fetching. */ diff -r 27377179fe58 -r 4f9bec0d65c1 includes/search.php --- a/includes/search.php Wed Jul 02 19:36:44 2008 -0400 +++ b/includes/search.php Wed Jul 02 22:15:55 2008 -0400 @@ -501,8 +501,6 @@ { if ( $page['namespace'] != 'Special' || $page['visible'] == 0 ) continue; - if ( !is_int($id) ) - continue; $idstring = 'ns=' . $page['namespace'] . ';pid=' . $page['urlname_nons']; $any = array_values(array_unique(array_merge($query['any'], $query_phrase['any']))); foreach ( $any as $term ) diff -r 27377179fe58 -r 4f9bec0d65c1 includes/sessions.php --- a/includes/sessions.php Wed Jul 02 19:36:44 2008 -0400 +++ b/includes/sessions.php Wed Jul 02 22:15:55 2008 -0400 @@ -2519,8 +2519,11 @@ // cache info if possible static $_cache = array(); + if ( is_int($id) && $id == 0 ) + $id = 1; + if ( is_int($id) ) - $col = "user_id = $id"; + $col = "u.user_id = $id"; else if ( is_string($id) ) $col = ENANO_SQLFUNC_LOWERCASE . "(username) = " . ENANO_SQLFUNC_LOWERCASE . "('" . $db->escape($id) . "')"; else diff -r 27377179fe58 -r 4f9bec0d65c1 includes/template.php --- a/includes/template.php Wed Jul 02 19:36:44 2008 -0400 +++ b/includes/template.php Wed Jul 02 22:15:55 2008 -0400 @@ -83,11 +83,6 @@ $this->theme_list[$i] = $row; $i++; } - // List out all CSS files for this theme - foreach ( $this->theme_list as $i => &$theme ) - { - $theme['css'] = $this->get_theme_css_files($theme['theme_id']); - } unset($theme); $this->theme_list = array_values($this->theme_list); // Create associative array of themes @@ -95,6 +90,7 @@ $this->named_theme_list[ $theme['theme_id'] ] =& $this->theme_list[$i]; $this->default_theme = ( $_ = getConfig('theme_default') ) ? $_ : $this->theme_list[0]['theme_id']; + $this->named_theme_list[ $this->default_theme ]['css'] = $this->get_theme_css_files($this->default_theme); // Come up with the default style. If the CSS file specified in default_style exists, we're good, just // use that. Otherwise, use the first stylesheet that comes to mind. $df_data =& $this->named_theme_list[ $this->default_theme ]; @@ -1394,12 +1390,12 @@ if ( file_exists($cache_file) ) { // this is about the time of the breaking change to cache file format - if ( filemtime($cache_file) > 1215038089 ) + if ( ($m = filemtime($cache_file)) > 1215038089 ) { $result = @include($cache_file); if ( isset($md5) ) { - if ( $md5 == md5_file(ENANO_ROOT . "/themes/{$this->theme}/$file") ) + if ( $m >= filemtime(ENANO_ROOT . "/themes/{$this->theme}/$file") ) { $result = $this->compile_template_text_post($result); return $result; diff -r 27377179fe58 -r 4f9bec0d65c1 index.php --- a/index.php Wed Jul 02 19:36:44 2008 -0400 +++ b/index.php Wed Jul 02 22:15:55 2008 -0400 @@ -19,7 +19,7 @@ define('ENANO_INTERFACE_INDEX', ''); // For the mighty and brave. - define('ENANO_DEBUG', ''); + // define('ENANO_DEBUG', ''); // Set up gzip encoding before any output is sent diff -r 27377179fe58 -r 4f9bec0d65c1 plugins/PrivateMessages.php --- a/plugins/PrivateMessages.php Wed Jul 02 19:36:44 2008 -0400 +++ b/plugins/PrivateMessages.php Wed Jul 02 22:15:55 2008 -0400 @@ -24,7 +24,7 @@ global $db, $session, $paths, $template, $plugins; // Common objects -$plugins->attachHook('session_started', 'PrivateMessages_paths_init();'); +// $plugins->attachHook('session_started', 'PrivateMessages_paths_init();'); function PrivateMessages_paths_init() { diff -r 27377179fe58 -r 4f9bec0d65c1 plugins/SpecialAdmin.php --- a/plugins/SpecialAdmin.php Wed Jul 02 19:36:44 2008 -0400 +++ b/plugins/SpecialAdmin.php Wed Jul 02 22:15:55 2008 -0400 @@ -24,7 +24,7 @@ global $db, $session, $paths, $template, $plugins; // Common objects -$plugins->attachHook('session_started', 'SpecialAdmin_paths_init();'); +// $plugins->attachHook('session_started', 'SpecialAdmin_paths_init();'); function SpecialAdmin_paths_init() { @@ -165,6 +165,7 @@ // Stats if(getConfig('log_hits') == '1') { + require_once(ENANO_ROOT . '/includes/stats.php'); $stats = stats_top_pages(10); //die('
'.print_r($stats,true).'
'); $c = 0; diff -r 27377179fe58 -r 4f9bec0d65c1 plugins/SpecialCSS.php --- a/plugins/SpecialCSS.php Wed Jul 02 19:36:44 2008 -0400 +++ b/plugins/SpecialCSS.php Wed Jul 02 22:15:55 2008 -0400 @@ -24,7 +24,7 @@ global $db, $session, $paths, $template, $plugins; // Common objects -$plugins->attachHook('session_started', 'SpecialCSS_paths_init();'); +// $plugins->attachHook('session_started', 'SpecialCSS_paths_init();'); function SpecialCSS_paths_init() { diff -r 27377179fe58 -r 4f9bec0d65c1 plugins/SpecialGroups.php --- a/plugins/SpecialGroups.php Wed Jul 02 19:36:44 2008 -0400 +++ b/plugins/SpecialGroups.php Wed Jul 02 22:15:55 2008 -0400 @@ -22,7 +22,7 @@ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for details. */ -$plugins->attachHook('session_started', 'SpecialGroups_paths_init();'); +// $plugins->attachHook('session_started', 'SpecialGroups_paths_init();'); function SpecialGroups_paths_init() { diff -r 27377179fe58 -r 4f9bec0d65c1 plugins/SpecialPageFuncs.php --- a/plugins/SpecialPageFuncs.php Wed Jul 02 19:36:44 2008 -0400 +++ b/plugins/SpecialPageFuncs.php Wed Jul 02 22:15:55 2008 -0400 @@ -24,7 +24,7 @@ global $db, $session, $paths, $template, $plugins; // Common objects -$plugins->attachHook('session_started', 'SpecialPageFuncs_paths_init();'); +// $plugins->attachHook('session_started', 'SpecialPageFuncs_paths_init();'); function SpecialPageFuncs_paths_init() { diff -r 27377179fe58 -r 4f9bec0d65c1 plugins/SpecialRecentChanges.php --- a/plugins/SpecialRecentChanges.php Wed Jul 02 19:36:44 2008 -0400 +++ b/plugins/SpecialRecentChanges.php Wed Jul 02 22:15:55 2008 -0400 @@ -24,7 +24,7 @@ global $db, $session, $paths, $template, $plugins; // Common objects -$plugins->attachHook('session_started', 'SpecialRecentChanges_paths_init();'); +// $plugins->attachHook('session_started', 'SpecialRecentChanges_paths_init();'); function SpecialRecentChanges_paths_init() { diff -r 27377179fe58 -r 4f9bec0d65c1 plugins/SpecialSearch.php --- a/plugins/SpecialSearch.php Wed Jul 02 19:36:44 2008 -0400 +++ b/plugins/SpecialSearch.php Wed Jul 02 22:15:55 2008 -0400 @@ -22,7 +22,7 @@ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for details. */ -$plugins->attachHook('session_started', 'SpecialSearch_paths_init();'); +// $plugins->attachHook('session_started', 'SpecialSearch_paths_init();'); function SpecialSearch_paths_init() { diff -r 27377179fe58 -r 4f9bec0d65c1 plugins/SpecialUpdownload.php --- a/plugins/SpecialUpdownload.php Wed Jul 02 19:36:44 2008 -0400 +++ b/plugins/SpecialUpdownload.php Wed Jul 02 22:15:55 2008 -0400 @@ -25,7 +25,7 @@ global $db, $session, $paths, $template, $plugins; // Common objects -$plugins->attachHook('session_started', 'SpecialUpDownload_paths_init();'); +// $plugins->attachHook('session_started', 'SpecialUpDownload_paths_init();'); function SpecialUpDownload_paths_init() { diff -r 27377179fe58 -r 4f9bec0d65c1 plugins/SpecialUserFuncs.php --- a/plugins/SpecialUserFuncs.php Wed Jul 02 19:36:44 2008 -0400 +++ b/plugins/SpecialUserFuncs.php Wed Jul 02 22:15:55 2008 -0400 @@ -24,7 +24,7 @@ global $db, $session, $paths, $template, $plugins; // Common objects -$plugins->attachHook('session_started', 'SpecialUserFuncs_paths_init();'); +// $plugins->attachHook('session_started', 'SpecialUserFuncs_paths_init();'); function SpecialUserFuncs_paths_init() {