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