| <?php |
| /** |
| * File containing the ezcMailPart class. |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| * @package Mail |
| * @version //autogen// |
| * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0 |
| */ |
| |
| /** |
| * Abstract base class for all mail MIME parts. |
| * |
| * This base class provides functionality to store headers and to generate |
| * the mail part. Implementations of this class must handle the body of that |
| * parts themselves. They must also implement {@link generateBody()} which is |
| * called when the message part is generated. |
| * |
| * @property ezcMailContentDispositionHeader $contentDisposition |
| * Contains the information from the Content-Disposition field of |
| * this mail. This useful especially when you are investigating |
| * retrieved mail to see if a part is an attachment or should be |
| * displayed inline. However, it can also be used to set the same |
| * on outgoing mail. Note that the ezcMailFile part sets the |
| * Content-Disposition field itself based on it's own properties |
| * when sending mail. |
| * @property int $size |
| * The size of the mail part in bytes. It is set when parsing a |
| * mail {@link ezcMailParser->parseMail()}. |
| * @property-read ezcMailHeadersHolder $headers |
| * Contains the header holder object, taking care of the |
| * headers of this part. Can be retreived for reasons of |
| * extending this class and its derivals. |
| * |
| * @package Mail |
| * @version //autogen// |
| */ |
| abstract class ezcMailPart |
| { |
| /** |
| * An associative array containing all the headers set for this part. |
| * |
| * @var ezcMailHeadersHolder |
| */ |
| private $headers = null; |
| |
| /** |
| * An associative array containing the charsets for the headers in this |
| * part. |
| * |
| * @var array(string=>string) |
| */ |
| private $headerCharsets = array(); |
| |
| /** |
| * An array of headers to exclude when generating the headers. |
| * |
| * @var array(string) |
| */ |
| private $excludeHeaders = array(); |
| |
| /** |
| * Holds the properties of this class. |
| * |
| * @var array(string=>mixed) |
| */ |
| protected $properties = array(); |
| |
| /** |
| * Constructs a new mail part. |
| */ |
| public function __construct() |
| { |
| $this->headers = new ezcMailHeadersHolder(); |
| } |
| |
| /** |
| * Sets the property $name to $value. |
| * |
| * @throws ezcBasePropertyNotFoundException |
| * if the property does not exist. |
| * @throws ezcBasePropertyPermissionException |
| * if the property is read-only. |
| * @param string $name |
| * @param mixed $value |
| * @ignore |
| */ |
| public function __set( $name, $value ) |
| { |
| switch ( $name ) |
| { |
| case 'contentDisposition': |
| case 'size': |
| $this->properties[$name] = $value; |
| break; |
| |
| case 'headers': |
| throw new ezcBasePropertyPermissionException( $name, ezcBasePropertyPermissionException::READ ); |
| |
| default: |
| throw new ezcBasePropertyNotFoundException( $name ); |
| } |
| } |
| |
| /** |
| * Returns the property $name. |
| * |
| * @throws ezcBasePropertyNotFoundException |
| * if the property does not exist. |
| * @param string $name |
| * @return mixed |
| * @ignore |
| */ |
| public function __get( $name ) |
| { |
| switch ( $name ) |
| { |
| case 'contentDisposition': |
| case 'size': |
| return isset( $this->properties[$name] ) ? $this->properties[$name] : null; |
| |
| case "headers": |
| return $this->headers; |
| |
| default: |
| throw new ezcBasePropertyNotFoundException( $name ); |
| |
| } |
| } |
| |
| /** |
| * Returns true if the property $name is set, otherwise false. |
| * |
| * @param string $name |
| * @return bool |
| * @ignore |
| */ |
| public function __isset( $name ) |
| { |
| switch ( $name ) |
| { |
| case 'contentDisposition': |
| case 'size': |
| return isset( $this->properties[$name] ); |
| |
| case "headers": |
| return isset( $this->headers ); |
| |
| default: |
| return false; |
| } |
| } |
| |
| /** |
| * Returns the RAW value of the header $name. |
| * |
| * Returns an empty string if the header is not found. |
| * Getting headers is case insensitive. Getting the header |
| * 'Message-Id' will match both 'Message-ID' and 'MESSAGE-ID' |
| * as well as 'Message-Id'. |
| * |
| * The raw value is MIME-encoded, so if you want to decode it, |
| * use {@link ezcMailTools::mimeDecode()} or implement your own |
| * MIME-decoding function. |
| * |
| * If $returnAllValues is true, the function will return all |
| * the values of the header $name from the mail in an array. If |
| * it is false it will return only the first value as a string |
| * if there are multiple values present in the mail. |
| * |
| * @param string $name |
| * @param bool $returnAllValues |
| * @return mixed |
| */ |
| public function getHeader( $name, $returnAllValues = false ) |
| { |
| if ( isset( $this->headers[$name] ) ) |
| { |
| if ( $returnAllValues === true ) |
| { |
| return $this->headers[$name]; |
| } |
| else if ( is_array( $this->headers[$name] ) ) |
| { |
| // return only the first value in order to not break compatibility |
| // see issue #14257 |
| return $this->headers[$name][0]; |
| } |
| else |
| { |
| return $this->headers[$name]; |
| } |
| } |
| return ''; |
| } |
| |
| /** |
| * Sets the header $name to the value $value and its charset to $charset. |
| * |
| * If the header is already set it will override the old value. |
| * |
| * Headers set should be folded at 76 or 998 characters according to |
| * the folding rules described in RFC 2822. |
| * |
| * If $charset is specified, it is associated with the header $name. It |
| * defaults to 'us-ascii' if not specified. The text in $value is encoded |
| * with $charset after calling generateHeaders(). |
| * |
| * Note: The header Content-Disposition will be overwritten by the |
| * contents of the contentsDisposition property if set. |
| * |
| * @see generateHeaders() |
| * |
| * @param string $name |
| * @param string $value |
| * @param string $charset |
| */ |
| public function setHeader( $name, $value, $charset = 'us-ascii' ) |
| { |
| $this->headers[$name] = $value; |
| $this->setHeaderCharset( $name, $charset ); |
| } |
| |
| /** |
| * Adds the headers $headers. |
| * |
| * The headers specified in the associative array $headers will overwrite |
| * any existing header values. |
| * |
| * The array $headers can have one of these 2 forms: |
| * - array( header_name => header_value ) - by default the 'us-ascii' charset |
| * will be associated with all headers |
| * - array( header_name => array( header_value, header_charset ) ) - if |
| * header_charset is missing it will default to 'us-ascii' |
| * |
| * Headers set should be folded at 76 or 998 characters according to |
| * the folding rules described in RFC 2822. |
| * |
| * @param array(string=>mixed) $headers |
| */ |
| public function setHeaders( array $headers ) |
| { |
| foreach ( $headers as $key => $value ) |
| { |
| if ( is_array( $value ) ) |
| { |
| $this->headers[$key] = $value[0]; |
| $charset = isset( $value[1] ) ? $value[1] : 'us-ascii'; |
| $this->setHeaderCharset( $key, $charset ); |
| } |
| else |
| { |
| $this->headers[$key] = $value; |
| $this->setHeaderCharset( $key ); |
| } |
| } |
| } |
| |
| /** |
| * Returns the headers set for this part as a RFC 822 string. |
| * |
| * Each header is separated by a line break. |
| * This method does not add the required two lines of space |
| * to separate the headers from the body of the part. |
| * |
| * It also encodes the headers (with the 'Q' encoding) if the charset |
| * associated with the header is different than 'us-ascii' or if it |
| * contains characters not allowed in mail headers. |
| * |
| * This function is called automatically by generate() and |
| * subclasses can override this method if they wish to set additional |
| * headers when the mail is generated. |
| * |
| * @see setHeader() |
| * |
| * @return string |
| */ |
| public function generateHeaders() |
| { |
| // set content disposition header |
| if ( $this->contentDisposition !== null && |
| ( $this->contentDisposition instanceof ezcMailContentDispositionHeader ) ) |
| { |
| $cdHeader = $this->contentDisposition; |
| $cd = "{$cdHeader->disposition}"; |
| if ( $cdHeader->fileName !== null ) |
| { |
| $fileInfo = null; |
| if ( $cdHeader->fileNameCharSet !== null ) |
| { |
| $fileInfo .= "*0*=\"{$cdHeader->fileNameCharSet}"; |
| if ( $cdHeader->fileNameLanguage !== null ) |
| { |
| $fileInfo .= "'{$cdHeader->fileNameLanguage}'"; |
| } |
| else |
| { |
| // RFC 2184: the single quote delimiters MUST be present |
| // even when one of the field values is omitted |
| $fileInfo .= "''"; |
| } |
| } |
| if ( $fileInfo !== null ) |
| { |
| $cd .= "; filename{$fileInfo}{$cdHeader->fileName}\""; |
| } |
| else |
| { |
| $cd .= "; filename=\"{$cdHeader->fileName}\""; |
| } |
| } |
| |
| if ( $cdHeader->creationDate !== null ) |
| { |
| $cd .= "; creation-date=\"{$cdHeader->creationDate}\""; |
| } |
| |
| if ( $cdHeader->modificationDate !== null ) |
| { |
| $cd .= "; modification-date=\"{$cdHeader->modificationDate}\""; |
| } |
| |
| if ( $cdHeader->readDate !== null ) |
| { |
| $cd .= "; read-date=\"{$cdHeader->readDate}\""; |
| } |
| |
| if ( $cdHeader->size !== null ) |
| { |
| $cd .= "; size={$cdHeader->size}"; |
| } |
| |
| foreach ( $cdHeader->additionalParameters as $addKey => $addValue ) |
| { |
| $cd .="; {$addKey}=\"{$addValue}\""; |
| } |
| |
| $this->setHeader( 'Content-Disposition', $cd ); |
| } |
| |
| // generate headers |
| $text = ""; |
| foreach ( $this->headers->getCaseSensitiveArray() as $header => $value ) |
| { |
| if ( is_array( $value ) ) |
| { |
| $value = $value[0]; |
| } |
| |
| // here we encode every header, even the ones that we don't add to |
| // the header set directly. We do that so that transports sill see |
| // all the encoded headers which they then can use accordingly. |
| $charset = $this->getHeaderCharset( $header ); |
| switch ( strtolower( $charset ) ) |
| { |
| case 'us-ascii': |
| $value = ezcMailHeaderFolder::foldAny( $value ); |
| break; |
| |
| case 'iso-8859-1': case 'iso-8859-2': case 'iso-8859-3': case 'iso-8859-4': |
| case 'iso-8859-5': case 'iso-8859-6': case 'iso-8859-7': case 'iso-8859-8': |
| case 'iso-8859-9': case 'iso-8859-10': case 'iso-8859-11': case 'iso-8859-12': |
| case 'iso-8859-13': case 'iso-8859-14': case 'iso-8859-15' :case 'iso-8859-16': |
| case 'windows-1250': case 'windows-1251': case 'windows-1252': |
| case 'utf-8': |
| if ( strpbrk( $value, "\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff" ) === false ) |
| { |
| $value = ezcMailHeaderFolder::foldAny( $value ); |
| break; |
| } |
| // break intentionally missing |
| |
| default: |
| $preferences = array( |
| 'input-charset' => $charset, |
| 'output-charset' => $charset, |
| 'line-length' => ezcMailHeaderFolder::getLimit(), |
| 'scheme' => 'Q', |
| 'line-break-chars' => ezcMailTools::lineBreak() |
| ); |
| $value = iconv_mime_encode( 'dummy', $value, $preferences ); |
| $value = substr( $value, 7 ); // "dummy: " + 1 |
| |
| // just to keep compatibility with code which might read |
| // the headers after generateHeaders() has been called |
| $this->setHeader( $header, $value, $charset ); |
| break; |
| } |
| |
| if ( in_array( strtolower( $header ), $this->excludeHeaders ) === false ) |
| { |
| $text .= "$header: $value" . ezcMailTools::lineBreak(); |
| } |
| } |
| |
| return $text; |
| } |
| |
| /** |
| * The array $headers will be excluded when the headers are generated. |
| * |
| * @see generateHeaders() |
| * |
| * @param array(string) $headers |
| */ |
| public function appendExcludeHeaders( array $headers ) |
| { |
| $lowerCaseHeaders = array(); |
| foreach ( $headers as $header ) |
| { |
| $lowerCaseHeaders[] = strtolower( $header ); |
| } |
| $this->excludeHeaders = array_merge( $this->excludeHeaders, $lowerCaseHeaders ); |
| } |
| |
| /** |
| * Returns the body of this part as a string. |
| * |
| * This method is called automatically by generate() and subclasses must |
| * implement it. |
| * |
| * @return string |
| */ |
| abstract public function generateBody(); |
| |
| /** |
| * Returns the complete mail part including both the header and the body |
| * as a string. |
| * |
| * @return string |
| */ |
| public function generate() |
| { |
| return $this->generateHeaders() . ezcMailTools::lineBreak() . $this->generateBody(); |
| } |
| |
| /** |
| * Returns the charset registered for the header $name. |
| * |
| * @param string $name |
| * @return string |
| */ |
| protected function getHeaderCharset( $name ) |
| { |
| if ( isset( $this->headerCharsets[$name] ) ) |
| { |
| return $this->headerCharsets[$name]; |
| } |
| |
| // if no charset is set then return 'us-ascii' |
| return 'us-ascii'; |
| } |
| |
| /** |
| * Sets the charset of the header $name to $value. |
| * |
| * If $value is not specified it defaults to 'us-ascii'. |
| * |
| * @param string $name |
| * @param string $value |
| */ |
| protected function setHeaderCharset( $name, $value = 'us-ascii' ) |
| { |
| $this->headerCharsets[$name] = $value; |
| } |
| } |
| ?> |