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

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

since number of accepted args not required for add_event_handler, simplify calls

  • Property svn:eol-style set to LF
File size: 14.4 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    $comm['website_url'] = strip_tags($comm['website_url']);
150    if (!preg_match('/^https?/i', $comm['website_url']))
151    {
152      $comm['website_url'] = 'http://'.$comm['website_url'];
153    }
154    if (!url_check_format($comm['website_url']))
155    {
156      $infos[] = l10n('Your website URL is invalid');
157      $comment_action='reject';
158    }
159  }
160
161  // email
162  if (empty($comm['email']))
163  {
164    if (!empty($user['email']))
165    {
166      $comm['email'] = $user['email'];
167    }
168    else if ($conf['comments_email_mandatory'])
169    {
170      $infos[] = l10n('Email address is missing. Please specify an email address.');
171      $comment_action='reject';
172    }
173  }
174  else if (!email_check_format($comm['email']))
175  {
176    $infos[] = l10n('mail address must be like xxx@yyy.eee (example : jack@altern.org)');
177    $comment_action='reject';
178  }
179
180  // anonymous id = ip address
181  $ip_components = explode('.', $comm['ip']);
182  if (count($ip_components) > 3)
183  {
184    array_pop($ip_components);
185  }
186  $comm['anonymous_id'] = implode('.', $ip_components);
187
188  if ($comment_action!='reject' and $conf['anti-flood_time']>0 and !is_admin())
189  { // anti-flood system
190    $reference_date = pwg_db_get_flood_period_expression($conf['anti-flood_time']);
191
192    $query = '
193SELECT count(1) FROM '.COMMENTS_TABLE.'
194  WHERE date > '.$reference_date.'
195    AND author_id = '.$comm['author_id'];
196    if (!is_classic_user())
197    {
198      $query.= '
199      AND anonymous_id = "'.$comm['anonymous_id'].'"';
200    }
201    $query.= '
202;';
203
204    list($counter) = pwg_db_fetch_row(pwg_query($query));
205    if ( $counter > 0 )
206    {
207      $infos[] = l10n('Anti-flood system : please wait for a moment before trying to post another comment');
208      $comment_action='reject';
209    }
210  }
211
212  // perform more spam check
213  $comment_action = trigger_change('user_comment_check',
214      $comment_action, $comm
215    );
216
217  if ( $comment_action!='reject' )
218  {
219    $query = '
220INSERT INTO '.COMMENTS_TABLE.'
221  (author, author_id, anonymous_id, content, date, validated, validation_date, image_id, website_url, email)
222  VALUES (
223    \''.$comm['author'].'\',
224    '.$comm['author_id'].',
225    \''.$comm['anonymous_id'].'\',
226    \''.$comm['content'].'\',
227    NOW(),
228    \''.($comment_action=='validate' ? 'true':'false').'\',
229    '.($comment_action=='validate' ? 'NOW()':'NULL').',
230    '.$comm['image_id'].',
231    '.(!empty($comm['website_url']) ? '\''.$comm['website_url'].'\'' : 'NULL').',
232    '.(!empty($comm['email']) ? '\''.$comm['email'].'\'' : 'NULL').'
233  )
234';
235    pwg_query($query);
236    $comm['id'] = pwg_db_insert_id(COMMENTS_TABLE);
237
238    invalidate_user_cache_nb_comments();
239
240    if ( ($conf['email_admin_on_comment'] && 'validate' == $comment_action)
241        or ($conf['email_admin_on_comment_validation'] and 'moderate' == $comment_action))
242    {
243      include_once(PHPWG_ROOT_PATH.'include/functions_mail.inc.php');
244
245      $comment_url = get_absolute_root_url().'comments.php?comment_id='.$comm['id'];
246
247      $keyargs_content = array(
248        get_l10n_args('Author: %s', stripslashes($comm['author']) ),
249        get_l10n_args('Email: %s', stripslashes($comm['email']) ),
250        get_l10n_args('Comment: %s', stripslashes($comm['content']) ),
251        get_l10n_args(''),
252        get_l10n_args('Manage this user comment: %s', $comment_url),
253      );
254
255      if ('moderate' == $comment_action)
256      {
257        $keyargs_content[] = get_l10n_args('(!) This comment requires validation');
258      }
259
260      pwg_mail_notification_admins(
261        get_l10n_args('Comment by %s', stripslashes($comm['author']) ),
262        $keyargs_content
263      );
264    }
265  }
266
267  return $comment_action;
268}
269
270/**
271 * Tries to delete a (or more) user comment.
272 *    only admin can delete all comments
273 *    other users can delete their own comments
274 *
275 * @param int|int[] $comment_id
276 * @return bool false if nothing deleted
277 */
278function delete_user_comment($comment_id)
279{
280  $user_where_clause = '';
281  if (!is_admin())
282  {
283    $user_where_clause = '   AND author_id = \''.$GLOBALS['user']['id'].'\'';
284  }
285
286  if (is_array($comment_id))
287    $where_clause = 'id IN('.implode(',', $comment_id).')';
288  else
289    $where_clause = 'id = '.$comment_id;
290
291  $query = '
292DELETE FROM '.COMMENTS_TABLE.'
293  WHERE '.$where_clause.
294$user_where_clause.'
295;';
296
297  if ( pwg_db_changes(pwg_query($query)) )
298  {
299    invalidate_user_cache_nb_comments();
300
301    email_admin('delete',
302                array('author' => $GLOBALS['user']['username'],
303                      'comment_id' => $comment_id
304                  ));
305    trigger_notify('user_comment_deletion', $comment_id);
306
307    return true;
308  }
309
310  return false;
311}
312
313/**
314 * Tries to update a user comment
315 *    only admin can update all comments
316 *    users can edit their own comments if admin allow them
317 *
318 * @param array $comment
319 * @param string $post_key secret key sent back to the browser
320 * @return string validate, moderate, reject
321 */
322
323function update_user_comment($comment, $post_key)
324{
325  global $conf, $page;
326
327  $comment_action = 'validate';
328
329  if ( !verify_ephemeral_key($post_key, $comment['image_id']) )
330  {
331    $comment_action='reject';
332  }
333  elseif (!$conf['comments_validation'] or is_admin()) // should the updated comment must be validated
334  {
335    $comment_action='validate'; //one of validate, moderate, reject
336  }
337  else
338  {
339    $comment_action='moderate'; //one of validate, moderate, reject
340  }
341
342  // perform more spam check
343  $comment_action =
344    trigger_change('user_comment_check',
345                  $comment_action,
346                  array_merge($comment,
347                              array('author' => $GLOBALS['user']['username'])
348                              )
349                  );
350
351  // website
352  if (!empty($comment['website_url']))
353  {
354    $comm['website_url'] = strip_tags($comm['website_url']);
355    if (!preg_match('/^https?/i', $comment['website_url']))
356    {
357      $comment['website_url'] = 'http://'.$comment['website_url'];
358    }
359    if (!url_check_format($comment['website_url']))
360    {
361      $page['errors'][] = l10n('Your website URL is invalid');
362      $comment_action='reject';
363    }
364  }
365
366  if ( $comment_action!='reject' )
367  {
368    $user_where_clause = '';
369    if (!is_admin())
370    {
371      $user_where_clause = '   AND author_id = \''.
372        $GLOBALS['user']['id'].'\'';
373    }
374
375    $query = '
376UPDATE '.COMMENTS_TABLE.'
377  SET content = \''.$comment['content'].'\',
378      website_url = '.(!empty($comment['website_url']) ? '\''.$comment['website_url'].'\'' : 'NULL').',
379      validated = \''.($comment_action=='validate' ? 'true':'false').'\',
380      validation_date = '.($comment_action=='validate' ? 'NOW()':'NULL').'
381  WHERE id = '.$comment['comment_id'].
382$user_where_clause.'
383;';
384    $result = pwg_query($query);
385
386    // mail admin and ask to validate the comment
387    if ($result and $conf['email_admin_on_comment_validation'] and 'moderate' == $comment_action)
388    {
389      include_once(PHPWG_ROOT_PATH.'include/functions_mail.inc.php');
390
391      $comment_url = get_absolute_root_url().'comments.php?comment_id='.$comment['comment_id'];
392
393      $keyargs_content = array(
394        get_l10n_args('Author: %s', stripslashes($GLOBALS['user']['username']) ),
395        get_l10n_args('Comment: %s', stripslashes($comment['content']) ),
396        get_l10n_args(''),
397        get_l10n_args('Manage this user comment: %s', $comment_url),
398        get_l10n_args('(!) This comment requires validation'),
399      );
400
401      pwg_mail_notification_admins(
402        get_l10n_args('Comment by %s', stripslashes($GLOBALS['user']['username']) ),
403        $keyargs_content
404      );
405    }
406    // just mail admin
407    elseif ($result)
408    {
409      email_admin('edit', array('author' => $GLOBALS['user']['username'],
410                                'content' => stripslashes($comment['content'])) );
411    }
412  }
413
414  return $comment_action;
415}
416
417/**
418 * Notifies admins about updated or deleted comment.
419 * Only used when no validation is needed, otherwise pwg_mail_notification_admins() is used.
420 *
421 * @param string $action edit, delete
422 * @param array $comment
423 */
424function email_admin($action, $comment)
425{
426  global $conf;
427
428  if (!in_array($action, array('edit', 'delete'))
429      or (($action=='edit') and !$conf['email_admin_on_comment_edition'])
430      or (($action=='delete') and !$conf['email_admin_on_comment_deletion']))
431  {
432    return;
433  }
434
435  include_once(PHPWG_ROOT_PATH.'include/functions_mail.inc.php');
436
437  $keyargs_content = array(
438    get_l10n_args('Author: %s', $comment['author']),
439    );
440
441  if ($action=='delete')
442  {
443    $keyargs_content[] = get_l10n_args('This author removed the comment with id %d', $comment['comment_id']);
444  }
445  else
446  {
447    $keyargs_content[] = get_l10n_args('This author modified following comment:');
448    $keyargs_content[] = get_l10n_args('Comment: %s', $comment['content']);
449  }
450
451  pwg_mail_notification_admins(
452    get_l10n_args('Comment by %s', $comment['author']),
453    $keyargs_content
454    );
455}
456
457/**
458 * Returns the author id of a comment
459 *
460 * @param int $comment_id
461 * @param bool $die_on_error
462 * @return int
463 */
464function get_comment_author_id($comment_id, $die_on_error=true)
465{
466  $query = '
467SELECT
468    author_id
469  FROM '.COMMENTS_TABLE.'
470  WHERE id = '.$comment_id.'
471;';
472  $result = pwg_query($query);
473  if (pwg_db_num_rows($result) == 0)
474  {
475    if ($die_on_error)
476    {
477      fatal_error('Unknown comment identifier');
478    }
479    else
480    {
481      return false;
482    }
483  }
484
485  list($author_id) = pwg_db_fetch_row($result);
486
487  return $author_id;
488}
489
490/**
491 * Tries to validate a user comment.
492 *
493 * @param int|int[] $comment_id
494 */
495function validate_user_comment($comment_id)
496{
497  if (is_array($comment_id))
498    $where_clause = 'id IN('.implode(',', $comment_id).')';
499  else
500    $where_clause = 'id = '.$comment_id;
501
502  $query = '
503UPDATE '.COMMENTS_TABLE.'
504  SET validated = \'true\'
505    , validation_date = NOW()
506  WHERE '.$where_clause.'
507;';
508  pwg_query($query);
509
510  invalidate_user_cache_nb_comments();
511  trigger_notify('user_comment_validation', $comment_id);
512}
513
514/**
515 * Clears cache of nb comments for all users
516 */
517function invalidate_user_cache_nb_comments()
518{
519  global $user;
520
521  unset($user['nb_available_comments']);
522
523  $query = '
524UPDATE '.USER_CACHE_TABLE.'
525  SET nb_available_comments = NULL
526;';
527  pwg_query($query);
528}
529
530?>
Note: See TracBrowser for help on using the repository browser.