# HG changeset patch # User Dan # Date 1231024278 18000 # Node ID 9cdfe82c56cdc025a889934f8aa6923cb00cba45 # Parent 4629ad98ee8872977f668a3ab05aa1e60b7e155c Major underlying changes to namespace handling. Each namespace is handled by its own class which extends Namespace_Default. Much greater customization/pluggability potential, at the possible expense of some code reusing (though code reusing has been avoided thus far). Also a bit better handling of page passwords [SECURITY]. diff -r 4629ad98ee88 -r 9cdfe82c56cd ajax.php --- a/ajax.php Sat Jan 03 17:54:26 2009 -0500 +++ b/ajax.php Sat Jan 03 18:11:18 2009 -0500 @@ -32,6 +32,7 @@ $revid = ( isset($_GET['revid']) ) ? intval($_GET['revid']) : 0; $page = new PageProcessor($paths->page_id, $paths->namespace, $revid); $page->password = $password; + $have_draft = false; if ( $src = $page->fetch_source() ) { @@ -151,6 +152,8 @@ break; case "getpage": // echo PageUtils::getpage($paths->page, false, ( (isset($_GET['oldid'])) ? $_GET['oldid'] : false )); + $output = new Output_Striptease(); + $revision_id = ( (isset($_GET['oldid'])) ? intval($_GET['oldid']) : 0 ); $page = new PageProcessor( $paths->page_id, $paths->namespace, $revision_id ); diff -r 4629ad98ee88 -r 9cdfe82c56cd includes/clientside/jsres.php --- a/includes/clientside/jsres.php Sat Jan 03 17:54:26 2009 -0500 +++ b/includes/clientside/jsres.php Sat Jan 03 18:11:18 2009 -0500 @@ -270,7 +270,8 @@ header("Last-Modified: $date"); header("ETag: \"$etag\""); header("Expires: $expires"); -header("Content-Length: " . strlen($everything)); +if ( !$do_gzip ) + header("Content-Length: " . strlen($everything)); $local_end = microtime_float(); $local_gentime = $local_end - $local_start; diff -r 4629ad98ee88 -r 9cdfe82c56cd includes/clientside/static/ajax.js --- a/includes/clientside/static/ajax.js Sat Jan 03 17:54:26 2009 -0500 +++ b/includes/clientside/static/ajax.js Sat Jan 03 18:11:18 2009 -0500 @@ -13,7 +13,7 @@ enableUnload(); setAjaxLoading(); var redir = ( disable_redirect ) ? '&redirect=no' : ''; - ajaxGet(scriptPath + '/ajax.php?title=' + physical_title +'&_mode=getpage&noheaders' + redir, function() { + ajaxGet(append_sid(scriptPath + '/ajax.php?title=' + physical_title +'&_mode=getpage&noheaders' + redir), function() { // Allow for 404 here, it's generated by the "page not found" error message // (even with noheaders specified, probably should be fixed) if ( ajax.readyState == 4 && ( ajax.status == 200 || ajax.status == 404 ) ) { diff -r 4629ad98ee88 -r 9cdfe82c56cd includes/comment.php --- a/includes/comment.php Sat Jan 03 17:54:26 2009 -0500 +++ b/includes/comment.php Sat Jan 03 18:11:18 2009 -0500 @@ -16,7 +16,7 @@ * Class that handles comments. Has HTML/Javascript frontend support. * @package Enano CMS * @subpackage Comment manager - * @license GNU General Public License + * @license GNU General Public License */ class Comments diff -r 4629ad98ee88 -r 9cdfe82c56cd includes/common.php --- a/includes/common.php Sat Jan 03 17:54:26 2009 -0500 +++ b/includes/common.php Sat Jan 03 18:11:18 2009 -0500 @@ -136,6 +136,7 @@ require_once(ENANO_ROOT.'/includes/paths.php'); require_once(ENANO_ROOT.'/includes/sessions.php'); require_once(ENANO_ROOT.'/includes/template.php'); +require_once(ENANO_ROOT.'/includes/output.php'); require_once(ENANO_ROOT.'/includes/plugins.php'); require_once(ENANO_ROOT.'/includes/cache.php'); require_once(ENANO_ROOT.'/includes/lang.php'); @@ -144,6 +145,7 @@ require_once(ENANO_ROOT.'/includes/email.php'); require_once(ENANO_ROOT.'/includes/json2.php'); require_once(ENANO_ROOT.'/includes/pageprocess.php'); +require_once(ENANO_ROOT.'/includes/namespaces/default.php'); require_once(ENANO_ROOT.'/includes/tagcloud.php'); strip_magic_quotes_gpc(); @@ -442,6 +444,14 @@ $paths->init(); + // setup output format + if ( defined('ENANO_OUTPUT_FORMAT') ) + $class = 'Output_' . ENANO_OUTPUT_FORMAT; + else + $class = ( isset($_GET['noheaders']) ) ? 'Output_Naked' : 'Output_HTML'; + + $output = new $class(); + // We're ready for whatever life throws us now, at least from an API point of view. define('ENANO_MAINSTREAM', ''); diff -r 4629ad98ee88 -r 9cdfe82c56cd includes/functions.php --- a/includes/functions.php Sat Jan 03 17:54:26 2009 -0500 +++ b/includes/functions.php Sat Jan 03 18:11:18 2009 -0500 @@ -277,7 +277,7 @@ { $logged_in = true; } - return $logged_in ? getConfig('main_page_alt', getConfig('main_page')) : getConfig('main_page'); + return $logged_in && getConfig('main_page_alt_enable', '0') == '1' ? getConfig('main_page_alt', getConfig('main_page')) : getConfig('main_page'); } /** @@ -523,10 +523,10 @@ function csrf_request_confirm() { global $db, $session, $paths, $template, $plugins; // Common objects - global $lang; + global $lang, $output; // If the token was overridden with the correct one, the user confirmed the action using this form. Continue exec. - if ( isset($_POST['cstok']) || isset($_GET ['cstok']) ) + if ( isset($_POST['cstok']) || isset($_GET['cstok']) ) { // using the if() check makes sure that the token isn't in a cookie, since $_REQUEST includes $_COOKIE. $token_check =& $_REQUEST['cstok']; @@ -537,8 +537,8 @@ } } - $template->tpl_strings['PAGE_NAME'] = htmlspecialchars($lang->get('user_csrf_confirm_title')); - $template->header(); + $output->set_title($lang->get('user_csrf_confirm_title')); + $output->header(); // initial info echo '

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

'; @@ -564,9 +564,9 @@ // insert the right CSRF token echo ''; echo '

'; - echo ''; + echo ''; - $template->footer(); + $output->footer(); exit; } @@ -638,6 +638,35 @@ } /** + * Returns the appropriate Namespace_* object for a page. + * @param string Page ID + * @param string Namespace + * @param int Revision ID + */ + +function namespace_factory($page_id, $namespace, $revision_id = 0) +{ + if ( !class_exists("Namespace_$namespace") ) + { + if ( file_exists(ENANO_ROOT . "/includes/namespaces/" . strtolower($namespace) . ".php") ) + { + require(ENANO_ROOT . "/includes/namespaces/" . strtolower($namespace) . ".php"); + } + } + if ( class_exists("Namespace_$namespace") ) + { + $class = "Namespace_$namespace"; + $ns = new $class($page_id, $namespace, $revision_id); + return $ns; + } + else + { + $ns = new Namespace_Default($page_id, $namespace, $revision_id); + return $ns; + } +} + +/** * These are some old functions that were used with the Midget codebase. They are deprecated and should not be used any more. */ @@ -683,22 +712,10 @@ } function arrayItemBottom($arr, $keyname) { - $keylist = array_keys($arr); - $keyflop = array_flip($keylist); - $idx = $keyflop[$keyname]; - $sz = sizeof($arr); $sz--; - while( $orig != $arr[$keylist[$sz]] ) { - // echo 'Keyname: '.$keylist[$idx] . '
'; flush(); ob_flush(); // Debugger - if($idx > $sz) return $arr; - if($keylist[$idx] == '' || $keylist[$idx] < 0 || !$keylist[$idx]) { - echo 'Infinite loop caught in arrayItemBottom(
';
-      print_r($arr);
-      echo '

, '.$keyname.');

EnanoCMS: Critical error during function call, exiting to prevent excessive server load.'; - exit; - } - $arr = arrayItemDown($arr, $keylist[$idx]); - $idx++; - } + $b = $arr[$keyname]; + unset($arr[$keyname]); + $arr[$keyname] = $b; + unset($b); return $arr; } @@ -822,18 +839,11 @@ exit; } - $theme = ( defined('ENANO_CONFIG_FETCHED') ) ? getConfig('theme_default') : 'oxygen'; - $style = ( defined('ENANO_CONFIG_FETCHED') ) ? '__foo__' : 'bleu'; - - $tpl = new template_nodb(); - $tpl->load_theme($theme, $style); - $tpl->tpl_strings['SITE_NAME'] = getConfig('site_name'); - $tpl->tpl_strings['SITE_DESC'] = getConfig('site_desc'); - $tpl->tpl_strings['COPYRIGHT'] = getConfig('copyright_notice'); - $tpl->tpl_strings['PAGE_NAME'] = $t; - $tpl->header(); + $output = new Output_Safe(); + $output->set_title($t); + $output->header(); echo $p; - $tpl->footer(); + $output->footer(); exit; } @@ -918,169 +928,7 @@ function show_category_info() { - global $db, $session, $paths, $template, $plugins; // Common objects - global $lang; - - if ( $paths->namespace == 'Category' ) - { - // Show member pages and subcategories - $q = $db->sql_query('SELECT p.urlname, p.namespace, p.name, p.namespace=\'Category\' AS is_category FROM '.table_prefix.'categories AS c - LEFT JOIN '.table_prefix.'pages AS p - ON ( p.urlname = c.page_id AND p.namespace = c.namespace ) - WHERE c.category_id=\'' . $db->escape($paths->page_id) . '\' - ORDER BY is_category DESC, p.name ASC;'); - if ( !$q ) - { - $db->_die(); - } - echo '

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

'; - echo '
'; - echo ''; - echo ''; - $ticker = 0; - $counter = 0; - $switched = false; - $class = 'row1'; - while ( $row = $db->fetchrow() ) - { - if ( $row['is_category'] == 0 && !$switched ) - { - if ( $counter > 0 ) - { - // Fill-in - while ( $ticker < 3 ) - { - $ticker++; - echo ''; - } - } - else - { - echo ''; - } - echo '
' . $lang->get('onpage_cat_msg_no_subcategories') . '
' . "\n\n"; - echo '

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

'; - echo '
'; - echo ''; - echo ''; - $counter = 0; - $ticker = -1; - $switched = true; - } - $counter++; - $ticker++; - if ( $ticker == 3 ) - { - echo ''; - $ticker = 0; - $class = ( $class == 'row3' ) ? 'row1' : 'row3'; - } - echo ""; - } - if ( !$switched ) - { - if ( $counter > 0 ) - { - // Fill-in - while ( $ticker < 2 ) - { - $ticker++; - echo ''; - } - } - else - { - echo ''; - } - echo '
"; // " to workaround stupid jEdit bug - - $link = makeUrlNS($row['namespace'], sanitize_page_id($row['urlname'])); - echo 'nslist[$row['namespace']] . sanitize_page_id($row['urlname']); - if ( !isPage( $key ) ) - { - echo ' class="wikilink-nonexistent"'; - } - echo '>'; - $title = get_page_title_ns($row['urlname'], $row['namespace']); - echo htmlspecialchars($title); - echo ''; - - echo "' . $lang->get('onpage_cat_msg_no_subcategories') . '
' . "\n\n"; - echo '

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

'; - echo '
'; - echo ''; - echo ''; - $counter = 0; - $ticker = 0; - $switched = true; - } - if ( $counter > 0 ) - { - // Fill-in - while ( $ticker < 2 ) - { - $ticker++; - echo ''; - } - } - else - { - echo ''; - } - echo '
' . $lang->get('onpage_cat_msg_no_pages') . '
' . "\n\n"; - } - - if ( $paths->namespace != 'Special' && $paths->namespace != 'Admin' ) - { - echo '
'; - echo '
'; - echo '(' . $lang->get('tags_catbox_link') . ')'; - echo '
'; - echo '
' . $lang->get('catedit_catbox_lbl_categories') . ' '; - - $where = '( c.page_id=\'' . $db->escape($paths->page_id) . '\' AND c.namespace=\'' . $db->escape($paths->namespace) . '\' )'; - $prefix = table_prefix; - $sql = <<sql_query($sql); - if ( !$q ) - $db->_die(); - - if ( $row = $db->fetchrow() ) - { - $list = array(); - do - { - $cid = sanitize_page_id($row['category_id']); - $title = get_page_title_ns($cid, 'Category'); - $link = makeUrlNS('Category', $cid); - $list[] = '' . htmlspecialchars($title) . ''; - } - while ( $row = $db->fetchrow() ); - echo implode(', ', $list); - } - else - { - echo $lang->get('catedit_catbox_lbl_uncategorized'); - } - - $can_edit = ( $session->get_permissions('edit_cat') && ( !$paths->page_protected || $session->get_permissions('even_when_protected') ) ); - if ( $can_edit ) - { - $edit_link = '' . $lang->get('catedit_catbox_link_edit') . ''; - echo ' [ ' . $edit_link . ' ]'; - } - - echo '
'; - - } - + throw new Exception('show_category_info() is deprecated. Use Namespace_*::display_categories().'); } /** @@ -1089,146 +937,7 @@ function show_file_info($page = false) { - global $db, $session, $paths, $template, $plugins; // Common objects - global $lang; - - $local_page_id = $paths->page_id; - $local_namespace = $paths->namespace; - - if ( is_object($page) ) - { - $local_page = $page->page_id; - $local_namespace = $page->namespace; - } - - // Prevent unnecessary work - if ( $local_namespace != 'File' ) - return null; - - $selfn = $local_page_id; - if ( substr($paths->cpage['name'], 0, strlen($paths->nslist['File'])) == $paths->nslist['File']) - { - $selfn = substr($local_page_id, strlen($paths->nslist['File']), strlen($local_page_id)); - } - $selfn = $db->escape($selfn); - $q = $db->sql_query('SELECT f.mimetype,f.time_id,f.size,l.log_id FROM ' . table_prefix . "files AS f\n" - . " LEFT JOIN " . table_prefix . "logs AS l\n" - . " ON ( l.time_id = f.time_id AND ( l.action = 'reupload' OR l.action IS NULL ) )\n" - . " WHERE f.page_id = '$selfn'\n" - . " ORDER BY f.time_id DESC;"); - if ( !$q ) - { - $db->_die('The file type could not be fetched.'); - } - - if ( $db->numrows() < 1 ) - { - echo '
-

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

-

' . $lang->get('onpage_filebox_msg_not_found', array('upload_link' => makeUrlNS('Special', 'UploadFile/'.$local_page_id))) . '

-
-
'; - return; - } - $r = $db->fetchrow(); - $mimetype = $r['mimetype']; - $datestring = enano_date('F d, Y h:i a', (int)$r['time_id']); - echo '
-

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

-

' . $lang->get('onpage_filebox_lbl_type') . ' '.$r['mimetype'].'
'; - - $size = $r['size'] . ' ' . $lang->get('etc_unit_bytes'); - if ( $r['size'] >= 1048576 ) - { - $size .= ' (' . ( round($r['size'] / 1048576, 1) ) . ' ' . $lang->get('etc_unit_megabytes_short') . ')'; - } - else if ( $r['size'] >= 1024 ) - { - $size .= ' (' . ( round($r['size'] / 1024, 1) ) . ' ' . $lang->get('etc_unit_kilobytes_short') . ')'; - } - - echo $lang->get('onpage_filebox_lbl_size', array('size' => $size)); - - echo '
' . $lang->get('onpage_filebox_lbl_uploaded') . ' ' . $datestring . '

'; - if ( substr($mimetype, 0, 6) != 'image/' && ( substr($mimetype, 0, 5) != 'text/' || $mimetype == 'text/html' || $mimetype == 'text/javascript' ) ) - { - echo '
- ' . $lang->get('onpage_filebox_msg_virus_warning') . ' -
'; - } - if ( substr($mimetype, 0, 6) == 'image/' ) - { - echo '

- - '.$paths->page.' - -

'; - } - echo '

- - ' . $lang->get('onpage_filebox_btn_download') . ' - '; - if(!$paths->page_protected && ( $paths->wiki_mode || $session->get_permissions('upload_new_version') )) - { - echo ' | - ' . $lang->get('onpage_filebox_btn_upload_new') . ' - '; - } - echo '

'; - if ( $db->numrows() > 1 ) - { - // requery, sql_result_seek() doesn't work on postgres - $db->free_result(); - $q = $db->sql_query('SELECT f.mimetype,f.time_id,f.size,l.log_id FROM ' . table_prefix . "files AS f\n" - . " LEFT JOIN " . table_prefix . "logs AS l\n" - . " ON ( l.time_id = f.time_id AND ( l.action = 'reupload' OR l.action IS NULL ) )\n" - . " WHERE f.page_id = '$selfn'\n" - . " ORDER BY f.time_id DESC;"); - if ( !$q ) - $db->_die(); - - echo '

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

'; - $last_rollback_id = false; - while ( $r = $db->fetchrow() ) - { - echo '(' . $lang->get('onpage_filebox_btn_this_version') . ') '; - if ( $session->get_permissions('history_rollback') && $last_rollback_id ) - echo ' (' . $lang->get('onpage_filebox_btn_revert') . ') '; - else if ( $session->get_permissions('history_rollback') && !$last_rollback_id ) - echo ' (' . $lang->get('onpage_filebox_btn_current') . ') '; - $last_rollback_id = $r['log_id']; - $mimetype = $r['mimetype']; - $datestring = enano_date('F d, Y h:i a', (int)$r['time_id']); - - echo $datestring.': '.$r['mimetype'].', '; - - $fs = $r['size']; - $fs = (int)$fs; - - if($fs >= 1048576) - { - $fs = round($fs / 1048576, 1); - $size = $fs . ' ' . $lang->get('etc_unit_megabytes_short'); - } - else - if ( $fs >= 1024 ) - { - $fs = round($fs / 1024, 1); - $size = $fs . ' ' . $lang->get('etc_unit_kilobytes_short'); - } - else - { - $size = $fs . ' ' . $lang->get('etc_unit_bytes'); - } - - echo $size; - - echo '
'; - } - echo '

'; - } - $db->free_result(); - echo '

'; + throw new Exception('show_file_info() is deprecated. Use Namespace_File::show_info().'); } /** @@ -1262,14 +971,17 @@ function display_page_footers() { global $db, $session, $paths, $template, $plugins; // Common objects - if(isset($_GET['nofooters'])) return; + + if ( isset($_GET['nofooters']) ) + { + return; + } + $code = $plugins->setHook('send_page_footers'); foreach ( $code as $cmd ) { eval($cmd); } - show_file_info(); - show_category_info(); } /** @@ -2915,6 +2627,8 @@ $char = strtolower($char); $char = intval(hexdec($char)); $char = chr($char); + if ( preg_match('/^[\w\.\/:;\(\)@\[\]_-]$/', $char) ) + continue; $page_id = str_replace($matches[0][$id], $char, $page_id); } diff -r 4629ad98ee88 -r 9cdfe82c56cd includes/namespaces/admin.php --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/includes/namespaces/admin.php Sat Jan 03 18:11:18 2009 -0500 @@ -0,0 +1,18 @@ +page_id; + if ( $output->naked ) + { + $sep = ( strstr($uri, '?') ) ? '&' : '?'; + $uri .= "{$sep}noheaders"; + } + if ( $session->sid_super ) + { + $sep = ( strstr($uri, '?') ) ? '&' : '?'; + $uri .= "{$sep}auth={$session->sid_super}"; + } + redirect( $uri, '', '', 0 ); + } +} + diff -r 4629ad98ee88 -r 9cdfe82c56cd includes/namespaces/default.php --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/includes/namespaces/default.php Sat Jan 03 18:11:18 2009 -0500 @@ -0,0 +1,735 @@ + + * @license GNU General Public License + */ + +class Namespace_Default +{ + /** + * Page ID + * @var string + */ + + public $page_id; + + /** + * Namespace + * @var string + */ + + public $namespace; + + /** + * Local copy of the page text + */ + + public $text_cache; + + /** + * Revision ID to send. If 0, the latest revision. + * @var int + */ + + public $revision_id = 0; + + /** + * Tracks whether the page exists + * @var bool + */ + + public $exists = false; + + /** + * Page title + * @var string + */ + + public $title = ''; + + /** + * Constructor. + */ + + public function __construct($page_id, $namespace, $revision_id = 0) + { + global $db, $session, $paths, $template, $plugins; // Common objects + + $this->page_id = sanitize_page_id($page_id); + $this->namespace = $namespace; + $this->revision_id = intval($revision_id); + + // only do this if calling from the (very heavily feature filled) abstract + // this will still be called if you're using your own handler but not replacing the constructor + if ( __CLASS__ == 'Namespace_Default' ) + { + $this->exists = false; + // NOTE! These should already be WELL sanitized before we reach this stage. + $q = $db->sql_query('SELECT name FROM ' . table_prefix . "pages WHERE urlname = '$this->page_id' AND namespace = '$this->namespace';"); + if ( !$q ) + $db->_die(); + + if ( $db->numrows() < 1 ) + { + // we still have a chance... some older databases don't do dots in the page title right + if ( strstr(dirtify_page_id($this->page_id), '.') ) + { + $page_id = str_replace('.', '.2e', $page_id); + + $q = $db->sql_query('SELECT name FROM ' . table_prefix . "pages WHERE urlname = '$page_id' AND namespace = '$this->namespace';"); + if ( !$q ) + $db->_die(); + + if ( $db->numrows() < 1 ) + { + $this->title = $paths->nslist[$namespace] . dirtify_page_id($page_id); + } + else + { + list($this->title) = $db->fetchrow_num(); + $this->exists = true; + $this->page_id = $page_id; + } + } + else + { + $this->title = $paths->nslist[$namespace] . dirtify_page_id($page_id); + } + } + else + { + list($this->title) = $db->fetchrow_num(); + $this->exists = true; + } + $db->free_result(); + } + } + + /** + * Pulls the page's actual text from the database. + */ + + function fetch_text() + { + global $db, $session, $paths, $template, $plugins; // Common objects + + if ( !empty($this->text_cache) ) + { + return $this->text_cache; + } + + if ( $this->revision_id > 0 && is_int($this->revision_id) ) + { + + $q = $db->sql_query('SELECT page_text, char_tag, time_id FROM '.table_prefix.'logs WHERE log_type=\'page\' AND action=\'edit\' AND page_id=\'' . $this->page_id . '\' AND namespace=\'' . $this->namespace . '\' AND log_id=' . $this->revision_id . ';'); + if ( !$q ) + { + $this->send_error('Error during SQL query.', true); + } + if ( $db->numrows() < 1 ) + { + // Compatibility fix for old pages with dots in the page ID + if ( strstr($this->page_id, '.2e') ) + { + $db->free_result(); + $page_id = str_replace('.2e', '.', $this->page_id); + $q = $db->sql_query('SELECT page_text, char_tag, time_id FROM '.table_prefix.'logs WHERE log_type=\'page\' AND action=\'edit\' AND page_id=\'' . $page_id . '\' AND namespace=\'' . $this->namespace . '\' AND log_id=' . $this->revision_id . ';'); + if ( !$q ) + { + $this->send_error('Error during SQL query.', true); + } + if ( $db->numrows() < 1 ) + { + $this->page_exists = false; + return 'err_no_text_rows'; + } + } + else + { + $this->page_exists = false; + return 'err_no_text_rows'; + } + } + else + { + $row = $db->fetchrow(); + } + + $db->free_result(); + + } + 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" + . " WHERE t.page_id='$this->page_id' AND t.namespace='$this->namespace'\n" + . " ORDER BY l.time_id DESC LIMIT 1;"); + if ( !$q ) + { + $this->send_error('Error during SQL query.', true); + } + if ( $db->numrows() < 1 ) + { + // Compatibility fix for old pages with dots in the page ID + if ( strstr($this->page_id, '.2e') ) + { + $db->free_result(); + $page_id = str_replace('.2e', '.', $this->page_id); + $q = $db->sql_query('SELECT page_text, char_tag FROM '.table_prefix.'page_text WHERE page_id=\'' . $page_id . '\' AND namespace=\'' . $this->namespace . '\';'); + if ( !$q ) + { + $this->send_error('Error during SQL query.', true); + } + if ( $db->numrows() < 1 ) + { + $this->page_exists = false; + return 'err_no_text_rows'; + } + } + else + { + $this->page_exists = false; + return 'err_no_text_rows'; + } + } + + $row = $db->fetchrow(); + $db->free_result(); + + } + + if ( !empty($row['char_tag']) ) + { + // This page text entry uses the old text-escaping format + $from = array( + "{APOS:{$row['char_tag']}}", + "{QUOT:{$row['char_tag']}}", + "{SLASH:{$row['char_tag']}}" + ); + $to = array("'", '"', '\\'); + $row['page_text'] = str_replace($from, $to, $row['page_text']); + } + + $this->text_cache = $row['page_text']; + + if ( isset($row['time_id']) ) + { + $this->revision_time = intval($row['time_id']); + } + + return $row['page_text']; + } + + /** + * Send the page. + */ + + public function send() + { + global $db, $session, $paths, $template, $plugins; // Common objects + global $output; + + $output->add_before_footer($this->display_categories()); + + if ( $this->exists ) + $this->send_from_db(); + else + { + // This is the DEPRECATED way to extend namespaces. It's left in only for compatibility with older plugins. + ob_start(); + $code = $plugins->setHook('page_not_found'); + foreach ( $code as $cmd ) + { + eval($cmd); + } + $c = ob_get_contents(); + if ( !empty($c) ) + { + ob_end_clean(); + echo $c; + } + else + { + $output->header(); + $this->error_404(); + $output->footer(); + } + } + } + + /** + * The "real" send-the-page function. The reason for this is so other namespaces can re-use the code + * to fetch the page from the DB while being able to install their own wrappers. + */ + + public function send_from_db($incl_inner_headers = true, $send_headers = true) + { + global $db, $session, $paths, $template, $plugins; // Common objects + global $lang; + global $output; + + $text = $this->fetch_text(); + + $text = preg_replace('/([\s]*)__NOBREADCRUMBS__([\s]*)/', '', $text); + $text = preg_replace('/([\s]*)__NOTOC__([\s]*)/', '', $text); + + $redir_enabled = false; + if ( preg_match('/^#redirect \[\[([^\]]+?)\]\]/i', $text, $match ) ) + { + $redir_enabled = true; + + $oldtarget = RenderMan::strToPageID($match[1]); + $oldtarget[0] = sanitize_page_id($oldtarget[0]); + + $url = makeUrlNS($oldtarget[1], $oldtarget[0], false, true); + $page_id_key = $paths->nslist[ $oldtarget[1] ] . $oldtarget[0]; + $page_data = $paths->pages[$page_id_key]; + $title = ( isset($page_data['name']) ) ? $page_data['name'] : $paths->nslist[$oldtarget[1]] . htmlspecialchars( str_replace('_', ' ', dirtify_page_id( $oldtarget[0] ) ) ); + if ( !isset($page_data['name']) ) + { + $cls = 'class="wikilink-nonexistent"'; + } + else + { + $cls = ''; + } + $a = '' . $title . ''; + $redir_html = '
+ + + + + +
+ Cute wet-floor icon + + ' . $lang->get('page_msg_this_is_a_redirector', array( 'redirect_target' => $a )) . ' +
+
+
+
'; + $text = str_replace($match[0], '', $text); + $text = trim($text); + } + + if ( $send_headers ) + { + $output->set_title($this->title); + $output->header(); + } + $this->do_breadcrumbs(); + + if ( $incl_inner_headers ) + { + display_page_headers(); + } + + if ( $this->revision_id ) + { + echo '
+ ' . $lang->get('page_msg_archived_title') . '
+ ' . $lang->get('page_msg_archived_body', array( + 'archive_date' => enano_date('F d, Y', $this->revision_time), + 'archive_time' => enano_date('h:i a', $this->revision_time), + 'current_link' => makeUrlNS($this->namespace, $this->page_id), + 'restore_link' => makeUrlNS($this->namespace, $this->page_id, 'do=edit&revid='.$this->revision_id), + 'restore_onclick' => 'ajaxEditor(\''.$this->revision_id.'\'); return false;', + )) . ' +
'; + } + + if ( $redir_enabled ) + { + echo $redir_html; + } + + $code = $plugins->setHook('pageprocess_render_head'); + foreach ( $code as $cmd ) + { + eval($cmd); + } + + if ( $incl_inner_headers ) + { + $text = '?>' . RenderMan::render($text); + } + else + { + $text = '?>' . $text; + $text = preg_replace('/(.*?)<\/nowiki>/s', '\\1', $text); + } + + eval ( $text ); + + $code = $plugins->setHook('pageprocess_render_tail'); + foreach ( $code as $cmd ) + { + eval($cmd); + } + + if ( $incl_inner_headers ) + { + display_page_footers(); + } + + if ( $send_headers ) + $output->footer(); + } + + /** + * Echoes out breadcrumb data, if appropriate. + * @access private + */ + + function do_breadcrumbs() + { + global $db, $session, $paths, $template, $plugins; // Common objects + global $lang; + + if ( strpos($this->text_cache, '__NOBREADCRUMBS__') !== false ) + return false; + + $mode = getConfig('breadcrumb_mode'); + + if ( $mode == 'never' ) + // Breadcrumbs are disabled + return true; + + // Minimum depth for breadcrumb display + $threshold = ( $mode == 'always' ) ? 0 : 1; + + $breadcrumb_data = explode('/', $this->page_id); + if ( count($breadcrumb_data) > $threshold ) + { + // If we're not on a subpage of the main page, add "Home" to the list + $show_home = false; + if ( $mode == 'always' ) + { + $show_home = true; + } + echo ' + + + '; + } + } + + public function error_404($userpage = false) + { + global $db, $session, $paths, $template, $plugins; // Common objects + global $lang, $output; + + @header('HTTP/1.1 404 Not Found'); + + $msg = ( $pp = $paths->sysmsg('Page_not_found') ) ? $pp : '{STANDARD404}'; + + $standard_404 = ''; + + if ( $userpage ) + { + $standard_404 .= '

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

+

' . $lang->get('page_msg_404_body_userpage'); + } + else + { + $standard_404 .= '

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

+

' . $lang->get('page_msg_404_body'); + } + if ( $session->get_permissions('create_page') ) + { + $standard_404 .= ' ' . $lang->get('page_msg_404_create', array( + 'create_flags' => 'href="'.makeUrlNS($this->namespace, $this->page_id, 'do=edit', true).'" onclick="ajaxEditor(); return false;"', + 'mainpage_link' => makeUrl(get_main_page(), false, true) + )); + } + else + { + $standard_404 .= ' ' . $lang->get('page_msg_404_gohome', array( + 'mainpage_link' => makeUrl(get_main_page(), false, true) + )); + } + $standard_404 .= '

'; + if ( $session->get_permissions('history_rollback') ) + { + $e = $db->sql_query('SELECT * FROM ' . table_prefix . 'logs WHERE action=\'delete\' AND page_id=\'' . $this->page_id . '\' AND namespace=\'' . $this->namespace . '\' ORDER BY time_id DESC;'); + if ( !$e ) + { + $db->_die('The deletion log could not be selected.'); + } + if ( $db->numrows() > 0 ) + { + $r = $db->fetchrow(); + $standard_404 .= '

' . $lang->get('page_msg_404_was_deleted', array( + 'delete_time' => enano_date('d M Y h:i a', $r['time_id']), + 'delete_reason' => htmlspecialchars($r['edit_summary']), + 'rollback_flags' => 'href="'.makeUrl($paths->page, 'do=rollback&id='.$r['log_id']).'" onclick="ajaxRollback(\''.$r['log_id'].'\'); return false;"' + )) + . '

'; + if ( $session->user_level >= USER_LEVEL_ADMIN ) + { + $standard_404 .= '

' . $lang->get('page_msg_404_admin_opts', array( + 'detag_link' => makeUrl($paths->page, 'do=detag', true) + )) + . '

'; + } + } + $db->free_result(); + } + $standard_404 .= '

+ ' . $lang->get('page_msg_404_http_response') . ' +

'; + + $parser = $template->makeParserText($msg); + $parser->assign_vars(array( + 'STANDARD404' => $standard_404 + )); + + $msg = RenderMan::render($parser->run()); + eval( '?>' . $msg ); + } + + /** + * Display the categories a page is in. If the current page is a category, its contents will also be printed. + */ + + function display_categories() + { + global $db, $session, $paths, $template, $plugins; // Common objects + global $lang; + + $html = ''; + + if ( $this->namespace == 'Category' ) + { + // Show member pages and subcategories + $q = $db->sql_query('SELECT p.urlname, p.namespace, p.name, p.namespace=\'Category\' AS is_category FROM '.table_prefix.'categories AS c + LEFT JOIN '.table_prefix.'pages AS p + ON ( p.urlname = c.page_id AND p.namespace = c.namespace ) + WHERE c.category_id=\'' . $db->escape($this->page_id) . '\' + ORDER BY is_category DESC, p.name ASC;'); + if ( !$q ) + { + $db->_die(); + } + $html .= '

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

'; + $html .= '
'; + $html .= ''; + $html .= ''; + $ticker = 0; + $counter = 0; + $switched = false; + $class = 'row1'; + while ( $row = $db->fetchrow() ) + { + if ( $row['is_category'] == 0 && !$switched ) + { + if ( $counter > 0 ) + { + // Fill-in + while ( $ticker < 3 ) + { + $ticker++; + $html .= ''; + } + } + else + { + $html .= ''; + } + $html .= '
' . $lang->get('onpage_cat_msg_no_subcategories') . '
' . "\n\n"; + $html .= '

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

'; + $html .= '
'; + $html .= ''; + $html .= ''; + $counter = 0; + $ticker = -1; + $switched = true; + } + $counter++; + $ticker++; + if ( $ticker == 3 ) + { + $html .= ''; + $ticker = 0; + $class = ( $class == 'row3' ) ? 'row1' : 'row3'; + } + $html .= ""; + } + if ( !$switched ) + { + if ( $counter > 0 ) + { + // Fill-in + while ( $ticker < 2 ) + { + $ticker++; + $html .= ''; + } + } + else + { + $html .= ''; + } + $html .= '
"; // " to workaround stupid jEdit bug + + $link = makeUrlNS($row['namespace'], sanitize_page_id($row['urlname'])); + $html .= 'nslist[$row['namespace']] . sanitize_page_id($row['urlname']); + if ( !isPage( $key ) ) + { + $html .= ' class="wikilink-nonexistent"'; + } + $html .= '>'; + $title = get_page_title_ns($row['urlname'], $row['namespace']); + $html .= htmlspecialchars($title); + $html .= ''; + + $html .= "' . $lang->get('onpage_cat_msg_no_subcategories') . '
' . "\n\n"; + $html .= '

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

'; + $html .= '
'; + $html .= ''; + $html .= ''; + $counter = 0; + $ticker = 0; + $switched = true; + } + if ( $counter > 0 ) + { + // Fill-in + while ( $ticker < 2 ) + { + $ticker++; + $html .= ''; + } + } + else + { + $html .= ''; + } + $html .= '
' . $lang->get('onpage_cat_msg_no_pages') . '
' . "\n\n"; + } + + if ( $this->namespace != 'Special' && $this->namespace != 'Admin' ) + { + $html .= '
'; + $html .= '
'; + $html .= '(' . $lang->get('tags_catbox_link') . ')'; + $html .= '
'; + $html .= '
' . $lang->get('catedit_catbox_lbl_categories') . ' '; + + $where = '( c.page_id=\'' . $db->escape($this->page_id) . '\' AND c.namespace=\'' . $db->escape($this->namespace) . '\' )'; + $prefix = table_prefix; + $sql = <<sql_query($sql); + if ( !$q ) + $db->_die(); + + if ( $row = $db->fetchrow() ) + { + $list = array(); + do + { + $cid = sanitize_page_id($row['category_id']); + $title = get_page_title_ns($cid, 'Category'); + $link = makeUrlNS('Category', $cid); + $list[] = '' . htmlspecialchars($title) . ''; + } + while ( $row = $db->fetchrow() ); + $html .= implode(', ', $list); + } + else + { + $html .= $lang->get('catedit_catbox_lbl_uncategorized'); + } + + $can_edit = ( $session->get_permissions('edit_cat') && ( !$paths->page_protected || $session->get_permissions('even_when_protected') ) ); + if ( $can_edit ) + { + $edit_link = '' . $lang->get('catedit_catbox_link_edit') . ''; + $html .= ' [ ' . $edit_link . ' ]'; + } + + $html .= '
'; + } + return $html; + } + /** + * Just tell us if the current page exists or not. + * @return bool + */ + + function exists() + { + return $this->exists; + } +} + +/** + * The namespaces that use the default handler. + */ + +class Namespace_Article extends Namespace_Default +{ +} + +class Namespace_Project extends Namespace_Default +{ +} + +class Namespace_Help extends Namespace_Default +{ +} + diff -r 4629ad98ee88 -r 9cdfe82c56cd includes/namespaces/file.php --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/includes/namespaces/file.php Sat Jan 03 18:11:18 2009 -0500 @@ -0,0 +1,176 @@ +add_before_footer($this->show_info()); + $output->add_before_footer($this->display_categories()); + + if ( $this->exists ) + { + $this->send_from_db(); + } + else + { + $output->header(); + $this->error_404(); + $output->footer(); + } + } + + function show_info() + { + global $db, $session, $paths, $template, $plugins; // Common objects + global $lang; + + $local_page_id = $this->page_id; + $local_namespace = $this->namespace; + $html = ''; + + // Prevent unnecessary work + if ( $local_namespace != 'File' ) + return null; + + $selfn = $local_page_id; + if ( substr($paths->cpage['name'], 0, strlen($paths->nslist['File'])) == $paths->nslist['File']) + { + $selfn = substr($local_page_id, strlen($paths->nslist['File']), strlen($local_page_id)); + } + $selfn = $db->escape($selfn); + $q = $db->sql_query('SELECT f.mimetype,f.time_id,f.size,l.log_id FROM ' . table_prefix . "files AS f\n" + . " LEFT JOIN " . table_prefix . "logs AS l\n" + . " ON ( l.time_id = f.time_id AND ( l.action = 'reupload' OR l.action IS NULL ) )\n" + . " WHERE f.page_id = '$selfn'\n" + . " ORDER BY f.time_id DESC;"); + if ( !$q ) + { + $db->_die('The file type could not be fetched.'); + } + + if ( $db->numrows() < 1 ) + { + $html .= '
+

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

+

' . $lang->get('onpage_filebox_msg_not_found', array('upload_link' => makeUrlNS('Special', 'UploadFile/'.$local_page_id))) . '

+
+
'; + return $html; + } + $r = $db->fetchrow(); + $mimetype = $r['mimetype']; + $datestring = enano_date('F d, Y h:i a', (int)$r['time_id']); + $html .= '
+

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

+

' . $lang->get('onpage_filebox_lbl_type') . ' '.$r['mimetype'].'
'; + + $size = $r['size'] . ' ' . $lang->get('etc_unit_bytes'); + if ( $r['size'] >= 1048576 ) + { + $size .= ' (' . ( round($r['size'] / 1048576, 1) ) . ' ' . $lang->get('etc_unit_megabytes_short') . ')'; + } + else if ( $r['size'] >= 1024 ) + { + $size .= ' (' . ( round($r['size'] / 1024, 1) ) . ' ' . $lang->get('etc_unit_kilobytes_short') . ')'; + } + + $html .= $lang->get('onpage_filebox_lbl_size', array('size' => $size)); + + $html .= '
' . $lang->get('onpage_filebox_lbl_uploaded') . ' ' . $datestring . '

'; + if ( substr($mimetype, 0, 6) != 'image/' && ( substr($mimetype, 0, 5) != 'text/' || $mimetype == 'text/html' || $mimetype == 'text/javascript' ) ) + { + $html .= '
+ ' . $lang->get('onpage_filebox_msg_virus_warning') . ' +
'; + } + if ( substr($mimetype, 0, 6) == 'image/' ) + { + $html .= '

+ + '.$paths->page.' + +

'; + } + $html .= '

+ + ' . $lang->get('onpage_filebox_btn_download') . ' + '; + if(!$paths->page_protected && ( $paths->wiki_mode || $session->get_permissions('upload_new_version') )) + { + $html .= ' | + ' . $lang->get('onpage_filebox_btn_upload_new') . ' + '; + } + $html .= '

'; + if ( $db->numrows() > 1 ) + { + // requery, sql_result_seek() doesn't work on postgres + $db->free_result(); + $q = $db->sql_query('SELECT f.mimetype,f.time_id,f.size,l.log_id FROM ' . table_prefix . "files AS f\n" + . " LEFT JOIN " . table_prefix . "logs AS l\n" + . " ON ( l.time_id = f.time_id AND ( l.action = 'reupload' OR l.action IS NULL ) )\n" + . " WHERE f.page_id = '$selfn'\n" + . " ORDER BY f.time_id DESC;"); + if ( !$q ) + $db->_die(); + + $html .= '

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

'; + $last_rollback_id = false; + while ( $r = $db->fetchrow() ) + { + $html .= '(' . $lang->get('onpage_filebox_btn_this_version') . ') '; + if ( $session->get_permissions('history_rollback') && $last_rollback_id ) + $html .= ' (' . $lang->get('onpage_filebox_btn_revert') . ') '; + else if ( $session->get_permissions('history_rollback') && !$last_rollback_id ) + $html .= ' (' . $lang->get('onpage_filebox_btn_current') . ') '; + $last_rollback_id = $r['log_id']; + $mimetype = $r['mimetype']; + $datestring = enano_date('F d, Y h:i a', (int)$r['time_id']); + + $html .= $datestring.': '.$r['mimetype'].', '; + + $fs = $r['size']; + $fs = (int)$fs; + + if($fs >= 1048576) + { + $fs = round($fs / 1048576, 1); + $size = $fs . ' ' . $lang->get('etc_unit_megabytes_short'); + } + else + if ( $fs >= 1024 ) + { + $fs = round($fs / 1024, 1); + $size = $fs . ' ' . $lang->get('etc_unit_kilobytes_short'); + } + else + { + $size = $fs . ' ' . $lang->get('etc_unit_bytes'); + } + + $html .= $size; + + $html .= '
'; + } + $html .= '

'; + } + $db->free_result(); + $html .= '

'; + return $html; + } +} + diff -r 4629ad98ee88 -r 9cdfe82c56cd includes/namespaces/special.php --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/includes/namespaces/special.php Sat Jan 03 18:11:18 2009 -0500 @@ -0,0 +1,60 @@ +page_id = sanitize_page_id($page_id); + $this->namespace = $namespace; + $this->revision_id = intval($revision_id); + + $this->exists = function_exists("page_{$this->namespace}_{$this->page_id}"); + } + + function send() + { + global $output; + + if ( $this->exists ) + { + @call_user_func("page_{$this->namespace}_{$this->page_id}"); + } + else + { + $output->header(); + $this->error_404(); + $output->footer(); + } + } + + function error_404() + { + global $lang, $output; + $func_name = "page_{$this->namespace}_{$this->page_id}"; + + if ( $this->namespace == 'Admin' ) + die_semicritical($lang->get('page_msg_admin_404_title'), $lang->get('page_msg_admin_404_body', array('func_name' => $func_name)), true); + + $title = $lang->get('page_err_custompage_function_missing_title'); + $message = $lang->get('page_err_custompage_function_missing_body', array( 'function_name' => $fname )); + + $output->set_title($title); + $output->header(); + echo "

$message

"; + $output->footer(); + } +} diff -r 4629ad98ee88 -r 9cdfe82c56cd includes/namespaces/template.php --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/includes/namespaces/template.php Sat Jan 03 18:11:18 2009 -0500 @@ -0,0 +1,41 @@ +add_before_footer($this->display_categories()); + $output->header(); + + if ( $this->exists ) + { + $text = $this->fetch_text(); + $text = preg_replace('/(.*?)<\/noinclude>/is', '\\1', $text); + $text = preg_replace('/(.*?)<\/nodisplay>/is', '', $text); + + $text = RenderMan::render( $text ); + + eval( '?>' . $text ); + } + else + { + $this->error_404(); + } + + $output->footer(); + } +} diff -r 4629ad98ee88 -r 9cdfe82c56cd includes/namespaces/user.php --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/includes/namespaces/user.php Sat Jan 03 18:11:18 2009 -0500 @@ -0,0 +1,472 @@ +YOUR TAB TEXT + * + * Then hook into userpage_tabs_body and echo out: + * + *
YOUR TAB CONTENT
+ * + * The userpage javascript runtime will take care of everything else, + * meaning transitions, click events, etc. Currently it's not possible + * to add custom click events to tabs, but any DOM-related JS that needs + * to run in your tab can be run onload and the effects will be seen when + * your tab is clicked. YOURTABID should be lowercase alphanumeric and + * have a short prefix so as to assure that it remains specific to your + * plugin. + * + * To hook into the "profile" tab, use userpage_sidebar_{left,right}. Just + * echo out table cells as normal. The table on the left (the wide one) has + * four columns, and the one on the right has one column. + * + * See plugins.php for a guide on creating and attaching to hooks. + */ + + $page_urlname = dirtify_page_id($this->page_id); + if ( $this->page_id == $paths->page_id && $this->namespace == $paths->namespace ) + { + $page_name = ( isset($paths->cpage['name']) ) ? $paths->cpage['name'] : $this->page_id; + } + else + { + $page_name = ( isset($paths->pages[$this->page_id]) ) ? $paths->pages[$this->page_id]['name'] : $this->page_id; + } + + $target_username = strtr($page_urlname, + Array( + '_' => ' ', + '<' => '<', + '>' => '>' + )); + + $target_username = preg_replace('/^' . str_replace('/', '\\/', preg_quote($paths->nslist['User'])) . '/', '', $target_username); + list($target_username) = explode('/', $target_username); + + if ( ( $page_name == str_replace('_', ' ', $this->page_id) || $page_name == $paths->nslist['User'] . str_replace('_', ' ', $this->page_id) ) || !$this->page_exists ) + { + $page_name = $lang->get('userpage_page_title', array('username' => $target_username)); + } + else + { + // User has a custom title for their userpage + $page_name = $paths->pages[ $paths->nslist[$this->namespace] . $this->page_id ]['name']; + } + + $template->tpl_strings['PAGE_NAME'] = htmlspecialchars($page_name); + + $q = $db->sql_query('SELECT u.username, u.user_id AS authoritative_uid, u.real_name, u.email, u.reg_time, u.user_has_avatar, u.avatar_type, x.*, COUNT(c.comment_id) AS n_comments + FROM '.table_prefix.'users u + LEFT JOIN '.table_prefix.'users_extra AS x + ON ( u.user_id = x.user_id OR x.user_id IS NULL ) + LEFT JOIN '.table_prefix.'comments AS c + ON ( ( c.user_id=u.user_id AND c.name=u.username AND c.approved=1 ) OR ( c.comment_id IS NULL AND c.approved IS NULL ) ) + WHERE u.username=\'' . $db->escape($target_username) . '\' + GROUP BY u.username, u.user_id, u.real_name, u.email, u.reg_time, u.user_has_avatar, u.avatar_type, x.user_id, x.user_aim, x.user_yahoo, x.user_msn, x.user_xmpp, x.user_homepage, x.user_location, x.user_job, x.user_hobbies, x.email_public;'); + if ( !$q ) + $db->_die(); + + $user_exists = true; + + if ( $db->numrows() < 1 ) + { + $user_exists = false; + } + else + { + $userdata = $db->fetchrow(); + if ( $userdata['authoritative_uid'] == 1 ) + { + // Hide data for anonymous user + $user_exists = false; + unset($userdata); + } + } + + // get the user's rank + if ( $user_exists ) + { + $rank_data = $session->get_user_rank(intval($userdata['authoritative_uid'])); + } + else + { + // get the rank data for the anonymous user (placeholder basically) + $rank_data = $session->get_user_rank(1); + } + + // add the userpage script to the header + $template->add_header(''); + + $output->header(); + + // if ( $send_headers ) + // { + // display_page_headers(); + // } + + // + // BASIC INFORMATION + // Presentation of username/rank/avatar/basic info + // + + if ( $user_exists ) + { + + ?> +
+ + +
+ + + '; + + echo ' '; + + echo '
+ '; + + // heading + echo ' + + ' . ( + $session->user_level >= USER_LEVEL_ADMIN ? + '' + : '' + ) . ' + '; + + // avi/rank/username + echo ' + + '; + + // join date & total comments + echo ''; + echo ' + '; + echo ' + '; + echo ''; + + // real name + if ( !empty($userdata['real_name']) ) + { + echo ' + + + '; + } + + // latest comments + + echo ''; + $q = $db->sql_query('SELECT page_id, namespace, subject, time FROM '.table_prefix.'comments WHERE name=\'' . $db->escape($target_username) . '\' AND user_id=' . $userdata['authoritative_uid'] . ' AND approved=1 ORDER BY time DESC LIMIT 7;'); + if ( !$q ) + $db->_die(); + + $comments = Array(); + $no_comments = false; + + if ( $row = $db->fetchrow() ) + { + do + { + $row['time'] = enano_date('F d, Y', $row['time']); + $comments[] = $row; + } + while ( $row = $db->fetchrow() ); + } + else + { + $no_comments = true; + } + + echo ''; + + $code = $plugins->setHook('userpage_sidebar_left'); + foreach ( $code as $cmd ) + { + eval($cmd); + } + + echo '
+ ' . $lang->get('userpage_heading_basics', array('username' => htmlspecialchars($target_username))) . ' + » ' . $lang->get('userpage_btn_administer_user') . '
+ ' . ( + $userdata['user_has_avatar'] == 1 ? + '
+ ' . $lang->get('usercp_avatar_image_alt', array('username' => $userdata['username'])) . ' +
' + : '' + ) . ' + ' . htmlspecialchars($userdata['username']) . ' + ' . ( !empty($rank_data['user_title']) ? '
' . htmlspecialchars($rank_data['user_title']) : '' ) . ' + ' . ( !empty($rank_data['rank_title']) ? '
' . htmlspecialchars($lang->get($rank_data['rank_title'])) : '' ) . ' +
+ ' . $lang->get('userpage_lbl_joined') . ' + + ' . enano_date('F d, Y h:i a', $userdata['reg_time']) . ' + + ' . $lang->get('userpage_lbl_num_comments') . ' + + ' . $userdata['n_comments'] . ' +
+ ' . $lang->get('userpage_lbl_real_name') . ' + + ' . htmlspecialchars($userdata['real_name']) . ' +
' . $lang->get('userpage_heading_comments', array('username' => htmlspecialchars($target_username))) . '
'; + echo '
'; + + echo ''; + $class = 'row1'; + + $tpl = ' '; + $parser = $template->makeParserText($tpl); + + if ( count($comments) > 0 ) + { + foreach ( $comments as $comment ) + { + $c_page_id = $paths->nslist[ $comment['namespace'] ] . sanitize_page_id($comment['page_id']); + if ( isset($paths->pages[ $c_page_id ]) ) + { + $parser->assign_bool(array( + 'page_exists' => true + )); + $page_title = htmlspecialchars($paths->pages[ $c_page_id ]['name']); + } + else + { + $parser->assign_bool(array( + 'page_exists' => false + )); + $page_title = htmlspecialchars(dirtify_page_id($c_page_id)); + } + $parser->assign_vars(array( + 'CLASS' => $class, + 'PAGE_LINK' => makeUrlNS($comment['namespace'], sanitize_page_id($comment['page_id'])), + 'PAGE' => $page_title, + 'SUBJECT' => $comment['subject'], + 'DATE' => $comment['time'], + 'COMMENT_LINK' => makeUrlNS($comment['namespace'], sanitize_page_id($comment['page_id']), 'do=comments', true) + )); + $class = ( $class == 'row3' ) ? 'row1' : 'row3'; + echo $parser->run(); + } + } + else + { + echo ''; + } + echo '
+ class="wikilink-nonexistent">{PAGE}
+ {lang:userpage_comments_lbl_posted} {DATE}
+ {SUBJECT} +
' . $lang->get('userpage_msg_no_comments') . '
'; + + echo '
'; + echo '
+
'; + + echo ''; + + // + // CONTACT INFORMATION + // + + echo ' '; + + echo '
+ '; + + // + // Main part of sidebar + // + + // Contact information + + echo ''; + + $class = 'row3'; + + if ( $userdata['email_public'] == 1 ) + { + $class = ( $class == 'row1' ) ? 'row3' : 'row1'; + $email_link = $email->encryptEmail($userdata['email']); + echo ''; + } + + $class = ( $class == 'row1' ) ? 'row3' : 'row1'; + if ( $session->user_logged_in ) + { + echo ''; + } + else + { + echo ''; + } + + if ( !empty($userdata['user_aim']) ) + { + $class = ( $class == 'row1' ) ? 'row3' : 'row1'; + echo ''; + } + + if ( !empty($userdata['user_yahoo']) ) + { + $class = ( $class == 'row1' ) ? 'row3' : 'row1'; + echo ''; + } + + if ( !empty($userdata['user_msn']) ) + { + $class = ( $class == 'row1' ) ? 'row3' : 'row1'; + $email_link = $email->encryptEmail($userdata['user_msn']); + echo ''; + } + + if ( !empty($userdata['user_xmpp']) ) + { + $class = ( $class == 'row1' ) ? 'row3' : 'row1'; + $email_link = $email->encryptEmail($userdata['user_xmpp']); + echo ''; + } + + // Real life + + echo ''; + + if ( !empty($userdata['user_location']) ) + { + $class = ( $class == 'row1' ) ? 'row3' : 'row1'; + echo ''; + } + + if ( !empty($userdata['user_job']) ) + { + $class = ( $class == 'row1' ) ? 'row3' : 'row1'; + echo ''; + } + + if ( !empty($userdata['user_hobbies']) ) + { + $class = ( $class == 'row1' ) ? 'row3' : 'row1'; + echo ''; + } + + if ( empty($userdata['user_location']) && empty($userdata['user_job']) && empty($userdata['user_hobbies']) ) + { + $class = ( $class == 'row1' ) ? 'row3' : 'row1'; + echo ''; + } + + $code = $plugins->setHook('userpage_sidebar_right'); + foreach ( $code as $cmd ) + { + eval($cmd); + } + + echo '
' . $lang->get('userpage_heading_contact') . '
' . $lang->get('userpage_lbl_email') . ' ' . $email_link . '
' . $lang->get('userpage_btn_send_pm', array('username' => htmlspecialchars($target_username), 'pm_link' => makeUrlNS('Special', 'PrivateMessages/Compose/to/' . $this->page_id, false, true))) . '
' . $lang->get('userpage_btn_send_pm_guest', array('username' => htmlspecialchars($target_username), 'login_flags' => 'href="' . makeUrlNS('Special', 'Login/' . $paths->nslist[$this->namespace] . $this->page_id) . '" onclick="ajaxStartLogin(); return false;"')) . '
' . $lang->get('userpage_lbl_aim') . ' ' . $userdata['user_aim'] . '
' . $lang->get('userpage_lbl_yim') . ' ' . $userdata['user_yahoo'] . '
' . $lang->get('userpage_lbl_wlm') . ' ' . $email_link . '
' . $lang->get('userpage_lbl_xmpp') . ' ' . $email_link . '
' . $lang->get('userpage_heading_real_life', array('username' => htmlspecialchars($target_username))) . '
' . $lang->get('userpage_lbl_location') . ' ' . $userdata['user_location'] . '
' . $lang->get('userpage_lbl_job') . ' ' . $userdata['user_job'] . '
' . $lang->get('userpage_lbl_hobbies') . ' ' . $userdata['user_hobbies'] . '
' . $lang->get('userpage_msg_no_contact_info', array('username' => htmlspecialchars($target_username))) . '
+
'; + echo ''; + + // + // End of profile + // + + echo ''; + + echo '
'; // tab:profile + + } + + // User's own content + + echo ''; + + echo '
'; + + if ( $this->exists ) + { + $this->send_from_db(true, false); + } + else + { + $this->error_404(true); + } + + echo '
'; // tab:content + + $code = $plugins->setHook('userpage_tabs_body'); + foreach ( $code as $cmd ) + { + eval($cmd); + } + + if ( $user_exists ) + { + echo '
'; // userpage_wrap + } + else + { + if ( !is_valid_ip($target_username) ) + { + echo '

' . $lang->get('userpage_msg_user_not_exist', array('username' => htmlspecialchars($target_username))) . '

'; + } + } + + // if ( $send_headers ) + // { + // display_page_footers(); + // } + + $output->footer(); + } +} + diff -r 4629ad98ee88 -r 9cdfe82c56cd includes/output.php --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/includes/output.php Sat Jan 03 18:11:18 2009 -0500 @@ -0,0 +1,262 @@ +header(). + * @access public + */ + + abstract public function header(); + + /** + * Call this to send extra stuff after the content (equivalent of $template->footer()). + * @access public + */ + + abstract public function footer(); + + /** + * Add some code just before the header. + * @access public + */ + + public function add_before_header($code) + { + $this->before_header .= $code; + } + + /** + * Add some code just after the header. + * @access public + */ + + public function add_after_header($code) + { + $this->after_header .= $code; + } + + /** + * Add some code just before the footer. + * @access public + */ + + public function add_before_footer($code) + { + $this->before_footer .= $code; + } + + /** + * Add some code just after the footer. + * @access public + */ + + public function add_after_footer($code) + { + $this->after_footer .= $code; + } + + /** + * Send any required HTML headers through, e.g. Content-type. + * @access public + */ + + public function http_headers() + { + header('Content-type: text/html'); + } + + /** + * Set the title of the page being output. + * @param string Page name + */ + + public function set_title($title) + { + $this->title = $title; + } + + /** + * Avoid sending things out of order. + * @var bool + * @var bool + */ + + public $headers_sent = false, $footers_sent = false; +} + +/** + * HTML outputter. + */ + +class Output_HTML extends Output_Base +{ + public function header() + { + if ( $this->headers_sent ) + return; + + $this->headers_sent = true; + + ob_start(); + } + + public function footer() + { + global $template; + if ( !$this->headers_sent ) + return; + + $this->headers_sent = false; + $content = ob_get_contents(); + ob_end_clean(); + + ob_start(); + echo $this->before_header; + echo $template->getHeader(); + echo $this->after_header; + echo $content; + echo $this->before_footer; + echo $template->getFooter(); + echo $this->after_footer; + + } + + public function set_title($title) + { + global $template; + $template->assign_vars(array( + 'PAGE_NAME' => $title + )); + } +} + +/** + * Outputter that bypasses $template->header() and $template->footer(), but still shows HTML added via {before,after}_{header,footer}. + */ + +class Output_Striptease extends Output_HTML +{ + public function header() + { + echo $this->before_header; + echo $this->after_header; + } + + public function footer() + { + echo $this->before_footer; + echo $this->after_footer; + } +} + +/** + * Outputter that bypasses $template->header() and $template->footer(). + */ + +class Output_Naked extends Output_HTML +{ + public $naked = true; + + public function header() + { + } + + public function footer() + { + } +} + +/** + * Safe template outputter + */ + +class Output_Safe +{ + protected $template; + protected $headers_sent = false; + public function __construct() + { + $this->template = new template_nodb(); + $theme = ( defined('ENANO_CONFIG_FETCHED') ) ? getConfig('theme_default') : 'oxygen'; + $style = ( defined('ENANO_CONFIG_FETCHED') ) ? '__foo__' : 'bleu'; + + $this->template->load_theme($theme, $style); + $this->template->tpl_strings['SITE_NAME'] = getConfig('site_name'); + $this->template->tpl_strings['SITE_DESC'] = getConfig('site_desc'); + $this->template->tpl_strings['COPYRIGHT'] = getConfig('copyright_notice'); + $this->template->tpl_strings['PAGE_NAME'] = 'Untitled'; + } + public function header() + { + if ( $this->headers_sent ) + return; + + $this->headers_sent = true; + + $this->template->header(); + } + + public function footer() + { + global $template; + if ( !$this->headers_sent ) + { + $this->template->header(); + } + + $this->headers_sent = false; + $this->template->footer(); + + } + + public function set_title($title) + { + $this->template->tpl_strings['PAGE_NAME'] = $title; + } +} + +?> diff -r 4629ad98ee88 -r 9cdfe82c56cd includes/pageprocess.php --- a/includes/pageprocess.php Sat Jan 03 17:54:26 2009 -0500 +++ b/includes/pageprocess.php Sat Jan 03 18:11:18 2009 -0500 @@ -19,7 +19,7 @@ * @package Enano * @subpackage UI * @copyright 2007 Dan Fuhry - * @license GNU General Public License + * @license GNU General Public License */ class PageProcessor @@ -34,6 +34,13 @@ var $namespace; /** + * The instance of the namespace processor for the namespace we're doing. + * @var object + */ + + var $ns; + + /** * The title of the page sent to the template parser * @var string */ @@ -193,6 +200,7 @@ } // Is there a custom function registered for handling this namespace? + // DEPRECATED (even though it only saw its way into one alpha release.) if ( $proc = $paths->get_namespace_processor($this->namespace) ) { // yes, just call that @@ -226,6 +234,7 @@ { $this->send_headers = false; $strict_no_headers = true; + $GLOBALS['output'] = new Output_Naked(); } if ( isset($paths->pages[$pathskey]['password']) ) { @@ -271,125 +280,15 @@ require_once(ENANO_ROOT.'/includes/stats.php'); doStats($this->page_id, $this->namespace); } - if ( $this->namespace == 'Special' || $this->namespace == 'Admin' ) - { - if ( $this->send_headers ) - { - $template->init_vars($this); - } - - $this->revision_time = time(); - - if ( !$this->page_exists ) - { - $func_name = "page_{$this->namespace}_{$this->page_id}"; - - die_semicritical($lang->get('page_msg_admin_404_title'), $lang->get('page_msg_admin_404_body', array('func_name' => $func_name)), (!$this->send_headers)); - } - $func_name = "page_{$this->namespace}_{$this->page_id}"; - if ( function_exists($func_name) ) - { - $result = @call_user_func($func_name); - return $result; - } - else - { - $title = $lang->get('page_err_custompage_function_missing_title'); - $message = $lang->get('page_err_custompage_function_missing_body', array( 'function_name' => $fname )); - - if ( $this->send_headers ) - { - $template->tpl_strings['PAGE_NAME'] = $title; - $template->header(); - echo "

$message

"; - $template->footer(); - } - else - { - echo "

$title

-

$message

"; - } - return false; - } - } - else if ( $this->namespace == 'User' && strpos($this->page_id, '/') === false ) - { - if ( $this->send_headers ) - { - $template->init_vars($this); - } - - $this->_handle_userpage(); - } - else if ( ( $this->namespace == 'Template' || $this->namespace == 'System' ) && $this->page_exists ) + + // We are all done. Ship off the page. + + if ( $this->send_headers ) { - if ( $this->send_headers ) - { - $template->init_vars($this); - } - - $this->header(); - - $text = $this->fetch_text(); - $text = preg_replace('/(.*?)<\/noinclude>/is', '\\1', $text); - $text = preg_replace('/(.*?)<\/nodisplay>/is', '', $text); - - $text = RenderMan::render( $text ); - - eval( '?>' . $text ); - - $this->footer(); - } - else if ( $this->namespace == 'API' ) - { - if ( $this->send_headers ) - { - $template->init_vars($this); - } - - $uri = scriptPath . '/' . $this->page_id; - if ( !$this->send_headers ) - { - $sep = ( strstr($uri, '?') ) ? '&' : '?'; - $uri .= "{$sep}noheaders"; - } - redirect( $uri, '', '', 0 ); + $template->init_vars($this); } - else if ( !$this->page_exists ) - { - // Perhaps this is hooked? - ob_start(); - - $code = $plugins->setHook('page_not_found'); - foreach ( $code as $cmd ) - { - eval($cmd); - } - - $ob = ob_get_contents(); - - if ( empty($ob) ) - { - if ( $this->send_headers ) - { - $template->init_vars($this); - } - $this->err_page_not_existent(); - } - else - { - // Something sent content, so we'll assume the page exist...ed at least according to the plugin - if ( $this->namespace != 'Special' && $this->namespace != 'Admin' && $do_stats ) - { - require_once(ENANO_ROOT.'/includes/stats.php'); - doStats($this->page_id, $this->namespace); - } - } - } - else - { - $this->send_from_db($strict_no_headers); - } + + $this->ns->send(); } /** @@ -450,6 +349,8 @@ function fetch_source() { + global $db, $session, $paths, $template, $plugins; // Common objects + if ( !$this->perms->get_permissions('view_source') ) { return false; @@ -458,6 +359,17 @@ { return ''; } + $pathskey = $paths->nslist[ $this->namespace ] . $this->page_id; + if ( isset($paths->pages[$pathskey]) ) + { + if ( isset($paths->pages[$pathskey]['password']) ) + { + if ( $paths->pages[$pathskey]['password'] != sha1('') && $paths->pages[$pathskey]['password'] !== $this->password && !empty($paths->pages[$pathskey]['password']) ) + { + return false; + } + } + } return $this->fetch_text(); } @@ -1013,48 +925,10 @@ $this->perms = $session->fetch_page_acl( $page_id, $namespace ); - // Exception for Admin: pages - if ( $this->namespace == 'Admin' ) - { - $fname = "page_Admin_{$this->page_id}"; - } - - // Does the page "exist"? - $pathskey = $paths->nslist[$namespace] . $page_id_cleaned; + // resolve namespace + $this->ns = namespace_factory($this->page_id, $this->namespace, $this->revision_id); - if ( $paths->page_id == $page_id && $paths->namespace == $namespace && !$paths->page_exists && ( $this->namespace != 'Admin' || ($this->namespace == 'Admin' && !function_exists($fname) ) ) ) - { - $this->page_exists = false; - } - else if ( !isset( $paths->pages[ $pathskey ] ) && ( ( $this->namespace == 'Admin' && !function_exists($fname) ) || ( $this->namespace != 'Admin' ) ) ) - { - $this->page_exists = false; - } - else - { - $this->page_exists = true; - } - - // Compatibility with older databases - if ( strstr($this->page_id, '.2e') && !$this->page_exists ) - { - $page_id = str_replace('.2e', '.', $page_id); - - if ( $paths->page_id == $page_id && $paths->namespace == $namespace && !$paths->page_exists && ( $this->namespace != 'Admin' || ($this->namespace == 'Admin' && !function_exists($fname) ) ) ) - { - $this->page_exists = false; - } - else if ( !isset( $paths->pages[ $paths->nslist[$namespace] . $page_id ] ) && ( $this->namespace == 'Admin' && !function_exists($fname) ) ) - { - $this->page_exists = false; - } - else - { - $this->page_exists = true; - } - - } - + $this->page_exists = $this->ns->exists(); $this->title = get_page_title_ns($this->page_id, $this->namespace); profiler_log("PageProcessor [{$this->namespace}:{$this->page_id}]: Ran _setup()"); @@ -1068,129 +942,22 @@ function render($incl_inner_headers = true, $_errormsg = false) { global $db, $session, $paths, $template, $plugins; // Common objects - global $lang; - - $text = $this->fetch_text(); + global $output, $lang; - $text = preg_replace('/([\s]*)__NOBREADCRUMBS__([\s]*)/', '', $text); - $text = preg_replace('/([\s]*)__NOTOC__([\s]*)/', '', $text); - - $redir_enabled = false; - if ( preg_match('/^#redirect \[\[([^\]]+?)\]\]/i', $text, $match ) ) + if ( count($this->redirect_stack) > 0 ) { - $redir_enabled = true; - - $oldtarget = RenderMan::strToPageID($match[1]); - $oldtarget[0] = sanitize_page_id($oldtarget[0]); - - $url = makeUrlNS($oldtarget[1], $oldtarget[0], false, true); - $page_id_key = $paths->nslist[ $oldtarget[1] ] . $oldtarget[0]; - $page_data = $paths->pages[$page_id_key]; - $title = ( isset($page_data['name']) ) ? $page_data['name'] : $paths->nslist[$oldtarget[1]] . htmlspecialchars( str_replace('_', ' ', dirtify_page_id( $oldtarget[0] ) ) ); - if ( !isset($page_data['name']) ) - { - $cls = 'class="wikilink-nonexistent"'; - } - else - { - $cls = ''; - } - $a = '' . $title . ''; - $redir_html = '
- - - - - -
- Cute wet-floor icon - - ' . $lang->get('page_msg_this_is_a_redirector', array( 'redirect_target' => $a )) . ' -
-
-
-
'; - $text = str_replace($match[0], '', $text); - $text = trim($text); - } - - $template->tpl_strings['PAGE_NAME'] = htmlspecialchars( $this->title ); - - $this->header(); - $this->do_breadcrumbs(); - - if ( $_errormsg ) - { - echo $_errormsg; - } - - if ( $incl_inner_headers ) - { - if ( count($this->redirect_stack) > 0 ) + $stack = array_reverse($this->redirect_stack); + foreach ( $stack as $oldtarget ) { - $stack = array_reverse($this->redirect_stack); - foreach ( $stack as $oldtarget ) - { - $url = makeUrlNS($oldtarget[1], $oldtarget[0], 'redirect=no', true); - $page_id_key = $paths->nslist[ $oldtarget[1] ] . $oldtarget[0]; - $page_data = $paths->pages[$page_id_key]; - $title = ( isset($page_data['name']) ) ? $page_data['name'] : $paths->nslist[$oldtarget[1]] . htmlspecialchars( str_replace('_', ' ', dirtify_page_id( $oldtarget[0] ) ) ); - $a = '' . $title . ''; - echo '' . $lang->get('page_msg_redirected_from', array('from' => $a)) . '
'; - } + $url = makeUrlNS($oldtarget[1], $oldtarget[0], 'redirect=no', true); + $page_id_key = $paths->nslist[ $oldtarget[1] ] . $oldtarget[0]; + $page_data = $paths->pages[$page_id_key]; + $title = ( isset($page_data['name']) ) ? $page_data['name'] : $paths->nslist[$oldtarget[1]] . htmlspecialchars( str_replace('_', ' ', dirtify_page_id( $oldtarget[0] ) ) ); + $a = '' . $title . ''; + $output->add_after_header('' . $lang->get('page_msg_redirected_from', array('from' => $a)) . '
'); } - display_page_headers(); - } - - if ( $this->revision_id ) - { - echo '
- ' . $lang->get('page_msg_archived_title') . '
- ' . $lang->get('page_msg_archived_body', array( - 'archive_date' => enano_date('F d, Y', $this->revision_time), - 'archive_time' => enano_date('h:i a', $this->revision_time), - 'current_link' => makeUrlNS($this->namespace, $this->page_id), - 'restore_link' => makeUrlNS($this->namespace, $this->page_id, 'do=edit&revid='.$this->revision_id), - 'restore_onclick' => 'ajaxEditor(\''.$this->revision_id.'\'); return false;', - )) . ' -
'; - } - - if ( $redir_enabled ) - { - echo $redir_html; } - - $code = $plugins->setHook('pageprocess_render_head'); - foreach ( $code as $cmd ) - { - eval($cmd); - } - - if ( $incl_inner_headers ) - { - $text = '?>' . RenderMan::render($text); - } - else - { - $text = '?>' . $text; - $text = preg_replace('/(.*?)<\/nowiki>/s', '\\1', $text); - } - - eval ( $text ); - - $code = $plugins->setHook('pageprocess_render_tail'); - foreach ( $code as $cmd ) - { - eval($cmd); - } - - if ( $incl_inner_headers ) - { - display_page_footers(); - } - - $this->footer(); + $this->ns->send($incl_inner_headers, $_errormsg); } /** @@ -1222,582 +989,7 @@ function fetch_text() { - global $db, $session, $paths, $template, $plugins; // Common objects - - if ( !empty($this->text_cache) ) - { - return $this->text_cache; - } - - if ( $this->revision_id > 0 && is_int($this->revision_id) ) - { - - $q = $db->sql_query('SELECT page_text, char_tag, time_id FROM '.table_prefix.'logs WHERE log_type=\'page\' AND action=\'edit\' AND page_id=\'' . $this->page_id . '\' AND namespace=\'' . $this->namespace . '\' AND log_id=' . $this->revision_id . ';'); - if ( !$q ) - { - $this->send_error('Error during SQL query.', true); - } - if ( $db->numrows() < 1 ) - { - // Compatibility fix for old pages with dots in the page ID - if ( strstr($this->page_id, '.2e') ) - { - $db->free_result(); - $page_id = str_replace('.2e', '.', $this->page_id); - $q = $db->sql_query('SELECT page_text, char_tag, time_id FROM '.table_prefix.'logs WHERE log_type=\'page\' AND action=\'edit\' AND page_id=\'' . $page_id . '\' AND namespace=\'' . $this->namespace . '\' AND log_id=' . $this->revision_id . ';'); - if ( !$q ) - { - $this->send_error('Error during SQL query.', true); - } - if ( $db->numrows() < 1 ) - { - $this->page_exists = false; - return 'err_no_text_rows'; - } - } - else - { - $this->page_exists = false; - return 'err_no_text_rows'; - } - } - else - { - $row = $db->fetchrow(); - } - - $db->free_result(); - - } - 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" - . " WHERE t.page_id='$this->page_id' AND t.namespace='$this->namespace'\n" - . " ORDER BY l.time_id DESC LIMIT 1;"); - if ( !$q ) - { - $this->send_error('Error during SQL query.', true); - } - if ( $db->numrows() < 1 ) - { - // Compatibility fix for old pages with dots in the page ID - if ( strstr($this->page_id, '.2e') ) - { - $db->free_result(); - $page_id = str_replace('.2e', '.', $this->page_id); - $q = $db->sql_query('SELECT page_text, char_tag FROM '.table_prefix.'page_text WHERE page_id=\'' . $page_id . '\' AND namespace=\'' . $this->namespace . '\';'); - if ( !$q ) - { - $this->send_error('Error during SQL query.', true); - } - if ( $db->numrows() < 1 ) - { - $this->page_exists = false; - return 'err_no_text_rows'; - } - } - else - { - $this->page_exists = false; - return 'err_no_text_rows'; - } - } - - $row = $db->fetchrow(); - $db->free_result(); - - } - - if ( !empty($row['char_tag']) ) - { - // This page text entry uses the old text-escaping format - $from = array( - "{APOS:{$row['char_tag']}}", - "{QUOT:{$row['char_tag']}}", - "{SLASH:{$row['char_tag']}}" - ); - $to = array("'", '"', '\\'); - $row['page_text'] = str_replace($from, $to, $row['page_text']); - } - - $this->text_cache = $row['page_text']; - - if ( isset($row['time_id']) ) - { - $this->revision_time = intval($row['time_id']); - } - - return $row['page_text']; - - } - - /** - * Handles the extra overhead required for user pages. - * @access private - */ - - function _handle_userpage() - { - global $db, $session, $paths, $template, $plugins; // Common objects - global $email; - global $lang; - - /** - * PLUGGING INTO USER PAGES - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * Userpages are highly programmable and extendable using a number of - * hooks. These hooks are: - * - * - userpage_sidebar_left - * - userpage_sidebar_right - * - userpage_tabs_links - * - userpage_tabs_body - * - * You can add a variety of sections to user pages, including new tabs - * and new sections on the tables. To add a tab, attach to - * userpage_tabs_links and echo out: - * - *
  • YOUR TAB TEXT
  • - * - * Then hook into userpage_tabs_body and echo out: - * - *
    YOUR TAB CONTENT
    - * - * The userpage javascript runtime will take care of everything else, - * meaning transitions, click events, etc. Currently it's not possible - * to add custom click events to tabs, but any DOM-related JS that needs - * to run in your tab can be run onload and the effects will be seen when - * your tab is clicked. YOURTABID should be lowercase alphanumeric and - * have a short prefix so as to assure that it remains specific to your - * plugin. - * - * To hook into the "profile" tab, use userpage_sidebar_{left,right}. Just - * echo out table cells as normal. The table on the left (the wide one) has - * four columns, and the one on the right has one column. - * - * See plugins.php for a guide on creating and attaching to hooks. - */ - - $page_urlname = dirtify_page_id($this->page_id); - if ( $this->page_id == $paths->page_id && $this->namespace == $paths->namespace ) - { - $page_name = ( isset($paths->cpage['name']) ) ? $paths->cpage['name'] : $this->page_id; - } - else - { - $page_name = ( isset($paths->pages[$this->page_id]) ) ? $paths->pages[$this->page_id]['name'] : $this->page_id; - } - - $target_username = strtr($page_urlname, - Array( - '_' => ' ', - '<' => '<', - '>' => '>' - )); - - $target_username = preg_replace('/^' . str_replace('/', '\\/', preg_quote($paths->nslist['User'])) . '/', '', $target_username); - list($target_username) = explode('/', $target_username); - - if ( ( $page_name == str_replace('_', ' ', $this->page_id) || $page_name == $paths->nslist['User'] . str_replace('_', ' ', $this->page_id) ) || !$this->page_exists ) - { - $page_name = $lang->get('userpage_page_title', array('username' => $target_username)); - } - else - { - // User has a custom title for their userpage - $page_name = $paths->pages[ $paths->nslist[$this->namespace] . $this->page_id ]['name']; - } - - $template->tpl_strings['PAGE_NAME'] = htmlspecialchars($page_name); - - $q = $db->sql_query('SELECT u.username, u.user_id AS authoritative_uid, u.real_name, u.email, u.reg_time, u.user_has_avatar, u.avatar_type, x.*, COUNT(c.comment_id) AS n_comments - FROM '.table_prefix.'users u - LEFT JOIN '.table_prefix.'users_extra AS x - ON ( u.user_id = x.user_id OR x.user_id IS NULL ) - LEFT JOIN '.table_prefix.'comments AS c - ON ( ( c.user_id=u.user_id AND c.name=u.username AND c.approved=1 ) OR ( c.comment_id IS NULL AND c.approved IS NULL ) ) - WHERE u.username=\'' . $db->escape($target_username) . '\' - GROUP BY u.username, u.user_id, u.real_name, u.email, u.reg_time, u.user_has_avatar, u.avatar_type, x.user_id, x.user_aim, x.user_yahoo, x.user_msn, x.user_xmpp, x.user_homepage, x.user_location, x.user_job, x.user_hobbies, x.email_public;'); - if ( !$q ) - $db->_die(); - - $user_exists = true; - - if ( $db->numrows() < 1 ) - { - $user_exists = false; - } - else - { - $userdata = $db->fetchrow(); - if ( $userdata['authoritative_uid'] == 1 ) - { - // Hide data for anonymous user - $user_exists = false; - unset($userdata); - } - } - - // get the user's rank - if ( $user_exists ) - { - $rank_data = $session->get_user_rank(intval($userdata['authoritative_uid'])); - } - else - { - // get the rank data for the anonymous user (placeholder basically) - $rank_data = $session->get_user_rank(1); - } - - // add the userpage script to the header - $template->add_header(''); - - $this->header(); - - // if ( $send_headers ) - // { - // display_page_headers(); - // } - - // - // BASIC INFORMATION - // Presentation of username/rank/avatar/basic info - // - - if ( $user_exists ) - { - - ?> -
    - - -
    - - - '; - - echo ' '; - - echo '
    - '; - - // heading - echo ' - - ' . ( - $session->user_level >= USER_LEVEL_ADMIN ? - '' - : '' - ) . ' - '; - - // avi/rank/username - echo ' - - '; - - // join date & total comments - echo ''; - echo ' - '; - echo ' - '; - echo ''; - - // real name - if ( !empty($userdata['real_name']) ) - { - echo ' - - - '; - } - - // latest comments - - echo ''; - $q = $db->sql_query('SELECT page_id, namespace, subject, time FROM '.table_prefix.'comments WHERE name=\'' . $db->escape($target_username) . '\' AND user_id=' . $userdata['authoritative_uid'] . ' AND approved=1 ORDER BY time DESC LIMIT 7;'); - if ( !$q ) - $db->_die(); - - $comments = Array(); - $no_comments = false; - - if ( $row = $db->fetchrow() ) - { - do - { - $row['time'] = enano_date('F d, Y', $row['time']); - $comments[] = $row; - } - while ( $row = $db->fetchrow() ); - } - else - { - $no_comments = true; - } - - echo ''; - - $code = $plugins->setHook('userpage_sidebar_left'); - foreach ( $code as $cmd ) - { - eval($cmd); - } - - echo '
    - ' . $lang->get('userpage_heading_basics', array('username' => htmlspecialchars($target_username))) . ' - » ' . $lang->get('userpage_btn_administer_user') . '
    - ' . ( - $userdata['user_has_avatar'] == 1 ? - '
    - ' . $lang->get('usercp_avatar_image_alt', array('username' => $userdata['username'])) . ' -
    ' - : '' - ) . ' - ' . htmlspecialchars($userdata['username']) . ' - ' . ( !empty($rank_data['user_title']) ? '
    ' . htmlspecialchars($rank_data['user_title']) : '' ) . ' - ' . ( !empty($rank_data['rank_title']) ? '
    ' . htmlspecialchars($lang->get($rank_data['rank_title'])) : '' ) . ' -
    - ' . $lang->get('userpage_lbl_joined') . ' - - ' . enano_date('F d, Y h:i a', $userdata['reg_time']) . ' - - ' . $lang->get('userpage_lbl_num_comments') . ' - - ' . $userdata['n_comments'] . ' -
    - ' . $lang->get('userpage_lbl_real_name') . ' - - ' . htmlspecialchars($userdata['real_name']) . ' -
    ' . $lang->get('userpage_heading_comments', array('username' => htmlspecialchars($target_username))) . '
    '; - echo '
    '; - - echo ''; - $class = 'row1'; - - $tpl = ' '; - $parser = $template->makeParserText($tpl); - - if ( count($comments) > 0 ) - { - foreach ( $comments as $comment ) - { - $c_page_id = $paths->nslist[ $comment['namespace'] ] . sanitize_page_id($comment['page_id']); - if ( isset($paths->pages[ $c_page_id ]) ) - { - $parser->assign_bool(array( - 'page_exists' => true - )); - $page_title = htmlspecialchars($paths->pages[ $c_page_id ]['name']); - } - else - { - $parser->assign_bool(array( - 'page_exists' => false - )); - $page_title = htmlspecialchars(dirtify_page_id($c_page_id)); - } - $parser->assign_vars(array( - 'CLASS' => $class, - 'PAGE_LINK' => makeUrlNS($comment['namespace'], sanitize_page_id($comment['page_id'])), - 'PAGE' => $page_title, - 'SUBJECT' => $comment['subject'], - 'DATE' => $comment['time'], - 'COMMENT_LINK' => makeUrlNS($comment['namespace'], sanitize_page_id($comment['page_id']), 'do=comments', true) - )); - $class = ( $class == 'row3' ) ? 'row1' : 'row3'; - echo $parser->run(); - } - } - else - { - echo ''; - } - echo '
    - class="wikilink-nonexistent">{PAGE}
    - {lang:userpage_comments_lbl_posted} {DATE}
    - {SUBJECT} -
    ' . $lang->get('userpage_msg_no_comments') . '
    '; - - echo '
    '; - echo '
    -
    '; - - echo ''; - - // - // CONTACT INFORMATION - // - - echo ' '; - - echo '
    - '; - - // - // Main part of sidebar - // - - // Contact information - - echo ''; - - $class = 'row3'; - - if ( $userdata['email_public'] == 1 ) - { - $class = ( $class == 'row1' ) ? 'row3' : 'row1'; - $email_link = $email->encryptEmail($userdata['email']); - echo ''; - } - - $class = ( $class == 'row1' ) ? 'row3' : 'row1'; - if ( $session->user_logged_in ) - { - echo ''; - } - else - { - echo ''; - } - - if ( !empty($userdata['user_aim']) ) - { - $class = ( $class == 'row1' ) ? 'row3' : 'row1'; - echo ''; - } - - if ( !empty($userdata['user_yahoo']) ) - { - $class = ( $class == 'row1' ) ? 'row3' : 'row1'; - echo ''; - } - - if ( !empty($userdata['user_msn']) ) - { - $class = ( $class == 'row1' ) ? 'row3' : 'row1'; - $email_link = $email->encryptEmail($userdata['user_msn']); - echo ''; - } - - if ( !empty($userdata['user_xmpp']) ) - { - $class = ( $class == 'row1' ) ? 'row3' : 'row1'; - $email_link = $email->encryptEmail($userdata['user_xmpp']); - echo ''; - } - - // Real life - - echo ''; - - if ( !empty($userdata['user_location']) ) - { - $class = ( $class == 'row1' ) ? 'row3' : 'row1'; - echo ''; - } - - if ( !empty($userdata['user_job']) ) - { - $class = ( $class == 'row1' ) ? 'row3' : 'row1'; - echo ''; - } - - if ( !empty($userdata['user_hobbies']) ) - { - $class = ( $class == 'row1' ) ? 'row3' : 'row1'; - echo ''; - } - - if ( empty($userdata['user_location']) && empty($userdata['user_job']) && empty($userdata['user_hobbies']) ) - { - $class = ( $class == 'row1' ) ? 'row3' : 'row1'; - echo ''; - } - - $code = $plugins->setHook('userpage_sidebar_right'); - foreach ( $code as $cmd ) - { - eval($cmd); - } - - echo '
    ' . $lang->get('userpage_heading_contact') . '
    ' . $lang->get('userpage_lbl_email') . ' ' . $email_link . '
    ' . $lang->get('userpage_btn_send_pm', array('username' => htmlspecialchars($target_username), 'pm_link' => makeUrlNS('Special', 'PrivateMessages/Compose/to/' . $this->page_id, false, true))) . '
    ' . $lang->get('userpage_btn_send_pm_guest', array('username' => htmlspecialchars($target_username), 'login_flags' => 'href="' . makeUrlNS('Special', 'Login/' . $paths->nslist[$this->namespace] . $this->page_id) . '" onclick="ajaxStartLogin(); return false;"')) . '
    ' . $lang->get('userpage_lbl_aim') . ' ' . $userdata['user_aim'] . '
    ' . $lang->get('userpage_lbl_yim') . ' ' . $userdata['user_yahoo'] . '
    ' . $lang->get('userpage_lbl_wlm') . ' ' . $email_link . '
    ' . $lang->get('userpage_lbl_xmpp') . ' ' . $email_link . '
    ' . $lang->get('userpage_heading_real_life', array('username' => htmlspecialchars($target_username))) . '
    ' . $lang->get('userpage_lbl_location') . ' ' . $userdata['user_location'] . '
    ' . $lang->get('userpage_lbl_job') . ' ' . $userdata['user_job'] . '
    ' . $lang->get('userpage_lbl_hobbies') . ' ' . $userdata['user_hobbies'] . '
    ' . $lang->get('userpage_msg_no_contact_info', array('username' => htmlspecialchars($target_username))) . '
    -
    '; - echo ''; - - // - // End of profile - // - - echo ''; - - echo '
    '; // tab:profile - - } - - // User's own content - - $send_headers = $this->send_headers; - $this->send_headers = false; - - echo ''; - - echo '
    '; - - if ( $this->page_exists ) - { - $this->render(); - } - else - { - $this->err_page_not_existent(true); - } - - echo '
    '; // tab:content - - $code = $plugins->setHook('userpage_tabs_body'); - foreach ( $code as $cmd ) - { - eval($cmd); - } - - if ( $user_exists ) - { - echo '
    '; // userpage_wrap - } - else - { - if ( !is_valid_ip($target_username) ) - { - echo '

    ' . $lang->get('userpage_msg_user_not_exist', array('username' => htmlspecialchars($target_username))) . '

    '; - } - } - - // if ( $send_headers ) - // { - // display_page_footers(); - // } - - $this->send_headers = $send_headers; - unset($send_headers); - - $this->footer(); - + return $this->ns->fetch_text(); } /** @@ -1910,13 +1102,13 @@ global $db, $session, $paths, $template, $plugins; // Common objects global $lang; - $title = 'Password required'; + $title = $lang->get('page_msg_passrequired_title'); $message = ( empty($this->password) ) ? '

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

    ' : '

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

    '; $message .= '

    -    +   

    '; if ( $this->send_headers ) @@ -1959,158 +1151,6 @@ } /** - * Tell the user the page doesn't exist, and present them with their options. - * @access private - */ - - function err_page_not_existent($userpage = false) - { - global $db, $session, $paths, $template, $plugins; // Common objects - global $lang; - - @header('HTTP/1.1 404 Not Found'); - - $this->header(); - $this->do_breadcrumbs(); - - $msg = ( $pp = $paths->sysmsg('Page_not_found') ) ? $pp : '{STANDARD404}'; - - $standard_404 = ''; - - if ( $userpage ) - { - $standard_404 .= '

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

    -

    ' . $lang->get('page_msg_404_body_userpage'); - } - else - { - $standard_404 .= '

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

    -

    ' . $lang->get('page_msg_404_body'); - } - if ( $session->get_permissions('create_page') ) - { - $standard_404 .= ' ' . $lang->get('page_msg_404_create', array( - 'create_flags' => 'href="'.makeUrlNS($this->namespace, $this->page_id, 'do=edit', true).'" onclick="ajaxEditor(); return false;"', - 'mainpage_link' => makeUrl(get_main_page(), false, true) - )); - } - else - { - $standard_404 .= ' ' . $lang->get('page_msg_404_gohome', array( - 'mainpage_link' => makeUrl(get_main_page(), false, true) - )); - } - $standard_404 .= '

    '; - if ( $session->get_permissions('history_rollback') ) - { - $e = $db->sql_query('SELECT * FROM ' . table_prefix . 'logs WHERE action=\'delete\' AND page_id=\'' . $this->page_id . '\' AND namespace=\'' . $this->namespace . '\' ORDER BY time_id DESC;'); - if ( !$e ) - { - $db->_die('The deletion log could not be selected.'); - } - if ( $db->numrows() > 0 ) - { - $r = $db->fetchrow(); - $standard_404 .= '

    ' . $lang->get('page_msg_404_was_deleted', array( - 'delete_time' => enano_date('d M Y h:i a', $r['time_id']), - 'delete_reason' => htmlspecialchars($r['edit_summary']), - 'rollback_flags' => 'href="'.makeUrl($paths->page, 'do=rollback&id='.$r['log_id']).'" onclick="ajaxRollback(\''.$r['log_id'].'\'); return false;"' - )) - . '

    '; - if ( $session->user_level >= USER_LEVEL_ADMIN ) - { - $standard_404 .= '

    ' . $lang->get('page_msg_404_admin_opts', array( - 'detag_link' => makeUrl($paths->page, 'do=detag', true) - )) - . '

    '; - } - } - $db->free_result(); - } - $standard_404 .= '

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

    '; - - $parser = $template->makeParserText($msg); - $parser->assign_vars(array( - 'STANDARD404' => $standard_404 - )); - - $msg = RenderMan::render($parser->run()); - eval( '?>' . $msg ); - - $this->footer(); - } - - /** - * Echoes out breadcrumb data, if appropriate. - * @access private - */ - - function do_breadcrumbs() - { - global $db, $session, $paths, $template, $plugins; // Common objects - global $lang; - - if ( strpos($this->text_cache, '__NOBREADCRUMBS__') !== false ) - return false; - - $mode = getConfig('breadcrumb_mode'); - - if ( $mode == 'never' ) - // Breadcrumbs are disabled - return true; - - // Minimum depth for breadcrumb display - $threshold = ( $mode == 'always' ) ? 0 : 1; - - $breadcrumb_data = explode('/', $this->page_id); - if ( count($breadcrumb_data) > $threshold ) - { - // If we're not on a subpage of the main page, add "Home" to the list - $show_home = false; - if ( $mode == 'always' ) - { - $show_home = true; - } - echo ' - - - '; - } - } - - /** * Send an error message and die. For debugging or critical technical errors only - nothing that would under normal circumstances be shown to the user. * @param string Error message * @param bool If true, send DBAL's debugging information as well diff -r 4629ad98ee88 -r 9cdfe82c56cd includes/pageutils.php --- a/includes/pageutils.php Sat Jan 03 17:54:26 2009 -0500 +++ b/includes/pageutils.php Sat Jan 03 18:11:18 2009 -0500 @@ -323,12 +323,13 @@ /** * Generates an HTML table with history information in it. - * @param $page_id the page ID - * @param $namespace the namespace + * @param string the page ID + * @param string the namespace + * @param string page password * @return string */ - public static function histlist($page_id, $namespace) + public static function histlist($page_id, $namespace, $password = false) { global $db, $session, $paths, $template, $plugins; // Common objects global $lang; @@ -339,6 +340,21 @@ ob_start(); $pname = $paths->nslist[$namespace] . $page_id; + + if ( !isPage($pname) ) + { + return 'DNE'; + } + + if ( isset($paths->pages[$pname]['password']) ) + { + $password_exists = ( !empty($paths->pages[$pname]['password']) && $paths->pages[$pname]['password'] !== sha1('') ); + if ( $password_exists && $password !== $paths->pages[$pname]['password'] ) + { + return '

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

    '; + } + } + $wiki = ( ( $paths->pages[$pname]['wiki_mode'] == 2 && getConfig('wiki_mode') == '1') || $paths->pages[$pname]['wiki_mode'] == 1) ? true : false; $prot = ( ( $paths->pages[$pname]['protected'] == 2 && $session->user_logged_in && $session->reg_time + 60*60*24*4 < time() ) || $paths->pages[$pname]['protected'] == 1) ? true : false; @@ -1491,7 +1507,7 @@ public static function setpass($page_id, $namespace, $pass) { global $db, $session, $paths, $template, $plugins; // Common objects - global $lang; + global $lang, $cache; // Determine permissions if($paths->pages[$paths->nslist[$namespace].$page_id]['password'] != '') $a = $session->get_permissions('password_reset'); @@ -1513,6 +1529,7 @@ { die('PageUtils::setpass(): Error during update query: '.$db->get_error()."\n\nSQL Backtrace:\n".$db->sql_backtrace()); } + $cache->purge('page_meta'); // Is the new password blank? if ( $p == '' ) { diff -r 4629ad98ee88 -r 9cdfe82c56cd includes/render.php --- a/includes/render.php Sat Jan 03 17:54:26 2009 -0500 +++ b/includes/render.php Sat Jan 03 18:11:18 2009 -0500 @@ -49,6 +49,11 @@ unset($perms); unset($perms); // PHP <5.1.5 Zend bug $perms = $session->fetch_page_acl($page_id, $namespace); + if ( !$perms ) + { + $session->init_permissions(); + $perms = $session->fetch_page_acl($page_id, $namespace); + }; } if(!$perms->get_permissions('read')) diff -r 4629ad98ee88 -r 9cdfe82c56cd language/english/core.json --- a/language/english/core.json Sat Jan 03 17:54:26 2009 -0500 +++ b/language/english/core.json Sat Jan 03 18:11:18 2009 -0500 @@ -151,9 +151,11 @@ msg_rb_success_delete: 'The deletion of this page, which occurred on %dateline%, has been undone. This page has been restored, but comments and categorization data may have been lost.', msg_rb_success_reupload: 'The file has been restored to the version uploaded on %dateline%.', + msg_passrequired_title: 'Password required', msg_passrequired: 'Access to this page requires a password. Please enter the password for this page below:', msg_pass_wrong: 'The password you entered for this page was incorrect. Please enter the password for this page below:', lbl_password: 'Password:', + btn_password_submit: 'Submit', msg_404_title: 'There is no page with this title yet.', msg_404_body: 'You have requested a page that doesn\'t exist yet.', @@ -408,7 +410,8 @@ log_delete: 'Deleted page', log_uploadnew: 'Uploaded new file version', lbl_comparingrevisions: 'Comparing revisions:', - summary_none_given: 'No edit summary provided.' + summary_none_given: 'No edit summary provided.', + err_wrong_password: 'Please enter the password for this page before viewing its history.' }, catedit: { title: 'Select which categories this page should be included in.',