PageRenderTime 52ms CodeModel.GetById 22ms RepoModel.GetById 1ms app.codeStats 0ms

/3.0/modules/ecard/lib/mime.php

http://github.com/gallery/gallery3-contrib
PHP | 912 lines | 474 code | 58 blank | 380 comment | 73 complexity | 8c6be17210296a8e3696ab0b5239cd31 MD5 | raw file
Possible License(s): GPL-3.0, GPL-2.0, LGPL-2.1
  1. <?php
  2. /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
  3. // +-----------------------------------------------------------------------+
  4. // | Copyright (c) 2002-2003 Richard Heyes |
  5. // | Copyright (c) 2003-2005 The PHP Group |
  6. // | All rights reserved. |
  7. // | |
  8. // | Redistribution and use in source and binary forms, with or without |
  9. // | modification, are permitted provided that the following conditions |
  10. // | are met: |
  11. // | |
  12. // | o Redistributions of source code must retain the above copyright |
  13. // | notice, this list of conditions and the following disclaimer. |
  14. // | o Redistributions in binary form must reproduce the above copyright |
  15. // | notice, this list of conditions and the following disclaimer in the |
  16. // | documentation and/or other materials provided with the distribution.|
  17. // | o The names of the authors may not be used to endorse or promote |
  18. // | products derived from this software without specific prior written |
  19. // | permission. |
  20. // | |
  21. // | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
  22. // | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
  23. // | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
  24. // | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
  25. // | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
  26. // | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
  27. // | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
  28. // | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
  29. // | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
  30. // | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
  31. // | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
  32. // | |
  33. // +-----------------------------------------------------------------------+
  34. // | Author: Richard Heyes <richard@phpguru.org> |
  35. // | Tomas V.V.Cox <cox@idecnet.com> (port to PEAR) |
  36. // +-----------------------------------------------------------------------+
  37. //
  38. if (!class_exists('Mail_mimePart')) {
  39. require_once(MODPATH . "ecard/lib/mimePart.php");
  40. }
  41. if (class_exists('Mail_mime')) return;
  42. /**
  43. * Mime mail composer class. Can handle: text and html bodies, embedded html
  44. * images and attachments.
  45. * Documentation and examples of this class are avaible here:
  46. * http://pear.php.net/manual/
  47. *
  48. * @notes This class is based on HTML Mime Mail class from
  49. * Richard Heyes <richard@phpguru.org> which was based also
  50. * in the mime_mail.class by Tobias Ratschiller <tobias@dnet.it> and
  51. * Sascha Schumann <sascha@schumann.cx>
  52. *
  53. * @author Richard Heyes <richard.heyes@heyes-computing.net>
  54. * @author Tomas V.V.Cox <cox@idecnet.com>
  55. * @package Mail
  56. * @access public
  57. */
  58. class Mail_mime
  59. {
  60. /**
  61. * Contains the plain text part of the email
  62. * @var string
  63. */
  64. var $_txtbody;
  65. /**
  66. * Contains the html part of the email
  67. * @var string
  68. */
  69. var $_htmlbody;
  70. /**
  71. * contains the mime encoded text
  72. * @var string
  73. */
  74. var $_mime;
  75. /**
  76. * contains the multipart content
  77. * @var string
  78. */
  79. var $_multipart;
  80. /**
  81. * list of the attached images
  82. * @var array
  83. */
  84. var $_html_images = array();
  85. /**
  86. * list of the attachements
  87. * @var array
  88. */
  89. var $_parts = array();
  90. /**
  91. * Build parameters
  92. * @var array
  93. */
  94. var $_build_params = array();
  95. /**
  96. * Headers for the mail
  97. * @var array
  98. */
  99. var $_headers = array();
  100. /**
  101. * End Of Line sequence (for serialize)
  102. * @var string
  103. */
  104. var $_eol;
  105. /**
  106. * Constructor function
  107. *
  108. * @access public
  109. */
  110. function Mail_mime($crlf = "\r\n")
  111. {
  112. $this->_setEOL($crlf);
  113. $this->_build_params = array(
  114. 'head_encoding' => 'quoted-printable',
  115. 'text_encoding' => '7bit',
  116. 'html_encoding' => 'quoted-printable',
  117. '7bit_wrap' => 998,
  118. 'html_charset' => 'ISO-8859-1',
  119. 'text_charset' => 'ISO-8859-1',
  120. 'head_charset' => 'ISO-8859-1'
  121. );
  122. }
  123. /**
  124. * Wakeup (unserialize) - re-sets EOL constant
  125. *
  126. * @access private
  127. */
  128. function __wakeup()
  129. {
  130. $this->_setEOL($this->_eol);
  131. }
  132. /**
  133. * Accessor function to set the body text. Body text is used if
  134. * it's not an html mail being sent or else is used to fill the
  135. * text/plain part that emails clients who don't support
  136. * html should show.
  137. *
  138. * @param string $data Either a string or
  139. * the file name with the contents
  140. * @param bool $isfile If true the first param should be treated
  141. * as a file name, else as a string (default)
  142. * @param bool $append If true the text or file is appended to
  143. * the existing body, else the old body is
  144. * overwritten
  145. * @return mixed true on success or PEAR_Error object
  146. * @access public
  147. */
  148. function setTXTBody($data, $isfile = false, $append = false)
  149. {
  150. if (!$isfile) {
  151. if (!$append) {
  152. $this->_txtbody = $data;
  153. } else {
  154. $this->_txtbody .= $data;
  155. }
  156. } else {
  157. $cont = $this->_file2str($data);
  158. if (!isset($cont) /*PEAR::isError($cont)*/) {
  159. return $cont;
  160. }
  161. if (!$append) {
  162. $this->_txtbody = $cont;
  163. } else {
  164. $this->_txtbody .= $cont;
  165. }
  166. }
  167. return true;
  168. }
  169. /**
  170. * Adds a html part to the mail
  171. *
  172. * @param string $data Either a string or the file name with the
  173. * contents
  174. * @param bool $isfile If true the first param should be treated
  175. * as a file name, else as a string (default)
  176. * @return mixed true on success or PEAR_Error object
  177. * @access public
  178. */
  179. function setHTMLBody($data, $isfile = false)
  180. {
  181. if (!$isfile) {
  182. $this->_htmlbody = $data;
  183. } else {
  184. $cont = $this->_file2str($data);
  185. if (!isset($cont) /*PEAR::isError($cont)*/) {
  186. return $cont;
  187. }
  188. $this->_htmlbody = $cont;
  189. }
  190. return true;
  191. }
  192. /**
  193. * Adds an image to the list of embedded images.
  194. *
  195. * @param string $file The image file name OR image data itself
  196. * @param string $c_type The content type
  197. * @param string $name The filename of the image.
  198. * Only use if $file is the image data
  199. * @param bool $isfilename Whether $file is a filename or not
  200. * Defaults to true
  201. * @return mixed true on success or PEAR_Error object
  202. * @access public
  203. */
  204. function addHTMLImage($file, $c_type='application/octet-stream',
  205. $name = '', $isfilename = true)
  206. {
  207. $filedata = ($isfilename === true) ? $this->_file2str($file)
  208. : $file;
  209. if ($isfilename === true) {
  210. $filename = ($name == '' ? $file : $name);
  211. } else {
  212. $filename = $name;
  213. }
  214. if (!isset($filedata) /*PEAR::isError($filedata)*/) {
  215. return $filedata;
  216. }
  217. $this->_html_images[] = array(
  218. 'body' => $filedata,
  219. 'name' => $filename,
  220. 'c_type' => $c_type,
  221. 'cid' => md5(uniqid(time()))
  222. );
  223. return true;
  224. }
  225. /**
  226. * Adds a file to the list of attachments.
  227. *
  228. * @param string $file The file name of the file to attach
  229. * OR the file contents itself
  230. * @param string $c_type The content type
  231. * @param string $name The filename of the attachment
  232. * Only use if $file is the contents
  233. * @param bool $isFilename Whether $file is a filename or not
  234. * Defaults to true
  235. * @param string $encoding The type of encoding to use.
  236. * Defaults to base64.
  237. * Possible values: 7bit, 8bit, base64,
  238. * or quoted-printable.
  239. * @param string $disposition The content-disposition of this file
  240. * Defaults to attachment.
  241. * Possible values: attachment, inline.
  242. * @param string $charset The character set used in the filename
  243. * of this attachment.
  244. * @return mixed true on success or PEAR_Error object
  245. * @access public
  246. */
  247. function addAttachment($file, $c_type = 'application/octet-stream',
  248. $name = '', $isfilename = true,
  249. $encoding = 'base64',
  250. $disposition = 'attachment', $charset = '')
  251. {
  252. $filedata = ($isfilename === true) ? $this->_file2str($file)
  253. : $file;
  254. if ($isfilename === true) {
  255. // Force the name the user supplied, otherwise use $file
  256. $filename = (!empty($name)) ? $name : $file;
  257. } else {
  258. $filename = $name;
  259. }
  260. if (empty($filename)) {
  261. $err = null; /*PEAR::raiseError(
  262. "The supplied filename for the attachment can't be empty"
  263. );*/
  264. return $err;
  265. }
  266. $filename = basename($filename);
  267. if (!isset($filedata) /*PEAR::isError($filedata)*/) {
  268. return $filedata;
  269. }
  270. $this->_parts[] = array(
  271. 'body' => $filedata,
  272. 'name' => $filename,
  273. 'c_type' => $c_type,
  274. 'encoding' => $encoding,
  275. 'charset' => $charset,
  276. 'disposition' => $disposition
  277. );
  278. return true;
  279. }
  280. /**
  281. * Get the contents of the given file name as string
  282. *
  283. * @param string $file_name path of file to process
  284. * @return string contents of $file_name
  285. * @access private
  286. */
  287. function &_file2str($file_name)
  288. {
  289. if (!is_readable($file_name)) {
  290. $err = null; //PEAR::raiseError('File is not readable ' . $file_name);
  291. return $err;
  292. }
  293. if (!$fd = fopen($file_name, 'rb')) {
  294. $err = null; //PEAR::raiseError('Could not open ' . $file_name);
  295. return $err;
  296. }
  297. $filesize = filesize($file_name);
  298. if ($filesize == 0){
  299. $cont = "";
  300. }else{
  301. if ($magic_quote_setting = get_magic_quotes_runtime()){
  302. @set_magic_quotes_runtime(0);
  303. }
  304. $cont = fread($fd, $filesize);
  305. if ($magic_quote_setting){
  306. @set_magic_quotes_runtime($magic_quote_setting);
  307. }
  308. }
  309. fclose($fd);
  310. return $cont;
  311. }
  312. /**
  313. * Adds a text subpart to the mimePart object and
  314. * returns it during the build process.
  315. *
  316. * @param mixed The object to add the part to, or
  317. * null if a new object is to be created.
  318. * @param string The text to add.
  319. * @return object The text mimePart object
  320. * @access private
  321. */
  322. function &_addTextPart(&$obj, $text)
  323. {
  324. $params['content_type'] = 'text/plain';
  325. $params['encoding'] = $this->_build_params['text_encoding'];
  326. $params['charset'] = $this->_build_params['text_charset'];
  327. if (is_object($obj)) {
  328. $ret = $obj->addSubpart($text, $params);
  329. return $ret;
  330. } else {
  331. $ret = new Mail_mimePart($text, $params);
  332. return $ret;
  333. }
  334. }
  335. /**
  336. * Adds a html subpart to the mimePart object and
  337. * returns it during the build process.
  338. *
  339. * @param mixed The object to add the part to, or
  340. * null if a new object is to be created.
  341. * @return object The html mimePart object
  342. * @access private
  343. */
  344. function &_addHtmlPart(&$obj)
  345. {
  346. $params['content_type'] = 'text/html';
  347. $params['encoding'] = $this->_build_params['html_encoding'];
  348. $params['charset'] = $this->_build_params['html_charset'];
  349. if (is_object($obj)) {
  350. $ret = $obj->addSubpart($this->_htmlbody, $params);
  351. return $ret;
  352. } else {
  353. $ret = new Mail_mimePart($this->_htmlbody, $params);
  354. return $ret;
  355. }
  356. }
  357. /**
  358. * Creates a new mimePart object, using multipart/mixed as
  359. * the initial content-type and returns it during the
  360. * build process.
  361. *
  362. * @return object The multipart/mixed mimePart object
  363. * @access private
  364. */
  365. function &_addMixedPart()
  366. {
  367. $params['content_type'] = 'multipart/mixed';
  368. $ret = new Mail_mimePart('', $params);
  369. return $ret;
  370. }
  371. /**
  372. * Adds a multipart/alternative part to a mimePart
  373. * object (or creates one), and returns it during
  374. * the build process.
  375. *
  376. * @param mixed The object to add the part to, or
  377. * null if a new object is to be created.
  378. * @return object The multipart/mixed mimePart object
  379. * @access private
  380. */
  381. function &_addAlternativePart(&$obj)
  382. {
  383. $params['content_type'] = 'multipart/alternative';
  384. if (is_object($obj)) {
  385. return $obj->addSubpart('', $params);
  386. } else {
  387. $ret = new Mail_mimePart('', $params);
  388. return $ret;
  389. }
  390. }
  391. /**
  392. * Adds a multipart/related part to a mimePart
  393. * object (or creates one), and returns it during
  394. * the build process.
  395. *
  396. * @param mixed The object to add the part to, or
  397. * null if a new object is to be created
  398. * @return object The multipart/mixed mimePart object
  399. * @access private
  400. */
  401. function &_addRelatedPart(&$obj)
  402. {
  403. $params['content_type'] = 'multipart/related';
  404. if (is_object($obj)) {
  405. return $obj->addSubpart('', $params);
  406. } else {
  407. $ret = new Mail_mimePart('', $params);
  408. return $ret;
  409. }
  410. }
  411. /**
  412. * Adds an html image subpart to a mimePart object
  413. * and returns it during the build process.
  414. *
  415. * @param object The mimePart to add the image to
  416. * @param array The image information
  417. * @return object The image mimePart object
  418. * @access private
  419. */
  420. function &_addHtmlImagePart(&$obj, $value)
  421. {
  422. $params['content_type'] = $value['c_type'] . '; ' .
  423. 'name="' . $value['name'] . '"';
  424. $params['encoding'] = 'base64';
  425. $params['disposition'] = 'inline';
  426. $params['dfilename'] = $value['name'];
  427. $params['cid'] = $value['cid'];
  428. $ret = $obj->addSubpart($value['body'], $params);
  429. return $ret;
  430. }
  431. /**
  432. * Adds an attachment subpart to a mimePart object
  433. * and returns it during the build process.
  434. *
  435. * @param object The mimePart to add the image to
  436. * @param array The attachment information
  437. * @return object The image mimePart object
  438. * @access private
  439. */
  440. function &_addAttachmentPart(&$obj, $value)
  441. {
  442. $params['dfilename'] = $value['name'];
  443. $params['encoding'] = $value['encoding'];
  444. if ($value['disposition'] != "inline") {
  445. $fname = array("fname" => $value['name']);
  446. $fname_enc = $this->_encodeHeaders($fname);
  447. $params['dfilename'] = $fname_enc['fname'];
  448. }
  449. if ($value['charset']) {
  450. $params['charset'] = $value['charset'];
  451. }
  452. $params['content_type'] = $value['c_type'] . '; ' .
  453. 'name="' . $params['dfilename'] . '"';
  454. $params['disposition'] = isset($value['disposition']) ?
  455. $value['disposition'] : 'attachment';
  456. $ret = $obj->addSubpart($value['body'], $params);
  457. return $ret;
  458. }
  459. /**
  460. * Returns the complete e-mail, ready to send using an alternative
  461. * mail delivery method. Note that only the mailpart that is made
  462. * with Mail_Mime is created. This means that,
  463. * YOU WILL HAVE NO TO: HEADERS UNLESS YOU SET IT YOURSELF
  464. * using the $xtra_headers parameter!
  465. *
  466. * @param string $separation The separation etween these two parts.
  467. * @param array $build_params The Build parameters passed to the
  468. * &get() function. See &get for more info.
  469. * @param array $xtra_headers The extra headers that should be passed
  470. * to the &headers() function.
  471. * See that function for more info.
  472. * @param bool $overwrite Overwrite the existing headers with new.
  473. * @return string The complete e-mail.
  474. * @access public
  475. */
  476. function getMessage($separation = null, $build_params = null, $xtra_headers = null, $overwrite = false)
  477. {
  478. if ($separation === null)
  479. {
  480. $separation = MAIL_MIME_CRLF;
  481. }
  482. $body = $this->get($build_params);
  483. $head = $this->txtHeaders($xtra_headers, $overwrite);
  484. $mail = $head . $separation . $body;
  485. return $mail;
  486. }
  487. /**
  488. * Builds the multipart message from the list ($this->_parts) and
  489. * returns the mime content.
  490. *
  491. * @param array Build parameters that change the way the email
  492. * is built. Should be associative. Can contain:
  493. * head_encoding - What encoding to use for the headers.
  494. * Options: quoted-printable or base64
  495. * Default is quoted-printable
  496. * text_encoding - What encoding to use for plain text
  497. * Options: 7bit, 8bit, base64, or quoted-printable
  498. * Default is 7bit
  499. * html_encoding - What encoding to use for html
  500. * Options: 7bit, 8bit, base64, or quoted-printable
  501. * Default is quoted-printable
  502. * 7bit_wrap - Number of characters before text is
  503. * wrapped in 7bit encoding
  504. * Default is 998
  505. * html_charset - The character set to use for html.
  506. * Default is iso-8859-1
  507. * text_charset - The character set to use for text.
  508. * Default is iso-8859-1
  509. * head_charset - The character set to use for headers.
  510. * Default is iso-8859-1
  511. * @return string The mime content
  512. * @access public
  513. */
  514. function &get($build_params = null)
  515. {
  516. if (isset($build_params)) {
  517. while (list($key, $value) = each($build_params)) {
  518. $this->_build_params[$key] = $value;
  519. }
  520. }
  521. if (!empty($this->_html_images) AND isset($this->_htmlbody)) {
  522. foreach ($this->_html_images as $key => $value) {
  523. $regex = array();
  524. $regex[] = '#(\s)((?i)src|background|href(?-i))\s*=\s*(["\']?)' .
  525. preg_quote($value['name'], '#') . '\3#';
  526. $regex[] = '#(?i)url(?-i)\(\s*(["\']?)' .
  527. preg_quote($value['name'], '#') . '\1\s*\)#';
  528. $rep = array();
  529. $rep[] = '\1\2=\3cid:' . $value['cid'] .'\3';
  530. $rep[] = 'url(\1cid:' . $value['cid'] . '\2)';
  531. $this->_htmlbody = preg_replace($regex, $rep,
  532. $this->_htmlbody
  533. );
  534. $this->_html_images[$key]['name'] = basename($this->_html_images[$key]['name']);
  535. }
  536. }
  537. $null = null;
  538. $attachments = !empty($this->_parts) ? true : false;
  539. $html_images = !empty($this->_html_images) ? true : false;
  540. $html = !empty($this->_htmlbody) ? true : false;
  541. $text = (!$html AND !empty($this->_txtbody)) ? true : false;
  542. switch (true) {
  543. case $text AND !$attachments:
  544. $message =& $this->_addTextPart($null, $this->_txtbody);
  545. break;
  546. case !$text AND !$html AND $attachments:
  547. $message =& $this->_addMixedPart();
  548. for ($i = 0; $i < count($this->_parts); $i++) {
  549. $this->_addAttachmentPart($message, $this->_parts[$i]);
  550. }
  551. break;
  552. case $text AND $attachments:
  553. $message =& $this->_addMixedPart();
  554. $this->_addTextPart($message, $this->_txtbody);
  555. for ($i = 0; $i < count($this->_parts); $i++) {
  556. $this->_addAttachmentPart($message, $this->_parts[$i]);
  557. }
  558. break;
  559. case $html AND !$attachments AND !$html_images:
  560. if (isset($this->_txtbody)) {
  561. $message =& $this->_addAlternativePart($null);
  562. $this->_addTextPart($message, $this->_txtbody);
  563. $this->_addHtmlPart($message);
  564. } else {
  565. $message =& $this->_addHtmlPart($null);
  566. }
  567. break;
  568. case $html AND !$attachments AND $html_images:
  569. if (isset($this->_txtbody)) {
  570. $message =& $this->_addAlternativePart($null);
  571. $this->_addTextPart($message, $this->_txtbody);
  572. $related =& $this->_addRelatedPart($message);
  573. } else {
  574. $message =& $this->_addRelatedPart($null);
  575. $related =& $message;
  576. }
  577. $this->_addHtmlPart($related);
  578. for ($i = 0; $i < count($this->_html_images); $i++) {
  579. $this->_addHtmlImagePart($related, $this->_html_images[$i]);
  580. }
  581. break;
  582. case $html AND $attachments AND !$html_images:
  583. $message =& $this->_addMixedPart();
  584. if (isset($this->_txtbody)) {
  585. $alt =& $this->_addAlternativePart($message);
  586. $this->_addTextPart($alt, $this->_txtbody);
  587. $this->_addHtmlPart($alt);
  588. } else {
  589. $this->_addHtmlPart($message);
  590. }
  591. for ($i = 0; $i < count($this->_parts); $i++) {
  592. $this->_addAttachmentPart($message, $this->_parts[$i]);
  593. }
  594. break;
  595. case $html AND $attachments AND $html_images:
  596. $message =& $this->_addMixedPart();
  597. if (isset($this->_txtbody)) {
  598. $alt =& $this->_addAlternativePart($message);
  599. $this->_addTextPart($alt, $this->_txtbody);
  600. $rel =& $this->_addRelatedPart($alt);
  601. } else {
  602. $rel =& $this->_addRelatedPart($message);
  603. }
  604. $this->_addHtmlPart($rel);
  605. for ($i = 0; $i < count($this->_html_images); $i++) {
  606. $this->_addHtmlImagePart($rel, $this->_html_images[$i]);
  607. }
  608. for ($i = 0; $i < count($this->_parts); $i++) {
  609. $this->_addAttachmentPart($message, $this->_parts[$i]);
  610. }
  611. break;
  612. }
  613. if (isset($message)) {
  614. $output = $message->encode();
  615. $this->_headers = array_merge($this->_headers,
  616. $output['headers']);
  617. $body = $output['body'];
  618. return $body;
  619. } else {
  620. $ret = false;
  621. return $ret;
  622. }
  623. }
  624. /**
  625. * Returns an array with the headers needed to prepend to the email
  626. * (MIME-Version and Content-Type). Format of argument is:
  627. * $array['header-name'] = 'header-value';
  628. *
  629. * @param array $xtra_headers Assoc array with any extra headers.
  630. * Optional.
  631. * @param bool $overwrite Overwrite already existing headers.
  632. * @return array Assoc array with the mime headers
  633. * @access public
  634. */
  635. function &headers($xtra_headers = null, $overwrite = false)
  636. {
  637. // Content-Type header should already be present,
  638. // So just add mime version header
  639. $headers['MIME-Version'] = '1.0';
  640. if (isset($xtra_headers)) {
  641. $headers = array_merge($headers, $xtra_headers);
  642. }
  643. if ($overwrite){
  644. $this->_headers = array_merge($this->_headers, $headers);
  645. }else{
  646. $this->_headers = array_merge($headers, $this->_headers);
  647. }
  648. $encodedHeaders = $this->_encodeHeaders($this->_headers);
  649. return $encodedHeaders;
  650. }
  651. /**
  652. * Get the text version of the headers
  653. * (usefull if you want to use the PHP mail() function)
  654. *
  655. * @param array $xtra_headers Assoc array with any extra headers.
  656. * Optional.
  657. * @param bool $overwrite Overwrite the existing heaers with new.
  658. * @return string Plain text headers
  659. * @access public
  660. */
  661. function txtHeaders($xtra_headers = null, $overwrite = false)
  662. {
  663. $headers = $this->headers($xtra_headers, $overwrite);
  664. $ret = '';
  665. foreach ($headers as $key => $val) {
  666. $ret .= "$key: $val" . MAIL_MIME_CRLF;
  667. }
  668. return $ret;
  669. }
  670. /**
  671. * Sets the Subject header
  672. *
  673. * @param string $subject String to set the subject to
  674. * access public
  675. */
  676. function setSubject($subject)
  677. {
  678. $this->_headers['Subject'] = $subject;
  679. }
  680. /**
  681. * Set an email to the From (the sender) header
  682. *
  683. * @param string $email The email direction to add
  684. * @access public
  685. */
  686. function setFrom($email)
  687. {
  688. $this->_headers['From'] = $email;
  689. }
  690. /**
  691. * Add an email to the Cc (carbon copy) header
  692. * (multiple calls to this method are allowed)
  693. *
  694. * @param string $email The email direction to add
  695. * @access public
  696. */
  697. function addCc($email)
  698. {
  699. if (isset($this->_headers['Cc'])) {
  700. $this->_headers['Cc'] .= ", $email";
  701. } else {
  702. $this->_headers['Cc'] = $email;
  703. }
  704. }
  705. /**
  706. * Add an email to the Bcc (blank carbon copy) header
  707. * (multiple calls to this method are allowed)
  708. *
  709. * @param string $email The email direction to add
  710. * @access public
  711. */
  712. function addBcc($email)
  713. {
  714. if (isset($this->_headers['Bcc'])) {
  715. $this->_headers['Bcc'] .= ", $email";
  716. } else {
  717. $this->_headers['Bcc'] = $email;
  718. }
  719. }
  720. /**
  721. * Since the PHP send function requires you to specifiy
  722. * recipients (To: header) separately from the other
  723. * headers, the To: header is not properly encoded.
  724. * To fix this, you can use this public method to
  725. * encode your recipients before sending to the send
  726. * function
  727. *
  728. * @param string $recipients A comma-delimited list of recipients
  729. * @return string Encoded data
  730. * @access public
  731. */
  732. function encodeRecipients($recipients)
  733. {
  734. $input = array("To" => $recipients);
  735. $retval = $this->_encodeHeaders($input);
  736. return $retval["To"] ;
  737. }
  738. /**
  739. * Encodes a header as per RFC2047
  740. *
  741. * @param array $input The header data to encode
  742. * @return array Encoded data
  743. * @access private
  744. */
  745. function _encodeHeaders($input)
  746. {
  747. foreach ($input as $hdr_name => $hdr_value) {
  748. if (function_exists('iconv_mime_encode') && preg_match('#[\x80-\xFF]{1}#', $hdr_value)){
  749. $imePref = array();
  750. if ($this->_build_params['head_encoding'] == 'base64'){
  751. $imePrefs['scheme'] = 'B';
  752. }else{
  753. $imePrefs['scheme'] = 'Q';
  754. }
  755. $imePrefs['input-charset'] = $this->_build_params['head_charset'];
  756. $imePrefs['output-charset'] = $this->_build_params['head_charset'];
  757. $hdr_value = iconv_mime_encode($hdr_name, $hdr_value, $imePrefs);
  758. $hdr_value = preg_replace("#^{$hdr_name}\:\ #", "", $hdr_value);
  759. }elseif (preg_match('#[\x80-\xFF]{1}#', $hdr_value)){
  760. //This header contains non ASCII chars and should be encoded.
  761. switch ($this->_build_params['head_encoding']) {
  762. case 'base64':
  763. //Base64 encoding has been selected.
  764. //Generate the header using the specified params and dynamicly
  765. //determine the maximum length of such strings.
  766. //75 is the value specified in the RFC. The -2 is there so
  767. //the later regexp doesn't break any of the translated chars.
  768. $prefix = '=?' . $this->_build_params['head_charset'] . '?B?';
  769. $suffix = '?=';
  770. $maxLength = 75 - strlen($prefix . $suffix) - 2;
  771. $maxLength1stLine = $maxLength - strlen($hdr_name);
  772. //Base64 encode the entire string
  773. $hdr_value = base64_encode($hdr_value);
  774. //This regexp will break base64-encoded text at every
  775. //$maxLength but will not break any encoded letters.
  776. $reg1st = "|.{0,$maxLength1stLine}[^\=][^\=]|";
  777. $reg2nd = "|.{0,$maxLength}[^\=][^\=]|";
  778. break;
  779. case 'quoted-printable':
  780. default:
  781. //quoted-printable encoding has been selected
  782. //Generate the header using the specified params and dynamicly
  783. //determine the maximum length of such strings.
  784. //75 is the value specified in the RFC. The -2 is there so
  785. //the later regexp doesn't break any of the translated chars.
  786. $prefix = '=?' . $this->_build_params['head_charset'] . '?Q?';
  787. $suffix = '?=';
  788. $maxLength = 75 - strlen($prefix . $suffix) - 2;
  789. $maxLength1stLine = $maxLength - strlen($hdr_name);
  790. //Replace all special characters used by the encoder.
  791. $search = array("=", "_", "?", " ");
  792. $replace = array("=3D", "=5F", "=3F", "_");
  793. $hdr_value = str_replace($search, $replace, $hdr_value);
  794. //Replace all extended characters (\x80-xFF) with their
  795. //ASCII values.
  796. $hdr_value = preg_replace(
  797. '#([\x80-\xFF])#e',
  798. '"=" . strtoupper(dechex(ord("\1")))',
  799. $hdr_value
  800. );
  801. //This regexp will break QP-encoded text at every $maxLength
  802. //but will not break any encoded letters.
  803. $reg1st = "|(.{0,$maxLength})[^\=]|";
  804. $reg2nd = "|(.{0,$maxLength})[^\=]|";
  805. break;
  806. }
  807. //Begin with the regexp for the first line.
  808. $reg = $reg1st;
  809. $output = "";
  810. while ($hdr_value) {
  811. //Split translated string at every $maxLength
  812. //But make sure not to break any translated chars.
  813. $found = preg_match($reg, $hdr_value, $matches);
  814. //After this first line, we need to use a different
  815. //regexp for the first line.
  816. $reg = $reg2nd;
  817. //Save the found part and encapsulate it in the
  818. //prefix & suffix. Then remove the part from the
  819. //$hdr_value variable.
  820. if ($found){
  821. $part = $matches[0];
  822. $hdr_value = substr($hdr_value, strlen($matches[0]));
  823. }else{
  824. $part = $hdr_value;
  825. $hdr_value = "";
  826. }
  827. //RFC 2047 specifies that any split header should be seperated
  828. //by a CRLF SPACE.
  829. if ($output){
  830. $output .= "\r\n ";
  831. }
  832. $output .= $prefix . $part . $suffix;
  833. }
  834. $hdr_value = $output;
  835. }
  836. $input[$hdr_name] = $hdr_value;
  837. }
  838. return $input;
  839. }
  840. /**
  841. * Set the object's end-of-line and define the constant if applicable
  842. *
  843. * @param string $eol End Of Line sequence
  844. * @access private
  845. */
  846. function _setEOL($eol)
  847. {
  848. $this->_eol = $eol;
  849. if (!defined('MAIL_MIME_CRLF')) {
  850. define('MAIL_MIME_CRLF', $this->_eol, true);
  851. }
  852. }
  853. } // End of class
  854. ?>