Dotclear

source: plugins/subscribeToComments/inc/class.subscriber.php @ 2294

Revision 2294, 13.8 KB checked in by Moe, 14 years ago (diff)

Subscribe to comments 1.3.2 :

  • limited subscribers list to the current blog (closes #461)
  • moved _public.php classes in inc/
  • switched to GPL v2
  • PHP 5.3 compatibility ?
Line 
1<?php
2# ***** BEGIN LICENSE BLOCK *****
3#
4# This file is part of Subscribe to comments, a plugin for Dotclear 2
5# Copyright (C) 2008,2009,2010 Moe (http://gniark.net/)
6#
7# Subscribe to comments is free software; you can redistribute it and/or
8# modify it under the terms of the GNU General Public License v2.0
9# as published by the Free Software Foundation.
10#
11# Subscribe to comments is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14# GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public
17# License along with this program. If not, see
18# <http://www.gnu.org/licenses/>.
19#
20# Icon (icon.png) and images are from Silk Icons :
21# <http://www.famfamfam.com/lab/icons/silk/>
22#
23# Inspired by Subscribe to Comments for WordPress :
24# <http://txfx.net/code/wordpress/subscribe-to-comments/>
25#
26# ***** END LICENSE BLOCK *****
27
28if (!defined('DC_RC_PATH')) {return;}
29
30/**
31@ingroup Subscribe to comments
32@brief Subscriber
33*/
34class subscriber
35{
36     public $email;
37     public $id;
38
39     private $key;
40
41     private $link;
42
43     private $blog_name;
44     private $blog_url;
45
46     /**
47     construct
48     @param    email     <b>string</b>  Email address
49     */
50     public function __construct($email)
51     {
52          global $core;
53          subscribeToComments::checkEmail($email);
54
55          $this->email = $email;
56
57          # create subscriber if it doesn't exist yet
58          $this->id = self::getID($email);
59         
60          $rs = $core->con->select('SELECT user_key FROM '.$core->prefix.
61               'comment_subscriber WHERE (id = \''.
62               $core->con->escape((int) $this->id).'\') '.
63               'AND (email = \''.$core->con->escape($this->email).'\');');
64         
65          if ($rs->isEmpty())
66          {
67               throw new Exception(__('Invalid email address or key.'));
68          }
69          # else
70          $this->key = $rs->user_key;
71
72          $this->link = self::pageLink($this->email,$this->key);
73
74          $this->blog_name = $core->blog->name;
75          $this->blog_url = $core->blog->url;
76     }
77
78     /**
79     get the ID of an subscriber
80     @param    email <b>string</b> Email address
81     @return   <b>integer</b> Subscriber ID
82     */
83     private static function getID($email)
84     {
85          global $core;
86
87          $rs = $core->con->select('SELECT id FROM '.
88               $core->prefix.'comment_subscriber '.
89               'WHERE (email = \''.$core->con->escape($email).'\');');
90          if ($rs->isEmpty())
91          {
92               # create an subscriber if it doesn't exist yet
93               return(self::createSubscriber($email));
94          }
95          else
96          {
97               return($rs->id);
98          }
99     }
100
101     /**
102     create a subscriber
103     @param    email <b>string</b> Email address
104     @return   <b>integer</b> Subscriber ID
105     */
106     private static function createSubscriber($email)
107     {
108          global $core;
109
110          # from /dotclear/inc/core/class.dc.blog.php
111          # Get ID
112          $rs = $core->con->select('SELECT MAX(id) FROM '.$core->prefix.
113               'comment_subscriber;');
114         
115          $id = (integer) $rs->f(0) + 1;
116          # from /dotclear/inc/core/class.dc.blog.php
117
118          # create a random key
119          $key = http::browserUID(
120               $email.crypt::hmac(DC_MASTER_KEY,crypt::createPassword()));
121
122          $cur = $core->con->openCursor($core->prefix.'comment_subscriber');
123          $cur->id = $id;
124          $cur->email = $email;
125          $cur->user_key = $key;
126          $cur->status = 1;
127          $cur->insert();
128
129          # create the cookie
130          $cookie = $key.bin2hex(pack('a32',$id));
131          setcookie('subscribetocomments',$cookie,strtotime('+1 year'),'/');
132
133          # email
134          $subject = sprintf(subscribeToComments::getSetting('account_subject'),
135               $core->blog->name,$core->blog->url,$email,
136               self::pageLink($email,$key));
137          $content = sprintf(subscribeToComments::getSetting('account_content'),
138               $core->blog->name,$core->blog->url,$email,
139               self::pageLink($email,$key));
140          subscribeToComments::mail($email,$subject,$content);
141
142          return($cur->id);
143     }
144
145     /**
146     subscribe to a post
147     @param    post_id   <b>integer</b> Post ID
148     */
149     public function subscribe($post_id)
150     {
151          global $core;
152
153          if (!is_numeric($post_id)) {throw new Exception(__('Invalid post ID.'));}
154
155          $post = subscribeToComments::getPost($post_id);
156
157          if (subscribeToComments::getPost($post_id) == false)
158          {throw new Exception(__('Invalid post.'));}
159
160          global $core;
161
162          $meta = new dcMeta($core);
163          # subscribe the email (id) to the post (id)
164          $rs = $meta->getMeta('subscriber',null,$this->id,$post_id);
165          if ($rs->isEmpty())
166          {
167               # insert into $core->prefix.'meta' the id of the subscriber
168               $cur = $core->con->openCursor($core->prefix.'meta');
169               $cur->post_id = $post_id;
170               $cur->meta_type = 'subscriber';
171               $cur->meta_id = $this->id;
172               $cur->insert();
173
174               if ($core->blog->settings->subscribetocomments_subscribe_active)
175               {
176                    # email
177                    $subject = sprintf(
178                         subscribeToComments::getSetting('subscribe_subject'),
179                         $this->blog_name,$this->blog_url,$this->email,$this->link,
180                         $post['title'],$post['url']);
181                    $content = sprintf(
182                         subscribeToComments::getSetting('subscribe_content'),
183                         $this->blog_name,$this->blog_url,$this->email,$this->link,
184                         $post['title'],$post['url']);
185                    subscribeToComments::mail($this->email,$subject,$content);
186               }
187          }
188     }
189
190     /**
191     send an email before changing email
192     @param    new_email <b>string</b>  New email
193     */
194     public function requestUpdateEmail($new_email)
195     {
196          global $core;
197
198          $rs = $core->con->select('SELECT id FROM '.$core->prefix.'comment_subscriber '.
199               'WHERE (email = \''.$core->con->escape($new_email).'\') LIMIT 1;');
200          if (!$rs->isEmpty())
201          {
202               throw new Exception(__('This email address already exists.'));
203          }
204
205          # create a random key
206          $key = http::browserUID(
207               $new_email.crypt::hmac(DC_MASTER_KEY,crypt::createPassword()));
208
209          $cur = $core->con->openCursor($core->prefix.'comment_subscriber');
210          $cur->temp_key = $key;
211          $cur->temp_expire = date('Y-m-d H:i:s',strtotime('+1 day'));
212          $cur->update('WHERE (id = \''.$core->con->escape($this->id).'\') '.
213          'AND (user_key = \''.$core->con->escape($this->key).'\');');
214
215          $url = subscribeToComments::url().
216          (($core->blog->settings->url_scan == 'query_string') ? '&' : '?').
217          'new_email='.urlencode($new_email).'&temp_key='.$key;
218
219          $subject = sprintf(subscribeToComments::getSetting('email_subject'),
220               $this->blog_name,$this->blog_url,$this->email,$this->link,$new_email,$url);
221          $content = sprintf(subscribeToComments::getSetting('email_content'),
222               $this->blog_name,$this->blog_url,$this->email,$this->link,$new_email,$url);
223
224          # email to new email
225          subscribeToComments::mail($new_email,$subject,$content);
226     }
227
228     /**
229     remove subscriptions
230     @param    posts     <b>array</b>   Posts
231     */
232     public function removeSubscription($posts)
233     {
234          if (is_array($posts))
235          {
236               global $core;
237
238               foreach ($posts as $k => $v)
239               {
240                    if (is_numeric($v))
241                    {
242                         $core->con->execute('DELETE FROM '.$core->prefix.'meta WHERE '.
243                              '(post_id = \''.$core->con->escape($v).'\') '.
244                              'AND (meta_type = \'subscriber\') AND '.
245                              '(meta_id = \''.$core->con->escape($this->id).'\');');
246                    }
247               }
248          }
249     }
250
251     /**
252     delete subscriptions and account
253     */
254     public function deleteAccount()
255     {
256          global $core;
257
258          # delete subscriptions
259          $core->con->execute('DELETE FROM '.$core->prefix.'meta WHERE '.
260               '(meta_type = \'subscriber\') '.
261               'AND (meta_id = \''.$core->con->escape($this->id).'\');');
262          # delete subscriber
263          $core->con->execute('DELETE FROM '.$core->prefix.'comment_subscriber '.
264               'WHERE (id = \''.$core->con->escape($this->id).'\') '.
265               'AND (user_key = \''.$core->con->escape($this->key).'\');');
266          self::logout();
267     }
268
269     /**
270     block emails
271     @param    block     <b>boolean</b> Block emails
272     */
273     public function blockEmails($block=false)
274     {
275          global $core;
276
277          # update status
278          $cur = $core->con->openCursor($core->prefix.'comment_subscriber');
279          $cur->status = (($block) ? -1 : 1);
280          $cur->update('WHERE (id = \''.$core->con->escape($this->id).'\') '.
281               'AND (user_key = \''.$core->con->escape($this->key).'\');');
282     }
283
284     /* /functions used by object */
285
286     /* static functions */
287     
288     /**
289     logout, destroy cookie
290     */
291     public static function logout()
292     {
293          session_regenerate_id();
294
295          # delete the cookie
296          unset($_COOKIE['subscribetocomments']);
297          setcookie('subscribetocomments','',0,'/');
298     }   
299
300     /**
301     login with to a key
302     @param    email     <b>string</b> Email
303     @param    key  <b>string</b> Key
304     */
305     public static function loginKey($email,$key)
306     {
307          self::logout();
308
309          global $core;
310
311          $rs = $core->con->select('SELECT id, user_key FROM '.
312               $core->prefix.'comment_subscriber '.
313               ' WHERE (email = \''.$core->con->escape($email).'\')'.
314               ' AND (user_key = \''.$core->con->escape($key).'\');');
315          if ($rs->isEmpty())
316          {
317               throw new Exception(__('Invalid email address or key.'));
318          }
319
320          session_regenerate_id();
321
322          # create the cookie
323          $cookie = $rs->user_key.bin2hex(pack('a32',$rs->id));
324          setcookie('subscribetocomments',$cookie,strtotime('+1 year'),'/');
325     }
326
327     /**
328     resend informations to an email address
329     @param    email <b>string</b> Email address
330     */
331     public static function resendInformations($email)
332     {
333          global $core;
334
335          $rs = $core->con->select('SELECT id, email, user_key FROM '.
336               $core->prefix.'comment_subscriber '.
337               ' WHERE (email = \''.$core->con->escape($email).'\')'.
338               ' AND (status = \'1\');');
339          if (!$rs->isEmpty())
340          {
341               # email
342               $subject = sprintf(
343                    subscribeToComments::getSetting('account_subject'),
344                    $core->blog->name,$core->blog->url,$rs->email,
345                    self::pageLink($rs->email,$rs->user_key));
346               $content = sprintf(
347                    subscribeToComments::getSetting('account_content'),
348                    $core->blog->name,$core->blog->url,$rs->email,
349                    self::pageLink($rs->email,$rs->user_key));
350               subscribeToComments::mail($rs->email,$subject,$content);
351          }
352          # don't show an error if the email does not exist
353          # prevent brut force attacks to guess existing emails
354          # 0.5 to 2 seconds
355          usleep(rand(50000,2000000));
356     }
357
358     /**
359     check the cookie
360     @return <b>boolean</b>   Subscriber is identified
361     */
362     public static function checkCookie()
363     {
364          $id = self::getCookie('id');
365          $key = self::getCookie('key');
366
367          global $core;
368
369          if (!is_numeric($id)) {return;}
370
371          $rs = $core->con->select('SELECT user_key FROM '.
372               $core->prefix.'comment_subscriber '.
373               'WHERE (id = \''.$core->con->escape($id).'\') '.
374               'AND (user_key = \''.$core->con->escape($key).'\');');
375          if ($rs->isEmpty())
376          {
377               return(false);
378          }
379          # else
380          return($key == $rs->user_key);
381     }
382
383     /**
384     check nonce when a action is requested with $_POST
385     */
386     public static function checkNonce()
387     {
388          # from /dotclear/inc/admin/prepend.php, modified
389          if ((empty($_POST['subscribeToCommentsNonce'])) OR
390               ($_POST['subscribeToCommentsNonce'] != 
391                    crypt::hmac(DC_MASTER_KEY,session_id()))
392          )
393          {
394               http::head(412);
395               header('Content-Type: text/html');
396               echo 'Precondition Failed';
397               echo '<br /><a href="'.subscribeToComments::url().'">'.
398                    __('Reload the page').'</a>';
399               exit;
400          }
401     }
402
403     /**
404     if emails are blocked
405     @return <b>boolean</b>   Emails are blocked
406     */
407     public static function blocked()
408     {
409          $id = self::getCookie('id');
410          $key = self::getCookie('key');
411
412          global $core;
413
414          $rs = $core->con->select('SELECT status FROM '.
415               $core->prefix.'comment_subscriber '.
416               'WHERE (id = \''.$core->con->escape((int) $id).'\') '.
417               'AND (user_key = \''.$core->con->escape($key).'\');');
418          if ($rs->isEmpty())
419          {
420               return(false);
421          }
422          # else
423          return($rs->status == -1);
424     }
425
426     /**
427     get the URL of the subscriptions page with email
428     @param    id   <b>interger</b>     Subscriber ID
429     @return   <b>string</b> URL
430     */
431     public static function pageLink($email,$key)
432     {
433          global $core;
434         
435          return(subscribeToComments::url().
436          (($core->blog->settings->url_scan == 'query_string') ? '&' : '?').'email='.
437          urlencode($email).'&key='.$key);
438     }
439
440     /**
441     get informations from the cookie
442     @param    value <b>string</b> Value to get
443     @return   <b>string</b>  Subscriber ID
444     */
445     public static function getCookie($value)
446     {
447          if ((!isset($_COOKIE['subscribetocomments']))
448               || (strlen($_COOKIE['subscribetocomments']) != 104))
449          {
450               return(false);
451          }
452
453          $id = substr($_COOKIE['subscribetocomments'],40);
454          $id = @unpack('a32',@pack('H*',$id));
455          if (is_array($id))
456          {
457               $id = $id[1];
458          }
459
460          if ($value == 'id')
461          {
462               return($id);
463          }
464          elseif ($value == 'key')
465          {
466               return(substr($_COOKIE['subscribetocomments'],0,40));
467          }
468          elseif ($value == 'email')
469          {
470               global $core;
471
472               $rs = $core->con->select('SELECT email FROM '.
473                    $core->prefix.'comment_subscriber '.
474                    'WHERE (id = \''.$core->con->escape((int) $id).'\');');
475
476               if ($rs->isEmpty())
477               {
478                    return(false);
479               }
480               # else
481               return($rs->email);
482          }
483          return(false);
484     }
485
486     /**
487     update the email address
488     @param    new_email <b>string</b>  New email
489     */
490     public static function updateEmail($new_email,$temp_key)
491     {
492          global $core;
493
494          $rs = $core->con->select('SELECT id, email, temp_expire FROM '.
495               $core->prefix.'comment_subscriber '.
496               'WHERE (temp_key = \''.$core->con->escape($temp_key).'\') LIMIT 1;');
497          if ($rs->isEmpty()) {throw new Exception(__('Invalid key.'));}
498          $rs_new_email = $core->con->select(
499               'SELECT id FROM '.$core->prefix.'comment_subscriber '.
500               'WHERE (email = \''.$core->con->escape($new_email).'\') LIMIT 1;');
501         
502          if (!$rs_new_email->isEmpty())
503          {
504               throw new Exception(__('This email address already exists.'));
505          }
506          if ($rs->temp_expire < date('Y-m-d H:i:s'))
507          {
508               throw new Exception(__('Link expired, request another email.'));
509          }
510
511          # create a random key
512          $key = http::browserUID(
513               $new_email.crypt::hmac(DC_MASTER_KEY,crypt::createPassword()));
514
515          $cur = $core->con->openCursor($core->prefix.'comment_subscriber');
516          $cur->email = $new_email;
517          $cur->user_key = $key;
518          $cur->temp_key = null;
519          $cur->temp_expire = null;
520          $cur->update('WHERE (id = \''.$core->con->escape((int) $rs->id).'\') '.
521          'AND (temp_key = \''.$core->con->escape($temp_key).'\');');
522
523          $subject = sprintf(subscribeToComments::getSetting('account_subject'),
524               $core->blog->name,$core->blog->url,$new_email,
525               self::pageLink($new_email,$key));
526          $content = sprintf(subscribeToComments::getSetting('account_content'),
527               $core->blog->name,$core->blog->url,$new_email,
528               self::pageLink($new_email,$key));
529
530          # email to new email
531          subscribeToComments::mail($new_email,$subject,$content);
532
533          # login with new email
534          self::loginKey($new_email,$key);
535     }
536}
537
538?>
Note: See TracBrowser for help on using the repository browser.

Sites map