OSDN Git Service

CHANGE: ENTITYクラスの整備。globalfunctions.phpの整理。
[nucleus-jp/nucleus-next.git] / nucleus / libs / NOTIFICATION.php
1 <?php
2 /*
3  * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/)
4  * Copyright (C) 2002-2009 The Nucleus Group
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  * (see nucleus/documentation/index.html#license for more info)
11  */
12 /**
13  * Class used to represent a collection of e-mail addresses, to which a
14  * message can be sent (e.g. comment or karma vote notification).
15  *
16  * @license http://nucleuscms.org/license.txt GNU General Public License
17  * @copyright Copyright (C) 2002-2009 The Nucleus Group
18  * @version $Id: NOTIFICATION.php 1534 2011-06-22 06:13:23Z sakamocchi $
19  */
20 class NOTIFICATION
21 {
22         static private $charset;
23         static private $scheme = 'B';
24         
25         /**
26          * NOTIFICATION::address_validation()
27          * Validating the string as address
28          * 
29          * FIXME: this is just migrated from globalfunctions.php
30          *  we should confirm this regular expression refering to RFC 5322
31          * 
32          * @link        http://www.ietf.org/rfc/rfc5322.txt
33          * @see         3.4. Address Specification
34          * 
35          * @static
36          * @param       String  $address        Address
37          * @return      Boolean valid or not
38          */
39         static public function address_validation($address)
40         {
41                 return (boolean) preg_match('#^(?!\\.)(?:\\.?[-a-zA-Z0-9!\\#$%&\'*+/=?^_`{|}~]+)+@(?!\\.)(?:\\.?(?!-)[-a-zA-Z0-9]+(?<!-)){2,}$#', $address);
42         }
43         
44         /**
45          * NOTIFICATION::get_mail_footer()
46          * Return mail footer with Nucleus CMS singnature
47          * 
48          * @static
49          * @param       void
50          * @return      String  Message body with 
51          */
52         static public function get_mail_footer()
53         {
54                 $message  = "\n";
55                 $message .= "\n";
56                 $message .= "-----------------------------\n";
57                 $message .=  "   Powered by Nucleus CMS\n";
58                 $message .=  "(http://www.nucleuscms.org/)\n";
59                 return $message;
60         }
61         
62         /**
63          * NOTIFICATION::mail
64          * Send mails with headers including 7bit-encoded multibyte string
65          * 
66          * @static
67          * @param       string  $to             receivers including singlebyte and multibyte strings, based on RFC 5322
68          * @param       string  $subject        subject including singlebyte and multibyte strings
69          * @param       string  $message        message including singlebyte and multibyte strings
70          * @param       string  $from           senders including singlebyte and multibyte strings, based on RFC 5322
71          * @param       string(B/Q)     $scheme 7bit-encoder scheme based on RFC 2047
72          * @return      boolean accepted delivery or not
73          */
74         static public function mail($to, $subject, $message, $from, $charset, $scheme='B')
75         {
76                 self::$charset = $charset;
77                 self::$scheme = $scheme;
78                 
79                 $to = self::mailbox_list_encoder($to);
80                 $subject = self::seven_bit_characters_encoder($subject);
81                 $from = 'From: ' . self::mailbox_list_encoder($from);
82                 
83                 /*
84                  * All of 7bit character encoding derives from ISO/IEC 646
85                  * So we can decide the body's encoding bit count by this regular expression.
86                  * 
87                  */
88                 $bitcount = '8bit';
89                 if ( preg_match('#\A[\x00-\x7f]*\z#', $message) )
90                 {
91                         $bitcount = '7bit';
92                 }
93                 
94                 $header  = 'Content-Type: text/html; charset=' . self::$charset . "; format=flowed; delsp=yes\n";
95                 $header .= "Content-Transfer-Encoding: {$bitcount}\n";
96                 $header .= "X-Mailer: Nucleus CMS NOTIFICATION class\n";
97                 
98                 return mail($to, $subject, $message, "{$from}\n{$header}");
99         }
100         
101         /**
102          * NOTIFICATION::mailbox_list_encoder
103          * Encode multi byte strings included in mailbox.
104          * The format of mailbox is based on RFC 5322, which obsoletes RFC 2822
105          * 
106          * @link        http://www.ietf.org/rfc/rfc5322.txt
107          * @see         3.4. Address Specification
108          * 
109          * @static
110          * @param       string  $mailbox_list           mailbox list
111          * @return      string  encoded string  
112          * 
113          */
114         static private function mailbox_list_encoder ($mailbox_list)
115         {
116                 $encoded_mailboxes = array();
117                 $mailboxes = preg_split('#,#', $mailbox_list);
118                 foreach ( $mailboxes as $mailbox )
119                 {
120                         if ( preg_match("#^([^,]+)?<([^,]+)?@([^,]+)?>$#", $mailbox, $match) )
121                         {
122                                 $display_name = self::seven_bit_characters_encoder(trim($match[1]));
123                                 $local_part = trim($match[2]);
124                                 $domain = trim($match[3]);
125                                 $encoded_mailboxes[] = "{$display_name} <{$local_part}@{$domain}>";
126                         }
127                         else if ( preg_match("#([^,]+)?@([^,]+)?#", $mailbox) )
128                         {
129                                 $encoded_mailboxes[] = $mailbox;
130                         }
131                         else
132                         {
133                                 continue;
134                         }
135                 }
136                 if ( $encoded_mailboxes == array() )
137                 {
138                         return FALSE;
139                 }
140                 return implode(',', $encoded_mailboxes);
141         }
142         
143         /**
144          * NOTIFICATION::seven_bit_characters_encoder
145          * Encoder into 7bit ASCII expression for Non-ASCII Text based on RFC 2047.
146          * 
147          * @link http://www.ietf.org/rfc/rfc2047.txt
148          * @see 2. Syntax of encoded-words
149          * 
150          * NOTE: RFC 2047 has a ambiguousity for dealing with 'linear-white-space'.
151          *  This causes a trouble related to line breaking between single byte and multi-byte strings.
152          *  To avoid this, single byte string is encoded as well as multi byte string here.
153          * 
154          * NOTE: RFC 2231 also defines the way to use non-ASCII characters in MIME header.
155          * http://www.ietf.org/rfc/rfc2231.txt
156          * 
157          * NOTE: iconv extension give the same functions as this in PHP5
158          * iconv_mime_encode():
159          * http://www.php.net/manual/en/function.iconv-mime-encode.php
160          * 
161          * @static
162          * @param       string  $charset        Character set encoding
163          * @param       string  $type   type of 7 bit encoding, should be 'B' or 'Q'
164          * @param       string  $string Target string with header field
165          * @return      string  encoded string
166          * 
167          */
168         static private function seven_bit_characters_encoder($string)
169         {
170                 $header = chr(13) . chr(10) . chr(32) . '=?' . self::$charset . '?' . self::$scheme . '?';
171                 $footer = "?=";
172                 $restriction = 78 - strlen($header) - strlen($footer) ;
173                 
174                 $encoded_words = array();
175                 for ( $i = 0; $i < self::strlen($string); $i++ )
176                 {
177                         if ( self::$scheme == 'B' )
178                         {
179                                 if ( $i == 0 )
180                                 {
181                                         $letters = '';
182                                 }
183                                 
184                                 $letter = self::substr($string, $i, 1);
185                                 $expected_length = strlen($letters) + strlen($letter) * 4 / 3;
186                                 
187                                 if ( $expected_length > $restriction )
188                                 {
189                                         $encoded_text = self::b_encoder($letters);
190                                         $encoded_words[] = "{$header}{$encoded_text}{$footer}";
191                                         $letters = '';
192                                 }
193                                 
194                                 $letters .= $letter;
195                                 
196                                 if ( $i == self::strlen($string) - 1 )
197                                 {
198                                         $encoded_text = self::b_encoder($letters);
199                                         $encoded_words[] = "{$header}{$encoded_text}{$footer}";
200                                         break;
201                                 }
202                                 continue;
203                         }
204                         else
205                         {
206                                 if ( $i == 0 )
207                                 {
208                                         $encoded_text = '';
209                                 }
210                                 
211                                 $encoded_letter = self::q_encoder(self::substr($string, $i, 1));
212                                 $expected_length = strlen($encoded_text) + strlen($encoded_letter);
213                                 
214                                 if ( $expected_length > $restriction )
215                                 {
216                                         $encoded_words[] = "{$header}{$encoded_text}{$footer}";
217                                         $letters = '';
218                                 }
219                                 
220                                 $encoded_text .= $encoded_letter;
221                                 
222                                 if ( $i == self::strlen($string) - 1 )
223                                 {
224                                         $encoded_words[] = "{$header}{$encoded_text}{$footer}";
225                                         break;
226                                 }
227                                 continue;
228                         }
229                 }
230                 
231                 return implode('', $encoded_words);
232         }
233         
234         /**
235          * NOTIFICATION::b_encoder()
236          * 
237          * B encoder according to RFC 2047.
238          * The "B" encoding is identical to the "BASE64" encoding defined by RFC 4648.
239          * 
240          * @link http://www.ietf.org/rfc/rfc4648.txt
241          * @see 6.8. Base64 Content-Transfer-Encoding
242          * 
243          * NOTE: According to RFC 4648
244          * (1)  The final quantum of encoding input is an integral multiple of 24 bits;
245          *              here, the final unit of encoded output will be an integral multiple
246          *              of 4 characters with no "=" padding.
247          * (2)  The final quantum of encoding input is exactly 8 bits; here,
248          *              the final unit of encoded output will be two characters followed
249          *              by two "=" padding characters.
250          * (3)  The final quantum of encoding input is exactly 16 bits; here,
251          *              the final unit of encoded output will be three characters followed
252          *              by one "=" padding character.
253          * 
254          * @static
255          * @param       string  $target targetted string
256          * @return      string  encoded string
257          */
258         static private function b_encoder($target)
259         {
260                 return base64_encode($target);
261         }
262         
263         /**
264          * NOTIFICATION::q_encoder()
265          * 
266          * Q encoder according to RFC 2047.
267          * The "Q" encoding is similar to "Quoted-Printable" content-transfer-encoding defined in RFC 2045,
268          *  but the "Q" encoding and the "Quoted-Printable" are different a bit.
269          * 
270          * @link http://www.ietf.org/rfc/rfc2047.txt
271          * @see 4.2. The "Q" encoding
272          * 
273          * NOTE: According to RFC 2047
274          * (1)  Any 8-bit value may be represented by a "=" followed by two hexadecimal digits.
275          *              For example, if the character set in use were ISO-8859-1,
276          *              the "=" character would thus be encoded as "=3D", and a SPACE by "=20".
277          *              (Upper case should be used for hexadecimal digits "A" through "F".)
278          * (2)  The 8-bit hexadecimal value 20 (e.g., ISO-8859-1 SPACE) may be
279          *              represented as "_" (underscore, ASCII 95.).
280          *              (This character may not pass through some internetwork mail gateways,
281          *              but its use will greatly enhance readability of "Q" encoded data
282          *              with mail readers that do not support this encoding.)
283          *              Note that the "_" always represents hexadecimal 20,
284          *              even if the SPACE character occupies a different code position
285          *              in the character set in use.
286          * (3)  8-bit values which correspond to printable ASCII characters
287          *              other than "=", "?", and "_" (underscore), MAY be represented as those characters.
288          *              (But see section 5 for restrictions.)
289          *              In particular, SPACE and TAB MUST NOT be represented as themselves within encoded words.
290          * 
291          * @static
292          * @param       string  $target targetted string
293          * @return      string  encoded string
294          */
295         static private function q_encoder($target)
296         {
297                 $string = '';
298                 
299                 for ( $i = 0; $i < strlen($target); $i++ )
300                 {
301                         $letter = substr ($target, $i, 1);
302                         $order = ord($letter);
303                         
304                         // Printable ASCII characters without "=", "?", "_"
305                         if ((33 <= $order && $order <= 60)
306                          || (62 == $order)
307                          || (64 <= $order && $order <= 94)
308                          || (96 <= $order && $order <= 126))
309                         {
310                                 $string .= strtoupper(dechex($order));
311                         }
312                         // Space shuold be encoded as the same strings as "_"
313                         else if ($order == 32)
314                         {
315                                 $string .= '_';
316                         }
317                         // Other characters
318                         else
319                         {
320                                 $string .= '=' . strtoupper(dechex($order));
321                         }
322                 }
323                 
324                 return $string;
325         }
326         
327         /**
328          * NOTICE: Deprecated
329          * NOTIFICATION::$addresses
330          * 
331          * @deprecated
332          */
333         private $addresses = array();
334         
335         /**
336          * NOTICE: Deprecated
337          * takes one string as argument, containing multiple e-mail addresses
338          * separated by semicolons
339          * eg: site@demuynck.org;nucleus@demuynck.org;foo@bar.com
340          * 
341          * @deprecated
342          */
343         function __construct($addresses)
344         {
345                 $this->addresses = i18n::explode(';' , $addresses);
346         }
347         
348         /**
349          * NOTICE: Deprecated
350          * NOTIFICATION::validAddresses()
351          * 
352          * returns true if all addresses are valid
353          * 
354          * @deprecated
355          * @param       Void
356          * @return      Boolean
357          */
358         function validAddresses()
359         {
360                 foreach ( $this->addresses as $address )
361                 {
362                         if ( !self::address_validation(trim($address)) )
363                         {
364                                 return 0;
365                         }
366                 }
367                 return 1;
368         }
369         
370         /**
371          * NOTICE: Deprecated
372          * NOTIFICATION::notify()
373          * 
374          * Sends email messages to all the email addresses
375          * 
376          * @deprecated
377          * @param       String  $title  
378          * @param       String  $message        
379          * @param       String  $from   
380          * @return      Void
381          */
382         function notify($title, $message, $from)
383         {
384                 global $member;
385                 $addresses = array();
386                 
387                 foreach ($this->addresses as $address)
388                 {
389                         if ( $member->isLoggedIn() && ($member->getEmail() == $address) )
390                         {
391                                 continue;
392                         }
393                         $addresses[] = $address;
394                 }
395                 
396                 self::mail(implode(',', $addresses), $title, $message , $from);
397                 return;
398         }
399 }