Automatically exported from code.google.com/p/planningalerts
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

352 lines
13 KiB

  1. <?php
  2. // +-----------------------------------------------------------------------+
  3. // | Copyright (c) 2002-2003 Richard Heyes |
  4. // | All rights reserved. |
  5. // | |
  6. // | Redistribution and use in source and binary forms, with or without |
  7. // | modification, are permitted provided that the following conditions |
  8. // | are met: |
  9. // | |
  10. // | o Redistributions of source code must retain the above copyright |
  11. // | notice, this list of conditions and the following disclaimer. |
  12. // | o Redistributions in binary form must reproduce the above copyright |
  13. // | notice, this list of conditions and the following disclaimer in the |
  14. // | documentation and/or other materials provided with the distribution.|
  15. // | o The names of the authors may not be used to endorse or promote |
  16. // | products derived from this software without specific prior written |
  17. // | permission. |
  18. // | |
  19. // | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
  20. // | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
  21. // | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
  22. // | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
  23. // | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
  24. // | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
  25. // | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
  26. // | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
  27. // | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
  28. // | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
  29. // | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
  30. // | |
  31. // +-----------------------------------------------------------------------+
  32. // | Author: Richard Heyes <richard@phpguru.org> |
  33. // +-----------------------------------------------------------------------+
  34. /**
  35. *
  36. * Raw mime encoding class
  37. *
  38. * What is it?
  39. * This class enables you to manipulate and build
  40. * a mime email from the ground up.
  41. *
  42. * Why use this instead of mime.php?
  43. * mime.php is a userfriendly api to this class for
  44. * people who aren't interested in the internals of
  45. * mime mail. This class however allows full control
  46. * over the email.
  47. *
  48. * Eg.
  49. *
  50. * // Since multipart/mixed has no real body, (the body is
  51. * // the subpart), we set the body argument to blank.
  52. *
  53. * $params['content_type'] = 'multipart/mixed';
  54. * $email = new Mail_mimePart('', $params);
  55. *
  56. * // Here we add a text part to the multipart we have
  57. * // already. Assume $body contains plain text.
  58. *
  59. * $params['content_type'] = 'text/plain';
  60. * $params['encoding'] = '7bit';
  61. * $text = $email->addSubPart($body, $params);
  62. *
  63. * // Now add an attachment. Assume $attach is
  64. * the contents of the attachment
  65. *
  66. * $params['content_type'] = 'application/zip';
  67. * $params['encoding'] = 'base64';
  68. * $params['disposition'] = 'attachment';
  69. * $params['dfilename'] = 'example.zip';
  70. * $attach =& $email->addSubPart($body, $params);
  71. *
  72. * // Now build the email. Note that the encode
  73. * // function returns an associative array containing two
  74. * // elements, body and headers. You will need to add extra
  75. * // headers, (eg. Mime-Version) before sending.
  76. *
  77. * $email = $message->encode();
  78. * $email['headers'][] = 'Mime-Version: 1.0';
  79. *
  80. *
  81. * Further examples are available at http://www.phpguru.org
  82. *
  83. * TODO:
  84. * - Set encode() to return the $obj->encoded if encode()
  85. * has already been run. Unless a flag is passed to specifically
  86. * re-build the message.
  87. *
  88. * @author Richard Heyes <richard@phpguru.org>
  89. * @version $Revision: 1.13 $
  90. * @package Mail
  91. */
  92. class Mail_mimePart {
  93. /**
  94. * The encoding type of this part
  95. * @var string
  96. */
  97. var $_encoding;
  98. /**
  99. * An array of subparts
  100. * @var array
  101. */
  102. var $_subparts;
  103. /**
  104. * The output of this part after being built
  105. * @var string
  106. */
  107. var $_encoded;
  108. /**
  109. * Headers for this part
  110. * @var array
  111. */
  112. var $_headers;
  113. /**
  114. * The body of this part (not encoded)
  115. * @var string
  116. */
  117. var $_body;
  118. /**
  119. * Constructor.
  120. *
  121. * Sets up the object.
  122. *
  123. * @param $body - The body of the mime part if any.
  124. * @param $params - An associative array of parameters:
  125. * content_type - The content type for this part eg multipart/mixed
  126. * encoding - The encoding to use, 7bit, 8bit, base64, or quoted-printable
  127. * cid - Content ID to apply
  128. * disposition - Content disposition, inline or attachment
  129. * dfilename - Optional filename parameter for content disposition
  130. * description - Content description
  131. * charset - Character set to use
  132. * @access public
  133. */
  134. function Mail_mimePart($body = '', $params = array())
  135. {
  136. if (!defined('MAIL_MIMEPART_CRLF')) {
  137. define('MAIL_MIMEPART_CRLF', defined('MAIL_MIME_CRLF') ? MAIL_MIME_CRLF : "\r\n", TRUE);
  138. }
  139. foreach ($params as $key => $value) {
  140. switch ($key) {
  141. case 'content_type':
  142. $headers['Content-Type'] = $value . (isset($charset) ? '; charset="' . $charset . '"' : '');
  143. break;
  144. case 'encoding':
  145. $this->_encoding = $value;
  146. $headers['Content-Transfer-Encoding'] = $value;
  147. break;
  148. case 'cid':
  149. $headers['Content-ID'] = '<' . $value . '>';
  150. break;
  151. case 'disposition':
  152. $headers['Content-Disposition'] = $value . (isset($dfilename) ? '; filename="' . $dfilename . '"' : '');
  153. break;
  154. case 'dfilename':
  155. if (isset($headers['Content-Disposition'])) {
  156. $headers['Content-Disposition'] .= '; filename="' . $value . '"';
  157. } else {
  158. $dfilename = $value;
  159. }
  160. break;
  161. case 'description':
  162. $headers['Content-Description'] = $value;
  163. break;
  164. case 'charset':
  165. if (isset($headers['Content-Type'])) {
  166. $headers['Content-Type'] .= '; charset="' . $value . '"';
  167. } else {
  168. $charset = $value;
  169. }
  170. break;
  171. }
  172. }
  173. // Default content-type
  174. if (!isset($headers['Content-Type'])) {
  175. $headers['Content-Type'] = 'text/plain';
  176. }
  177. //Default encoding
  178. if (!isset($this->_encoding)) {
  179. $this->_encoding = '7bit';
  180. }
  181. // Assign stuff to member variables
  182. $this->_encoded = array();
  183. $this->_headers = $headers;
  184. $this->_body = $body;
  185. }
  186. /**
  187. * encode()
  188. *
  189. * Encodes and returns the email. Also stores
  190. * it in the encoded member variable
  191. *
  192. * @return An associative array containing two elements,
  193. * body and headers. The headers element is itself
  194. * an indexed array.
  195. * @access public
  196. */
  197. function encode()
  198. {
  199. $encoded =& $this->_encoded;
  200. if (!empty($this->_subparts)) {
  201. srand((double)microtime()*1000000);
  202. $boundary = '=_' . md5(rand() . microtime());
  203. $this->_headers['Content-Type'] .= ';' . MAIL_MIMEPART_CRLF . "\t" . 'boundary="' . $boundary . '"';
  204. // Add body parts to $subparts
  205. for ($i = 0; $i < count($this->_subparts); $i++) {
  206. $headers = array();
  207. $tmp = $this->_subparts[$i]->encode();
  208. foreach ($tmp['headers'] as $key => $value) {
  209. $headers[] = $key . ': ' . $value;
  210. }
  211. $subparts[] = implode(MAIL_MIMEPART_CRLF, $headers) . MAIL_MIMEPART_CRLF . MAIL_MIMEPART_CRLF . $tmp['body'];
  212. }
  213. $encoded['body'] = '--' . $boundary . MAIL_MIMEPART_CRLF .
  214. implode('--' . $boundary . MAIL_MIMEPART_CRLF, $subparts) .
  215. '--' . $boundary.'--' . MAIL_MIMEPART_CRLF;
  216. } else {
  217. $encoded['body'] = $this->_getEncodedData($this->_body, $this->_encoding) . MAIL_MIMEPART_CRLF;
  218. }
  219. // Add headers to $encoded
  220. $encoded['headers'] =& $this->_headers;
  221. return $encoded;
  222. }
  223. /**
  224. * &addSubPart()
  225. *
  226. * Adds a subpart to current mime part and returns
  227. * a reference to it
  228. *
  229. * @param $body The body of the subpart, if any.
  230. * @param $params The parameters for the subpart, same
  231. * as the $params argument for constructor.
  232. * @return A reference to the part you just added. It is
  233. * crucial if using multipart/* in your subparts that
  234. * you use =& in your script when calling this function,
  235. * otherwise you will not be able to add further subparts.
  236. * @access public
  237. */
  238. function &addSubPart($body, $params)
  239. {
  240. $this->_subparts[] = new Mail_mimePart($body, $params);
  241. return $this->_subparts[count($this->_subparts) - 1];
  242. }
  243. /**
  244. * _getEncodedData()
  245. *
  246. * Returns encoded data based upon encoding passed to it
  247. *
  248. * @param $data The data to encode.
  249. * @param $encoding The encoding type to use, 7bit, base64,
  250. * or quoted-printable.
  251. * @access private
  252. */
  253. function _getEncodedData($data, $encoding)
  254. {
  255. switch ($encoding) {
  256. case '8bit':
  257. case '7bit':
  258. return $data;
  259. break;
  260. case 'quoted-printable':
  261. return $this->_quotedPrintableEncode($data);
  262. break;
  263. case 'base64':
  264. return rtrim(chunk_split(base64_encode($data), 76, MAIL_MIMEPART_CRLF));
  265. break;
  266. default:
  267. return $data;
  268. }
  269. }
  270. /**
  271. * quoteadPrintableEncode()
  272. *
  273. * Encodes data to quoted-printable standard.
  274. *
  275. * @param $input The data to encode
  276. * @param $line_max Optional max line length. Should
  277. * not be more than 76 chars
  278. *
  279. * @access private
  280. */
  281. function _quotedPrintableEncode($input , $line_max = 76)
  282. {
  283. $lines = preg_split("/\r?\n/", $input);
  284. $eol = MAIL_MIMEPART_CRLF;
  285. $escape = '=';
  286. $output = '';
  287. while(list(, $line) = each($lines)){
  288. $linlen = strlen($line);
  289. $newline = '';
  290. for ($i = 0; $i < $linlen; $i++) {
  291. $char = substr($line, $i, 1);
  292. $dec = ord($char);
  293. if (($dec == 32) AND ($i == ($linlen - 1))){ // convert space at eol only
  294. $char = '=20';
  295. } elseif(($dec == 9) AND ($i == ($linlen - 1))) { // convert tab at eol only
  296. $char = '=09';
  297. } elseif($dec == 9) {
  298. ; // Do nothing if a tab.
  299. } elseif(($dec == 61) OR ($dec < 32 ) OR ($dec > 126)) {
  300. $char = $escape . strtoupper(sprintf('%02s', dechex($dec)));
  301. }
  302. if ((strlen($newline) + strlen($char)) >= $line_max) { // MAIL_MIMEPART_CRLF is not counted
  303. $output .= $newline . $escape . $eol; // soft line break; " =\r\n" is okay
  304. $newline = '';
  305. }
  306. $newline .= $char;
  307. } // end of for
  308. $output .= $newline . $eol;
  309. }
  310. $output = substr($output, 0, -1 * strlen($eol)); // Don't want last crlf
  311. return $output;
  312. }
  313. } // End of class
  314. ?>