diff -r de56132c008d -r bdac73ed481e includes/pageutils.php --- a/includes/pageutils.php Sun Mar 28 21:49:26 2010 -0400 +++ b/includes/pageutils.php Sun Mar 28 23:10:46 2010 -0400 @@ -13,2446 +13,2446 @@ */ class PageUtils { - - /** - * Tell if a username is used or not. - * @param $name the name to check for - * @return string - */ - - public static function checkusername($name) - { - global $db, $session, $paths, $template, $plugins; // Common objects - $name = str_replace('_', ' ', $name); - $q = $db->sql_query('SELECT username FROM ' . table_prefix.'users WHERE username=\'' . $db->escape(rawurldecode($name)) . '\''); - if ( !$q ) - { - die($db->get_error()); - } - if ( $db->numrows() < 1) - { - $db->free_result(); return('good'); - } - else - { - $db->free_result(); return('bad'); - } - } - - /** - * Get the wiki formatting source for a page - * @param $page the full page id (Namespace:Pagename) - * @return string - * @todo (DONE) Make it require a password (just for security purposes) - */ - - public static function getsource($page, $password = false) - { - global $db, $session, $paths, $template, $plugins; // Common objects - if ( !isPage($page) ) - { - return ''; - } - - list($page_id, $namespace) = RenderMan::strToPageID($page); - $ns = namespace_factory($page_id, $namespace); - $cdata = $ns->get_cdata(); - - if ( strlen($cdata['password']) == 40 ) - { - if(!$password || ( $password != $cdata['password'])) - { - return 'invalid_password'; - } - } - - if(!$session->get_permissions('view_source')) // Dependencies handle this for us - this also checks for read privileges - return 'access_denied'; - $pid = RenderMan::strToPageID($page); - if($pid[1] == 'Special' || $pid[1] == 'Admin') - { - die('This type of page (' . $paths->nslist[$pid[1]] . ') cannot be edited because the page source code is not stored in the database.'); - } - - $e = $db->sql_query('SELECT page_text,char_tag FROM ' . table_prefix.'page_text WHERE page_id=\'' . $pid[0] . '\' AND namespace=\'' . $pid[1] . '\''); - if ( !$e ) - { - $db->_die('The page text could not be selected.'); - } - if( $db->numrows() < 1 ) - { - return ''; //$db->_die('There were no rows in the text table that matched the page text query.'); - } - - $r = $db->fetchrow(); - $db->free_result(); - $message = $r['page_text']; - - return htmlspecialchars($message); - } - - /** - * DEPRECATED. Previously returned the full rendered contents of a page. - * @param $page the full page id (Namespace:Pagename) - * @param $send_headers true if the theme headers should be sent (still dependent on current page settings), false otherwise - * @return string - */ - - public static function getpage($page, $send_headers = false, $hist_id = false) - { - die('PageUtils->getpage is deprecated.'); - } - - /** - * Writes page data to the database, after verifying permissions and running the XSS filter - * @param $page_id the page ID - * @param $namespace the namespace - * @param $message the text to save - * @return string - */ - - public static function savepage($page_id, $namespace, $message, $summary = 'No edit summary given', $minor = false) - { - global $db, $session, $paths, $template, $plugins; // Common objects - - $page = new PageProcessor($page_id, $namespace); - $cdata = $page->ns->get_cdata(); - return $page->update_page($message, $summary, $minor, $cdata['page_format']); - } - - /** - * Creates a page, both in memory and in the database. - * @param string $page_id - * @param string $namespace - * @return bool true on success, false on failure - */ - - public static function createPage($page_id, $namespace, $name = false, $visible = 1) - { - global $db, $session, $paths, $template, $plugins; // Common objects - if(in_array($namespace, Array('Special', 'Admin'))) - { - // echo 'Notice: PageUtils::createPage: You can\'t create a special page in the database
'; - return 'You can\'t create a special page in the database'; - } - - if(!isset($paths->nslist[$namespace])) - { - // echo 'Notice: PageUtils::createPage: Couldn\'t look up the namespace
'; - return 'Couldn\'t look up the namespace'; - } - - $pname = $paths->nslist[$namespace] . $page_id; - if(isPage($pname)) - { - // echo 'Notice: PageUtils::createPage: Page already exists
'; - return 'Page already exists'; - } - - if(!$session->get_permissions('create_page')) - { - // echo 'Notice: PageUtils::createPage: Not authorized to create pages
'; - return 'Not authorized to create pages'; - } - - if($session->user_level < USER_LEVEL_ADMIN && $namespace == 'System') - { - // echo 'Notice: PageUtils::createPage: Not authorized to create system messages
'; - return 'Not authorized to create system messages'; - } - - if ( substr($page_id, 0, 8) == 'Project:' ) - { - // echo 'Notice: PageUtils::createPage: Prefix "Project:" is reserved
'; - return 'The prefix "Project:" is reserved for a parser shortcut; if a page was created using this prefix, it would not be possible to link to it.'; - } - - /* - // Dunno why this was here. Enano can handle more flexible names than this... - $regex = '#^([A-z0-9 _\-\.\/\!\@\(\)]*)$#is'; - if(!preg_match($regex, $name)) - { - //echo 'Notice: PageUtils::createPage: Name contains invalid characters
'; - return 'Name contains invalid characters'; - } - */ - - $page_id = dirtify_page_id($page_id); - - if ( !$name ) - $name = str_replace('_', ' ', $page_id); - - $page_id = sanitize_page_id( $page_id ); - - $prot = ( $namespace == 'System' ) ? 1 : 0; - - $ips = array( - 'ip' => array(), - 'u' => array() - ); - - $page_data = Array( - 'name'=>$name, - 'urlname'=>$page_id, - 'namespace'=>$namespace, - 'special'=>0,'visible'=>1,'comments_on'=>0,'protected'=>$prot,'delvotes'=>0,'delvote_ips'=>serialize($ips),'wiki_mode'=>2, - ); - - // die('PageUtils::createpage: Creating page with this data:
' . print_r($page_data, true) . '
'); - - $paths->add_page($page_data); - - $qa = $db->sql_query('INSERT INTO ' . table_prefix.'pages(name,urlname,namespace,visible,protected,delvote_ips) VALUES(\'' . $db->escape($name) . '\', \'' . $db->escape($page_id) . '\', \'' . $namespace . '\', '. ( $visible ? '1' : '0' ) .', ' . $prot . ', \'' . $db->escape(serialize($ips)) . '\');'); - $qb = $db->sql_query('INSERT INTO ' . table_prefix.'page_text(page_id,namespace) VALUES(\'' . $db->escape($page_id) . '\', \'' . $namespace . '\');'); - $qc = $db->sql_query('INSERT INTO ' . table_prefix.'logs(time_id,date_string,log_type,action,author,author_uid,page_id,namespace) VALUES('.time().', \'DEPRECATED\', \'page\', \'create\', \'' . $session->username . '\', ' . $session->user_id . ', \'' . $db->escape($page_id) . '\', \'' . $namespace . '\');'); - - if($qa && $qb && $qc) - return 'good'; - else - { - return $db->get_error(); - } - } - - /** - * Sets the protection level on a page. - * @param $page_id string the page ID - * @param $namespace string the namespace - * @param $level int level of protection - 0 is off, 1 is full, 2 is semi - * @param $reason string why the page is being (un)protected - * @return string - "good" on success, in all other cases, an error string (on query failure, calls $db->_die() ) - */ - public static function protect($page_id, $namespace, $level, $reason) - { - global $db, $session, $paths, $template, $plugins; // Common objects - - $page = new PageProcessor($page_id, $namespace); - return $page->protect_page($level, $reason); - } - - /** - * Generates an HTML table with history information in it. - * @param string the page ID - * @param string the namespace - * @param string page password - * @return string - */ - - public static function histlist($page_id, $namespace, $password = false) - { - global $db, $session, $paths, $template, $plugins; // Common objects - global $lang; - - if(!$session->get_permissions('history_view')) - return 'Access denied'; - - ob_start(); - - $pname = $paths->get_pathskey($page_id, $namespace); - $ns = namespace_factory($page_id, $namespace); - $cdata = $ns->get_cdata(); - - if ( !isPage($pname) ) - { - return 'DNE'; - } - - if ( isPage($pname) ) - { - $password_exists = ( !empty($cdata['password']) && $cdata['password'] !== sha1('') ); - if ( $password_exists && $password !== $cdata['password'] ) - { - return '

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

'; - } - } - - $wiki = ( ( $cdata['wiki_mode'] == 2 && getConfig('wiki_mode') == '1') || $cdata['wiki_mode'] == 1) ? true : false; - $prot = ( ( $cdata['protected'] == 2 && $session->user_logged_in && $session->reg_time + 60*60*24*4 < time() ) || $cdata['protected'] == 1) ? true : false; - - $q = 'SELECT log_id,time_id,date_string,page_id,namespace,author,author_uid,u.username,edit_summary,minor_edit FROM ' . table_prefix . "logs AS l\n" - . " LEFT JOIN " . table_prefix . "users AS u\n" - . " ON ( u.user_id = l.author_uid OR u.user_id IS NULL )\n" - . " WHERE log_type='page' AND action='edit' AND page_id='$page_id' AND namespace='$namespace' AND is_draft != 1 ORDER BY time_id DESC;"; - - if ( !($q = $db->sql_query($q)) ) - $db->_die('The history data for the page "' . $paths->cpage['name'] . '" could not be selected.'); - - echo $lang->get('history_page_subtitle') . ' -

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

'; - $numrows = $db->numrows(); - if ( $numrows < 1 ) - { - echo $lang->get('history_no_entries'); - } - else - { - echo '
- - ' . ( urlSeparator == '&' ? '' : '' ) . ' - ' . ( $session->sid_super ? '' : '') . ' - -
  -
- - - - - - - - - '."\n"."\n"; - $cls = 'row2'; - $ticker = 0; - - while ( $r = $db->fetchrow($q) ) - { - - $ticker++; - - if($cls == 'row2') $cls = 'row1'; - else $cls = 'row2'; - - echo ''."\n"; - - // Diff selection - if($ticker == 1) - { - $s1 = ''; - $s2 = 'checked="checked" '; - } - elseif($ticker == 2) - { - $s1 = 'checked="checked" '; - $s2 = ''; - } - else - { - $s1 = ''; - $s2 = ''; - } - if($ticker > 1) echo ''."\n"; else echo ''; - if($ticker < $numrows) echo ''."\n"; else echo ''; - - // Date and time - echo ''."\n"; - - // User - $real_username = $r['author_uid'] > 1 && !empty($r['username']) ? $r['username'] : $r['author']; - $rank_info = $session->get_user_rank($r['author_uid']); - if ( $session->get_permissions('mod_misc') && is_valid_ip($r['author']) && $r['author_uid'] == 1 ) - { - $rc = ' style="cursor: pointer;" title="' . $lang->get('history_tip_rdns') . '" onclick="ajaxReverseDNS(this, \'' . $r['author'] . '\');"'; - } - else - { - $rc = ''; - } - echo ''."\n"; - - // Edit summary - if ( $r['edit_summary'] == 'Automatic backup created when logs were purged' ) - { - $r['edit_summary'] = $lang->get('history_summary_clearlogs'); - } - echo ''."\n"; - - // Minor edit - echo ''."\n"; - - // Actions! - echo ''."\n"; - echo ''."\n"; - echo ''."\n"; - - echo ''."\n"."\n"; - - } - echo '
' . $lang->get('history_col_diff') . '' . $lang->get('history_col_datetime') . '' . $lang->get('history_col_user') . '' . $lang->get('history_col_summary') . '' . $lang->get('history_col_minor') . '' . $lang->get('history_col_actions') . '
' . enano_date(ED_DATE | ED_TIME, intval($r['time_id'])) . 'nslist['User'] . sanitize_page_id($real_username)) ) - { - echo 'class="wikilink-nonexistent"'; - } - echo 'style="' . $rank_info['rank_style'] . '">' . htmlspecialchars($real_username) . '' . $r['edit_summary'] . ''. (( $r['minor_edit'] ) ? 'M' : '' ) .'' . $lang->get('history_action_view') . '' . $lang->get('history_action_contrib') . '' . $lang->get('history_action_restore') . '
-
-
- - -
- '; - } - $db->free_result(); - echo '

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

'; - - $sql = 'SELECT log_id,action,time_id,date_string,page_id,namespace,author,author_uid,u.username,edit_summary,minor_edit FROM ' . table_prefix . "logs AS l\n" - . " LEFT JOIN " . table_prefix . "users AS u\n" - . " ON ( u.user_id = l.author_uid OR u.user_id IS NULL )\n" - . " WHERE log_type='page' AND action!='edit' AND page_id='$page_id' AND namespace='$namespace' AND is_draft != 1 ORDER BY time_id DESC;"; - - if ( !( $q = $db->sql_query($sql)) ) - { - $db->_die('The history data for the page "' . htmlspecialchars($paths->cpage['name']) . '" could not be selected.'); - } - if ( $db->numrows() < 1 ) - { - echo $lang->get('history_no_entries'); - } - else - { - - echo '
- - - - - - - - '; - $cls = 'row2'; - while($r = $db->fetchrow($q)) { - - if($cls == 'row2') $cls = 'row1'; - else $cls = 'row2'; - - echo ''; - - // Date and time - echo ''; - - // User - $real_username = $r['author_uid'] > 1 && !empty($r['username']) ? $r['username'] : $r['author']; - $rank_info = $session->get_user_rank($r['author_uid']); - if ( $session->get_permissions('mod_misc') && is_valid_ip($r['author']) && $r['author_uid'] == 1 ) - { - $rc = ' style="cursor: pointer;" title="' . $lang->get('history_tip_rdns') . '" onclick="ajaxReverseDNS(this, \'' . $r['author'] . '\');"'; - } - else - { - $rc = ''; - } - echo ''."\n"; - - - // Minor edit - echo ''; - - // Action taken - echo ''; - - // Actions! - echo ''; - echo ''; - - echo ''; - } - echo '
' . $lang->get('history_col_datetime') . '' . $lang->get('history_col_user') . '' . $lang->get('history_col_minor') . '' . $lang->get('history_col_action_taken') . '' . $lang->get('history_col_extra') . '
' . enano_date(ED_DATE | ED_TIME, intval($r['time_id'])) . 'nslist['User'] . sanitize_page_id($real_username)) ) - { - echo 'class="wikilink-nonexistent"'; - } - echo 'style="' . $rank_info['rank_style'] . '">' . htmlspecialchars($real_username) . ''. (( $r['minor_edit'] ) ? 'M' : '' ) .''; - // Some of these are sanitized at insert-time. Others follow the newer Enano policy of stripping HTML at runtime. - if ($r['action']=='prot') echo $lang->get('history_log_protect') . '' . $lang->get('history_extra_reason') . ' ' . ( $r['edit_summary'] === '__REVERSION__' ? $lang->get('history_extra_protection_reversion') : htmlspecialchars($r['edit_summary']) ); - elseif($r['action']=='unprot') echo $lang->get('history_log_unprotect') . '' . $lang->get('history_extra_reason') . ' ' . ( $r['edit_summary'] === '__REVERSION__' ? $lang->get('history_extra_protection_reversion') : htmlspecialchars($r['edit_summary']) ); - elseif($r['action']=='semiprot') echo $lang->get('history_log_semiprotect') . '' . $lang->get('history_extra_reason') . ' ' . ( $r['edit_summary'] === '__REVERSION__' ? $lang->get('history_extra_protection_reversion') : htmlspecialchars($r['edit_summary']) ); - elseif($r['action']=='rename') echo $lang->get('history_log_rename') . '' . $lang->get('history_extra_oldtitle') . ' '.htmlspecialchars($r['edit_summary']); - elseif($r['action']=='create') echo $lang->get('history_log_create') . ''; - elseif($r['action']=='delete') echo $lang->get('history_log_delete') . '' . $lang->get('history_extra_reason') . ' ' . $r['edit_summary']; - elseif($r['action']=='reupload') echo $lang->get('history_log_uploadnew') . '' . $lang->get('history_extra_reason') . ' ' . ( $r['edit_summary'] === '__ROLLBACK__' ? $lang->get('history_extra_upload_reversion') : htmlspecialchars($r['edit_summary']) ); - elseif($r['action']=='votereset')echo $lang->get('history_log_votereset') . '' . $lang->get('history_extra_numvotes') . ' ' . $r['edit_summary']; - echo '' . $lang->get('history_action_contrib') . '' . $lang->get('history_action_revert') . '
'; - } - $db->free_result(); - $ret = ob_get_contents(); - ob_end_clean(); - return $ret; - } - - /** - * Rolls back a logged action - * @param $id the time ID, a.k.a. the primary key in the logs table - * @return string - */ - - public static function rollback($id) - { - global $db, $session, $paths, $template, $plugins; // Common objects - global $lang; - - // placeholder - return 'PageUtils->rollback() is deprecated - use PageProcessor instead.'; - } - - /** - * Posts a comment. - * @param $page_id the page ID - * @param $namespace the namespace - * @param $name the name of the person posting, defaults to current username/IP - * @param $subject the subject line of the comment - * @param $text the comment text - * @return string javascript code - */ - - public static function addcomment($page_id, $namespace, $name, $subject, $text, $captcha_code = false, $captcha_id = false) - { - global $db, $session, $paths, $template, $plugins; // Common objects - $_ob = ''; - if(!$session->get_permissions('post_comments')) - return 'Access denied'; - if(getConfig('comments_need_login') == '2' && !$session->user_logged_in) _die('Access denied to post comments: you need to be logged in first.'); - if(getConfig('comments_need_login') == '1' && !$session->user_logged_in) - { - if(!$captcha_code || !$captcha_id) _die('BUG: PageUtils::addcomment: no CAPTCHA data passed to method'); - $result = $session->get_captcha($captcha_id); - if(strtolower($captcha_code) != strtolower($result)) _die('The confirmation code you entered was incorrect.'); - } - $text = RenderMan::preprocess_text($text); - $name = $session->user_logged_in ? RenderMan::preprocess_text($session->username) : RenderMan::preprocess_text($name); - $subj = RenderMan::preprocess_text($subject); - if(getConfig('approve_comments', '0')=='1') $appr = '0'; else $appr = '1'; - $q = 'INSERT INTO ' . table_prefix.'comments(page_id,namespace,subject,comment_data,name,user_id,approved,time) VALUES(\'' . $page_id . '\',\'' . $namespace . '\',\'' . $subj . '\',\'' . $text . '\',\'' . $name . '\',' . $session->user_id . ',' . $appr . ','.time().')'; - $e = $db->sql_query($q); - if(!$e) die('alert(unescape(\''.rawurlencode('Error inserting comment data: '.$db->get_error().'\n\nQuery:\n' . $q) . '\'))'); - else $_ob .= '
Your comment has been posted.
'; - return PageUtils::comments($page_id, $namespace, false, Array(), $_ob); - } - - /** - * Generates partly-compiled HTML/Javascript code to be eval'ed by the user's browser to display comments - * @param $page_id the page ID - * @param $namespace the namespace - * @param $action administrative action to perform, default is false - * @param $flags additional info for $action, shouldn't be used except when deleting/approving comments, etc. - * @param $_ob text to prepend to output, used by PageUtils::addcomment - * @return array - * @access private - */ - - public static function comments_raw($page_id, $namespace, $action = false, $flags = Array(), $_ob = '') - { - global $db, $session, $paths, $template, $plugins; // Common objects - global $lang; - - $pname = $paths->nslist[$namespace] . $page_id; - $template->init_vars(); - - ob_start(); - - if($action && $session->get_permissions('mod_comments')) // Nip hacking attempts in the bud - { - switch($action) { - case "delete": - if(isset($flags['id'])) - { - $q = 'DELETE FROM ' . table_prefix.'comments WHERE page_id=\'' . $page_id . '\' AND namespace=\'' . $namespace . '\' AND comment_id='.intval($flags['id']).' LIMIT 1;'; - } else { - $n = $db->escape($flags['name']); - $s = $db->escape($flags['subj']); - $t = $db->escape($flags['text']); - $q = 'DELETE FROM ' . table_prefix.'comments WHERE page_id=\'' . $page_id . '\' AND namespace=\'' . $namespace . '\' AND name=\'' . $n . '\' AND subject=\'' . $s . '\' AND comment_data=\'' . $t . '\' LIMIT 1;'; - } - $e=$db->sql_query($q); - if(!$e) die('alert(unesape(\''.rawurlencode('Error during query: '.$db->get_error().'\n\nQuery:\n' . $q) . '\'));'); - break; - case "approve": - if(isset($flags['id'])) - { - $where = 'comment_id='.intval($flags['id']); - } else { - $n = $db->escape($flags['name']); - $s = $db->escape($flags['subj']); - $t = $db->escape($flags['text']); - $where = 'name=\'' . $n . '\' AND subject=\'' . $s . '\' AND comment_data=\'' . $t . '\''; - } - $q = 'SELECT approved FROM ' . table_prefix.'comments WHERE page_id=\'' . $page_id . '\' AND namespace=\'' . $namespace . '\' AND ' . $where . ' LIMIT 1;'; - $e = $db->sql_query($q); - if(!$e) die('alert(unesape(\''.rawurlencode('Error selecting approval status: '.$db->get_error().'\n\nQuery:\n' . $q) . '\'));'); - $r = $db->fetchrow(); - $db->free_result(); - $a = ( $r['approved'] ) ? '0' : '1'; - $q = 'UPDATE ' . table_prefix.'comments SET approved=' . $a . ' WHERE page_id=\'' . $page_id . '\' AND namespace=\'' . $namespace . '\' AND ' . $where . ';'; - $e=$db->sql_query($q); - if(!$e) die('alert(unesape(\''.rawurlencode('Error during query: '.$db->get_error().'\n\nQuery:\n' . $q) . '\'));'); - if($a=='1') $v = $lang->get('comment_btn_mod_unapprove'); - else $v = $lang->get('comment_btn_mod_approve'); - echo 'document.getElementById("mdgApproveLink'.intval($_GET['id']).'").innerHTML="' . $v . '";'; - break; - } - } - - if(!defined('ENANO_TEMPLATE_LOADED')) - { - $template->load_theme($session->theme, $session->style); - } - - $tpl = $template->makeParser('comment.tpl'); - - $e = $db->sql_query('SELECT * FROM ' . table_prefix.'comments WHERE page_id=\'' . $page_id . '\' AND namespace=\'' . $namespace . '\' AND approved=0;'); - if(!$e) $db->_die('The comment text data could not be selected.'); - $num_unapp = $db->numrows(); - $db->free_result(); - $e = $db->sql_query('SELECT * FROM ' . table_prefix.'comments WHERE page_id=\'' . $page_id . '\' AND namespace=\'' . $namespace . '\' AND approved=1;'); - if(!$e) $db->_die('The comment text data could not be selected.'); - $num_app = $db->numrows(); - $db->free_result(); - $lq = $db->sql_query('SELECT c.comment_id,c.subject,c.name,c.comment_data,c.approved,c.time,c.user_id,c.ip_address,u.user_level,u.email,u.signature,u.user_has_avatar,u.avatar_type - FROM ' . table_prefix.'comments AS c - LEFT JOIN ' . table_prefix.'users AS u - ON c.user_id=u.user_id - WHERE page_id=\'' . $page_id . '\' - AND namespace=\'' . $namespace . '\' ORDER BY c.time ASC;'); - if(!$lq) _die('The comment text data could not be selected. '.$db->get_error()); - $_ob .= '

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

'; - - $n = ( $session->get_permissions('mod_comments')) ? $db->numrows() : $num_app; - - $subst = array( - 'num_comments' => $n, - 'page_type' => $template->namespace_string - ); - - $_ob .= '

'; - $_ob .= ( $n == 0 ) ? $lang->get('comment_msg_count_zero', $subst) : ( $n == 1 ? $lang->get('comment_msg_count_one', $subst) : $lang->get('comment_msg_count_plural', $subst) ); - - if ( $session->get_permissions('mod_comments') && $num_unapp > 0 ) - { - $_ob .= ' ' . $lang->get('comment_msg_count_unapp_mod', array( 'num_unapp' => $num_unapp )) . ''; - } - else if ( !$session->get_permissions('mod_comments') && $num_unapp > 0 ) - { - $ls = ( $num_unapp == 1 ) ? 'comment_msg_count_unapp_one' : 'comment_msg_count_unapp_plural'; - $_ob .= ' ' . $lang->get($ls, array( 'num_unapp' => $num_unapp )) . ''; - } - $_ob .= '

'; - $list = 'list = { '; - // _die(htmlspecialchars($ttext)); - $i = -1; - while ( $row = $db->fetchrow($lq) ) - { - $i++; - $strings = Array(); - $bool = Array(); - if ( $session->get_permissions('mod_comments') || $row['approved'] == COMMENT_APPROVED ) - { - $list .= $i . ' : { \'comment\' : unescape(\''.rawurlencode($row['comment_data']).'\'), \'name\' : unescape(\''.rawurlencode($row['name']).'\'), \'subject\' : unescape(\''.rawurlencode($row['subject']).'\'), }, '; - - // Comment ID (used in the Javascript apps) - $strings['ID'] = (string)$i; - - // Determine the name, and whether to link to the user page or not - $name = ''; - if($row['user_id'] > 1) $name .= ''; - $name .= $row['name']; - if($row['user_id'] > 1) $name .= ''; - $strings['NAME'] = $name; unset($name); - - // Subject - $s = $row['subject']; - if(!$row['approved']) $s .= ' ' . $lang->get('comment_msg_note_unapp') . ''; - $strings['SUBJECT'] = $s; - - // Date and time - $strings['DATETIME'] = enano_date(ED_DATE | ED_TIME, $row['time']); - - // User level - switch($row['user_level']) - { - default: - case USER_LEVEL_GUEST: - $l = $lang->get('user_type_guest'); - break; - case USER_LEVEL_MEMBER: - case USER_LEVEL_CHPREF: - $l = $lang->get('user_type_member'); - break; - case USER_LEVEL_MOD: - $l = $lang->get('user_type_mod'); - break; - case USER_LEVEL_ADMIN: - $l = $lang->get('user_type_admin'); - break; - } - $strings['USER_LEVEL'] = $l; unset($l); - - // The actual comment data - $strings['DATA'] = RenderMan::render($row['comment_data']); - - if($session->get_permissions('edit_comments')) - { - // Edit link - $strings['EDIT_LINK'] = '' . $lang->get('comment_btn_edit') . ''; - - // Delete link - $strings['DELETE_LINK'] = '' . $lang->get('comment_btn_delete') . ''; - } - else - { - // Edit link - $strings['EDIT_LINK'] = ''; - - // Delete link - $strings['DELETE_LINK'] = ''; - } - - // Send PM link - $strings['SEND_PM_LINK'] = ( $session->user_logged_in && $row['user_id'] > 1 ) ? '' . $lang->get('comment_btn_send_privmsg') . '
' : ''; - - // Add Buddy link - $strings['ADD_BUDDY_LINK'] = ( $session->user_logged_in && $row['user_id'] > 1 ) ? '' . $lang->get('comment_btn_add_buddy') . '' : ''; - - // Mod links - $applink = ''; - $applink .= ''; - if($row['approved']) $applink .= $lang->get('comment_btn_mod_unapprove'); - else $applink .= $lang->get('comment_btn_mod_approve'); - $applink .= ''; - $strings['MOD_APPROVE_LINK'] = $applink; unset($applink); - $strings['MOD_DELETE_LINK'] = '' . $lang->get('comment_btn_mod_delete') . ''; - $strings['MOD_IP_LINK'] = '' . ( ( empty($row['ip_address']) ) ? $lang->get('comment_btn_mod_ip_missing') : $lang->get('comment_btn_mod_ip_notimplemented') ) . ''; - - // Signature - $strings['SIGNATURE'] = ''; - if($row['signature'] != '') $strings['SIGNATURE'] = RenderMan::render($row['signature']); - - // Avatar - if ( $row['user_has_avatar'] == 1 ) - { - $bool['user_has_avatar'] = true; - $strings['AVATAR_ALT'] = $lang->get('usercp_avatar_image_alt', array('username' => $row['name'])); - $strings['AVATAR_URL'] = make_avatar_url(intval($row['user_id']), $row['avatar_type'], $row['email']); - $strings['USERPAGE_LINK'] = makeUrlNS('User', $row['name']); - } - - $bool['auth_mod'] = ($session->get_permissions('mod_comments')) ? true : false; - $bool['can_edit'] = ( ( $session->user_logged_in && $row['name'] == $session->username && $session->get_permissions('edit_comments') ) || $session->get_permissions('mod_comments') ) ? true : false; - $bool['signature'] = ( $strings['SIGNATURE'] == '' ) ? false : true; - - // Done processing and compiling, now let's cook it into HTML - $tpl->assign_vars($strings); - $tpl->assign_bool($bool); - $_ob .= $tpl->run(); - } - } - if(getConfig('comments_need_login') != '2' || $session->user_logged_in) - { - if($session->get_permissions('post_comments')) - { - $_ob .= '

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

'; - $_ob .= $lang->get('comment_postform_blurb'); - if(getConfig('approve_comments', '0')=='1') $_ob .= ' ' . $lang->get('comment_postform_blurb_unapp'); - if(getConfig('comments_need_login') == '1' && !$session->user_logged_in) - { - $_ob .= ' ' . $lang->get('comment_postform_blurb_captcha'); - } - $sn = $session->user_logged_in ? $session->username . '' : ''; - $_ob .= ' -
-
- - - '; - if(getConfig('comments_need_login') == '1' && !$session->user_logged_in) - { - $session->kill_captcha(); - $captcha = $session->make_captcha(); - $_ob .= ''; - } - $_ob .= ' - - -
' . $lang->get('comment_postform_field_name') . '' . $sn . '
' . $lang->get('comment_postform_field_subject') . '
' . $lang->get('comment_postform_field_captcha_title') . '
' . $lang->get('comment_postform_field_captcha_blurb') . '
Visual confirmation
' . $lang->get('comment_postform_field_captcha_label') . '
' . $lang->get('comment_postform_field_comment') . '
-
-
'; - } - } else { - // FIXME: l10n - $_ob .= '

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

You need to be logged in to post comments. Log in

'; - } - $list .= '};'; - echo 'document.getElementById(\'ajaxEditContainer\').innerHTML = unescape(\''. rawurlencode($_ob) .'\'); - ' . $list; - echo 'Fat.fade_all(); document.getElementById(\'mdgCommentForm\').style.display = \'none\'; document.getElementById(\'mdgCommentFormLink\').style.display="inline";'; - - $ret = ob_get_contents(); - ob_end_clean(); - return Array($ret, $_ob); - - } - - /** - * Generates ready-to-execute Javascript code to be eval'ed by the user's browser to display comments - * @param $page_id the page ID - * @param $namespace the namespace - * @param $action administrative action to perform, default is false - * @param $flags additional info for $action, shouldn't be used except when deleting/approving comments, etc. - * @param $_ob text to prepend to output, used by PageUtils::addcomment - * @return string - */ - - public static function comments($page_id, $namespace, $action = false, $id = -1, $_ob = '') - { - global $db, $session, $paths, $template, $plugins; // Common objects - $r = PageUtils::comments_raw($page_id, $namespace, $action, $id, $_ob); - return $r[0]; - } - - /** - * Generates HTML code for comments - used in browser compatibility mode - * @param $page_id the page ID - * @param $namespace the namespace - * @param $action administrative action to perform, default is false - * @param $flags additional info for $action, shouldn't be used except when deleting/approving comments, etc. - * @param $_ob text to prepend to output, used by PageUtils::addcomment - * @return string - */ - - public static function comments_html($page_id, $namespace, $action = false, $id = -1, $_ob = '') - { - global $db, $session, $paths, $template, $plugins; // Common objects - $r = PageUtils::comments_raw($page_id, $namespace, $action, $id, $_ob); - return $r[1]; - } - - /** - * Updates comment data. - * @param $page_id the page ID - * @param $namespace the namespace - * @param $subject new subject - * @param $text new text - * @param $old_subject the old subject, unprocessed and identical to the value in the DB - * @param $old_text the old text, unprocessed and identical to the value in the DB - * @param $id the javascript list ID, used internally by the client-side app - * @return string - */ - - public static function savecomment($page_id, $namespace, $subject, $text, $old_subject, $old_text, $id = -1) - { - global $db, $session, $paths, $template, $plugins; // Common objects - if(!$session->get_permissions('edit_comments')) - return 'result="BAD";error="Access denied"'; - // Avoid SQL injection - $old_text = $db->escape($old_text); - $old_subject = $db->escape($old_subject); - // Safety check - username/login - if(!$session->get_permissions('mod_comments')) // allow mods to edit comments - { - if(!$session->user_logged_in) _die('AJAX comment save safety check failed because you are not logged in. Sometimes this can happen because you are using a browser that does not send cookies as part of AJAX requests.

Please log in and try again.'); - $q = 'SELECT c.name FROM ' . table_prefix.'comments c, ' . table_prefix.'users u WHERE comment_data=\'' . $old_text . '\' AND subject=\'' . $old_subject . '\' AND page_id=\'' . $page_id . '\' AND namespace=\'' . $namespace . '\' AND u.user_id=c.user_id;'; - $s = $db->sql_query($q); - if(!$s) _die('SQL error during safety check: '.$db->get_error().'

Attempted SQL:
'.htmlspecialchars($q).'
'); - $r = $db->fetchrow($s); - $db->free_result(); - if($db->numrows() < 1 || $r['name'] != $session->username) _die('Safety check failed, probably due to a hacking attempt.'); - } - $s = RenderMan::preprocess_text($subject); - $t = RenderMan::preprocess_text($text); - $sql = 'UPDATE ' . table_prefix.'comments SET subject=\'' . $s . '\',comment_data=\'' . $t . '\' WHERE comment_data=\'' . $old_text . '\' AND subject=\'' . $old_subject . '\' AND page_id=\'' . $page_id . '\' AND namespace=\'' . $namespace . '\''; - $result = $db->sql_query($sql); - if($result) - { - return 'result="GOOD"; - list[' . $id . '][\'subject\'] = unescape(\''.str_replace('%5Cn', '%0A', rawurlencode(str_replace('{{EnAnO:Newline}}', '\\n', stripslashes(str_replace('\\n', '{{EnAnO:Newline}}', $s))))).'\'); - list[' . $id . '][\'comment\'] = unescape(\''.str_replace('%5Cn', '%0A', rawurlencode(str_replace('{{EnAnO:Newline}}', '\\n', stripslashes(str_replace('\\n', '{{EnAnO:Newline}}', $t))))).'\'); id = ' . $id . '; - s = unescape(\''.rawurlencode($s).'\'); - t = unescape(\''.str_replace('%5Cn', '
', rawurlencode(RenderMan::render(str_replace('{{EnAnO:Newline}}', "\n", stripslashes(str_replace('\\n', '{{EnAnO:Newline}}', $t)))))).'\');'; - } - else - { - return 'result="BAD"; error=unescape("'.rawurlencode('Enano encountered a problem whilst saving the comment. - Performed SQL: - ' . $sql . ' - - Error returned by MySQL: '.$db->get_error()).'");'; - } - } - - /** - * Updates comment data using the comment_id column instead of the old, messy way - * @param $page_id the page ID - * @param $namespace the namespace - * @param $subject new subject - * @param $text new text - * @param $id the comment ID (primary key in enano_comments table) - * @return string - */ - - public static function savecomment_neater($page_id, $namespace, $subject, $text, $id) - { - global $db, $session, $paths, $template, $plugins; // Common objects - if(!is_int($id)) die('PageUtils::savecomment: $id is not an integer, aborting for safety'); - if(!$session->get_permissions('edit_comments')) - return 'Access denied'; - // Safety check - username/login - if(!$session->get_permissions('mod_comments')) // allow mods to edit comments - { - if(!$session->user_logged_in) _die('AJAX comment save safety check failed because you are not logged in. Sometimes this can happen because you are using a browser that does not send cookies as part of AJAX requests.

Please log in and try again.'); - $q = 'SELECT c.name FROM ' . table_prefix.'comments c, ' . table_prefix.'users u WHERE comment_id=' . $id . ' AND page_id=\'' . $page_id . '\' AND namespace=\'' . $namespace . '\' AND u.user_id=c.user_id;'; - $s = $db->sql_query($q); - if(!$s) _die('SQL error during safety check: '.$db->get_error().'

Attempted SQL:
'.htmlspecialchars($q).'
'); - $r = $db->fetchrow($s); - if($db->numrows() < 1 || $r['name'] != $session->username) _die('Safety check failed, probably due to a hacking attempt.'); - $db->free_result(); - } - $s = RenderMan::preprocess_text($subject); - $t = RenderMan::preprocess_text($text); - $sql = 'UPDATE ' . table_prefix.'comments SET subject=\'' . $s . '\',comment_data=\'' . $t . '\' WHERE comment_id=' . $id . ' AND page_id=\'' . $page_id . '\' AND namespace=\'' . $namespace . '\''; - $result = $db->sql_query($sql); - if($result) - return 'good'; - else return 'Enano encountered a problem whilst saving the comment. - Performed SQL: - ' . $sql . ' - - Error returned by MySQL: '.$db->get_error(); - } - - /** - * Deletes a comment. - * @param $page_id the page ID - * @param $namespace the namespace - * @param $name the name the user posted under - * @param $subj the subject of the comment to be deleted - * @param $text the text of the comment to be deleted - * @param $id the javascript list ID, used internally by the client-side app - * @return string - */ - - public static function deletecomment($page_id, $namespace, $name, $subj, $text, $id) - { - global $db, $session, $paths, $template, $plugins; // Common objects - - if(!$session->get_permissions('edit_comments')) - return 'alert("Access to delete/edit comments is denied");'; - - if(!preg_match('#^([0-9]+)$#', (string)$id)) die('$_GET[id] is improperly formed.'); - $n = $db->escape($name); - $s = $db->escape($subj); - $t = $db->escape($text); - - // Safety check - username/login - if(!$session->get_permissions('mod_comments')) // allows mods to delete comments - { - if(!$session->user_logged_in) _die('AJAX comment save safety check failed because you are not logged in. Sometimes this can happen because you are using a browser that does not send cookies as part of AJAX requests.

Please log in and try again.'); - $q = 'SELECT c.name FROM ' . table_prefix.'comments c, ' . table_prefix.'users u WHERE comment_data=\'' . $t . '\' AND subject=\'' . $s . '\' AND page_id=\'' . $page_id . '\' AND namespace=\'' . $namespace . '\' AND u.user_id=c.user_id;'; - $s = $db->sql_query($q); - if(!$s) _die('SQL error during safety check: '.$db->get_error().'

Attempted SQL:
'.htmlspecialchars($q).'
'); - $r = $db->fetchrow($s); - if($db->numrows() < 1 || $r['name'] != $session->username) _die('Safety check failed, probably due to a hacking attempt.'); - $db->free_result(); - } - $q = 'DELETE FROM ' . table_prefix.'comments WHERE page_id=\'' . $page_id . '\' AND namespace=\'' . $namespace . '\' AND name=\'' . $n . '\' AND subject=\'' . $s . '\' AND comment_data=\'' . $t . '\' LIMIT 1;'; - $e=$db->sql_query($q); - if(!$e) return('alert(unesape(\''.rawurlencode('Error during query: '.$db->get_error().'\n\nQuery:\n' . $q) . '\'));'); - return('good'); - } - - /** - * Deletes a comment in a cleaner fashion. - * @param $page_id the page ID - * @param $namespace the namespace - * @param $id the comment ID (primary key) - * @return string - */ - - public static function deletecomment_neater($page_id, $namespace, $id) - { - global $db, $session, $paths, $template, $plugins; // Common objects - - if(!preg_match('#^([0-9]+)$#', (string)$id)) die('$_GET[id] is improperly formed.'); - - if(!$session->get_permissions('edit_comments')) - return 'alert("Access to delete/edit comments is denied");'; - - // Safety check - username/login - if(!$session->get_permissions('mod_comments')) // allows mods to delete comments - { - if(!$session->user_logged_in) _die('AJAX comment save safety check failed because you are not logged in. Sometimes this can happen because you are using a browser that does not send cookies as part of AJAX requests.

Please log in and try again.'); - $q = 'SELECT c.name FROM ' . table_prefix.'comments c, ' . table_prefix.'users u WHERE comment_id=' . $id . ' AND page_id=\'' . $page_id . '\' AND namespace=\'' . $namespace . '\' AND u.user_id=c.user_id;'; - $s = $db->sql_query($q); - if(!$s) _die('SQL error during safety check: '.$db->get_error().'

Attempted SQL:
'.htmlspecialchars($q).'
'); - $r = $db->fetchrow($s); - if($db->numrows() < 1 || $r['name'] != $session->username) _die('Safety check failed, probably due to a hacking attempt.'); - $db->free_result(); - } - $q = 'DELETE FROM ' . table_prefix.'comments WHERE page_id=\'' . $page_id . '\' AND namespace=\'' . $namespace . '\' AND comment_id=' . $id . ' LIMIT 1;'; - $e=$db->sql_query($q); - if(!$e) return('alert(unesape(\''.rawurlencode('Error during query: '.$db->get_error().'\n\nQuery:\n' . $q) . '\'));'); - return('good'); - } - - /** - * Renames a page. - * @param $page_id the page ID - * @param $namespace the namespace - * @param $name the new name for the page - * @return string error string or success message - */ - - public static function rename($page_id, $namespace, $name) - { - global $db, $session, $paths, $template, $plugins; // Common objects - global $lang; - - $page = new PageProcessor($page_id, $namespace); - return $page->rename_page($name); - } - - /** - * Flushes (clears) the action logs for a given page - * @param $page_id the page ID - * @param $namespace the namespace - * @return string error/success string - */ - - public static function flushlogs($page_id, $namespace) - { - global $db, $session, $paths, $template, $plugins; // Common objects - global $lang; - if ( !is_object($lang) && defined('IN_ENANO_INSTALL') ) - { - // This is a special exception for the Enano installer, which doesn't init languages yet. - $lang = new Language('eng'); - } - if(!$session->get_permissions('clear_logs') && !defined('IN_ENANO_INSTALL')) - { - return $lang->get('etc_access_denied'); - } - if ( !$session->sid_super ) - { - return $lang->get('etc_access_denied_need_reauth'); - } - - $page_id_db = $db->escape($page_id); - $namespace_db = $db->escape($namespace); - - // If we're flushing a file, also clear all revisions before the current - if ( $namespace == 'File' ) - { - $q = $db->sql_query('SELECT file_id FROM ' . table_prefix . "files WHERE page_id='$page_id_db' ORDER BY time_id DESC;"); - if ( !$q ) - $db->_die(); - // discard first row (current revision) - $db->fetchrow(); - $id_list = array(); - while ( $row = $db->fetchrow() ) - $id_list[] = $row['file_id']; - - require_once(ENANO_ROOT . '/includes/namespaces/file.php'); - - // clear out each file - foreach ( $id_list as $id ) - Namespace_File::delete_file($id); - } - - $q = $db->sql_query('DELETE FROM ' . table_prefix . "logs WHERE page_id='$page_id_db' AND namespace='$namespace';"); - if ( !$q ) - $db->_die('The log entries could not be deleted.'); - - // If the page exists, make a backup of it in case it gets spammed/vandalized - // If not, the admin's probably deleting a trash page - if ( isPage($paths->get_pathskey($page_id, $namespace)) ) - { - $q = $db->sql_query('SELECT page_text,char_tag FROM ' . table_prefix . "page_text WHERE page_id='$page_id_db' AND namespace='$namespace_db';"); - if ( !$q ) - $db->_die('The current page text could not be selected; as a result, creating the backup of the page failed. Please make a backup copy of the page by clicking Edit this page and then clicking Save Changes.'); - $row = $db->fetchrow(); - $db->free_result(); - $minor_edit = ( ENANO_DBLAYER == 'MYSQL' ) ? 'false' : '0'; - $username = $db->escape($session->username); - $q = 'INSERT INTO ' . table_prefix . "logs ( log_type, action, time_id, date_string, page_id, namespace, page_text, char_tag, author, author_uid, edit_summary, minor_edit ) VALUES\n" - . " ('page', 'edit', " . time() . ", 'DEPRECATED', '$page_id', '$namespace', '" . $db->escape($row['page_text']) . "', '', '{$username}', $session->user_id, '" . $lang->get('page_flushlogs_backup_summary') . "', $minor_edit);"; - if ( !$db->sql_query($q) ) - $db->_die('The history (log) entry could not be inserted into the logs table.'); - } - - return $lang->get('ajax_clearlogs_success'); - } - - /** - * Deletes a page. - * @param string $page_id the condemned page ID - * @param string $namespace the condemned namespace - * @param string The reason for deleting the page in question - * @return string - */ - - public static function deletepage($page_id, $namespace, $reason) - { - global $db, $session, $paths, $template, $plugins; // Common objects - global $lang; - global $cache; - $perms = $session->fetch_page_acl($page_id, $namespace); - $x = trim($reason); - if ( empty($x) ) - { - return $lang->get('ajax_delete_need_reason'); - } - if(!$perms->get_permissions('delete_page')) return('Administrative privileges are required to delete pages, you loser.'); - - if ( !$session->sid_super ) - { - return $lang->get('etc_access_denied_need_reauth'); - } - - $e = $db->sql_query('INSERT INTO ' . table_prefix.'logs(time_id,date_string,log_type,action,page_id,namespace,author,author_uid,edit_summary) VALUES('.time().', \''.enano_date(ED_DATE | ED_TIME).'\', \'page\', \'delete\', \'' . $page_id . '\', \'' . $namespace . '\', \'' . $session->username . '\', ' . $session->user_id . ', \'' . $db->escape(htmlspecialchars($reason)) . '\')'); - if(!$e) $db->_die('The page log entry could not be inserted.'); - $e = $db->sql_query('DELETE FROM ' . table_prefix.'categories WHERE page_id=\'' . $page_id . '\' AND namespace=\'' . $namespace . '\''); - if(!$e) $db->_die('The page categorization entries could not be deleted.'); - $e = $db->sql_query('DELETE FROM ' . table_prefix.'comments WHERE page_id=\'' . $page_id . '\' AND namespace=\'' . $namespace . '\''); - if(!$e) $db->_die('The page comments could not be deleted.'); - $e = $db->sql_query('DELETE FROM ' . table_prefix.'page_text WHERE page_id=\'' . $page_id . '\' AND namespace=\'' . $namespace . '\''); - if(!$e) $db->_die('The page text entry could not be deleted.'); - $e = $db->sql_query('DELETE FROM ' . table_prefix.'pages WHERE urlname=\'' . $page_id . '\' AND namespace=\'' . $namespace . '\''); - if(!$e) $db->_die('The page entry could not be deleted.'); - if ( $namespace == 'File' ) - { - $e = $db->sql_query('DELETE FROM ' . table_prefix.'files WHERE page_id=\'' . $page_id . '\''); - if(!$e) $db->_die('The file entry could not be deleted.'); - } - $cache->purge('page_meta'); - return $lang->get('ajax_delete_success'); - } - - /** - * Deletes files associated with a File page. - * @param string Page ID - */ - - public static function delete_page_files($page_id) - { - global $db, $session, $paths, $template, $plugins; // Common objects - - $q = $db->sql_query('SELECT file_id, filename, file_key, time_id, file_extension FROM ' . table_prefix . "files WHERE page_id = '{$db->escape($page_id)}';"); - if ( !$q ) - $db->_die(); - - while ( $row = $db->fetchrow() ) - { - // wipe original file - foreach ( array( - ENANO_ROOT . "/files/{$row['file_key']}_{$row['time_id']}{$row['file_extension']}", - ENANO_ROOT . "/files/{$row['file_key']}{$row['file_extension']}" - ) as $orig_file ) - { - if ( file_exists($orig_file) ) - @unlink($orig_file); - } - - // wipe cached files - if ( $dr = @opendir(ENANO_ROOT . '/cache/') ) - { - // lol404.jpg-1217958283-200x320.jpg - while ( $dh = @readdir($dr) ) - { - $regexp = ':^' . preg_quote("{$row['filename']}-{$row['time_id']}-") . '[0-9]+x[0-9]+\.' . ltrim($row['file_extension'], '.') . '$:'; - if ( preg_match($regexp, $dh) ) - { - @unlink(ENANO_ROOT . "/cache/$dh"); - } - } - @closedir($dr); - } - } - - $q = $db->sql_query('DELETE FROM ' . table_prefix . "files WHERE page_id = '{$db->escape($page_id)}';"); - if ( !$q ) - $db->die(); - - return true; - } - - /** - * Increments the deletion votes for a page by 1, and adds the current username/IP to the list of users that have voted for the page to prevent dual-voting - * @param $page_id the page ID - * @param $namespace the namespace - * @return string - */ - - public static function delvote($page_id, $namespace) - { - global $db, $session, $paths, $template, $plugins; // Common objects - global $lang; - global $cache; - - if ( !$session->get_permissions('vote_delete') ) - { - return $lang->get('etc_access_denied'); - } - - if ( $namespace == 'Admin' || $namespace == 'Special' || $namespace == 'System' ) - { - return 'Special pages and system messages can\'t be voted for deletion.'; - } - - $pname = $paths->nslist[$namespace] . sanitize_page_id($page_id); - - if ( !isPage($pname) ) - { - return 'The page does not exist.'; - } - - $ns = namespace_factory($page_id, $namespace); - $cdata = $ns->get_cdata(); - - $cv =& $cdata['delvotes']; - $ips =& $cdata['delvote_ips']; - - if ( empty($ips) ) - { - $ips = array( - 'ip' => array(), - 'u' => array() - ); - } - else - { - $ips = @unserialize($ips); - if ( !$ips ) - { - $ips = array( - 'ip' => array(), - 'u' => array() - ); - } - } - - if ( in_array($session->username, $ips['u']) || in_array($_SERVER['REMOTE_ADDR'], $ips['ip']) ) - { - return $lang->get('ajax_delvote_already_voted'); - } - - $ips['u'][] = $session->username; - $ips['ip'][] = $_SERVER['REMOTE_ADDR']; - $ips = $db->escape( serialize($ips) ); - - $cv++; - - $q = 'UPDATE ' . table_prefix.'pages SET delvotes=' . $cv . ',delvote_ips=\'' . $ips . '\' WHERE urlname=\'' . $page_id . '\' AND namespace=\'' . $namespace . '\''; - $w = $db->sql_query($q); - if ( !$w ) - $db->_die(); - - // all done, flush page cache to mark it up - $cache->purge('page_meta'); - - return $lang->get('ajax_delvote_success'); - } - - /** - * Resets the number of votes against a page to 0. - * @param $page_id the page ID - * @param $namespace the namespace - * @return string - */ - - public static function resetdelvotes($page_id, $namespace) - { - global $db, $session, $paths, $template, $plugins; // Common objects - global $lang; - global $cache; - - if ( !$session->get_permissions('vote_reset') ) - { - return $lang->get('etc_access_denied'); - } - - $page_id = $db->escape($page_id); - $namespace = $db->escape($namespace); - - // pull existing info - $q = $db->sql_query('SELECT delvotes, delvote_ips FROM ' . table_prefix . "pages WHERE urlname = '$page_id' AND namespace = '$namespace'"); - if ( !$q ) - $db->_die(); - if ( $db->numrows() < 1 ) - return $lang->get('page_err_page_not_exist'); - - list($delvotes, $delvote_ips) = $db->fetchrow_num(); - $db->free_result(); - $delvote_ips = $db->escape($delvote_ips); - $username = $db->escape($session->username); - - // log action - $time = time(); - $q = $db->sql_query('INSERT INTO ' . table_prefix . "logs (time_id, log_type, action, edit_summary, page_text, author, author_uid, page_id, namespace) VALUES\n" - . " ( $time, 'page', 'votereset', '$delvotes', '$delvote_ips', '$username', $session->user_id, '$page_id', '$namespace' )"); - if ( !$q ) - $db->_die(); - - // reset votes - $empty_vote_record = $db->escape(serialize(array('ip'=>array(),'u'=>array()))); - $q = 'UPDATE ' . table_prefix.'pages SET delvotes=0,delvote_ips=\'' . $empty_vote_record . '\' WHERE urlname=\'' . $page_id . '\' AND namespace=\'' . $namespace . '\''; - $e = $db->sql_query($q); - if ( !$e ) - { - $db->_die('The number of delete votes was not reset.'); - } - else - { - $cache->purge('page_meta'); - return $lang->get('ajax_delvote_reset_success'); - } - } - - /** - * Gets a list of styles for a given theme name. As of Banshee, this returns JSON. - * @param $id the name of the directory for the theme - * @return string JSON string with an array containing a list of themes - */ - - public static function getstyles() - { - - if ( !preg_match('/^([a-z0-9_-]+)$/', $_GET['id']) ) - return enano_json_encode(false); - - $dir = './themes/' . $_GET['id'] . '/css/'; - $list = Array(); - // Open a known directory, and proceed to read its contents - if (is_dir($dir)) { - if ($dh = opendir($dir)) { - while (($file = readdir($dh)) !== false) { - if ( preg_match('#^(.*?)\.css$#is', $file) && $file != '_printable.css' ) // _printable.css should be included with every theme - { // it should be a copy of the original style, but - // mostly black and white - // Note to self: document this - $list[] = substr($file, 0, strlen($file)-4); - } - } - closedir($dh); - } - } - else - { - return(enano_json_encode(Array('mode' => 'error', 'error' => $dir.' is not a dir'))); - } - - return enano_json_encode($list); - } - - /** - * Assembles a Javascript app with category information - * @param $page_id the page ID - * @param $namespace the namespace - * @return string Javascript code - */ - - public static function catedit($page_id, $namespace) - { - $d = PageUtils::catedit_raw($page_id, $namespace); - return $d[0] . ' /* BEGIN CONTENT */ document.getElementById("ajaxEditContainer").innerHTML = unescape(\''.rawurlencode($d[1]).'\');'; - } - - /** - * Does the actual HTML/javascript generation for cat editing, but returns an array - * @access private - */ - - public static function catedit_raw($page_id, $namespace) - { - global $db, $session, $paths, $template, $plugins; // Common objects - global $lang; - - ob_start(); - $_ob = ''; - $e = $db->sql_query('SELECT category_id FROM ' . table_prefix.'categories WHERE page_id=\'' . $paths->page_id . '\' AND namespace=\'' . $paths->namespace . '\''); - if(!$e) jsdie('Error selecting category information for current page: '.$db->get_error()); - $cat_current = Array(); - while($r = $db->fetchrow()) - { - $cat_current[] = $r; - } - $db->free_result(); - - $cat_all = array(); - $q = $db->sql_query('SELECT * FROM ' . table_prefix . 'pages WHERE namespace = \'Category\';'); - if ( !$q ) - $db->_die(); - - while ( $row = $db->fetchrow() ) - { - $cat_all[] = Namespace_Default::bake_cdata($row); - } - - // Make $cat_all an associative array, like $paths->pages - $sz = sizeof($cat_all); - for($i=0;$i<$sz;$i++) - { - $cat_all[$cat_all[$i]['urlname_nons']] = $cat_all[$i]; - } - // Now, the "zipper" function - join the list of categories with the list of cats that this page is a part of - $cat_info = $cat_all; - for($i=0;$iget('catedit_title') . ' -
'; - if ( sizeof($cat_info) < 1 ) - { - $_ob .= '

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

'; - } - for ( $i = 0; $i < sizeof($cat_info) / 2; $i++ ) - { - // Protection code added 1/3/07 - // Updated 3/4/07 - $is_prot = false; - $perms = $session->fetch_page_acl($cat_info[$i]['urlname_nons'], 'Category'); - if ( !$session->get_permissions('edit_cat') || !$perms->get_permissions('edit_cat') || - ( $cat_info[$i]['really_protected'] && !$perms->get_permissions('even_when_protected') ) ) - $is_prot = true; - $prot = ( $is_prot ) ? ' disabled="disabled" ' : ''; - $prottext = ( $is_prot ) ? ' (protected)' : ''; - echo 'catlist[' . $i . '] = \'' . $cat_info[$i]['urlname_nons'] . '\';'; - $_ob .= '' . $cat_info[$i]['name'].$prottext.'
'; - } - - $disabled = ( sizeof($cat_info) < 1 ) ? 'disabled="disabled"' : ''; - - $_ob .= '
'; - - $cont = ob_get_contents(); - ob_end_clean(); - return Array($cont, $_ob); - } - - /** - * Saves category information - * WARNING: If $which_cats is empty, all the category information for the selected page will be nuked! - * @param $page_id string the page ID - * @param $namespace string the namespace - * @param $which_cats array associative array of categories to put the page in - * @return string "GOOD" on success, error string on failure - */ - - public static function catsave($page_id, $namespace, $which_cats) - { - global $db, $session, $paths, $template, $plugins; // Common objects - if(!$session->get_permissions('edit_cat')) return('Insufficient privileges to change category information'); - - $page_perms = $session->fetch_page_acl($page_id, $namespace); - $ns = namespace_factory($page_id, $namespace); - $page_data = $ns->get_cdata(); - - $cat_all = array(); - $q = $db->sql_query('SELECT * FROM ' . table_prefix . 'pages WHERE namespace = \'Category\';'); - if ( !$q ) - $db->_die(); - - while ( $row = $db->fetchrow() ) - { - $cat_all[] = Namespace_Default::bake_cdata($row); - } - - // Make $cat_all an associative array, like $paths->pages - $sz = sizeof($cat_all); - for($i=0;$i<$sz;$i++) - { - $cat_all[$cat_all[$i]['urlname_nons']] = $cat_all[$i]; - } - - $rowlist = Array(); - - for($i=0;$ifetch_page_acl($cat_all[$i]['urlname_nons'], 'Category'); - if ( !$session->get_permissions('edit_cat') || !$perms->get_permissions('edit_cat') || - ( $cat_all[$i]['really_protected'] && !$perms->get_permissions('even_when_protected') ) || - ( !$page_perms->get_permissions('even_when_protected') && $page_data['protected'] == '1' ) ) - $auth = false; - if(!$auth) - { - // Find out if the page is currently in the category - $q = $db->sql_query('SELECT * FROM ' . table_prefix.'categories WHERE page_id=\'' . $page_id . '\' AND namespace=\'' . $namespace . '\';'); - if(!$q) - return 'MySQL error: ' . $db->get_error(); - if($db->numrows() > 0) - { - $auth = true; - $which_cats[$cat_all[$i]['urlname_nons']] = true; // Force the category to stay in its current state - } - $db->free_result(); - } - if(isset($which_cats[$cat_all[$i]['urlname_nons']]) && $which_cats[$cat_all[$i]['urlname_nons']] == true /* for clarity ;-) */ && $auth ) $rowlist[] = '(\'' . $page_id . '\', \'' . $namespace . '\', \'' . $cat_all[$i]['urlname_nons'] . '\')'; - } - if(sizeof($rowlist) > 0) - { - $val = implode(',', $rowlist); - $q = 'INSERT INTO ' . table_prefix.'categories(page_id,namespace,category_id) VALUES' . $val . ';'; - $e = $db->sql_query('DELETE FROM ' . table_prefix.'categories WHERE page_id=\'' . $page_id . '\' AND namespace=\'' . $namespace . '\';'); - if(!$e) $db->_die('The old category data could not be deleted.'); - $e = $db->sql_query($q); - if(!$e) $db->_die('The new category data could not be inserted.'); - return('GOOD'); - } - else - { - $e = $db->sql_query('DELETE FROM ' . table_prefix.'categories WHERE page_id=\'' . $page_id . '\' AND namespace=\'' . $namespace . '\';'); - if(!$e) $db->_die('The old category data could not be deleted.'); - return('GOOD'); - } - } - - /** - * Sets the wiki mode level for a page. - * @param $page_id string the page ID - * @param $namespace string the namespace - * @param $level int 0 for off, 1 for on, 2 for use global setting - * @return string "GOOD" on success, error string on failure - */ - - public static function setwikimode($page_id, $namespace, $level) - { - global $db, $session, $paths, $template, $plugins; // Common objects - global $cache; - - if(!$session->get_permissions('set_wiki_mode')) return('Insufficient access rights'); - if ( !isset($level) || ( isset($level) && !preg_match('#^([0-2]){1}$#', (string)$level) ) ) - { - return('Invalid mode string'); - } - $q = $db->sql_query('UPDATE ' . table_prefix.'pages SET wiki_mode=' . $level . ' WHERE urlname=\'' . $page_id . '\' AND namespace=\'' . $namespace . '\';'); - if ( !$q ) - { - return('Error during update query: '.$db->get_error()."\n\nSQL Backtrace:\n".$db->sql_backtrace()); - } - - $cache->purge('page_meta'); - return('GOOD'); - } - - /** - * Sets the access password for a page. - * @param $page_id string the page ID - * @param $namespace string the namespace - * @param $pass string the SHA1 hash of the password - if the password doesn't match the regex ^([0-9a-f]*){40,40}$ it will be sha1'ed - * @return string - */ - - public static function setpass($page_id, $namespace, $pass) - { - global $db, $session, $paths, $template, $plugins; // Common objects - global $lang, $cache; - // Determine permissions - $ns = namespace_factory($page_id, $namespace); - $cdata = $ns->get_cdata(); - if ( $cdata['password'] != '' ) - $a = $session->get_permissions('password_reset'); - else - $a = $session->get_permissions('password_set'); - if ( !$a ) - return $lang->get('etc_access_denied'); - if ( !isset($pass) ) - return('Password was not set on URL'); - $p = $pass; - if ( !preg_match('#([0-9a-f]){40,40}#', $p) ) - { - $p = sha1($p); - } - if ( $p == 'da39a3ee5e6b4b0d3255bfef95601890afd80709' ) - // sha1('') = da39a3ee5e6b4b0d3255bfef95601890afd80709 - $p = ''; - $e = $db->sql_query('UPDATE ' . table_prefix.'pages SET password=\'' . $p . '\' WHERE urlname=\'' . $page_id . '\' AND namespace=\'' . $namespace . '\';'); - if ( !$e ) - { - die('PageUtils::setpass(): Error during update query: '.$db->get_error()."\n\nSQL Backtrace:\n".$db->sql_backtrace()); - } - // Is the new password blank? - if ( $p == '' ) - { - return $lang->get('ajax_password_disable_success'); - } - else - { - return $lang->get('ajax_password_success'); - } - } - - /** - * Generates some preview HTML - * @param $text string the wikitext to use - * @return string - */ - - public static function genPreview($text) - { - global $lang; - $ret = '
' . $lang->get('editor_preview_blurb') . '
'; - $text = RenderMan::render(RenderMan::preprocess_text($text, false, false)); - ob_start(); - eval('?>' . $text); - $text = ob_get_contents(); - ob_end_clean(); - $ret .= $text; - $ret .= '
'; - return $ret; - } - - /** - * Makes a scrollable box - * @param string $text the inner HTML - * @param int $height Optional - the maximum height. Defaults to 250. - * @return string - */ - - public static function scrollBox($text, $height = 250) - { - return '
' . $text . '
'; - } - - /** - * Generates a diff summary between two page revisions. - * @param $page_id the page ID - * @param $namespace the namespace - * @param $id1 the time ID of the first revision - * @param $id2 the time ID of the second revision - * @return string XHTML-formatted diff - */ - - public static function pagediff($page_id, $namespace, $id1, $id2) - { - global $db, $session, $paths, $template, $plugins; // Common objects - global $lang; - - if ( !$session->get_permissions('history_view') ) - return $lang->get('etc_access_denied'); - - if(!preg_match('#^([0-9]+)$#', (string)$id1) || - !preg_match('#^([0-9]+)$#', (string)$id2 )) return 'SQL injection attempt'; - // OK we made it through security - // Safest way to make sure we don't end up with the revisions in wrong columns is to make 2 queries - if ( !$q1 = $db->sql_query('SELECT time_id,page_text,char_tag,author,edit_summary FROM ' . table_prefix.'logs WHERE log_id = ' . $id1 . ' AND log_type=\'page\' AND action=\'edit\' AND page_id=\'' . $page_id . '\' AND namespace=\'' . $namespace . '\';')) return 'MySQL error: ' . $db->get_error(); - if ( !$q2 = $db->sql_query('SELECT time_id,page_text,char_tag,author,edit_summary FROM ' . table_prefix.'logs WHERE log_id = ' . $id2 . ' AND log_type=\'page\' AND action=\'edit\' AND page_id=\'' . $page_id . '\' AND namespace=\'' . $namespace . '\';')) return 'MySQL error: ' . $db->get_error(); - $row1 = $db->fetchrow($q1); - $db->free_result($q1); - $row2 = $db->fetchrow($q2); - $db->free_result($q2); - if(sizeof($row1) < 1 || sizeof($row2) < 2) - { - if ( !$q1 = $db->sql_query('SELECT time_id,page_text,char_tag,author,edit_summary FROM ' . table_prefix.'logs WHERE time_id = ' . $id1 . ' AND log_type=\'page\' AND action=\'edit\' AND page_id=\'' . $page_id . '\' AND namespace=\'' . $namespace . '\';')) return 'MySQL error: ' . $db->get_error(); - if ( !$q2 = $db->sql_query('SELECT time_id,page_text,char_tag,author,edit_summary FROM ' . table_prefix.'logs WHERE time_id = ' . $id2 . ' AND log_type=\'page\' AND action=\'edit\' AND page_id=\'' . $page_id . '\' AND namespace=\'' . $namespace . '\';')) return 'MySQL error: ' . $db->get_error(); - $row1 = $db->fetchrow($q1); - $db->free_result($q1); - $row2 = $db->fetchrow($q2); - $db->free_result($q2); - if(sizeof($row1) < 1 || sizeof($row2) < 2) - return 'Couldn\'t find any rows that matched the query. The time ID probably doesn\'t exist in the logs table.'; - } - $text1 = $row1['page_text']; - $text2 = $row2['page_text']; - $time1 = enano_date(ED_DATE | ED_TIME, $row1['time_id']); - $time2 = enano_date(ED_DATE | ED_TIME, $row2['time_id']); - $_ob = " -

" . $lang->get('history_lbl_comparingrevisions') . " {$time1} → {$time2}

- "; - // Free some memory - unset($row1, $row2, $q1, $q2); - - $_ob .= RenderMan::diff($text1, $text2); - return $_ob; - } - - /** - * Gets ACL information about the selected page for target type X and target ID Y. - * @param array $parms What to select. This is an array purely for JSON compatibility. It should be an associative array with keys target_type and target_id. - * @return array - */ - - public static function acl_editor($parms = Array()) - { - global $db, $session, $paths, $template, $plugins; // Common objects - global $lang; - - if(!$session->get_permissions('edit_acl') && ( $session->user_level < USER_LEVEL_ADMIN || !defined('ACL_ALWAYS_ALLOW_ADMIN_EDIT_ACL')) ) - { - return Array( - 'mode' => 'error', - 'error' => $lang->get('acl_err_access_denied') - ); - } - if ( !$session->sid_super ) - { - return Array( - 'mode' => 'error', - 'error' => $lang->get('etc_access_denied_need_reauth') - ); - } - $parms['page_id'] = ( isset($parms['page_id']) ) ? $parms['page_id'] : false; - $parms['namespace'] = ( isset($parms['namespace']) ) ? $parms['namespace'] : false; - $page_id =& $parms['page_id']; - $namespace =& $parms['namespace']; - $page_where_clause = ( empty($page_id) || empty($namespace) ) ? 'AND a.page_id IS NULL AND a.namespace IS NULL' : 'AND a.page_id=\'' . $db->escape($page_id) . '\' AND a.namespace=\'' . $db->escape($namespace) . '\''; - $page_where_clause_lite = ( empty($page_id) || empty($namespace) ) ? 'AND page_id IS NULL AND namespace IS NULL' : 'AND page_id=\'' . $db->escape($page_id) . '\' AND namespace=\'' . $db->escape($namespace) . '\''; - //die(print_r($page_id,true)); - $template->load_theme(); - // $perms_obj = $session->fetch_page_acl($page_id, $namespace); - $perms_obj =& $session; - $return = Array(); - if ( !file_exists(ENANO_ROOT . '/themes/' . $session->theme . '/acledit.tpl') ) - { - return Array( - 'mode' => 'error', - 'error' => $lang->get('acl_err_missing_template'), - ); - } - $return['template'] = $template->extract_vars('acledit.tpl'); - $return['page_id'] = $page_id; - $return['namespace'] = $namespace; - if(isset($parms['mode'])) - { - switch($parms['mode']) - { - case 'listgroups': - $return['groups'] = Array(); - $q = $db->sql_query('SELECT group_id,group_name FROM ' . table_prefix.'groups ORDER BY group_name ASC;'); - while($row = $db->fetchrow()) - { - $return['groups'][] = Array( - 'id' => $row['group_id'], - 'name' => $row['group_name'], - ); - } - $db->free_result(); - $return['page_groups'] = Array(); - $q = $db->sql_query('SELECT pg_id,pg_name FROM ' . table_prefix.'page_groups ORDER BY pg_name ASC;'); - if ( !$q ) - return Array( - 'mode' => 'error', - 'error' => $db->get_error() - ); - while ( $row = $db->fetchrow() ) - { - $return['page_groups'][] = Array( - 'id' => $row['pg_id'], - 'name' => $row['pg_name'] - ); - } - break; - case 'seltarget_id': - if ( !is_int($parms['target_id']) ) - { - return Array( - 'mode' => 'error', - 'error' => 'Expected parameter target_id type int' - ); - } - $q = $db->sql_query('SELECT target_id, target_type, page_id, namespace, rules FROM ' . table_prefix . "acl WHERE rule_id = {$parms['target_id']};"); - if ( !$q ) - return Array( - 'mode' => 'error', - 'error' => $db->get_error() - ); - if ( $db->numrows() < 1 ) - return Array( - 'mode' => 'error', - 'error' => "No rule with ID {$parms['target_id']} found" - ); - $parms = $db->fetchrow(); - $db->free_result(); - - // regenerate page selection - $parms['page_id'] = ( isset($parms['page_id']) ) ? $parms['page_id'] : false; - $parms['namespace'] = ( isset($parms['namespace']) ) ? $parms['namespace'] : false; - $parms['mode'] = 'seltarget_id'; - $page_id =& $parms['page_id']; - $namespace =& $parms['namespace']; - $page_where_clause = ( empty($page_id) || empty($namespace) ) ? 'AND a.page_id IS NULL AND a.namespace IS NULL' : 'AND a.page_id=\'' . $db->escape($page_id) . '\' AND a.namespace=\'' . $db->escape($namespace) . '\''; - $page_where_clause_lite = ( empty($page_id) || empty($namespace) ) ? 'AND page_id IS NULL AND namespace IS NULL' : 'AND page_id=\'' . $db->escape($page_id) . '\' AND namespace=\'' . $db->escape($namespace) . '\''; - - $return['page_id'] = $parms['page_id']; - $return['namespace'] = $parms['namespace']; - - // From here, let the seltarget handler take over - case 'seltarget': - $return['mode'] = 'seltarget'; - $return['acl_types'] = $perms_obj->acl_types; - $return['acl_deps'] = $perms_obj->acl_deps; - $return['acl_descs'] = $perms_obj->acl_descs; - $return['target_type'] = $parms['target_type']; - $return['target_id'] = $parms['target_id']; - switch($parms['target_type']) - { - case ACL_TYPE_USER: - $user_col = ( $parms['mode'] == 'seltarget_id' ) ? 'user_id' : 'username'; - $q = $db->sql_query('SELECT a.rules,u.user_id,u.username FROM ' . table_prefix.'users AS u - LEFT JOIN ' . table_prefix.'acl AS a - ON a.target_id=u.user_id - WHERE a.target_type='.ACL_TYPE_USER.' - AND u.' . $user_col . ' = \'' . $db->escape($parms['target_id']) . '\' - ' . $page_where_clause . ';'); - if(!$q) - return(Array('mode'=>'error','error'=>$db->get_error())); - if($db->numrows() < 1) - { - $return['type'] = 'new'; - $q = $db->sql_query('SELECT user_id,username FROM ' . table_prefix.'users WHERE username=\'' . $db->escape($parms['target_id']) . '\';'); - if(!$q) - return(Array('mode'=>'error','error'=>$db->get_error())); - if($db->numrows() < 1) - return Array('mode'=>'error','error'=>$lang->get('acl_err_user_not_found'),'debug' => $db->sql_backtrace()); - $row = $db->fetchrow(); - $return['target_name'] = $row['username']; - $return['target_id'] = intval($row['user_id']); - $return['current_perms'] = array(); - } - else - { - $return['type'] = 'edit'; - $row = $db->fetchrow(); - $return['target_name'] = $row['username']; - $return['target_id'] = intval($row['user_id']); - $return['current_perms'] = $session->string_to_perm($row['rules']); - } - $db->free_result(); - // Eliminate types that don't apply to this namespace - if ( $namespace && $namespace != '__PageGroup' ) - { - foreach ( $return['current_perms'] AS $i => $perm ) - { - if ( ( $page_id != null && $namespace != null ) && ( !in_array ( $namespace, $session->acl_scope[$i] ) && !in_array('All', $session->acl_scope[$i]) ) ) - { - // echo "// SCOPE CONTROL: eliminating: $i\n"; - unset($return['current_perms'][$i]); - unset($return['acl_types'][$i]); - unset($return['acl_descs'][$i]); - unset($return['acl_deps'][$i]); - } - } - } - break; - case ACL_TYPE_GROUP: - $q = $db->sql_query('SELECT a.rules,g.group_name,g.group_id FROM ' . table_prefix.'groups AS g - LEFT JOIN ' . table_prefix.'acl AS a - ON a.target_id=g.group_id - WHERE a.target_type='.ACL_TYPE_GROUP.' - AND g.group_id=\''.intval($parms['target_id']).'\' - ' . $page_where_clause . ';'); - if(!$q) - return(Array('mode'=>'error','error'=>$db->get_error())); - if($db->numrows() < 1) - { - $return['type'] = 'new'; - $q = $db->sql_query('SELECT group_id,group_name FROM ' . table_prefix.'groups WHERE group_id=\''.intval($parms['target_id']).'\';'); - if(!$q) - return(Array('mode'=>'error','error'=>$db->get_error())); - if($db->numrows() < 1) - return Array('mode'=>'error','error'=>$lang->get('acl_err_bad_group_id')); - $row = $db->fetchrow(); - $return['target_name'] = $row['group_name']; - $return['target_id'] = intval($row['group_id']); - $return['current_perms'] = array(); - } - else - { - $return['type'] = 'edit'; - $row = $db->fetchrow(); - $return['target_name'] = $row['group_name']; - $return['target_id'] = intval($row['group_id']); - $return['current_perms'] = $session->string_to_perm($row['rules']); - } - $db->free_result(); - // Eliminate types that don't apply to this namespace - if ( $namespace && $namespace != '__PageGroup' ) - { - foreach ( $return['current_perms'] AS $i => $perm ) - { - if ( ( $page_id != false && $namespace != false ) && ( !in_array ( $namespace, $session->acl_scope[$i] ) && !in_array('All', $session->acl_scope[$i]) ) ) - { - // echo "// SCOPE CONTROL: eliminating: $i\n"; //; ".print_r($namespace,true).":".print_r($page_id,true)."\n"; - unset($return['current_perms'][$i]); - unset($return['acl_types'][$i]); - unset($return['acl_descs'][$i]); - unset($return['acl_deps'][$i]); - } - } - } - //return Array('mode'=>'debug','text'=>print_r($return, true)); - break; - default: - return Array('mode'=>'error','error','Invalid ACL type ID'); - break; - } - return $return; - break; - case 'save_new': - case 'save_edit': - if ( defined('ENANO_DEMO_MODE') ) - { - return Array('mode'=>'error','error'=>$lang->get('acl_err_demo')); - } - $q = $db->sql_query('DELETE FROM ' . table_prefix.'acl WHERE target_type='.intval($parms['target_type']).' AND target_id='.intval($parms['target_id']).' - ' . $page_where_clause_lite . ';'); - if(!$q) - return Array('mode'=>'error','error'=>$db->get_error()); - if ( sizeof ( $parms['perms'] ) < 1 ) - { - // As of 1.1.x, this returns success because the rule length is zero if the user selected "inherit" in all columns - return Array( - 'mode' => 'success', - 'target_type' => $parms['target_type'], - 'target_id' => $parms['target_id'], - 'target_name' => $parms['target_name'], - 'page_id' => $page_id, - 'namespace' => $namespace, - ); - } - $rules = $session->perm_to_string($parms['perms']); - $q = ($page_id && $namespace) ? 'INSERT INTO ' . table_prefix.'acl ( target_type, target_id, page_id, namespace, rules ) - VALUES( '.intval($parms['target_type']).', '.intval($parms['target_id']).', \'' . $db->escape($page_id) . '\', \'' . $db->escape($namespace) . '\', \'' . $db->escape($rules) . '\' )' : - 'INSERT INTO ' . table_prefix.'acl ( target_type, target_id, rules ) - VALUES( '.intval($parms['target_type']).', '.intval($parms['target_id']).', \'' . $db->escape($rules) . '\' )'; - if(!$db->sql_query($q)) return Array('mode'=>'error','error'=>$db->get_error()); - return Array( - 'mode' => 'success', - 'target_type' => $parms['target_type'], - 'target_id' => $parms['target_id'], - 'target_name' => $parms['target_name'], - 'page_id' => $page_id, - 'namespace' => $namespace, - ); - break; - case 'delete': - if ( defined('ENANO_DEMO_MODE') ) - { - return Array('mode'=>'error','error'=>$lang->get('acl_err_demo')); - } - $sql = 'DELETE FROM ' . table_prefix.'acl WHERE target_type='.intval($parms['target_type']).' AND target_id='.intval($parms['target_id']).' - ' . $page_where_clause_lite . ';'; - $q = $db->sql_query($sql); - if(!$q) - return Array('mode'=>'error','error'=>$db->get_error()); - return Array( - 'mode' => 'delete', - 'target_type' => $parms['target_type'], - 'target_id' => $parms['target_id'], - 'target_name' => $parms['target_name'], - 'page_id' => $page_id, - 'namespace' => $namespace, - ); - break; - case 'list_existing': - - $return = array( - 'mode' => 'list_existing', - 'key' => acl_list_draw_key(), - 'rules' => array() - ); - - $acl_columns = 'a.' . implode(', a.', $db->columns_in(table_prefix . 'acl')); - $users_columns = 'u.' . implode(', u.', $db->columns_in(table_prefix . 'users')); - $groups_columns = 'g.' . implode(', g.', $db->columns_in(table_prefix . 'groups')); - $pg_columns = 'p.' . implode(', p.', array('pg_id', 'pg_type', 'pg_name', 'pg_target')); - - $q = $db->sql_query("SELECT a.rule_id, u.username, g.group_name, a.target_type, a.target_id, a.page_id, a.namespace, a.rules, p.pg_name\n" - . " FROM " . table_prefix . "acl AS a\n" - . " LEFT JOIN " . table_prefix . "users AS u\n" - . " ON ( (a.target_type = " . ACL_TYPE_USER . " AND a.target_id = u.user_id) OR (u.user_id IS NULL) )\n" - . " LEFT JOIN " . table_prefix . "groups AS g\n" - . " ON ( (a.target_type = " . ACL_TYPE_GROUP . " AND a.target_id = g.group_id) OR (g.group_id IS NULL) )\n" - . " LEFT JOIN " . table_prefix . "page_groups as p\n" - . " ON ( (a.namespace = '__PageGroup' AND a.page_id = CAST(p.pg_id AS CHAR)) OR (p.pg_id IS NULL) )\n" - . " WHERE ( a.target_type = " . ACL_TYPE_USER . " OR a.target_type = " . ACL_TYPE_GROUP . " )\n" - . " GROUP BY a.rule_id, $acl_columns, $users_columns, $groups_columns, $pg_columns\n" - . " ORDER BY a.target_type ASC, a.rule_id ASC;" - ); - - if ( !$q ) - $db->_die(); - - while ( $row = $db->fetchrow($q) ) - { - if ( $row['target_type'] == ACL_TYPE_USER && empty($row['username']) ) - { - // This is only done if we have an ACL affecting a user that doesn't exist. - // Nice little bit of maintenance to have. - if ( !$db->sql_query("DELETE FROM " . table_prefix . "acl WHERE rule_id = {$row['rule_id']};") ) - $db->_die(); - continue; - } - $score = get_acl_rule_score($row['rules']); - $deep_limit = ACL_SCALE_MINIMAL_SHADE; - // Determine background color of cell by score - if ( $score > 5 ) - { - // high score, show in green - $color = 2.5 * $score; - if ( $color > 255 ) - $color = 255; - $color = round($color); - // blend with the colordepth limit - $color = $deep_limit + ( ( 0xFF - $deep_limit ) - ( ( $color / 0xFF ) * ( 0xFF - $deep_limit ) ) ); - $color = dechex($color); - $color = "{$color}ff{$color}"; - } - else if ( $score < -5 ) - { - // low score, show in red - $color = 0 - $score; - $color = 2.5 * $color; - if ( $color > 255 ) - $color = 255; - $color = round($color); - // blend with the colordepth limit - $color = $deep_limit + ( ( 0xFF - $deep_limit ) - ( ( $color / 0xFF ) * ( 0xFF - $deep_limit ) ) ); - $color = dechex($color); - $color = "ff{$color}{$color}"; - } - else - { - $color = 'efefef'; - } - - // Rate rule textually based on its score - if ( $score >= 70 ) - $desc = $lang->get('acl_msg_scale_allow'); - else if ( $score >= 50 ) - $desc = $lang->get('acl_msg_scale_mostly_allow'); - else if ( $score >= 25 ) - $desc = $lang->get('acl_msg_scale_some_allow'); - else if ( $score >= -25 ) - $desc = $lang->get('acl_msg_scale_mixed'); - else if ( $score <= -70 ) - $desc = $lang->get('acl_msg_scale_deny'); - else if ( $score <= -50 ) - $desc = $lang->get('acl_msg_scale_mostly_deny'); - else if ( $score <= -25 ) - $desc = $lang->get('acl_msg_scale_some_deny'); - - // group and user target info - $info = ''; - if ( $row['target_type'] == ACL_TYPE_USER ) - $info = $lang->get('acl_msg_list_user', array( 'username' => $row['username'] )); // "(User: {$row['username']})"; - else if ( $row['target_type'] == ACL_TYPE_GROUP ) - $info = $lang->get('acl_msg_list_group', array( 'group' => $row['group_name'] )); - - // affected pages info - if ( $row['page_id'] && $row['namespace'] && $row['namespace'] != '__PageGroup' ) - $info .= $lang->get('acl_msg_list_on_page', array( 'page_name' => "{$row['namespace']}:{$row['page_id']}" )); - else if ( $row['page_id'] && $row['namespace'] && $row['namespace'] == '__PageGroup' ) - $info .= $lang->get('acl_msg_list_on_page_group', array( 'page_group' => $row['pg_name'] )); - else - $info .= $lang->get('acl_msg_list_entire_site'); - - $score_string = $lang->get('acl_msg_list_score', array - ( - 'score' => $score, - 'desc' => $desc, - 'info' => $info - )); - $return['rules'][] = array( - 'score_string' => $score_string, - 'rule_id' => $row['rule_id'], - 'color' => $color - ); - } - - break; - case 'list_presets': - $presets = array(); - $q = $db->sql_query('SELECT page_id AS preset_name, rule_id, rules FROM ' . table_prefix . "acl WHERE target_type = " . ACL_TYPE_PRESET . ";"); - if ( !$q ) - $db->die_json(); - - while ( $row = $db->fetchrow() ) - { - $row['rules'] = $session->string_to_perm($row['rules']); - $presets[] = $row; - } - - return array( - 'mode' => 'list_existing', - 'presets' => $presets - ); - break; - case 'save_preset': - if ( empty($parms['preset_name']) ) - { - return array( - 'mode' => 'error', - 'error' => $lang->get('acl_err_preset_name_empty') - ); - } - $preset_name = $db->escape($parms['preset_name']); - $q = $db->sql_query('DELETE FROM ' . table_prefix . "acl WHERE target_type = " . ACL_TYPE_PRESET . " AND page_id = '$preset_name';"); - if ( !$q ) - $db->die_json(); - - $perms = $session->perm_to_string($parms['perms']); - if ( !$perms ) - { - return array( - 'mode' => 'error', - 'error' => $lang->get('acl_err_preset_is_blank') - ); - } - - $perms = $db->escape($perms); - $q = $db->sql_query('INSERT INTO ' . table_prefix . "acl(page_id, target_type, rules) VALUES\n" - . " ( '$preset_name', " . ACL_TYPE_PRESET . ", '$perms' );"); - if ( !$q ) - $db->die_json(); - - return array( - 'mode' => 'success' - ); - break; - case 'trace': - list($targetpid, $targetns) = RenderMan::strToPageID($parms['page']); - try - { - $perms = $session->fetch_page_acl_user($parms['user'], $targetpid, $targetns); - $perm_table = array( - AUTH_ALLOW => 'acl_lbl_field_allow', - AUTH_WIKIMODE => 'acl_lbl_field_wikimode', - AUTH_DISALLOW => 'acl_lbl_field_disallow', - AUTH_DENY => 'acl_lbl_field_deny' - ); - - $return = array( - 'mode' => 'trace', - 'perms' => array() - ); - - foreach ( $perms->perm_resolve_table as $perm_type => $lookup_data ) - { - if ( !$session->check_acl_scope($perm_type, $targetns) ) - continue; - - $src_l10n = $lang->get($session->acl_inherit_lang_table[$lookup_data['src']], $lookup_data); - $divclass = preg_replace('/^acl_inherit_/', '', $session->acl_inherit_lang_table[$lookup_data['src']]); - $perm_string = $lang->get($perm_table[$perms->perms[$perm_type]]); - $perm_name = $lang->get($session->acl_descs[$perm_type]); - - $return['perms'][$perm_type] = array( - 'divclass' => "acl_inherit acl_$divclass", - 'perm_type' => $perm_type, - 'perm_name' => $perm_name, - 'perm_value' => $perm_string, - 'perm_src' => $src_l10n, - 'rule_id' => intval($lookup_data['rule_id']), - 'bad_deps' => $perms->acl_check_deps($perm_type, true) - ); - } - - // group rules if possible - $return['groups'] = array(); - foreach ( $return['perms'] as $rule ) - { - if ( !isset($return['groups'][$rule['rule_id']]) ) - { - $return['groups'][$rule['rule_id']] = array(); - } - $return['groups'][$rule['rule_id']][] = $rule['perm_type']; - } - } - catch ( Exception $e ) - { - $return = array( - 'mode' => 'error', - 'error' => $e->getMessage() - ); - } - - break; - default: - return Array('mode'=>'error','error'=>'Hacking attempt'); - break; - } - } - return $return; - } - - /** - * Same as PageUtils::acl_editor(), but the parms are a JSON string instead of an array. This also returns a JSON string. - * @param string $parms Same as PageUtils::acl_editor/$parms, but should be a valid JSON string. - * @return string - */ - - public static function acl_json($parms = '{ }') - { - global $db, $session, $paths, $template, $plugins; // Common objects - try - { - $parms = enano_json_decode($parms); - } - catch ( Zend_Json_Exception $e ) - { - $parms = array(); - } - $ret = PageUtils::acl_editor($parms); - $ret = enano_json_encode($ret); - return $ret; - } - - /** - * A non-Javascript frontend for the ACL API. - * @param array The request data, if any, this should be in the format required by PageUtils::acl_editor() - */ - - public static function aclmanager($parms) - { - global $db, $session, $paths, $template, $plugins; // Common objects - global $lang; - ob_start(); - // Convenience - $formstart = '
'; - $formend = '
'; - $parms = PageUtils::acl_preprocess($parms); - $response = PageUtils::acl_editor($parms); - $response = PageUtils::acl_postprocess($response); - - //die('
' . htmlspecialchars(print_r($response, true)) . '
'); - - switch($response['mode']) - { - case 'debug': - echo '
' . htmlspecialchars($response['text']) . '
'; - break; - case 'stage1': - echo '

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

-

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

'; - echo $formstart; - echo '

-

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

-

'; - } - - echo '

-

-

' . $template->username_field('data[target_id_user]') . '

-

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

-

- ' . $groupsel . ' -

-
- - - - -
'; - echo $formend; - break; - case 'success': - echo '
- ' . $lang->get('acl_lbl_save_success_title') . '
- ' . $lang->get('acl_lbl_save_success_body', array( 'target_name' => $response['target_name'] )) . '
- ' . $formstart . ' - - - - - - - - - ' . $formend . ' -
'; - break; - case 'delete': - echo '
- ' . $lang->get('acl_lbl_delete_success_title') . '
- ' . $lang->get('acl_lbl_delete_success_body', array('target_name' => $response['target_name'])) . '
- ' . $formstart . ' - - - - - - - - - ' . $formend . ' -
'; - break; - case 'seltarget': - if ( $response['type'] == 'edit' ) - { - echo '

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

'; - } - else - { - echo '

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

'; - } - $type = ( $response['target_type'] == ACL_TYPE_GROUP ) ? $lang->get('acl_target_type_group') : $lang->get('acl_target_type_user'); - $scope = ( $response['page_id'] ) ? ( $response['namespace'] == '__PageGroup' ? $lang->get('acl_scope_type_pagegroup') : $lang->get('acl_scope_type_thispage') ) : $lang->get('acl_scope_type_wholesite'); - $subs = array( - 'target_type' => $type, - 'target' => $response['target_name'], - 'scope_type' => $scope - ); - echo $lang->get('acl_lbl_editwin_body', $subs); - echo $formstart; - $parser = $template->makeParserText( $response['template']['acl_field_begin'] ); - echo $parser->run(); - $parser = $template->makeParserText( $response['template']['acl_field_item'] ); - $cls = 'row2'; - foreach ( $response['acl_types'] as $acl_type => $value ) - { - $vars = Array( - 'FIELD_INHERIT_CHECKED' => '', - 'FIELD_DENY_CHECKED' => '', - 'FIELD_DISALLOW_CHECKED' => '', - 'FIELD_WIKIMODE_CHECKED' => '', - 'FIELD_ALLOW_CHECKED' => '', - ); - $cls = ( $cls == 'row1' ) ? 'row2' : 'row1'; - $vars['ROW_CLASS'] = $cls; - - switch ( $response['current_perms'][$acl_type] ) - { - case 'i': - default: - $vars['FIELD_INHERIT_CHECKED'] = 'checked="checked"'; - break; - case AUTH_ALLOW: - $vars['FIELD_ALLOW_CHECKED'] = 'checked="checked"'; - break; - case AUTH_WIKIMODE: - $vars['FIELD_WIKIMODE_CHECKED'] = 'checked="checked"'; - break; - case AUTH_DISALLOW: - $vars['FIELD_DISALLOW_CHECKED'] = 'checked="checked"'; - break; - case AUTH_DENY: - $vars['FIELD_DENY_CHECKED'] = 'checked="checked"'; - break; - } - $vars['FIELD_NAME'] = 'data[perms][' . $acl_type . ']'; - if ( preg_match('/^([a-z0-9_]+)$/', $response['acl_descs'][$acl_type]) ) - { - $vars['FIELD_DESC'] = $lang->get($response['acl_descs'][$acl_type]); - } - else - { - $vars['FIELD_DESC'] = $response['acl_descs'][$acl_type]; - } - $parser->assign_vars($vars); - echo $parser->run(); - } - $parser = $template->makeParserText( $response['template']['acl_field_end'] ); - echo $parser->run(); - echo '
- - - - - - - ' . ( ( $response['type'] == 'edit' ) ? '  ' : '' ) . ' -
'; - echo $formend; - break; - case 'error': - ob_end_clean(); - die_friendly('Error occurred', '

Error returned by permissions API:

' . htmlspecialchars($response['error']) . '
'); - break; - } - $ret = ob_get_contents(); - ob_end_clean(); - echo - $template->getHeader() . - $ret . - $template->getFooter(); - } - - /** - * Preprocessor to turn the form-submitted data from the ACL editor into something the backend can handle - * @param array The posted data - * @return array - * @access private - */ - - public static function acl_preprocess($parms) - { - if ( !isset($parms['mode']) ) - // Nothing to do - return $parms; - switch ( $parms['mode'] ) - { - case 'seltarget': - - // Who's affected? - $parms['target_type'] = intval( $parms['target_type'] ); - $parms['target_id'] = ( $parms['target_type'] == ACL_TYPE_GROUP ) ? $parms['target_id_grp'] : $parms['target_id_user']; - - case 'save_edit': - case 'save_new': - if ( isset($parms['act_delete_rule']) ) - { - $parms['mode'] = 'delete'; - } - - // Scope (just this page or entire site?) - if ( $parms['scope'] == 'entire_site' || ( $parms['page_id'] == 'false' && $parms['namespace'] == 'false' ) ) - { - $parms['page_id'] = false; - $parms['namespace'] = false; - } - else if ( $parms['scope'] == 'page_group' ) - { - $parms['page_id'] = $parms['pg_id']; - $parms['namespace'] = '__PageGroup'; - } - - break; - } - - if ( isset($parms['act_go_stage1']) ) - { - $parms = array( - 'mode' => 'listgroups' - ); - } - - return $parms; - } - - public static function acl_postprocess($response) - { - if(!isset($response['mode'])) - { - if ( isset($response['groups']) ) - $response['mode'] = 'stage1'; - else - $response = Array( - 'mode' => 'error', - 'error' => 'Invalid action passed by API backend.', - ); - } - return $response; - } - + + /** + * Tell if a username is used or not. + * @param $name the name to check for + * @return string + */ + + public static function checkusername($name) + { + global $db, $session, $paths, $template, $plugins; // Common objects + $name = str_replace('_', ' ', $name); + $q = $db->sql_query('SELECT username FROM ' . table_prefix.'users WHERE username=\'' . $db->escape(rawurldecode($name)) . '\''); + if ( !$q ) + { + die($db->get_error()); + } + if ( $db->numrows() < 1) + { + $db->free_result(); return('good'); + } + else + { + $db->free_result(); return('bad'); + } + } + + /** + * Get the wiki formatting source for a page + * @param $page the full page id (Namespace:Pagename) + * @return string + * @todo (DONE) Make it require a password (just for security purposes) + */ + + public static function getsource($page, $password = false) + { + global $db, $session, $paths, $template, $plugins; // Common objects + if ( !isPage($page) ) + { + return ''; + } + + list($page_id, $namespace) = RenderMan::strToPageID($page); + $ns = namespace_factory($page_id, $namespace); + $cdata = $ns->get_cdata(); + + if ( strlen($cdata['password']) == 40 ) + { + if(!$password || ( $password != $cdata['password'])) + { + return 'invalid_password'; + } + } + + if(!$session->get_permissions('view_source')) // Dependencies handle this for us - this also checks for read privileges + return 'access_denied'; + $pid = RenderMan::strToPageID($page); + if($pid[1] == 'Special' || $pid[1] == 'Admin') + { + die('This type of page (' . $paths->nslist[$pid[1]] . ') cannot be edited because the page source code is not stored in the database.'); + } + + $e = $db->sql_query('SELECT page_text,char_tag FROM ' . table_prefix.'page_text WHERE page_id=\'' . $pid[0] . '\' AND namespace=\'' . $pid[1] . '\''); + if ( !$e ) + { + $db->_die('The page text could not be selected.'); + } + if( $db->numrows() < 1 ) + { + return ''; //$db->_die('There were no rows in the text table that matched the page text query.'); + } + + $r = $db->fetchrow(); + $db->free_result(); + $message = $r['page_text']; + + return htmlspecialchars($message); + } + + /** + * DEPRECATED. Previously returned the full rendered contents of a page. + * @param $page the full page id (Namespace:Pagename) + * @param $send_headers true if the theme headers should be sent (still dependent on current page settings), false otherwise + * @return string + */ + + public static function getpage($page, $send_headers = false, $hist_id = false) + { + die('PageUtils->getpage is deprecated.'); + } + + /** + * Writes page data to the database, after verifying permissions and running the XSS filter + * @param $page_id the page ID + * @param $namespace the namespace + * @param $message the text to save + * @return string + */ + + public static function savepage($page_id, $namespace, $message, $summary = 'No edit summary given', $minor = false) + { + global $db, $session, $paths, $template, $plugins; // Common objects + + $page = new PageProcessor($page_id, $namespace); + $cdata = $page->ns->get_cdata(); + return $page->update_page($message, $summary, $minor, $cdata['page_format']); + } + + /** + * Creates a page, both in memory and in the database. + * @param string $page_id + * @param string $namespace + * @return bool true on success, false on failure + */ + + public static function createPage($page_id, $namespace, $name = false, $visible = 1) + { + global $db, $session, $paths, $template, $plugins; // Common objects + if(in_array($namespace, Array('Special', 'Admin'))) + { + // echo 'Notice: PageUtils::createPage: You can\'t create a special page in the database
'; + return 'You can\'t create a special page in the database'; + } + + if(!isset($paths->nslist[$namespace])) + { + // echo 'Notice: PageUtils::createPage: Couldn\'t look up the namespace
'; + return 'Couldn\'t look up the namespace'; + } + + $pname = $paths->nslist[$namespace] . $page_id; + if(isPage($pname)) + { + // echo 'Notice: PageUtils::createPage: Page already exists
'; + return 'Page already exists'; + } + + if(!$session->get_permissions('create_page')) + { + // echo 'Notice: PageUtils::createPage: Not authorized to create pages
'; + return 'Not authorized to create pages'; + } + + if($session->user_level < USER_LEVEL_ADMIN && $namespace == 'System') + { + // echo 'Notice: PageUtils::createPage: Not authorized to create system messages
'; + return 'Not authorized to create system messages'; + } + + if ( substr($page_id, 0, 8) == 'Project:' ) + { + // echo 'Notice: PageUtils::createPage: Prefix "Project:" is reserved
'; + return 'The prefix "Project:" is reserved for a parser shortcut; if a page was created using this prefix, it would not be possible to link to it.'; + } + + /* + // Dunno why this was here. Enano can handle more flexible names than this... + $regex = '#^([A-z0-9 _\-\.\/\!\@\(\)]*)$#is'; + if(!preg_match($regex, $name)) + { + //echo 'Notice: PageUtils::createPage: Name contains invalid characters
'; + return 'Name contains invalid characters'; + } + */ + + $page_id = dirtify_page_id($page_id); + + if ( !$name ) + $name = str_replace('_', ' ', $page_id); + + $page_id = sanitize_page_id( $page_id ); + + $prot = ( $namespace == 'System' ) ? 1 : 0; + + $ips = array( + 'ip' => array(), + 'u' => array() + ); + + $page_data = Array( + 'name'=>$name, + 'urlname'=>$page_id, + 'namespace'=>$namespace, + 'special'=>0,'visible'=>1,'comments_on'=>0,'protected'=>$prot,'delvotes'=>0,'delvote_ips'=>serialize($ips),'wiki_mode'=>2, + ); + + // die('PageUtils::createpage: Creating page with this data:
' . print_r($page_data, true) . '
'); + + $paths->add_page($page_data); + + $qa = $db->sql_query('INSERT INTO ' . table_prefix.'pages(name,urlname,namespace,visible,protected,delvote_ips) VALUES(\'' . $db->escape($name) . '\', \'' . $db->escape($page_id) . '\', \'' . $namespace . '\', '. ( $visible ? '1' : '0' ) .', ' . $prot . ', \'' . $db->escape(serialize($ips)) . '\');'); + $qb = $db->sql_query('INSERT INTO ' . table_prefix.'page_text(page_id,namespace) VALUES(\'' . $db->escape($page_id) . '\', \'' . $namespace . '\');'); + $qc = $db->sql_query('INSERT INTO ' . table_prefix.'logs(time_id,date_string,log_type,action,author,author_uid,page_id,namespace) VALUES('.time().', \'DEPRECATED\', \'page\', \'create\', \'' . $session->username . '\', ' . $session->user_id . ', \'' . $db->escape($page_id) . '\', \'' . $namespace . '\');'); + + if($qa && $qb && $qc) + return 'good'; + else + { + return $db->get_error(); + } + } + + /** + * Sets the protection level on a page. + * @param $page_id string the page ID + * @param $namespace string the namespace + * @param $level int level of protection - 0 is off, 1 is full, 2 is semi + * @param $reason string why the page is being (un)protected + * @return string - "good" on success, in all other cases, an error string (on query failure, calls $db->_die() ) + */ + public static function protect($page_id, $namespace, $level, $reason) + { + global $db, $session, $paths, $template, $plugins; // Common objects + + $page = new PageProcessor($page_id, $namespace); + return $page->protect_page($level, $reason); + } + + /** + * Generates an HTML table with history information in it. + * @param string the page ID + * @param string the namespace + * @param string page password + * @return string + */ + + public static function histlist($page_id, $namespace, $password = false) + { + global $db, $session, $paths, $template, $plugins; // Common objects + global $lang; + + if(!$session->get_permissions('history_view')) + return 'Access denied'; + + ob_start(); + + $pname = $paths->get_pathskey($page_id, $namespace); + $ns = namespace_factory($page_id, $namespace); + $cdata = $ns->get_cdata(); + + if ( !isPage($pname) ) + { + return 'DNE'; + } + + if ( isPage($pname) ) + { + $password_exists = ( !empty($cdata['password']) && $cdata['password'] !== sha1('') ); + if ( $password_exists && $password !== $cdata['password'] ) + { + return '

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

'; + } + } + + $wiki = ( ( $cdata['wiki_mode'] == 2 && getConfig('wiki_mode') == '1') || $cdata['wiki_mode'] == 1) ? true : false; + $prot = ( ( $cdata['protected'] == 2 && $session->user_logged_in && $session->reg_time + 60*60*24*4 < time() ) || $cdata['protected'] == 1) ? true : false; + + $q = 'SELECT log_id,time_id,date_string,page_id,namespace,author,author_uid,u.username,edit_summary,minor_edit FROM ' . table_prefix . "logs AS l\n" + . " LEFT JOIN " . table_prefix . "users AS u\n" + . " ON ( u.user_id = l.author_uid OR u.user_id IS NULL )\n" + . " WHERE log_type='page' AND action='edit' AND page_id='$page_id' AND namespace='$namespace' AND is_draft != 1 ORDER BY time_id DESC;"; + + if ( !($q = $db->sql_query($q)) ) + $db->_die('The history data for the page "' . $paths->cpage['name'] . '" could not be selected.'); + + echo $lang->get('history_page_subtitle') . ' +

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

'; + $numrows = $db->numrows(); + if ( $numrows < 1 ) + { + echo $lang->get('history_no_entries'); + } + else + { + echo '
+ + ' . ( urlSeparator == '&' ? '' : '' ) . ' + ' . ( $session->sid_super ? '' : '') . ' + +
  +
+ + + + + + + + + '."\n"."\n"; + $cls = 'row2'; + $ticker = 0; + + while ( $r = $db->fetchrow($q) ) + { + + $ticker++; + + if($cls == 'row2') $cls = 'row1'; + else $cls = 'row2'; + + echo ''."\n"; + + // Diff selection + if($ticker == 1) + { + $s1 = ''; + $s2 = 'checked="checked" '; + } + elseif($ticker == 2) + { + $s1 = 'checked="checked" '; + $s2 = ''; + } + else + { + $s1 = ''; + $s2 = ''; + } + if($ticker > 1) echo ''."\n"; else echo ''; + if($ticker < $numrows) echo ''."\n"; else echo ''; + + // Date and time + echo ''."\n"; + + // User + $real_username = $r['author_uid'] > 1 && !empty($r['username']) ? $r['username'] : $r['author']; + $rank_info = $session->get_user_rank($r['author_uid']); + if ( $session->get_permissions('mod_misc') && is_valid_ip($r['author']) && $r['author_uid'] == 1 ) + { + $rc = ' style="cursor: pointer;" title="' . $lang->get('history_tip_rdns') . '" onclick="ajaxReverseDNS(this, \'' . $r['author'] . '\');"'; + } + else + { + $rc = ''; + } + echo ''."\n"; + + // Edit summary + if ( $r['edit_summary'] == 'Automatic backup created when logs were purged' ) + { + $r['edit_summary'] = $lang->get('history_summary_clearlogs'); + } + echo ''."\n"; + + // Minor edit + echo ''."\n"; + + // Actions! + echo ''."\n"; + echo ''."\n"; + echo ''."\n"; + + echo ''."\n"."\n"; + + } + echo '
' . $lang->get('history_col_diff') . '' . $lang->get('history_col_datetime') . '' . $lang->get('history_col_user') . '' . $lang->get('history_col_summary') . '' . $lang->get('history_col_minor') . '' . $lang->get('history_col_actions') . '
' . enano_date(ED_DATE | ED_TIME, intval($r['time_id'])) . 'nslist['User'] . sanitize_page_id($real_username)) ) + { + echo 'class="wikilink-nonexistent"'; + } + echo 'style="' . $rank_info['rank_style'] . '">' . htmlspecialchars($real_username) . '' . $r['edit_summary'] . ''. (( $r['minor_edit'] ) ? 'M' : '' ) .'' . $lang->get('history_action_view') . '' . $lang->get('history_action_contrib') . '' . $lang->get('history_action_restore') . '
+
+
+ + +
+ '; + } + $db->free_result(); + echo '

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

'; + + $sql = 'SELECT log_id,action,time_id,date_string,page_id,namespace,author,author_uid,u.username,edit_summary,minor_edit FROM ' . table_prefix . "logs AS l\n" + . " LEFT JOIN " . table_prefix . "users AS u\n" + . " ON ( u.user_id = l.author_uid OR u.user_id IS NULL )\n" + . " WHERE log_type='page' AND action!='edit' AND page_id='$page_id' AND namespace='$namespace' AND is_draft != 1 ORDER BY time_id DESC;"; + + if ( !( $q = $db->sql_query($sql)) ) + { + $db->_die('The history data for the page "' . htmlspecialchars($paths->cpage['name']) . '" could not be selected.'); + } + if ( $db->numrows() < 1 ) + { + echo $lang->get('history_no_entries'); + } + else + { + + echo '
+ + + + + + + + '; + $cls = 'row2'; + while($r = $db->fetchrow($q)) { + + if($cls == 'row2') $cls = 'row1'; + else $cls = 'row2'; + + echo ''; + + // Date and time + echo ''; + + // User + $real_username = $r['author_uid'] > 1 && !empty($r['username']) ? $r['username'] : $r['author']; + $rank_info = $session->get_user_rank($r['author_uid']); + if ( $session->get_permissions('mod_misc') && is_valid_ip($r['author']) && $r['author_uid'] == 1 ) + { + $rc = ' style="cursor: pointer;" title="' . $lang->get('history_tip_rdns') . '" onclick="ajaxReverseDNS(this, \'' . $r['author'] . '\');"'; + } + else + { + $rc = ''; + } + echo ''."\n"; + + + // Minor edit + echo ''; + + // Action taken + echo ''; + + // Actions! + echo ''; + echo ''; + + echo ''; + } + echo '
' . $lang->get('history_col_datetime') . '' . $lang->get('history_col_user') . '' . $lang->get('history_col_minor') . '' . $lang->get('history_col_action_taken') . '' . $lang->get('history_col_extra') . '
' . enano_date(ED_DATE | ED_TIME, intval($r['time_id'])) . 'nslist['User'] . sanitize_page_id($real_username)) ) + { + echo 'class="wikilink-nonexistent"'; + } + echo 'style="' . $rank_info['rank_style'] . '">' . htmlspecialchars($real_username) . ''. (( $r['minor_edit'] ) ? 'M' : '' ) .''; + // Some of these are sanitized at insert-time. Others follow the newer Enano policy of stripping HTML at runtime. + if ($r['action']=='prot') echo $lang->get('history_log_protect') . '' . $lang->get('history_extra_reason') . ' ' . ( $r['edit_summary'] === '__REVERSION__' ? $lang->get('history_extra_protection_reversion') : htmlspecialchars($r['edit_summary']) ); + elseif($r['action']=='unprot') echo $lang->get('history_log_unprotect') . '' . $lang->get('history_extra_reason') . ' ' . ( $r['edit_summary'] === '__REVERSION__' ? $lang->get('history_extra_protection_reversion') : htmlspecialchars($r['edit_summary']) ); + elseif($r['action']=='semiprot') echo $lang->get('history_log_semiprotect') . '' . $lang->get('history_extra_reason') . ' ' . ( $r['edit_summary'] === '__REVERSION__' ? $lang->get('history_extra_protection_reversion') : htmlspecialchars($r['edit_summary']) ); + elseif($r['action']=='rename') echo $lang->get('history_log_rename') . '' . $lang->get('history_extra_oldtitle') . ' '.htmlspecialchars($r['edit_summary']); + elseif($r['action']=='create') echo $lang->get('history_log_create') . ''; + elseif($r['action']=='delete') echo $lang->get('history_log_delete') . '' . $lang->get('history_extra_reason') . ' ' . $r['edit_summary']; + elseif($r['action']=='reupload') echo $lang->get('history_log_uploadnew') . '' . $lang->get('history_extra_reason') . ' ' . ( $r['edit_summary'] === '__ROLLBACK__' ? $lang->get('history_extra_upload_reversion') : htmlspecialchars($r['edit_summary']) ); + elseif($r['action']=='votereset')echo $lang->get('history_log_votereset') . '' . $lang->get('history_extra_numvotes') . ' ' . $r['edit_summary']; + echo '' . $lang->get('history_action_contrib') . '' . $lang->get('history_action_revert') . '
'; + } + $db->free_result(); + $ret = ob_get_contents(); + ob_end_clean(); + return $ret; + } + + /** + * Rolls back a logged action + * @param $id the time ID, a.k.a. the primary key in the logs table + * @return string + */ + + public static function rollback($id) + { + global $db, $session, $paths, $template, $plugins; // Common objects + global $lang; + + // placeholder + return 'PageUtils->rollback() is deprecated - use PageProcessor instead.'; + } + + /** + * Posts a comment. + * @param $page_id the page ID + * @param $namespace the namespace + * @param $name the name of the person posting, defaults to current username/IP + * @param $subject the subject line of the comment + * @param $text the comment text + * @return string javascript code + */ + + public static function addcomment($page_id, $namespace, $name, $subject, $text, $captcha_code = false, $captcha_id = false) + { + global $db, $session, $paths, $template, $plugins; // Common objects + $_ob = ''; + if(!$session->get_permissions('post_comments')) + return 'Access denied'; + if(getConfig('comments_need_login') == '2' && !$session->user_logged_in) _die('Access denied to post comments: you need to be logged in first.'); + if(getConfig('comments_need_login') == '1' && !$session->user_logged_in) + { + if(!$captcha_code || !$captcha_id) _die('BUG: PageUtils::addcomment: no CAPTCHA data passed to method'); + $result = $session->get_captcha($captcha_id); + if(strtolower($captcha_code) != strtolower($result)) _die('The confirmation code you entered was incorrect.'); + } + $text = RenderMan::preprocess_text($text); + $name = $session->user_logged_in ? RenderMan::preprocess_text($session->username) : RenderMan::preprocess_text($name); + $subj = RenderMan::preprocess_text($subject); + if(getConfig('approve_comments', '0')=='1') $appr = '0'; else $appr = '1'; + $q = 'INSERT INTO ' . table_prefix.'comments(page_id,namespace,subject,comment_data,name,user_id,approved,time) VALUES(\'' . $page_id . '\',\'' . $namespace . '\',\'' . $subj . '\',\'' . $text . '\',\'' . $name . '\',' . $session->user_id . ',' . $appr . ','.time().')'; + $e = $db->sql_query($q); + if(!$e) die('alert(unescape(\''.rawurlencode('Error inserting comment data: '.$db->get_error().'\n\nQuery:\n' . $q) . '\'))'); + else $_ob .= '
Your comment has been posted.
'; + return PageUtils::comments($page_id, $namespace, false, Array(), $_ob); + } + + /** + * Generates partly-compiled HTML/Javascript code to be eval'ed by the user's browser to display comments + * @param $page_id the page ID + * @param $namespace the namespace + * @param $action administrative action to perform, default is false + * @param $flags additional info for $action, shouldn't be used except when deleting/approving comments, etc. + * @param $_ob text to prepend to output, used by PageUtils::addcomment + * @return array + * @access private + */ + + public static function comments_raw($page_id, $namespace, $action = false, $flags = Array(), $_ob = '') + { + global $db, $session, $paths, $template, $plugins; // Common objects + global $lang; + + $pname = $paths->nslist[$namespace] . $page_id; + $template->init_vars(); + + ob_start(); + + if($action && $session->get_permissions('mod_comments')) // Nip hacking attempts in the bud + { + switch($action) { + case "delete": + if(isset($flags['id'])) + { + $q = 'DELETE FROM ' . table_prefix.'comments WHERE page_id=\'' . $page_id . '\' AND namespace=\'' . $namespace . '\' AND comment_id='.intval($flags['id']).' LIMIT 1;'; + } else { + $n = $db->escape($flags['name']); + $s = $db->escape($flags['subj']); + $t = $db->escape($flags['text']); + $q = 'DELETE FROM ' . table_prefix.'comments WHERE page_id=\'' . $page_id . '\' AND namespace=\'' . $namespace . '\' AND name=\'' . $n . '\' AND subject=\'' . $s . '\' AND comment_data=\'' . $t . '\' LIMIT 1;'; + } + $e=$db->sql_query($q); + if(!$e) die('alert(unesape(\''.rawurlencode('Error during query: '.$db->get_error().'\n\nQuery:\n' . $q) . '\'));'); + break; + case "approve": + if(isset($flags['id'])) + { + $where = 'comment_id='.intval($flags['id']); + } else { + $n = $db->escape($flags['name']); + $s = $db->escape($flags['subj']); + $t = $db->escape($flags['text']); + $where = 'name=\'' . $n . '\' AND subject=\'' . $s . '\' AND comment_data=\'' . $t . '\''; + } + $q = 'SELECT approved FROM ' . table_prefix.'comments WHERE page_id=\'' . $page_id . '\' AND namespace=\'' . $namespace . '\' AND ' . $where . ' LIMIT 1;'; + $e = $db->sql_query($q); + if(!$e) die('alert(unesape(\''.rawurlencode('Error selecting approval status: '.$db->get_error().'\n\nQuery:\n' . $q) . '\'));'); + $r = $db->fetchrow(); + $db->free_result(); + $a = ( $r['approved'] ) ? '0' : '1'; + $q = 'UPDATE ' . table_prefix.'comments SET approved=' . $a . ' WHERE page_id=\'' . $page_id . '\' AND namespace=\'' . $namespace . '\' AND ' . $where . ';'; + $e=$db->sql_query($q); + if(!$e) die('alert(unesape(\''.rawurlencode('Error during query: '.$db->get_error().'\n\nQuery:\n' . $q) . '\'));'); + if($a=='1') $v = $lang->get('comment_btn_mod_unapprove'); + else $v = $lang->get('comment_btn_mod_approve'); + echo 'document.getElementById("mdgApproveLink'.intval($_GET['id']).'").innerHTML="' . $v . '";'; + break; + } + } + + if(!defined('ENANO_TEMPLATE_LOADED')) + { + $template->load_theme($session->theme, $session->style); + } + + $tpl = $template->makeParser('comment.tpl'); + + $e = $db->sql_query('SELECT * FROM ' . table_prefix.'comments WHERE page_id=\'' . $page_id . '\' AND namespace=\'' . $namespace . '\' AND approved=0;'); + if(!$e) $db->_die('The comment text data could not be selected.'); + $num_unapp = $db->numrows(); + $db->free_result(); + $e = $db->sql_query('SELECT * FROM ' . table_prefix.'comments WHERE page_id=\'' . $page_id . '\' AND namespace=\'' . $namespace . '\' AND approved=1;'); + if(!$e) $db->_die('The comment text data could not be selected.'); + $num_app = $db->numrows(); + $db->free_result(); + $lq = $db->sql_query('SELECT c.comment_id,c.subject,c.name,c.comment_data,c.approved,c.time,c.user_id,c.ip_address,u.user_level,u.email,u.signature,u.user_has_avatar,u.avatar_type + FROM ' . table_prefix.'comments AS c + LEFT JOIN ' . table_prefix.'users AS u + ON c.user_id=u.user_id + WHERE page_id=\'' . $page_id . '\' + AND namespace=\'' . $namespace . '\' ORDER BY c.time ASC;'); + if(!$lq) _die('The comment text data could not be selected. '.$db->get_error()); + $_ob .= '

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

'; + + $n = ( $session->get_permissions('mod_comments')) ? $db->numrows() : $num_app; + + $subst = array( + 'num_comments' => $n, + 'page_type' => $template->namespace_string + ); + + $_ob .= '

'; + $_ob .= ( $n == 0 ) ? $lang->get('comment_msg_count_zero', $subst) : ( $n == 1 ? $lang->get('comment_msg_count_one', $subst) : $lang->get('comment_msg_count_plural', $subst) ); + + if ( $session->get_permissions('mod_comments') && $num_unapp > 0 ) + { + $_ob .= ' ' . $lang->get('comment_msg_count_unapp_mod', array( 'num_unapp' => $num_unapp )) . ''; + } + else if ( !$session->get_permissions('mod_comments') && $num_unapp > 0 ) + { + $ls = ( $num_unapp == 1 ) ? 'comment_msg_count_unapp_one' : 'comment_msg_count_unapp_plural'; + $_ob .= ' ' . $lang->get($ls, array( 'num_unapp' => $num_unapp )) . ''; + } + $_ob .= '

'; + $list = 'list = { '; + // _die(htmlspecialchars($ttext)); + $i = -1; + while ( $row = $db->fetchrow($lq) ) + { + $i++; + $strings = Array(); + $bool = Array(); + if ( $session->get_permissions('mod_comments') || $row['approved'] == COMMENT_APPROVED ) + { + $list .= $i . ' : { \'comment\' : unescape(\''.rawurlencode($row['comment_data']).'\'), \'name\' : unescape(\''.rawurlencode($row['name']).'\'), \'subject\' : unescape(\''.rawurlencode($row['subject']).'\'), }, '; + + // Comment ID (used in the Javascript apps) + $strings['ID'] = (string)$i; + + // Determine the name, and whether to link to the user page or not + $name = ''; + if($row['user_id'] > 1) $name .= ''; + $name .= $row['name']; + if($row['user_id'] > 1) $name .= ''; + $strings['NAME'] = $name; unset($name); + + // Subject + $s = $row['subject']; + if(!$row['approved']) $s .= ' ' . $lang->get('comment_msg_note_unapp') . ''; + $strings['SUBJECT'] = $s; + + // Date and time + $strings['DATETIME'] = enano_date(ED_DATE | ED_TIME, $row['time']); + + // User level + switch($row['user_level']) + { + default: + case USER_LEVEL_GUEST: + $l = $lang->get('user_type_guest'); + break; + case USER_LEVEL_MEMBER: + case USER_LEVEL_CHPREF: + $l = $lang->get('user_type_member'); + break; + case USER_LEVEL_MOD: + $l = $lang->get('user_type_mod'); + break; + case USER_LEVEL_ADMIN: + $l = $lang->get('user_type_admin'); + break; + } + $strings['USER_LEVEL'] = $l; unset($l); + + // The actual comment data + $strings['DATA'] = RenderMan::render($row['comment_data']); + + if($session->get_permissions('edit_comments')) + { + // Edit link + $strings['EDIT_LINK'] = '' . $lang->get('comment_btn_edit') . ''; + + // Delete link + $strings['DELETE_LINK'] = '' . $lang->get('comment_btn_delete') . ''; + } + else + { + // Edit link + $strings['EDIT_LINK'] = ''; + + // Delete link + $strings['DELETE_LINK'] = ''; + } + + // Send PM link + $strings['SEND_PM_LINK'] = ( $session->user_logged_in && $row['user_id'] > 1 ) ? '' . $lang->get('comment_btn_send_privmsg') . '
' : ''; + + // Add Buddy link + $strings['ADD_BUDDY_LINK'] = ( $session->user_logged_in && $row['user_id'] > 1 ) ? '' . $lang->get('comment_btn_add_buddy') . '' : ''; + + // Mod links + $applink = ''; + $applink .= ''; + if($row['approved']) $applink .= $lang->get('comment_btn_mod_unapprove'); + else $applink .= $lang->get('comment_btn_mod_approve'); + $applink .= ''; + $strings['MOD_APPROVE_LINK'] = $applink; unset($applink); + $strings['MOD_DELETE_LINK'] = '' . $lang->get('comment_btn_mod_delete') . ''; + $strings['MOD_IP_LINK'] = '' . ( ( empty($row['ip_address']) ) ? $lang->get('comment_btn_mod_ip_missing') : $lang->get('comment_btn_mod_ip_notimplemented') ) . ''; + + // Signature + $strings['SIGNATURE'] = ''; + if($row['signature'] != '') $strings['SIGNATURE'] = RenderMan::render($row['signature']); + + // Avatar + if ( $row['user_has_avatar'] == 1 ) + { + $bool['user_has_avatar'] = true; + $strings['AVATAR_ALT'] = $lang->get('usercp_avatar_image_alt', array('username' => $row['name'])); + $strings['AVATAR_URL'] = make_avatar_url(intval($row['user_id']), $row['avatar_type'], $row['email']); + $strings['USERPAGE_LINK'] = makeUrlNS('User', $row['name']); + } + + $bool['auth_mod'] = ($session->get_permissions('mod_comments')) ? true : false; + $bool['can_edit'] = ( ( $session->user_logged_in && $row['name'] == $session->username && $session->get_permissions('edit_comments') ) || $session->get_permissions('mod_comments') ) ? true : false; + $bool['signature'] = ( $strings['SIGNATURE'] == '' ) ? false : true; + + // Done processing and compiling, now let's cook it into HTML + $tpl->assign_vars($strings); + $tpl->assign_bool($bool); + $_ob .= $tpl->run(); + } + } + if(getConfig('comments_need_login') != '2' || $session->user_logged_in) + { + if($session->get_permissions('post_comments')) + { + $_ob .= '

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

'; + $_ob .= $lang->get('comment_postform_blurb'); + if(getConfig('approve_comments', '0')=='1') $_ob .= ' ' . $lang->get('comment_postform_blurb_unapp'); + if(getConfig('comments_need_login') == '1' && !$session->user_logged_in) + { + $_ob .= ' ' . $lang->get('comment_postform_blurb_captcha'); + } + $sn = $session->user_logged_in ? $session->username . '' : ''; + $_ob .= ' +
+
+ + + '; + if(getConfig('comments_need_login') == '1' && !$session->user_logged_in) + { + $session->kill_captcha(); + $captcha = $session->make_captcha(); + $_ob .= ''; + } + $_ob .= ' + + +
' . $lang->get('comment_postform_field_name') . '' . $sn . '
' . $lang->get('comment_postform_field_subject') . '
' . $lang->get('comment_postform_field_captcha_title') . '
' . $lang->get('comment_postform_field_captcha_blurb') . '
Visual confirmation
' . $lang->get('comment_postform_field_captcha_label') . '
' . $lang->get('comment_postform_field_comment') . '
+
+
'; + } + } else { + // FIXME: l10n + $_ob .= '

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

You need to be logged in to post comments. Log in

'; + } + $list .= '};'; + echo 'document.getElementById(\'ajaxEditContainer\').innerHTML = unescape(\''. rawurlencode($_ob) .'\'); + ' . $list; + echo 'Fat.fade_all(); document.getElementById(\'mdgCommentForm\').style.display = \'none\'; document.getElementById(\'mdgCommentFormLink\').style.display="inline";'; + + $ret = ob_get_contents(); + ob_end_clean(); + return Array($ret, $_ob); + + } + + /** + * Generates ready-to-execute Javascript code to be eval'ed by the user's browser to display comments + * @param $page_id the page ID + * @param $namespace the namespace + * @param $action administrative action to perform, default is false + * @param $flags additional info for $action, shouldn't be used except when deleting/approving comments, etc. + * @param $_ob text to prepend to output, used by PageUtils::addcomment + * @return string + */ + + public static function comments($page_id, $namespace, $action = false, $id = -1, $_ob = '') + { + global $db, $session, $paths, $template, $plugins; // Common objects + $r = PageUtils::comments_raw($page_id, $namespace, $action, $id, $_ob); + return $r[0]; + } + + /** + * Generates HTML code for comments - used in browser compatibility mode + * @param $page_id the page ID + * @param $namespace the namespace + * @param $action administrative action to perform, default is false + * @param $flags additional info for $action, shouldn't be used except when deleting/approving comments, etc. + * @param $_ob text to prepend to output, used by PageUtils::addcomment + * @return string + */ + + public static function comments_html($page_id, $namespace, $action = false, $id = -1, $_ob = '') + { + global $db, $session, $paths, $template, $plugins; // Common objects + $r = PageUtils::comments_raw($page_id, $namespace, $action, $id, $_ob); + return $r[1]; + } + + /** + * Updates comment data. + * @param $page_id the page ID + * @param $namespace the namespace + * @param $subject new subject + * @param $text new text + * @param $old_subject the old subject, unprocessed and identical to the value in the DB + * @param $old_text the old text, unprocessed and identical to the value in the DB + * @param $id the javascript list ID, used internally by the client-side app + * @return string + */ + + public static function savecomment($page_id, $namespace, $subject, $text, $old_subject, $old_text, $id = -1) + { + global $db, $session, $paths, $template, $plugins; // Common objects + if(!$session->get_permissions('edit_comments')) + return 'result="BAD";error="Access denied"'; + // Avoid SQL injection + $old_text = $db->escape($old_text); + $old_subject = $db->escape($old_subject); + // Safety check - username/login + if(!$session->get_permissions('mod_comments')) // allow mods to edit comments + { + if(!$session->user_logged_in) _die('AJAX comment save safety check failed because you are not logged in. Sometimes this can happen because you are using a browser that does not send cookies as part of AJAX requests.

Please log in and try again.'); + $q = 'SELECT c.name FROM ' . table_prefix.'comments c, ' . table_prefix.'users u WHERE comment_data=\'' . $old_text . '\' AND subject=\'' . $old_subject . '\' AND page_id=\'' . $page_id . '\' AND namespace=\'' . $namespace . '\' AND u.user_id=c.user_id;'; + $s = $db->sql_query($q); + if(!$s) _die('SQL error during safety check: '.$db->get_error().'

Attempted SQL:
'.htmlspecialchars($q).'
'); + $r = $db->fetchrow($s); + $db->free_result(); + if($db->numrows() < 1 || $r['name'] != $session->username) _die('Safety check failed, probably due to a hacking attempt.'); + } + $s = RenderMan::preprocess_text($subject); + $t = RenderMan::preprocess_text($text); + $sql = 'UPDATE ' . table_prefix.'comments SET subject=\'' . $s . '\',comment_data=\'' . $t . '\' WHERE comment_data=\'' . $old_text . '\' AND subject=\'' . $old_subject . '\' AND page_id=\'' . $page_id . '\' AND namespace=\'' . $namespace . '\''; + $result = $db->sql_query($sql); + if($result) + { + return 'result="GOOD"; + list[' . $id . '][\'subject\'] = unescape(\''.str_replace('%5Cn', '%0A', rawurlencode(str_replace('{{EnAnO:Newline}}', '\\n', stripslashes(str_replace('\\n', '{{EnAnO:Newline}}', $s))))).'\'); + list[' . $id . '][\'comment\'] = unescape(\''.str_replace('%5Cn', '%0A', rawurlencode(str_replace('{{EnAnO:Newline}}', '\\n', stripslashes(str_replace('\\n', '{{EnAnO:Newline}}', $t))))).'\'); id = ' . $id . '; + s = unescape(\''.rawurlencode($s).'\'); + t = unescape(\''.str_replace('%5Cn', '
', rawurlencode(RenderMan::render(str_replace('{{EnAnO:Newline}}', "\n", stripslashes(str_replace('\\n', '{{EnAnO:Newline}}', $t)))))).'\');'; + } + else + { + return 'result="BAD"; error=unescape("'.rawurlencode('Enano encountered a problem whilst saving the comment. + Performed SQL: + ' . $sql . ' + + Error returned by MySQL: '.$db->get_error()).'");'; + } + } + + /** + * Updates comment data using the comment_id column instead of the old, messy way + * @param $page_id the page ID + * @param $namespace the namespace + * @param $subject new subject + * @param $text new text + * @param $id the comment ID (primary key in enano_comments table) + * @return string + */ + + public static function savecomment_neater($page_id, $namespace, $subject, $text, $id) + { + global $db, $session, $paths, $template, $plugins; // Common objects + if(!is_int($id)) die('PageUtils::savecomment: $id is not an integer, aborting for safety'); + if(!$session->get_permissions('edit_comments')) + return 'Access denied'; + // Safety check - username/login + if(!$session->get_permissions('mod_comments')) // allow mods to edit comments + { + if(!$session->user_logged_in) _die('AJAX comment save safety check failed because you are not logged in. Sometimes this can happen because you are using a browser that does not send cookies as part of AJAX requests.

Please log in and try again.'); + $q = 'SELECT c.name FROM ' . table_prefix.'comments c, ' . table_prefix.'users u WHERE comment_id=' . $id . ' AND page_id=\'' . $page_id . '\' AND namespace=\'' . $namespace . '\' AND u.user_id=c.user_id;'; + $s = $db->sql_query($q); + if(!$s) _die('SQL error during safety check: '.$db->get_error().'

Attempted SQL:
'.htmlspecialchars($q).'
'); + $r = $db->fetchrow($s); + if($db->numrows() < 1 || $r['name'] != $session->username) _die('Safety check failed, probably due to a hacking attempt.'); + $db->free_result(); + } + $s = RenderMan::preprocess_text($subject); + $t = RenderMan::preprocess_text($text); + $sql = 'UPDATE ' . table_prefix.'comments SET subject=\'' . $s . '\',comment_data=\'' . $t . '\' WHERE comment_id=' . $id . ' AND page_id=\'' . $page_id . '\' AND namespace=\'' . $namespace . '\''; + $result = $db->sql_query($sql); + if($result) + return 'good'; + else return 'Enano encountered a problem whilst saving the comment. + Performed SQL: + ' . $sql . ' + + Error returned by MySQL: '.$db->get_error(); + } + + /** + * Deletes a comment. + * @param $page_id the page ID + * @param $namespace the namespace + * @param $name the name the user posted under + * @param $subj the subject of the comment to be deleted + * @param $text the text of the comment to be deleted + * @param $id the javascript list ID, used internally by the client-side app + * @return string + */ + + public static function deletecomment($page_id, $namespace, $name, $subj, $text, $id) + { + global $db, $session, $paths, $template, $plugins; // Common objects + + if(!$session->get_permissions('edit_comments')) + return 'alert("Access to delete/edit comments is denied");'; + + if(!preg_match('#^([0-9]+)$#', (string)$id)) die('$_GET[id] is improperly formed.'); + $n = $db->escape($name); + $s = $db->escape($subj); + $t = $db->escape($text); + + // Safety check - username/login + if(!$session->get_permissions('mod_comments')) // allows mods to delete comments + { + if(!$session->user_logged_in) _die('AJAX comment save safety check failed because you are not logged in. Sometimes this can happen because you are using a browser that does not send cookies as part of AJAX requests.

Please log in and try again.'); + $q = 'SELECT c.name FROM ' . table_prefix.'comments c, ' . table_prefix.'users u WHERE comment_data=\'' . $t . '\' AND subject=\'' . $s . '\' AND page_id=\'' . $page_id . '\' AND namespace=\'' . $namespace . '\' AND u.user_id=c.user_id;'; + $s = $db->sql_query($q); + if(!$s) _die('SQL error during safety check: '.$db->get_error().'

Attempted SQL:
'.htmlspecialchars($q).'
'); + $r = $db->fetchrow($s); + if($db->numrows() < 1 || $r['name'] != $session->username) _die('Safety check failed, probably due to a hacking attempt.'); + $db->free_result(); + } + $q = 'DELETE FROM ' . table_prefix.'comments WHERE page_id=\'' . $page_id . '\' AND namespace=\'' . $namespace . '\' AND name=\'' . $n . '\' AND subject=\'' . $s . '\' AND comment_data=\'' . $t . '\' LIMIT 1;'; + $e=$db->sql_query($q); + if(!$e) return('alert(unesape(\''.rawurlencode('Error during query: '.$db->get_error().'\n\nQuery:\n' . $q) . '\'));'); + return('good'); + } + + /** + * Deletes a comment in a cleaner fashion. + * @param $page_id the page ID + * @param $namespace the namespace + * @param $id the comment ID (primary key) + * @return string + */ + + public static function deletecomment_neater($page_id, $namespace, $id) + { + global $db, $session, $paths, $template, $plugins; // Common objects + + if(!preg_match('#^([0-9]+)$#', (string)$id)) die('$_GET[id] is improperly formed.'); + + if(!$session->get_permissions('edit_comments')) + return 'alert("Access to delete/edit comments is denied");'; + + // Safety check - username/login + if(!$session->get_permissions('mod_comments')) // allows mods to delete comments + { + if(!$session->user_logged_in) _die('AJAX comment save safety check failed because you are not logged in. Sometimes this can happen because you are using a browser that does not send cookies as part of AJAX requests.

Please log in and try again.'); + $q = 'SELECT c.name FROM ' . table_prefix.'comments c, ' . table_prefix.'users u WHERE comment_id=' . $id . ' AND page_id=\'' . $page_id . '\' AND namespace=\'' . $namespace . '\' AND u.user_id=c.user_id;'; + $s = $db->sql_query($q); + if(!$s) _die('SQL error during safety check: '.$db->get_error().'

Attempted SQL:
'.htmlspecialchars($q).'
'); + $r = $db->fetchrow($s); + if($db->numrows() < 1 || $r['name'] != $session->username) _die('Safety check failed, probably due to a hacking attempt.'); + $db->free_result(); + } + $q = 'DELETE FROM ' . table_prefix.'comments WHERE page_id=\'' . $page_id . '\' AND namespace=\'' . $namespace . '\' AND comment_id=' . $id . ' LIMIT 1;'; + $e=$db->sql_query($q); + if(!$e) return('alert(unesape(\''.rawurlencode('Error during query: '.$db->get_error().'\n\nQuery:\n' . $q) . '\'));'); + return('good'); + } + + /** + * Renames a page. + * @param $page_id the page ID + * @param $namespace the namespace + * @param $name the new name for the page + * @return string error string or success message + */ + + public static function rename($page_id, $namespace, $name) + { + global $db, $session, $paths, $template, $plugins; // Common objects + global $lang; + + $page = new PageProcessor($page_id, $namespace); + return $page->rename_page($name); + } + + /** + * Flushes (clears) the action logs for a given page + * @param $page_id the page ID + * @param $namespace the namespace + * @return string error/success string + */ + + public static function flushlogs($page_id, $namespace) + { + global $db, $session, $paths, $template, $plugins; // Common objects + global $lang; + if ( !is_object($lang) && defined('IN_ENANO_INSTALL') ) + { + // This is a special exception for the Enano installer, which doesn't init languages yet. + $lang = new Language('eng'); + } + if(!$session->get_permissions('clear_logs') && !defined('IN_ENANO_INSTALL')) + { + return $lang->get('etc_access_denied'); + } + if ( !$session->sid_super ) + { + return $lang->get('etc_access_denied_need_reauth'); + } + + $page_id_db = $db->escape($page_id); + $namespace_db = $db->escape($namespace); + + // If we're flushing a file, also clear all revisions before the current + if ( $namespace == 'File' ) + { + $q = $db->sql_query('SELECT file_id FROM ' . table_prefix . "files WHERE page_id='$page_id_db' ORDER BY time_id DESC;"); + if ( !$q ) + $db->_die(); + // discard first row (current revision) + $db->fetchrow(); + $id_list = array(); + while ( $row = $db->fetchrow() ) + $id_list[] = $row['file_id']; + + require_once(ENANO_ROOT . '/includes/namespaces/file.php'); + + // clear out each file + foreach ( $id_list as $id ) + Namespace_File::delete_file($id); + } + + $q = $db->sql_query('DELETE FROM ' . table_prefix . "logs WHERE page_id='$page_id_db' AND namespace='$namespace';"); + if ( !$q ) + $db->_die('The log entries could not be deleted.'); + + // If the page exists, make a backup of it in case it gets spammed/vandalized + // If not, the admin's probably deleting a trash page + if ( isPage($paths->get_pathskey($page_id, $namespace)) ) + { + $q = $db->sql_query('SELECT page_text,char_tag FROM ' . table_prefix . "page_text WHERE page_id='$page_id_db' AND namespace='$namespace_db';"); + if ( !$q ) + $db->_die('The current page text could not be selected; as a result, creating the backup of the page failed. Please make a backup copy of the page by clicking Edit this page and then clicking Save Changes.'); + $row = $db->fetchrow(); + $db->free_result(); + $minor_edit = ( ENANO_DBLAYER == 'MYSQL' ) ? 'false' : '0'; + $username = $db->escape($session->username); + $q = 'INSERT INTO ' . table_prefix . "logs ( log_type, action, time_id, date_string, page_id, namespace, page_text, char_tag, author, author_uid, edit_summary, minor_edit ) VALUES\n" + . " ('page', 'edit', " . time() . ", 'DEPRECATED', '$page_id', '$namespace', '" . $db->escape($row['page_text']) . "', '', '{$username}', $session->user_id, '" . $lang->get('page_flushlogs_backup_summary') . "', $minor_edit);"; + if ( !$db->sql_query($q) ) + $db->_die('The history (log) entry could not be inserted into the logs table.'); + } + + return $lang->get('ajax_clearlogs_success'); + } + + /** + * Deletes a page. + * @param string $page_id the condemned page ID + * @param string $namespace the condemned namespace + * @param string The reason for deleting the page in question + * @return string + */ + + public static function deletepage($page_id, $namespace, $reason) + { + global $db, $session, $paths, $template, $plugins; // Common objects + global $lang; + global $cache; + $perms = $session->fetch_page_acl($page_id, $namespace); + $x = trim($reason); + if ( empty($x) ) + { + return $lang->get('ajax_delete_need_reason'); + } + if(!$perms->get_permissions('delete_page')) return('Administrative privileges are required to delete pages, you loser.'); + + if ( !$session->sid_super ) + { + return $lang->get('etc_access_denied_need_reauth'); + } + + $e = $db->sql_query('INSERT INTO ' . table_prefix.'logs(time_id,date_string,log_type,action,page_id,namespace,author,author_uid,edit_summary) VALUES('.time().', \''.enano_date(ED_DATE | ED_TIME).'\', \'page\', \'delete\', \'' . $page_id . '\', \'' . $namespace . '\', \'' . $session->username . '\', ' . $session->user_id . ', \'' . $db->escape(htmlspecialchars($reason)) . '\')'); + if(!$e) $db->_die('The page log entry could not be inserted.'); + $e = $db->sql_query('DELETE FROM ' . table_prefix.'categories WHERE page_id=\'' . $page_id . '\' AND namespace=\'' . $namespace . '\''); + if(!$e) $db->_die('The page categorization entries could not be deleted.'); + $e = $db->sql_query('DELETE FROM ' . table_prefix.'comments WHERE page_id=\'' . $page_id . '\' AND namespace=\'' . $namespace . '\''); + if(!$e) $db->_die('The page comments could not be deleted.'); + $e = $db->sql_query('DELETE FROM ' . table_prefix.'page_text WHERE page_id=\'' . $page_id . '\' AND namespace=\'' . $namespace . '\''); + if(!$e) $db->_die('The page text entry could not be deleted.'); + $e = $db->sql_query('DELETE FROM ' . table_prefix.'pages WHERE urlname=\'' . $page_id . '\' AND namespace=\'' . $namespace . '\''); + if(!$e) $db->_die('The page entry could not be deleted.'); + if ( $namespace == 'File' ) + { + $e = $db->sql_query('DELETE FROM ' . table_prefix.'files WHERE page_id=\'' . $page_id . '\''); + if(!$e) $db->_die('The file entry could not be deleted.'); + } + $cache->purge('page_meta'); + return $lang->get('ajax_delete_success'); + } + + /** + * Deletes files associated with a File page. + * @param string Page ID + */ + + public static function delete_page_files($page_id) + { + global $db, $session, $paths, $template, $plugins; // Common objects + + $q = $db->sql_query('SELECT file_id, filename, file_key, time_id, file_extension FROM ' . table_prefix . "files WHERE page_id = '{$db->escape($page_id)}';"); + if ( !$q ) + $db->_die(); + + while ( $row = $db->fetchrow() ) + { + // wipe original file + foreach ( array( + ENANO_ROOT . "/files/{$row['file_key']}_{$row['time_id']}{$row['file_extension']}", + ENANO_ROOT . "/files/{$row['file_key']}{$row['file_extension']}" + ) as $orig_file ) + { + if ( file_exists($orig_file) ) + @unlink($orig_file); + } + + // wipe cached files + if ( $dr = @opendir(ENANO_ROOT . '/cache/') ) + { + // lol404.jpg-1217958283-200x320.jpg + while ( $dh = @readdir($dr) ) + { + $regexp = ':^' . preg_quote("{$row['filename']}-{$row['time_id']}-") . '[0-9]+x[0-9]+\.' . ltrim($row['file_extension'], '.') . '$:'; + if ( preg_match($regexp, $dh) ) + { + @unlink(ENANO_ROOT . "/cache/$dh"); + } + } + @closedir($dr); + } + } + + $q = $db->sql_query('DELETE FROM ' . table_prefix . "files WHERE page_id = '{$db->escape($page_id)}';"); + if ( !$q ) + $db->die(); + + return true; + } + + /** + * Increments the deletion votes for a page by 1, and adds the current username/IP to the list of users that have voted for the page to prevent dual-voting + * @param $page_id the page ID + * @param $namespace the namespace + * @return string + */ + + public static function delvote($page_id, $namespace) + { + global $db, $session, $paths, $template, $plugins; // Common objects + global $lang; + global $cache; + + if ( !$session->get_permissions('vote_delete') ) + { + return $lang->get('etc_access_denied'); + } + + if ( $namespace == 'Admin' || $namespace == 'Special' || $namespace == 'System' ) + { + return 'Special pages and system messages can\'t be voted for deletion.'; + } + + $pname = $paths->nslist[$namespace] . sanitize_page_id($page_id); + + if ( !isPage($pname) ) + { + return 'The page does not exist.'; + } + + $ns = namespace_factory($page_id, $namespace); + $cdata = $ns->get_cdata(); + + $cv =& $cdata['delvotes']; + $ips =& $cdata['delvote_ips']; + + if ( empty($ips) ) + { + $ips = array( + 'ip' => array(), + 'u' => array() + ); + } + else + { + $ips = @unserialize($ips); + if ( !$ips ) + { + $ips = array( + 'ip' => array(), + 'u' => array() + ); + } + } + + if ( in_array($session->username, $ips['u']) || in_array($_SERVER['REMOTE_ADDR'], $ips['ip']) ) + { + return $lang->get('ajax_delvote_already_voted'); + } + + $ips['u'][] = $session->username; + $ips['ip'][] = $_SERVER['REMOTE_ADDR']; + $ips = $db->escape( serialize($ips) ); + + $cv++; + + $q = 'UPDATE ' . table_prefix.'pages SET delvotes=' . $cv . ',delvote_ips=\'' . $ips . '\' WHERE urlname=\'' . $page_id . '\' AND namespace=\'' . $namespace . '\''; + $w = $db->sql_query($q); + if ( !$w ) + $db->_die(); + + // all done, flush page cache to mark it up + $cache->purge('page_meta'); + + return $lang->get('ajax_delvote_success'); + } + + /** + * Resets the number of votes against a page to 0. + * @param $page_id the page ID + * @param $namespace the namespace + * @return string + */ + + public static function resetdelvotes($page_id, $namespace) + { + global $db, $session, $paths, $template, $plugins; // Common objects + global $lang; + global $cache; + + if ( !$session->get_permissions('vote_reset') ) + { + return $lang->get('etc_access_denied'); + } + + $page_id = $db->escape($page_id); + $namespace = $db->escape($namespace); + + // pull existing info + $q = $db->sql_query('SELECT delvotes, delvote_ips FROM ' . table_prefix . "pages WHERE urlname = '$page_id' AND namespace = '$namespace'"); + if ( !$q ) + $db->_die(); + if ( $db->numrows() < 1 ) + return $lang->get('page_err_page_not_exist'); + + list($delvotes, $delvote_ips) = $db->fetchrow_num(); + $db->free_result(); + $delvote_ips = $db->escape($delvote_ips); + $username = $db->escape($session->username); + + // log action + $time = time(); + $q = $db->sql_query('INSERT INTO ' . table_prefix . "logs (time_id, log_type, action, edit_summary, page_text, author, author_uid, page_id, namespace) VALUES\n" + . " ( $time, 'page', 'votereset', '$delvotes', '$delvote_ips', '$username', $session->user_id, '$page_id', '$namespace' )"); + if ( !$q ) + $db->_die(); + + // reset votes + $empty_vote_record = $db->escape(serialize(array('ip'=>array(),'u'=>array()))); + $q = 'UPDATE ' . table_prefix.'pages SET delvotes=0,delvote_ips=\'' . $empty_vote_record . '\' WHERE urlname=\'' . $page_id . '\' AND namespace=\'' . $namespace . '\''; + $e = $db->sql_query($q); + if ( !$e ) + { + $db->_die('The number of delete votes was not reset.'); + } + else + { + $cache->purge('page_meta'); + return $lang->get('ajax_delvote_reset_success'); + } + } + + /** + * Gets a list of styles for a given theme name. As of Banshee, this returns JSON. + * @param $id the name of the directory for the theme + * @return string JSON string with an array containing a list of themes + */ + + public static function getstyles() + { + + if ( !preg_match('/^([a-z0-9_-]+)$/', $_GET['id']) ) + return enano_json_encode(false); + + $dir = './themes/' . $_GET['id'] . '/css/'; + $list = Array(); + // Open a known directory, and proceed to read its contents + if (is_dir($dir)) { + if ($dh = opendir($dir)) { + while (($file = readdir($dh)) !== false) { + if ( preg_match('#^(.*?)\.css$#is', $file) && $file != '_printable.css' ) // _printable.css should be included with every theme + { // it should be a copy of the original style, but + // mostly black and white + // Note to self: document this + $list[] = substr($file, 0, strlen($file)-4); + } + } + closedir($dh); + } + } + else + { + return(enano_json_encode(Array('mode' => 'error', 'error' => $dir.' is not a dir'))); + } + + return enano_json_encode($list); + } + + /** + * Assembles a Javascript app with category information + * @param $page_id the page ID + * @param $namespace the namespace + * @return string Javascript code + */ + + public static function catedit($page_id, $namespace) + { + $d = PageUtils::catedit_raw($page_id, $namespace); + return $d[0] . ' /* BEGIN CONTENT */ document.getElementById("ajaxEditContainer").innerHTML = unescape(\''.rawurlencode($d[1]).'\');'; + } + + /** + * Does the actual HTML/javascript generation for cat editing, but returns an array + * @access private + */ + + public static function catedit_raw($page_id, $namespace) + { + global $db, $session, $paths, $template, $plugins; // Common objects + global $lang; + + ob_start(); + $_ob = ''; + $e = $db->sql_query('SELECT category_id FROM ' . table_prefix.'categories WHERE page_id=\'' . $paths->page_id . '\' AND namespace=\'' . $paths->namespace . '\''); + if(!$e) jsdie('Error selecting category information for current page: '.$db->get_error()); + $cat_current = Array(); + while($r = $db->fetchrow()) + { + $cat_current[] = $r; + } + $db->free_result(); + + $cat_all = array(); + $q = $db->sql_query('SELECT * FROM ' . table_prefix . 'pages WHERE namespace = \'Category\';'); + if ( !$q ) + $db->_die(); + + while ( $row = $db->fetchrow() ) + { + $cat_all[] = Namespace_Default::bake_cdata($row); + } + + // Make $cat_all an associative array, like $paths->pages + $sz = sizeof($cat_all); + for($i=0;$i<$sz;$i++) + { + $cat_all[$cat_all[$i]['urlname_nons']] = $cat_all[$i]; + } + // Now, the "zipper" function - join the list of categories with the list of cats that this page is a part of + $cat_info = $cat_all; + for($i=0;$iget('catedit_title') . ' +
'; + if ( sizeof($cat_info) < 1 ) + { + $_ob .= '

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

'; + } + for ( $i = 0; $i < sizeof($cat_info) / 2; $i++ ) + { + // Protection code added 1/3/07 + // Updated 3/4/07 + $is_prot = false; + $perms = $session->fetch_page_acl($cat_info[$i]['urlname_nons'], 'Category'); + if ( !$session->get_permissions('edit_cat') || !$perms->get_permissions('edit_cat') || + ( $cat_info[$i]['really_protected'] && !$perms->get_permissions('even_when_protected') ) ) + $is_prot = true; + $prot = ( $is_prot ) ? ' disabled="disabled" ' : ''; + $prottext = ( $is_prot ) ? ' (protected)' : ''; + echo 'catlist[' . $i . '] = \'' . $cat_info[$i]['urlname_nons'] . '\';'; + $_ob .= '' . $cat_info[$i]['name'].$prottext.'
'; + } + + $disabled = ( sizeof($cat_info) < 1 ) ? 'disabled="disabled"' : ''; + + $_ob .= '
'; + + $cont = ob_get_contents(); + ob_end_clean(); + return Array($cont, $_ob); + } + + /** + * Saves category information + * WARNING: If $which_cats is empty, all the category information for the selected page will be nuked! + * @param $page_id string the page ID + * @param $namespace string the namespace + * @param $which_cats array associative array of categories to put the page in + * @return string "GOOD" on success, error string on failure + */ + + public static function catsave($page_id, $namespace, $which_cats) + { + global $db, $session, $paths, $template, $plugins; // Common objects + if(!$session->get_permissions('edit_cat')) return('Insufficient privileges to change category information'); + + $page_perms = $session->fetch_page_acl($page_id, $namespace); + $ns = namespace_factory($page_id, $namespace); + $page_data = $ns->get_cdata(); + + $cat_all = array(); + $q = $db->sql_query('SELECT * FROM ' . table_prefix . 'pages WHERE namespace = \'Category\';'); + if ( !$q ) + $db->_die(); + + while ( $row = $db->fetchrow() ) + { + $cat_all[] = Namespace_Default::bake_cdata($row); + } + + // Make $cat_all an associative array, like $paths->pages + $sz = sizeof($cat_all); + for($i=0;$i<$sz;$i++) + { + $cat_all[$cat_all[$i]['urlname_nons']] = $cat_all[$i]; + } + + $rowlist = Array(); + + for($i=0;$ifetch_page_acl($cat_all[$i]['urlname_nons'], 'Category'); + if ( !$session->get_permissions('edit_cat') || !$perms->get_permissions('edit_cat') || + ( $cat_all[$i]['really_protected'] && !$perms->get_permissions('even_when_protected') ) || + ( !$page_perms->get_permissions('even_when_protected') && $page_data['protected'] == '1' ) ) + $auth = false; + if(!$auth) + { + // Find out if the page is currently in the category + $q = $db->sql_query('SELECT * FROM ' . table_prefix.'categories WHERE page_id=\'' . $page_id . '\' AND namespace=\'' . $namespace . '\';'); + if(!$q) + return 'MySQL error: ' . $db->get_error(); + if($db->numrows() > 0) + { + $auth = true; + $which_cats[$cat_all[$i]['urlname_nons']] = true; // Force the category to stay in its current state + } + $db->free_result(); + } + if(isset($which_cats[$cat_all[$i]['urlname_nons']]) && $which_cats[$cat_all[$i]['urlname_nons']] == true /* for clarity ;-) */ && $auth ) $rowlist[] = '(\'' . $page_id . '\', \'' . $namespace . '\', \'' . $cat_all[$i]['urlname_nons'] . '\')'; + } + if(sizeof($rowlist) > 0) + { + $val = implode(',', $rowlist); + $q = 'INSERT INTO ' . table_prefix.'categories(page_id,namespace,category_id) VALUES' . $val . ';'; + $e = $db->sql_query('DELETE FROM ' . table_prefix.'categories WHERE page_id=\'' . $page_id . '\' AND namespace=\'' . $namespace . '\';'); + if(!$e) $db->_die('The old category data could not be deleted.'); + $e = $db->sql_query($q); + if(!$e) $db->_die('The new category data could not be inserted.'); + return('GOOD'); + } + else + { + $e = $db->sql_query('DELETE FROM ' . table_prefix.'categories WHERE page_id=\'' . $page_id . '\' AND namespace=\'' . $namespace . '\';'); + if(!$e) $db->_die('The old category data could not be deleted.'); + return('GOOD'); + } + } + + /** + * Sets the wiki mode level for a page. + * @param $page_id string the page ID + * @param $namespace string the namespace + * @param $level int 0 for off, 1 for on, 2 for use global setting + * @return string "GOOD" on success, error string on failure + */ + + public static function setwikimode($page_id, $namespace, $level) + { + global $db, $session, $paths, $template, $plugins; // Common objects + global $cache; + + if(!$session->get_permissions('set_wiki_mode')) return('Insufficient access rights'); + if ( !isset($level) || ( isset($level) && !preg_match('#^([0-2]){1}$#', (string)$level) ) ) + { + return('Invalid mode string'); + } + $q = $db->sql_query('UPDATE ' . table_prefix.'pages SET wiki_mode=' . $level . ' WHERE urlname=\'' . $page_id . '\' AND namespace=\'' . $namespace . '\';'); + if ( !$q ) + { + return('Error during update query: '.$db->get_error()."\n\nSQL Backtrace:\n".$db->sql_backtrace()); + } + + $cache->purge('page_meta'); + return('GOOD'); + } + + /** + * Sets the access password for a page. + * @param $page_id string the page ID + * @param $namespace string the namespace + * @param $pass string the SHA1 hash of the password - if the password doesn't match the regex ^([0-9a-f]*){40,40}$ it will be sha1'ed + * @return string + */ + + public static function setpass($page_id, $namespace, $pass) + { + global $db, $session, $paths, $template, $plugins; // Common objects + global $lang, $cache; + // Determine permissions + $ns = namespace_factory($page_id, $namespace); + $cdata = $ns->get_cdata(); + if ( $cdata['password'] != '' ) + $a = $session->get_permissions('password_reset'); + else + $a = $session->get_permissions('password_set'); + if ( !$a ) + return $lang->get('etc_access_denied'); + if ( !isset($pass) ) + return('Password was not set on URL'); + $p = $pass; + if ( !preg_match('#([0-9a-f]){40,40}#', $p) ) + { + $p = sha1($p); + } + if ( $p == 'da39a3ee5e6b4b0d3255bfef95601890afd80709' ) + // sha1('') = da39a3ee5e6b4b0d3255bfef95601890afd80709 + $p = ''; + $e = $db->sql_query('UPDATE ' . table_prefix.'pages SET password=\'' . $p . '\' WHERE urlname=\'' . $page_id . '\' AND namespace=\'' . $namespace . '\';'); + if ( !$e ) + { + die('PageUtils::setpass(): Error during update query: '.$db->get_error()."\n\nSQL Backtrace:\n".$db->sql_backtrace()); + } + // Is the new password blank? + if ( $p == '' ) + { + return $lang->get('ajax_password_disable_success'); + } + else + { + return $lang->get('ajax_password_success'); + } + } + + /** + * Generates some preview HTML + * @param $text string the wikitext to use + * @return string + */ + + public static function genPreview($text) + { + global $lang; + $ret = '
' . $lang->get('editor_preview_blurb') . '
'; + $text = RenderMan::render(RenderMan::preprocess_text($text, false, false)); + ob_start(); + eval('?>' . $text); + $text = ob_get_contents(); + ob_end_clean(); + $ret .= $text; + $ret .= '
'; + return $ret; + } + + /** + * Makes a scrollable box + * @param string $text the inner HTML + * @param int $height Optional - the maximum height. Defaults to 250. + * @return string + */ + + public static function scrollBox($text, $height = 250) + { + return '
' . $text . '
'; + } + + /** + * Generates a diff summary between two page revisions. + * @param $page_id the page ID + * @param $namespace the namespace + * @param $id1 the time ID of the first revision + * @param $id2 the time ID of the second revision + * @return string XHTML-formatted diff + */ + + public static function pagediff($page_id, $namespace, $id1, $id2) + { + global $db, $session, $paths, $template, $plugins; // Common objects + global $lang; + + if ( !$session->get_permissions('history_view') ) + return $lang->get('etc_access_denied'); + + if(!preg_match('#^([0-9]+)$#', (string)$id1) || + !preg_match('#^([0-9]+)$#', (string)$id2 )) return 'SQL injection attempt'; + // OK we made it through security + // Safest way to make sure we don't end up with the revisions in wrong columns is to make 2 queries + if ( !$q1 = $db->sql_query('SELECT time_id,page_text,char_tag,author,edit_summary FROM ' . table_prefix.'logs WHERE log_id = ' . $id1 . ' AND log_type=\'page\' AND action=\'edit\' AND page_id=\'' . $page_id . '\' AND namespace=\'' . $namespace . '\';')) return 'MySQL error: ' . $db->get_error(); + if ( !$q2 = $db->sql_query('SELECT time_id,page_text,char_tag,author,edit_summary FROM ' . table_prefix.'logs WHERE log_id = ' . $id2 . ' AND log_type=\'page\' AND action=\'edit\' AND page_id=\'' . $page_id . '\' AND namespace=\'' . $namespace . '\';')) return 'MySQL error: ' . $db->get_error(); + $row1 = $db->fetchrow($q1); + $db->free_result($q1); + $row2 = $db->fetchrow($q2); + $db->free_result($q2); + if(sizeof($row1) < 1 || sizeof($row2) < 2) + { + if ( !$q1 = $db->sql_query('SELECT time_id,page_text,char_tag,author,edit_summary FROM ' . table_prefix.'logs WHERE time_id = ' . $id1 . ' AND log_type=\'page\' AND action=\'edit\' AND page_id=\'' . $page_id . '\' AND namespace=\'' . $namespace . '\';')) return 'MySQL error: ' . $db->get_error(); + if ( !$q2 = $db->sql_query('SELECT time_id,page_text,char_tag,author,edit_summary FROM ' . table_prefix.'logs WHERE time_id = ' . $id2 . ' AND log_type=\'page\' AND action=\'edit\' AND page_id=\'' . $page_id . '\' AND namespace=\'' . $namespace . '\';')) return 'MySQL error: ' . $db->get_error(); + $row1 = $db->fetchrow($q1); + $db->free_result($q1); + $row2 = $db->fetchrow($q2); + $db->free_result($q2); + if(sizeof($row1) < 1 || sizeof($row2) < 2) + return 'Couldn\'t find any rows that matched the query. The time ID probably doesn\'t exist in the logs table.'; + } + $text1 = $row1['page_text']; + $text2 = $row2['page_text']; + $time1 = enano_date(ED_DATE | ED_TIME, $row1['time_id']); + $time2 = enano_date(ED_DATE | ED_TIME, $row2['time_id']); + $_ob = " +

" . $lang->get('history_lbl_comparingrevisions') . " {$time1} → {$time2}

+ "; + // Free some memory + unset($row1, $row2, $q1, $q2); + + $_ob .= RenderMan::diff($text1, $text2); + return $_ob; + } + + /** + * Gets ACL information about the selected page for target type X and target ID Y. + * @param array $parms What to select. This is an array purely for JSON compatibility. It should be an associative array with keys target_type and target_id. + * @return array + */ + + public static function acl_editor($parms = Array()) + { + global $db, $session, $paths, $template, $plugins; // Common objects + global $lang; + + if(!$session->get_permissions('edit_acl') && ( $session->user_level < USER_LEVEL_ADMIN || !defined('ACL_ALWAYS_ALLOW_ADMIN_EDIT_ACL')) ) + { + return Array( + 'mode' => 'error', + 'error' => $lang->get('acl_err_access_denied') + ); + } + if ( !$session->sid_super ) + { + return Array( + 'mode' => 'error', + 'error' => $lang->get('etc_access_denied_need_reauth') + ); + } + $parms['page_id'] = ( isset($parms['page_id']) ) ? $parms['page_id'] : false; + $parms['namespace'] = ( isset($parms['namespace']) ) ? $parms['namespace'] : false; + $page_id =& $parms['page_id']; + $namespace =& $parms['namespace']; + $page_where_clause = ( empty($page_id) || empty($namespace) ) ? 'AND a.page_id IS NULL AND a.namespace IS NULL' : 'AND a.page_id=\'' . $db->escape($page_id) . '\' AND a.namespace=\'' . $db->escape($namespace) . '\''; + $page_where_clause_lite = ( empty($page_id) || empty($namespace) ) ? 'AND page_id IS NULL AND namespace IS NULL' : 'AND page_id=\'' . $db->escape($page_id) . '\' AND namespace=\'' . $db->escape($namespace) . '\''; + //die(print_r($page_id,true)); + $template->load_theme(); + // $perms_obj = $session->fetch_page_acl($page_id, $namespace); + $perms_obj =& $session; + $return = Array(); + if ( !file_exists(ENANO_ROOT . '/themes/' . $session->theme . '/acledit.tpl') ) + { + return Array( + 'mode' => 'error', + 'error' => $lang->get('acl_err_missing_template'), + ); + } + $return['template'] = $template->extract_vars('acledit.tpl'); + $return['page_id'] = $page_id; + $return['namespace'] = $namespace; + if(isset($parms['mode'])) + { + switch($parms['mode']) + { + case 'listgroups': + $return['groups'] = Array(); + $q = $db->sql_query('SELECT group_id,group_name FROM ' . table_prefix.'groups ORDER BY group_name ASC;'); + while($row = $db->fetchrow()) + { + $return['groups'][] = Array( + 'id' => $row['group_id'], + 'name' => $row['group_name'], + ); + } + $db->free_result(); + $return['page_groups'] = Array(); + $q = $db->sql_query('SELECT pg_id,pg_name FROM ' . table_prefix.'page_groups ORDER BY pg_name ASC;'); + if ( !$q ) + return Array( + 'mode' => 'error', + 'error' => $db->get_error() + ); + while ( $row = $db->fetchrow() ) + { + $return['page_groups'][] = Array( + 'id' => $row['pg_id'], + 'name' => $row['pg_name'] + ); + } + break; + case 'seltarget_id': + if ( !is_int($parms['target_id']) ) + { + return Array( + 'mode' => 'error', + 'error' => 'Expected parameter target_id type int' + ); + } + $q = $db->sql_query('SELECT target_id, target_type, page_id, namespace, rules FROM ' . table_prefix . "acl WHERE rule_id = {$parms['target_id']};"); + if ( !$q ) + return Array( + 'mode' => 'error', + 'error' => $db->get_error() + ); + if ( $db->numrows() < 1 ) + return Array( + 'mode' => 'error', + 'error' => "No rule with ID {$parms['target_id']} found" + ); + $parms = $db->fetchrow(); + $db->free_result(); + + // regenerate page selection + $parms['page_id'] = ( isset($parms['page_id']) ) ? $parms['page_id'] : false; + $parms['namespace'] = ( isset($parms['namespace']) ) ? $parms['namespace'] : false; + $parms['mode'] = 'seltarget_id'; + $page_id =& $parms['page_id']; + $namespace =& $parms['namespace']; + $page_where_clause = ( empty($page_id) || empty($namespace) ) ? 'AND a.page_id IS NULL AND a.namespace IS NULL' : 'AND a.page_id=\'' . $db->escape($page_id) . '\' AND a.namespace=\'' . $db->escape($namespace) . '\''; + $page_where_clause_lite = ( empty($page_id) || empty($namespace) ) ? 'AND page_id IS NULL AND namespace IS NULL' : 'AND page_id=\'' . $db->escape($page_id) . '\' AND namespace=\'' . $db->escape($namespace) . '\''; + + $return['page_id'] = $parms['page_id']; + $return['namespace'] = $parms['namespace']; + + // From here, let the seltarget handler take over + case 'seltarget': + $return['mode'] = 'seltarget'; + $return['acl_types'] = $perms_obj->acl_types; + $return['acl_deps'] = $perms_obj->acl_deps; + $return['acl_descs'] = $perms_obj->acl_descs; + $return['target_type'] = $parms['target_type']; + $return['target_id'] = $parms['target_id']; + switch($parms['target_type']) + { + case ACL_TYPE_USER: + $user_col = ( $parms['mode'] == 'seltarget_id' ) ? 'user_id' : 'username'; + $q = $db->sql_query('SELECT a.rules,u.user_id,u.username FROM ' . table_prefix.'users AS u + LEFT JOIN ' . table_prefix.'acl AS a + ON a.target_id=u.user_id + WHERE a.target_type='.ACL_TYPE_USER.' + AND u.' . $user_col . ' = \'' . $db->escape($parms['target_id']) . '\' + ' . $page_where_clause . ';'); + if(!$q) + return(Array('mode'=>'error','error'=>$db->get_error())); + if($db->numrows() < 1) + { + $return['type'] = 'new'; + $q = $db->sql_query('SELECT user_id,username FROM ' . table_prefix.'users WHERE username=\'' . $db->escape($parms['target_id']) . '\';'); + if(!$q) + return(Array('mode'=>'error','error'=>$db->get_error())); + if($db->numrows() < 1) + return Array('mode'=>'error','error'=>$lang->get('acl_err_user_not_found'),'debug' => $db->sql_backtrace()); + $row = $db->fetchrow(); + $return['target_name'] = $row['username']; + $return['target_id'] = intval($row['user_id']); + $return['current_perms'] = array(); + } + else + { + $return['type'] = 'edit'; + $row = $db->fetchrow(); + $return['target_name'] = $row['username']; + $return['target_id'] = intval($row['user_id']); + $return['current_perms'] = $session->string_to_perm($row['rules']); + } + $db->free_result(); + // Eliminate types that don't apply to this namespace + if ( $namespace && $namespace != '__PageGroup' ) + { + foreach ( $return['current_perms'] AS $i => $perm ) + { + if ( ( $page_id != null && $namespace != null ) && ( !in_array ( $namespace, $session->acl_scope[$i] ) && !in_array('All', $session->acl_scope[$i]) ) ) + { + // echo "// SCOPE CONTROL: eliminating: $i\n"; + unset($return['current_perms'][$i]); + unset($return['acl_types'][$i]); + unset($return['acl_descs'][$i]); + unset($return['acl_deps'][$i]); + } + } + } + break; + case ACL_TYPE_GROUP: + $q = $db->sql_query('SELECT a.rules,g.group_name,g.group_id FROM ' . table_prefix.'groups AS g + LEFT JOIN ' . table_prefix.'acl AS a + ON a.target_id=g.group_id + WHERE a.target_type='.ACL_TYPE_GROUP.' + AND g.group_id=\''.intval($parms['target_id']).'\' + ' . $page_where_clause . ';'); + if(!$q) + return(Array('mode'=>'error','error'=>$db->get_error())); + if($db->numrows() < 1) + { + $return['type'] = 'new'; + $q = $db->sql_query('SELECT group_id,group_name FROM ' . table_prefix.'groups WHERE group_id=\''.intval($parms['target_id']).'\';'); + if(!$q) + return(Array('mode'=>'error','error'=>$db->get_error())); + if($db->numrows() < 1) + return Array('mode'=>'error','error'=>$lang->get('acl_err_bad_group_id')); + $row = $db->fetchrow(); + $return['target_name'] = $row['group_name']; + $return['target_id'] = intval($row['group_id']); + $return['current_perms'] = array(); + } + else + { + $return['type'] = 'edit'; + $row = $db->fetchrow(); + $return['target_name'] = $row['group_name']; + $return['target_id'] = intval($row['group_id']); + $return['current_perms'] = $session->string_to_perm($row['rules']); + } + $db->free_result(); + // Eliminate types that don't apply to this namespace + if ( $namespace && $namespace != '__PageGroup' ) + { + foreach ( $return['current_perms'] AS $i => $perm ) + { + if ( ( $page_id != false && $namespace != false ) && ( !in_array ( $namespace, $session->acl_scope[$i] ) && !in_array('All', $session->acl_scope[$i]) ) ) + { + // echo "// SCOPE CONTROL: eliminating: $i\n"; //; ".print_r($namespace,true).":".print_r($page_id,true)."\n"; + unset($return['current_perms'][$i]); + unset($return['acl_types'][$i]); + unset($return['acl_descs'][$i]); + unset($return['acl_deps'][$i]); + } + } + } + //return Array('mode'=>'debug','text'=>print_r($return, true)); + break; + default: + return Array('mode'=>'error','error','Invalid ACL type ID'); + break; + } + return $return; + break; + case 'save_new': + case 'save_edit': + if ( defined('ENANO_DEMO_MODE') ) + { + return Array('mode'=>'error','error'=>$lang->get('acl_err_demo')); + } + $q = $db->sql_query('DELETE FROM ' . table_prefix.'acl WHERE target_type='.intval($parms['target_type']).' AND target_id='.intval($parms['target_id']).' + ' . $page_where_clause_lite . ';'); + if(!$q) + return Array('mode'=>'error','error'=>$db->get_error()); + if ( sizeof ( $parms['perms'] ) < 1 ) + { + // As of 1.1.x, this returns success because the rule length is zero if the user selected "inherit" in all columns + return Array( + 'mode' => 'success', + 'target_type' => $parms['target_type'], + 'target_id' => $parms['target_id'], + 'target_name' => $parms['target_name'], + 'page_id' => $page_id, + 'namespace' => $namespace, + ); + } + $rules = $session->perm_to_string($parms['perms']); + $q = ($page_id && $namespace) ? 'INSERT INTO ' . table_prefix.'acl ( target_type, target_id, page_id, namespace, rules ) + VALUES( '.intval($parms['target_type']).', '.intval($parms['target_id']).', \'' . $db->escape($page_id) . '\', \'' . $db->escape($namespace) . '\', \'' . $db->escape($rules) . '\' )' : + 'INSERT INTO ' . table_prefix.'acl ( target_type, target_id, rules ) + VALUES( '.intval($parms['target_type']).', '.intval($parms['target_id']).', \'' . $db->escape($rules) . '\' )'; + if(!$db->sql_query($q)) return Array('mode'=>'error','error'=>$db->get_error()); + return Array( + 'mode' => 'success', + 'target_type' => $parms['target_type'], + 'target_id' => $parms['target_id'], + 'target_name' => $parms['target_name'], + 'page_id' => $page_id, + 'namespace' => $namespace, + ); + break; + case 'delete': + if ( defined('ENANO_DEMO_MODE') ) + { + return Array('mode'=>'error','error'=>$lang->get('acl_err_demo')); + } + $sql = 'DELETE FROM ' . table_prefix.'acl WHERE target_type='.intval($parms['target_type']).' AND target_id='.intval($parms['target_id']).' + ' . $page_where_clause_lite . ';'; + $q = $db->sql_query($sql); + if(!$q) + return Array('mode'=>'error','error'=>$db->get_error()); + return Array( + 'mode' => 'delete', + 'target_type' => $parms['target_type'], + 'target_id' => $parms['target_id'], + 'target_name' => $parms['target_name'], + 'page_id' => $page_id, + 'namespace' => $namespace, + ); + break; + case 'list_existing': + + $return = array( + 'mode' => 'list_existing', + 'key' => acl_list_draw_key(), + 'rules' => array() + ); + + $acl_columns = 'a.' . implode(', a.', $db->columns_in(table_prefix . 'acl')); + $users_columns = 'u.' . implode(', u.', $db->columns_in(table_prefix . 'users')); + $groups_columns = 'g.' . implode(', g.', $db->columns_in(table_prefix . 'groups')); + $pg_columns = 'p.' . implode(', p.', array('pg_id', 'pg_type', 'pg_name', 'pg_target')); + + $q = $db->sql_query("SELECT a.rule_id, u.username, g.group_name, a.target_type, a.target_id, a.page_id, a.namespace, a.rules, p.pg_name\n" + . " FROM " . table_prefix . "acl AS a\n" + . " LEFT JOIN " . table_prefix . "users AS u\n" + . " ON ( (a.target_type = " . ACL_TYPE_USER . " AND a.target_id = u.user_id) OR (u.user_id IS NULL) )\n" + . " LEFT JOIN " . table_prefix . "groups AS g\n" + . " ON ( (a.target_type = " . ACL_TYPE_GROUP . " AND a.target_id = g.group_id) OR (g.group_id IS NULL) )\n" + . " LEFT JOIN " . table_prefix . "page_groups as p\n" + . " ON ( (a.namespace = '__PageGroup' AND a.page_id = CAST(p.pg_id AS CHAR)) OR (p.pg_id IS NULL) )\n" + . " WHERE ( a.target_type = " . ACL_TYPE_USER . " OR a.target_type = " . ACL_TYPE_GROUP . " )\n" + . " GROUP BY a.rule_id, $acl_columns, $users_columns, $groups_columns, $pg_columns\n" + . " ORDER BY a.target_type ASC, a.rule_id ASC;" + ); + + if ( !$q ) + $db->_die(); + + while ( $row = $db->fetchrow($q) ) + { + if ( $row['target_type'] == ACL_TYPE_USER && empty($row['username']) ) + { + // This is only done if we have an ACL affecting a user that doesn't exist. + // Nice little bit of maintenance to have. + if ( !$db->sql_query("DELETE FROM " . table_prefix . "acl WHERE rule_id = {$row['rule_id']};") ) + $db->_die(); + continue; + } + $score = get_acl_rule_score($row['rules']); + $deep_limit = ACL_SCALE_MINIMAL_SHADE; + // Determine background color of cell by score + if ( $score > 5 ) + { + // high score, show in green + $color = 2.5 * $score; + if ( $color > 255 ) + $color = 255; + $color = round($color); + // blend with the colordepth limit + $color = $deep_limit + ( ( 0xFF - $deep_limit ) - ( ( $color / 0xFF ) * ( 0xFF - $deep_limit ) ) ); + $color = dechex($color); + $color = "{$color}ff{$color}"; + } + else if ( $score < -5 ) + { + // low score, show in red + $color = 0 - $score; + $color = 2.5 * $color; + if ( $color > 255 ) + $color = 255; + $color = round($color); + // blend with the colordepth limit + $color = $deep_limit + ( ( 0xFF - $deep_limit ) - ( ( $color / 0xFF ) * ( 0xFF - $deep_limit ) ) ); + $color = dechex($color); + $color = "ff{$color}{$color}"; + } + else + { + $color = 'efefef'; + } + + // Rate rule textually based on its score + if ( $score >= 70 ) + $desc = $lang->get('acl_msg_scale_allow'); + else if ( $score >= 50 ) + $desc = $lang->get('acl_msg_scale_mostly_allow'); + else if ( $score >= 25 ) + $desc = $lang->get('acl_msg_scale_some_allow'); + else if ( $score >= -25 ) + $desc = $lang->get('acl_msg_scale_mixed'); + else if ( $score <= -70 ) + $desc = $lang->get('acl_msg_scale_deny'); + else if ( $score <= -50 ) + $desc = $lang->get('acl_msg_scale_mostly_deny'); + else if ( $score <= -25 ) + $desc = $lang->get('acl_msg_scale_some_deny'); + + // group and user target info + $info = ''; + if ( $row['target_type'] == ACL_TYPE_USER ) + $info = $lang->get('acl_msg_list_user', array( 'username' => $row['username'] )); // "(User: {$row['username']})"; + else if ( $row['target_type'] == ACL_TYPE_GROUP ) + $info = $lang->get('acl_msg_list_group', array( 'group' => $row['group_name'] )); + + // affected pages info + if ( $row['page_id'] && $row['namespace'] && $row['namespace'] != '__PageGroup' ) + $info .= $lang->get('acl_msg_list_on_page', array( 'page_name' => "{$row['namespace']}:{$row['page_id']}" )); + else if ( $row['page_id'] && $row['namespace'] && $row['namespace'] == '__PageGroup' ) + $info .= $lang->get('acl_msg_list_on_page_group', array( 'page_group' => $row['pg_name'] )); + else + $info .= $lang->get('acl_msg_list_entire_site'); + + $score_string = $lang->get('acl_msg_list_score', array + ( + 'score' => $score, + 'desc' => $desc, + 'info' => $info + )); + $return['rules'][] = array( + 'score_string' => $score_string, + 'rule_id' => $row['rule_id'], + 'color' => $color + ); + } + + break; + case 'list_presets': + $presets = array(); + $q = $db->sql_query('SELECT page_id AS preset_name, rule_id, rules FROM ' . table_prefix . "acl WHERE target_type = " . ACL_TYPE_PRESET . ";"); + if ( !$q ) + $db->die_json(); + + while ( $row = $db->fetchrow() ) + { + $row['rules'] = $session->string_to_perm($row['rules']); + $presets[] = $row; + } + + return array( + 'mode' => 'list_existing', + 'presets' => $presets + ); + break; + case 'save_preset': + if ( empty($parms['preset_name']) ) + { + return array( + 'mode' => 'error', + 'error' => $lang->get('acl_err_preset_name_empty') + ); + } + $preset_name = $db->escape($parms['preset_name']); + $q = $db->sql_query('DELETE FROM ' . table_prefix . "acl WHERE target_type = " . ACL_TYPE_PRESET . " AND page_id = '$preset_name';"); + if ( !$q ) + $db->die_json(); + + $perms = $session->perm_to_string($parms['perms']); + if ( !$perms ) + { + return array( + 'mode' => 'error', + 'error' => $lang->get('acl_err_preset_is_blank') + ); + } + + $perms = $db->escape($perms); + $q = $db->sql_query('INSERT INTO ' . table_prefix . "acl(page_id, target_type, rules) VALUES\n" + . " ( '$preset_name', " . ACL_TYPE_PRESET . ", '$perms' );"); + if ( !$q ) + $db->die_json(); + + return array( + 'mode' => 'success' + ); + break; + case 'trace': + list($targetpid, $targetns) = RenderMan::strToPageID($parms['page']); + try + { + $perms = $session->fetch_page_acl_user($parms['user'], $targetpid, $targetns); + $perm_table = array( + AUTH_ALLOW => 'acl_lbl_field_allow', + AUTH_WIKIMODE => 'acl_lbl_field_wikimode', + AUTH_DISALLOW => 'acl_lbl_field_disallow', + AUTH_DENY => 'acl_lbl_field_deny' + ); + + $return = array( + 'mode' => 'trace', + 'perms' => array() + ); + + foreach ( $perms->perm_resolve_table as $perm_type => $lookup_data ) + { + if ( !$session->check_acl_scope($perm_type, $targetns) ) + continue; + + $src_l10n = $lang->get($session->acl_inherit_lang_table[$lookup_data['src']], $lookup_data); + $divclass = preg_replace('/^acl_inherit_/', '', $session->acl_inherit_lang_table[$lookup_data['src']]); + $perm_string = $lang->get($perm_table[$perms->perms[$perm_type]]); + $perm_name = $lang->get($session->acl_descs[$perm_type]); + + $return['perms'][$perm_type] = array( + 'divclass' => "acl_inherit acl_$divclass", + 'perm_type' => $perm_type, + 'perm_name' => $perm_name, + 'perm_value' => $perm_string, + 'perm_src' => $src_l10n, + 'rule_id' => intval($lookup_data['rule_id']), + 'bad_deps' => $perms->acl_check_deps($perm_type, true) + ); + } + + // group rules if possible + $return['groups'] = array(); + foreach ( $return['perms'] as $rule ) + { + if ( !isset($return['groups'][$rule['rule_id']]) ) + { + $return['groups'][$rule['rule_id']] = array(); + } + $return['groups'][$rule['rule_id']][] = $rule['perm_type']; + } + } + catch ( Exception $e ) + { + $return = array( + 'mode' => 'error', + 'error' => $e->getMessage() + ); + } + + break; + default: + return Array('mode'=>'error','error'=>'Hacking attempt'); + break; + } + } + return $return; + } + + /** + * Same as PageUtils::acl_editor(), but the parms are a JSON string instead of an array. This also returns a JSON string. + * @param string $parms Same as PageUtils::acl_editor/$parms, but should be a valid JSON string. + * @return string + */ + + public static function acl_json($parms = '{ }') + { + global $db, $session, $paths, $template, $plugins; // Common objects + try + { + $parms = enano_json_decode($parms); + } + catch ( Zend_Json_Exception $e ) + { + $parms = array(); + } + $ret = PageUtils::acl_editor($parms); + $ret = enano_json_encode($ret); + return $ret; + } + + /** + * A non-Javascript frontend for the ACL API. + * @param array The request data, if any, this should be in the format required by PageUtils::acl_editor() + */ + + public static function aclmanager($parms) + { + global $db, $session, $paths, $template, $plugins; // Common objects + global $lang; + ob_start(); + // Convenience + $formstart = '
'; + $formend = '
'; + $parms = PageUtils::acl_preprocess($parms); + $response = PageUtils::acl_editor($parms); + $response = PageUtils::acl_postprocess($response); + + //die('
' . htmlspecialchars(print_r($response, true)) . '
'); + + switch($response['mode']) + { + case 'debug': + echo '
' . htmlspecialchars($response['text']) . '
'; + break; + case 'stage1': + echo '

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

+

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

'; + echo $formstart; + echo '

+

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

+

'; + } + + echo '

+

+

' . $template->username_field('data[target_id_user]') . '

+

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

+

+ ' . $groupsel . ' +

+
+ + + + +
'; + echo $formend; + break; + case 'success': + echo '
+ ' . $lang->get('acl_lbl_save_success_title') . '
+ ' . $lang->get('acl_lbl_save_success_body', array( 'target_name' => $response['target_name'] )) . '
+ ' . $formstart . ' + + + + + + + + + ' . $formend . ' +
'; + break; + case 'delete': + echo '
+ ' . $lang->get('acl_lbl_delete_success_title') . '
+ ' . $lang->get('acl_lbl_delete_success_body', array('target_name' => $response['target_name'])) . '
+ ' . $formstart . ' + + + + + + + + + ' . $formend . ' +
'; + break; + case 'seltarget': + if ( $response['type'] == 'edit' ) + { + echo '

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

'; + } + else + { + echo '

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

'; + } + $type = ( $response['target_type'] == ACL_TYPE_GROUP ) ? $lang->get('acl_target_type_group') : $lang->get('acl_target_type_user'); + $scope = ( $response['page_id'] ) ? ( $response['namespace'] == '__PageGroup' ? $lang->get('acl_scope_type_pagegroup') : $lang->get('acl_scope_type_thispage') ) : $lang->get('acl_scope_type_wholesite'); + $subs = array( + 'target_type' => $type, + 'target' => $response['target_name'], + 'scope_type' => $scope + ); + echo $lang->get('acl_lbl_editwin_body', $subs); + echo $formstart; + $parser = $template->makeParserText( $response['template']['acl_field_begin'] ); + echo $parser->run(); + $parser = $template->makeParserText( $response['template']['acl_field_item'] ); + $cls = 'row2'; + foreach ( $response['acl_types'] as $acl_type => $value ) + { + $vars = Array( + 'FIELD_INHERIT_CHECKED' => '', + 'FIELD_DENY_CHECKED' => '', + 'FIELD_DISALLOW_CHECKED' => '', + 'FIELD_WIKIMODE_CHECKED' => '', + 'FIELD_ALLOW_CHECKED' => '', + ); + $cls = ( $cls == 'row1' ) ? 'row2' : 'row1'; + $vars['ROW_CLASS'] = $cls; + + switch ( $response['current_perms'][$acl_type] ) + { + case 'i': + default: + $vars['FIELD_INHERIT_CHECKED'] = 'checked="checked"'; + break; + case AUTH_ALLOW: + $vars['FIELD_ALLOW_CHECKED'] = 'checked="checked"'; + break; + case AUTH_WIKIMODE: + $vars['FIELD_WIKIMODE_CHECKED'] = 'checked="checked"'; + break; + case AUTH_DISALLOW: + $vars['FIELD_DISALLOW_CHECKED'] = 'checked="checked"'; + break; + case AUTH_DENY: + $vars['FIELD_DENY_CHECKED'] = 'checked="checked"'; + break; + } + $vars['FIELD_NAME'] = 'data[perms][' . $acl_type . ']'; + if ( preg_match('/^([a-z0-9_]+)$/', $response['acl_descs'][$acl_type]) ) + { + $vars['FIELD_DESC'] = $lang->get($response['acl_descs'][$acl_type]); + } + else + { + $vars['FIELD_DESC'] = $response['acl_descs'][$acl_type]; + } + $parser->assign_vars($vars); + echo $parser->run(); + } + $parser = $template->makeParserText( $response['template']['acl_field_end'] ); + echo $parser->run(); + echo '
+ + + + + + + ' . ( ( $response['type'] == 'edit' ) ? '  ' : '' ) . ' +
'; + echo $formend; + break; + case 'error': + ob_end_clean(); + die_friendly('Error occurred', '

Error returned by permissions API:

' . htmlspecialchars($response['error']) . '
'); + break; + } + $ret = ob_get_contents(); + ob_end_clean(); + echo + $template->getHeader() . + $ret . + $template->getFooter(); + } + + /** + * Preprocessor to turn the form-submitted data from the ACL editor into something the backend can handle + * @param array The posted data + * @return array + * @access private + */ + + public static function acl_preprocess($parms) + { + if ( !isset($parms['mode']) ) + // Nothing to do + return $parms; + switch ( $parms['mode'] ) + { + case 'seltarget': + + // Who's affected? + $parms['target_type'] = intval( $parms['target_type'] ); + $parms['target_id'] = ( $parms['target_type'] == ACL_TYPE_GROUP ) ? $parms['target_id_grp'] : $parms['target_id_user']; + + case 'save_edit': + case 'save_new': + if ( isset($parms['act_delete_rule']) ) + { + $parms['mode'] = 'delete'; + } + + // Scope (just this page or entire site?) + if ( $parms['scope'] == 'entire_site' || ( $parms['page_id'] == 'false' && $parms['namespace'] == 'false' ) ) + { + $parms['page_id'] = false; + $parms['namespace'] = false; + } + else if ( $parms['scope'] == 'page_group' ) + { + $parms['page_id'] = $parms['pg_id']; + $parms['namespace'] = '__PageGroup'; + } + + break; + } + + if ( isset($parms['act_go_stage1']) ) + { + $parms = array( + 'mode' => 'listgroups' + ); + } + + return $parms; + } + + public static function acl_postprocess($response) + { + if(!isset($response['mode'])) + { + if ( isset($response['groups']) ) + $response['mode'] = 'stage1'; + else + $response = Array( + 'mode' => 'error', + 'error' => 'Invalid action passed by API backend.', + ); + } + return $response; + } + } /** @@ -2462,32 +2462,32 @@ function acl_list_draw_key() { - $out = '
'; - $out .= '
← Deny
'; - $out .= '
Allow →
'; - $out .= 'Neutral'; - $out .= '
'; - // 11 boxes on each side of the center - $inc = ceil ( ( 0xFF - ACL_SCALE_MINIMAL_SHADE ) / 11 ); - for ( $i = ACL_SCALE_MINIMAL_SHADE; $i <= 0xFF; $i+= $inc ) - { - $octet = dechex($i); - $color = "ff$octet$octet"; - $out .= '
 
'; - } - $out .= '
 
'; - for ( $i = 0xFF; $i >= ACL_SCALE_MINIMAL_SHADE; $i-= $inc ) - { - $octet = dechex($i); - $color = "{$octet}ff{$octet}"; - $out .= '
 
'; - } - $out .= '
'; - $out .= '
-100
'; - $out .= '
+100
'; - $out .= '0'; - $out .= '
'; - return $out; + $out = '
'; + $out .= '
← Deny
'; + $out .= '
Allow →
'; + $out .= 'Neutral'; + $out .= '
'; + // 11 boxes on each side of the center + $inc = ceil ( ( 0xFF - ACL_SCALE_MINIMAL_SHADE ) / 11 ); + for ( $i = ACL_SCALE_MINIMAL_SHADE; $i <= 0xFF; $i+= $inc ) + { + $octet = dechex($i); + $color = "ff$octet$octet"; + $out .= '
 
'; + } + $out .= '
 
'; + for ( $i = 0xFF; $i >= ACL_SCALE_MINIMAL_SHADE; $i-= $inc ) + { + $octet = dechex($i); + $color = "{$octet}ff{$octet}"; + $out .= '
 
'; + } + $out .= '
'; + $out .= '
-100
'; + $out .= '
+100
'; + $out .= '0'; + $out .= '
'; + return $out; } /** @@ -2496,43 +2496,43 @@ function get_acl_rule_score($perms) { - global $db, $session, $paths, $template, $plugins; // Common objects - if ( is_string($perms) ) - $perms = $session->string_to_perm($perms); - else if ( !is_array($perms) ) - return false; - $score = 0; - foreach ( $perms as $item ) - { - switch ( $item ) - { - case AUTH_ALLOW : - $inc = 2; - break; - case AUTH_WIKIMODE: - $inc = 1; - break; - case AUTH_DISALLOW: - $inc = -1; - break; - case AUTH_DENY: - $inc = -2; - break; - default: - $inc = 0; - break; - } - $score += $inc; - } - // this is different from the beta; calculate highest score and - // get percentage to be fairer to smaller/less broad rules - $divisor = count($perms) * 2; - if ( $divisor == 0 ) - { - return 0; - } - $score = 100 * ( $score / $divisor ); - return round($score); + global $db, $session, $paths, $template, $plugins; // Common objects + if ( is_string($perms) ) + $perms = $session->string_to_perm($perms); + else if ( !is_array($perms) ) + return false; + $score = 0; + foreach ( $perms as $item ) + { + switch ( $item ) + { + case AUTH_ALLOW : + $inc = 2; + break; + case AUTH_WIKIMODE: + $inc = 1; + break; + case AUTH_DISALLOW: + $inc = -1; + break; + case AUTH_DENY: + $inc = -2; + break; + default: + $inc = 0; + break; + } + $score += $inc; + } + // this is different from the beta; calculate highest score and + // get percentage to be fairer to smaller/less broad rules + $divisor = count($perms) * 2; + if ( $divisor == 0 ) + { + return 0; + } + $score = 100 * ( $score / $divisor ); + return round($score); } ?>