[ Index ] |
|
Code source de Horde 3.1.3 |
1 <?php 2 3 /* We need to (unfortunately) hard code these constants because they reside in 4 * the imap module, which is not required for Horde. 5 * These constants are found in the UW-imap c-client distribution: 6 * ftp://ftp.cac.washington.edu/imap/ 7 * The constants appear in the file include/mail.h */ 8 require_once 'Horde/Util.php'; 9 if (!Util::extensionExists('imap')) { 10 /* Primary body types */ 11 define('TYPETEXT', 0); 12 define('TYPEMULTIPART', 1); 13 define('TYPEMESSAGE', 2); 14 define('TYPEAPPLICATION', 3); 15 define('TYPEAUDIO', 4); 16 define('TYPEIMAGE', 5); 17 define('TYPEVIDEO', 6); 18 define('TYPEOTHER', 8); 19 20 /* Body encodings */ 21 define('ENC7BIT', 0); 22 define('ENC8BIT', 1); 23 define('ENCBINARY', 2); 24 define('ENCBASE64', 3); 25 define('ENCQUOTEDPRINTABLE', 4); 26 define('ENCOTHER', 5); 27 } 28 29 /** 30 * Older versions of PHP's imap extension don't define TYPEMODEL. 31 */ 32 if (!defined('TYPEMODEL')) { 33 define('TYPEMODEL', 7); 34 } 35 36 /** 37 * Return a code for type()/encoding(). 38 */ 39 define('MIME_CODE', 1); 40 41 /** 42 * Return a string for type()/encoding(). 43 */ 44 define('MIME_STRING', 2); 45 46 47 /** 48 * The MIME:: class provides methods for dealing with MIME standards. 49 * 50 * $Horde: framework/MIME/MIME.php,v 1.139.4.20 2006/03/24 04:29:52 chuck Exp $ 51 * 52 * Copyright 1999-2006 Chuck Hagenbuch <chuck@horde.org> 53 * 54 * See the enclosed file COPYING for license information (LGPL). If you 55 * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html. 56 * 57 * @author Chuck Hagenbuch <chuck@horde.org> 58 * @since Horde 1.3 59 * @package Horde_MIME 60 */ 61 class MIME { 62 63 /** 64 * A listing of the allowed MIME types. 65 * 66 * @var array 67 */ 68 var $mime_types = array( 69 TYPETEXT => 'text', 70 TYPEMULTIPART => 'multipart', 71 TYPEMESSAGE => 'message', 72 TYPEAPPLICATION => 'application', 73 TYPEAUDIO => 'audio', 74 TYPEIMAGE => 'image', 75 TYPEVIDEO => 'video', 76 TYPEMODEL => 'model', 77 TYPEOTHER => 'other' 78 ); 79 80 /** 81 * A listing of the allowed MIME encodings. 82 * 83 * @var array 84 */ 85 var $mime_encodings = array( 86 ENC7BIT => '7bit', 87 ENC8BIT => '8bit', 88 ENCBINARY => 'binary', 89 ENCBASE64 => 'base64', 90 ENCQUOTEDPRINTABLE => 'quoted-printable', 91 ENCOTHER => 'unknown' 92 ); 93 94 /** 95 * Filter for RFC822. 96 * 97 * @var string 98 */ 99 var $rfc822_filter = "()<>@,;:\\\"[]\1\2\3\4\5\6\7\10\11\12\13\14\15\16\17\20\21\22\23\24\25\26\27\30\31\32\33\34\35\36\37\177"; 100 101 /** 102 * Determines if a string contains 8-bit characters. 103 * 104 * @param string $string The string to check. 105 * 106 * @return boolean True if it does, false if it doesn't. 107 */ 108 function is8bit($string) 109 { 110 return (is_string($string) && preg_match('/[\x80-\xff]/', $string)); 111 } 112 113 /** 114 * Encodes a string containing non-ASCII characters according to RFC 2047. 115 * 116 * @param string $text The text to encode. 117 * @param string $charset The character set of the text. 118 * 119 * @return string The text, encoded only if it contains non-ASCII 120 * characters. 121 */ 122 function encode($text, $charset = null) 123 { 124 /* Return if nothing needs to be encoded. */ 125 if (!MIME::is8bit($text)) { 126 return $text; 127 } 128 129 if (is_null($charset)) { 130 $charset = NLS::getCharset(); 131 } 132 133 $charset = String::lower($charset); 134 $line = ''; 135 136 /* Get the list of elements in the string. */ 137 $size = preg_match_all('/([^\s]+)([\s]*)/', $text, $matches, PREG_SET_ORDER); 138 139 foreach ($matches as $key => $val) { 140 if (MIME::is8bit($val[1])) { 141 if ((($key + 1) < $size) && 142 MIME::is8bit($matches[$key + 1][1])) { 143 $line .= MIME::_encode($val[1] . $val[2], $charset) . ' '; 144 } else { 145 $line .= MIME::_encode($val[1], $charset) . $val[2]; 146 } 147 } else { 148 $line .= $val[1] . $val[2]; 149 } 150 } 151 152 return rtrim($line); 153 } 154 155 /** 156 * Internal recursive function to RFC 2047 encode a string. 157 * 158 * @access private 159 * 160 * @param string $text The text to encode. 161 * @param string $charset The character set of the text. 162 * 163 * @return string The text, encoded only if it contains non-ASCII 164 * characters. 165 */ 166 function _encode($text, $charset) 167 { 168 $char_len = strlen($charset); 169 $txt_len = strlen($text) * 2; 170 171 /* RFC 2047 [2] states that no encoded word can be more than 75 172 characters long. If longer, you must split the word. */ 173 if (($txt_len + $char_len + 7) > 75) { 174 $pos = intval((68 - $char_len) / 2); 175 return MIME::_encode(substr($text, 0, $pos), $charset) . ' ' . MIME::_encode(substr($text, $pos), $charset); 176 } else { 177 return '=?' . $charset . '?b?' . trim(base64_encode($text)) . '?='; 178 } 179 } 180 181 /** 182 * Encodes a line via quoted-printable encoding. 183 * Wraps lines at 76 characters. 184 * 185 * @param string $text The text to encode. 186 * @param string $eol The EOL sequence to use. 187 * 188 * @return string The quoted-printable encoded string. 189 */ 190 function quotedPrintableEncode($text, $eol) 191 { 192 $output = ''; 193 194 foreach (preg_split("/\r?\n/", $text) as $line) { 195 /* We need to go character by character through the line. */ 196 $length = strlen($line); 197 $current_line = ''; 198 $current_length = 0; 199 200 for ($i = 0; $i < $length; $i++) { 201 $char = substr($line, $i, 1); 202 $ascii = ord($char); 203 204 /* Spaces or tabs at the end of the line are NOT allowed. 205 * Also, Characters in ASCII below 32 or above 126 AND 61 206 * must be encoded. */ 207 if (((($ascii === 9) || ($ascii === 32)) && ($i == ($length - 1))) || 208 (($ascii < 32) || ($ascii > 126) || ($ascii === 61))) { 209 $char = '=' . String::upper(sprintf('%02s', dechex($ascii))); 210 } 211 212 /* Lines must be 76 characters or less. */ 213 $char_length = strlen($char); 214 $current_length += $char_length; 215 if ($current_length > 76) { 216 $output .= $current_line . '=' . $eol; 217 $current_line = ''; 218 $current_length = $char_length; 219 } 220 $current_line .= $char; 221 } 222 $output .= $current_line . $eol; 223 } 224 225 return $output; 226 } 227 228 /** 229 * Encodes a string containing email addresses according to RFC 2047. 230 * 231 * This differs from MIME::encode() because it keeps email addresses legal, 232 * only encoding the personal information. 233 * 234 * @param string $addresses The email addresses to encode. 235 * @param string $charset The character set of the text. 236 * @param string $defserver The default domain to append to mailboxes. 237 * 238 * @return string The text, encoded only if it contains non-ascii 239 * characters. 240 */ 241 function encodeAddress($addresses, $charset = null, $defserver = null) 242 { 243 if (is_array($addresses)) { 244 $addr_arr = $addresses; 245 } else { 246 /* parseAddressList() does not process the null entry 247 * 'undisclosed-recipients:;' correctly. */ 248 if (preg_match('/undisclosed-recipients:\s*;/i', trim($addresses))) { 249 return $addresses; 250 } 251 252 require_once 'Mail/RFC822.php'; 253 $parser = &new Mail_RFC822(); 254 $addr_arr = $parser->parseAddressList($addresses, $defserver, true, false); 255 if (is_a($addr_arr, 'PEAR_Error')) { 256 return $addr_arr; 257 } 258 } 259 260 $text = ''; 261 if (is_array($addr_arr)) { 262 foreach ($addr_arr as $addr) { 263 // Check for groups. 264 if (!empty($addr->groupname)) { 265 $text .= MIME::encode($addr->groupname, $charset) . ': ' . MIME::encodeAddress($addr->addresses) . ';'; 266 continue; 267 } 268 269 if (empty($addr->personal)) { 270 $personal = ''; 271 } else { 272 if ((substr($addr->personal, 0, 1) == '"') && 273 (substr($addr->personal, -1) == '"')) { 274 $addr->personal = substr($addr->personal, 1, -1); 275 } 276 $personal = MIME::encode($addr->personal, $charset); 277 } 278 if (strlen($text) != 0) { 279 $text .= ', '; 280 } 281 $text .= MIME::trimEmailAddress(MIME::rfc822WriteAddress($addr->mailbox, $addr->host, $personal)); 282 } 283 } 284 285 return $text; 286 } 287 288 /** 289 * Decodes an RFC 2047-encoded string. 290 * 291 * @param string $string The text to decode. 292 * @param string $to_charset The charset that the text should be decoded 293 * to. 294 * 295 * @return string The decoded text. 296 */ 297 function decode($string, $to_charset = null) 298 { 299 if (($pos = strpos($string, '=?')) === false) { 300 return $string; 301 } 302 303 /* Take out any spaces between multiple encoded words. */ 304 $string = preg_replace('|\?=\s=\?|', '?==?', $string); 305 306 /* Save any preceding text. */ 307 $preceding = substr($string, 0, $pos); 308 309 $search = substr($string, $pos + 2); 310 $d1 = strpos($search, '?'); 311 if ($d1 === false) { 312 return $string; 313 } 314 315 $charset = substr($string, $pos + 2, $d1); 316 $search = substr($search, $d1 + 1); 317 318 $d2 = strpos($search, '?'); 319 if ($d2 === false) { 320 return $string; 321 } 322 323 $encoding = substr($search, 0, $d2); 324 $search = substr($search, $d2 + 1); 325 326 $end = strpos($search, '?='); 327 if ($end === false) { 328 $end = strlen($search); 329 } 330 331 $encoded_text = substr($search, 0, $end); 332 $rest = substr($string, (strlen($preceding . $charset . $encoding . $encoded_text) + 6)); 333 334 if (!isset($to_charset)) { 335 $to_charset = NLS::getCharset(); 336 } 337 338 switch ($encoding) { 339 case 'Q': 340 case 'q': 341 $encoded_text = str_replace('_', ' ', $encoded_text); 342 $decoded = preg_replace('/=([0-9a-f]{2})/ie', 'chr(0x\1)', $encoded_text); 343 $decoded = String::convertCharset($decoded, $charset, $to_charset); 344 break; 345 346 case 'B': 347 case 'b': 348 $decoded = base64_decode($encoded_text); 349 $decoded = String::convertCharset($decoded, $charset, $to_charset); 350 break; 351 352 default: 353 $decoded = '=?' . $charset . '?' . $encoding . '?' . $encoded_text . '?='; 354 break; 355 } 356 357 return $preceding . $decoded . MIME::decode($rest, $to_charset); 358 } 359 360 /** 361 * Decodes an RFC 2231-encoded string. 362 * 363 * @param string $string The entire string to decode, including the 364 * parameter name. 365 * @param string $charset The charset that the text should be decoded to. 366 * 367 * @return array The decoded text, or the original string if it was not 368 * encoded. 369 */ 370 function decodeRFC2231($string, $to_charset = null) 371 { 372 if (($pos = strpos($string, '*')) === false) { 373 return false; 374 } 375 376 if (!isset($to_charset)) { 377 $to_charset = NLS::getCharset(); 378 } 379 380 $attribute = substr($string, 0, $pos); 381 $charset = $lang = null; 382 $output = ''; 383 384 /* Get the character set and language used in the encoding, if 385 * any. */ 386 if (preg_match("/^[^=]+\*\=([^']*)'([^']*)'/", $string, $matches)) { 387 $charset = $matches[1]; 388 $lang = $matches[2]; 389 $string = str_replace($charset . "'" . $lang . "'", '', $string); 390 } 391 392 $lines = preg_split('/' . preg_quote($attribute) . '(?:\*\d)*/', $string); 393 foreach ($lines as $line) { 394 $pos = strpos($line, '*='); 395 if ($pos === 0) { 396 $line = substr($line, 2); 397 $line = str_replace('_', '%20', $line); 398 $line = str_replace('=', '%', $line); 399 $output .= urldecode($line); 400 } else { 401 $line = substr($line, 1); 402 $output .= $line; 403 } 404 } 405 406 /* RFC 2231 uses quoted printable encoding. */ 407 if (!is_null($charset)) { 408 $output = String::convertCharset($output, $charset, $to_charset); 409 } 410 411 return array( 412 'attribute' => $attribute, 413 'value' => $output 414 ); 415 } 416 417 /** 418 * If an email address has no personal information, get rid of any angle 419 * brackets (<>) around it. 420 * 421 * @param string $address The address to trim. 422 * 423 * @return string The trimmed address. 424 */ 425 function trimEmailAddress($address) 426 { 427 $address = trim($address); 428 429 if ((substr($address, 0, 1) == '<') && (substr($address, -1) == '>')) { 430 $address = substr($address, 1, -1); 431 } 432 433 return $address; 434 } 435 436 /** 437 * Builds an RFC 822 compliant email address. 438 * 439 * @param string $mailbox Mailbox name. 440 * @param string $host Domain name of mailbox's host. 441 * @param string $personal Personal name phrase. 442 * 443 * @return string The correctly escaped and quoted 444 * "$personal <$mailbox@$host>" string. 445 */ 446 function rfc822WriteAddress($mailbox, $host = null, $personal = '') 447 { 448 $address = ''; 449 450 if (!empty($personal)) { 451 $vars = get_class_vars('MIME'); 452 $address .= MIME::_rfc822Encode($personal, $vars['rfc822_filter'] . '.'); 453 $address .= ' <'; 454 } 455 456 if (!is_null($host)) { 457 $address .= MIME::_rfc822Encode($mailbox); 458 if (substr($host, 0, 1) != '@') { 459 $address .= '@' . $host; 460 } 461 } 462 463 if (!empty($personal)) { 464 $address .= '>'; 465 } 466 467 return $address; 468 } 469 470 /** 471 * Explodes a RFC 822 string, ignoring a delimiter if preceded by a "\" 472 * character, or if delimiter is inside single or double quotes. 473 * 474 * @param string $str The RFC 822 string. 475 * @param string $delimiter The delimter. 476 * 477 * @return array The exploded string in an array. 478 */ 479 function rfc822Explode($str, $delimiter) 480 { 481 $arr = array(); 482 $match = 0; 483 $quotes = array('"', "'"); 484 $in_quote = null; 485 $in_group = false; 486 $prev = null; 487 488 if (empty($str)) { 489 return array($str); 490 } 491 492 if (in_array($str{0}, $quotes)) { 493 $in_quote = $str{0}; 494 } elseif ($str{0} == ':') { 495 $in_group = true; 496 } elseif ($str{0} == $delimiter) { 497 $arr[] = ''; 498 $match = 1; 499 } 500 501 for ($i = 1; $i < strlen($str); $i++) { 502 $char = $str{$i}; 503 if (in_array($char, $quotes)) { 504 if ($prev !== '\\') { 505 if ($in_quote === $char) { 506 $in_quote = null; 507 } elseif (is_null($in_quote)) { 508 $in_quote = $char; 509 } 510 } 511 } elseif ($in_group) { 512 if ($char == ';') { 513 $arr[] = substr($str, $match, $i - $match + 1); 514 $match = $i + 1; 515 $in_group = false; 516 } 517 } elseif ($char == ':') { 518 $in_group = true; 519 } elseif ($char == $delimiter && 520 $prev !== '\\' && 521 is_null($in_quote)) { 522 $arr[] = substr($str, $match, $i - $match); 523 $match = $i + 1; 524 } 525 $prev = $char; 526 } 527 528 if ($match != $i) { 529 /* The string ended without a $delimiter. */ 530 $arr[] = substr($str, $match, $i - $match); 531 } 532 533 return $arr; 534 } 535 536 /** 537 * Takes an address object, as returned by imap_header() for example, and 538 * formats it as a string. 539 * 540 * Object format for the address "John Doe <john_doe@example.com>" is: 541 * <pre> 542 * $object->personal = Personal name ("John Doe") 543 * $object->mailbox = The user's mailbox ("john_doe") 544 * $object->host = The host the mailbox is on ("example.com") 545 * </pre> 546 * 547 * @param stdClass $ob The address object to be turned into a string. 548 * @param mixed $filter A user@example.com style bare address to ignore. 549 * Either single string or an array of strings. If 550 * the address matches $filter, an empty string will 551 * be returned. 552 * 553 * @return string The formatted address (Example: John Doe 554 * <john_doe@example.com>). 555 */ 556 function addrObject2String($ob, $filter = '') 557 { 558 /* If the personal name is set, decode it. */ 559 $ob->personal = isset($ob->personal) ? MIME::decode($ob->personal) : ''; 560 561 /* If both the mailbox and the host are empty, return an empty 562 string. If we just let this case fall through, the call to 563 MIME::rfc822WriteAddress() will end up return just a '@', which 564 is undesirable. */ 565 if (empty($ob->mailbox) && empty($ob->host)) { 566 return ''; 567 } 568 569 /* Make sure these two variables have some sort of value. */ 570 if (!isset($ob->mailbox)) { 571 $ob->mailbox = ''; 572 } elseif ($ob->mailbox == 'undisclosed-recipients') { 573 return ''; 574 } 575 if (!isset($ob->host)) { 576 $ob->host = ''; 577 } 578 579 /* Filter out unwanted addresses based on the $filter string. */ 580 if ($filter) { 581 if (!is_array($filter)) { 582 $filter = array($filter); 583 } 584 foreach ($filter as $f) { 585 if (strcasecmp($f, $ob->mailbox . '@' . $ob->host) == 0) { 586 return ''; 587 } 588 } 589 } 590 591 /* Return the trimmed, formatted email address. */ 592 return MIME::trimEmailAddress(MIME::rfc822WriteAddress($ob->mailbox, $ob->host, $ob->personal)); 593 } 594 595 /** 596 * Takes an array of address objects, as returned by imap_headerinfo(), 597 * for example, and passes each of them through MIME::addrObject2String(). 598 * 599 * @param array $addresses The array of address objects. 600 * @param mixed $filter A user@example.com style bare address to 601 * ignore. If any address matches $filter, it 602 * will not be included in the final string. 603 * 604 * @return string All of the addresses in a comma-delimited string. 605 * Returns the empty string on error/no addresses found. 606 */ 607 function addrArray2String($addresses, $filter = '') 608 { 609 $addrList = array(); 610 611 if (!is_array($addresses)) { 612 return ''; 613 } 614 615 foreach ($addresses as $addr) { 616 $val = MIME::addrObject2String($addr, $filter); 617 if (!empty($val)) { 618 $bareAddr = String::lower(MIME::bareAddress($val)); 619 if (!isset($addrList[$bareAddr])) { 620 $addrList[$bareAddr] = $val; 621 } 622 } 623 } 624 625 if (empty($addrList)) { 626 return ''; 627 } else { 628 return implode(', ', $addrList); 629 } 630 } 631 632 /** 633 * Returns the bare address. 634 * 635 * @param string $address The address string. 636 * @param string $defserver The default domain to append to mailboxes. 637 * @param boolean $multiple Should we return multiple results? 638 * 639 * @return mixed If $multiple is false, returns the mailbox@host e-mail 640 * address. If $multiple is true, returns an array of 641 * these addresses. 642 */ 643 function bareAddress($address, $defserver = null, $multiple = false) 644 { 645 $addressList = array(); 646 647 /* Use built-in IMAP function only if available and if not parsing 648 * distribution lists because it doesn't parse distribution lists 649 * properly. */ 650 if (Util::extensionExists('imap') && strpos($address, ':') === false) { 651 $from = imap_rfc822_parse_adrlist($address, $defserver); 652 } else { 653 require_once 'Mail/RFC822.php'; 654 $parser = new Mail_RFC822(); 655 $from = $parser->parseAddressList($address, $defserver, false, false); 656 if (is_a($from, 'PEAR_Error')) { 657 return $multiple ? array() : ''; 658 } 659 } 660 661 foreach ($from as $entry) { 662 if (isset($entry->mailbox) && 663 $entry->mailbox != 'undisclosed-recipients' && 664 $entry->mailbox != 'UNEXPECTED_DATA_AFTER_ADDRESS') { 665 if (isset($entry->host)) { 666 $addressList[] = $entry->mailbox . '@' . $entry->host; 667 } else { 668 $addressList[] = $entry->mailbox; 669 } 670 } 671 } 672 673 return $multiple ? $addressList : array_pop($addressList); 674 } 675 676 /** 677 * Quotes and escapes the given string if necessary. 678 * 679 * @access private 680 * 681 * @param string $str The string to be quoted and escaped. 682 * @param string $filter A list of characters that make it necessary to 683 * quote the string if they occur. 684 * 685 * @return string The correctly quoted and escaped string. 686 */ 687 function _rfc822Encode($str, $filter = '') 688 { 689 if (empty($filter)) { 690 $vars = get_class_vars('MIME'); 691 $filter = $vars['rfc822_filter'] . ' '; 692 } 693 694 // Strip double quotes if they are around the string already. 695 if (substr($str, 0, 1) == '"' && substr($str, -1) == '"') { 696 $str = substr($str, 1, -1); 697 } 698 699 if (strcspn($str, $filter) != strlen($str)) { 700 $str = str_replace('\"', '"', $str); 701 return '"' . str_replace('"', '\\"', str_replace('\\', '\\\\', $str)) . '"'; 702 } else { 703 return $str; 704 } 705 } 706 707 /** 708 * Returns the MIME type for the given input. 709 * 710 * @param mixed $input Either the MIME code or type string. 711 * @param integer $format If MIME_CODE, return code. 712 * If MIME_STRING, returns lowercase string. 713 * 714 * @return mixed See above. 715 */ 716 function type($input, $format = null) 717 { 718 return MIME::_getCode($input, $format, 'mime_types'); 719 } 720 721 /** 722 * Returns the MIME encoding for the given input. 723 * 724 * @param mixed $input Either the MIME code or encoding string. 725 * @param integer $format If MIME_CODE, return code. 726 * If MIME_STRING, returns lowercase string. 727 * If not set, returns the opposite value. 728 * 729 * @return mixed See above. 730 */ 731 function encoding($input, $format = null) 732 { 733 return MIME::_getCode($input, $format, 'mime_encodings'); 734 } 735 736 /** 737 * Retrieves MIME encoding/type data from the internal arrays. 738 * 739 * @access private 740 * 741 * @param mixed $input Either the MIME code or encoding string. 742 * @param string $format If MIME_CODE, returns code. 743 * If MIME_STRING, returns lowercase string. 744 * If null, returns the oppposite value. 745 * @param string $type The name of the internal array. 746 * 747 * @return mixed See above. 748 */ 749 function _getCode($input, $format, $type) 750 { 751 $numeric = is_numeric($input); 752 if (!$numeric) { 753 $input = String::lower($input); 754 } 755 756 switch ($format) { 757 case MIME_CODE: 758 if ($numeric) return $input; 759 break; 760 761 case MIME_STRING: 762 if (!$numeric) return $input; 763 break; 764 } 765 766 $vars = get_class_vars('MIME'); 767 768 if ($numeric) { 769 if (isset($vars[$type][$input])) { 770 return $vars[$type][$input]; 771 } 772 } else { 773 if (($search = array_search($input, $vars[$type]))) { 774 return $search; 775 } 776 } 777 778 return null; 779 } 780 781 /** 782 * Generates a Message-ID string conforming to RFC 2822 [3.6.4] and the 783 * standards outlined in 'draft-ietf-usefor-message-id-01.txt'. 784 * 785 * @param string A message ID string. 786 */ 787 function generateMessageID() 788 { 789 return '<' . date('YmdHis') . '.' . 790 substr(base_convert(microtime() . mt_rand(), 10, 36), -16) . 791 '@' . $_SERVER['SERVER_NAME'] . '>'; 792 } 793 794 /** 795 * Adds proper linebreaks to a header string. 796 * RFC 2822 [2.2.3] says that headers SHOULD be wrapped at 78 characters. 797 * However, since we may be dealing with quoted text that contains spaces, 798 * strict wrapping at 78 characters may add unwanted newlines and tabs to 799 * the quoted parameter. The correct way to get around this is to encode 800 * paraeters according to RFC 2231. However, since most mailers do not 801 * seem to support this, we will instead simply use long lines. RFC 2822 802 * says headers SHOULD only be 78 characters a line, but also says that 803 * a header line MUST not be more than 998 characters. Therefore, the 804 * compromise is to put each parameter on a separate line and chop it 805 * only if it is longer than 998 characters. 806 * 807 * @param string $header The header name. 808 * @param string $text The text of the header field. 809 * @param string $eol The EOL string to use. 810 * 811 * @return string The header text, with linebreaks inserted. 812 */ 813 function wrapHeaders($header, $text, $eol = "\r\n") 814 { 815 $header = rtrim($header); 816 817 /* Remove any existing linebreaks. */ 818 $text = preg_replace("/\r?\n\s?/", ' ', $text); 819 $text = $header . ': ' . rtrim($text); 820 821 $eollength = strlen($eol); 822 $header_lower = strtolower($header); 823 824 if (($header_lower != 'content-type') && 825 ($header_lower != 'content-disposition')) { 826 /* Wrap the line. */ 827 $line = wordwrap($text, 75, $eol . "\t"); 828 829 /* Make sure there are no empty lines. */ 830 $line = preg_replace('/' . $eol . "\t\s*" . $eol . "\t/", '/' . $eol . "\t/", $line); 831 832 return substr($line, strlen($header) + 2); 833 } 834 835 /* Split the line by the RFC parameter separator ';'. */ 836 $params = preg_split("/\s*;\s*/", $text); 837 838 $line = ''; 839 $length = 1000 - $eollength; 840 $paramcount = count($params); 841 842 foreach ($params as $count => $val) { 843 /* If longer than RFC allows, then simply chop off the excess. */ 844 $moreparams = (($count + 1) != $paramcount); 845 $maxlength = $length - (!empty($line) ? 1 : 0) - (($moreparams) ? 1 : 0); 846 if (strlen($val) > $maxlength) { 847 $val = substr($val, 0, $maxlength); 848 849 /* If we have an opening quote, add a closing quote after 850 * chopping the rest of the text. */ 851 if (strpos($val, '"') !== false) { 852 $val = substr($val, 0, -1); 853 $val .= '"'; 854 } 855 856 } 857 858 if (!empty($line)) { 859 $line .= "\t"; 860 } 861 $line .= $val . (($moreparams) ? ';' : '') . $eol; 862 } 863 864 return substr($line, strlen($header) + 2, ($eollength * -1)); 865 } 866 867 }
titre
Description
Corps
titre
Description
Corps
titre
Description
Corps
titre
Corps
Généré le : Sun Feb 25 18:01:28 2007 | par Balluche grâce à PHPXref 0.7 |