Вход Регистрация
Файл: textpattern-4.5.7/textpattern/publish/comment.php
Строк: 577
<?php

/*
    This is Textpattern
    Copyright 2005 by Dean Allen - all rights reserved.

    Use of this software denotes acceptance of the Textpattern license agreement

$HeadURL: https://textpattern.googlecode.com/svn/releases/4.5.7/source/textpattern/publish/comment.php $
$LastChangedRevision: 4058 $

*/

// -------------------------------------------------------------
    
function fetchComments($id)
    {
        
$rs safe_rows(
            
"*, unix_timestamp(posted) as time",
            
"txp_discuss"'parentid='.intval($id).' and visible='.VISIBLE.' order by posted asc'
        
);

        if (
$rs) return $rs;
    }

// -------------------------------------------------------------
    
function discuss($id)
    {
        
$rs safe_row('*, unix_timestamp(Posted) as uPosted, unix_timestamp(LastMod) as uLastMod, unix_timestamp(Expires) as uExpires''textpattern''ID='.intval($id).' and Status >= 4');
        if (
$rs) {
            
populateArticleData($rs);
            
$result parse_form('comments_display');
            return 
$result;
        }

        return 
'';
    }


// -------------------------------------------------------------
    
function getNextNonce($check_only false)
    {
        static 
$nonce '';
        if (!
$nonce && !$check_only)
            
$nonce md5uniqidrand(), true ) );
        return 
$nonce;
    }
    function 
getNextSecret($check_only false)
    {
        static 
$secret '';
        if (!
$secret && !$check_only)
            
$secret md5uniqidrand(), true ) );
        return 
$secret;
    }

    function 
commentForm($id$atts=NULL)
    {
        global 
$prefs;
        
extract($prefs);

        
$h5 = ($doctype == 'html5');

        
extract(lAtts(array(
            
'isize'         => '25',
            
'msgrows'       => '5',
            
'msgcols'       => '25',
            
'msgstyle'      => '',
            
'form'          => 'comment_form',
            
'previewlabel'  => gTxt('preview'),
            
'submitlabel'   => gTxt('submit'),
            
'rememberlabel' => gTxt('remember'),
            
'forgetlabel'   => gTxt('forget')
        ),
$atts0));

        
$namewarn false;
        
$emailwarn false;
        
$commentwarn false;
        
$name  pcs('name');
        
$email clean_url(pcs('email'));
        
$web   clean_url(pcs('web'));
        
$n_message 'message';

        
extractdoDeEnt psa( array(
            
'checkbox_type',
            
'remember',
            
'forget',
            
'parentid',
            
'preview',
            
'message',
            
'submit',
            
'backpage'
        
) ) ) );
        if (
$message == '')
        {    
//Second or later preview will have randomized message-field name
            
$in getComment();
            
$message doDeEnt($in['message']);
        }
        if ( 
$preview ) {
            
$name  ps('name');
            
$email clean_url(ps('email'));
            
$web   clean_url(ps('web'));
            
$nonce getNextNonce();
            
$secret getNextSecret();
            
safe_insert("txp_discuss_nonce""issue_time=now(), nonce='".doSlash($nonce)."', secret='".doSlash($secret)."'");
            
$n_message md5('message'.$secret);

            
$namewarn = ($comments_require_name && !trim($name));
            
$emailwarn = ($comments_require_email && !trim($email));
            
$commentwarn = (!trim($message));

            
$evaluator =& get_comment_evaluator();
            if (
$namewarn$evaluator -> add_estimate(RELOAD,1,gTxt('comment_name_required'));
            if (
$emailwarn$evaluator -> add_estimate(RELOAD,1,gTxt('comment_email_required'));
            if (
$commentwarn$evaluator -> add_estimate(RELOAD,1,gTxt('comment_required'));

        }
        else
        {
            
$rememberCookie cs('txp_remember');
            if(
$rememberCookie === '')
            {
                
$checkbox_type 'remember';
                
$remember 1;
            }
            else if(
$rememberCookie == 1)
                
$checkbox_type 'forget';
            else
                
$checkbox_type 'remember';
        }

        
// If the form fields are filled (anything other than blank), pages
        // really should not be saved by a public cache. rfc2616/14.9.1
        
if ($name || $email || $web) {
            
header('Cache-Control: private');
        }

        
$parentid = (!$parentid) ? $id $parentid;

        
$url $GLOBALS['pretext']['request_uri'];

        
// Experimental clean urls with only 404-error-document on apache
        // possibly requires messy urls for POST requests.
        
if (defined('PARTLY_MESSY') and (PARTLY_MESSY))
        {
            
$url hu.'?id='.intval($parentid);
        }

        
$out '<form id="txpCommentInputForm" method="post" action="'.txpspecialchars($url).'#cpreview">'.

            
# prevent XHTML Strict validation gotchas
            
n.'<div class="comments-wrapper">'.n.n;

        
$Form fetch('Form''txp_form''name'$form);

        
$required = ($h5) ? ' required' '';

        
$msgstyle = ($msgstyle ' style="'.$msgstyle.'"' '');
        
$msgrows = ($msgrows and is_numeric($msgrows)) ? ' rows="'.intval($msgrows).'"' '';
        
$msgcols = ($msgcols and is_numeric($msgcols)) ? ' cols="'.intval($msgcols).'"' '';

        
$textarea '<textarea id="message" name="'.$n_message.'"'.$msgcols.$msgrows.$msgstyle.$required.
            
' class="txpCommentInputMessage'.(($commentwarn) ? ' comments_error"' '"').
            
'>'.txpspecialchars(substr(trim($message), 065535)).'</textarea>';

        
// by default, the submit button is visible but disabled
        
$comment_submit_button fInput('submit''submit'$submitlabel'button disabled''''''''''txpCommentSubmit'true);

        
// if all fields checkout, the submit button is active/clickable
        
if ($preview) {
            
$comment_submit_button fInput('submit''submit'$submitlabel'button''''''''''txpCommentSubmit'false);
        }

        if (
$checkbox_type == 'forget')
        {
            
// inhibit default remember
            
if ($forget == 1)
            {
                
destroyCookies();
            }

            
$checkbox checkbox('forget'1$forget'''forget').' '.tag(txpspecialchars($forgetlabel), 'label'' for="forget"');
        }

        else
        {
            
// inhibit default remember
            
if ($remember != 1)
            {
                
destroyCookies();
            }

            
$checkbox checkbox('remember'1$remember'''remember').' '.tag(txpspecialchars($rememberlabel), 'label'' for="remember"');
        }

        
$checkbox .= ' '.hInput('checkbox_type'$checkbox_type);

        
$vals = array(
            
'comment_name_input'    => fInput('text''name'$name'comment_name_input'.($namewarn ' comments_error' ''), ''''$isize'''name'false$h5 && $comments_require_name),
            
'comment_email_input'   => fInput($h5 'email' 'text''email'$email'comment_email_input'.($emailwarn ' comments_error' ''), ''''$isize'''email'false$h5 && $comments_require_email),
            
'comment_web_input'     => fInput($h5 'text' /* TODO: type = 'url' once browsers are less strict */ 'text''web'$web'comment_web_input'''''$isize'''web'falsefalse),
            
'comment_message_input' => $textarea.'<!-- plugin-place-holder -->',
            
'comment_remember'      => $checkbox,
            
'comment_preview'       => fInput('submit''preview'$previewlabel'button''''''''''txpCommentPreview'false),
            
'comment_submit'        => $comment_submit_button
        
);

        foreach (
$vals as $a => $b)
        {
            
$Form str_replace('<txp:'.$a.' />'$b$Form);
        }

        
$form parse($Form);

        
$out .= $form.
            
n.hInput('parentid'$parentid);

        
$split rand(131);

        
$out .= ($preview) ? n.hInput(substr($nonce0$split), substr($nonce$split)) : '';

        
$out .= (!$preview) ?
            
n.hInput('backpage'$url) :
            
n.hInput('backpage'$backpage);

        
$out str_replace'<!-- plugin-place-holder -->'callback_event('comment.form'), $out);

        
$out .= n.n.'</div>'.n.'</form>';

        return 
$out;
    }

// -------------------------------------------------------------
    
function popComments($id)
    {
        global 
$sitename,$s,$thisarticle;
        
$preview gps('preview');
        
$h3 = ($preview) ? hed(gTxt('message_preview'),3) : '';
        
$discuss discuss($id);
        
ob_start('parse');
        
$out fetch_form('popup_comments');
        
$out str_replace("<txp:popup_comments />",$discuss,$out);

        return 
$out;
    }

// -------------------------------------------------------------
    
function setCookies($name,$email,$web)
    {
        
$cookietime time() + (365*24*3600);
        
ob_start();
        
setcookie("txp_name",  $name,  $cookietime"/");
        
setcookie("txp_email"$email$cookietime"/");
        
setcookie("txp_web",   $web,     $cookietime"/");
        
setcookie("txp_last",  date("H:i d/m/Y"),$cookietime,"/");
        
setcookie("txp_remember"'1'$cookietime"/");
    }

// -------------------------------------------------------------
    
function destroyCookies()
    {
        
$cookietime time()-3600;
        
ob_start();
        
setcookie("txp_name",  ''$cookietime"/");
        
setcookie("txp_email"''$cookietime"/");
        
setcookie("txp_web",   ''$cookietime"/");
        
setcookie("txp_last",  ''$cookietime"/");
        
setcookie("txp_remember"'0'$cookietime + (365*25*3600), "/");
    }

// -------------------------------------------------------------
    
function getComment()
    {
        
// comment spam filter plugins: call this function to fetch comment contents

        
$c psa( array(
            
'parentid',
            
'name',
            
'email',
            
'web',
            
'message',
            
'backpage',
            
'remember'
        
) );

        
$n = array();

        foreach (
stripPost() as $k => $v)
        {
            if (
preg_match('#^[A-Fa-f0-9]{32}$#'$k.$v))
            {
                
$n[] = doSlash($k.$v);
            }
        }

        
$c['nonce'] = '';
        
$c['secret'] = '';
        if (!empty(
$n)) {
            
$rs safe_row('nonce, secret''txp_discuss_nonce'"nonce in ('".join("','"$n)."')");
            
$c['nonce'] = $rs['nonce'];
            
$c['secret'] = $rs['secret'];
        }
        
$c['message'] = ps(md5('message'.$c['secret']));
        return 
$c;
    }

// -------------------------------------------------------------
    
function saveComment()
    {
        global 
$siteurl,$comments_moderate,$comments_sendmail,
            
$comments_disallow_images,$prefs;

        
$ref serverset('HTTP_REFERRER');
        
$in getComment();
        
$evaluator =& get_comment_evaluator();

        
extract($in);

        if (!
checkCommentsAllowed($parentid))
            
txp_die(gTxt('comments_closed'), '403');

        
$ip serverset('REMOTE_ADDR');

        if (!
checkBan($ip))
            
txp_die(gTxt('you_have_been_banned'), '403');

        
$blacklisted is_blacklisted($ip);
        if (
$blacklisted)
            
txp_die(gTxt('your_ip_is_blacklisted_by'.' '.$blacklisted), '403');

        
$web clean_url($web);
        
$email clean_url($email);
        if (
$remember == || ps('checkbox_type') == 'forget' && ps('forget') != 1)
            
setCookies($name$email$web);
        else
            
destroyCookies();

        
$name doSlash(strip_tags(deEntBrackets($name)));
        
$web doSlash(strip_tags(deEntBrackets($web)));
        
$email doSlash(strip_tags(deEntBrackets($email)));

        
$message substr(trim($message), 065535);
        
$message2db doSlash(markup_comment($message));

        
$isdup safe_row("message,name""txp_discuss",
            
"name='$name' and message='$message2db' and ip='".doSlash($ip)."'");

        if (   (
$prefs['comments_require_name'] && !trim($name))
            || (
$prefs['comments_require_email'] && !trim($email))
            || (!
trim($message)))
        {
            
$evaluator -> add_estimate(RELOAD,1); // The error-messages are added in the preview-code
        
}

        if (
$isdup)
            
$evaluator -> add_estimate(RELOAD,1); // FIXME? Tell the user about dupe?

        
if ( ($evaluator->get_result() != RELOAD) && checkNonce($nonce) ) {
            
callback_event('comment.save');
            
$visible $evaluator->get_result();
            if (
$visible != RELOAD) {
                
$parentid assert_int($parentid);
                
$commentid safe_insert(
                    
"txp_discuss",
                    
"parentid = $parentid,
                     name     = '
$name',
                     email    = '
$email',
                     web      = '
$web',
                     ip       = '"
.doSlash($ip)."',
                     message  = '
$message2db',
                     visible  = "
.intval($visible).",
                     posted   = now()"
                
);
                if (
$commentid) {
                    
safe_update("txp_discuss_nonce""used = 1""nonce='".doSlash($nonce)."'");
                    if (
$prefs['comment_means_site_updated']) {
                        
update_lastmod();
                    }
                    
callback_event('comment.saved'''falsecompact('message''name''email''web''parentid''commentid''ip''visible'));
                    
mail_comment($message$name$email$web$parentid$commentid);

                    
$updated update_comments_count($parentid);

                    
$backpage substr($backpage0$prefs['max_url_len']);
                    
$backpage preg_replace("/[x0ax0d#].*$/s",'',$backpage);
                    
$backpage preg_replace("#(https?://[^/]+)/.*$#","$1",hu).$backpage;
                    if (
defined('PARTLY_MESSY') and (PARTLY_MESSY))
                    {
                        
$backpage permlinkurl_id($parentid);
                    }
                    
$backpage .= ((strstr($backpage,'?')) ? '&' '?') . 'commented='.(($visible==VISIBLE) ? '1' '0');

                    
txp_status_header('302 Found');
                    if(
$comments_moderate){
                        
header('Location: '.$backpage.'#txpCommentInputForm');
                    }else{
                        
header('Location: '.$backpage.'#c'.sprintf("%06s",$commentid));
                    }
                    
log_hit('302');
                    
$evaluator->write_trace();
                    exit;
                }
            }
        }
        
// Force another Preview
        
$_POST['preview'] = RELOAD;
        
//$evaluator->write_trace();
    
}

// -------------------------------------------------------------
    
class comment_evaluation {
        var 
$status;
        var 
$message;
        var 
$txpspamtrace = array();
        var 
$status_text = array();

        function 
comment_evaluation() {
            global 
$prefs;
            
extract(getComment());
            
$this->status = array( SPAM     => array(),
                                   
MODERATE => array(),
                                   
VISIBLE  => array(),
                                   
RELOAD   => array()
                                );
            
$this->status_text = array(    SPAM => gTxt('spam'),
                                    
MODERATE => gTxt('unmoderated'),
                                    
VISIBLE  => gTxt('visible'),
                                    
RELOAD   => gTxt('reload')
                                );
            
$this->message $this->status;
            
$this -> txpspamtrace[] = "Comment on $parentid by $name (".safe_strftime($prefs['archive_dateformat'],time()).")";
            if (
$prefs['comments_moderate'])
                
$this->status[MODERATE][]=0.5;
            else
                
$this->status[VISIBLE][]=0.5;
        }

        function 
add_estimate($type SPAM$probability 0.75$msg='') {
            global 
$production_status;

            if (!
array_key_exists($type$this->status))
                
trigger_error(gTxt('unknown_spam_estimate'), E_USER_WARNING);

            
$this -> txpspamtrace[] = "   $type; ".max(0,min(1,$probability))."; $msg";
            
//FIXME trace is only viewable for RELOADS. Maybe add info to HTTP-Headers in debug-mode

            
$this->status[$type][] = max(0,min(1,$probability));
            if (
trim($msg)) $this->message[$type][] = $msg;
        }

        function 
get_result($result_type='numeric') {
            
$result = array();
            foreach (
$this->status as $key => $value)
                
$result[$key] = array_sum($value)/max(1,count($value));
            
arsort($resultSORT_NUMERIC);
            
reset($result);
            return ((
$result_type == 'numeric') ? key($result) : $this->status_text[key($result)]);
        }
        function 
get_result_message() {
            return 
$this->message[$this->get_result()];
        }
        function 
write_trace() {
            global 
$prefs;
            
$file $prefs['tempdir'].DS.'evaluator_trace.php';
            if (!
file_exists($file)) {
                
$fp fopen($file,'wb');
                if (
$fp)
                    
fwrite($fp,"<?php return; ?>n".
                    
"This trace-file tracks saved comments. (created ".safe_strftime($prefs['archive_dateformat'],time()).")n".
                    
"Format is: Type; Probability; Message (Type can be -1 => spam, 0 => moderate, 1 => visible)nn");
            } else {
                
$fp fopen($file,'ab');
            }
            if (
$fp) {
                
fwrite($fpimplode("n"$this->txpspamtrace ));
                
fwrite($fp"n  RESULT: ".$this->get_result()."nn");
                
fclose($fp);
            }
        }
    }

    function &
get_comment_evaluator() {
        static 
$instance;

        
// If the instance is not there, create one
        
if(!isset($instance)) {
            
$instance = new comment_evaluation();
        }
        return 
$instance;
    }

// -------------------------------------------------------------
    
function checkNonce($nonce)
    {
        if (!
$nonce || !preg_match('#^[a-zA-Z0-9]*$#',$nonce))
            return 
false;
            
// delete expired nonces
        
safe_delete("txp_discuss_nonce""issue_time < date_sub(now(),interval 10 minute)");
            
// check for nonce
        
return (safe_row("*""txp_discuss_nonce""nonce='".doSlash($nonce)."' and used = 0")) ? true false;
    }

// -------------------------------------------------------------
    
function checkBan($ip)
    {
        return (!
fetch("ip""txp_discuss_ipban""ip"$ip)) ? true false;
    }

// -------------------------------------------------------------
    
function checkCommentsAllowed($id)
    {
        global 
$use_comments$comments_disabled_after$thisarticle;

        
$id intval($id);

        if (!
$use_comments || !$id)
            return 
false;

        if (isset(
$thisarticle['thisid']) && ($thisarticle['thisid'] == $id) && isset($thisarticle['annotate']))
        {
            
$Annotate $thisarticle['annotate'];
            
$uPosted  $thisarticle['posted'];
        }
        else
        {
            
extract(
                
safe_row(
                    
"Annotate,unix_timestamp(Posted) as uPosted",
                        
"textpattern""ID = $id"
                
)
            );
        }

        if (
$Annotate != 1)
            return 
false;

        if(
$comments_disabled_after) {
            
$lifespan = ( $comments_disabled_after 86400 );
            
$timesince = ( time() - $uPosted );
            return ( 
$lifespan $timesince );
        }

        return 
true;
    }

// -------------------------------------------------------------
        
function comments_help()
    {
        return (
'<a id="txpCommentHelpLink" href="'.HELP_URL.'?item=textile_comments&amp;language='.LANG.'" onclick="window.open(this.href, 'popupwindow', 'width=300,height=400,scrollbars,resizable'); return false;">'.gTxt('textile_help').'</a>');
    }

// -------------------------------------------------------------
    
function mail_comment($message$cname$cemail$cweb$parentid$discussid)
    {
        global 
$sitename$comments_sendmail;

        if (!
$comments_sendmail) return;
        
$evaluator =& get_comment_evaluator();
        if (
$comments_sendmail == && $evaluator->get_result() == SPAM) return;

        
$parentid assert_int($parentid);
        
$discussid assert_int($discussid);
        
$article safe_row("Section, Posted, ID, url_title, AuthorID, Title""textpattern""ID = $parentid");
        
extract($article);
        
extract(safe_row("RealName, email""txp_users""name = '".doSlash($AuthorID)."'"));

        
$out gTxt('greeting').$RealName,".n.n;
        
$out .= str_replace('{title}',$Title,gTxt('comment_recorded')).n;
        
$out .= permlinkurl_id($parentid).n;
        if (
has_privs('discuss'$AuthorID))
            
$out .= hu.'textpattern/index.php?event=discuss&step=discuss_edit&discussid='.$discussid.n;
        
$out .= gTxt('status').": ".$evaluator->get_result('text').'. '.implode(',',$evaluator->get_result_message()).n;
        
$out .= n;
        
$out .= gTxt('comment_name').": $cname".n;
        
$out .= gTxt('comment_email').": $cemail".n;
        
$out .= gTxt('comment_web').": $cweb".n;
        
$out .= gTxt('comment_comment').": $message";

        
$subject strtr(gTxt('comment_received'),array('{site}' => $sitename'{title}' => $Title));

        
$success txpMail($email$subject$out$cemail);
    }

// -------------------------------------------------------------
    # deprecated, use fInput instead
    
function input($type,$name,$val,$size='',$class='',$tab='',$chkd='')
    {
        
trigger_error(gTxt('deprecated_function_with', array('{name}' => __FUNCTION__'{with}' => 'fInput')), E_USER_NOTICE);
        
$o = array(
            
'<input type="'.$type.'" name="'.$name.'" id="'.$name.'" value="'.$val.'"',
            (
$size)    ? ' size="'.$size.'"'      '',
            (
$class) ? ' class="'.$class.'"'    '',
            (
$tab)     ? ' tabindex="'.$tab.'"'    '',
            (
$chkd)    ? ' checked="checked"'    '',
            
' />'.n
        
);
        return 
join('',$o);
    }

?>
Онлайн: 3
Реклама