[ Index ]

PHP Cross Reference of Textpattern 4.0.8

title

Body

[close]

/textpattern/publish/ -> comment.php (source)

   1  <?php
   2  
   3  /*
   4      This is Textpattern
   5      Copyright 2005 by Dean Allen - all rights reserved.
   6  
   7      Use of this software denotes acceptance of the Textpattern license agreement
   8  
   9  $HeadURL: https://textpattern.googlecode.com/svn/releases/4.0.8/source/textpattern/publish/comment.php $
  10  $LastChangedRevision: 3011 $
  11  
  12  */
  13  
  14  // -------------------------------------------------------------
  15  	function fetchComments($id)
  16      {
  17          $rs = safe_rows(
  18              "*, unix_timestamp(posted) as time",
  19              "txp_discuss", 'parentid='.intval($id).' and visible='.VISIBLE.' order by posted asc'
  20          );
  21  
  22          if ($rs) return $rs;
  23      }
  24  
  25  // -------------------------------------------------------------
  26  	function discuss($id)
  27      {
  28          $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');
  29          if ($rs) {
  30              populateArticleData($rs);
  31              $result = parse_form('comments_display');
  32              return $result;
  33          }
  34  
  35          return '';
  36      }
  37  
  38  
  39  // -------------------------------------------------------------
  40  	function getNextNonce($check_only = false)
  41      {
  42          static $nonce = '';
  43          if (!$nonce && !$check_only)
  44              $nonce = md5( uniqid( rand(), true ) );
  45          return $nonce;
  46      }
  47  	function getNextSecret($check_only = false)
  48      {
  49          static $secret = '';
  50          if (!$secret && !$check_only)
  51              $secret = md5( uniqid( rand(), true ) );
  52          return $secret;
  53      }
  54  
  55  	function commentForm($id, $atts=NULL)
  56      {
  57          global $prefs;
  58          extract($prefs);
  59  
  60          extract(lAtts(array(
  61              'isize'      => '25',
  62              'msgrows'   => '5',
  63              'msgcols'   => '25',
  64              'msgstyle'  => '',
  65              'form'   => 'comment_form',
  66          ),$atts, 0));
  67  
  68          $namewarn = false;
  69          $emailwarn = false;
  70          $commentwarn = false;
  71          $name  = pcs('name');
  72          $email = clean_url(pcs('email'));
  73          $web   = clean_url(pcs('web'));
  74          $n_message = 'message';
  75  
  76          extract( doDeEnt ( psa( array(
  77              'checkbox_type',
  78              'remember',
  79              'forget',
  80              'parentid',
  81              'preview',
  82              'message',
  83              'submit',
  84              'backpage'
  85          ) ) ) );
  86          if ($message == '')
  87          {    //Second or later preview will have randomized message-field name
  88              $in = getComment();
  89              $message = doDeEnt($in['message']);
  90          }
  91          if ( $preview ) {
  92              $name  = ps('name');
  93              $email = clean_url(ps('email'));
  94              $web   = clean_url(ps('web'));
  95              $nonce = getNextNonce();
  96              $secret = getNextSecret();
  97              safe_insert("txp_discuss_nonce", "issue_time=now(), nonce='".doSlash($nonce)."', secret='".doSlash($secret)."'");
  98              $n_message = md5('message'.$secret);
  99  
 100              $namewarn = ($comments_require_name && !trim($name));
 101              $emailwarn = ($comments_require_email && !trim($email));
 102              $commentwarn = (!trim($message));
 103  
 104              $evaluator =& get_comment_evaluator();
 105              if ($namewarn) $evaluator -> add_estimate(RELOAD,1,gTxt('comment_name_required'));
 106              if ($emailwarn) $evaluator -> add_estimate(RELOAD,1,gTxt('comment_email_required'));
 107              if ($commentwarn) $evaluator -> add_estimate(RELOAD,1,gTxt('comment_required'));
 108  
 109          }
 110          else
 111          {
 112              $rememberCookie = cs('txp_remember');
 113              if($rememberCookie === '')
 114              {
 115                  $checkbox_type = 'remember';
 116                  $remember = 1;
 117              }
 118              else if($rememberCookie == 1)
 119                  $checkbox_type = 'forget';
 120              else
 121                  $checkbox_type = 'remember';
 122          }
 123  
 124          // If the form fields are filled (anything other than blank), pages
 125          // really should not be saved by a public cache. rfc2616/14.9.1
 126          if ($name || $email || $web) {
 127              header('Cache-Control: private');
 128          }
 129  
 130          $parentid = (!$parentid) ? $id : $parentid;
 131  
 132          $url = $GLOBALS['pretext']['request_uri'];
 133  
 134          // Experimental clean urls with only 404-error-document on apache
 135          // possibly requires messy urls for POST requests.
 136          if (defined('PARTLY_MESSY') and (PARTLY_MESSY))
 137          {
 138              $url = hu.'?id='.intval($parentid);
 139          }
 140  
 141          $out = '<form id="txpCommentInputForm" method="post" action="'.htmlspecialchars($url).'#cpreview">'.
 142  
 143              # prevent XHTML Strict validation gotchas
 144              n.'<div class="comments-wrapper">'.n.n;
 145  
 146          $Form = fetch('Form', 'txp_form', 'name', $form);
 147  
 148          $msgstyle = ($msgstyle ? ' style="'.$msgstyle.'"' : '');
 149          $msgrows = ($msgrows and is_numeric($msgrows)) ? ' rows="'.intval($msgrows).'"' : '';
 150          $msgcols = ($msgcols and is_numeric($msgcols)) ? ' cols="'.intval($msgcols).'"' : '';
 151  
 152          $textarea = '<textarea id="message" name="'.$n_message.'"'.$msgcols.$msgrows.$msgstyle.
 153              ' class="txpCommentInputMessage'.(($commentwarn) ? ' comments_error"' : '"').
 154              '>'.htmlspecialchars(substr(trim($message), 0, 65535)).'</textarea>';
 155  
 156          // by default, the submit button is visible but disabled
 157          $comment_submit_button = fInput('submit', 'submit', gTxt('submit'), 'button disabled', '', '', '', '', 'txpCommentSubmit', true);
 158  
 159          // if all fields checkout, the submit button is active/clickable
 160          if ($preview) {
 161              $comment_submit_button = fInput('submit', 'submit', gTxt('submit'), 'button', '', '', '', '', 'txpCommentSubmit', false);
 162          }
 163  
 164          if ($checkbox_type == 'forget')
 165          {
 166              // inhibit default remember
 167              if ($forget == 1)
 168              {
 169                  destroyCookies();
 170              }
 171  
 172              $checkbox = checkbox('forget', 1, $forget, '', 'forget').' '.tag(gTxt('forget'), 'label', ' for="forget"');
 173          }
 174  
 175          else
 176          {
 177              // inhibit default remember
 178              if ($remember != 1)
 179              {
 180                  destroyCookies();
 181              }
 182  
 183              $checkbox = checkbox('remember', 1, $remember, '', 'remember').' '.tag(gTxt('remember'), 'label', ' for="remember"');
 184          }
 185  
 186          $checkbox .= ' '.hInput('checkbox_type', $checkbox_type);
 187  
 188          $vals = array(
 189              'comment_name_input'        => fInput('text', 'name', htmlspecialchars($name), 'comment_name_input'.($namewarn ? ' comments_error' : ''), '', '', $isize, '', 'name'),
 190              'comment_email_input'        => fInput('text', 'email', htmlspecialchars($email), 'comment_email_input'.($emailwarn ? ' comments_error' : ''), '', '', $isize, '', 'email'),
 191              'comment_web_input'            => fInput('text', 'web', htmlspecialchars($web)    , 'comment_web_input', '', '', $isize, '', 'web'),
 192              'comment_message_input'     => $textarea.'<!-- plugin-place-holder -->',
 193              'comment_remember'            => $checkbox,
 194              'comment_preview'            => fInput('submit', 'preview', gTxt('preview'), 'button', '', '', '', '', 'txpCommentPreview', false),
 195              'comment_submit'            => $comment_submit_button
 196          );
 197  
 198          foreach ($vals as $a => $b)
 199          {
 200              $Form = str_replace('<txp:'.$a.' />', $b, $Form);
 201          }
 202  
 203          $form = parse($Form);
 204  
 205          $out .= $form.
 206              n.hInput('parentid', $parentid);
 207  
 208          $split = rand(1, 31);
 209  
 210          $out .= ($preview) ? n.hInput(substr($nonce, 0, $split), substr($nonce, $split)) : '';
 211  
 212          $out .= (!$preview) ?
 213              n.hInput('backpage', htmlspecialchars($url)) :
 214              n.hInput('backpage', htmlspecialchars($backpage));
 215  
 216          $out = str_replace( '<!-- plugin-place-holder -->', callback_event('comment.form'), $out);
 217  
 218          $out .= n.n.'</div>'.n.'</form>';
 219  
 220          return $out;
 221      }
 222  
 223  // -------------------------------------------------------------
 224  	function popComments($id)
 225      {
 226          global $sitename,$s,$thisarticle;
 227          $preview = gps('preview');
 228          $h3 = ($preview) ? hed(gTxt('message_preview'),3) : '';
 229          $discuss = discuss($id);
 230          ob_start('parse');
 231          $out = fetch_form('popup_comments');
 232          $out = str_replace("<txp:popup_comments />",$discuss,$out);
 233  
 234          return $out;
 235  
 236      }
 237  
 238  // -------------------------------------------------------------
 239  	function setCookies($name,$email,$web)
 240      {
 241          $cookietime = time() + (365*24*3600);
 242          ob_start();
 243          setcookie("txp_name",  $name,  $cookietime, "/");
 244          setcookie("txp_email", $email, $cookietime, "/");
 245          setcookie("txp_web",   $web,     $cookietime, "/");
 246          setcookie("txp_last",  date("H:i d/m/Y"),$cookietime,"/");
 247          setcookie("txp_remember", '1', $cookietime, "/");
 248      }
 249  
 250  // -------------------------------------------------------------
 251  	function destroyCookies()
 252      {
 253          $cookietime = time()-3600;
 254          ob_start();
 255          setcookie("txp_name",  '', $cookietime, "/");
 256          setcookie("txp_email", '', $cookietime, "/");
 257          setcookie("txp_web",   '', $cookietime, "/");
 258          setcookie("txp_last",  '', $cookietime, "/");
 259          setcookie("txp_remember", '0', $cookietime + (365*25*3600), "/");
 260      }
 261  
 262  // -------------------------------------------------------------
 263  	function getComment()
 264      {
 265          // comment spam filter plugins: call this function to fetch comment contents
 266  
 267          $c = psa( array(
 268              'parentid',
 269              'name',
 270              'email',
 271              'web',
 272              'message',
 273              'backpage',
 274              'remember'
 275          ) );
 276  
 277          $n = array();
 278  
 279          foreach (stripPost() as $k => $v)
 280          {
 281              if (preg_match('#^[A-Fa-f0-9]{32}$#', $k.$v))
 282              {
 283                  $n[] = doSlash($k.$v);
 284              }
 285          }
 286  
 287          $c['nonce'] = '';
 288          $c['secret'] = '';
 289          if (!empty($n)) {
 290              $rs = safe_row('nonce, secret', 'txp_discuss_nonce', "nonce in ('".join("','", $n)."')");
 291              $c['nonce'] = $rs['nonce'];
 292              $c['secret'] = $rs['secret'];
 293          }
 294          $c['message'] = ps(md5('message'.$c['secret']));
 295          return $c;
 296      }
 297  
 298  // -------------------------------------------------------------
 299  	function saveComment()
 300      {
 301          global $siteurl,$comments_moderate,$comments_sendmail,$txpcfg,
 302              $comments_disallow_images,$prefs;
 303  
 304          $ref = serverset('HTTP_REFERRER');
 305          $in = getComment();
 306          $evaluator =& get_comment_evaluator();
 307  
 308          extract($in);
 309  
 310          if (!checkCommentsAllowed($parentid))
 311              txp_die ( gTxt('comments_closed'), '403');
 312  
 313          $ip = serverset('REMOTE_ADDR');
 314  
 315          if (!checkBan($ip))
 316              txp_die(gTxt('you_have_been_banned'), '403');
 317  
 318          $blacklisted = is_blacklisted($ip);
 319          if ($blacklisted)
 320              txp_die(gTxt('your_ip_is_blacklisted_by'.' '.$blacklisted), '403');
 321  
 322          $web = clean_url($web);
 323          $email = clean_url($email);
 324          if ($remember == 1 || ps('checkbox_type') == 'forget' && ps('forget') != 1)
 325              setCookies($name, $email, $web);
 326          else
 327              destroyCookies();
 328  
 329          $name = doSlash(strip_tags(deEntBrackets($name)));
 330          $web = doSlash(strip_tags(deEntBrackets($web)));
 331          $email = doSlash(strip_tags(deEntBrackets($email)));
 332  
 333          $message = substr(trim($message), 0, 65535);
 334          $message2db = doSlash(markup_comment($message));
 335  
 336          $isdup = safe_row("message,name", "txp_discuss",
 337              "name='$name' and message='$message2db' and ip='".doSlash($ip)."'");
 338  
 339          if (   ($prefs['comments_require_name'] && !trim($name))
 340              || ($prefs['comments_require_email'] && !trim($email))
 341              || (!trim($message)))
 342          {
 343              $evaluator -> add_estimate(RELOAD,1); // The error-messages are added in the preview-code
 344          }
 345  
 346          if ($isdup)
 347              $evaluator -> add_estimate(RELOAD,1); // FIXME? Tell the user about dupe?
 348  
 349          if ( ($evaluator->get_result() != RELOAD) && checkNonce($nonce) ) {
 350              callback_event('comment.save');
 351              $visible = $evaluator->get_result();
 352              if ($visible != RELOAD) {
 353                  $parentid = assert_int($parentid);
 354                  $rs = safe_insert(
 355                      "txp_discuss",
 356                      "parentid  = $parentid,
 357                       name          = '$name',
 358                       email      = '$email',
 359                       web          = '$web',
 360                       ip          = '".doSlash($ip)."',
 361                       message   = '$message2db',
 362                       visible   = ".intval($visible).",
 363                       posted      = now()"
 364                  );
 365                  if ($rs) {
 366                      safe_update("txp_discuss_nonce", "used = 1", "nonce='".doSlash($nonce)."'");
 367                      if ($prefs['comment_means_site_updated']) {
 368                          update_lastmod();
 369                      }
 370                      if ($comments_sendmail) {
 371                          mail_comment($message,$name,$email,$web,$parentid, $rs);
 372                      }
 373  
 374                      $updated = update_comments_count($parentid);
 375  
 376                      $backpage = substr($backpage, 0, $prefs['max_url_len']);
 377                      $backpage = preg_replace("/[\x0a\x0d#].*$/s",'',$backpage);
 378                      $backpage = preg_replace("#(https?://[^/]+)/.*$#","$1",hu).$backpage;
 379                      if (defined('PARTLY_MESSY') and (PARTLY_MESSY))
 380                      {
 381                          $backpage = permlinkurl_id($parentid);
 382                      }
 383                      $backpage .= ((strstr($backpage,'?')) ? '&' : '?') . 'commented='.(($visible==VISIBLE) ? '1' : '0');
 384  
 385                      txp_status_header('302 Found');
 386                      if($comments_moderate){
 387                          header('Location: '.$backpage.'#txpCommentInputForm');
 388                      }else{
 389                          header('Location: '.$backpage.'#c'.sprintf("%06s",$rs));
 390                      }
 391                      log_hit('302');
 392                      $evaluator->write_trace();
 393                      exit;
 394                  }
 395              }
 396          }
 397          // Force another Preview
 398          $_POST['preview'] = RELOAD;
 399          //$evaluator->write_trace();
 400      }
 401  
 402  // -------------------------------------------------------------
 403      class comment_evaluation {
 404          var $status;
 405          var $message;
 406          var $txpspamtrace = array();
 407          var $status_text = array();
 408  
 409  		function comment_evaluation() {
 410              global $prefs;
 411              extract(getComment());
 412              $this->status = array( SPAM  => array(),
 413                                     MODERATE => array(),
 414                                     VISIBLE  => array(),
 415                                     RELOAD  => array()
 416                                  );
 417              $this->status_text = array(    SPAM => gTxt('spam'),
 418                                      MODERATE => gTxt('unmoderated'),
 419                                      VISIBLE  => gTxt('visible'),
 420                                      RELOAD  => gTxt('reload')
 421                                  );
 422              $this->message = $this->status;
 423              $this -> txpspamtrace[] = "Comment on $parentid by $name (".safe_strftime($prefs['archive_dateformat'],time()).")";
 424              if ($prefs['comments_moderate'])
 425                  $this->status[MODERATE][]=0.5;
 426              else
 427                  $this->status[VISIBLE][]=0.5;
 428          }
 429  
 430  		function add_estimate($type = SPAM, $probability = 0.75, $msg='') {
 431              global $production_status;
 432  
 433              if (!array_key_exists($type, $this->status))
 434                  trigger_error(gTxt('unknown_spam_estimate'), E_USER_WARNING);
 435  
 436              $this -> txpspamtrace[] = "   $type; ".max(0,min(1,$probability))."; $msg";
 437              //FIXME trace is only viewable for RELOADS. Maybe add info to HTTP-Headers in debug-mode
 438  
 439              $this->status[$type][] = max(0,min(1,$probability));
 440              if (trim($msg)) $this->message[$type][] = $msg;
 441          }
 442  
 443  		function get_result($result_type='numeric') {
 444              $result = array();
 445              foreach ($this->status as $key => $value)
 446                  $result[$key] = array_sum($value)/max(1,count($value));
 447              arsort($result, SORT_NUMERIC);
 448              reset($result);
 449              return (($result_type == 'numeric') ? key($result) : $this->status_text[key($result)]);
 450          }
 451  		function get_result_message() {
 452              return $this->message[$this->get_result()];
 453          }
 454  		function write_trace() {
 455              global $prefs;
 456              $file = $prefs['tempdir'].DS.'evaluator_trace.php';
 457              if (!file_exists($file)) {
 458                  $fp = fopen($file,'wb');
 459                  if ($fp)
 460                      fwrite($fp,"<?php return; ?>\n".
 461                      "This trace-file tracks saved comments. (created ".safe_strftime($prefs['archive_dateformat'],time()).")\n".
 462                      "Format is: Type; Probability; Message (Type can be -1 => spam, 0 => moderate, 1 => visible)\n\n");
 463              } else {
 464                  $fp = fopen($file,'ab');
 465              }
 466              if ($fp) {
 467                  fwrite($fp, implode("\n", $this->txpspamtrace ));
 468                  fwrite($fp, "\n  RESULT: ".$this->get_result()."\n\n");
 469                  fclose($fp);
 470              }
 471          }
 472      }
 473  
 474      function &get_comment_evaluator() {
 475          static $instance;
 476  
 477          // If the instance is not there, create one
 478          if(!isset($instance)) {
 479              $instance = new comment_evaluation();
 480          }
 481          return $instance;
 482      }
 483  
 484  // -------------------------------------------------------------
 485  	function checkNonce($nonce)
 486      {
 487          if (!$nonce && !preg_match('#^[a-zA-Z0-9]*$#',$nonce))
 488              return false;
 489              // delete expired nonces
 490          safe_delete("txp_discuss_nonce", "issue_time < date_sub(now(),interval 10 minute)");
 491              // check for nonce
 492          return (safe_row("*", "txp_discuss_nonce", "nonce='".doSlash($nonce)."' and used = 0")) ? true : false;
 493      }
 494  
 495  // -------------------------------------------------------------
 496  	function checkBan($ip)
 497      {
 498          return (!fetch("ip", "txp_discuss_ipban", "ip", $ip)) ? true : false;
 499      }
 500  
 501  // -------------------------------------------------------------
 502  	function checkCommentsAllowed($id)
 503      {
 504          global $use_comments, $comments_disabled_after, $thisarticle;
 505  
 506          $id = intval($id);
 507  
 508          if (!$use_comments || !$id)
 509              return false;
 510  
 511          if (isset($thisarticle['thisid']) && ($thisarticle['thisid'] == $id) && isset($thisarticle['annotate']))
 512          {
 513              $Annotate = $thisarticle['annotate'];
 514              $uPosted  = $thisarticle['posted'];
 515          }
 516          else
 517          {
 518              extract(
 519                  safe_row(
 520                      "Annotate,unix_timestamp(Posted) as uPosted",
 521                          "textpattern", "ID = $id"
 522                  )
 523              );
 524          }
 525  
 526          if ($Annotate != 1)
 527              return false;
 528  
 529          if($comments_disabled_after) {
 530              $lifespan = ( $comments_disabled_after * 86400 );
 531              $timesince = ( time() - $uPosted );
 532              return ( $lifespan > $timesince );
 533          }
 534  
 535          return true;
 536      }
 537  
 538  // -------------------------------------------------------------
 539  		function comments_help()
 540      {
 541          return ('<a id="txpCommentHelpLink" href="http://rpc.textpattern.com/help/index.php?item=textile_comments&amp;language='.LANG.'" onclick="window.open(this.href, \'popupwindow\', \'width=300,height=400,scrollbars,resizable\'); return false;">'.gTxt('textile_help').'</a>');
 542      }
 543  
 544  // -------------------------------------------------------------
 545  	function mail_comment($message, $cname, $cemail, $cweb, $parentid, $discussid)
 546      {
 547          global $sitename;
 548          $parentid = assert_int($parentid);
 549          $discussid = assert_int($discussid);
 550          $article = safe_row("Section, Posted, ID, url_title, AuthorID, Title", "textpattern", "ID = $parentid");
 551          extract($article);
 552          extract(safe_row("RealName, email", "txp_users", "name = '".doSlash($AuthorID)."'"));
 553  
 554          $evaluator =& get_comment_evaluator();
 555  
 556          $out = gTxt('greeting')." $RealName,".n.n;
 557          $out .= str_replace('{title}',$Title,gTxt('comment_recorded')).n;
 558          $out .= permlinkurl_id($parentid).n;
 559          if (has_privs('discuss', $AuthorID))
 560              $out .= hu.'textpattern/index.php?event=discuss&step=discuss_edit&discussid='.$discussid.n;
 561          $out .= gTxt('status').": ".$evaluator->get_result('text').'. '.implode(',',$evaluator->get_result_message()).n;
 562          $out .= n;
 563          $out .= gTxt('comment_name').": $cname".n;
 564          $out .= gTxt('comment_email').": $cemail".n;
 565          $out .= gTxt('comment_web').": $cweb".n;
 566          $out .= gTxt('comment_comment').": $message";
 567  
 568          $subject = strtr(gTxt('comment_received'),array('{site}' => $sitename, '{title}' => $Title));
 569  
 570          $success = txpMail($email, $subject, $out, $cemail);
 571      }
 572  // -------------------------------------------------------------
 573      # deprecated, use fInput instead
 574  	function input($type,$name,$val,$size='',$class='',$tab='',$chkd='')
 575      {
 576          $o = array(
 577              '<input type="'.$type.'" name="'.$name.'" id="'.$name.'" value="'.$val.'"',
 578              ($size)    ? ' size="'.$size.'"'      : '',
 579              ($class) ? ' class="'.$class.'"'    : '',
 580              ($tab)     ? ' tabindex="'.$tab.'"'    : '',
 581              ($chkd)    ? ' checked="checked"'    : '',
 582              ' />'.n
 583          );
 584          return join('',$o);
 585      }
 586  ?>


Generated: Thu May 21 23:03:01 2009 Cross-referenced by PHPXref 0.7