| [ Index ] |
PHP Cross Reference of Akelos Framework |
[Summary view] [Print] [Text view]
1 <?php 2 3 include_once(AK_CONTRIB_DIR.DS.'pear'.DS.'Mail.php'); 4 5 class AkMailBase extends Mail 6 { 7 8 var $raw_message = ''; 9 var $charset = AK_ACTION_MAILER_DEFAULT_CHARSET; 10 var $content_type; 11 var $body; 12 13 var $parts = array(); 14 var $attachments = array(); 15 16 var $_attach_html_images = true; 17 18 function AkMailBase() 19 { 20 $args = func_get_args(); 21 if(isset($args[0])){ 22 if(count($args) == 1 && is_string($args[0])){ 23 $this->raw_message = $args[0]; 24 }elseif(is_array($args[0])){ 25 AkMailParser::importStructure($this, $args[0]); 26 } 27 } 28 } 29 30 function &parse($raw_email = '') 31 { 32 if(empty($raw_email)){ 33 trigger_error(Ak::t('Cannot parse an empty message'), E_USER_ERROR); 34 } 35 $Mail =& new AkMailMessage((array)AkMailParser::parse($raw_email)); 36 return $Mail; 37 } 38 39 function &load($email_file) 40 { 41 if(!file_exists($email_file)){ 42 trigger_error(Ak::t('Cannot find mail file at %path',array('%path'=>$email_file)), E_USER_ERROR); 43 } 44 $Mail =& new AkMail((array)AkMailParser::parse(file_get_contents($email_file))); 45 return $Mail; 46 } 47 48 49 function setBody($body) 50 { 51 if(is_string($body)){ 52 $content_type = @$this->content_type; 53 $this->body = stristr($content_type,'text/') ? str_replace(array("\r\n","\r"),"\n", $body) : $body; 54 if($this->_attach_html_images && $content_type == 'text/html'){ 55 $Parser = new AkMailParser(); 56 $Parser->extractImagesIntoInlineParts($this); 57 } 58 }else{ 59 $this->body = $body; 60 } 61 } 62 63 64 function getBody() 65 { 66 if(!is_array($this->body)){ 67 $encoding = $this->getContentTransferEncoding(); 68 $charset = $this->getCharset(); 69 switch ($encoding) { 70 case 'quoted-printable': 71 return trim(AkActionMailerQuoting::chunkQuoted(AkActionMailerQuoting::quotedPrintableEncode($this->body, $charset))); 72 case 'base64': 73 return $this->_base64Body($this->body); 74 default: 75 return trim($this->body); 76 } 77 } 78 } 79 80 function _base64Body($content) 81 { 82 $Cache =& Ak::cache(); 83 $cache_id = md5($content); 84 $Cache->init(3600); 85 if (!$encoded_content = $Cache->get($cache_id)) { 86 $encoded_content = trim(chunk_split(base64_encode($content))); 87 unset($content); 88 $Cache->save($encoded_content); 89 } 90 return $encoded_content; 91 } 92 93 /** 94 * Specify the CC addresses for the message. 95 */ 96 function setCc($cc) 97 { 98 $this->cc = $cc; 99 } 100 101 /** 102 * Specify the BCC addresses for the message. 103 */ 104 function setBcc($bcc) 105 { 106 $this->bcc = $bcc; 107 } 108 109 /** 110 * Specify the charset to use for the message. 111 */ 112 function setCharset($charset, $append_to_content_type_as_attribute = true) 113 { 114 $this->charset = $charset; 115 if($append_to_content_type_as_attribute){ 116 $this->setContenttypeAttributes(array('charset'=>$charset)); 117 } 118 } 119 120 function getCharset($default_to = null) 121 { 122 return empty($this->charset) ? AK_ACTION_MAILER_DEFAULT_CHARSET : $this->charset; 123 } 124 125 /** 126 * Specify the content type for the message. This defaults to <tt>text/plain</tt> 127 * in most cases, but can be automatically set in some situations. 128 */ 129 function setContentType($content_type) 130 { 131 list($this->content_type, $ctype_attrs) = $this->_getContentTypeAndAttributes($content_type); 132 $this->setContenttypeAttributes($ctype_attrs); 133 } 134 135 136 function getContentType() 137 { 138 return empty($this->content_type) ? ($this->isMultipart()?'multipart/alternative':null) : $this->content_type.$this->getContenttypeAttributes(); 139 } 140 141 function hasContentType() 142 { 143 return !empty($this->content_type); 144 } 145 146 function setContenttypeAttributes($attributes = array()) 147 { 148 foreach ($attributes as $key=>$value){ 149 if(strtolower($key) == 'charset'){ 150 $this->setCharset($value, false); 151 } 152 $this->content_type_attributes[$key] = $value; 153 } 154 } 155 156 function getContentTypeAttributes() 157 { 158 return $this->_getAttributesForHeader('content_type'); 159 } 160 161 function bodyToString($Mail = null) 162 { 163 $Mail = empty($Mail) ? $this : $Mail; 164 $result = ''; 165 foreach ((array)$Mail as $field => $value){ 166 if(!empty($value) && is_string($value)){ 167 if($Mail->isMainMessage() && $field=='body'){ 168 $result .= $value."\n"; 169 }elseif(empty($Mail->data) && $field=='body'){ 170 $result .= $value."\n"; 171 }elseif(!empty($Mail->data) && $field=='original_filename'){ 172 $result .= $value; 173 } 174 } 175 if($field == 'parts' && !empty($value) && is_array($value)){ 176 foreach ($value as $part){ 177 if(!empty($part->data) && !empty($part->original_filename)){ 178 $result .= "Attachment: "; 179 $result .= $this->bodyToString($part)."\n"; 180 }else{ 181 $result .= $this->bodyToString($part)."\n"; 182 } 183 } 184 } 185 } 186 187 return $result; 188 } 189 190 function isMainMessage() 191 { 192 return strtolower(get_class($this)) == 'akmailmessage'; 193 } 194 195 function isPart() 196 { 197 return strtolower(get_class($this)) == 'akmailpart'; 198 } 199 200 function _getAttributesForHeader($header_index, $force_reload = false) 201 { 202 if(empty($this->_header_attributes_set_for[$header_index]) || $force_reload){ 203 $header_index = strtolower(AkInflector::underscore($header_index)).'_attributes'; 204 if(!empty($this->$header_index)){ 205 $attributes = ''; 206 if(!empty($this->$header_index)){ 207 foreach ((array)$this->$header_index as $key=>$value){ 208 $attributes .= ";$key=$value"; 209 } 210 } 211 $this->_header_attributes_set_for[$header_index] = $attributes; 212 } 213 } 214 if (!empty($this->_header_attributes_set_for[$header_index])){ 215 return $this->_header_attributes_set_for[$header_index]; 216 } 217 } 218 219 /** 220 * Specify the content disposition for the message. 221 */ 222 function setContentDisposition($content_disposition) 223 { 224 $this->content_disposition = $content_disposition; 225 } 226 227 /** 228 * Specify the content transfer encoding for the message. 229 */ 230 function setContentTransferEncoding($content_transfer_encoding) 231 { 232 $this->content_transfer_encoding = $content_transfer_encoding; 233 } 234 235 /** 236 * Alias for setContentTransferEncoding 237 */ 238 function setTransferEncoding($content_transfer_encoding) 239 { 240 $this->setContentTransferEncoding($content_transfer_encoding); 241 } 242 243 function getContentTransferEncoding() 244 { 245 if(empty($this->content_transfer_encoding)){ 246 return null; 247 } 248 return $this->content_transfer_encoding; 249 } 250 251 function getTransferEncoding() 252 { 253 return $this->getTransferEncoding(); 254 } 255 256 function _getContentTypeAndAttributes($content_type = null) 257 { 258 if(empty($content_type)){ 259 return array($this->getDefault('content_type'), array()); 260 } 261 $attributes = array(); 262 if(strstr($content_type,';')){ 263 list($content_type, $attrs) = split(";\\s*",$content_type); 264 if(!empty($attrs)){ 265 foreach ((array)$attrs as $s){ 266 if(strstr($s,'=')){ 267 list($k,$v) = array_map('trim',split("=", $s, 2)); 268 if(!empty($v)){ 269 $attributes[$k] = $v; 270 } 271 } 272 } 273 } 274 } 275 276 $attributes = array_diff(array_merge(array('charset'=> (empty($this->_charset)?$this->getDefault('charset'):$this->_charset)),$attributes), array('')); 277 return array(trim($content_type), $attributes); 278 } 279 280 281 function getDefault($field) 282 { 283 $field = AkInflector::underscore($field); 284 $defaults = array( 285 'charset' => $this->getCharset(), 286 'content_type' => 'text/plain', 287 ); 288 return isset($defaults[$field]) ? $defaults[$field] : null; 289 } 290 291 292 function _addHeaderAttributes() 293 { 294 foreach($this->getHeaders() as $k=>$v){ 295 $this->headers[$k] .= $this->_getAttributesForHeader($k); 296 } 297 } 298 299 function getRawHeaders($options = array()) 300 { 301 if(empty($this->raw_headers)){ 302 303 $this->headers = $this->getHeaders(true); 304 305 if($this->isPart()){ 306 $this->prepareHeadersForRendering(array( 307 'skip' => (array)@$options['skip'], 308 'only' => (array)@$options['only'] 309 )); 310 } 311 unset($this->headers['Charset']); 312 $headers = $this->prepareHeaders($this->headers); 313 if(!is_array($headers)){ 314 trigger_error($headers->message, E_USER_NOTICE); 315 return false; 316 }else{ 317 $this->raw_headers = array_pop($headers); 318 } 319 } 320 return $this->raw_headers; 321 } 322 323 function getHeaders($force_reload = false) 324 { 325 if(empty($this->headers) || $force_reload){ 326 $this->loadHeaders(); 327 $this->_addHeaderAttributes(); 328 329 } 330 return $this->headers; 331 } 332 333 function getHeader($header_name) 334 { 335 $headers = $this->getHeaders(); 336 return isset($headers[$header_name]) ? $headers[$header_name] : null; 337 } 338 339 function loadHeaders() 340 { 341 if(empty($this->date) && $this->isMainMessage()){ 342 $this->setDate(); 343 } 344 $new_headers = array(); 345 $this->_moveMailInstanceAttributesToHeaders(); 346 foreach (array_map(array('AkActionMailerQuoting','chunkQuoted'), $this->headers) as $header=>$value){ 347 if(!is_numeric($header)){ 348 $new_headers[$this->_castHeaderKey($header)] = $value; 349 } 350 } 351 $this->headers = $new_headers; 352 $this->_sanitizeHeaders($this->headers); 353 } 354 355 function _moveMailInstanceAttributesToHeaders() 356 { 357 foreach ((array)$this as $k=>$v){ 358 if($k[0] != '_' && $this->_belongsToHeaders($k)){ 359 $attribute_getter = 'get'.ucfirst($k); 360 $attribute_name = AkInflector::underscore($k); 361 $header_value = method_exists($this,$attribute_getter) ? $this->$attribute_getter() : $v; 362 is_array($header_value) ? null : $this->setHeader($attribute_name, $header_value); 363 } 364 } 365 } 366 367 function _belongsToHeaders($attribute) 368 { 369 return !in_array(strtolower($attribute),array('body','recipients','part','parts','raw_message','sep','implicit_parts_order','header','headers')); 370 } 371 372 function _castHeaderKey($key) 373 { 374 return str_replace(' ','-',ucwords(str_replace('_',' ',AkInflector::underscore($key)))); 375 } 376 377 /** 378 * Specify additional headers to be added to the message. 379 */ 380 function setHeaders($headers, $options = array()) 381 { 382 foreach ((array)$headers as $name=>$value){ 383 $this->setHeader($name, $value, $options); 384 } 385 } 386 387 388 function setHeader($name, $value = null, $options = array()) 389 { 390 if(is_array($value)){ 391 $this->setHeaders($value, $options); 392 }else{ 393 $this->headers[$name] = $value; 394 } 395 } 396 397 398 399 /** 400 * Generic setter 401 * 402 * Calling $this->set(array('body'=>'Hello World', 'subject' => 'First subject')); 403 * is the same as calling $this->setBody('Hello World'); and $this->setSubject('First Subject'); 404 * 405 * This simplifies creating mail objects from datasources. 406 * 407 * If the method does not exists the parameter will be added to the header. 408 */ 409 function set($attributes = array()) 410 { 411 foreach ((array)$attributes as $key=>$value){ 412 if($key[0] != '_'){ 413 $attribute_setter = 'set'.AkInflector::camelize($key); 414 if(method_exists($this, $attribute_setter)){ 415 $this->$attribute_setter($value); 416 }else{ 417 $this->setHeader($key, $value); 418 } 419 } 420 } 421 } 422 423 424 function getSortedParts($parts, $order = array()) 425 { 426 $this->_parts_order = array_map('strtolower', empty($order) ? $this->implicit_parts_order : $order); 427 usort($parts, array($this,'_contentTypeComparison')); 428 return array_reverse(&$parts); 429 } 430 431 function sortParts() 432 { 433 if(!empty($this->parts)){ 434 $this->parts = $this->getSortedParts($this->parts); 435 } 436 } 437 438 function _contentTypeComparison($a, $b) 439 { 440 if(!isset($a->content_type) || !isset($b->content_type)){ 441 if (!isset($a->content_type) && !isset($b->content_type)) { 442 return 0; 443 } else if (!isset($a->content_type)) { 444 return -1; 445 } else { 446 return 1; 447 } 448 } 449 450 $a_ct = strtolower($a->content_type); 451 $b_ct = strtolower($b->content_type); 452 $a_in = in_array($a_ct, $this->_parts_order); 453 $b_in = in_array($b_ct, $this->_parts_order); 454 if($a_in && $b_in){ 455 $a_pos = array_search($a_ct, $this->_parts_order); 456 $b_pos = array_search($b_ct, $this->_parts_order); 457 return (($a_pos == $b_pos) ? 0 : (($a_pos < $b_pos) ? -1 : 1)); 458 } 459 return $a_in ? -1 : ($b_in ? 1 : (($a_ct == $b_ct) ? 0 : (($a_ct < $b_ct) ? -1 : 1))); 460 } 461 462 463 464 465 function setParts($parts, $position = 'append', $propagate_multipart_parts = false) 466 { 467 foreach ((array)$parts as $k=>$part){ 468 if(is_numeric($k)){ 469 $this->setPart((array)$part, $position, $propagate_multipart_parts); 470 }else{ 471 $this->setPart($parts, $position, $propagate_multipart_parts); 472 break; 473 } 474 } 475 } 476 477 478 /** 479 * Add a part to a multipart message, with an array of options like 480 * (content-type, charset, body, headers, etc.). 481 * 482 * function my_mail_message() 483 * { 484 * $this->setPart(array( 485 * 'content-type' => 'text/plain', 486 * 'body' => "hello, world", 487 * 'transfer_encoding' => "base64" 488 * )); 489 * } 490 */ 491 function setPart($options = array(), $position = 'append', $propagate_multipart_parts = false) 492 { 493 $default_options = array('content_disposition' => 'inline', 'content_transfer_encoding' => 'quoted-printable'); 494 $options = array_merge($default_options, $options); 495 $Part =& new AkMailPart($options); 496 $position == 'append' ? array_push($this->parts, $Part) : array_unshift($this->parts, $Part); 497 empty($propagate_multipart_parts) ? $this->_propagateMultipartParts() : null; 498 } 499 500 function _propagateMultipartParts() 501 { 502 if(!empty($this->parts)){ 503 foreach (array_keys($this->parts) as $k){ 504 $Part =& $this->parts[$k]; 505 if(empty($Part->_propagated)){ 506 $Part->_propagated = true; 507 if(!empty($Part->content_disposition)){ 508 // Inline bodies 509 if(isset($Part->content_type) && stristr($Part->content_type,'text/') && $Part->content_disposition == 'inline'){ 510 if((!empty($this->body) && is_string($this->body)) 511 || (!empty($this->body) && is_array($this->body) && ($this->isMultipart() || $this->content_type == 'text/plain')) 512 ){ 513 $this->_moveBodyToInlinePart(); 514 } 515 $type = strstr($Part->content_type, '/') ? substr($Part->content_type,strpos($Part->content_type,"/")+1) : $Part->content_type; 516 $Part->_on_body_as = $type; 517 $this->body[$type] = $Part->body; 518 519 } 520 521 // Attachments 522 elseif ($Part->content_disposition == 'attachment' || ($Part->content_disposition == 'inline' && !preg_match('/^(text|multipart)\//i',$Part->content_type)) || !empty($Part->content_location)){ 523 $this->_addAttachment($Part); 524 } 525 } 526 } 527 } 528 } 529 } 530 531 function _moveBodyToInlinePart() 532 { 533 $options = array( 534 'content_type' => @$this->content_type, 535 'body' => @$this->body, 536 'charset' => @$this->charset, 537 'content_disposition' => 'inline' 538 ); 539 foreach (array_keys($options) as $k){ 540 unset($this->$k); 541 } 542 543 $this->setAsMultipart(); 544 $this->setPart($options, 'preppend'); 545 } 546 547 function setAsMultipart() 548 { 549 $this->_multipart_message = true; 550 } 551 552 function isMultipart() 553 { 554 return !empty($this->_multipart_message); 555 } 556 function isAttachment() 557 { 558 return $this->content_disposition == 'attachment'; 559 } 560 561 function _addAttachment(&$Part) 562 { 563 $Part->original_filename = !empty($Part->content_type_attributes['name']) ? $Part->content_type_attributes['name'] : 564 (!empty($Part->content_disposition_attributes['filename']) ? $Part->content_disposition_attributes['filename'] : 565 (empty($Part->filename) ? @$Part->content_location : $Part->filename)); 566 567 $Part->original_filename = preg_replace('/[^A-Z^a-z^0-9^\-^_^\.]*/','',$Part->original_filename); 568 569 if(!empty($Part->body)){ 570 $Part->data =& $Part->body; 571 } 572 if(empty($Part->content_disposition_attributes['filename'])){ 573 $Part->content_disposition_attributes['filename'] = $Part->original_filename; 574 } 575 if(empty($Part->content_type_attributes['name'])){ 576 $Part->content_type_attributes['name'] = $Part->original_filename; 577 } 578 unset($Part->content_type_attributes['charset']); 579 $this->attachments[] =& $Part; 580 } 581 582 function hasAttachments() 583 { 584 return !empty($this->attachments); 585 } 586 587 function hasParts() 588 { 589 return !empty($this->parts); 590 } 591 592 function hasNonAttachmentParts() 593 { 594 return (count($this->parts) - count($this->attachments)) > 0; 595 } 596 597 /** 598 * Add an attachment to a multipart message. This is simply a part with the 599 * content-disposition set to "attachment". 600 * 601 * $this->setAttachment("image/jpg", array( 602 * 'body' => Ak::file_get_contents('hello.jpg'), 603 * 'filename' => "hello.jpg" 604 * )); 605 */ 606 function setAttachment() 607 { 608 $args = func_get_args(); 609 $options = array(); 610 if(count($args) == 2){ 611 $options['content_type'] = array_shift($args); 612 } 613 614 $arg_options = @array_shift($args); 615 $options = array_merge($options, is_string($arg_options) ? array('body'=>$arg_options) : (array)$arg_options); 616 $options = array_merge(array('content_disposition' => 'attachment', 'content_transfer_encoding' => 'base64'), $options); 617 618 $this->setPart($options); 619 } 620 621 function setAttachments($attachments = array()) 622 { 623 foreach ($attachments as $attachment){ 624 $this->setAttachment($attachment); 625 } 626 } 627 628 629 function setMessageId($id) 630 { 631 $this->messageId = $id; 632 } 633 634 635 /** 636 * Specify the order in which parts should be sorted, based on content-type. 637 * This defaults to the value for the +default_implicit_parts_order+. 638 */ 639 function setImplicitPartsOrder($implicit_parts_order) 640 { 641 $this->implicit_parts_order = $implicit_parts_order; 642 } 643 644 645 646 function getEncoded() 647 { 648 $header = $this->getRawHeaders(); 649 return $header ? $header.AK_ACTION_MAILER_EOL.AK_ACTION_MAILER_EOL.$this->getBody() : false; 650 } 651 652 } 653 654 ?>
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated: Mon Oct 27 12:43:49 2008 | Cross-referenced by PHPXref 0.6 |