Source for file comment_post.php
Documentation is available at comment_post.php
* This file posts a comment!
* This file is part of Quam Plures - {@link http://quamplures.net/}
* See also {@link https://launchpad.net/quam-plures}.
* @copyright (c) 2009 - 2011 by the Quam Plures developers - {@link http://quamplures.net/}
* @copyright (c)2003-2009 by Francois PLANQUE - {@link http://fplanque.net/}
* {@internal License choice
* - If you have received this file as part of a package, please find the license.txt file in
* the same folder or the closest folder above for complete license terms.
* - If you have received this file individually (e-g: from http://evocms.cvs.sourceforge.net/)
* then you must choose one of the following licenses before using the file:
* - GNU General Public License 2 (GPL) - http://www.opensource.org/licenses/gpl-license.php
* - Mozilla Public License 1.1 (MPL) - http://www.opensource.org/licenses/mozilla1.1.php
* {@internal Open Source relicensing agreement:
require_once dirname(__FILE__ ). '/../qp_config/_config.php';
require_once $inc_path. '_main.inc.php';
header( 'Content-Type: text/html; charset='. $io_charset );
// Getting GET or POST parameters:
param( 'comment_post_ID', 'integer', true ); // required
param( 'redirect_to', 'string', '' );
$commented_Item = & $ItemCache->get_by_ID( $comment_post_ID );
if( ! $commented_Item->can_comment( NULL ) )
$Messages->add( T_('You cannot leave comments on this post!'), 'error' );
// Note: we use funky field names to defeat the most basic guestbook spam bots and/or their most basic authors
$comment = param( 'p', 'html' );
param( 'comment_autobr', 'integer', ($comments_use_autobr == 'always') ? 1 : 0 );
$comment_allow_msgform = null;
{ // User is not logged in (registered users), we need some id info from him:
// Note: we use funky field names to defeat the most basic guestbook spam bots and/or their most basic authors
$author = param( 'u', 'string' );
$email = param( 'i', 'string' );
$url = param( 'o', 'string' );
param( 'comment_cookies', 'integer', 0 );
param( 'comment_allow_msgform', 'integer', 0 ); // checkbox
param( 'comment_rating', 'integer', NULL );
$now = date( 'Y-m-d H:i:s', $localtimenow );
$original_comment = $comment;
// Trigger event: a Plugin could add a $category="error" message here..
// This must get triggered before any internal validation and must pass all relevant params.
// openID plugin will validate a given OpenID here
$Plugins->trigger_event( 'CommentFormSent', array(
'comment_post_ID' => $comment_post_ID,
'original_comment' => & $original_comment,
'comment_autobr' => & $comment_autobr,
'anon_name' => & $author,
'anon_email' => & $email,
'rating' => & $comment_rating,
'anon_allow_msgform' => & $comment_allow_msgform,
'anon_cookies' => & $comment_cookies,
'redirect_to' => & $redirect_to,
$commented_Item->get_Blog(); // Make sure Blog is loaded (will be needed wether logged in or not)
// Does user have permission to edit?
$perm_comment_edit = $User->check_perm( 'blog_comments', 'edit', false, $commented_Item->Blog->ID );
{ // User is still not logged in
// NO permission to edit!
$perm_comment_edit = false;
// we need some id info from the anonymous user:
{ // We want Name and EMail with comments
$Messages->add( T_('Please fill in your name.'), 'error' );
$Messages->add( T_('Please fill in your email.'), 'error' );
$Messages->add( T_('Supplied name is invalid.'), 'error' );
$Messages->add( T_('Supplied email address is invalid.'), 'error' );
{ // add 'http://' if no protocol defined for URL; but not if the user seems to be entering an email address alone
{ // ex: https:// is 8 chars
// Note: as part of the validation we require the url to be absolute; otherwise we cannot detect bozos typing in
// a title for their comment or whatever...
$Messages->add( T_('Supplied website address is invalid: '). $error, 'error' );
// CHECK and FORMAT content
// TODO: AutoBR should really be a "comment renderer" (like with Items)
// OLD stub: $comment = format_to_post( $comment, $comment_autobr, 1 ); // includes antispam
$saved_comment = $comment;
$comment = check_html_sanity( $comment, $perm_comment_edit ? 'posting' : 'commenting',
$comment_autobr, NULL, true /* escape comments */ );
$comment = $saved_comment;
{ // comment should not be empty!
$Messages->add( T_('Please do not send empty comments.'), 'error' );
// Flood protection was here and SHOULD NOT have moved down!
* Create comment object. Gets validated, before recording it into DB:
$Comment->set( 'type', 'comment' );
$Comment->set_Item( $commented_Item );
{ // User is logged in, we'll use his ID
$Comment->set_author_User( $User );
{ // User is not logged in:
$Comment->set( 'author', $author );
$Comment->set( 'author_email', $email );
$Comment->set( 'author_url', $url );
$Comment->set( 'allow_msgform', $comment_allow_msgform );
if( $commented_Item->can_rate() )
$Comment->set( 'rating', $comment_rating );
$Comment->set( 'author_IP', $Hit->IP );
$Comment->set( 'date', $now );
$Comment->set( 'content', $comment );
{ // User has perm to moderate comments, publish automatically:
$Comment->set( 'status', 'published' );
{ // Assign default status for new comments:
$Comment->set( 'status', $commented_Item->Blog->get_setting('new_feedback_status') );
if( $action != 'preview' )
* NOTE: devs can override the flood protection delay in /qp_config/_overrides_TEST.php
* TODO: Put time check into query?
* TODO: move that as far !!UP!! as possible! We want to waste minimum resources on Floods
* TODO: have several thresholds. For example:
* 1 comment max every 30 sec + 5 comments max every 10 minutes + 15 comments max every 24 hours
* TODO: factorize with trackback
$query = 'SELECT MAX(comment_date)
WHERE comment_author_IP = '. $DB->quote($Hit->IP). '
OR comment_author_email = '. $DB->quote($Comment->get_author_email());
if( $then = $DB->get_var( $query ) )
if( ($time_newcomment - $time_lastcomment) < $minimum_comment_interval )
$Messages->add( sprintf( T_('You can only post a new comment every %d seconds.'), $minimum_comment_interval ), 'error' );
/* end flood-protection */
// Trigger event: a Plugin could add a $category="error" message here..
$Plugins->trigger_event( 'BeforeCommentFormInsert', array(
'original_comment' => $original_comment,
'is_preview' => ($action == 'preview'),
'action' => & $action ) );
* Display error messages:
if( $Messages->count('error') )
if( ! isset ($page_title) )
$page_title = T_('Errors while processing your comment');
// TODO: dh> HEAD part should be some global front end include file..
// fp> actually, I'd like the error messages to de displayed in a templatenable file. Something that looks like the _main template file but with minimum extra gadgets (in order to save on DB requests at each "spam denied" error)
// fp> So please don't waste time on implementing a half baked solution.
// fp> We may want to rethink templates more deeply beofre implementing this.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<title> <?php echo $app_shortname. ' › '. $page_title ?></title>
<meta name="ROBOTS" content="NOINDEX" />
<meta http-equiv="Content-Type" content="text/html; charset= <?php echo $io_charset ?>" />
$Messages->display( T_('Cannot post comment, please correct these errors:'),
'[<a href="javascript:history.go(-1)">'. T_('Back to comment editing'). '</a>]' );
if( $action == 'preview' )
{ // set the Comment into user's session and redirect.
$Comment->set( 'original_content', $original_comment ); // used in the textarea input field again
$Session->set( 'core.preview_Comment', $Comment );
$Session->set( 'core.no_CachePageContent', 1 );
// This message serves the purpose that the next page will not even try to retrieve preview from cache... (and won't collect data to be cached)
// This is session based, so it's not 100% safe to prevent caching. We are also using explicit caching prevention whenever personal data is displayed
$Messages->add( T_('This is a preview only! Do not forget to send your comment!'), 'error' );
// Passthrough comment_cookies & comment_allow_msgform params:
// fp> moved this down here in order to keep return URLs clean whenever this is not needed.
$redirect_to = url_add_param($redirect_to, 'redir=no&comment_cookies='. $comment_cookies
. '&comment_allow_msgform='. $comment_allow_msgform, '&');
$redirect_to .= '#comment_preview';
{ // delete any preview comment from session data:
$Session->delete( 'core.preview_Comment' );
$email = ' '; // this to make sure a cookie is set for 'no email'
$url = ' '; // this to make sure a cookie is set for 'no url'
// fplanque: made cookies available for whole site
setcookie( $cookie_name, $author, $cookie_expires, $cookie_path, $cookie_domain);
setcookie( $cookie_email, $email, $cookie_expires, $cookie_path, $cookie_domain);
setcookie( $cookie_url, $url, $cookie_expires, $cookie_path, $cookie_domain);
if( !empty($_COOKIE[$cookie_name]) )
setcookie( $cookie_name, '', $cookie_expired, $cookie_path, $cookie_domain);
if( !empty($_COOKIE[$cookie_email]) )
setcookie( $cookie_email, '', $cookie_expired, $cookie_path, $cookie_domain);
if( !empty($_COOKIE[$cookie_url]) )
setcookie( $cookie_url, '', $cookie_expired, $cookie_path, $cookie_domain);
// Note: we don't give any clue that we have automatically deleted a comment. It would only give spammers the perfect tool to find out how to pass the filter.
{ // comment has not been deleted
// Trigger event: a Plugin should cleanup any temporary data here..
$Plugins->trigger_event( 'AfterCommentFormInsert', array( 'Comment' => & $Comment, 'original_comment' => $original_comment ) );
* --------------------------
* New comment notifications:
* --------------------------
// TODO: dh> this should only send published feedback probably and should also use "outbound_notifications_mode"
// fp> yes for general users, but comment moderators need to receive notifications for new unpublished comments
$Comment->send_email_notifications();
// Add a message, according to the comment's status:
if( $Comment->status == 'published' )
$Messages->add( T_('Your comment has been submitted.'), 'success' );
// Append anchor to the redirect_to param, so the user sees his comment:
$redirect_to .= '#'. $Comment->get_anchor();
$Messages->add( T_('Your comment has been submitted. It will appear once it has been approved.'), 'success' );
{ // Not logged in user. We want him to see his comment has not vanished if he checks back on the Item page
// before the cache has expired. Invalidate cache for that page:
// Note: this is approximative and may not cover all URLs where the user expects to see the comment...
// TODO: fp> solution: touch dates?
$PageCache->invalidate( $Comment->Item->get_single_url() );
|