# HG changeset patch # User Dan # Date 1215041804 14400 # Node ID 27377179fe58a4b32ba7a59ec496041d39520dd0 # Parent 2529833a77314fd907965840df86d4539164b794 Another sweep from the optimization monster. template: rewrote parts of tplWikiFormat to do faster validation and less eval()ing template: sidebar is now cached for anonymous users (thanks to Richard Greene for the suggestion) dbal: rewrote SQL query parser, much cruft taken out template: made tplWikiFormat depend more on RenderMan common: moved some lesser-used includes out of main loading sequence Expect a lot of changes to AES code in the next commit! diff -r 2529833a7731 -r 27377179fe58 ajax.php --- a/ajax.php Mon Jun 30 17:22:29 2008 -0400 +++ b/ajax.php Wed Jul 02 19:36:44 2008 -0400 @@ -14,76 +14,6 @@ define('ENANO_INTERFACE_AJAX', ''); - // fillusername should be done without the help of the rest of Enano - all we need is the DBAL - if ( isset($_GET['_mode']) && $_GET['_mode'] == 'fillusername' ) - { - // setup and load a very basic, specialized instance of the Enano API - function microtime_float() - { - list($usec, $sec) = explode(" ", microtime()); - return ((float)$usec + (float)$sec); - } - // Determine directory (special case for development servers) - if ( strpos(__FILE__, '/repo/') && file_exists('.enanodev') ) - { - $filename = str_replace('/repo/', '/', __FILE__); - } - else - { - $filename = __FILE__; - } - define('ENANO_ROOT', dirname($filename)); - require(ENANO_ROOT.'/includes/functions.php'); - require(ENANO_ROOT.'/includes/dbal.php'); - require(ENANO_ROOT.'/includes/json2.php'); - - require(ENANO_ROOT . '/config.php'); - unset($dbuser, $dbpasswd); - if ( !isset($dbdriver) ) - $dbdriver = 'mysql'; - - $db = new $dbdriver(); - - $db->connect(); - - // result is sent using JSON - $return = Array( - 'mode' => 'success', - 'users_real' => Array() - ); - - // should be connected to the DB now - $name = (isset($_GET['name'])) ? $db->escape($_GET['name']) : false; - if ( !$name ) - { - $return = array( - 'mode' => 'error', - 'error' => 'Invalid URI' - ); - die( enano_json_encode($return) ); - } - $allowanon = ( isset($_GET['allowanon']) && $_GET['allowanon'] == '1' ) ? '' : ' AND user_id > 1'; - $q = $db->sql_query('SELECT username FROM '.table_prefix.'users WHERE ' . ENANO_SQLFUNC_LOWERCASE . '(username) LIKE ' . ENANO_SQLFUNC_LOWERCASE . '(\'%'.$name.'%\')' . $allowanon . ' ORDER BY username ASC;'); - if ( !$q ) - { - $db->die_json(); - } - $i = 0; - while($r = $db->fetchrow()) - { - $return['users_real'][] = $r['username']; - $i++; - } - $db->free_result(); - - // all done! :-) - $db->close(); - - echo enano_json_encode( $return ); - - exit; - } - require('includes/common.php'); global $db, $session, $paths, $template, $plugins; // Common objects @@ -93,6 +23,7 @@ switch($_GET['_mode']) { case "checkusername": + require_once(ENANO_ROOT.'/includes/pageutils.php'); echo PageUtils::checkusername($_GET['name']); break; case "getsource": @@ -230,18 +161,7 @@ break; case "savepage": /* **** OBSOLETE **** */ - $summ = ( isset($_POST['summary']) ) ? $_POST['summary'] : ''; - $minor = isset($_POST['minor']); - $e = PageUtils::savepage($paths->page_id, $paths->namespace, $_POST['text'], $summ, $minor); - if ( $e == 'good' ) - { - $page = new PageProcessor($paths->page_id, $paths->namespace); - $page->send(); - } - else - { - echo '

Error saving the page: '.$e.'

'; - } + break; case "savepage_json": header('Content-type: application/json'); @@ -434,6 +354,7 @@ echo enano_json_encode($result); break; case "histlist": + require_once(ENANO_ROOT.'/includes/pageutils.php'); echo PageUtils::histlist($paths->page_id, $paths->namespace); break; case "rollback": @@ -445,6 +366,7 @@ echo enano_json_encode($result); break; case "comments": + require_once(ENANO_ROOT.'/includes/comment.php'); $comments = new Comments($paths->page_id, $paths->namespace); if ( isset($_POST['data']) ) { @@ -463,33 +385,42 @@ echo enano_json_encode($result); break; case "flushlogs": + require_once(ENANO_ROOT.'/includes/pageutils.php'); echo PageUtils::flushlogs($paths->page_id, $paths->namespace); break; case "deletepage": + require_once(ENANO_ROOT.'/includes/pageutils.php'); $reason = ( isset($_POST['reason']) ) ? $_POST['reason'] : false; if ( empty($reason) ) die($lang->get('page_err_need_reason')); echo PageUtils::deletepage($paths->page_id, $paths->namespace, $reason); break; case "delvote": + require_once(ENANO_ROOT.'/includes/pageutils.php'); echo PageUtils::delvote($paths->page_id, $paths->namespace); break; case "resetdelvotes": + require_once(ENANO_ROOT.'/includes/pageutils.php'); echo PageUtils::resetdelvotes($paths->page_id, $paths->namespace); break; case "getstyles": + require_once(ENANO_ROOT.'/includes/pageutils.php'); echo PageUtils::getstyles($_GET['id']); break; case "catedit": + require_once(ENANO_ROOT.'/includes/pageutils.php'); echo PageUtils::catedit($paths->page_id, $paths->namespace); break; case "catsave": + require_once(ENANO_ROOT.'/includes/pageutils.php'); echo PageUtils::catsave($paths->page_id, $paths->namespace, $_POST); break; case "setwikimode": + require_once(ENANO_ROOT.'/includes/pageutils.php'); echo PageUtils::setwikimode($paths->page_id, $paths->namespace, (int)$_GET['mode']); break; case "setpass": + require_once(ENANO_ROOT.'/includes/pageutils.php'); echo PageUtils::setpass($paths->page_id, $paths->namespace, $_POST['password']); break; case "fillusername": @@ -537,9 +468,11 @@ } break; case "preview": + require_once(ENANO_ROOT.'/includes/pageutils.php'); echo PageUtils::genPreview($_POST['text']); break; case "pagediff": + require_once(ENANO_ROOT.'/includes/pageutils.php'); $id1 = ( isset($_GET['diff1']) ) ? (int)$_GET['diff1'] : false; $id2 = ( isset($_GET['diff2']) ) ? (int)$_GET['diff2'] : false; if(!$id1 || !$id2) { echo '

Invalid request.

'; $template->footer(); break; } @@ -558,6 +491,7 @@ else echo $rdns; break; case 'acljson': + require_once(ENANO_ROOT.'/includes/pageutils.php'); $parms = ( isset($_POST['acl_params']) ) ? rawurldecode($_POST['acl_params']) : false; echo PageUtils::acl_json($parms); break; diff -r 2529833a7731 -r 27377179fe58 includes/clientside/static/ajax.js --- a/includes/clientside/static/ajax.js Mon Jun 30 17:22:29 2008 -0400 +++ b/includes/clientside/static/ajax.js Wed Jul 02 19:36:44 2008 -0400 @@ -149,7 +149,11 @@ if ( !box ) return false; - var newname = ( obj.getElementsByTagName('input')[0] ).value; + var input = obj.getElementsByTagName('input')[0]; + console.debug(obj, input); + if ( !input ) + return false; + var newname = input.value; newname = trim(newname); if ( newname.length < 1 ) diff -r 2529833a7731 -r 27377179fe58 includes/clientside/static/enano-lib-basic.js --- a/includes/clientside/static/enano-lib-basic.js Mon Jun 30 17:22:29 2008 -0400 +++ b/includes/clientside/static/enano-lib-basic.js Wed Jul 02 19:36:44 2008 -0400 @@ -465,6 +465,7 @@ ajaxEditTheme: 'theme-manager.js', ajaxToggleSystemThemes: 'theme-manager.js', ajaxInstallTheme: 'theme-manager.js', + ajaxInitRankEdit: 'rank-manager.js' }; var placeholder_instances = {}; diff -r 2529833a7731 -r 27377179fe58 includes/clientside/static/functions.js --- a/includes/clientside/static/functions.js Mon Jun 30 17:22:29 2008 -0400 +++ b/includes/clientside/static/functions.js Wed Jul 02 19:36:44 2008 -0400 @@ -558,6 +558,7 @@ return z; } +var shift = false; function isKeyPressed(event) { if (event.shiftKey==1) diff -r 2529833a7731 -r 27377179fe58 includes/common.php --- a/includes/common.php Mon Jun 30 17:22:29 2008 -0400 +++ b/includes/common.php Wed Jul 02 19:36:44 2008 -0400 @@ -138,20 +138,10 @@ require_once(ENANO_ROOT.'/includes/template.php'); require_once(ENANO_ROOT.'/includes/plugins.php'); require_once(ENANO_ROOT.'/includes/lang.php'); -require_once(ENANO_ROOT.'/includes/comment.php'); -require_once(ENANO_ROOT.'/includes/wikiformat.php'); -require_once(ENANO_ROOT.'/includes/diff.php'); require_once(ENANO_ROOT.'/includes/render.php'); -require_once(ENANO_ROOT.'/includes/stats.php'); -require_once(ENANO_ROOT.'/includes/pageutils.php'); -require_once(ENANO_ROOT.'/includes/js-compressor.php'); require_once(ENANO_ROOT.'/includes/rijndael.php'); require_once(ENANO_ROOT.'/includes/email.php'); -require_once(ENANO_ROOT.'/includes/search.php'); -require_once(ENANO_ROOT.'/includes/json.php'); require_once(ENANO_ROOT.'/includes/json2.php'); -require_once(ENANO_ROOT.'/includes/math.php'); -require_once(ENANO_ROOT.'/includes/wikiengine/Tables.php'); require_once(ENANO_ROOT.'/includes/pageprocess.php'); require_once(ENANO_ROOT.'/includes/tagcloud.php'); @@ -198,6 +188,8 @@ // END BACKGROUND AND ENVIRONMENT CHECKS // +profiler_log('Background/environment checks done'); + // // MAIN API INITIALIZATION // @@ -308,7 +300,6 @@
 <?php
 define("ENANO_ALLOW_LOAD_NOLANG", 1);
-$_GET["title"] = "langinstall";
 require("includes/common.php");
 install_language("eng", "English", "English", ENANO_ROOT . "/language/english/enano.json");
'); } diff -r 2529833a7731 -r 27377179fe58 includes/constants.php --- a/includes/constants.php Mon Jun 30 17:22:29 2008 -0400 +++ b/includes/constants.php Wed Jul 02 19:36:44 2008 -0400 @@ -76,6 +76,13 @@ define('IMAGE_TYPE_GIF', 2); define('IMAGE_TYPE_JPG', 3); +// token types +define('TOKEN_VARIABLE', 1); +define('TOKEN_BOOLOP', 2); +define('TOKEN_PARENTHLEFT', 3); +define('TOKEN_PARENTHRIGHT', 4); +define('TOKEN_NOT', 5); + // // User types - don't touch these // diff -r 2529833a7731 -r 27377179fe58 includes/dbal.php --- a/includes/dbal.php Mon Jun 30 17:22:29 2008 -0400 +++ b/includes/dbal.php Wed Jul 02 19:36:44 2008 -0400 @@ -32,7 +32,10 @@ $debug = $debug[0]['file'] . ', line ' . $debug[0]['line']; echo "$errtype: $errstr
Error source:
$debug
"; } - + +global $db_sql_parse_time; +$db_sql_parse_time = 0; + class mysql { var $num_queries, $query_backtrace, $query_times, $query_sources, $latest_result, $latest_query, $_conn, $sql_stack_fields, $sql_stack_values, $debug; var $row = array(); @@ -309,79 +312,46 @@ } /** - * Checks a SQL query for possible signs of injection attempts + * Performs heuristic analysis on a SQL query to check for known attack patterns. * @param string $q the query to check * @return bool true if query passed check, otherwise false */ function check_query($q, $debug = false) { - if($debug) echo "\$db->check_query(): checking query: ".htmlspecialchars($q).'
'."\n"; - $sz = strlen($q); - $quotechar = false; - $quotepos = 0; - $prev_is_quote = false; - $just_started = false; - for ( $i = 0; $i < strlen($q); $i++, $c = substr($q, $i, 1) ) + global $db_sql_parse_time; + $ts = microtime_float(); + + // remove properly escaped quotes + $q = str_replace(array("\\\"", "\\'"), '', $q); + + // make sure quotes match + foreach ( array('"', "'") as $quote ) { - $next = substr($q, $i+1, 1); - $next2 = substr($q, $i+2, 1); - $prev = substr($q, $i-1, 1); - $prev2 = substr($q, $i-2, 1); - if(isset($c) && in_array($c, Array('"', "'", '`'))) + if ( get_char_count($q, $quote) % 2 == 1 ) { - if($quotechar) - { - if ( - ( $quotechar == $c && $quotechar != $next && ( $quotechar != $prev || $just_started ) && $prev != '\\') || - ( $prev2 == '\\' && $prev == $quotechar && $quotechar == $c ) - ) - { - $quotechar = false; - if($debug) echo('$db->check_query(): just finishing a quote section, quoted string: '.htmlspecialchars(substr($q, $quotepos, $i - $quotepos + 1)) . '
'); - $q = substr($q, 0, $quotepos) . 'SAFE_QUOTE' . substr($q, $i + 1, strlen($q)); - if($debug) echo('$db->check_query(): Filtered query: '.$q.'
'); - $i = $quotepos; - } - } - else - { - $quotechar = $c; - $quotepos = $i; - $just_started = true; - } - if($debug) echo '$db->check_query(): found quote char as pos: '.$i.'
'; - continue; - } - $just_started = false; - } - if(substr(trim($q), strlen(trim($q))-1, 1) == ';') $q = substr(trim($q), 0, strlen(trim($q))-1); - for($i=0;$i'; - else $e .= $c; - } - echo 'Injection attempt caught at pos: '.$i.'
'; - } + // mismatched quotes return false; } + // this quote is now confirmed to be matching; we can safely move all quoted strings out and replace with a token + $q = preg_replace("/$quote(.*?)$quote/s", 'SAFE_QUOTE', $q); } + $q = preg_replace("/(SAFE_QUOTE)+/", 'SAFE_QUOTE', $q); + + // quotes are now matched out. does this string have a comment marker in it? + if ( strstr($q, '--') ) + { + return false; + } + if ( preg_match('/[\s]+(SAFE_QUOTE|[\S]+)=\\1($|[\s]+)/', $q, $match) ) { if ( $debug ) echo 'Found always-true test in query, injection attempt caught, match:
' . '
' . print_r($match, true) . '
'; return false; } + + $ts = microtime_float() - $ts; + $db_sql_parse_time += $ts; return true; } @@ -1066,72 +1036,39 @@ function check_query($q, $debug = false) { - if($debug) echo "\$db->check_query(): checking query: ".htmlspecialchars($q).'
'."\n"; - $sz = strlen($q); - $quotechar = false; - $quotepos = 0; - $prev_is_quote = false; - $just_started = false; - for ( $i = 0; $i < strlen($q); $i++, $c = substr($q, $i, 1) ) + global $db_sql_parse_time; + $ts = microtime_float(); + + // remove properly escaped quotes + $q = str_replace(array("\\\"", "\\'"), '', $q); + + // make sure quotes match + foreach ( array('"', "'") as $quote ) { - $next = substr($q, $i+1, 1); - $next2 = substr($q, $i+2, 1); - $prev = substr($q, $i-1, 1); - $prev2 = substr($q, $i-2, 1); - if(isset($c) && in_array($c, Array('"', "'", '`'))) + if ( get_char_count($q, $quote) % 2 == 1 ) { - if($quotechar) - { - if ( - ( $quotechar == $c && $quotechar != $next && ( $quotechar != $prev || $just_started ) && $prev != '\\') || - ( $prev2 == '\\' && $prev == $quotechar && $quotechar == $c ) - ) - { - $quotechar = false; - if($debug) echo('$db->check_query(): just finishing a quote section, quoted string: '.htmlspecialchars(substr($q, $quotepos, $i - $quotepos + 1)) . '
'); - $q = substr($q, 0, $quotepos) . 'SAFE_QUOTE' . substr($q, $i + 1, strlen($q)); - if($debug) echo('$db->check_query(): Filtered query: '.$q.'
'); - $i = $quotepos; - } - } - else - { - $quotechar = $c; - $quotepos = $i; - $just_started = true; - } - if($debug) echo '$db->check_query(): found quote char as pos: '.$i.'
'; - continue; - } - $just_started = false; - } - if(substr(trim($q), strlen(trim($q))-1, 1) == ';') $q = substr(trim($q), 0, strlen(trim($q))-1); - for($i=0;$i'; - else $e .= $c; - } - echo 'Injection attempt caught at pos: '.$i.'
'; - } + // mismatched quotes return false; } + // this quote is now confirmed to be matching; we can safely move all quoted strings out and replace with a token + $q = preg_replace("/$quote(.*?)$quote/s", 'SAFE_QUOTE', $q); } + $q = preg_replace("/(SAFE_QUOTE)+/", 'SAFE_QUOTE', $q); + + // quotes are now matched out. does this string have a comment marker in it? + if ( strstr($q, '--') ) + { + return false; + } + if ( preg_match('/[\s]+(SAFE_QUOTE|[\S]+)=\\1($|[\s]+)/', $q, $match) ) { if ( $debug ) echo 'Found always-true test in query, injection attempt caught, match:
' . '
' . print_r($match, true) . '
'; return false; } + + $ts = microtime_float() - $ts; + $db_sql_parse_time += $ts; return true; } diff -r 2529833a7731 -r 27377179fe58 includes/functions.php --- a/includes/functions.php Mon Jun 30 17:22:29 2008 -0400 +++ b/includes/functions.php Wed Jul 02 19:36:44 2008 -0400 @@ -4325,6 +4325,10 @@ foreach ( $profile as $i => $entry ) { + // $time_since_last = $entry['time'] - $time_last; + // if ( $time_since_last < 0.01 ) + // continue; + $html .= "\n\n Event $i\n"; $html .= '' . "\n"; diff -r 2529833a7731 -r 27377179fe58 includes/pageprocess.php --- a/includes/pageprocess.php Mon Jun 30 17:22:29 2008 -0400 +++ b/includes/pageprocess.php Wed Jul 02 19:36:44 2008 -0400 @@ -157,8 +157,6 @@ if ( !is_int($revision_id) ) $revision_id = 0; - profiler_log("PageProcessor [{$namespace}:{$page_id}]: Ran initial checks"); - $this->_setup( $page_id, $namespace, $revision_id ); } @@ -172,7 +170,7 @@ global $db, $session, $paths, $template, $plugins; // Common objects global $lang; - profiler_log("PageProcessor [{$this->namespace}:{$this->page_id}]: Started send process"); + profiler_log('PageProcessor: send() called'); if ( !$this->perms->get_permissions('read') ) { @@ -190,7 +188,6 @@ { // Page isn't whitelisted, behave as normal $this->err_access_denied(); - profiler_log("PageProcessor [{$this->namespace}:{$this->page_id}]: Finished send process"); return false; } } @@ -237,7 +234,6 @@ if ( $this->password != $password ) { $this->err_wrong_password(); - profiler_log("PageProcessor [{$this->namespace}:{$this->page_id}]: Finished send process"); return false; } } @@ -245,6 +241,7 @@ } if ( $this->page_exists && $this->namespace != 'Special' && $this->namespace != 'Admin' && $do_stats ) { + require_once(ENANO_ROOT.'/includes/stats.php'); doStats($this->page_id, $this->namespace); } if ( $this->namespace == 'Special' || $this->namespace == 'Admin' ) @@ -265,9 +262,7 @@ $func_name = "page_{$this->namespace}_{$this->page_id}"; if ( function_exists($func_name) ) { - profiler_log("PageProcessor [{$this->namespace}:{$this->page_id}]: Calling special/admin page"); $result = @call_user_func($func_name); - profiler_log("PageProcessor [{$this->namespace}:{$this->page_id}]: Finished send process"); return $result; } else @@ -287,7 +282,6 @@ echo "

$title

$message

"; } - profiler_log("PageProcessor [{$this->namespace}:{$this->page_id}]: Finished send process"); return false; } } @@ -372,13 +366,11 @@ $template->init_vars($this); } - // die($this->page_id); + $text = $this->fetch_text(); - $text = $this->fetch_text(); if ( $text == 'err_no_text_rows' ) { $this->err_no_rows(); - profiler_log("PageProcessor [{$this->namespace}:{$this->page_id}]: Finished send process"); return false; } else @@ -409,7 +401,6 @@ } } } - profiler_log("PageProcessor [{$this->namespace}:{$this->page_id}]: Finished send process"); } /** @@ -1029,6 +1020,7 @@ global $lang; $text = $this->fetch_text(); + $text = preg_replace('/([\s]*)__NOBREADCRUMBS__([\s]*)/', '', $text); $text = preg_replace('/([\s]*)__NOTOC__([\s]*)/', '', $text); @@ -1228,7 +1220,6 @@ } else { - $q = $db->sql_query('SELECT t.page_text, t.char_tag, l.time_id FROM '.table_prefix."page_text AS t\n" . " LEFT JOIN " . table_prefix . "logs AS l\n" . " ON ( l.page_id = t.page_id AND l.namespace = t.namespace )\n" diff -r 2529833a7731 -r 27377179fe58 includes/paths.php --- a/includes/paths.php Mon Jun 30 17:22:29 2008 -0400 +++ b/includes/paths.php Wed Jul 02 19:36:44 2008 -0400 @@ -113,7 +113,7 @@ eval($cmd); } - $this->wiki_mode = (int)getConfig('wiki_mode')=='1'; + $this->wiki_mode = ( getConfig('wiki_mode') == '1' ) ? 1 : 0; $this->template_cache = Array(); } function parse_url($sanitize = true) diff -r 2529833a7731 -r 27377179fe58 includes/render.php --- a/includes/render.php Mon Jun 30 17:22:29 2008 -0400 +++ b/includes/render.php Wed Jul 02 19:36:44 2008 -0400 @@ -217,6 +217,9 @@ global $db, $session, $paths, $template, $plugins; // Common objects global $lang; + require_once(ENANO_ROOT.'/includes/wikiformat.php'); + require_once(ENANO_ROOT.'/includes/wikiengine/Tables.php'); + profiler_log("RenderMan: starting wikitext render"); $random_id = md5( time() . mt_rand() ); @@ -474,13 +477,19 @@ /** * Parses internal links (wikilinks) in a block of text. * @param string Text to process + * @param string Optional. If included will be used as a template instead of using the default syntax. * @return string */ - public static function parse_internal_links($text) + public static function parse_internal_links($text, $tplcode = false) { global $db, $session, $paths, $template, $plugins; // Common objects + if ( is_string($tplcode) ) + { + $parser = $template->makeParserText($tplcode); + } + // stage 1 - links with alternate text preg_match_all('/\[\[([^\[\]<>\{\}\|]+)\|(.+?)\]\]/', $text, $matches); foreach ( $matches[0] as $i => $match ) @@ -493,7 +502,19 @@ $quot = '"'; $exists = ( isPage($pid_clean) ) ? '' : ' class="wikilink-nonexistent"'; - $link = "{$inner_text}"; + if ( $tplcode ) + { + $parser->assign_vars(array( + 'HREF' => $url, + 'FLAGS' => $exists, + 'TEXT' => $inner_text + )); + $link = $parser->run(); + } + else + { + $link = "{$inner_text}"; + } $text = str_replace($match, $link, $text); } @@ -510,7 +531,19 @@ $quot = '"'; $exists = ( isPage($pid_clean) ) ? '' : ' class="wikilink-nonexistent"'; - $link = "{$inner_text}"; + if ( $tplcode ) + { + $parser->assign_vars(array( + 'HREF' => $url, + 'FLAGS' => $exists, + 'TEXT' => $inner_text + )); + $link = $parser->run(); + } + else + { + $link = "{$inner_text}"; + } $text = str_replace($match, $link, $text); } @@ -845,6 +878,7 @@ public static function diff($str1, $str2) { global $db, $session, $paths, $template, $plugins; // Common objects + require_once(ENANO_ROOT.'/includes/diff.php'); $str1 = explode("\n", $str1); $str2 = explode("\n", $str2); $diff = new Diff($str1, $str2); diff -r 2529833a7731 -r 27377179fe58 includes/sessions.php --- a/includes/sessions.php Mon Jun 30 17:22:29 2008 -0400 +++ b/includes/sessions.php Wed Jul 02 19:36:44 2008 -0400 @@ -586,8 +586,8 @@ . ' ON g.group_id=m.group_id' . "\n" . ' WHERE ( m.user_id='.$this->user_id.'' . "\n" . ' OR g.group_name=\'Everyone\')' . "\n" - . ' ' . ( enano_version() == '1.0RC1' ? '' : 'AND ( m.pending != 1 OR m.pending IS NULL )' ) . '' . "\n" - . ' ORDER BY group_id ASC;'); // Make sure "Everyone" comes first so the permissions can be overridden + . ' ' . ( /* quick hack for upgrade compatibility reasons */ enano_version() == '1.0RC1' ? '' : 'AND ( m.pending != 1 OR m.pending IS NULL )' ) . '' . "\n" + . ' ORDER BY group_id ASC;'); // The ORDER BY is to make sure "Everyone" comes first so the permissions can be overridden if($row = $db->fetchrow()) { do { @@ -2801,6 +2801,8 @@ $objcache[$namespace][$page_id] = new Session_ACLPageInfo( $page_id, $namespace, $this->acl_types, $this->acl_descs, $this->acl_deps, $this->acl_base_cache ); $object =& $objcache[$namespace][$page_id]; + profiler_log("session: fetched ACLs for page {$namespace}:{$page_id}"); + return $object; } @@ -3020,48 +3022,12 @@ // Cache the sitewide permissions for later use $this->acl_base_cache = $this->perms; - // Eliminate types that don't apply to this namespace - foreach ( $this->perms AS $i => $perm ) - { - if ( !in_array ( $paths->namespace, $this->acl_scope[$i] ) && !in_array('All', $this->acl_scope[$i]) ) - { - unset($this->perms[$i]); - } - } - - // PAGE group info - $pg_list = $paths->get_page_groups($paths->page_id, $paths->namespace); - $pg_info = ''; - foreach ( $pg_list as $g_id ) - { - $pg_info .= ' ( page_id=\'' . $g_id . '\' AND namespace=\'__PageGroup\' ) OR'; - } + profiler_log('session: base ACL set calculated'); - // Build a query to grab ACL info - $bs = 'SELECT rules,target_type,target_id FROM '.table_prefix.'acl WHERE ( '; - $q = Array(); - $q[] = '( target_type='.ACL_TYPE_USER.' AND target_id='.$this->user_id.' )'; - if(count($this->groups) > 0) - { - foreach($this->groups as $g_id => $g_name) - { - $q[] = '( target_type='.ACL_TYPE_GROUP.' AND target_id='.intval($g_id).' )'; - } - } - // The reason we're using an ORDER BY statement here is because ACL_TYPE_GROUP is less than ACL_TYPE_USER, causing the user's individual - // permissions to override group permissions. - $bs .= implode(" OR\n ", $q) . " )\n AND (" . $pg_info . ' ( page_id=\''.$db->escape($paths->page_id).'\' AND namespace=\''.$db->escape($paths->namespace).'\' ) ) - ORDER BY target_type ASC, page_id ASC, namespace ASC;'; - $q = $this->sql($bs); - if ( $row = $db->fetchrow() ) - { - do { - $rules = $this->string_to_perm($row['rules']); - $is_everyone = ( $row['target_type'] == ACL_TYPE_GROUP && $row['target_id'] == 1 ); - $this->acl_merge_with_current($rules, $is_everyone); - } while ( $row = $db->fetchrow() ); - } - + // Load and calculate permissions for the current page + $page_acl = $this->fetch_page_acl($paths->page_id, $paths->namespace); + $this->perms = $page_acl->perms; + $this->acl_defaults_used = $page_acl->acl_defaults_used; } /** @@ -3558,6 +3524,8 @@ global $db, $session, $paths, $template, $plugins; // Common objects // Setup EnanoMath and Diffie-Hellman + require_once(ENANO_ROOT.'/includes/math.php'); + global $dh_supported; $dh_supported = true; try diff -r 2529833a7731 -r 27377179fe58 includes/template.php --- a/includes/template.php Mon Jun 30 17:22:29 2008 -0400 +++ b/includes/template.php Wed Jul 02 19:36:44 2008 -0400 @@ -86,23 +86,9 @@ // List out all CSS files for this theme foreach ( $this->theme_list as $i => &$theme ) { - $theme['css'] = array(); - $dir = ENANO_ROOT . "/themes/{$theme['theme_id']}/css"; - if ( $dh = @opendir($dir) ) - { - while ( ( $file = @readdir($dh) ) !== false ) - { - if ( preg_match('/\.css$/', $file) ) - $theme['css'][] = preg_replace('/\.css$/', '', $file); - } - closedir($dh); - } - // No CSS files? If so, nuke it. - if ( count($theme['css']) < 1 ) - { - unset($this->theme_list[$i]); - } + $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 foreach ( $this->theme_list as $i => &$theme ) @@ -116,6 +102,33 @@ } /** + * Gets the list of available CSS files (styles) for the specified theme. + * @param string Theme ID + * @return array + */ + + function get_theme_css_files($theme_id) + { + $css = array(); + $dir = ENANO_ROOT . "/themes/{$theme_id}/css"; + if ( $dh = @opendir($dir) ) + { + while ( ( $file = @readdir($dh) ) !== false ) + { + if ( preg_match('/\.css$/', $file) ) + $css[] = preg_replace('/\.css$/', '', $file); + } + closedir($dh); + } + // No CSS files? If so, nuke it. + if ( count($css) < 1 ) + { + unset($this->theme_list[$theme_id]); + } + return $css; + } + + /** * Failsafe constructor for upgrades. */ @@ -566,8 +579,6 @@ // PAGE TOOLBAR (on-page controls/actions) // - profiler_log('template: var init: finished initial setup, starting toolbar'); - // Initialize the toolbar $tb = ''; @@ -948,8 +959,6 @@ // OTHER SWITCHES // - profiler_log('template: var init: finshed toolbar, starting other switches'); - $is_opera = (isset($_SERVER['HTTP_USER_AGENT']) && strstr($_SERVER['HTTP_USER_AGENT'], 'Opera')) ? true : false; $this->tpl_bool = Array( @@ -1043,8 +1052,6 @@ $admin_link = $parser->run(); - profiler_log('template: var init: finished sidebar/misc processing, starting dynamic vars and finalization'); - $SID = ($session->sid_super) ? $session->sid_super : ''; $urlname_clean = str_replace('\'', '\\\'', str_replace('\\', '\\\\', dirtify_page_id($local_fullpage))); @@ -1111,8 +1118,6 @@ } $js_dynamic .= "\n //]]>\n "; - profiler_log('template: var init: finished JS dynamic vars and assigning final var set'); - $tpl_strings = Array( 'PAGE_NAME'=>htmlspecialchars($local_cdata['name']), 'PAGE_URLNAME'=> $urlname_clean, @@ -1154,14 +1159,14 @@ $this->assign_vars($tpl_strings, true); + profiler_log('template: var init: finished toolbar building and initial assign()'); + // // COMPILE THE SIDEBAR // // This is done after the big assign_vars() so that sidebar code has access to the newly assigned variables - profiler_log('template: var init: finished final var set, executing and applying sidebar templates'); - list($this->tpl_strings['SIDEBAR_LEFT'], $this->tpl_strings['SIDEBAR_RIGHT'], $min) = $this->fetch_sidebar(); $this->tpl_bool['sidebar_left'] = ( $this->tpl_strings['SIDEBAR_LEFT'] != $min) ? true : false; $this->tpl_bool['sidebar_right'] = ( $this->tpl_strings['SIDEBAR_RIGHT'] != $min) ? true : false; @@ -1299,7 +1304,11 @@ $t = str_replace('[[EnanoPoweredLinkLong]]', $lang->get('page_enano_powered_long', array('about_uri' => $this->tpl_strings['URL_ABOUT_ENANO'])), $t); if ( defined('ENANO_DEBUG') ) + { $t = str_replace('', '
' . profiler_make_html() . '
', $t); + // ob_end_clean(); + // return profiler_make_html(); + } return $t; } @@ -1381,8 +1390,28 @@ $this->init_vars(); } + $cache_file = ENANO_ROOT . '/cache/' . $this->theme . '-' . str_replace('/', '-', $file) . '.php'; + if ( file_exists($cache_file) ) + { + // this is about the time of the breaking change to cache file format + if ( filemtime($cache_file) > 1215038089 ) + { + $result = @include($cache_file); + if ( isset($md5) ) + { + if ( $md5 == md5_file(ENANO_ROOT . "/themes/{$this->theme}/$file") ) + { + $result = $this->compile_template_text_post($result); + return $result; + } + } + } + } + $compiled = $this->compile_template($file); - return eval($compiled); + $result = eval($compiled); + + return $result; } /** @@ -1475,30 +1504,7 @@

'); } - // Check for cached copy - // This will make filenames in the pattern of theme-file.tpl.php - $cache_file = ENANO_ROOT . '/cache/' . $this->theme . '-' . str_replace('/', '-', $filename) . '.php'; - - // Only use cached copy if caching is enabled - // (it is enabled by default I think) - if ( file_exists($cache_file) && getConfig('cache_thumbs') == '1' ) - { - // Cache files are auto-generated, but otherwise are normal PHP files - include($cache_file); - - // Fetch content of the ORIGINAL - $text = file_get_contents($tpl_file_fullpath); - - // $md5 will be set by the cached file - // This makes sure that a cached copy of the template is used only if its MD5 - // matches the MD5 of the file that the compiled file was compiled from. - if ( isset($md5) && $md5 == md5($text) ) - { - return $this->compile_template_text_post(str_replace('\\"', '"', $tpl_text)); - } - } - - // We won't use the cached copy here + // We won't use the cached copy here. $text = file_get_contents($tpl_file_fullpath); // This will be used later when writing the cached file @@ -1507,6 +1513,9 @@ // Preprocessing and checks complete - compile the code $text = $this->compile_tpl_code($text); + // Generate cache filename + $cache_file = ENANO_ROOT . '/cache/' . $this->theme . '-' . str_replace('/', '-', $filename) . '.php'; + // Perhaps caching is enabled and the admin has changed the template? if ( is_writable( ENANO_ROOT . '/cache/' ) && getConfig('cache_thumbs') == '1' ) { @@ -1517,19 +1526,22 @@ return $text; } - // Escape the compiled code so it can be eval'ed - $text_escaped = addslashes($text); - $notice = <<'); + fwrite($h, $file_contents); fclose($h); } @@ -1613,6 +1625,26 @@ global $db, $session, $paths, $template, $plugins; // Common objects global $lang; + $START = microtime_float(); + + // localize the whole string first + preg_match_all('/\{lang:([a-z0-9]+_[a-z0-9_]+)\}/', $message, $matches); + foreach ( $matches[1] as $i => $string_id ) + { + $string = $lang->get($string_id); + $string = str_replace('\\', '\\\\', $string); + $string = str_replace('\'', '\\\'', $string); + $message = str_replace_once($matches[0][$i], $string, $message); + } + + // first: the hackish optimization - + // if it's only a bunch of letters, numbers and spaces, just skip this sh*t. + + if ( preg_match('/^[\w\s\.]*$/i', $message) ) + { + return $message; + } + $filter_links = false; $tplvars = $this->extract_vars($filename); if($session->sid_super) $as = htmlspecialchars(urlSeparator).'auth='.$session->sid_super; @@ -1636,185 +1668,45 @@ // Conditionals - preg_match_all('#\{if ([A-Za-z0-9_ \(\)&\|\!-]*)\}(.*?)\{\/if\}#is', $message, $links); - - // Temporary exception from coding standards - using tab length of 4 here for clarity - for ( $i = 0; $i < sizeof($links[1]); $i++ ) - { - $condition =& $links[1][$i]; - $message = str_replace('{if '.$condition.'}'.$links[2][$i].'{/if}', '{CONDITIONAL:'.$i.':'.$random_id.'}', $message); - - // Time for some manual parsing... - $chk = false; - $current_id = ''; - $prn_level = 0; - // Used to keep track of where we are in the conditional - // Object of the game: turn {if this && ( that OR !something_else )} ... {/if} into if( ( isset($this->tpl_bool['that']) && $this->tpl_bool['that'] ) && ... - // Method of attack: escape all variables, ignore all else. Non-valid code is filtered out by a regex above. - $in_var_now = true; - $in_var_last = false; - $current_var = ''; - $current_var_start_pos = 0; - $current_var_end_pos = 0; - $j = -1; - $condition = $condition . ' '; - $d = strlen($condition); - while($j < $d) - { - $j++; - $in_var_last = $in_var_now; - - $char = substr($condition, $j, 1); - $in_var_now = ( preg_match('#^([A-z0-9_]*){1}$#', $char) ) ? true : false; - if(!$in_var_last && $in_var_now) - { - $current_var_start_pos = $j; - } - if($in_var_last && !$in_var_now) - { - $current_var_end_pos = $j; - } - if($in_var_now) - { - $current_var .= $char; - continue; - } - // OK we are not inside of a variable. That means that we JUST hit the end because the counter ($j) will be advanced to the beginning of the next variable once processing here is complete. - if($char != ' ' && $char != '(' && $char != ')' && $char != 'A' && $char != 'N' && $char != 'D' && $char != 'O' && $char != 'R' && $char != '&' && $char != '|' && $char != '!' && $char != '<' && $char != '>' && $char != '0' && $char != '1' && $char != '2' && $char != '3' && $char != '4' && $char != '5' && $char != '6' && $char != '7' && $char != '8' && $char != '9') - { - // XSS attack! Bail out - $errmsg = '

Error: Syntax error (possibly XSS attack) caught in template code:

'; - $errmsg .= '
';
-                $errmsg .= '{if '.htmlspecialchars($condition).'}';
-                $errmsg .= "\n    ";
-                for ( $k = 0; $k < $j; $k++ )
-                {
-                    $errmsg .= " ";
-                }
-                // Show position of error
-                $errmsg .= '^';
-                $errmsg .= '
'; - $message = str_replace('{CONDITIONAL:'.$i.':'.$random_id.'}', $errmsg, $message); - continue 2; - } - if($current_var != '') - { - $cd = '( isset($this->tpl_bool[\''.$current_var.'\']) && $this->tpl_bool[\''.$current_var.'\'] )'; - $cvt = substr($condition, 0, $current_var_start_pos) . $cd . substr($condition, $current_var_end_pos, strlen($condition)); - $j = $j + strlen($cd) - strlen($current_var); - $current_var = ''; - $condition = $cvt; - $d = strlen($condition); - } - } - $condition = substr($condition, 0, strlen($condition)-1); - $condition = '$chk = ( '.$condition.' ) ? true : false;'; - eval($condition); - - if($chk) - { - if(strstr($links[2][$i], '{else}')) $c = substr($links[2][$i], 0, strpos($links[2][$i], '{else}')); - else $c = $links[2][$i]; - $message = str_replace('{CONDITIONAL:'.$i.':'.$random_id.'}', $c, $message); - } - else - { - if(strstr($links[2][$i], '{else}')) $c = substr($links[2][$i], strpos($links[2][$i], '{else}')+6, strlen($links[2][$i])); - else $c = ''; - $message = str_replace('{CONDITIONAL:'.$i.':'.$random_id.'}', $c, $message); - } - } - - preg_match_all('#\{!if ([A-Za-z_-]*)\}(.*?)\{\/if\}#is', $message, $links); - - for($i=0;$itpl_bool[$links[1][$i]]) && $this->tpl_bool[$links[1][$i]]) { - if(strstr($links[2][$i], '{else}')) $c = substr($links[2][$i], strpos($links[2][$i], '{else}')+6, strlen($links[2][$i])); - else $c = ''; - $message = str_replace('{CONDITIONAL:'.$i.':'.$random_id.'}', $c, $message); - } else { - if(strstr($links[2][$i], '{else}')) $c = substr($links[2][$i], 0, strpos($links[2][$i], '{else}')); - else $c = $links[2][$i]; - $message = str_replace('{CONDITIONAL:'.$i.':'.$random_id.'}', $c, $message); - } - } - - preg_match_all('/\{lang:([a-z0-9]+_[a-z0-9_]+)\}/', $message, $matches); - foreach ( $matches[1] as $i => $string_id ) - { - $string = $lang->get($string_id); - $string = str_replace('\\', '\\\\', $string); - $string = str_replace('\'', '\\\'', $string); - $message = str_replace_once($matches[0][$i], $string, $message); - } + $message = $this->twf_parse_conditionals($message); /* * HTML RENDERER */ // Images - $j = preg_match_all('#\[\[:'.$paths->nslist['File'].'([\w\s0-9_\(\)!@%\^\+\|\.-]+?)\]\]#is', $message, $matchlist); - $matches = Array(); - $matches['images'] = $matchlist[1]; - for($i=0;$inslist['File'].$matches['images'][$i])) - { - $message = str_replace('[[:'.$paths->nslist['File'].$matches['images'][$i].']]', - ''.$matches['images'][$i].'', - $message); - } - } + $message = RenderMan::process_image_tags($message, $taglist); + $message = RenderMan::process_imgtags_stage2($message, $taglist); // Internal links - - $text_parser = $this->makeParserText($tplvars['sidebar_button']); - - preg_match_all("#\[\[([^\|\]\n\a\r\t]*?)\]\]#is", $message, $il); - for($i=0;$iassign_vars(Array( - 'HREF' => $href, - 'FLAGS' => '', - 'TEXT' => $il[1][$i] - )); - $message = str_replace("[[{$il[1][$i]}]]", $text_parser->run(), $message); - } - - preg_match_all('#\[\[([^\|\]\n\a\r\t]*?)\|([^\]\r\n\a\t]*?)\]\]#is', $message, $il); - for($i=0;$iassign_vars(Array( - 'HREF' => $href, - 'FLAGS' => '', - 'TEXT' => $il[2][$i] - )); - $message = str_replace("[[{$il[1][$i]}|{$il[2][$i]}]]", $text_parser->run(), $message); - } + $message = RenderMan::parse_internal_links($message, $tplvars['sidebar_button']); // External links - // $message = preg_replace('#\[(http|ftp|irc):\/\/([a-z0-9\/:_\.\?&%\#@_\\\\-]+?) ([^\]]+)\\]#', '\\3
', $message); - // $message = preg_replace('#\[(http|ftp|irc):\/\/([a-z0-9\/:_\.\?&%\#@_\\\\-]+?)\\]#', '\\1://\\2
', $message); - preg_match_all('/\[((https?|ftp|irc):\/\/([^@\s\]"\':]+)?((([a-z0-9-]+\.)*)[a-z0-9-]+)(\/[A-z0-9_%\|~`!\!@#\$\^&\*\(\):;\.,\/-]*(\?(([a-z0-9_-]+)(=[A-z0-9_%\|~`\!@#\$\^&\*\(\):;\.,\/-\[\]]+)?((&([a-z0-9_-]+)(=[A-z0-9_%\|~`!\!@#\$\^&\*\(\):;\.,\/-]+)?)*))?)?)?) ([^\]]+)\]/is', $message, $ext_link); - - // die('
' . htmlspecialchars( print_r($ext_link, true) ) . '
'); + $url_regexp = <<makeParserText($tplvars['sidebar_button']); + + preg_match_all('/\[' . $url_regexp . '[ ]([^\]]+)\]/isx', $message, $ext_link); for ( $i = 0; $i < count($ext_link[0]); $i++ ) { $text_parser->assign_vars(Array( 'HREF' => $ext_link[1][$i], 'FLAGS' => '', - 'TEXT' => $ext_link[16][$i] + 'TEXT' => $ext_link[2][$i] )); $message = str_replace($ext_link[0][$i], $text_parser->run(), $message); } - preg_match_all('/\[((https?|ftp|irc):\/\/([^@\s\]"\':]+)?((([a-z0-9-]+\.)*)[a-z0-9-]+)(\/[A-z0-9_%\|~`!\!@#\$\^&\*\(\):;\.,\/-]*(\?(([a-z0-9_-]+)(=[A-z0-9_%\|~`\!@#\$\^&\*\(\):;\.,\/-\[\]]+)?((&([a-z0-9_-]+)(=[A-z0-9_%\|~`!\!@#\$\^&\*\(\):;\.,\/-]+)?)*))?)?)?)\]/is', $message, $ext_link); + preg_match_all('/\[' . $url_regexp . '\]/is', $message, $ext_link); for ( $i = 0; $i < count($ext_link[0]); $i++ ) { @@ -1826,34 +1718,182 @@ $message = str_replace($ext_link[0][$i], $text_parser->run(), $message); } - $parser1 = $this->makeParserText($tplvars['sidebar_section']); - $parser2 = $this->makeParserText($tplvars['sidebar_section_raw']); - - preg_match_all('#\{slider(2|)=([^\}]*?)\}(.*?)\{\/slider(2|)\}#is', $message, $sb); - - // Modified to support the sweet new template var system - for($i=0;$iassign_vars(Array('TITLE'=>$sb[2][$i],'CONTENT'=>$sb[3][$i])); - $message = str_replace("{slider{$sb[1][$i]}={$sb[2][$i]}}{$sb[3][$i]}{/slider{$sb[4][$i]}}", $p->run(), $message); - } + $TIME = microtime_float() - $START; /* - Extras ;-) - $message = preg_replace('##is', '', $message); - $message = preg_replace('##is', '', $message); - $message = preg_replace('##is', '', $message); - $message = preg_replace('##is', '', $message); - $message = preg_replace('##is', '', $message); + if ( $TIME > 0.02 ) + { + echo 'template: tplWikiFormat took a while for this one. string dump:
';
+      echo htmlspecialchars($message);
+      echo '
'; + } */ - //die('
'.htmlspecialchars($message).'
'); - //eval($message); exit; + return $message; + } + + /** + * Parses conditional {if} blocks in sidebars and other tplWikiFormatted things + * @param string A string potentially containing conditional blocks + * @return string Processed string + */ + + function twf_parse_conditionals($message) + { + if ( !preg_match_all('/\{(!?)if ([a-z0-9_\(\)\|&! ]+)\}(.*?)(?:\{else\}(.*?))?\{\/if\}/is', $message, $matches) ) + { + return $message; + } + foreach ( $matches[0] as $match_id => $full_block ) + { + // 1 = "not" flag + // 2 = condition + // 3 = if true + // 4 = else + $condresult = $this->process_condition($matches[2][$match_id]); + if ( !empty($matches[1][$match_id]) ) + { + if ( $condresult == 1 ) + $condresult = 2; + else if ( $condresult == 2 ) + $condresult = 1; + } + switch($condresult) + { + case 1: + // evaluated to false + $message = str_replace_once($full_block, $matches[4][$match_id], $message); + break; + case 2: + // evaluated to true + $message = str_replace_once($full_block, $matches[3][$match_id], $message); + break; + case 3: + $message = str_replace_once($full_block, "Syntax error: mismatched parentheses (" . htmlspecialchars($matches[2][$match_id]) . ")
\n", $message); + break; + case 4: + $message = str_replace_once($full_block, "Syntax error: illegal character (" . htmlspecialchars($matches[2][$match_id]) . ")
\n", $message); + break; + case 5: + $message = str_replace_once($full_block, "Syntax error: illegal sequence (" . htmlspecialchars($matches[2][$match_id]) . ")
\n", $message); + break; + } + } return $message; } /** + * Inner-loop parser for a conditional block. Verifies a string condition to make sure it's syntactically correct, then returns what it evaluates to. + * Return values: + * 1 - string evaluates to true + * 2 - string evaluates to false + * 3 - Syntax error - mismatched parentheses + * 4 - Syntax error - unknown token + * 5 - Syntax error - invalid sequence + * @param string + * @return int + * + */ + + function process_condition($condition) + { + // make sure parentheses are matched + $parentheses = preg_replace('/[^\(\)]/', '', $condition); + if ( !empty($parentheses) ) + { + $i = 0; + $parentheses = enano_str_split($parentheses); + foreach ( $parentheses as $chr ) + { + $inc = ( $chr == '(' ) ? 1 : -1; + $i += $inc; + } + if ( $i != 0 ) + { + // mismatched parentheses + return 3; + } + } + // sequencer check + // first, pad all sequences of characters with spaces + $seqcheck = preg_replace('/([a-z0-9_]+)/i', '\\1 ', $condition); + $seqcheck = preg_replace('/([&|()!])/i', '\\1 ', $seqcheck); + // now shrink all spaces to one space each + $seqcheck = preg_replace('/[ ]+/', ' ', $seqcheck); + + // explode it. the allowed sequences are: + // - TOKEN_NOT + TOKEN_VARIABLE + // - TOKEN_NOT + TOKEN_PARENTHLEFT + // - TOKEN_BOOLOP + TOKEN_NOT + // - TOKEN_PARENTHRIGHT + TOKEN_NOT + // - TOKEN_VARIABLE + TOKEN_BOOLOP + // - TOKEN_BOOLOP + TOKEN_PARENTHLEFT + // - TOKEN_PARENTHLEFT + TOKEN_VARIABLE + // - TOKEN_BOOLOP + TOKEN_VARIABLE + // - TOKEN_VARIABLE + TOKEN_PARENTHRIGHT + // - TOKEN_PARENTHRIGHT + TOKEN_BOOLOP + $seqcheck = explode(' ', trim($seqcheck)); + $last_item = TOKEN_BOOLOP; + foreach ( $seqcheck as $i => $token ) + { + // determine type + if ( $token == '(' ) + { + $type = TOKEN_PARENTHLEFT; + } + else if ( $token == ')' ) + { + $type = TOKEN_PARENTHRIGHT; + } + else if ( $token == '!' ) + { + $type = TOKEN_NOT; + } + else if ( strtolower($token) == 'and' || strtolower($token) == 'or' || $token == '&&' || $token == '||' ) + { + $type = TOKEN_BOOLOP; + } + else if ( preg_match('/^[a-z0-9_]+$/i', $token) ) + { + $type = TOKEN_VARIABLE; + // at this point it's considered safe to wrap it + $seqcheck[$i] = "( isset(\$this->tpl_bool['$token']) && \$this->tpl_bool['$token'] )"; + } + else + { + // syntax error - doesn't match known token types + return 4; + } + // inner sequence check + if ( + ( $last_item == TOKEN_BOOLOP && $type == TOKEN_NOT ) || + ( $last_item == TOKEN_PARENTHRIGHT && $type == TOKEN_NOT ) || + ( $last_item == TOKEN_NOT && $type == TOKEN_VARIABLE ) || + ( $last_item == TOKEN_NOT && $type == TOKEN_PARENTHLEFT ) || + ( $last_item == TOKEN_VARIABLE && $type == TOKEN_BOOLOP ) || + ( $last_item == TOKEN_BOOLOP && $type == TOKEN_PARENTHLEFT ) || + ( $last_item == TOKEN_PARENTHLEFT && $type == TOKEN_VARIABLE ) || + ( $last_item == TOKEN_BOOLOP && $type == TOKEN_VARIABLE ) || + ( $last_item == TOKEN_VARIABLE && $type == TOKEN_PARENTHRIGHT ) || + ( $last_item == TOKEN_PARENTHRIGHT && $type == TOKEN_BOOLOP ) + ) + { + // sequence is good, continue + } + else + { + // sequence is invalid, break out + return 5; + } + $last_item = $type; + } + // passed all checks + $seqcheck = implode(' ', $seqcheck); + $result = eval("return ( $seqcheck ) ? true : false;"); + return ( $result ) ? 2 : 1; + } + + /** * Print a text field that auto-completes a username entered into it. * @param string $name - the name of the form field * @return string @@ -1977,6 +2017,25 @@ $left = ''; $right = ''; + // check the cache + $cache_enable = getConfig('cache_thumbs') == '1' && !$session->user_logged_in; + $cache_file = ENANO_ROOT . "/cache/cache_anon_sidebar.php"; + $cache_fresh = intval(getConfig('sidebar_anon_cache_time') + 600) >= time(); + if ( $cache_enable && $cache_fresh ) + { + @include($cache_file); + if ( isset($sidebar_cache) ) + { + // we loaded the cache! + foreach ( $sidebar_cache as $i => $_ ) + { + $block =& $sidebar_cache[$i]; + $block = str_replace('$USERNAME$', $session->username, $block); + } + return $sidebar_cache; + } + } + if ( !$this->fetch_block('Links') ) $this->initLinksWidget(); @@ -1988,9 +2047,11 @@ if(isset($vars['sidebar_top'])) { - $left .= $this->parse($vars['sidebar_top']); - $right .= $this->parse($vars['sidebar_top']); + $top = $this->parse($vars['sidebar_top']); + $left .= $top; + $right .= $top; } + while($row = $db->fetchrow()) { switch($row['block_type']) @@ -2033,19 +2094,42 @@ $db->free_result(); if(isset($vars['sidebar_bottom'])) { - $left .= $this->parse($vars['sidebar_bottom']); - $right .= $this->parse($vars['sidebar_bottom']); + $bottom = $this->parse($vars['sidebar_bottom']); + $left .= $bottom; + $right .= $bottom; } $min = ''; if(isset($vars['sidebar_top'])) { - $min .= $this->parse($vars['sidebar_top']); + $min .= $top; } if(isset($vars['sidebar_bottom'])) { - $min .= $this->parse($vars['sidebar_bottom']); + $min .= $bottom; } - return Array($left, $right, $min); + $return = Array($left, $right, $min); + if ( $cache_enable ) + { + $cachestore = Language::var_export_string($return); + $cachestore = str_replace($session->username, '$USERNAME$', $cachestore); + $cachestore = <<user_level >= USER_LEVEL_ADMIN ) ? 'title="You may disable this button in the admin panel under General Configuration."' : ''; if(getConfig('sflogo_enabled')=='1') { @@ -2676,11 +2761,8 @@ function process_template($file) { - profiler_log("[template_nodb] STARTED eval of file $file"); $compiled = $this->compile_template($file); - profiler_log("[template_nodb] COMPILED file $file"); $result = eval($compiled); - profiler_log("[template_nodb] FINISHED eval of file $file"); return $result; } diff -r 2529833a7731 -r 27377179fe58 index.php --- a/index.php Mon Jun 30 17:22:29 2008 -0400 +++ b/index.php Wed Jul 02 19:36:44 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 @@ -65,6 +65,7 @@ break; case 'comments': $template->header(); + require_once(ENANO_ROOT.'/includes/pageutils.php'); $sub = ( isset ($_GET['sub']) ) ? $_GET['sub'] : false; switch($sub) { @@ -121,6 +122,7 @@ redirect(makeUrl($paths->page), '', '', 0); break; } + require_once(ENANO_ROOT.'/includes/pageutils.php'); if(isset($_POST['_save'])) { $captcha_valid = true; @@ -258,6 +260,7 @@ $template->footer(); break; case 'history': + require_once(ENANO_ROOT.'/includes/pageutils.php'); $hist = PageUtils::histlist($paths->page_id, $paths->namespace); $template->header(); echo $hist; @@ -286,6 +289,7 @@ $template->footer(); break; case 'catedit': + require_once(ENANO_ROOT.'/includes/pageutils.php'); if(isset($_POST['__enanoSaveButton'])) { unset($_POST['__enanoSaveButton']); @@ -313,6 +317,7 @@ break; case 'protect': if (!isset($_REQUEST['level'])) die_friendly('Invalid request', '

No protection level specified

'); + require_once(ENANO_ROOT.'/includes/pageutils.php'); if(!empty($_POST['reason'])) { if(!preg_match('#^([0-2]*){1}$#', $_POST['level'])) die_friendly('Error protecting page', '

Request validation failed

'); @@ -349,6 +354,7 @@ $template->footer(); break; case 'rename': + require_once(ENANO_ROOT.'/includes/pageutils.php'); if(!empty($_POST['newname'])) { $r = PageUtils::rename($paths->page_id, $paths->namespace, $_POST['newname']); @@ -370,6 +376,7 @@ { die_friendly($lang->get('etc_access_denied_short'), '

' . $lang->get('etc_access_denied') . '

'); } + require_once(ENANO_ROOT.'/includes/pageutils.php'); if(isset($_POST['_downthejohn'])) { $template->header(); @@ -388,6 +395,7 @@ $template->footer(); break; case 'delvote': + require_once(ENANO_ROOT.'/includes/pageutils.php'); if(isset($_POST['_ballotbox'])) { $template->header(); @@ -416,6 +424,7 @@ $template->footer(); break; case 'resetvotes': + require_once(ENANO_ROOT.'/includes/pageutils.php'); if(!$session->get_permissions('vote_reset')) { die_friendly($lang->get('etc_access_denied_short'), '

' . $lang->get('etc_access_denied') . '

'); @@ -442,6 +451,7 @@ { die_friendly($lang->get('etc_access_denied_short'), '

' . $lang->get('etc_access_denied') . '

'); } + require_once(ENANO_ROOT.'/includes/pageutils.php'); if(isset($_POST['_adiossucker'])) { $reason = ( isset($_POST['reason']) ) ? $_POST['reason'] : false; @@ -509,6 +519,8 @@ } break; case 'diff': + require_once(ENANO_ROOT.'/includes/pageutils.php'); + require_once(ENANO_ROOT.'/includes/diff.php'); $template->header(); $id1 = ( isset($_GET['diff1']) ) ? (int)$_GET['diff1'] : false; $id2 = ( isset($_GET['diff2']) ) ? (int)$_GET['diff2'] : false; @@ -533,6 +545,7 @@ die_friendly($lang->get('page_detag_success_title'), '

' . $lang->get('page_detag_success_body') . '

'); break; case 'aclmanager': + require_once(ENANO_ROOT.'/includes/pageutils.php'); $data = ( isset($_POST['data']) ) ? $_POST['data'] : Array('mode' => 'listgroups'); PageUtils::aclmanager($data); break; diff -r 2529833a7731 -r 27377179fe58 plugins/SpecialSearch.php --- a/plugins/SpecialSearch.php Mon Jun 30 17:22:29 2008 -0400 +++ b/plugins/SpecialSearch.php Wed Jul 02 19:36:44 2008 -0400 @@ -65,6 +65,8 @@ global $aggressive_optimize_html; global $lang; + require_once(ENANO_ROOT.'/includes/search.php'); + $aggressive_optimize_html = false; if ( !$q = $paths->getParam(0) )