4 * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/)
\r
5 * Copyright (C) 2002-2012 The Nucleus Group
\r
7 * This program is free software; you can redistribute it and/or
\r
8 * modify it under the terms of the GNU General Public License
\r
9 * as published by the Free Software Foundation; either version 2
\r
10 * of the License, or (at your option) any later version.
\r
11 * (see nucleus/documentation/index.html#license for more info)
\r
14 * Class used to represent a collection of e-mail addresses, to which a
\r
15 * message can be sent (e.g. comment or karma vote notification).
\r
17 * @license http://nucleuscms.org/license.txt GNU General Public License
\r
18 * @copyright Copyright (C) 2002-2012 The Nucleus Group
\r
19 * @version $Id: NOTIFICATION.php 1534 2011-06-22 06:13:23Z sakamocchi $
\r
23 static private $charset;
\r
24 static private $scheme = 'B';
\r
27 * NOTIFICATION::address_validation()
\r
28 * Validating the string as address
\r
30 * FIXME: this is just migrated from globalfunctions.php
\r
31 * we should confirm this regular expression refering to RFC 5322
\r
33 * @link http://www.ietf.org/rfc/rfc5322.txt
\r
34 * @see 3.4. Address Specification
\r
37 * @param String $address Address
\r
38 * @return Boolean valid or not
\r
40 static public function address_validation($address)
\r
42 return (boolean) preg_match('#^(?!\\.)(?:\\.?[-a-zA-Z0-9!\\#$%&\'*+/=?^_`{|}~]+)+@(?!\\.)(?:\\.?(?!-)[-a-zA-Z0-9]+(?<!-)){2,}$#', $address);
\r
46 * NOTIFICATION::get_mail_footer()
\r
47 * Return mail footer with Nucleus CMS singnature
\r
51 * @return String Message body with
\r
53 static public function get_mail_footer()
\r
57 $message .= "-----------------------------\n";
\r
58 $message .= " Powered by Nucleus CMS\n";
\r
59 $message .= "(http://www.nucleuscms.org/)\n";
\r
64 * NOTIFICATION::mail
\r
65 * Send mails with headers including 7bit-encoded multibyte string
\r
68 * @param string $to receivers including singlebyte and multibyte strings, based on RFC 5322
\r
69 * @param string $subject subject including singlebyte and multibyte strings
\r
70 * @param string $message message including singlebyte and multibyte strings
\r
71 * @param string $from senders including singlebyte and multibyte strings, based on RFC 5322
\r
72 * @param string(B/Q) $scheme 7bit-encoder scheme based on RFC 2047
\r
73 * @return boolean accepted delivery or not
\r
75 static public function mail($to, $subject, $message, $from, $charset, $scheme='B')
\r
77 self::$charset = $charset;
\r
78 self::$scheme = $scheme;
\r
80 $to = self::mailbox_list_encoder($to);
\r
81 $subject = self::seven_bit_characters_encoder($subject);
\r
82 $from = 'From: ' . self::mailbox_list_encoder($from);
\r
85 * All of 7bit character encoding derives from ISO/IEC 646
\r
86 * So we can decide the body's encoding bit count by this regular expression.
\r
90 if ( preg_match('#\A[\x00-\x7f]*\z#', $message) )
\r
95 $header = 'Content-Type: text/html; charset=' . self::$charset . "; format=flowed; delsp=yes\n";
\r
96 $header .= "Content-Transfer-Encoding: {$bitcount}\n";
\r
97 $header .= "X-Mailer: Nucleus CMS NOTIFICATION class\n";
\r
99 return mail($to, $subject, $message, "{$from}\n{$header}");
\r
103 * NOTIFICATION::mailbox_list_encoder
\r
104 * Encode multi byte strings included in mailbox.
\r
105 * The format of mailbox is based on RFC 5322, which obsoletes RFC 2822
\r
107 * @link http://www.ietf.org/rfc/rfc5322.txt
\r
108 * @see 3.4. Address Specification
\r
111 * @param string $mailbox_list mailbox list
\r
112 * @return string encoded string
\r
115 static private function mailbox_list_encoder ($mailbox_list)
\r
117 $encoded_mailboxes = array();
\r
118 $mailboxes = preg_split('#,#', $mailbox_list);
\r
119 foreach ( $mailboxes as $mailbox )
\r
121 if ( preg_match("#^([^,]+)?<([^,]+)?@([^,]+)?>$#", $mailbox, $match) )
\r
123 $display_name = self::seven_bit_characters_encoder(trim($match[1]));
\r
124 $local_part = trim($match[2]);
\r
125 $domain = trim($match[3]);
\r
126 $encoded_mailboxes[] = "{$display_name} <{$local_part}@{$domain}>";
\r
128 else if ( preg_match("#([^,]+)?@([^,]+)?#", $mailbox) )
\r
130 $encoded_mailboxes[] = $mailbox;
\r
137 if ( $encoded_mailboxes == array() )
\r
141 return implode(',', $encoded_mailboxes);
\r
145 * NOTIFICATION::seven_bit_characters_encoder
\r
146 * Encoder into 7bit ASCII expression for Non-ASCII Text based on RFC 2047.
\r
148 * @link http://www.ietf.org/rfc/rfc2047.txt
\r
149 * @see 2. Syntax of encoded-words
\r
151 * NOTE: RFC 2047 has a ambiguousity for dealing with 'linear-white-space'.
\r
152 * This causes a trouble related to line breaking between single byte and multi-byte strings.
\r
153 * To avoid this, single byte string is encoded as well as multi byte string here.
\r
155 * NOTE: RFC 2231 also defines the way to use non-ASCII characters in MIME header.
\r
156 * http://www.ietf.org/rfc/rfc2231.txt
\r
158 * NOTE: iconv extension give the same functions as this in PHP5
\r
159 * iconv_mime_encode():
\r
160 * http://www.php.net/manual/en/function.iconv-mime-encode.php
\r
163 * @param string $charset Character set encoding
\r
164 * @param string $type type of 7 bit encoding, should be 'B' or 'Q'
\r
165 * @param string $string Target string with header field
\r
166 * @return string encoded string
\r
169 static private function seven_bit_characters_encoder($string)
\r
171 $header = chr(13) . chr(10) . chr(32) . '=?' . self::$charset . '?' . self::$scheme . '?';
\r
173 $restriction = 78 - strlen($header) - strlen($footer) ;
\r
175 $encoded_words = array();
\r
176 for ( $i = 0; $i < i18n::strlen($string); $i++ )
\r
178 if ( self::$scheme == 'B' )
\r
185 $letter = i18n::substr($string, $i, 1);
\r
186 $expected_length = strlen($letters) + strlen($letter) * 4 / 3;
\r
188 if ( $expected_length > $restriction )
\r
190 $encoded_text = self::b_encoder($letters);
\r
191 $encoded_words[] = "{$header}{$encoded_text}{$footer}";
\r
195 $letters .= $letter;
\r
197 if ( $i == i18n::strlen($string) - 1 )
\r
199 $encoded_text = self::b_encoder($letters);
\r
200 $encoded_words[] = "{$header}{$encoded_text}{$footer}";
\r
209 $encoded_text = '';
\r
212 $encoded_letter = self::q_encoder(i18n::substr($string, $i, 1));
\r
213 $expected_length = strlen($encoded_text) + strlen($encoded_letter);
\r
215 if ( $expected_length > $restriction )
\r
217 $encoded_words[] = "{$header}{$encoded_text}{$footer}";
\r
221 $encoded_text .= $encoded_letter;
\r
223 if ( $i == i18n::strlen($string) - 1 )
\r
225 $encoded_words[] = "{$header}{$encoded_text}{$footer}";
\r
232 return implode('', $encoded_words);
\r
236 * NOTIFICATION::b_encoder()
\r
238 * B encoder according to RFC 2047.
\r
239 * The "B" encoding is identical to the "BASE64" encoding defined by RFC 4648.
\r
241 * @link http://www.ietf.org/rfc/rfc4648.txt
\r
242 * @see 6.8. Base64 Content-Transfer-Encoding
\r
244 * NOTE: According to RFC 4648
\r
245 * (1) The final quantum of encoding input is an integral multiple of 24 bits;
\r
246 * here, the final unit of encoded output will be an integral multiple
\r
247 * of 4 characters with no "=" padding.
\r
248 * (2) The final quantum of encoding input is exactly 8 bits; here,
\r
249 * the final unit of encoded output will be two characters followed
\r
250 * by two "=" padding characters.
\r
251 * (3) The final quantum of encoding input is exactly 16 bits; here,
\r
252 * the final unit of encoded output will be three characters followed
\r
253 * by one "=" padding character.
\r
256 * @param string $target targetted string
\r
257 * @return string encoded string
\r
259 static private function b_encoder($target)
\r
261 return base64_encode($target);
\r
265 * NOTIFICATION::q_encoder()
\r
267 * Q encoder according to RFC 2047.
\r
268 * The "Q" encoding is similar to "Quoted-Printable" content-transfer-encoding defined in RFC 2045,
\r
269 * but the "Q" encoding and the "Quoted-Printable" are different a bit.
\r
271 * @link http://www.ietf.org/rfc/rfc2047.txt
\r
272 * @see 4.2. The "Q" encoding
\r
274 * NOTE: According to RFC 2047
\r
275 * (1) Any 8-bit value may be represented by a "=" followed by two hexadecimal digits.
\r
276 * For example, if the character set in use were ISO-8859-1,
\r
277 * the "=" character would thus be encoded as "=3D", and a SPACE by "=20".
\r
278 * (Upper case should be used for hexadecimal digits "A" through "F".)
\r
279 * (2) The 8-bit hexadecimal value 20 (e.g., ISO-8859-1 SPACE) may be
\r
280 * represented as "_" (underscore, ASCII 95.).
\r
281 * (This character may not pass through some internetwork mail gateways,
\r
282 * but its use will greatly enhance readability of "Q" encoded data
\r
283 * with mail readers that do not support this encoding.)
\r
284 * Note that the "_" always represents hexadecimal 20,
\r
285 * even if the SPACE character occupies a different code position
\r
286 * in the character set in use.
\r
287 * (3) 8-bit values which correspond to printable ASCII characters
\r
288 * other than "=", "?", and "_" (underscore), MAY be represented as those characters.
\r
289 * (But see section 5 for restrictions.)
\r
290 * In particular, SPACE and TAB MUST NOT be represented as themselves within encoded words.
\r
293 * @param string $target targetted string
\r
294 * @return string encoded string
\r
296 static private function q_encoder($target)
\r
300 for ( $i = 0; $i < strlen($target); $i++ )
\r
302 $letter = substr ($target, $i, 1);
\r
303 $order = ord($letter);
\r
305 // Printable ASCII characters without "=", "?", "_"
\r
306 if ((33 <= $order && $order <= 60)
\r
308 || (64 <= $order && $order <= 94)
\r
309 || (96 <= $order && $order <= 126))
\r
311 $string .= strtoupper(dechex($order));
\r
313 // Space shuold be encoded as the same strings as "_"
\r
314 else if ($order == 32)
\r
318 // Other characters
\r
321 $string .= '=' . strtoupper(dechex($order));
\r
329 * NOTICE: Deprecated
\r
330 * NOTIFICATION::$addresses
\r
334 private $addresses = array();
\r
337 * NOTICE: Deprecated
\r
338 * takes one string as argument, containing multiple e-mail addresses
\r
339 * separated by semicolons
\r
340 * eg: site@demuynck.org;nucleus@demuynck.org;foo@bar.com
\r
344 function __construct($addresses)
\r
346 $this->addresses = preg_split('#;#' , $addresses);
\r
350 * NOTICE: Deprecated
\r
351 * NOTIFICATION::validAddresses()
\r
353 * returns true if all addresses are valid
\r
359 function validAddresses()
\r
361 foreach ( $this->addresses as $address )
\r
363 if ( !self::address_validation(trim($address)) )
\r
372 * NOTICE: Deprecated
\r
373 * NOTIFICATION::notify()
\r
375 * Sends email messages to all the email addresses
\r
378 * @param String $title
\r
379 * @param String $message
\r
380 * @param String $from
\r
383 function notify($title, $message, $from)
\r
386 $addresses = array();
\r
388 foreach ($this->addresses as $address)
\r
390 if ( $member->isLoggedIn() && ($member->getEmail() == $address) )
\r
394 $addresses[] = $address;
\r
397 self::mail(implode(',', $addresses), $title, $message , $from);
\r
404 * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/)
405 * Copyright (C) 2002-2009 The Nucleus Group
407 * This program is free software; you can redistribute it and/or
408 * modify it under the terms of the GNU General Public License
409 * as published by the Free Software Foundation; either version 2
410 * of the License, or (at your option) any later version.
411 * (see nucleus/documentation/index.html#license for more info)
414 * Class used to represent a collection of e-mail addresses, to which a
415 * message can be sent (e.g. comment or karma vote notification).
417 * @license http://nucleuscms.org/license.txt GNU General Public License
418 * @copyright Copyright (C) 2002-2009 The Nucleus Group
419 * @version $Id: NOTIFICATION.php 1836 2012-05-12 10:38:31Z sakamocchi $
423 static private $charset;
424 static private $scheme = 'B';
427 * NOTIFICATION::address_validation()
428 * Validating the string as address
430 * FIXME: this is just migrated from globalfunctions.php
431 * we should confirm this regular expression refering to RFC 5322
433 * @link http://www.ietf.org/rfc/rfc5322.txt
434 * @see 3.4. Address Specification
437 * @param String $address Address
438 * @return Boolean valid or not
440 static public function address_validation($address)
442 return (boolean) preg_match('#^(?!\\.)(?:\\.?[-a-zA-Z0-9!\\#$%&\'*+/=?^_`{|}~]+)+@(?!\\.)(?:\\.?(?!-)[-a-zA-Z0-9]+(?<!-)){2,}$#', $address);
446 * NOTIFICATION::get_mail_footer()
447 * Return mail footer with Nucleus CMS singnature
451 * @return String Message body with
453 static public function get_mail_footer()
457 $message .= "-----------------------------\n";
458 $message .= " Powered by Nucleus CMS\n";
459 $message .= "(http://www.nucleuscms.org/)\n";
465 * Send mails with headers including 7bit-encoded multibyte string
468 * @param string $to receivers including singlebyte and multibyte strings, based on RFC 5322
469 * @param string $subject subject including singlebyte and multibyte strings
470 * @param string $message message including singlebyte and multibyte strings
471 * @param string $from senders including singlebyte and multibyte strings, based on RFC 5322
472 * @param string(B/Q) $scheme 7bit-encoder scheme based on RFC 2047
473 * @return boolean accepted delivery or not
475 static public function mail($to, $subject, $message, $from, $charset, $scheme='B')
477 self::$charset = $charset;
478 self::$scheme = $scheme;
480 $to = self::mailbox_list_encoder($to);
481 $subject = self::seven_bit_characters_encoder($subject);
482 $from = 'From: ' . self::mailbox_list_encoder($from);
485 * All of 7bit character encoding derives from ISO/IEC 646
486 * So we can decide the body's encoding bit count by this regular expression.
490 if ( preg_match('#\A[\x00-\x7f]*\z#', $message) )
495 $header = 'Content-Type: text/plain; charset=' . self::$charset . "; format=flowed; delsp=yes\n";
496 $header .= "Content-Transfer-Encoding: {$bitcount}\n";
497 $header .= "X-Mailer: Nucleus CMS NOTIFICATION class\n";
499 return mail($to, $subject, $message, "{$from}\n{$header}");
503 * NOTIFICATION::mailbox_list_encoder
504 * Encode multi byte strings included in mailbox.
505 * The format of mailbox is based on RFC 5322, which obsoletes RFC 2822
507 * @link http://www.ietf.org/rfc/rfc5322.txt
508 * @see 3.4. Address Specification
511 * @param string $mailbox_list mailbox list
512 * @return string encoded string
515 static private function mailbox_list_encoder ($mailbox_list)
517 $encoded_mailboxes = array();
518 $mailboxes = preg_split('#,#', $mailbox_list);
519 foreach ( $mailboxes as $mailbox )
521 if ( preg_match("#^([^,]+)?<([^,]+)?@([^,]+)?>$#", $mailbox, $match) )
523 $display_name = self::seven_bit_characters_encoder(trim($match[1]));
524 $local_part = trim($match[2]);
525 $domain = trim($match[3]);
526 $encoded_mailboxes[] = "{$display_name} <{$local_part}@{$domain}>";
528 else if ( preg_match("#([^,]+)?@([^,]+)?#", $mailbox) )
530 $encoded_mailboxes[] = $mailbox;
537 if ( $encoded_mailboxes == array() )
541 return implode(',', $encoded_mailboxes);
545 * NOTIFICATION::seven_bit_characters_encoder
546 * Encoder into 7bit ASCII expression for Non-ASCII Text based on RFC 2047.
548 * @link http://www.ietf.org/rfc/rfc2047.txt
549 * @see 2. Syntax of encoded-words
551 * NOTE: RFC 2047 has a ambiguousity for dealing with 'linear-white-space'.
552 * This causes a trouble related to line breaking between single byte and multi-byte strings.
553 * To avoid this, single byte string is encoded as well as multi byte string here.
555 * NOTE: RFC 2231 also defines the way to use non-ASCII characters in MIME header.
556 * http://www.ietf.org/rfc/rfc2231.txt
558 * NOTE: iconv extension give the same functions as this in PHP5
559 * iconv_mime_encode():
560 * http://www.php.net/manual/en/function.iconv-mime-encode.php
563 * @param string $charset Character set encoding
564 * @param string $type type of 7 bit encoding, should be 'B' or 'Q'
565 * @param string $string Target string with header field
566 * @return string encoded string
569 static private function seven_bit_characters_encoder($string)
571 $header = chr(13) . chr(10) . chr(32) . '=?' . self::$charset . '?' . self::$scheme . '?';
573 $restriction = 78 - strlen($header) - strlen($footer) ;
575 $encoded_words = array();
576 for ( $i = 0; $i < i18n::strlen($string); $i++ )
578 if ( self::$scheme == 'B' )
585 $letter = i18n::substr($string, $i, 1);
586 $expected_length = strlen($letters) + strlen($letter) * 4 / 3;
588 if ( $expected_length > $restriction )
590 $encoded_text = self::b_encoder($letters);
591 $encoded_words[] = "{$header}{$encoded_text}{$footer}";
597 if ( $i == i18n::strlen($string) - 1 )
599 $encoded_text = self::b_encoder($letters);
600 $encoded_words[] = "{$header}{$encoded_text}{$footer}";
612 $encoded_letter = self::q_encoder(i18n::substr($string, $i, 1));
613 $expected_length = strlen($encoded_text) + strlen($encoded_letter);
615 if ( $expected_length > $restriction )
617 $encoded_words[] = "{$header}{$encoded_text}{$footer}";
621 $encoded_text .= $encoded_letter;
623 if ( $i == i18n::strlen($string) - 1 )
625 $encoded_words[] = "{$header}{$encoded_text}{$footer}";
632 return implode('', $encoded_words);
636 * NOTIFICATION::b_encoder()
638 * B encoder according to RFC 2047.
639 * The "B" encoding is identical to the "BASE64" encoding defined by RFC 4648.
641 * @link http://www.ietf.org/rfc/rfc4648.txt
642 * @see 6.8. Base64 Content-Transfer-Encoding
644 * NOTE: According to RFC 4648
645 * (1) The final quantum of encoding input is an integral multiple of 24 bits;
646 * here, the final unit of encoded output will be an integral multiple
647 * of 4 characters with no "=" padding.
648 * (2) The final quantum of encoding input is exactly 8 bits; here,
649 * the final unit of encoded output will be two characters followed
650 * by two "=" padding characters.
651 * (3) The final quantum of encoding input is exactly 16 bits; here,
652 * the final unit of encoded output will be three characters followed
653 * by one "=" padding character.
656 * @param string $target targetted string
657 * @return string encoded string
659 static private function b_encoder($target)
661 return base64_encode($target);
665 * NOTIFICATION::q_encoder()
667 * Q encoder according to RFC 2047.
668 * The "Q" encoding is similar to "Quoted-Printable" content-transfer-encoding defined in RFC 2045,
669 * but the "Q" encoding and the "Quoted-Printable" are different a bit.
671 * @link http://www.ietf.org/rfc/rfc2047.txt
672 * @see 4.2. The "Q" encoding
674 * NOTE: According to RFC 2047
675 * (1) Any 8-bit value may be represented by a "=" followed by two hexadecimal digits.
676 * For example, if the character set in use were ISO-8859-1,
677 * the "=" character would thus be encoded as "=3D", and a SPACE by "=20".
678 * (Upper case should be used for hexadecimal digits "A" through "F".)
679 * (2) The 8-bit hexadecimal value 20 (e.g., ISO-8859-1 SPACE) may be
680 * represented as "_" (underscore, ASCII 95.).
681 * (This character may not pass through some internetwork mail gateways,
682 * but its use will greatly enhance readability of "Q" encoded data
683 * with mail readers that do not support this encoding.)
684 * Note that the "_" always represents hexadecimal 20,
685 * even if the SPACE character occupies a different code position
686 * in the character set in use.
687 * (3) 8-bit values which correspond to printable ASCII characters
688 * other than "=", "?", and "_" (underscore), MAY be represented as those characters.
689 * (But see section 5 for restrictions.)
690 * In particular, SPACE and TAB MUST NOT be represented as themselves within encoded words.
693 * @param string $target targetted string
694 * @return string encoded string
696 static private function q_encoder($target)
700 for ( $i = 0; $i < strlen($target); $i++ )
702 $letter = substr ($target, $i, 1);
703 $order = ord($letter);
705 // Printable ASCII characters without "=", "?", "_"
706 if ((33 <= $order && $order <= 60)
708 || (64 <= $order && $order <= 94)
709 || (96 <= $order && $order <= 126))
711 $string .= strtoupper(dechex($order));
713 // Space shuold be encoded as the same strings as "_"
714 else if ($order == 32)
721 $string .= '=' . strtoupper(dechex($order));
730 * NOTIFICATION::$addresses
734 private $addresses = array();
738 * takes one string as argument, containing multiple e-mail addresses
739 * separated by semicolons
740 * eg: site@demuynck.org;nucleus@demuynck.org;foo@bar.com
744 function __construct($addresses)
746 $this->addresses = preg_split('#;#' , $addresses);
751 * NOTIFICATION::validAddresses()
753 * returns true if all addresses are valid
759 function validAddresses()
761 foreach ( $this->addresses as $address )
763 if ( !self::address_validation(trim($address)) )
773 * NOTIFICATION::notify()
775 * Sends email messages to all the email addresses
778 * @param String $title
779 * @param String $message
780 * @param String $from
783 function notify($title, $message, $from)
786 $addresses = array();
788 foreach ($this->addresses as $address)
790 if ( $member->isLoggedIn() && ($member->getEmail() == $address) )
794 $addresses[] = $address;
797 self::mail(implode(',', $addresses), $title, $message , $from);
801 >>>>>>> skinnable-master