source: trunk/include/picture_comment.inc.php @ 1737

Last change on this file since 1737 was 1737, checked in by rvelices, 17 years ago

feature 625: comment anti-spam - protect against some of the spam robots

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 10.5 KB
Line 
1<?php
2// +-----------------------------------------------------------------------+
3// | PhpWebGallery - a PHP based picture gallery                           |
4// | Copyright (C) 2002-2003 Pierrick LE GALL - pierrick@phpwebgallery.net |
5// | Copyright (C) 2003-2007 PhpWebGallery Team - http://phpwebgallery.net |
6// +-----------------------------------------------------------------------+
7// | branch        : BSF (Best So Far)
8// | file          : $Id: picture_comment.inc.php 1737 2007-01-19 02:56:54Z rvelices $
9// | last update   : $Date: 2007-01-19 02:56:54 +0000 (Fri, 19 Jan 2007) $
10// | last modifier : $Author: rvelices $
11// | revision      : $Revision: 1737 $
12// +-----------------------------------------------------------------------+
13// | This program is free software; you can redistribute it and/or modify  |
14// | it under the terms of the GNU General Public License as published by  |
15// | the Free Software Foundation                                          |
16// |                                                                       |
17// | This program is distributed in the hope that it will be useful, but   |
18// | WITHOUT ANY WARRANTY; without even the implied warranty of            |
19// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU      |
20// | General Public License for more details.                              |
21// |                                                                       |
22// | You should have received a copy of the GNU General Public License     |
23// | along with this program; if not, write to the Free Software           |
24// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, |
25// | USA.                                                                  |
26// +-----------------------------------------------------------------------+
27
28/**
29 * This file is included by the picture page to manage user comments
30 *
31 */
32
33if (!function_exists('hash_hmac'))
34{
35function hash_hmac($algo, $data, $key, $raw_output=false)
36{
37  /* md5 and sha1 only */
38  $algo=strtolower($algo);
39  $p=array('md5'=>'H32','sha1'=>'H40');
40  if ( !isset($p[$algo]) or !function_exists($algo) )
41  {
42    $algo = 'md5';
43  }
44  if(strlen($key)>64) $key=pack($p[$algo],$algo($key));
45  if(strlen($key)<64) $key=str_pad($key,64,chr(0));
46
47  $ipad=substr($key,0,64) ^ str_repeat(chr(0x36),64);
48  $opad=substr($key,0,64) ^ str_repeat(chr(0x5C),64);
49
50  $ret = $algo($opad.pack($p[$algo],$algo($ipad.$data)));
51  if ($raw_output)
52  {
53    $ret = pack('H*', $ret);
54  }
55  return $ret;
56}
57}
58
59//returns string action to perform on a new comment: validate, moderate, reject
60function user_comment_check($action, $comment, $picture)
61{
62  global $conf,$user;
63
64  if ($action=='reject')
65    return $action;
66
67  $my_action = $conf['comment_spam_reject'] ? 'reject':'moderate';
68  if ($action==$my_action)
69    return $action;
70
71  // we do here only BASIC spam check (plugins can do more)
72  if ( !$user['is_the_guest'] )
73    return $action;
74
75  $link_count = preg_match_all( '/https?:\/\//',
76    $comment['content'], $matches);
77
78  if ( $link_count>$conf['comment_spam_max_links'] )
79    return $my_action;
80
81  if ( isset($comment['ip']) and $conf['comment_spam_check_ip'] )
82  {
83    $rev_ip = implode( '.', array_reverse( explode('.',$comment['ip']) ) );
84    $lookup = $rev_ip . '.sbl-xbl.spamhaus.org.';
85    $res = gethostbyname( $lookup );
86    if ( $lookup != $res )
87      return $my_action;
88  }
89
90  return $action;
91}
92
93
94
95add_event_handler('user_comment_check', 'user_comment_check',
96  EVENT_HANDLER_PRIORITY_NEUTRAL, 3);
97
98
99// the picture is commentable if it belongs at least to one category which
100// is commentable
101$page['show_comments'] = false;
102foreach ($related_categories as $category)
103{
104  if ($category['commentable'] == 'true')
105  {
106    $page['show_comments'] = true;
107    break;
108  }
109}
110
111if ( $page['show_comments'] and isset( $_POST['content'] ) )
112{
113  if ( $user['is_the_guest'] and !$conf['comments_forall'] )
114  {
115    die ('Session expired');
116  }
117  if (!$conf['comments_validation'] or is_admin())
118  {
119    $comment_action='validate'; //one of validate, moderate, reject
120  }
121  else
122  {
123    $comment_action='moderate'; //one of validate, moderate, reject
124  }
125
126  $_POST['content'] = trim( stripslashes($_POST['content']) );
127
128  if ( $user['is_the_guest'] )
129  {
130    $author = empty($_POST['author'])?'guest':$_POST['author'];
131    // if a guest try to use the name of an already existing user, he must be
132    // rejected
133    if ( $author != 'guest' )
134    {
135      $query = 'SELECT COUNT(*) AS user_exists';
136      $query.= ' FROM '.USERS_TABLE;
137      $query.= ' WHERE '.$conf['user_fields']['username']." = '".$author."'";
138      $query.= ';';
139      $row = mysql_fetch_assoc( pwg_query( $query ) );
140      if ( $row['user_exists'] == 1 )
141      {
142        $template->assign_block_vars(
143          'information',
144          array('INFORMATION'=>$lang['comment_user_exists']));
145        $comment_action='reject';
146      }
147    }
148  }
149  else
150  {
151    $author = $user['username'];
152  }
153
154  $comm = array(
155    'author' => $author,
156    'content' => $_POST['content'],
157    'image_id' => $page['image_id'],
158    'ip' => $_SERVER['REMOTE_ADDR'],
159    'agent' => $_SERVER['HTTP_USER_AGENT']
160   );
161
162  if ($comment_action!='reject' and empty($comm['content']) )
163  { // empty comment content
164    $comment_action='reject';
165  }
166
167  $key = explode(':', @$_POST['key']);
168  if ( count($key)!=2
169        or $key[0]>time() or $key[0]<time()-1800 // 30 minutes expiration
170        or hash_hmac('md5', $key[0], $conf['secret_key'])!=$key[1]
171      )
172  {
173    $comment_action='reject';
174  }
175 
176  if ($comment_action!='reject' and $conf['anti-flood_time']>0 )
177  { // anti-flood system
178    $reference_date = time() - $conf['anti-flood_time'];
179    $query = 'SELECT id FROM '.COMMENTS_TABLE;
180    $query.= ' WHERE date > FROM_UNIXTIME('.$reference_date.')';
181    $query.= " AND author = '".$comm['author']."'";
182    $query.= ';';
183    if ( mysql_num_rows( pwg_query( $query ) ) > 0 )
184    {
185      $template->assign_block_vars(
186        'information',
187        array('INFORMATION'=>$lang['comment_anti-flood']));
188      $comment_action='reject';
189    }
190  }
191
192  // perform more spam check
193  $comment_action = trigger_event('user_comment_check',
194      $comment_action, $comm, $picture['current']
195    );
196
197  if ( $comment_action!='reject' )
198  {
199    list($dbnow) = mysql_fetch_row(pwg_query('SELECT NOW();'));
200
201    $data = $comm;
202    $data['date'] = $dbnow;
203    $data['content'] = addslashes(
204        // this htmlpsecialchars is not good here
205        htmlspecialchars($comm['content'],ENT_QUOTES)
206      );
207
208    if ($comment_action=='validate')
209    {
210      $data['validated'] = 'true';
211      $data['validation_date'] = $dbnow;
212    }
213    else
214    {
215      $data['validated'] = 'false';
216    }
217
218    include_once(PHPWG_ROOT_PATH.'admin/include/functions.php');
219    $fields = array('author', 'date', 'image_id', 'content', 'validated',
220                    'validation_date');
221    mass_inserts(COMMENTS_TABLE, $fields, array($data));
222    $comm['id'] = mysql_insert_id();
223
224    // information message
225    $message = $lang['comment_added'];
226    if ($comment_action!='validate')
227    {
228      $message.= '<br />'.$lang['comment_to_validate'];
229    }
230    $template->assign_block_vars('information',
231                                 array('INFORMATION'=>$message));
232    if ( ($comment_action=='validate' and $conf['email_admin_on_comment'])
233      or $conf['email_admin_on_comment_validation'] )
234    {
235      include_once(PHPWG_ROOT_PATH.'include/functions_mail.inc.php');
236
237      $del_url = get_host_url().cookie_path()
238        .'comments.php?delete='.$comm['id'];
239
240      $content =
241        'Author: '.$comm['author']."\n"
242        .'Comment: '.$comm['content']."\n"
243        .'IP: '.$comm['ip']."\n"
244        .'Browser: '.$comm['agent']."\n\n"
245        .'Delete: '.$del_url."\n";
246      if ($comment_action!='validate')
247      {
248        $content .=
249          'Validate: '.get_host_url().cookie_path()
250          .'comments.php?validate='.$comm['id'];
251      }
252      pwg_mail( get_webmaster_mail_address(), '',
253          'PWG comment by '.$comm['author'],
254          $content
255          );
256    }
257  }
258  else
259  {
260    $template->assign_block_vars('information',
261          array('INFORMATION'=>l10n('comment_not_added') )
262        );
263  }
264
265  // allow plugins to notify what's going on
266  trigger_action( 'user_comment_insertion',
267      array_merge($comm, array('action'=>$comment_action) )
268    );
269}
270
271
272if ($page['show_comments'])
273{
274  // number of comment for this picture
275  $query = 'SELECT COUNT(*) AS nb_comments';
276  $query.= ' FROM '.COMMENTS_TABLE.' WHERE image_id = '.$page['image_id'];
277  $query.= " AND validated = 'true'";
278  $query.= ';';
279  $row = mysql_fetch_array( pwg_query( $query ) );
280
281  // navigation bar creation
282  if (!isset($page['start']))
283  {
284    $page['start'] = 0;
285  }
286
287  $page['navigation_bar'] = create_navigation_bar(
288    duplicate_picture_url(array(), array('start')),
289    $row['nb_comments'],
290    $page['start'],
291    $conf['nb_comment_page'],
292    true // We want a clean URL
293    );
294
295  $template->assign_block_vars(
296    'comments',
297    array(
298      'NB_COMMENT' => $row['nb_comments'],
299      'NAV_BAR' => $page['navigation_bar'],
300      )
301    );
302
303  if ($row['nb_comments'] > 0)
304  {
305    $query = '
306SELECT id,author,date,image_id,content
307  FROM '.COMMENTS_TABLE.'
308  WHERE image_id = '.$page['image_id'].'
309    AND validated = \'true\'
310  ORDER BY date ASC
311  LIMIT '.$page['start'].', '.$conf['nb_comment_page'].'
312;';
313    $result = pwg_query( $query );
314
315    while ($row = mysql_fetch_array($result))
316    {
317      $template->assign_block_vars(
318        'comments.comment',
319        array(
320          'COMMENT_AUTHOR' => empty($row['author'])
321            ? $lang['guest']
322            : $row['author'],
323
324          'COMMENT_DATE' => format_date(
325            $row['date'],
326            'mysql_datetime',
327            true),
328
329          'COMMENT' => trigger_event('render_comment_content',$row['content']),
330          )
331        );
332
333      if (is_admin())
334      {
335        $template->assign_block_vars(
336          'comments.comment.delete',
337          array(
338            'U_COMMENT_DELETE' =>
339              add_url_params(
340                    $url_self,
341                    array(
342                      'action'=>'delete_comment',
343                      'comment_to_delete'=>$row['id']
344                    )
345                )
346            )
347          );
348      }
349    }
350  }
351
352  if (!$user['is_the_guest']
353      or ($user['is_the_guest'] and $conf['comments_forall']))
354  {
355    $key = time();
356    $key .= ':'.hash_hmac('md5', $key, $conf['secret_key']);
357    $template->assign_block_vars('comments.add_comment',
358        array(
359          'key' => $key
360        ));
361    // display author field if the user is not logged in
362    if ($user['is_the_guest'])
363    {
364      $template->assign_block_vars(
365        'comments.add_comment.author_field', array()
366        );
367    }
368  }
369}
370
371?>
Note: See TracBrowser for help on using the repository browser.