source: extensions/Subscribe_to_comments/include/functions.inc.php @ 15656

Last change on this file since 15656 was 15656, checked in by mistic100, 12 years ago

use Quoted-Printable for emails

File size: 20.4 KB
Line 
1<?php
2if (!defined('PHPWG_ROOT_PATH')) die('Hacking attempt!');
3
4include_once(PHPWG_ROOT_PATH.'include/functions_mail.inc.php');
5
6/**
7 * Send comment to subscribers
8 * @param: array comment (author, content, image_id|category_id)
9 */
10function send_comment_to_subscribers($comm)
11{
12  if ( empty($comm) or !is_array($comm) )
13  {
14    trigger_error('send_comment_to_subscribers: undefineded comm', E_USER_WARNING);
15    return false;
16  }
17 
18  global $conf, $page, $user, $template;
19 
20  // create search clauses
21  $where_clauses = array();
22  if (isset($comm['image_id']))
23  {
24    $element_id = $comm['image_id'];
25    $element_type = 'image';
26   
27    array_push($where_clauses, 'type = "image" AND element_id = '.$element_id.'');
28    if (!empty($page['category']['id'])) array_push($where_clauses, 'type = "album-images" AND element_id = '.$page['category']['id'].'');
29    array_push($where_clauses, 'type = "all-images"');
30  }
31  else if (isset($comm['category_id']))
32  {
33    $element_id = $comm['category_id'];
34    $element_type = 'category';
35   
36    array_push($where_clauses, 'type = "album" AND element_id = '.$element_id.'');
37    array_push($where_clauses, 'type = "all-albums"');
38  }
39  else
40  {
41    return;
42  }
43 
44  // exclude current user
45  $exclude = null;
46  if (!empty($_POST['stc_mail']))
47  {
48    $exclude = pwg_db_real_escape_string($_POST['stc_mail']);
49  }
50  else if (!is_a_guest())
51  {
52    $exclude = $user['email'];
53  }
54 
55  // get subscribers datas
56  $query = '
57SELECT
58    id,
59    email,
60    language
61  FROM '.SUBSCRIBE_TO_TABLE.'
62  WHERE (
63      ('.implode(")\n      OR (", $where_clauses).')
64    )
65    AND validated = true
66    AND email != "'.$exclude.'"
67';
68  $subscriptions = hash_from_query($query, 'email');
69 
70  set_make_full_url();
71 
72  // get element infos
73  if ($element_type == 'image')
74  {
75    $element = get_picture_infos($comm['image_id']);
76  }
77  else
78  {
79    $element = get_category_infos($comm['category_id']);
80  }
81 
82  // format comment
83  if ($comm['author'] == 'guest') $comm['author'] = l10n('guest');
84  $comm['author'] = trigger_event('render_comment_author', $comm['author']);
85  $comm['content'] = trigger_event('render_comment_content', $comm['content']);
86 
87  // mail content
88  $subject = '['.strip_tags($conf['gallery_title']).'] Re:'.$element['name'];
89   
90  $template->set_filename('stc_mail', dirname(__FILE__).'/../template/mail/notification.tpl');
91
92  foreach ($subscriptions as $row)
93  {
94    // get subscriber id
95    if ( ($uid = get_userid_by_email($row['email'])) !== false )
96    {
97      $row['user_id'] = $uid;
98    }
99    else
100    {
101      $row['user_id'] = $conf['guest_id'];
102    }
103   
104    // check permissions
105    if (!user_can_view_element($row['user_id'], $element_id, $element_type))
106    {
107      continue;
108    }
109   
110    // send mail
111    switch_lang_to($row['language']);
112    load_language('plugin.lang', SUBSCRIBE_TO_PATH);
113   
114    $comm['caption'] = sprintf('<b>%s</b> wrote on <i>%s</i>', $comm['author'], format_date(date('Y-d-m H:i:s')));
115   
116    $template->assign('STC', array(
117      'element' => $element,
118      'comment' => $comm,
119      'UNSUB_URL' => make_stc_url('unsubscribe', $row['email'], $row['id']),
120      'MANAGE_URL' => make_stc_url('manage', $row['email']),
121      'GALLERY_TITLE' => $conf['gallery_title'],
122      ));
123   
124    $content = $template->parse('stc_mail', true);
125
126    stc_send_mail($row['email'], $content, $subject);
127    switch_lang_back();
128  }
129 
130  load_language('plugin.lang', SUBSCRIBE_TO_PATH);
131  unset_make_full_url();
132}
133
134
135/**
136 * add an email to subscribers list
137 * @param: string email
138 * @param: string type (image|album-images|all-images|album|all-albums)
139 * @param: int element_id
140 * @return: bool
141 */
142function subscribe_to_comments($email, $type, $element_id='NULL')
143{
144  if (empty($type))
145  {
146    trigger_error('subscribe_to_comment: missing type', E_USER_WARNING);
147    return false;
148  }
149 
150  if ( !in_array($type, array('all-images','all-albums')) and $element_id == 'NULL' )
151  {
152    trigger_error('subscribe_to_comment: missing element_id', E_USER_WARNING);
153    return false;
154  }
155 
156  global $page, $conf, $user, $template, $picture;
157 
158  // check email
159  if ( !empty($email) and !is_valid_email($email) )
160  {
161    array_push($page['errors'], l10n('mail address must be like xxx@yyy.eee (example : jack@altern.org)'));
162    return false;
163  }
164  if ( ( is_a_guest() or empty($user['email']) ) and empty($email) )
165  {
166    array_push($page['errors'], l10n('Invalid email adress, your are not subscribed to comments.'));
167    return false;
168  }
169  else if ( !is_a_guest() and empty($email) )
170  {
171    $email = $user['email'];
172  }
173 
174  // search if already registered (can use ODKU because we want to get the id of inserted OR updated row)
175  $query = '
176SELECT id
177  FROM '.SUBSCRIBE_TO_TABLE.'
178  WHERE
179    type = "'.$type.'"
180    AND element_id = '.$element_id.'
181    AND email = "'.pwg_db_real_escape_string($email).'"
182;';
183  $result = pwg_query($query);
184 
185  if (pwg_db_num_rows($result))
186  {
187    list($inserted_id) = pwg_db_fetch_row($result);
188  }
189  else
190  {
191    $query = '
192INSERT INTO '.SUBSCRIBE_TO_TABLE.'(
193    type,
194    element_id,
195    language,
196    email,
197    registration_date,
198    validated
199  )
200  VALUES(
201    "'.$type.'",
202    '.$element_id.',
203    "'.$user['language'].'",
204    "'.pwg_db_real_escape_string($email).'",
205    NOW(),
206    "'.(is_a_guest() ? "false" : "true").'"
207  )
208;';
209    pwg_query($query);
210   
211    $inserted_id = pwg_db_insert_id();
212  }
213 
214  // notify admins
215  if ( pwg_db_changes(null) != 0 and $conf['Subscribe_to_Comments']['notify_admin_on_subscribe'] )
216  {
217    stc_mail_notification_admins($email, $type, $element_id, $inserted_id);
218  }
219 
220  // send validation mail
221  if ( is_a_guest() and pwg_db_changes(null) != 0 )
222  {
223    set_make_full_url();
224   
225    $template->set_filename('stc_mail', dirname(__FILE__).'/../template/mail/confirm.tpl');
226   
227    $subject = '['.strip_tags($conf['gallery_title']).'] '.l10n('Confirm your subscribtion to comments');
228     
229    switch ($type)
230    {
231      case 'image':
232        $element = get_picture_infos($element_id);
233        $element['on'] = sprintf(l10n('the picture <a href="%s">%s</a>'), $element['url'], $element['name']);
234        break;
235      case 'album-images':
236        $element = get_category_infos($element_id);
237        $element['on'] = sprintf(l10n('all pictures of the album <a href="%s">%s</a>'), $element['url'], $element['name']);
238        break;
239      case 'all-images':
240        $element['thumbnail'] = null;
241        $element['on'] = l10n('all pictures of the gallery');
242        break;
243      case 'album':
244        $element = get_category_infos($element_id);
245        $element['on'] = sprintf(l10n('the album <a href="%s">%s</a>'), $element['url'], $element['name']);
246        break;
247      case 'all-albums':
248        $element['thumbnail'] = null;
249        $element['on'] = l10n('all albums of the gallery');
250        break;
251    }
252   
253    $template->assign('STC', array(
254      'element' => $element,
255      'VALIDATE_URL' => make_stc_url('validate', $email, $inserted_id),
256      'MANAGE_URL' => make_stc_url('manage', $email),
257      'GALLERY_TITLE' => $conf['gallery_title'],
258      ));
259   
260    $content = $template->parse('stc_mail', true);
261
262    stc_send_mail($email, $content, $subject);
263    unset_make_full_url();
264   
265    array_push($page['infos'], l10n('Please check your email inbox to confirm your subscription.'));
266    return true;
267  }
268  // just display confirmation message
269  else if (pwg_db_changes(null) != 0)
270  {
271    array_push($page['infos'], l10n('You have been added to the list of subscribers.'));
272    return true;
273  }
274 
275  return false;
276}
277
278
279/**
280 * remove an email from subscribers list
281 * @param: string email
282 * @param: int subscription id
283 * @return: bool
284 */
285function un_subscribe_to_comments($email, $id)
286{ 
287  if (empty($id))
288  {
289    trigger_error('un_subscribe_to_comment: missing id', E_USER_WARNING);
290    return false;
291  }
292 
293  global $template, $user;
294 
295  // check email
296  if ( ( is_a_guest() or empty($user['email']) ) and empty($email) )
297  {
298    return false;
299  }
300  else if ( !is_a_guest() and empty($email) )
301  {
302    $email = $user['email'];
303  }
304 
305  // delete subscription
306  $query = '
307DELETE FROM '.SUBSCRIBE_TO_TABLE.'
308  WHERE
309    email = "'.pwg_db_real_escape_string($email).'"
310    AND id = "'.pwg_db_real_escape_string($id).'"
311;';
312  pwg_query($query);
313     
314  if (pwg_db_changes(null) != 0) return true;
315  return false;
316}
317
318
319/**
320 * validate a subscription
321 * @param: string email
322 * @param: int subscription id
323 * @return: bool
324 */
325function validate_subscriptions($email, $id)
326{
327  if (empty($email))
328  {
329    trigger_error('validate_subscriptions: missing email', E_USER_WARNING);
330    return false;
331  }
332 
333  if (empty($id))
334  {
335    trigger_error('validate_subscriptions: missing id', E_USER_WARNING);
336    return false;
337  }
338 
339  $query = '
340UPDATE '.SUBSCRIBE_TO_TABLE.'
341  SET validated = "true"
342  WHERE
343    email = "'.pwg_db_real_escape_string($email).'"
344    AND id = '.pwg_db_real_escape_string($id).'
345;';
346  pwg_query($query);
347     
348  if (pwg_db_changes(null) != 0) return true;
349  return false;
350}
351
352
353/**
354 * send notification to admins
355 * @param: string email
356 * @param: string type (image|album-images|all-images|album|all-albums)
357 * @param: int element_id
358 * @param: int subscription id
359 */
360function stc_mail_notification_admins($email, $type, $element_id, $inserted_id)
361{
362  global $user, $conf, $template;
363 
364  $admins = get_admins_email();
365  if (empty($admins)) return;
366 
367  set_make_full_url();
368  switch_lang_to(get_default_language());
369  load_language('plugin.lang', SUBSCRIBE_TO_PATH);
370 
371  $template->set_filename('stc_mail', dirname(__FILE__).'/../template/mail/admin.tpl');
372   
373  $subject = '['.strip_tags($conf['gallery_title']).'] '.sprintf(l10n('%s has subscribed to comments on'), is_a_guest()?$email:$user['username']);
374   
375  switch ($type)
376  {
377    case 'image':
378      $element = get_picture_infos($element_id, false);
379      $element['on'] = sprintf(l10n('the picture <a href="%s">%s</a>'), $element['url'], $element['name']);
380      break;
381    case 'album-images':
382      $element = get_category_infos($element_id, false);
383      $element['on'] = sprintf(l10n('all pictures of the album <a href="%s">%s</a>'), $element['url'], $element['name']);
384      break;
385    case 'all-images':
386      $element['on'] = l10n('all pictures of the gallery');
387      break;
388    case 'album':
389      $element = get_category_infos($element_id, false);
390      $element['on'] = sprintf(l10n('the album <a href="%s">%s</a>'), $element['url'], $element['name']);
391      break;
392    case 'all-albums':
393      $element['on'] = l10n('all albums of the gallery');
394      break;
395  }
396 
397  $technical_infos[] = sprintf(l10n('Connected user: %s'), stripslashes($user['username']));
398  $technical_infos[] = sprintf(l10n('IP: %s'), $_SERVER['REMOTE_ADDR']);
399  $technical_infos[] = sprintf(l10n('Browser: %s'), $_SERVER['HTTP_USER_AGENT']);
400 
401  $template->assign('STC', array(
402    'ELEMENT' => $element['on'],
403    'USER' => sprintf(l10n('%s has subscribed to comments on'), is_a_guest() ? '<b>'.$email.'</b>' : '<b>'.$user['username'].'</b> ('.$email.')'), 
404    'GALLERY_TITLE' => $conf['gallery_title'],
405    'TECHNICAL' => implode('<br>', $technical_infos),
406    ));
407 
408  $content = $template->parse('stc_mail', true);
409
410  stc_send_mail($admins, $content, $subject);
411 
412  unset_make_full_url();
413  switch_lang_back();
414  load_language('plugin.lang', SUBSCRIBE_TO_PATH);
415}
416
417
418/**
419 * create absolute url to subscriptions section
420 * @param: string action
421 * @param: string email
422 * @param: int optional
423 * @return: string
424 */
425function make_stc_url($action, $email, $id=null)
426{
427  if ( empty($action) or empty($email) )
428  {
429    trigger_error('make_stc_url: missing action and/or mail', E_USER_WARNING);
430    return null;
431  }
432 
433  global $conf;
434  set_make_full_url();
435 
436  $url_params = array(
437    'action' => $action,
438    'email' => $email,
439    );
440 
441  if (!empty($id))
442  {
443    $url_params['id'] = $id;
444  }
445 
446  $url_params['key'] = crypt_value(
447    $action.$email.(isset($url_params['id'])?$url_params['id']:null), 
448    $conf['secret_key']
449    );
450 
451  $url = add_url_params(
452    make_index_url( array('section' => 'subscriptions') ),
453    $url_params
454    );
455   
456  unset_make_full_url();
457  return $url;
458}
459
460
461/**
462 * send mail with STC style
463 * @param: string to
464 * @param: string content
465 * @param: string subject
466 * @return: bool
467 */
468function stc_send_mail($to, $content, $subject)
469{
470  global $conf, $conf_mail, $page, $template;
471 
472  // inputs
473  if (empty($to))
474  {
475    return false;
476  }
477
478  if (empty($content))
479  {
480    return false;
481  }
482 
483  if (empty($subject))
484  {
485    $subject = 'Piwigo';
486  }
487  else
488  {
489    $subject = trim(preg_replace('#[\n\r]+#s', '', $subject));
490    $subject = encode_mime_header($subject);
491  }
492 
493  if (!isset($conf_mail))
494  {
495    $conf_mail = get_mail_configuration();
496  }
497
498  $args['from'] = $conf_mail['formated_email_webmaster'];
499 
500  set_make_full_url();
501 
502  // hearders
503  $headers = 'From: '.$args['from']."\n"; 
504  $headers.= 'MIME-Version: 1.0'."\n";
505  $headers.= 'X-Mailer: Piwigo Mailer'."\n";
506  $headers.= 'Content-Transfer-Encoding: Quoted-Printable'."\n";
507  $headers.= 'Content-Type: text/html; charset="'.get_pwg_charset().'";'."\n";
508 
509  // template
510  $template->set_filenames(array(
511    'stc_mail_header' => dirname(__FILE__).'/../template/mail/header.tpl',
512    'stc_mail_footer' => dirname(__FILE__).'/../template/mail/footer.tpl',
513    ));
514  $stc_mail_css = file_get_contents(dirname(__FILE__).'/../template/mail/style.css');
515   
516  $template->assign(array(
517    'GALLERY_URL' => get_gallery_home_url(),
518    'PHPWG_URL' => PHPWG_URL,
519    'STC_MAIL_CSS' => str_replace("\n", null, $stc_mail_css),
520    ));
521 
522  $content = $template->parse('stc_mail_header', true) . $content . $template->parse('stc_mail_footer', true);
523 
524  $content = quoted_printable_encode($content);
525  $content = wordwrap($content, 70, "\n", true);
526
527  unset_make_full_url();
528 
529  // send mail
530  return
531    trigger_event('send_mail',
532      false, /* Result */
533      trigger_event('send_mail_to', get_strict_email_list($to)),
534      trigger_event('send_mail_subject', $subject),
535      trigger_event('send_mail_content', $content),
536      trigger_event('send_mail_headers', $headers),
537      $args
538    );
539}
540
541
542/**
543 * get name, url and thumbnail of a picture
544 * @param: int image_id
545 * @param: bool return thumbnail
546 * @return: array (id, name, url, thumbnail)
547 */
548function get_picture_infos($image_id, $with_thumb=true)
549{
550  $query = '
551SELECT
552    id,
553    file,
554    name,
555    path
556  FROM '.IMAGES_TABLE.'
557  WHERE id = '.$image_id.'
558;';
559  $element = pwg_db_fetch_assoc(pwg_query($query));
560   
561  if (empty($element['name']))
562  {
563    $element['name'] = get_name_from_file($element['file']);
564  }
565 
566  $url_params = array('image_id' => $element['id']);
567  $element['url'] = make_picture_url($url_params);
568 
569  if ($with_thumb)
570  {
571    $element['thumbnail'] = DerivativeImage::thumb_url($element);
572  }
573 
574  return $element;
575}
576
577/**
578 * get name, url and thumbnail of a category
579 * @param: int cat_id
580 * @param: int return thumbnail
581 * @return: array (id, name, url, thumbnail)
582 */
583function get_category_infos($cat_id, $with_thumb=true)
584{
585  global $conf;
586 
587  $query = '
588SELECT
589    cat.id,
590    cat.name,
591    cat.permalink,
592    img.id AS image_id,
593    img.path
594  FROM '.CATEGORIES_TABLE.' AS cat
595    LEFT JOIN '.USER_CACHE_CATEGORIES_TABLE.' AS ucc
596      ON ucc.cat_id = cat.id AND ucc.user_id = '.$conf['guest_id'].'
597    LEFT JOIN '.IMAGES_TABLE.' AS img
598      ON img.id = ucc.user_representative_picture_id
599  WHERE cat.id = '.$cat_id.'
600;';
601  $element = pwg_db_fetch_assoc(pwg_query($query));
602  // we use guest_id for user_cache because we don't know the status of recipient
603 
604  $element['url'] = make_index_url(array(
605    'section'=>'categories',
606    'category'=>$element,
607    ));
608 
609  if ($with_thumb)
610  {
611    $element['thumbnail'] = DerivativeImage::thumb_url(array(
612      'id'=>$element['image_id'],
613      'path'=>$element['path'],
614      ));
615  }
616 
617  return $element;
618}
619
620/**
621 * get list of admins email
622 * @return: string
623 */
624function get_admins_email()
625{
626  global $conf, $user;
627 
628  $admins = array();
629 
630  $query = '
631SELECT
632    u.'.$conf['user_fields']['username'].' AS username,
633    u.'.$conf['user_fields']['email'].' AS email
634  FROM '.USERS_TABLE.' AS u
635    JOIN '.USER_INFOS_TABLE.' AS i
636      ON i.user_id =  u.'.$conf['user_fields']['id'].'
637  WHERE i.status IN ("webmaster", "admin")
638    AND '.$conf['user_fields']['email'].' IS NOT NULL
639    AND i.user_id != '.$user['id'].'
640  ORDER BY username
641;';
642
643  $datas = pwg_query($query);
644  if (!empty($datas))
645  {
646    while ($admin = pwg_db_fetch_assoc($datas))
647    {
648      array_push($admins, format_email($admin['username'], $admin['email']));
649    }
650  }
651
652  return implode(',', $admins);
653}
654
655
656/**
657 * check if the given user can view the category/image
658 * @param: int user_id
659 * @param: int element_id
660 * @param: string type (image|category)
661 * @return: bool
662 */
663function user_can_view_element($user_id, $element_id, $type)
664{
665  global $conf;
666 
667  $old_conf = $conf['external_authentification'];
668  $conf['external_authentification'] = false;
669  $user = getuserdata($user_id, true);
670  $conf['external_authentification'] = $old_conf;
671 
672  if ($type == 'image')
673  {
674    return !in_array($element_id, explode(',', $user['image_access_list']));
675  }
676  else if ($type == 'category')
677  {
678    return !in_array($element_id, explode(',', $user['forbidden_categories']));
679  }
680  else
681  {
682    return false;
683  }
684}
685
686
687/**
688 * check if mail adress is valid
689 * @param: string email
690 * @return: bool
691 */
692function is_valid_email($mail_address)
693{
694  if (version_compare(PHP_VERSION, '5.2.0') >= 0)
695  {
696    return filter_var($mail_address, FILTER_VALIDATE_EMAIL)!==false;
697  }
698  else
699  {
700    $atom   = '[-a-z0-9!#$%&\'*+\\/=?^_`{|}~]';   // before  arobase
701    $domain = '([a-z0-9]([-a-z0-9]*[a-z0-9]+)?)'; // domain name
702    $regex = '/^' . $atom . '+' . '(\.' . $atom . '+)*' . '@' . '(' . $domain . '{1,63}\.)+' . $domain . '{2,63}$/i';
703
704    if (!preg_match($regex, $mail_address)) return false;
705    return true;
706  }
707}
708
709
710/**
711 * crypt a string using mcrypt extension or
712 * http://stackoverflow.com/questions/800922/how-to-encrypt-string-without-mcrypt-library-in-php/802957#802957
713 * @param: string value to crypt
714 * @param: string key
715 * @return: string
716 */
717function crypt_value($value, $key)
718{ 
719  if (extension_loaded('mcrypt'))
720  {
721    $iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB);
722    $iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
723    $result = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $value, MCRYPT_MODE_ECB, $iv);
724  }
725  else
726  {
727    $result = null;
728    for($i = 0; $i < strlen($value); $i++)
729    {
730      $char = substr($value, $i, 1);
731      $keychar = substr($key, ($i % strlen($key))-1, 1);
732      $char = chr(ord($char) + ord($keychar));
733      $result .= $char;
734    }
735  }
736 
737  $result = base64url_encode($result);
738  return trim($result); 
739}
740
741/**
742 * decrypt a string crypted with previous function
743 * @param: string value to decrypt
744 * @param: string key
745 * @return: string
746 */
747function decrypt_value($value, $key)
748{
749  $value = base64url_decode($value); 
750 
751  if (extension_loaded('mcrypt'))
752  {
753    $iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB);
754    $iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
755    $result = mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, $value, MCRYPT_MODE_ECB, $iv);
756  }
757  else
758  {
759    $result = null;
760    for($i = 0; $i < strlen($value); $i++)
761    {
762      $char = substr($value, $i, 1);
763      $keychar = substr($key, ($i % strlen($key))-1, 1);
764      $char = chr(ord($char) - ord($keychar));
765      $result .= $char;
766    }
767  }
768 
769  return trim($result);
770}
771
772/**
773 * variant of base64 functions usable into url
774 * http://php.net/manual/en/function.base64-encode.php#103849
775 */
776function base64url_encode($data)
777{
778  return rtrim(strtr(base64_encode($data), '+/', '-_'), '=');
779}
780function base64url_decode($data)
781{
782  return base64_decode(str_pad(strtr($data, '-_', '+/'), strlen($data) % 4, '=', STR_PAD_RIGHT));
783} 
784
785?>
Note: See TracBrowser for help on using the repository browser.