[ Index ] |
PHP Cross Reference of Textpattern 4.0.8 |
[Summary view] [Print] [Text view]
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&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 ?>
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Thu May 21 23:03:01 2009 | Cross-referenced by PHPXref 0.7 |