diff -r de56132c008d -r bdac73ed481e includes/comment.php --- a/includes/comment.php Sun Mar 28 21:49:26 2010 -0400 +++ b/includes/comment.php Sun Mar 28 23:10:46 2010 -0400 @@ -20,466 +20,466 @@ class Comments { - # - # VARIABLES - # - - /** - * Current list of comments. - * @var array - */ - - var $comments = Array(); - - /** - * Object to track permissions. - * @var object - */ - - var $perms; - - # - # METHODS - # - - /** - * Constructor. - * @param string Page ID of the page to load comments for - * @param string Namespace of the page to load comments for - */ - - function __construct($page_id, $namespace) - { - global $db, $session, $paths, $template, $plugins; // Common objects - - // Initialize permissions - if ( $page_id == $paths->page_id && $namespace == $paths->namespace ) - $this->perms =& $GLOBALS['session']; - else - $this->perms = $session->fetch_page_acl($page_id, $namespace); - - $this->page_id = $db->escape($page_id); - $this->namespace = $db->escape($namespace); - } - - /** - * Processes a command in JSON format. - * @param mixed Either the JSON-encoded input string, probably something sent from the Javascript/AJAX frontend, or an equivalent array - */ - - function process_json($json) - { - global $db, $session, $paths, $template, $plugins; // Common objects - global $lang; - - $is_json = !is_array($json); - - if ( $is_json ) - { - $data = enano_json_decode($json); - $data = decode_unicode_array($data); - } - else - { - $data =& $json; - } - if ( !isset($data['mode']) ) - { - $ret = Array('mode'=>'error','error'=>'No mode defined!'); - echo enano_json_encode($ret); - return $ret; - } - if ( getConfig('enable_comments', '1') == '0' ) - { - $ret = Array('mode'=>'error','error'=>'Comments are not enabled on this site.'); - echo enano_json_encode($ret); - return $ret; - } - $ret = Array(); - $ret['mode'] = $data['mode']; - if ( isset($data['passback']) ) - $ret['passback'] = $data['passback']; - switch ( $data['mode'] ) - { - case 'fetch': - if ( !$template->theme_loaded ) - $template->load_theme(); - if ( !isset($data['have_template']) ) - { - $ret['template'] = file_get_contents(ENANO_ROOT . '/themes/' . $template->theme . '/comment.tpl'); - } - $approve_clause = $this->perms->get_permissions('mod_comments') ? '' : " AND approved = " . COMMENT_APPROVED; - // Get totals - $q = $db->sql_query('SELECT approved FROM ' . table_prefix . "comments WHERE page_id = '$this->page_id' AND namespace = '$this->namespace'{$approve_clause};"); - if ( !$q ) - $db->die_json(); - $counts = array('total' => 0, 'approved' => 0, 'unapproved' => 0, 'spam' => 0); - while ( $row = $db->fetchrow() ) - { - $counts['total']++; - switch($row['approved']): - case COMMENT_APPROVED: $counts['approved']++; break; - case COMMENT_UNAPPROVED: $counts['unapproved']++; break; - case COMMENT_SPAM: $counts['spam']++; break; - endswitch; - } - $counts['unapproved'] = $counts['total'] - $counts['approved']; - $data['counts'] = $counts; - // FIXME, this should be a user preference eventually - $ret['per_page'] = $per_page = getConfig('comments_per_page', 10); - $page = ( !empty($data['pagenum']) ) ? intval($data['pagenum']) : 0; - if ( $page > 0 ) - { - $ret['mode'] = 'refetch'; - } - $limit_clause = "LIMIT $per_page OFFSET " . ($page * $per_page); - $q = $db->sql_query('SELECT c.comment_id,c.name,c.subject,c.comment_data,c.time,c.approved,( c.ip_address IS NOT NULL ) AS have_ip,u.user_level,u.user_id,u.email,u.signature,u.user_has_avatar,u.avatar_type, b.buddy_id IS NOT NULL AS is_buddy, ( b.is_friend IS NOT NULL AND b.is_friend=1 ) AS is_friend FROM '.table_prefix.'comments AS c - LEFT JOIN '.table_prefix.'users AS u - ON (u.user_id=c.user_id) - LEFT JOIN '.table_prefix.'buddies AS b - ON ( ( b.user_id=' . $session->user_id.' AND b.buddy_user_id=c.user_id ) OR b.user_id IS NULL) - LEFT JOIN '.table_prefix.'ranks AS r - ON ( ( u.user_rank = r.rank_id ) ) - WHERE page_id=\'' . $this->page_id . '\' - AND namespace=\'' . $this->namespace . '\' - ' . $approve_clause . ' - GROUP BY c.comment_id,c.name,c.subject,c.comment_data,c.time,c.approved,c.ip_address,u.user_level,u.user_id,u.email,u.signature,u.user_has_avatar,u.avatar_type,b.buddy_id,b.is_friend - ORDER BY c.time ASC - ' . $limit_clause . ';'); - $ret['comments'] = Array(); - if (!$q) - $db->die_json(); - if ( $row = $db->fetchrow($q) ) - { - do { - - if ( !$this->perms->get_permissions('mod_comments') && $row['approved'] != COMMENT_APPROVED ) - continue; - - // Localize the rank - $row = array_merge($row, $session->get_user_rank(intval($row['user_id']))); - - // Send the source - $row['comment_source'] = $row['comment_data']; - - // Format text - $row['comment_data'] = RenderMan::render($row['comment_data']); - - // Hide it if it's a post from a foe - if ( $row['is_buddy'] == 1 && $row['is_friend'] == 0 ) - { - $seed = md5(sha1(mt_rand() . microtime())); - $wrapper = ' -
-' . $lang->get('comment_msg_foe_comment_hidden') . ' ' . $lang->get('comment_btn_display_foe_comment') . '
- '; - $row['comment_data'] = $wrapper; - } - - // Format date - $row['time'] = enano_date(ED_DATE | ED_TIME, $row['time']); - - // Format signature - $row['signature'] = ( !empty($row['signature']) ) ? RenderMan::render($row['signature']) : ''; - - // Do we have the IP? - $row['have_ip'] = ( $row['have_ip'] == 1 ); - - // Avatar URL - $row['avatar_path'] = make_avatar_url($row['user_id'], $row['avatar_type'], $row['email']); - - // Add the comment to the list - $ret['comments'][] = $row; - - } while ( $row = $db->fetchrow($q) ); - } - $db->free_result(); - $ret['count_appr'] = $counts['approved']; - $ret['count_total'] = $counts['total']; - $ret['count_visible'] = $this->perms->get_permissions('mod_comments') ? $counts['total'] : $counts['approved']; - $ret['count_unappr'] = $counts['unapproved']; - $ret['auth_mod_comments'] = $this->perms->get_permissions('mod_comments'); - $ret['auth_post_comments'] = $this->perms->get_permissions('post_comments'); - $ret['auth_edit_comments'] = $this->perms->get_permissions('edit_comments'); - $ret['auth_edit_wysiwyg'] = $this->perms->get_permissions('edit_wysiwyg'); - $ret['user_id'] = $session->user_id; - $ret['username'] = $session->username; - $ret['logged_in'] = $session->user_logged_in; - - $ret['user_level'] = Array(); - $ret['user_level']['guest'] = USER_LEVEL_GUEST; - $ret['user_level']['member'] = USER_LEVEL_MEMBER; - $ret['user_level']['mod'] = USER_LEVEL_MOD; - $ret['user_level']['admin'] = USER_LEVEL_ADMIN; - - $ret['approval_needed'] = ( getConfig('approve_comments', '0') == '1' ); - $ret['guest_posting'] = getConfig('comments_need_login'); - - if ( $ret['guest_posting'] == '1' && !$session->user_logged_in ) - { - $session->kill_captcha(); - $ret['captcha'] = $session->make_captcha(); - } - break; - case 'edit': - $cid = (string)$data['id']; - if ( !ctype_digit($cid) || intval($cid) < 1 ) - { - echo '{"mode":"error","error":"HACKING ATTEMPT"}'; - return false; - } - $cid = intval($cid); - $q = $db->sql_query('SELECT c.user_id,c.approved FROM '.table_prefix.'comments c LEFT JOIN '.table_prefix.'users u ON (u.user_id=c.user_id) WHERE comment_id='.$cid.';'); - if(!$q) - $db->die_json(); - $row = $db->fetchrow(); - $uid = intval($row['user_id']); - $can_edit = ( ( $uid == $session->user_id && $uid != 1 && $this->perms->get_permissions('edit_comments') ) || ( $this->perms->get_permissions('mod_comments') ) ); - if(!$can_edit) - { - echo '{"mode":"error","error":"HACKING ATTEMPT"}'; - return false; - } - $data['data'] = str_replace("\r", '', $data['data']); // Windows compatibility - $text = RenderMan::preprocess_text($data['data'], true, false); - $text2 = $db->escape($text); - $subj = $db->escape(htmlspecialchars($data['subj'])); - $q = $db->sql_query('UPDATE '.table_prefix.'comments SET subject=\'' . $subj . '\',comment_data=\'' . $text2 . '\' WHERE comment_id=' . $cid . ';'); - if(!$q) - $db->die_json(); - $ret = Array( - 'mode' => 'redraw', - 'id' => $data['local_id'], - 'subj' => htmlspecialchars($data['subj']), - 'text' => RenderMan::render($text), - 'src' => $text, - 'approved' => $row['approved'] - ); - break; - case 'delete': - $cid = (string)$data['id']; - if ( !ctype_digit($cid) || intval($cid) < 1 ) - { - echo '{"mode":"error","error":"HACKING ATTEMPT"}'; - return false; - } - $cid = intval($cid); - $q = $db->sql_query('SELECT c.user_id FROM '.table_prefix.'comments c LEFT JOIN '.table_prefix.'users u ON (u.user_id=c.user_id) WHERE comment_id='.$cid.';'); - if(!$q) - $db->die_json(); - $row = $db->fetchrow(); - $uid = intval($row['user_id']); - $can_edit = ( ( $uid == $session->user_id && $uid != 1 && $this->perms->get_permissions('edit_comments') ) || ( $this->perms->get_permissions('mod_comments') ) ); - if(!$can_edit) - { - echo '{"mode":"error","error":"HACKING ATTEMPT"}'; - return false; - } - $q = $db->sql_query('DELETE FROM '.table_prefix.'comments WHERE comment_id='.$cid.';'); - if(!$q) - $db->die_json(); - $ret = Array( - 'mode' => 'annihilate', - 'id' => $data['local_id'] - ); - break; - case 'submit': - - // Now for a huge round of security checks... - - $errors = Array(); - - // Authorization - // Like the rest of the ACL system, this call is a one-stop check for ALL ACL entries. - if ( !$this->perms->get_permissions('post_comments') ) - $errors[] = 'The site security policy prevents your user account from posting comments;'; - - // Guest authorization - if ( getConfig('comments_need_login') == '2' && !$session->user_logged_in ) - $errors[] = $lang->get('comment_err_need_login'); - - // CAPTCHA code - if ( getConfig('comments_need_login') == '1' && !$session->user_logged_in ) - { - $real_code = $session->get_captcha($data['captcha_id']); - if ( strtolower($real_code) !== strtolower($data['captcha_code']) ) - $errors[] = $lang->get('comment_err_captcha_wrong'); - $session->kill_captcha(); - } - - // Spam check - $spam_policy = getConfig('comment_spam_policy', 'moderate'); - $sc_name = ( $session->user_logged_in ) ? $session->username : $data['name']; - $sc_mail = ( $session->user_logged_in ) ? $session->email : false; - $sc_url = ( $session->user_logged_in ) ? @$session->user_extra['user_homepage'] : false; - $spamcheck = $spam_policy === 'accept' ? true : spamalyze($data['text'], $sc_name, $sc_mail, $sc_url); - if ( !$spamcheck && $spam_policy === 'reject' ) - { - $errors[] = $lang->get('comment_err_spamcheck_failed_rejected'); - } - - if ( count($errors) > 0 ) - { - $ret = Array( - 'mode' => 'error', - 'error' => implode("\n", $errors) - ); - } - else - { - // We're authorized! - - // Preprocess - $name = ( $session->user_logged_in ) ? htmlspecialchars($session->username) : htmlspecialchars($data['name']); - $subj = htmlspecialchars($data['subj']); - $text = RenderMan::preprocess_text($data['text'], true, false); - $src = $text; - $sql_subj = $db->escape($subj); - $sql_text = $db->escape($text); - $text = RenderMan::render($text); - $appr = ( getConfig('approve_comments', '0') == '1' ) ? COMMENT_UNAPPROVED : COMMENT_APPROVED; - if ( $spam_policy === 'moderate' && !$spamcheck ) - $appr = COMMENT_SPAM; - $time = time(); - $date = enano_date(ED_DATE | ED_TIME, $time); - $ip = $_SERVER['REMOTE_ADDR']; - if ( !is_valid_ip($ip) ) - die('Hacking attempt'); - - // Send it to the database - $q = $db->sql_query('INSERT INTO '.table_prefix.'comments(page_id,namespace,name,subject,comment_data,approved, time, user_id, ip_address) VALUES' . "\n " . - "('$this->page_id', '$this->namespace', '$name', '$sql_subj', '$sql_text', $appr, $time, {$session->user_id}, '$ip');"); - if(!$q) - $db->die_json(); - - // Re-fetch - $q = $db->sql_query('SELECT c.comment_id,c.name,c.subject,c.comment_data,c.time,c.approved,u.user_level,u.user_id,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 (u.user_id=c.user_id) - WHERE page_id=\'' . $this->page_id . '\' - AND namespace=\'' . $this->namespace . '\' - AND time='.$time.' ORDER BY comment_id DESC LIMIT 1;'); - if(!$q) - $db->die_json(); - - $row = $db->fetchrow(); - $db->free_result(); - $row['time'] = $date; - $row['comment_data'] = $text; - $row['comment_source'] = $src; - $ret = Array( - 'mode' => 'materialize' - ); - $ret = enano_safe_array_merge($ret, $row); - - $ret['auth_mod_comments'] = $this->perms->get_permissions('mod_comments'); - $ret['auth_post_comments'] = $this->perms->get_permissions('post_comments'); - $ret['auth_edit_comments'] = $this->perms->get_permissions('edit_comments'); - $ret['user_id'] = $session->user_id; - $ret['rank_data'] = $session->get_user_rank($session->user_id); - $ret['username'] = $session->username; - $ret['logged_in'] = $session->user_logged_in; - $ret['signature'] = RenderMan::render($row['signature']); - - $ret['user_level_list'] = Array(); - $ret['user_level_list']['guest'] = USER_LEVEL_GUEST; - $ret['user_level_list']['member'] = USER_LEVEL_MEMBER; - $ret['user_level_list']['mod'] = USER_LEVEL_MOD; - $ret['user_level_list']['admin'] = USER_LEVEL_ADMIN; - $ret['avatar_path'] = make_avatar_url($row['user_id'], $row['avatar_type'], $row['email']); - } - - break; - case 'approve': - if ( !$this->perms->get_permissions('mod_comments') ) - { - $ret = Array( - 'mode' => 'error', - 'error' => 'You are not authorized to moderate comments.' - ); - echo enano_json_encode($ret); - return $ret; - } - - $cid = (string)$data['id']; - if ( !ctype_digit($cid) || intval($cid) < 1 ) - { - echo '{"mode":"error","error":"HACKING ATTEMPT"}'; - return false; - } - $cid = intval($cid); - $q = $db->sql_query('SELECT subject,approved FROM '.table_prefix.'comments WHERE comment_id='.$cid.';'); - if(!$q || $db->numrows() < 1) - $db->die_json(); - $row = $db->fetchrow(); - $db->free_result(); - $appr = ( $row['approved'] == '1' ) ? '0' : '1'; - $q = $db->sql_query('UPDATE '.table_prefix."comments SET approved=$appr WHERE comment_id=$cid;"); - if (!$q) - $db->die_json(); - - $ret = Array( - 'mode' => 'redraw', - 'approved' => $appr, - 'subj' => $row['subject'], - 'id' => $data['local_id'], - 'approve_updated' => 'yes' - ); - - break; - case 'view_ip': - if ( !$session->get_permissions('mod_comments') ) - { - return array( - 'mode' => 'error', - 'error' => 'Unauthorized' - ); - } - // fetch comment info - if ( !is_int($data['id']) ) - { - return array( - 'mode' => 'error', - 'error' => 'Unauthorized' - ); - } - $id =& $data['id']; - $q = $db->sql_query('SELECT ip_address, name FROM ' . table_prefix . 'comments WHERE comment_id = ' . $id . ';'); - if ( !$q || $db->numrows() < 1 ) - { - $db->die_json(); - } - list($ip_addr, $name) = $db->fetchrow_num($q); - $db->free_result(); - $name = $db->escape($name); - $username = $db->escape($session->username); - // log this action - $q = $db->sql_query('INSERT INTO ' . table_prefix . "logs(time_id, log_type, action, page_text, author, author_uid, edit_summary) VALUES\n " - . "( " . time() . ", 'security', 'view_comment_ip', '$name', '$username', $session->user_id, '{$_SERVER['REMOTE_ADDR']}' );"); - if ( !$q ) - $db->die_json(); - - // send packet - $ret = array( - 'mode' => 'redraw', - 'ip_addr' => $ip_addr, - 'local_id' => $data['local_id'] - ); - break; - default: - $ret = Array( - 'mode' => 'error', - 'error' => $data['mode'] . ' is not a valid request mode' - ); - break; - } - if ( $is_json ) - echo enano_json_encode($ret); - - return $ret; - } - + # + # VARIABLES + # + + /** + * Current list of comments. + * @var array + */ + + var $comments = Array(); + + /** + * Object to track permissions. + * @var object + */ + + var $perms; + + # + # METHODS + # + + /** + * Constructor. + * @param string Page ID of the page to load comments for + * @param string Namespace of the page to load comments for + */ + + function __construct($page_id, $namespace) + { + global $db, $session, $paths, $template, $plugins; // Common objects + + // Initialize permissions + if ( $page_id == $paths->page_id && $namespace == $paths->namespace ) + $this->perms =& $GLOBALS['session']; + else + $this->perms = $session->fetch_page_acl($page_id, $namespace); + + $this->page_id = $db->escape($page_id); + $this->namespace = $db->escape($namespace); + } + + /** + * Processes a command in JSON format. + * @param mixed Either the JSON-encoded input string, probably something sent from the Javascript/AJAX frontend, or an equivalent array + */ + + function process_json($json) + { + global $db, $session, $paths, $template, $plugins; // Common objects + global $lang; + + $is_json = !is_array($json); + + if ( $is_json ) + { + $data = enano_json_decode($json); + $data = decode_unicode_array($data); + } + else + { + $data =& $json; + } + if ( !isset($data['mode']) ) + { + $ret = Array('mode'=>'error','error'=>'No mode defined!'); + echo enano_json_encode($ret); + return $ret; + } + if ( getConfig('enable_comments', '1') == '0' ) + { + $ret = Array('mode'=>'error','error'=>'Comments are not enabled on this site.'); + echo enano_json_encode($ret); + return $ret; + } + $ret = Array(); + $ret['mode'] = $data['mode']; + if ( isset($data['passback']) ) + $ret['passback'] = $data['passback']; + switch ( $data['mode'] ) + { + case 'fetch': + if ( !$template->theme_loaded ) + $template->load_theme(); + if ( !isset($data['have_template']) ) + { + $ret['template'] = file_get_contents(ENANO_ROOT . '/themes/' . $template->theme . '/comment.tpl'); + } + $approve_clause = $this->perms->get_permissions('mod_comments') ? '' : " AND approved = " . COMMENT_APPROVED; + // Get totals + $q = $db->sql_query('SELECT approved FROM ' . table_prefix . "comments WHERE page_id = '$this->page_id' AND namespace = '$this->namespace'{$approve_clause};"); + if ( !$q ) + $db->die_json(); + $counts = array('total' => 0, 'approved' => 0, 'unapproved' => 0, 'spam' => 0); + while ( $row = $db->fetchrow() ) + { + $counts['total']++; + switch($row['approved']): + case COMMENT_APPROVED: $counts['approved']++; break; + case COMMENT_UNAPPROVED: $counts['unapproved']++; break; + case COMMENT_SPAM: $counts['spam']++; break; + endswitch; + } + $counts['unapproved'] = $counts['total'] - $counts['approved']; + $data['counts'] = $counts; + // FIXME, this should be a user preference eventually + $ret['per_page'] = $per_page = getConfig('comments_per_page', 10); + $page = ( !empty($data['pagenum']) ) ? intval($data['pagenum']) : 0; + if ( $page > 0 ) + { + $ret['mode'] = 'refetch'; + } + $limit_clause = "LIMIT $per_page OFFSET " . ($page * $per_page); + $q = $db->sql_query('SELECT c.comment_id,c.name,c.subject,c.comment_data,c.time,c.approved,( c.ip_address IS NOT NULL ) AS have_ip,u.user_level,u.user_id,u.email,u.signature,u.user_has_avatar,u.avatar_type, b.buddy_id IS NOT NULL AS is_buddy, ( b.is_friend IS NOT NULL AND b.is_friend=1 ) AS is_friend FROM '.table_prefix.'comments AS c + LEFT JOIN '.table_prefix.'users AS u + ON (u.user_id=c.user_id) + LEFT JOIN '.table_prefix.'buddies AS b + ON ( ( b.user_id=' . $session->user_id.' AND b.buddy_user_id=c.user_id ) OR b.user_id IS NULL) + LEFT JOIN '.table_prefix.'ranks AS r + ON ( ( u.user_rank = r.rank_id ) ) + WHERE page_id=\'' . $this->page_id . '\' + AND namespace=\'' . $this->namespace . '\' + ' . $approve_clause . ' + GROUP BY c.comment_id,c.name,c.subject,c.comment_data,c.time,c.approved,c.ip_address,u.user_level,u.user_id,u.email,u.signature,u.user_has_avatar,u.avatar_type,b.buddy_id,b.is_friend + ORDER BY c.time ASC + ' . $limit_clause . ';'); + $ret['comments'] = Array(); + if (!$q) + $db->die_json(); + if ( $row = $db->fetchrow($q) ) + { + do { + + if ( !$this->perms->get_permissions('mod_comments') && $row['approved'] != COMMENT_APPROVED ) + continue; + + // Localize the rank + $row = array_merge($row, $session->get_user_rank(intval($row['user_id']))); + + // Send the source + $row['comment_source'] = $row['comment_data']; + + // Format text + $row['comment_data'] = RenderMan::render($row['comment_data']); + + // Hide it if it's a post from a foe + if ( $row['is_buddy'] == 1 && $row['is_friend'] == 0 ) + { + $seed = md5(sha1(mt_rand() . microtime())); + $wrapper = ' + +' . $lang->get('comment_msg_foe_comment_hidden') . ' ' . $lang->get('comment_btn_display_foe_comment') . '
+ '; + $row['comment_data'] = $wrapper; + } + + // Format date + $row['time'] = enano_date(ED_DATE | ED_TIME, $row['time']); + + // Format signature + $row['signature'] = ( !empty($row['signature']) ) ? RenderMan::render($row['signature']) : ''; + + // Do we have the IP? + $row['have_ip'] = ( $row['have_ip'] == 1 ); + + // Avatar URL + $row['avatar_path'] = make_avatar_url($row['user_id'], $row['avatar_type'], $row['email']); + + // Add the comment to the list + $ret['comments'][] = $row; + + } while ( $row = $db->fetchrow($q) ); + } + $db->free_result(); + $ret['count_appr'] = $counts['approved']; + $ret['count_total'] = $counts['total']; + $ret['count_visible'] = $this->perms->get_permissions('mod_comments') ? $counts['total'] : $counts['approved']; + $ret['count_unappr'] = $counts['unapproved']; + $ret['auth_mod_comments'] = $this->perms->get_permissions('mod_comments'); + $ret['auth_post_comments'] = $this->perms->get_permissions('post_comments'); + $ret['auth_edit_comments'] = $this->perms->get_permissions('edit_comments'); + $ret['auth_edit_wysiwyg'] = $this->perms->get_permissions('edit_wysiwyg'); + $ret['user_id'] = $session->user_id; + $ret['username'] = $session->username; + $ret['logged_in'] = $session->user_logged_in; + + $ret['user_level'] = Array(); + $ret['user_level']['guest'] = USER_LEVEL_GUEST; + $ret['user_level']['member'] = USER_LEVEL_MEMBER; + $ret['user_level']['mod'] = USER_LEVEL_MOD; + $ret['user_level']['admin'] = USER_LEVEL_ADMIN; + + $ret['approval_needed'] = ( getConfig('approve_comments', '0') == '1' ); + $ret['guest_posting'] = getConfig('comments_need_login'); + + if ( $ret['guest_posting'] == '1' && !$session->user_logged_in ) + { + $session->kill_captcha(); + $ret['captcha'] = $session->make_captcha(); + } + break; + case 'edit': + $cid = (string)$data['id']; + if ( !ctype_digit($cid) || intval($cid) < 1 ) + { + echo '{"mode":"error","error":"HACKING ATTEMPT"}'; + return false; + } + $cid = intval($cid); + $q = $db->sql_query('SELECT c.user_id,c.approved FROM '.table_prefix.'comments c LEFT JOIN '.table_prefix.'users u ON (u.user_id=c.user_id) WHERE comment_id='.$cid.';'); + if(!$q) + $db->die_json(); + $row = $db->fetchrow(); + $uid = intval($row['user_id']); + $can_edit = ( ( $uid == $session->user_id && $uid != 1 && $this->perms->get_permissions('edit_comments') ) || ( $this->perms->get_permissions('mod_comments') ) ); + if(!$can_edit) + { + echo '{"mode":"error","error":"HACKING ATTEMPT"}'; + return false; + } + $data['data'] = str_replace("\r", '', $data['data']); // Windows compatibility + $text = RenderMan::preprocess_text($data['data'], true, false); + $text2 = $db->escape($text); + $subj = $db->escape(htmlspecialchars($data['subj'])); + $q = $db->sql_query('UPDATE '.table_prefix.'comments SET subject=\'' . $subj . '\',comment_data=\'' . $text2 . '\' WHERE comment_id=' . $cid . ';'); + if(!$q) + $db->die_json(); + $ret = Array( + 'mode' => 'redraw', + 'id' => $data['local_id'], + 'subj' => htmlspecialchars($data['subj']), + 'text' => RenderMan::render($text), + 'src' => $text, + 'approved' => $row['approved'] + ); + break; + case 'delete': + $cid = (string)$data['id']; + if ( !ctype_digit($cid) || intval($cid) < 1 ) + { + echo '{"mode":"error","error":"HACKING ATTEMPT"}'; + return false; + } + $cid = intval($cid); + $q = $db->sql_query('SELECT c.user_id FROM '.table_prefix.'comments c LEFT JOIN '.table_prefix.'users u ON (u.user_id=c.user_id) WHERE comment_id='.$cid.';'); + if(!$q) + $db->die_json(); + $row = $db->fetchrow(); + $uid = intval($row['user_id']); + $can_edit = ( ( $uid == $session->user_id && $uid != 1 && $this->perms->get_permissions('edit_comments') ) || ( $this->perms->get_permissions('mod_comments') ) ); + if(!$can_edit) + { + echo '{"mode":"error","error":"HACKING ATTEMPT"}'; + return false; + } + $q = $db->sql_query('DELETE FROM '.table_prefix.'comments WHERE comment_id='.$cid.';'); + if(!$q) + $db->die_json(); + $ret = Array( + 'mode' => 'annihilate', + 'id' => $data['local_id'] + ); + break; + case 'submit': + + // Now for a huge round of security checks... + + $errors = Array(); + + // Authorization + // Like the rest of the ACL system, this call is a one-stop check for ALL ACL entries. + if ( !$this->perms->get_permissions('post_comments') ) + $errors[] = 'The site security policy prevents your user account from posting comments;'; + + // Guest authorization + if ( getConfig('comments_need_login') == '2' && !$session->user_logged_in ) + $errors[] = $lang->get('comment_err_need_login'); + + // CAPTCHA code + if ( getConfig('comments_need_login') == '1' && !$session->user_logged_in ) + { + $real_code = $session->get_captcha($data['captcha_id']); + if ( strtolower($real_code) !== strtolower($data['captcha_code']) ) + $errors[] = $lang->get('comment_err_captcha_wrong'); + $session->kill_captcha(); + } + + // Spam check + $spam_policy = getConfig('comment_spam_policy', 'moderate'); + $sc_name = ( $session->user_logged_in ) ? $session->username : $data['name']; + $sc_mail = ( $session->user_logged_in ) ? $session->email : false; + $sc_url = ( $session->user_logged_in ) ? @$session->user_extra['user_homepage'] : false; + $spamcheck = $spam_policy === 'accept' ? true : spamalyze($data['text'], $sc_name, $sc_mail, $sc_url); + if ( !$spamcheck && $spam_policy === 'reject' ) + { + $errors[] = $lang->get('comment_err_spamcheck_failed_rejected'); + } + + if ( count($errors) > 0 ) + { + $ret = Array( + 'mode' => 'error', + 'error' => implode("\n", $errors) + ); + } + else + { + // We're authorized! + + // Preprocess + $name = ( $session->user_logged_in ) ? htmlspecialchars($session->username) : htmlspecialchars($data['name']); + $subj = htmlspecialchars($data['subj']); + $text = RenderMan::preprocess_text($data['text'], true, false); + $src = $text; + $sql_subj = $db->escape($subj); + $sql_text = $db->escape($text); + $text = RenderMan::render($text); + $appr = ( getConfig('approve_comments', '0') == '1' ) ? COMMENT_UNAPPROVED : COMMENT_APPROVED; + if ( $spam_policy === 'moderate' && !$spamcheck ) + $appr = COMMENT_SPAM; + $time = time(); + $date = enano_date(ED_DATE | ED_TIME, $time); + $ip = $_SERVER['REMOTE_ADDR']; + if ( !is_valid_ip($ip) ) + die('Hacking attempt'); + + // Send it to the database + $q = $db->sql_query('INSERT INTO '.table_prefix.'comments(page_id,namespace,name,subject,comment_data,approved, time, user_id, ip_address) VALUES' . "\n " . + "('$this->page_id', '$this->namespace', '$name', '$sql_subj', '$sql_text', $appr, $time, {$session->user_id}, '$ip');"); + if(!$q) + $db->die_json(); + + // Re-fetch + $q = $db->sql_query('SELECT c.comment_id,c.name,c.subject,c.comment_data,c.time,c.approved,u.user_level,u.user_id,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 (u.user_id=c.user_id) + WHERE page_id=\'' . $this->page_id . '\' + AND namespace=\'' . $this->namespace . '\' + AND time='.$time.' ORDER BY comment_id DESC LIMIT 1;'); + if(!$q) + $db->die_json(); + + $row = $db->fetchrow(); + $db->free_result(); + $row['time'] = $date; + $row['comment_data'] = $text; + $row['comment_source'] = $src; + $ret = Array( + 'mode' => 'materialize' + ); + $ret = enano_safe_array_merge($ret, $row); + + $ret['auth_mod_comments'] = $this->perms->get_permissions('mod_comments'); + $ret['auth_post_comments'] = $this->perms->get_permissions('post_comments'); + $ret['auth_edit_comments'] = $this->perms->get_permissions('edit_comments'); + $ret['user_id'] = $session->user_id; + $ret['rank_data'] = $session->get_user_rank($session->user_id); + $ret['username'] = $session->username; + $ret['logged_in'] = $session->user_logged_in; + $ret['signature'] = RenderMan::render($row['signature']); + + $ret['user_level_list'] = Array(); + $ret['user_level_list']['guest'] = USER_LEVEL_GUEST; + $ret['user_level_list']['member'] = USER_LEVEL_MEMBER; + $ret['user_level_list']['mod'] = USER_LEVEL_MOD; + $ret['user_level_list']['admin'] = USER_LEVEL_ADMIN; + $ret['avatar_path'] = make_avatar_url($row['user_id'], $row['avatar_type'], $row['email']); + } + + break; + case 'approve': + if ( !$this->perms->get_permissions('mod_comments') ) + { + $ret = Array( + 'mode' => 'error', + 'error' => 'You are not authorized to moderate comments.' + ); + echo enano_json_encode($ret); + return $ret; + } + + $cid = (string)$data['id']; + if ( !ctype_digit($cid) || intval($cid) < 1 ) + { + echo '{"mode":"error","error":"HACKING ATTEMPT"}'; + return false; + } + $cid = intval($cid); + $q = $db->sql_query('SELECT subject,approved FROM '.table_prefix.'comments WHERE comment_id='.$cid.';'); + if(!$q || $db->numrows() < 1) + $db->die_json(); + $row = $db->fetchrow(); + $db->free_result(); + $appr = ( $row['approved'] == '1' ) ? '0' : '1'; + $q = $db->sql_query('UPDATE '.table_prefix."comments SET approved=$appr WHERE comment_id=$cid;"); + if (!$q) + $db->die_json(); + + $ret = Array( + 'mode' => 'redraw', + 'approved' => $appr, + 'subj' => $row['subject'], + 'id' => $data['local_id'], + 'approve_updated' => 'yes' + ); + + break; + case 'view_ip': + if ( !$session->get_permissions('mod_comments') ) + { + return array( + 'mode' => 'error', + 'error' => 'Unauthorized' + ); + } + // fetch comment info + if ( !is_int($data['id']) ) + { + return array( + 'mode' => 'error', + 'error' => 'Unauthorized' + ); + } + $id =& $data['id']; + $q = $db->sql_query('SELECT ip_address, name FROM ' . table_prefix . 'comments WHERE comment_id = ' . $id . ';'); + if ( !$q || $db->numrows() < 1 ) + { + $db->die_json(); + } + list($ip_addr, $name) = $db->fetchrow_num($q); + $db->free_result(); + $name = $db->escape($name); + $username = $db->escape($session->username); + // log this action + $q = $db->sql_query('INSERT INTO ' . table_prefix . "logs(time_id, log_type, action, page_text, author, author_uid, edit_summary) VALUES\n " + . "( " . time() . ", 'security', 'view_comment_ip', '$name', '$username', $session->user_id, '{$_SERVER['REMOTE_ADDR']}' );"); + if ( !$q ) + $db->die_json(); + + // send packet + $ret = array( + 'mode' => 'redraw', + 'ip_addr' => $ip_addr, + 'local_id' => $data['local_id'] + ); + break; + default: + $ret = Array( + 'mode' => 'error', + 'error' => $data['mode'] . ' is not a valid request mode' + ); + break; + } + if ( $is_json ) + echo enano_json_encode($ret); + + return $ret; + } + } // class Comments