diff -r de56132c008d -r bdac73ed481e includes/namespaces/default.php --- a/includes/namespaces/default.php Sun Mar 28 21:49:26 2010 -0400 +++ b/includes/namespaces/default.php Sun Mar 28 23:10:46 2010 -0400 @@ -21,1013 +21,1013 @@ 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 = ''; - - /** - * PathManager info array ("cdata") for this page. (The one with urlname, name, namespace, delvotes, delvote_ips, protected, visible, etc.) - * @var array - */ - - public $cdata = array(); - - /** - * ACL calculation instance for this page. - * @var object(Session_ACLPageInfo) - */ - - public $perms = false; - - /** - * Protection calculation - * @var bool - */ - - public $page_protected = false; - - /** - * Wiki mode calculation - * @var bool - */ - - public $wiki_mode = false; - - /** - * Page conditions. These represent the final decision as to whether an action is allowed or not. They are set to true if ACLs permit AND if - * the action "makes sense." (e.g., you can't vote to delete a non-wikimode page.) - * @var array - */ - - public $conds = array(); - - /** - * 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); - - // grab the cdata - $this->build_cdata(); - - $this->page_protected = $this->cdata['really_protected'] ? true : false; - switch($this->cdata['wiki_mode']) - { - case 0: $this->wiki_mode = false; break; - case 1: $this->wiki_mode = true; break; - default: case 2: $this->wiki_mode = getConfig('wiki_mode') == 1; break; - } - } - - /** - * Build the page's cdata. - */ - - public function build_cdata() - { - global $db, $session, $paths, $template, $plugins; // Common objects - static $cdata_cache = array(); - $pathskey = $paths->get_pathskey($this->page_id, $this->namespace); - if ( isset($cdata_cache[$pathskey]) ) - { - $this->cdata = $cdata_cache[$pathskey]; - $this->exists = $cdata_cache[$pathskey]['page_exists']; - $this->title = $cdata_cache[$pathskey]['name']; - return null; - } - - $this->exists = false; - $ns_char = substr($paths->nslist['Special'], -1); - $page_name = $this->namespace == 'Article' ? dirtify_page_id($this->page_id) : "{$this->namespace}{$ns_char}" . dirtify_page_id($this->page_id); - $page_name = str_replace('_', ' ', $page_name); - $this->title = $page_name; - - $this->cdata = array( - 'name' => $page_name, - 'urlname' => $this->page_id, - 'namespace' => $this->namespace, - 'special' => 0, - 'visible' => 0, - 'comments_on' => 1, - 'protected' => 0, - 'delvotes' => 0, - 'delvote_ips' => '', - 'wiki_mode' => 2, - 'page_exists' => false, - 'page_format' => getConfig('default_page_format', 'wikitext') - ); - - if ( $data_from_db = Namespace_Default::get_cdata_from_db($this->page_id, $this->namespace) ) - { - $this->exists = true; - $this->cdata = $data_from_db; - $this->cdata['page_exists'] = true; - $this->title = $this->cdata['name']; - } - - $this->cdata = Namespace_Default::bake_cdata($this->cdata); - - $cdata_cache[$pathskey] = $this->cdata; - } - - /** - * 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(); - } - } - } - - /** - * Get a redirect, if there is one. - * @return mixed Array: Page ID and namespace, associative; bool: false (no redirect) - */ - - public function get_redirect() - { - $text = $this->fetch_text(); - if ( preg_match('/^#redirect \[\[([^\]]+?)\]\]/i', $text, $match ) ) - { - list($page_id, $namespace) = RenderMan::strToPageID($match[1]); - return array( - 'page_id' => $page_id, - 'namespace' => $namespace - ); - } - return false; - } - - /** - * 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(); - - profiler_log("Namespace [$this->namespace, $this->page_id]: pulled text from DB"); - - $text = preg_replace('/([\s]*)__NOBREADCRUMBS__([\s]*)/', '', $text); - $text = preg_replace('/([\s]*)__NOTOC__([\s]*)/', '', $text); - $text = preg_replace('/^#redirect \[\[.+?\]\]\s*/i', '', $text); - - if ( $send_headers ) - { - $output->set_title($this->title); - $output->header(); - } - $this->do_breadcrumbs(); - - if ( $incl_inner_headers ) - { - if ( !$this->perms ) - $this->perms = $session->fetch_page_acl($this->page_id, $this->namespace); - - if ( $this->perms->get_permissions('vote_reset') && $this->cdata['delvotes'] > 0) - { - $delvote_ips = unserialize($this->cdata['delvote_ips']); - $hr = htmlspecialchars(implode(', ', $delvote_ips['u'])); - - $string_id = ( $this->cdata['delvotes'] == 1 ) ? 'delvote_lbl_votes_one' : 'delvote_lbl_votes_plural'; - $string = $lang->get($string_id, array('num_users' => $this->cdata['delvotes'])); - - echo '
' . $lang->get('page_msg_404_body_userpage'); - } - else - { - $standard_404 .= '
' . $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(ED_DATE | ED_TIME, $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 .= ''; - } - } - else - { - $html .= ' | ' . $lang->get('onpage_cat_msg_no_subcategories') . ' | '; - } - $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 .= " | "; - } - if ( !$switched ) - { - if ( $counter > 0 ) - { - // Fill-in - while ( $ticker < 2 ) - { - $ticker++; - $html .= ''; - } - } - else - { - $html .= ' | ' . $lang->get('onpage_cat_msg_no_subcategories') . ' | '; - } - $html .= '
'; - } - } - else - { - $html .= ' | ' . $lang->get('onpage_cat_msg_no_pages') . ' | '; - } - $html .= '
' . print_r($this->perms, true) . "\n---------------------------------\nBacktrace:\n" . enano_debug_print_backtrace(true)); - - $enforce_protection = ( $this->page_protected && ( ( $session->check_acl_scope('even_when_protected', $this->namespace) && !$this->perms->get_permissions('even_when_protected') ) || !$session->check_acl_scope('even_when_protected', $this->namespace) ) ); - - $conds = array(); - - // Article: always show - $conds['article'] = true; - - // Discussion: Show if comments are enabled on the site, and if comments are on for this page. - $conds['comments'] = $this->perms->get_permissions('read') && getConfig('enable_comments', '1')=='1' && $this->cdata['comments_on'] == 1; - - // Edit: Show if we have permission to edit the page, and if we don't have protection in effect - $conds['edit'] = $this->perms->get_permissions('read') && $session->check_acl_scope('edit_page', $this->namespace) && $this->perms->get_permissions('edit_page') && !$enforce_protection; - - // View source: Show if we have permission to view source and either ACLs prohibit editing or protection is in effect - $conds['viewsource'] = $session->check_acl_scope('view_source', $this->namespace) && $this->perms->get_permissions('view_source') && ( !$this->perms->get_permissions('edit_page') || $enforce_protection ) && $this->namespace != 'API'; - - // History: Show if we have permission to see history and if the page exists - $conds['history'] = $session->check_acl_scope('history_view', $this->namespace) && $this->exists && $this->perms->get_permissions('history_view'); - - // Rename: Show if the page exists, if we have permission to rename, and if protection isn't in effect - $conds['rename'] = $session->check_acl_scope('rename', $this->namespace) && $this->exists && $this->perms->get_permissions('rename') && !$enforce_protection; - - // Vote-to-delete: Show if we have Wiki Mode on, if we have permission to vote for deletion, and if the page exists (can't vote to delete a nonexistent page) - $conds['delvote'] = $this->wiki_mode && $session->check_acl_scope('vote_delete', $this->namespace) && $this->perms->get_permissions('vote_delete') && $this->exists; - - // Reset votes: Show if we have Wiki Mode on, if we have permission to reset votes, if the page exists, and if there's at least one vote - $conds['resetvotes'] = $session->check_acl_scope('vote_reset', $this->namespace) && $this->wiki_mode && $this->exists && $this->perms->get_permissions('vote_reset') && $this->cdata['delvotes'] > 0; - - // Delete page: Show if the page exists and if we have permission to delete it - $conds['delete'] = $session->check_acl_scope('delete_page', $this->namespace) && $this->exists && $this->perms->get_permissions('delete_page'); - - // Printable view: Show if the page exists - $conds['printable'] = $this->exists; - - // Protect: Show if we have Wiki Mode on, if the page exists, and if we have permission to protect the page. - $conds['protect'] = $session->check_acl_scope('protect', $this->namespace) && $this->wiki_mode && $this->exists && $this->perms->get_permissions('protect'); - - // Set Wiki Mode: Show if the page exists and if we have permission to set wiki mode - $conds['setwikimode'] = $session->check_acl_scope('set_wiki_mode', $this->namespace) && $this->exists && $this->perms->get_permissions('set_wiki_mode'); - - // Clear logs: Show if we have permission to clear logs - $conds['clearlogs'] = $session->check_acl_scope('clear_logs', $this->namespace) && $this->perms->get_permissions('clear_logs'); - - // Set password: a little bit complicated. If there's a password, check for password_reset; else, check for password_set. - $conds['password'] = empty($this->cdata['password']) ? - $session->check_acl_scope('password_set', $this->namespace) && $this->perms->get_permissions('password_set') : - $session->check_acl_scope('password_reset', $this->namespace) && $this->perms->get_permissions('password_reset'); - - // Edit ACLs: Show if this is a non-Enano page that's calling the Enano API and (a) if we have permissions to edit ACLs or (b) we're an admin AND ACL_ALWAYS_ALLOW_ADMIN_EDIT_ACL is on - $conds['acledit'] = $this->namespace != 'API' && $session->check_acl_scope('edit_acl', $this->namespace) && ( $this->perms->get_permissions('edit_acl') || ( defined('ACL_ALWAYS_ALLOW_ADMIN_EDIT_ACL') && $session->user_level >= USER_LEVEL_ADMIN ) ); - - // Admin page: Show if the page exists and if we're an admin - $conds['adminpage'] = $session->user_level >= USER_LEVEL_ADMIN && $this->exists; - - // Allow plugins to change stuff - $code = $plugins->setHook('page_conds_set'); - foreach ( $code as $cmd ) - { - eval($cmd); - } - - $this->conds = $conds; - } - - /** - * Return page conditions - * @return array - */ - - public function get_conds() - { - if ( empty($this->conds) ) - $this->set_conds(); - - return $this->conds; - } - - /** - * Just tell us if the current page exists or not. - * @return bool - */ - - public function exists() - { - return $this->exists; - } - - /** - * Return cdata - * @return array - */ - - public function get_cdata() - { - return $this->cdata; - } - - /** - * Bake, or finalize the processing of, a cdata array. - * @static - * @access public - */ - - public static function bake_cdata($cdata) - { - global $db, $session, $paths, $template, $plugins; // Common objects - - // urlname_nons is the actual page_id. - $cdata['urlname_nons'] = $cdata['urlname']; - if ( isset($paths->nslist[ $cdata['namespace'] ]) ) - { - $cdata['urlname'] = $paths->nslist[ $cdata['namespace'] ] . $cdata['urlname']; - } - else - { - $ns_char = substr($paths->nslist['Special'], -1); - $cdata['urlname'] = $cdata['namespace'] . $ns_char . $cdata['urlname']; - } - - // add missing keys - $defaults = array( - 'special' => 0, - 'visible' => 0, - 'comments_on' => 1, - 'protected' => 0, - 'delvotes' => 0, - 'delvote_ips' => serialize(array()), - 'wiki_mode' => 2, - 'page_format' => getConfig('default_page_format', 'wikitext') - ); - foreach ( $defaults as $key => $value ) - { - if ( !isset($cdata[$key]) ) - $cdata[$key] = $value; - } - - // fix up deletion votes - if ( empty($cdata['delvotes']) ) - $cdata['delvotes'] = 0; - - // fix up deletion vote IP list - if ( empty($cdata['delvote_ips']) ) - $cdata['delvote_ips'] = serialize(array()); - - // calculate wiki mode - $cdata['really_wiki_mode'] = ( $cdata['wiki_mode'] == 1 || ( $cdata['wiki_mode'] == 2 && getConfig('wiki_mode', 0) == 1 ) ); - - // calculate protection - $cdata['really_protected'] = ( $cdata['protected'] > 0 ); - if ( $cdata['protected'] == 2 ) - { - $cdata['really_protected'] = !$session->user_logged_in || ( $session->user_logged_in && $session->reg_time + 86400*4 > time() ); - } - - return $cdata; - } - - /** - * Grabs raw (unbaked) cdata from the database, caching if possible. - * @param string Page ID - * @param string Namespace. - * @static - */ - - public static function get_cdata_from_db($page_id, $namespace) - { - global $db, $session, $paths, $template, $plugins; // Common objects - static $cache = array(); - - $pathskey = $paths->get_pathskey($page_id, $namespace); - if ( isset($cache[$pathskey]) ) - return $cache[$pathskey]; - - $page_id_db = $db->escape($page_id); - $namespace_db = $db->escape($namespace); - - $q = $db->sql_query('SELECT p.*' - . ' FROM ' . table_prefix . "pages AS p\n" - . " WHERE p.urlname = '$page_id_db' AND p.namespace = '$namespace_db'\n" - . " GROUP BY p.urlname, p.name, p.namespace, p.page_order, p.special, p.visible, p.protected, p.wiki_mode, p.comments_on, p.delvotes, p.delvote_ips, p.page_format, p.password;"); - - if ( !$q ) - $db->_die(); - - if ( $db->numrows() < 1 ) - { - $db->free_result(); - $cache[$pathskey] = false; - return false; - } - - $row = $db->fetchrow(); - - // Get comment counts - // FIXME: Apparently there's a bit of recursion in here. Fetching permissions depends on this cdata function. - // Perhaps we should eliminate session's dependency on cdata? (What is it used for?) - $q = $db->sql_query('SELECT approved FROM ' . table_prefix . "comments WHERE page_id = '$page_id_db' AND namespace = '$namespace_db';"); - // yay parallel assignment - $row['comments_approved'] = $row['comments_unapproved'] = $row['comments_spam'] = 0; - while ( $commentrow = $db->fetchrow() ) - switch($commentrow['approved']) - { - case COMMENT_APPROVED: - default: - $row['comments_approved']++; - break; - case COMMENT_UNAPPROVED: - $row['comments_unapproved']++; - break; - case COMMENT_SPAM: - $row['comments_spam']++; - break; - } - - $cache[$pathskey] = $row; - return $row; - } + /** + * 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 = ''; + + /** + * PathManager info array ("cdata") for this page. (The one with urlname, name, namespace, delvotes, delvote_ips, protected, visible, etc.) + * @var array + */ + + public $cdata = array(); + + /** + * ACL calculation instance for this page. + * @var object(Session_ACLPageInfo) + */ + + public $perms = false; + + /** + * Protection calculation + * @var bool + */ + + public $page_protected = false; + + /** + * Wiki mode calculation + * @var bool + */ + + public $wiki_mode = false; + + /** + * Page conditions. These represent the final decision as to whether an action is allowed or not. They are set to true if ACLs permit AND if + * the action "makes sense." (e.g., you can't vote to delete a non-wikimode page.) + * @var array + */ + + public $conds = array(); + + /** + * 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); + + // grab the cdata + $this->build_cdata(); + + $this->page_protected = $this->cdata['really_protected'] ? true : false; + switch($this->cdata['wiki_mode']) + { + case 0: $this->wiki_mode = false; break; + case 1: $this->wiki_mode = true; break; + default: case 2: $this->wiki_mode = getConfig('wiki_mode') == 1; break; + } + } + + /** + * Build the page's cdata. + */ + + public function build_cdata() + { + global $db, $session, $paths, $template, $plugins; // Common objects + static $cdata_cache = array(); + $pathskey = $paths->get_pathskey($this->page_id, $this->namespace); + if ( isset($cdata_cache[$pathskey]) ) + { + $this->cdata = $cdata_cache[$pathskey]; + $this->exists = $cdata_cache[$pathskey]['page_exists']; + $this->title = $cdata_cache[$pathskey]['name']; + return null; + } + + $this->exists = false; + $ns_char = substr($paths->nslist['Special'], -1); + $page_name = $this->namespace == 'Article' ? dirtify_page_id($this->page_id) : "{$this->namespace}{$ns_char}" . dirtify_page_id($this->page_id); + $page_name = str_replace('_', ' ', $page_name); + $this->title = $page_name; + + $this->cdata = array( + 'name' => $page_name, + 'urlname' => $this->page_id, + 'namespace' => $this->namespace, + 'special' => 0, + 'visible' => 0, + 'comments_on' => 1, + 'protected' => 0, + 'delvotes' => 0, + 'delvote_ips' => '', + 'wiki_mode' => 2, + 'page_exists' => false, + 'page_format' => getConfig('default_page_format', 'wikitext') + ); + + if ( $data_from_db = Namespace_Default::get_cdata_from_db($this->page_id, $this->namespace) ) + { + $this->exists = true; + $this->cdata = $data_from_db; + $this->cdata['page_exists'] = true; + $this->title = $this->cdata['name']; + } + + $this->cdata = Namespace_Default::bake_cdata($this->cdata); + + $cdata_cache[$pathskey] = $this->cdata; + } + + /** + * 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(); + } + } + } + + /** + * Get a redirect, if there is one. + * @return mixed Array: Page ID and namespace, associative; bool: false (no redirect) + */ + + public function get_redirect() + { + $text = $this->fetch_text(); + if ( preg_match('/^#redirect \[\[([^\]]+?)\]\]/i', $text, $match ) ) + { + list($page_id, $namespace) = RenderMan::strToPageID($match[1]); + return array( + 'page_id' => $page_id, + 'namespace' => $namespace + ); + } + return false; + } + + /** + * 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(); + + profiler_log("Namespace [$this->namespace, $this->page_id]: pulled text from DB"); + + $text = preg_replace('/([\s]*)__NOBREADCRUMBS__([\s]*)/', '', $text); + $text = preg_replace('/([\s]*)__NOTOC__([\s]*)/', '', $text); + $text = preg_replace('/^#redirect \[\[.+?\]\]\s*/i', '', $text); + + if ( $send_headers ) + { + $output->set_title($this->title); + $output->header(); + } + $this->do_breadcrumbs(); + + if ( $incl_inner_headers ) + { + if ( !$this->perms ) + $this->perms = $session->fetch_page_acl($this->page_id, $this->namespace); + + if ( $this->perms->get_permissions('vote_reset') && $this->cdata['delvotes'] > 0) + { + $delvote_ips = unserialize($this->cdata['delvote_ips']); + $hr = htmlspecialchars(implode(', ', $delvote_ips['u'])); + + $string_id = ( $this->cdata['delvotes'] == 1 ) ? 'delvote_lbl_votes_one' : 'delvote_lbl_votes_plural'; + $string = $lang->get($string_id, array('num_users' => $this->cdata['delvotes'])); + + echo '+ ' . $lang->get('etc_lbl_notice') . ' ' . $string . ''; + } + } + + if ( $this->revision_id ) + { + echo '
+ ' . $lang->get('delvote_lbl_users_that_voted') . ' ' . $hr . '
+ ' . $lang->get('delvote_btn_deletepage') . ' | ' . $lang->get('delvote_btn_resetvotes') . ' ++ ' . $lang->get('page_msg_archived_title') . ''; + $q = $db->sql_query('SELECT page_format FROM ' . table_prefix . "logs WHERE log_id = {$this->revision_id};"); + if ( !$q ) + $db->_die(); + + list($page_format) = $db->fetchrow_num(); + $db->free_result(); + } + else + { + $page_format = $this->cdata['page_format']; + } + + $code = $plugins->setHook('pageprocess_render_head'); + foreach ( $code as $cmd ) + { + eval($cmd); + } + + $prof_contentevent = profiler_log("Namespace [$this->namespace, $this->page_id]: headers and preprocessing done - about to send content"); + + if ( $incl_inner_headers ) + { + if ( $page_format === 'wikitext' ) + { + $text = '?>' . RenderMan::render($text); + } + else + { + // Page format is XHTML. This means we want to disable functionality that MCE takes care of, while still retaining + // the ability to wikilink, the ability to use images, etc. Basically, RENDER_INLINEONLY disables all behavior in + // the rendering engine/Text_Wiki that conflicts with MCE. + $text = '?>' . RenderMan::render($text, RENDER_INLINE); + } + } + else + { + $text = '?>' . $text; + $text = preg_replace('/
+ ' . $lang->get('page_msg_archived_body', array( + 'archive_date' => enano_date(ED_DATE, $this->revision_time), + 'archive_time' => enano_date(ED_TIME, $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;', + )) . ' +(.*?)<\/nowiki>/s', '\\1', $text); + } + + eval ( $text ); + + profiler_log("Namespace [$this->namespace, $this->page_id]: content sent", true, $prof_contentevent); + + $code = $plugins->setHook('pageprocess_render_tail'); + foreach ( $code as $cmd ) + { + eval($cmd); + } + + if ( $incl_inner_headers ) + { + display_page_footers(); + } + + profiler_log("Namespace [$this->namespace, $this->page_id]: sent 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() + { + global $db, $session, $paths, $template, $plugins; // Common objects + global $lang, $output; + + $userpage = $this->namespace == 'User'; + + @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(ED_DATE | ED_TIME, $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 .= '' . "\n\n"; + $html .= ''; + $html .= '
'; + $ticker = 0; + $counter = 0; + $switched = false; + $class = 'row1'; + while ( $row = $db->fetchrow($q) ) + { + if ( $row['is_category'] == 0 && !$switched ) + { + if ( $counter > 0 ) + { + // Fill-in + while ( $ticker < 3 ) + { + $ticker++; + $html .= ' '; + } + } + else + { + $html .= ' ' . $lang->get('onpage_cat_msg_no_subcategories') . ' '; + } + $html .= '' . $lang->get('onpage_cat_heading_pages') . '
'; + $html .= ''; + $html .= '' . "\n\n"; + $html .= ''; + $html .= '
'; + $counter = 0; + $ticker = -1; + $switched = true; + } + $counter++; + $ticker++; + if ( $ticker == 3 ) + { + $html .= ' '; + $ticker = 0; + $class = ( $class == 'row3' ) ? 'row1' : 'row3'; + } + $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 .= " "; + } + if ( !$switched ) + { + if ( $counter > 0 ) + { + // Fill-in + while ( $ticker < 2 ) + { + $ticker++; + $html .= ''; + } + } + else + { + $html .= ' ' . $lang->get('onpage_cat_msg_no_subcategories') . ' '; + } + $html .= '' . $lang->get('onpage_cat_heading_pages') . '
'; + $html .= ''; + $html .= '' . "\n\n"; + } + + if ( $this->namespace != 'Special' && $this->namespace != 'Admin' ) + { + $html .= ''; + $html .= '
'; + $counter = 0; + $ticker = 0; + $switched = true; + } + if ( $counter > 0 ) + { + // Fill-in + while ( $ticker < 2 ) + { + $ticker++; + $html .= ' '; + } + } + else + { + $html .= ' ' . $lang->get('onpage_cat_msg_no_pages') . ' '; + } + $html .= ''; + $html .= ''; + } + return $html; + } + + /** + * Pull in switches as to whether a specific toolbar button should be used or not. This sets things up according to the current page being displayed. + * @return array Associative + */ + + function set_conds() + { + global $db, $session, $paths, $template, $plugins; // Common objects + + if ( !$this->perms ) + $this->perms = $session->fetch_page_acl($this->page_id, $this->namespace); + + if ( !$this->perms ) + { + // We're trying to send a page WAY too early (session hasn't been started yet), such as for a redirect. Send a default set of conds because + // there's NO way to get permissions to determine anything otherwise. Yes, starting $session here might be dangerous. + $this->conds = array( + 'article' => true, + 'comments' => false, + 'edit' => false, + 'viewsource' => false, + 'history' => false, + 'rename' => false, + 'delvote' => false, + 'resetvotes' => false, + 'delete' => false, + 'printable' => false, + 'protect' => false, + 'setwikimode' => false, + 'clearlogs' => false, + 'password' => false, + 'acledit' => false, + 'adminpage' => false + ); + return $this->conds; + } + + // die('have perms:'; + $html .= '(' . $lang->get('tags_catbox_link') . ')'; + $html .= ''; + $html .= '' . $lang->get('catedit_catbox_lbl_categories') . ' '; + + $q = $db->sql_query('SELECT category_id FROM ' . table_prefix . "categories WHERE page_id = '$this->page_id' AND namespace = '$this->namespace';"); + 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($q) ); + $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 .= '' . print_r($this->perms, true) . "\n---------------------------------\nBacktrace:\n" . enano_debug_print_backtrace(true)); + + $enforce_protection = ( $this->page_protected && ( ( $session->check_acl_scope('even_when_protected', $this->namespace) && !$this->perms->get_permissions('even_when_protected') ) || !$session->check_acl_scope('even_when_protected', $this->namespace) ) ); + + $conds = array(); + + // Article: always show + $conds['article'] = true; + + // Discussion: Show if comments are enabled on the site, and if comments are on for this page. + $conds['comments'] = $this->perms->get_permissions('read') && getConfig('enable_comments', '1')=='1' && $this->cdata['comments_on'] == 1; + + // Edit: Show if we have permission to edit the page, and if we don't have protection in effect + $conds['edit'] = $this->perms->get_permissions('read') && $session->check_acl_scope('edit_page', $this->namespace) && $this->perms->get_permissions('edit_page') && !$enforce_protection; + + // View source: Show if we have permission to view source and either ACLs prohibit editing or protection is in effect + $conds['viewsource'] = $session->check_acl_scope('view_source', $this->namespace) && $this->perms->get_permissions('view_source') && ( !$this->perms->get_permissions('edit_page') || $enforce_protection ) && $this->namespace != 'API'; + + // History: Show if we have permission to see history and if the page exists + $conds['history'] = $session->check_acl_scope('history_view', $this->namespace) && $this->exists && $this->perms->get_permissions('history_view'); + + // Rename: Show if the page exists, if we have permission to rename, and if protection isn't in effect + $conds['rename'] = $session->check_acl_scope('rename', $this->namespace) && $this->exists && $this->perms->get_permissions('rename') && !$enforce_protection; + + // Vote-to-delete: Show if we have Wiki Mode on, if we have permission to vote for deletion, and if the page exists (can't vote to delete a nonexistent page) + $conds['delvote'] = $this->wiki_mode && $session->check_acl_scope('vote_delete', $this->namespace) && $this->perms->get_permissions('vote_delete') && $this->exists; + + // Reset votes: Show if we have Wiki Mode on, if we have permission to reset votes, if the page exists, and if there's at least one vote + $conds['resetvotes'] = $session->check_acl_scope('vote_reset', $this->namespace) && $this->wiki_mode && $this->exists && $this->perms->get_permissions('vote_reset') && $this->cdata['delvotes'] > 0; + + // Delete page: Show if the page exists and if we have permission to delete it + $conds['delete'] = $session->check_acl_scope('delete_page', $this->namespace) && $this->exists && $this->perms->get_permissions('delete_page'); + + // Printable view: Show if the page exists + $conds['printable'] = $this->exists; + + // Protect: Show if we have Wiki Mode on, if the page exists, and if we have permission to protect the page. + $conds['protect'] = $session->check_acl_scope('protect', $this->namespace) && $this->wiki_mode && $this->exists && $this->perms->get_permissions('protect'); + + // Set Wiki Mode: Show if the page exists and if we have permission to set wiki mode + $conds['setwikimode'] = $session->check_acl_scope('set_wiki_mode', $this->namespace) && $this->exists && $this->perms->get_permissions('set_wiki_mode'); + + // Clear logs: Show if we have permission to clear logs + $conds['clearlogs'] = $session->check_acl_scope('clear_logs', $this->namespace) && $this->perms->get_permissions('clear_logs'); + + // Set password: a little bit complicated. If there's a password, check for password_reset; else, check for password_set. + $conds['password'] = empty($this->cdata['password']) ? + $session->check_acl_scope('password_set', $this->namespace) && $this->perms->get_permissions('password_set') : + $session->check_acl_scope('password_reset', $this->namespace) && $this->perms->get_permissions('password_reset'); + + // Edit ACLs: Show if this is a non-Enano page that's calling the Enano API and (a) if we have permissions to edit ACLs or (b) we're an admin AND ACL_ALWAYS_ALLOW_ADMIN_EDIT_ACL is on + $conds['acledit'] = $this->namespace != 'API' && $session->check_acl_scope('edit_acl', $this->namespace) && ( $this->perms->get_permissions('edit_acl') || ( defined('ACL_ALWAYS_ALLOW_ADMIN_EDIT_ACL') && $session->user_level >= USER_LEVEL_ADMIN ) ); + + // Admin page: Show if the page exists and if we're an admin + $conds['adminpage'] = $session->user_level >= USER_LEVEL_ADMIN && $this->exists; + + // Allow plugins to change stuff + $code = $plugins->setHook('page_conds_set'); + foreach ( $code as $cmd ) + { + eval($cmd); + } + + $this->conds = $conds; + } + + /** + * Return page conditions + * @return array + */ + + public function get_conds() + { + if ( empty($this->conds) ) + $this->set_conds(); + + return $this->conds; + } + + /** + * Just tell us if the current page exists or not. + * @return bool + */ + + public function exists() + { + return $this->exists; + } + + /** + * Return cdata + * @return array + */ + + public function get_cdata() + { + return $this->cdata; + } + + /** + * Bake, or finalize the processing of, a cdata array. + * @static + * @access public + */ + + public static function bake_cdata($cdata) + { + global $db, $session, $paths, $template, $plugins; // Common objects + + // urlname_nons is the actual page_id. + $cdata['urlname_nons'] = $cdata['urlname']; + if ( isset($paths->nslist[ $cdata['namespace'] ]) ) + { + $cdata['urlname'] = $paths->nslist[ $cdata['namespace'] ] . $cdata['urlname']; + } + else + { + $ns_char = substr($paths->nslist['Special'], -1); + $cdata['urlname'] = $cdata['namespace'] . $ns_char . $cdata['urlname']; + } + + // add missing keys + $defaults = array( + 'special' => 0, + 'visible' => 0, + 'comments_on' => 1, + 'protected' => 0, + 'delvotes' => 0, + 'delvote_ips' => serialize(array()), + 'wiki_mode' => 2, + 'page_format' => getConfig('default_page_format', 'wikitext') + ); + foreach ( $defaults as $key => $value ) + { + if ( !isset($cdata[$key]) ) + $cdata[$key] = $value; + } + + // fix up deletion votes + if ( empty($cdata['delvotes']) ) + $cdata['delvotes'] = 0; + + // fix up deletion vote IP list + if ( empty($cdata['delvote_ips']) ) + $cdata['delvote_ips'] = serialize(array()); + + // calculate wiki mode + $cdata['really_wiki_mode'] = ( $cdata['wiki_mode'] == 1 || ( $cdata['wiki_mode'] == 2 && getConfig('wiki_mode', 0) == 1 ) ); + + // calculate protection + $cdata['really_protected'] = ( $cdata['protected'] > 0 ); + if ( $cdata['protected'] == 2 ) + { + $cdata['really_protected'] = !$session->user_logged_in || ( $session->user_logged_in && $session->reg_time + 86400*4 > time() ); + } + + return $cdata; + } + + /** + * Grabs raw (unbaked) cdata from the database, caching if possible. + * @param string Page ID + * @param string Namespace. + * @static + */ + + public static function get_cdata_from_db($page_id, $namespace) + { + global $db, $session, $paths, $template, $plugins; // Common objects + static $cache = array(); + + $pathskey = $paths->get_pathskey($page_id, $namespace); + if ( isset($cache[$pathskey]) ) + return $cache[$pathskey]; + + $page_id_db = $db->escape($page_id); + $namespace_db = $db->escape($namespace); + + $q = $db->sql_query('SELECT p.*' + . ' FROM ' . table_prefix . "pages AS p\n" + . " WHERE p.urlname = '$page_id_db' AND p.namespace = '$namespace_db'\n" + . " GROUP BY p.urlname, p.name, p.namespace, p.page_order, p.special, p.visible, p.protected, p.wiki_mode, p.comments_on, p.delvotes, p.delvote_ips, p.page_format, p.password;"); + + if ( !$q ) + $db->_die(); + + if ( $db->numrows() < 1 ) + { + $db->free_result(); + $cache[$pathskey] = false; + return false; + } + + $row = $db->fetchrow(); + + // Get comment counts + // FIXME: Apparently there's a bit of recursion in here. Fetching permissions depends on this cdata function. + // Perhaps we should eliminate session's dependency on cdata? (What is it used for?) + $q = $db->sql_query('SELECT approved FROM ' . table_prefix . "comments WHERE page_id = '$page_id_db' AND namespace = '$namespace_db';"); + // yay parallel assignment + $row['comments_approved'] = $row['comments_unapproved'] = $row['comments_spam'] = 0; + while ( $commentrow = $db->fetchrow() ) + switch($commentrow['approved']) + { + case COMMENT_APPROVED: + default: + $row['comments_approved']++; + break; + case COMMENT_UNAPPROVED: + $row['comments_unapproved']++; + break; + case COMMENT_SPAM: + $row['comments_spam']++; + break; + } + + $cache[$pathskey] = $row; + return $row; + } } /**