alecpl
2008-11-06 68af648117f563311c717b5a086df0ae2e5c538f
program/lib/Mail/mimePart.php
@@ -182,13 +182,16 @@
            }
        }
        if (isset($contentType['type'])) {
            $headers['Content-Type'] = $contentType['type'];
            if (isset($contentType['name'])) {
                $headers['Content-Type'] .= ';' . MAIL_MIMEPART_CRLF;
                $headers['Content-Type'] .= $this->_buildHeaderParam('name', $contentType['name'],
                                                isset($contentType['charset']) ? $contentType['charset'] : 'US-ASCII',
                                                isset($contentType['language']) ? $contentType['language'] : NULL);
                $headers['Content-Type'] .=
          $this->_buildHeaderParam('name', $contentType['name'],
                        isset($contentType['charset']) ? $contentType['charset'] : 'US-ASCII',
                        isset($contentType['language']) ? $contentType['language'] : NULL,
         isset($params['name-encoding']) ?  $params['name-encoding'] : NULL);
            } elseif (isset($contentType['charset'])) {
                $headers['Content-Type'] .= "; charset=\"{$contentType['charset']}\"";
            }
@@ -199,15 +202,14 @@
            $headers['Content-Disposition'] = $contentDisp['disp'];
            if (isset($contentDisp['filename'])) {
                $headers['Content-Disposition'] .= ';' . MAIL_MIMEPART_CRLF;
                $headers['Content-Disposition'] .= $this->_buildHeaderParam('filename', $contentDisp['filename'],
                                                isset($contentDisp['charset']) ? $contentDisp['charset'] : 'US-ASCII',
                                                isset($contentDisp['language']) ? $contentDisp['language'] : NULL);
                $headers['Content-Disposition'] .=
          $this->_buildHeaderParam('filename', $contentDisp['filename'],
                        isset($contentDisp['charset']) ? $contentDisp['charset'] : 'US-ASCII',
                        isset($contentDisp['language']) ? $contentDisp['language'] : NULL,
         isset($params['filename-encoding']) ? $params['filename-encoding'] : NULL);
            }
        }
        // Default content-type
        if (!isset($headers['Content-Type'])) {
            $headers['Content-Type'] = 'text/plain';
@@ -255,8 +257,8 @@
            }
            $encoded['body'] = '--' . $boundary . MAIL_MIMEPART_CRLF . 
                               rtrim(implode('--' . $boundary . MAIL_MIMEPART_CRLF , $subparts), MAIL_MIMEPART_CRLF) . MAIL_MIMEPART_CRLF .
                               '--' . $boundary.'--' . MAIL_MIMEPART_CRLF;
            implode('--' . $boundary . MAIL_MIMEPART_CRLF , $subparts) .
                           '--' . $boundary.'--' . MAIL_MIMEPART_CRLF;
        } else {
            $encoded['body'] = $this->_getEncodedData($this->_body, $this->_encoding);
@@ -388,39 +390,36 @@
     * @param $value        The value of the paramter
     * @param $charset      The characterset of $value
     * @param $language     The language used in $value
     * @param $maxLength    The maximum length of a line. Defauls to 75
     * @param $paramEnc     Parameter encoding type
     * @param $maxLength    The maximum length of a line. Defauls to 78
     *
     * @access private
     */
    function _buildHeaderParam($name, $value, $charset=NULL, $language=NULL, $maxLength=75)
    function _buildHeaderParam($name, $value, $charset=NULL, $language=NULL, $paramEnc=NULL, $maxLength=78)
    {
        //If we find chars to encode, or if charset or language
        //is not any of the defaults, we need to encode the value.
        $shouldEncode = 0;
        $secondAsterisk = '';
        if (preg_match('#([\x80-\xFF]){1}#', $value)) {
            $shouldEncode = 1;
        } elseif ($charset && (strtolower($charset) != 'us-ascii')) {
            $shouldEncode = 1;
        } elseif ($language && ($language != 'en' && $language != 'en-us')) {
            $shouldEncode = 1;
        }
        if ($shouldEncode) {
            $search  = array('%',   ' ',   "\t");
            $replace = array('%25', '%20', '%09');
            $encValue = str_replace($search, $replace, $value);
            $encValue = preg_replace('#([\x80-\xFF])#e', '"%" . strtoupper(dechex(ord("\1")))', $encValue);
            $value = "$charset'$language'$encValue";
            $secondAsterisk = '*';
        }
        $header = " {$name}{$secondAsterisk}=\"{$value}\"; ";
        // RFC 2183/2184/2822:
   // value needs encoding if contains non-ASCII chars or is longer than 78 chars
        if (!preg_match('#[^\x20-\x7E]#', $value)) { // ASCII
       $quoted = addcslashes($value, '\\"');
       if (strlen($name) + strlen($quoted) + 6 <= $maxLength)
      return " {$name}=\"{$quoted}\"; ";
   }
   // use quoted-printable/base64 encoding (RFC2047)
   if ($paramEnc == 'quoted-printable' || $paramEnc == 'base64')
       return $this->_buildRFC2047Param($name, $value, $charset, $paramEnc);
        $encValue = preg_replace('#([^\x20-\x7E])#e', '"%" . strtoupper(dechex(ord("\1")))', $value);
        $value = "$charset'$language'$encValue";
        $header = " {$name}*=\"{$value}\"; ";
        if (strlen($header) <= $maxLength) {
            return $header;
        }
        $preLength = strlen(" {$name}*0{$secondAsterisk}=\"");
        $preLength = strlen(" {$name}*0*=\"");
        $sufLength = strlen("\";");
        $maxLength = MAX(16, $maxLength - $preLength - $sufLength - 2);
        $maxLength = max(16, $maxLength - $preLength - $sufLength - 2);
        $maxLengthReg = "|(.{0,$maxLength}[^\%][^\%])|";
        $headers = array();
@@ -429,10 +428,10 @@
            $matches = array();
            $found = preg_match($maxLengthReg, $value, $matches);
            if ($found) {
                $headers[] = " {$name}*{$headCount}{$secondAsterisk}=\"{$matches[0]}\"";
                $headers[] = " {$name}*{$headCount}*=\"{$matches[0]}\"";
                $value = substr($value, strlen($matches[0]));
            } else {
                $headers[] = " {$name}*{$headCount}{$secondAsterisk}=\"{$value}\"";
                $headers[] = " {$name}*{$headCount}*=\"{$value}\"";
                $value = "";
            }
            $headCount++;
@@ -440,4 +439,84 @@
        $headers = implode(MAIL_MIMEPART_CRLF, $headers) . ';';
        return $headers;
    }
    /**
     * Encodes header parameter as per RFC2047 if needed (values too long will be truncated)
     *
     * @param string $name  The parameter name
     * @param string $value  The parameter value
     * @param string $charset  The parameter charset
     * @param string $encoding  Encoding type (quoted-printable or base64)
     * @param int $maxLength  Encoded parameter max length (75 is the value specified in the RFC)
     *
     * @return string Parameter line
     * @access private
     */
    function _buildRFC2047Param($name, $value, $charset, $encoding='quoted-printable', $maxLength=75)
    {
        if (!preg_match('#([^\x20-\x7E]){1}#', $value))
   {
       $quoted = addcslashes($value, '\\"');
       $maxLength = $maxLength - 6;
       if (strlen($quoted) > $maxLength)
       {
      // truncate filename leaving extension
      $ext = strrchr($quoted, '.');
      $quoted = substr($quoted, 0, $maxLength - strlen($ext));
      // remove backslashes from the end of filename
      preg_replace('/[\\\\]+$/', '', $quoted);
      $quoted .= $ext;
       }
   }
   else if ($encoding == 'base64')
   {
       $ext = strrchr($value, '.');
            $value = substr($value, 0, strlen($value) - strlen($ext));
            $ext = base64_encode($ext);
       $value = base64_encode($value);
            $prefix = '=?' . $charset . '?B?';
            $suffix = '?=';
            $maxLength = $maxLength - strlen($prefix . $suffix) - strlen($ext) - 2;
            //We can cut base64 every 4 characters, so the real max
            //we can get must be rounded down.
            $maxLength = $maxLength - ($maxLength % 4);
            $quoted = $prefix . substr($value, 0, $maxLength) . $ext . $suffix;
        }
   else // quoted-printable
   {
       $ext = strrchr($value, '.');
            $value = substr($value, 0, strlen($value) - strlen($ext));
       // Replace all special characters used by the encoder.
            $search  = array('=',   '_',   '?',   ' ');
       $replace = array('=3D', '=5F', '=3F', '_');
       $ext = str_replace($search, $replace, $ext);
       $value = str_replace($search, $replace, $value);
       // Replace all extended characters (\x80-xFF) with their
       // ASCII values.
       $ext = preg_replace('/([\x80-\xFF])/e',
      '"=" . strtoupper(dechex(ord("\1")))', $ext);
       $value = preg_replace('/([\x80-\xFF])/e',
      '"=" . strtoupper(dechex(ord("\1")))', $value);
            $prefix = '=?' . $charset . '?Q?';
            $suffix = '?=';
            $maxLength = $maxLength - strlen($prefix . $suffix) - strlen($ext) - 2;
       // Truncate QP-encoded text at $maxLength
       // but not break any encoded letters.
       if(preg_match("/^(.{0,$maxLength}[^\=][^\=])/", $value, $matches))
          $value = $matches[1];
       $quoted = $prefix . $value . $ext . $suffix;
        }
   return " {$name}=\"{$quoted}\"; ";
    }
} // End of class