source: trunk/include/functions_comment.inc.php @ 29408

Last change on this file since 29408 was 29060, checked in by rvelices, 10 years ago

bug 3100 display IP address of comment author on admin page and also save the entire ip address in the database, not only the first three ip components

  • Property svn:eol-style set to LF
File size: 14.6 KB
Line 
1<?php
2// +-----------------------------------------------------------------------+
3// | Piwigo - a PHP based photo gallery                                    |
4// +-----------------------------------------------------------------------+
5// | Copyright(C) 2008-2014 Piwigo Team                  http://piwigo.org |
6// | Copyright(C) 2003-2008 PhpWebGallery Team    http://phpwebgallery.net |
7// | Copyright(C) 2002-2003 Pierrick LE GALL   http://le-gall.net/pierrick |
8// +-----------------------------------------------------------------------+
9// | This program is free software; you can redistribute it and/or modify  |
10// | it under the terms of the GNU General Public License as published by  |
11// | the Free Software Foundation                                          |
12// |                                                                       |
13// | This program is distributed in the hope that it will be useful, but   |
14// | WITHOUT ANY WARRANTY; without even the implied warranty of            |
15// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU      |
16// | General Public License for more details.                              |
17// |                                                                       |
18// | You should have received a copy of the GNU General Public License     |
19// | along with this program; if not, write to the Free Software           |
20// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, |
21// | USA.                                                                  |
22// +-----------------------------------------------------------------------+
23
24/**
25 * @package functions\comment
26 */
27
28
29add_event_handler('user_comment_check', 'user_comment_check');
30
31/**
32 * Does basic check on comment and returns action to perform.
33 * This method is called by a trigger_change()
34 *
35 * @param string $action before check
36 * @param array $comment
37 * @return string validate, moderate, reject
38 */
39function user_comment_check($action, $comment)
40{
41  global $conf,$user;
42
43  if ($action=='reject')
44    return $action;
45
46  $my_action = $conf['comment_spam_reject'] ? 'reject':'moderate';
47
48  if ($action==$my_action)
49    return $action;
50
51  // we do here only BASIC spam check (plugins can do more)
52  if ( !is_a_guest() )
53    return $action;
54
55  $link_count = preg_match_all( '/https?:\/\//',
56    $comment['content'], $matches);
57
58  if ( strpos($comment['author'], 'http://')!==false )
59  {
60    $link_count++;
61  }
62
63  if ( $link_count>$conf['comment_spam_max_links'] )
64  {
65    $_POST['cr'][] = 'links';
66    return $my_action;
67  }
68  return $action;
69}
70
71/**
72 * Tries to insert a user comment and returns action to perform.
73 *
74 * @param array &$comm
75 * @param string $key secret key sent back to the browser
76 * @param array &$infos output array of error messages
77 * @return string validate, moderate, reject
78 */
79function insert_user_comment(&$comm, $key, &$infos)
80{
81  global $conf, $user;
82
83  $comm = array_merge( $comm,
84    array(
85      'ip' => $_SERVER['REMOTE_ADDR'],
86      'agent' => $_SERVER['HTTP_USER_AGENT']
87    )
88   );
89
90  $infos = array();
91  if (!$conf['comments_validation'] or is_admin())
92  {
93    $comment_action='validate'; //one of validate, moderate, reject
94  }
95  else
96  {
97    $comment_action='moderate'; //one of validate, moderate, reject
98  }
99
100  // display author field if the user status is guest or generic
101  if (!is_classic_user())
102  {
103    if ( empty($comm['author']) )
104    {
105      if ($conf['comments_author_mandatory'])
106      {
107        $infos[] = l10n('Username is mandatory');
108        $comment_action='reject';
109      }
110      $comm['author'] = 'guest';
111    }
112    $comm['author_id'] = $conf['guest_id'];
113    // if a guest try to use the name of an already existing user, he must be
114    // rejected
115    if ( $comm['author'] != 'guest' )
116    {
117      $query = '
118SELECT COUNT(*) AS user_exists
119  FROM '.USERS_TABLE.'
120  WHERE '.$conf['user_fields']['username']." = '".addslashes($comm['author'])."'";
121      $row = pwg_db_fetch_assoc( pwg_query( $query ) );
122      if ( $row['user_exists'] == 1 )
123      {
124        $infos[] = l10n('This login is already used by another user');
125        $comment_action='reject';
126      }
127    }
128  }
129  else
130  {
131    $comm['author'] = addslashes($user['username']);
132    $comm['author_id'] = $user['id'];
133  }
134
135  if ( empty($comm['content']) )
136  { // empty comment content
137    $comment_action='reject';
138  }
139
140  if ( !verify_ephemeral_key(@$key, $comm['image_id']) )
141  {
142    $comment_action='reject';
143    $_POST['cr'][] = 'key'; // rvelices: I use this outside to see how spam robots work
144  }
145
146  // website
147  if (!empty($comm['website_url']))
148  {
149    if (!$conf['comments_enable_website'])
150    { // honeypot: if the field is disabled, it should be empty !
151      $comment_action='reject';
152      $_POST['cr'][] = 'website_url';
153    }
154    else
155    {
156      $comm['website_url'] = strip_tags($comm['website_url']);
157      if (!preg_match('/^https?/i', $comm['website_url']))
158      {
159        $comm['website_url'] = 'http://'.$comm['website_url'];
160      }
161      if (!url_check_format($comm['website_url']))
162      {
163        $infos[] = l10n('Your website URL is invalid');
164        $comment_action='reject';
165      }
166    }
167  }
168
169  // email
170  if (empty($comm['email']))
171  {
172    if (!empty($user['email']))
173    {
174      $comm['email'] = $user['email'];
175    }
176    elseif ($conf['comments_email_mandatory'])
177    {
178      $infos[] = l10n('Email address is missing. Please specify an email address.');
179      $comment_action='reject';
180    }
181  }
182  elseif (!email_check_format($comm['email']))
183  {
184    $infos[] = l10n('mail address must be like xxx@yyy.eee (example : jack@altern.org)');
185    $comment_action='reject';
186  }
187
188  // anonymous id = ip address
189  $ip_components = explode('.', $comm['ip']);
190  if (count($ip_components) > 3)
191  {
192    array_pop($ip_components);
193  }
194  $anonymous_id = implode('.', $ip_components);
195
196  if ($comment_action!='reject' and $conf['anti-flood_time']>0 and !is_admin())
197  { // anti-flood system
198    $reference_date = pwg_db_get_flood_period_expression($conf['anti-flood_time']);
199
200    $query = '
201SELECT count(1) FROM '.COMMENTS_TABLE.'
202  WHERE date > '.$reference_date.'
203    AND author_id = '.$comm['author_id'];
204    if (!is_classic_user())
205    {
206      $query.= '
207      AND anonymous_id LIKE "'.$anonymous_id.'.%"';
208    }
209    $query.= '
210;';
211
212    list($counter) = pwg_db_fetch_row(pwg_query($query));
213    if ( $counter > 0 )
214    {
215      $infos[] = l10n('Anti-flood system : please wait for a moment before trying to post another comment');
216      $comment_action='reject';
217      $_POST['cr'][] = 'flood_time';
218    }
219  }
220
221  // perform more spam check
222  $comment_action = trigger_change('user_comment_check',
223      $comment_action, $comm
224    );
225
226  if ( $comment_action!='reject' )
227  {
228    $query = '
229INSERT INTO '.COMMENTS_TABLE.'
230  (author, author_id, anonymous_id, content, date, validated, validation_date, image_id, website_url, email)
231  VALUES (
232    \''.$comm['author'].'\',
233    '.$comm['author_id'].',
234    \''.$comm['ip'].'\',
235    \''.$comm['content'].'\',
236    NOW(),
237    \''.($comment_action=='validate' ? 'true':'false').'\',
238    '.($comment_action=='validate' ? 'NOW()':'NULL').',
239    '.$comm['image_id'].',
240    '.(!empty($comm['website_url']) ? '\''.$comm['website_url'].'\'' : 'NULL').',
241    '.(!empty($comm['email']) ? '\''.$comm['email'].'\'' : 'NULL').'
242  )
243';
244    pwg_query($query);
245    $comm['id'] = pwg_db_insert_id(COMMENTS_TABLE);
246
247    invalidate_user_cache_nb_comments();
248
249    if ( ($conf['email_admin_on_comment'] && 'validate' == $comment_action)
250        or ($conf['email_admin_on_comment_validation'] and 'moderate' == $comment_action))
251    {
252      include_once(PHPWG_ROOT_PATH.'include/functions_mail.inc.php');
253
254      $comment_url = get_absolute_root_url().'comments.php?comment_id='.$comm['id'];
255
256      $keyargs_content = array(
257        get_l10n_args('Author: %s', stripslashes($comm['author']) ),
258        get_l10n_args('Email: %s', stripslashes($comm['email']) ),
259        get_l10n_args('Comment: %s', stripslashes($comm['content']) ),
260        get_l10n_args(''),
261        get_l10n_args('Manage this user comment: %s', $comment_url),
262      );
263
264      if ('moderate' == $comment_action)
265      {
266        $keyargs_content[] = get_l10n_args('(!) This comment requires validation');
267      }
268
269      pwg_mail_notification_admins(
270        get_l10n_args('Comment by %s', stripslashes($comm['author']) ),
271        $keyargs_content
272      );
273    }
274  }
275
276  return $comment_action;
277}
278
279/**
280 * Tries to delete a (or more) user comment.
281 *    only admin can delete all comments
282 *    other users can delete their own comments
283 *
284 * @param int|int[] $comment_id
285 * @return bool false if nothing deleted
286 */
287function delete_user_comment($comment_id)
288{
289  $user_where_clause = '';
290  if (!is_admin())
291  {
292    $user_where_clause = '   AND author_id = \''.$GLOBALS['user']['id'].'\'';
293  }
294
295  if (is_array($comment_id))
296    $where_clause = 'id IN('.implode(',', $comment_id).')';
297  else
298    $where_clause = 'id = '.$comment_id;
299
300  $query = '
301DELETE FROM '.COMMENTS_TABLE.'
302  WHERE '.$where_clause.
303$user_where_clause.'
304;';
305
306  if ( pwg_db_changes(pwg_query($query)) )
307  {
308    invalidate_user_cache_nb_comments();
309
310    email_admin('delete',
311                array('author' => $GLOBALS['user']['username'],
312                      'comment_id' => $comment_id
313                  ));
314    trigger_notify('user_comment_deletion', $comment_id);
315
316    return true;
317  }
318
319  return false;
320}
321
322/**
323 * Tries to update a user comment
324 *    only admin can update all comments
325 *    users can edit their own comments if admin allow them
326 *
327 * @param array $comment
328 * @param string $post_key secret key sent back to the browser
329 * @return string validate, moderate, reject
330 */
331
332function update_user_comment($comment, $post_key)
333{
334  global $conf, $page;
335
336  $comment_action = 'validate';
337
338  if ( !verify_ephemeral_key($post_key, $comment['image_id']) )
339  {
340    $comment_action='reject';
341  }
342  elseif (!$conf['comments_validation'] or is_admin()) // should the updated comment must be validated
343  {
344    $comment_action='validate'; //one of validate, moderate, reject
345  }
346  else
347  {
348    $comment_action='moderate'; //one of validate, moderate, reject
349  }
350
351  // perform more spam check
352  $comment_action =
353    trigger_change('user_comment_check',
354                  $comment_action,
355                  array_merge($comment,
356                              array('author' => $GLOBALS['user']['username'])
357                              )
358                  );
359
360  // website
361  if (!empty($comment['website_url']))
362  {
363    $comm['website_url'] = strip_tags($comm['website_url']);
364    if (!preg_match('/^https?/i', $comment['website_url']))
365    {
366      $comment['website_url'] = 'http://'.$comment['website_url'];
367    }
368    if (!url_check_format($comment['website_url']))
369    {
370      $page['errors'][] = l10n('Your website URL is invalid');
371      $comment_action='reject';
372    }
373  }
374
375  if ( $comment_action!='reject' )
376  {
377    $user_where_clause = '';
378    if (!is_admin())
379    {
380      $user_where_clause = '   AND author_id = \''.
381        $GLOBALS['user']['id'].'\'';
382    }
383
384    $query = '
385UPDATE '.COMMENTS_TABLE.'
386  SET content = \''.$comment['content'].'\',
387      website_url = '.(!empty($comment['website_url']) ? '\''.$comment['website_url'].'\'' : 'NULL').',
388      validated = \''.($comment_action=='validate' ? 'true':'false').'\',
389      validation_date = '.($comment_action=='validate' ? 'NOW()':'NULL').'
390  WHERE id = '.$comment['comment_id'].
391$user_where_clause.'
392;';
393    $result = pwg_query($query);
394
395    // mail admin and ask to validate the comment
396    if ($result and $conf['email_admin_on_comment_validation'] and 'moderate' == $comment_action)
397    {
398      include_once(PHPWG_ROOT_PATH.'include/functions_mail.inc.php');
399
400      $comment_url = get_absolute_root_url().'comments.php?comment_id='.$comment['comment_id'];
401
402      $keyargs_content = array(
403        get_l10n_args('Author: %s', stripslashes($GLOBALS['user']['username']) ),
404        get_l10n_args('Comment: %s', stripslashes($comment['content']) ),
405        get_l10n_args(''),
406        get_l10n_args('Manage this user comment: %s', $comment_url),
407        get_l10n_args('(!) This comment requires validation'),
408      );
409
410      pwg_mail_notification_admins(
411        get_l10n_args('Comment by %s', stripslashes($GLOBALS['user']['username']) ),
412        $keyargs_content
413      );
414    }
415    // just mail admin
416    elseif ($result)
417    {
418      email_admin('edit', array('author' => $GLOBALS['user']['username'],
419                                'content' => stripslashes($comment['content'])) );
420    }
421  }
422
423  return $comment_action;
424}
425
426/**
427 * Notifies admins about updated or deleted comment.
428 * Only used when no validation is needed, otherwise pwg_mail_notification_admins() is used.
429 *
430 * @param string $action edit, delete
431 * @param array $comment
432 */
433function email_admin($action, $comment)
434{
435  global $conf;
436
437  if (!in_array($action, array('edit', 'delete'))
438      or (($action=='edit') and !$conf['email_admin_on_comment_edition'])
439      or (($action=='delete') and !$conf['email_admin_on_comment_deletion']))
440  {
441    return;
442  }
443
444  include_once(PHPWG_ROOT_PATH.'include/functions_mail.inc.php');
445
446  $keyargs_content = array(
447    get_l10n_args('Author: %s', $comment['author']),
448    );
449
450  if ($action=='delete')
451  {
452    $keyargs_content[] = get_l10n_args('This author removed the comment with id %d', $comment['comment_id']);
453  }
454  else
455  {
456    $keyargs_content[] = get_l10n_args('This author modified following comment:');
457    $keyargs_content[] = get_l10n_args('Comment: %s', $comment['content']);
458  }
459
460  pwg_mail_notification_admins(
461    get_l10n_args('Comment by %s', $comment['author']),
462    $keyargs_content
463    );
464}
465
466/**
467 * Returns the author id of a comment
468 *
469 * @param int $comment_id
470 * @param bool $die_on_error
471 * @return int
472 */
473function get_comment_author_id($comment_id, $die_on_error=true)
474{
475  $query = '
476SELECT
477    author_id
478  FROM '.COMMENTS_TABLE.'
479  WHERE id = '.$comment_id.'
480;';
481  $result = pwg_query($query);
482  if (pwg_db_num_rows($result) == 0)
483  {
484    if ($die_on_error)
485    {
486      fatal_error('Unknown comment identifier');
487    }
488    else
489    {
490      return false;
491    }
492  }
493
494  list($author_id) = pwg_db_fetch_row($result);
495
496  return $author_id;
497}
498
499/**
500 * Tries to validate a user comment.
501 *
502 * @param int|int[] $comment_id
503 */
504function validate_user_comment($comment_id)
505{
506  if (is_array($comment_id))
507    $where_clause = 'id IN('.implode(',', $comment_id).')';
508  else
509    $where_clause = 'id = '.$comment_id;
510
511  $query = '
512UPDATE '.COMMENTS_TABLE.'
513  SET validated = \'true\'
514    , validation_date = NOW()
515  WHERE '.$where_clause.'
516;';
517  pwg_query($query);
518
519  invalidate_user_cache_nb_comments();
520  trigger_notify('user_comment_validation', $comment_id);
521}
522
523/**
524 * Clears cache of nb comments for all users
525 */
526function invalidate_user_cache_nb_comments()
527{
528  global $user;
529
530  unset($user['nb_available_comments']);
531
532  $query = '
533UPDATE '.USER_CACHE_TABLE.'
534  SET nb_available_comments = NULL
535;';
536  pwg_query($query);
537}
538
539?>
Note: See TracBrowser for help on using the repository browser.