[ Index ]

PHP Cross Reference of Akelos Framework

title

Body

[close]

/AkActionMailer/ -> AkMailBase.php (source)

   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  ?>


Generated: Mon Oct 27 12:43:49 2008 Cross-referenced by PHPXref 0.6