PageRenderTime 46ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/htdocs/includes/nusoap/lib/Mail/mime.php

https://bitbucket.org/speedealing/speedealing
PHP | 712 lines | 363 code | 45 blank | 304 comment | 56 complexity | 4253bc41b622aaeb59545793f6dcdb49 MD5 | raw file
Possible License(s): LGPL-3.0, LGPL-2.1, GPL-3.0, MIT
  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. require_once('PEAR.php');
  39. require_once('Mail/mimePart.php');
  40. /**
  41. * Mime mail composer class. Can handle: text and html bodies, embedded html
  42. * images and attachments.
  43. * Documentation and examples of this class are avaible here:
  44. * http://pear.php.net/manual/
  45. *
  46. * @notes This class is based on HTML Mime Mail class from
  47. * Richard Heyes <richard@phpguru.org> which was based also
  48. * in the mime_mail.class by Tobias Ratschiller <tobias@dnet.it> and
  49. * Sascha Schumann <sascha@schumann.cx>
  50. *
  51. * @author Richard Heyes <richard.heyes@heyes-computing.net>
  52. * @author Tomas V.V.Cox <cox@idecnet.com>
  53. * @package Mail
  54. * @access public
  55. */
  56. class Mail_mime
  57. {
  58. /**
  59. * Contains the plain text part of the email
  60. * @var string
  61. */
  62. var $_txtbody;
  63. /**
  64. * Contains the html part of the email
  65. * @var string
  66. */
  67. var $_htmlbody;
  68. /**
  69. * contains the mime encoded text
  70. * @var string
  71. */
  72. var $_mime;
  73. /**
  74. * contains the multipart content
  75. * @var string
  76. */
  77. var $_multipart;
  78. /**
  79. * list of the attached images
  80. * @var array
  81. */
  82. var $_html_images = array();
  83. /**
  84. * list of the attachements
  85. * @var array
  86. */
  87. var $_parts = array();
  88. /**
  89. * Build parameters
  90. * @var array
  91. */
  92. var $_build_params = array();
  93. /**
  94. * Headers for the mail
  95. * @var array
  96. */
  97. var $_headers = array();
  98. /**
  99. * End Of Line sequence (for serialize)
  100. * @var string
  101. */
  102. var $_eol;
  103. /**
  104. * Constructor function
  105. *
  106. * @access public
  107. */
  108. function Mail_mime($crlf = "\r\n")
  109. {
  110. $this->_setEOL($crlf);
  111. $this->_build_params = array(
  112. 'text_encoding' => '7bit',
  113. 'html_encoding' => 'quoted-printable',
  114. '7bit_wrap' => 998,
  115. 'html_charset' => 'ISO-8859-1',
  116. 'text_charset' => 'ISO-8859-1',
  117. 'head_charset' => 'ISO-8859-1'
  118. );
  119. }
  120. /**
  121. * Wakeup (unserialize) - re-sets EOL constant
  122. *
  123. * @access private
  124. */
  125. function __wakeup()
  126. {
  127. $this->_setEOL($this->_eol);
  128. }
  129. /**
  130. * Accessor function to set the body text. Body text is used if
  131. * it's not an html mail being sent or else is used to fill the
  132. * text/plain part that emails clients who don't support
  133. * html should show.
  134. *
  135. * @param string $data Either a string or
  136. * the file name with the contents
  137. * @param bool $isfile If true the first param should be treated
  138. * as a file name, else as a string (default)
  139. * @param bool $append If true the text or file is appended to
  140. * the existing body, else the old body is
  141. * overwritten
  142. * @return mixed true on success or PEAR_Error object
  143. * @access public
  144. */
  145. function setTXTBody($data, $isfile = false, $append = false)
  146. {
  147. if (!$isfile) {
  148. if (!$append) {
  149. $this->_txtbody = $data;
  150. } else {
  151. $this->_txtbody .= $data;
  152. }
  153. } else {
  154. $cont = $this->_file2str($data);
  155. if (PEAR::isError($cont)) {
  156. return $cont;
  157. }
  158. if (!$append) {
  159. $this->_txtbody = $cont;
  160. } else {
  161. $this->_txtbody .= $cont;
  162. }
  163. }
  164. return true;
  165. }
  166. /**
  167. * Adds a html part to the mail
  168. *
  169. * @param string $data Either a string or the file name with the
  170. * contents
  171. * @param bool $isfile If true the first param should be treated
  172. * as a file name, else as a string (default)
  173. * @return mixed true on success or PEAR_Error object
  174. * @access public
  175. */
  176. function setHTMLBody($data, $isfile = false)
  177. {
  178. if (!$isfile) {
  179. $this->_htmlbody = $data;
  180. } else {
  181. $cont = $this->_file2str($data);
  182. if (PEAR::isError($cont)) {
  183. return $cont;
  184. }
  185. $this->_htmlbody = $cont;
  186. }
  187. return true;
  188. }
  189. /**
  190. * Adds an image to the list of embedded images.
  191. *
  192. * @param string $file The image file name OR image data itself
  193. * @param string $c_type The content type
  194. * @param string $name The filename of the image.
  195. * Only use if $file is the image data
  196. * @param bool $isfilename Whether $file is a filename or not
  197. * Defaults to true
  198. * @return mixed true on success or PEAR_Error object
  199. * @access public
  200. */
  201. function addHTMLImage($file, $c_type='application/octet-stream',
  202. $name = '', $isfilename = true)
  203. {
  204. $filedata = ($isfilename === true) ? $this->_file2str($file)
  205. : $file;
  206. if ($isfilename === true) {
  207. $filename = ($name == '' ? basename($file) : basename($name));
  208. } else {
  209. $filename = basename($name);
  210. }
  211. if (PEAR::isError($filedata)) {
  212. return $filedata;
  213. }
  214. $this->_html_images[] = array(
  215. 'body' => $filedata,
  216. 'name' => $filename,
  217. 'c_type' => $c_type,
  218. 'cid' => md5(uniqid(time()))
  219. );
  220. return true;
  221. }
  222. /**
  223. * Adds a file to the list of attachments.
  224. *
  225. * @param string $file The file name of the file to attach
  226. * OR the file data itself
  227. * @param string $c_type The content type
  228. * @param string $name The filename of the attachment
  229. * Only use if $file is the file data
  230. * @param bool $isFilename Whether $file is a filename or not
  231. * Defaults to true
  232. * @return mixed true on success or PEAR_Error object
  233. * @access public
  234. */
  235. function addAttachment($file, $c_type = 'application/octet-stream',
  236. $name = '', $isfilename = true,
  237. $encoding = 'base64')
  238. {
  239. $filedata = ($isfilename === true) ? $this->_file2str($file)
  240. : $file;
  241. if ($isfilename === true) {
  242. // Force the name the user supplied, otherwise use $file
  243. $filename = (!empty($name)) ? $name : $file;
  244. } else {
  245. $filename = $name;
  246. }
  247. if (empty($filename)) {
  248. return PEAR::raiseError(
  249. 'The supplied filename for the attachment can\'t be empty'
  250. );
  251. }
  252. $filename = basename($filename);
  253. if (PEAR::isError($filedata)) {
  254. return $filedata;
  255. }
  256. $this->_parts[] = array(
  257. 'body' => $filedata,
  258. 'name' => $filename,
  259. 'c_type' => $c_type,
  260. 'encoding' => $encoding
  261. );
  262. return true;
  263. }
  264. /**
  265. * Get the contents of the given file name as string
  266. *
  267. * @param string $file_name path of file to process
  268. * @return string contents of $file_name
  269. * @access private
  270. */
  271. function &_file2str($file_name)
  272. {
  273. if (!is_readable($file_name)) {
  274. return PEAR::raiseError('File is not readable ' . $file_name);
  275. }
  276. if (!$fd = fopen($file_name, 'rb')) {
  277. return PEAR::raiseError('Could not open ' . $file_name);
  278. }
  279. $filesize = filesize($file_name);
  280. if ($filesize == 0){
  281. $cont = "";
  282. }else{
  283. $cont = fread($fd, $filesize);
  284. }
  285. fclose($fd);
  286. return $cont;
  287. }
  288. /**
  289. * Adds a text subpart to the mimePart object and
  290. * returns it during the build process.
  291. *
  292. * @param mixed The object to add the part to, or
  293. * null if a new object is to be created.
  294. * @param string The text to add.
  295. * @return object The text mimePart object
  296. * @access private
  297. */
  298. function &_addTextPart(&$obj, $text)
  299. {
  300. $params['content_type'] = 'text/plain';
  301. $params['encoding'] = $this->_build_params['text_encoding'];
  302. $params['charset'] = $this->_build_params['text_charset'];
  303. if (is_object($obj)) {
  304. return $obj->addSubpart($text, $params);
  305. } else {
  306. return new Mail_mimePart($text, $params);
  307. }
  308. }
  309. /**
  310. * Adds a html subpart to the mimePart object and
  311. * returns it during the build process.
  312. *
  313. * @param mixed The object to add the part to, or
  314. * null if a new object is to be created.
  315. * @return object The html mimePart object
  316. * @access private
  317. */
  318. function &_addHtmlPart(&$obj)
  319. {
  320. $params['content_type'] = 'text/html';
  321. $params['encoding'] = $this->_build_params['html_encoding'];
  322. $params['charset'] = $this->_build_params['html_charset'];
  323. if (is_object($obj)) {
  324. return $obj->addSubpart($this->_htmlbody, $params);
  325. } else {
  326. return new Mail_mimePart($this->_htmlbody, $params);
  327. }
  328. }
  329. /**
  330. * Creates a new mimePart object, using multipart/mixed as
  331. * the initial content-type and returns it during the
  332. * build process.
  333. *
  334. * @return object The multipart/mixed mimePart object
  335. * @access private
  336. */
  337. function &_addMixedPart()
  338. {
  339. $params['content_type'] = 'multipart/mixed';
  340. return new Mail_mimePart('', $params);
  341. }
  342. /**
  343. * Adds a multipart/alternative part to a mimePart
  344. * object (or creates one), and returns it during
  345. * the build process.
  346. *
  347. * @param mixed The object to add the part to, or
  348. * null if a new object is to be created.
  349. * @return object The multipart/mixed mimePart object
  350. * @access private
  351. */
  352. function &_addAlternativePart(&$obj)
  353. {
  354. $params['content_type'] = 'multipart/alternative';
  355. if (is_object($obj)) {
  356. return $obj->addSubpart('', $params);
  357. } else {
  358. return new Mail_mimePart('', $params);
  359. }
  360. }
  361. /**
  362. * Adds a multipart/related part to a mimePart
  363. * object (or creates one), and returns it during
  364. * the build process.
  365. *
  366. * @param mixed The object to add the part to, or
  367. * null if a new object is to be created
  368. * @return object The multipart/mixed mimePart object
  369. * @access private
  370. */
  371. function &_addRelatedPart(&$obj)
  372. {
  373. $params['content_type'] = 'multipart/related';
  374. if (is_object($obj)) {
  375. return $obj->addSubpart('', $params);
  376. } else {
  377. return new Mail_mimePart('', $params);
  378. }
  379. }
  380. /**
  381. * Adds an html image subpart to a mimePart object
  382. * and returns it during the build process.
  383. *
  384. * @param object The mimePart to add the image to
  385. * @param array The image information
  386. * @return object The image mimePart object
  387. * @access private
  388. */
  389. function &_addHtmlImagePart(&$obj, $value)
  390. {
  391. $params['content_type'] = $value['c_type'];
  392. $params['encoding'] = 'base64';
  393. $params['disposition'] = 'inline';
  394. $params['dfilename'] = $value['name'];
  395. $params['cid'] = $value['cid'];
  396. $obj->addSubpart($value['body'], $params);
  397. }
  398. /**
  399. * Adds an attachment subpart to a mimePart object
  400. * and returns it during the build process.
  401. *
  402. * @param object The mimePart to add the image to
  403. * @param array The attachment information
  404. * @return object The image mimePart object
  405. * @access private
  406. */
  407. function &_addAttachmentPart(&$obj, $value)
  408. {
  409. $params['content_type'] = $value['c_type'];
  410. $params['encoding'] = $value['encoding'];
  411. $params['disposition'] = 'attachment';
  412. $params['dfilename'] = $value['name'];
  413. $obj->addSubpart($value['body'], $params);
  414. }
  415. /**
  416. * Builds the multipart message from the list ($this->_parts) and
  417. * returns the mime content.
  418. *
  419. * @param array Build parameters that change the way the email
  420. * is built. Should be associative. Can contain:
  421. * text_encoding - What encoding to use for plain text
  422. * Default is 7bit
  423. * html_encoding - What encoding to use for html
  424. * Default is quoted-printable
  425. * 7bit_wrap - Number of characters before text is
  426. * wrapped in 7bit encoding
  427. * Default is 998
  428. * html_charset - The character set to use for html.
  429. * Default is iso-8859-1
  430. * text_charset - The character set to use for text.
  431. * Default is iso-8859-1
  432. * head_charset - The character set to use for headers.
  433. * Default is iso-8859-1
  434. * @return string The mime content
  435. * @access public
  436. */
  437. function &get($build_params = null)
  438. {
  439. if (isset($build_params)) {
  440. while (list($key, $value) = each($build_params)) {
  441. $this->_build_params[$key] = $value;
  442. }
  443. }
  444. if (!empty($this->_html_images) AND isset($this->_htmlbody)) {
  445. foreach ($this->_html_images as $value) {
  446. $regex = '#(\s)((?i)src|background|href(?-i))\s*=\s*(["\']?)' . preg_quote($value['name'], '#') .
  447. '\3#';
  448. $rep = '\1\2=\3cid:' . $value['cid'] .'\3';
  449. $this->_htmlbody = preg_replace($regex, $rep,
  450. $this->_htmlbody
  451. );
  452. }
  453. }
  454. $null = null;
  455. $attachments = !empty($this->_parts) ? true : false;
  456. $form_images = !empty($this->_html_images) ? true : false;
  457. $form = !empty($this->_htmlbody) ? true : false;
  458. $text = (!$form AND !empty($this->_txtbody)) ? true : false;
  459. switch (true) {
  460. case $text AND !$attachments:
  461. $message =& $this->_addTextPart($null, $this->_txtbody);
  462. break;
  463. case !$text AND !$form AND $attachments:
  464. $message =& $this->_addMixedPart();
  465. for ($i = 0; $i < count($this->_parts); $i++) {
  466. $this->_addAttachmentPart($message, $this->_parts[$i]);
  467. }
  468. break;
  469. case $text AND $attachments:
  470. $message =& $this->_addMixedPart();
  471. $this->_addTextPart($message, $this->_txtbody);
  472. for ($i = 0; $i < count($this->_parts); $i++) {
  473. $this->_addAttachmentPart($message, $this->_parts[$i]);
  474. }
  475. break;
  476. case $form AND !$attachments AND !$form_images:
  477. if (isset($this->_txtbody)) {
  478. $message =& $this->_addAlternativePart($null);
  479. $this->_addTextPart($message, $this->_txtbody);
  480. $this->_addHtmlPart($message);
  481. } else {
  482. $message =& $this->_addHtmlPart($null);
  483. }
  484. break;
  485. case $form AND !$attachments AND $form_images:
  486. if (isset($this->_txtbody)) {
  487. $message =& $this->_addAlternativePart($null);
  488. $this->_addTextPart($message, $this->_txtbody);
  489. $related =& $this->_addRelatedPart($message);
  490. } else {
  491. $message =& $this->_addRelatedPart($null);
  492. $related =& $message;
  493. }
  494. $this->_addHtmlPart($related);
  495. for ($i = 0; $i < count($this->_html_images); $i++) {
  496. $this->_addHtmlImagePart($related, $this->_html_images[$i]);
  497. }
  498. break;
  499. case $form AND $attachments AND !$form_images:
  500. $message =& $this->_addMixedPart();
  501. if (isset($this->_txtbody)) {
  502. $alt =& $this->_addAlternativePart($message);
  503. $this->_addTextPart($alt, $this->_txtbody);
  504. $this->_addHtmlPart($alt);
  505. } else {
  506. $this->_addHtmlPart($message);
  507. }
  508. for ($i = 0; $i < count($this->_parts); $i++) {
  509. $this->_addAttachmentPart($message, $this->_parts[$i]);
  510. }
  511. break;
  512. case $form AND $attachments AND $form_images:
  513. $message =& $this->_addMixedPart();
  514. if (isset($this->_txtbody)) {
  515. $alt =& $this->_addAlternativePart($message);
  516. $this->_addTextPart($alt, $this->_txtbody);
  517. $rel =& $this->_addRelatedPart($alt);
  518. } else {
  519. $rel =& $this->_addRelatedPart($message);
  520. }
  521. $this->_addHtmlPart($rel);
  522. for ($i = 0; $i < count($this->_html_images); $i++) {
  523. $this->_addHtmlImagePart($rel, $this->_html_images[$i]);
  524. }
  525. for ($i = 0; $i < count($this->_parts); $i++) {
  526. $this->_addAttachmentPart($message, $this->_parts[$i]);
  527. }
  528. break;
  529. }
  530. if (isset($message)) {
  531. $output = $message->encode();
  532. $this->_headers = array_merge($this->_headers,
  533. $output['headers']);
  534. return $output['body'];
  535. } else {
  536. return false;
  537. }
  538. }
  539. /**
  540. * Returns an array with the headers needed to prepend to the email
  541. * (MIME-Version and Content-Type). Format of argument is:
  542. * $array['header-name'] = 'header-value';
  543. *
  544. * @param array $xtra_headers Assoc array with any extra headers.
  545. * Optional.
  546. * @return array Assoc array with the mime headers
  547. * @access public
  548. */
  549. function &headers($xtra_headers = null)
  550. {
  551. // Content-Type header should already be present,
  552. // So just add mime version header
  553. $headers['MIME-Version'] = '1.0';
  554. if (isset($xtra_headers)) {
  555. $headers = array_merge($headers, $xtra_headers);
  556. }
  557. $this->_headers = array_merge($headers, $this->_headers);
  558. return $this->_encodeHeaders($this->_headers);
  559. }
  560. /**
  561. * Get the text version of the headers
  562. * (usefull if you want to use the PHP mail() function)
  563. *
  564. * @param array $xtra_headers Assoc array with any extra headers.
  565. * Optional.
  566. * @return string Plain text headers
  567. * @access public
  568. */
  569. function txtHeaders($xtra_headers = null)
  570. {
  571. $headers = $this->headers($xtra_headers);
  572. $ret = '';
  573. foreach ($headers as $key => $val) {
  574. $ret .= "$key: $val" . MAIL_MIME_CRLF;
  575. }
  576. return $ret;
  577. }
  578. /**
  579. * Sets the Subject header
  580. *
  581. * @param string $subject String to set the subject to
  582. * access public
  583. */
  584. function setSubject($subject)
  585. {
  586. $this->_headers['Subject'] = $subject;
  587. }
  588. /**
  589. * Set an email to the From (the sender) header
  590. *
  591. * @param string $email The email direction to add
  592. * @access public
  593. */
  594. function setFrom($email)
  595. {
  596. $this->_headers['From'] = $email;
  597. }
  598. /**
  599. * Add an email to the Cc (carbon copy) header
  600. * (multiple calls to this method are allowed)
  601. *
  602. * @param string $email The email direction to add
  603. * @access public
  604. */
  605. function addCc($email)
  606. {
  607. if (isset($this->_headers['Cc'])) {
  608. $this->_headers['Cc'] .= ", $email";
  609. } else {
  610. $this->_headers['Cc'] = $email;
  611. }
  612. }
  613. /**
  614. * Add an email to the Bcc (blank carbon copy) header
  615. * (multiple calls to this method are allowed)
  616. *
  617. * @param string $email The email direction to add
  618. * @access public
  619. */
  620. function addBcc($email)
  621. {
  622. if (isset($this->_headers['Bcc'])) {
  623. $this->_headers['Bcc'] .= ", $email";
  624. } else {
  625. $this->_headers['Bcc'] = $email;
  626. }
  627. }
  628. /**
  629. * Encodes a header as per RFC2047
  630. *
  631. * @param string $input The header data to encode
  632. * @return string Encoded data
  633. * @access private
  634. */
  635. function _encodeHeaders($input)
  636. {
  637. foreach ($input as $hdr_name => $hdr_value) {
  638. preg_match_all('/(\w*[\x80-\xFF]+\w*)/', $hdr_value, $matches);
  639. foreach ($matches[1] as $value) {
  640. $replacement = preg_replace('/([\x80-\xFF])/e',
  641. '"=" .
  642. strtoupper(dechex(ord("\1")))',
  643. $value);
  644. $hdr_value = str_replace($value, '=?' .
  645. $this->_build_params['head_charset'] .
  646. '?Q?' . $replacement . '?=',
  647. $hdr_value);
  648. }
  649. $input[$hdr_name] = $hdr_value;
  650. }
  651. return $input;
  652. }
  653. /**
  654. * Set the object's end-of-line and define the constant if applicable
  655. *
  656. * @param string $eol End Of Line sequence
  657. * @access private
  658. */
  659. function _setEOL($eol)
  660. {
  661. $this->_eol = $eol;
  662. if (!defined('MAIL_MIME_CRLF')) {
  663. define('MAIL_MIME_CRLF', $this->_eol, true);
  664. }
  665. }
  666. } // End of class
  667. ?>