# MailAddress.class.php

Go to the documentation of this file.

    00001 <?php
    00002 /***************************************************************************
    00003  *   Copyright (C) 2009 by Ivan Y. Khvostishkov                            *
    00004  *                                                                         *
    00005  *   This program is free software; you can redistribute it and/or modify  *
    00006  *   it under the terms of the GNU Lesser General Public License as        *
    00007  *   published by the Free Software Foundation; either version 3 of the    *
    00008  *   License, or (at your option) any later version.                       *
    00009  *                                                                         *
    00010  ***************************************************************************/
    00011
    00019     final class MailAddress
    00020     {
    00021         const RFC_MAX_ENCODED_WORD_LENGTH = 75;
    00022
    00023         private $address    = null;
    00024         private $person     = null;
    00025         private $charset    = 'UTF-8';
    00026
    00027         public static function create()
    00028         {
    00029             return new self;
    00030         }
    00031
    00032         public function setAddress($address)
    00033         {
    00034             $this->address = $address;
    00035
    00036             return $this;
    00037         }
    00038
    00039         public function getAddress()
    00040         {
    00041             return $this->address;
    00042         }
    00043
    00044         public function setPerson($person)
    00045         {
    00046             $this->person = $person;
    00047
    00048             return $this;
    00049         }
    00050
    00051         public function getPerson()
    00052         {
    00053             return $this->person;
    00054         }
    00055
    00056         public function setCharset($charset)
    00057         {
    00058             $this->charset = $charset;
    00059
    00060             return $this;
    00061         }
    00062
    00063         public function getCharset()
    00064         {
    00065             return $this->charset;
    00066         }
    00067
    00068         public function toString()
    00069         {
    00070             $specials = preg_quote('()<>@,;:".[]\\', '/');
    00071             $cr = '\015';
    00072             $space = '\ ';
    00073
    00074             $ctls = '\000-\037\177';
    00075             $char = '\000-\177';
    00076
    00077             $atom = "[^{$specials}{$space}{$ctls}]+";
    00078             $asciiAtom = "[$char]+";
    00079
    00080             if (
    00081                 !preg_match($this->getAddressRegExp($asciiAtom), $this->address)
    00082                 || !preg_match($this->getAddressRegExp($atom), $this->address)
    00083             )
    00084                 throw new WrongArgumentException(
    00085                     'wrongly formatted address is encountered'
    00086                     .' or local-part contains quoted-string'
    00087                     .' or domain contains domain-literal (unimplemented yet)'
    00088                 );
    00089
    00090             if (!$this->person)
    00091                 return $this->address;
    00092
    00093
    00094             $person = $this->person;
    00095
    00096             if (
    00097                 !preg_match($this->getUnquotedPhraseRegexp($asciiAtom), $person)
    00098                 || !preg_match($this->getUnquotedPhraseRegexp($atom), $person)
    00099             ) {
    00100                 // TODO: linear-white-space instead of simple space may be here
    00101                 $qtextWithNoExceptions = "[$char\ ]";
    00102                 $qtextExceptions = "[$cr\"\\\\]";
    00103
    00104                 // TODO: quoted-pair inside quoted-string is allowed too
    00105                 if (
    00106                     preg_match("/^{$qtextWithNoExceptions}*$/u", $person)
    00107                     && !preg_match("/{$qtextExceptions}/", $person)
    00108                 ) {
    00109                     $person = '"'.$person.'"';
    00110
    00111                 } else {
    00112                     $person = $this->getEncodedPerson();
    00113                 }
    00114             }
    00115
    00116             return "$person <{$this->address}>";
    00117         }
    00118
    00119         private function getAddressRegExp($atom)
    00120         {
    00121             // TODO: word may be a quoted-string also
    00122             $word = $atom;
    00123
    00124             $localPart = "{$word}(\.{$word})*";
    00125
    00126             $domainRef = $atom;
    00127
    00128             // TODO: sub-domain may be a domain-literal also
    00129             $subDomain = $domainRef;
    00130
    00131             $domain = "{$subDomain}(\.{$subDomain})*";
    00132
    00133             $addrSpec = "{$localPart}@{$domain}";
    00134
    00135             return "/^{$addrSpec}$/";
    00136         }
    00137
    00138         private function getUnquotedPhraseRegexp($atom)
    00139         {
    00140             return "/^({$atom})(\ {$atom})*$/u";
    00141         }
    00142
    00143         private function getEncodedWord($word)
    00144         {
    00145             return "=?{$this->charset}?B?".base64_encode($word)."?=";
    00146         }
    00147
    00148         private function getEncodedPerson()
    00149         {
    00150             $result = null;
    00151
    00152             $personChunk = null;
    00153
    00154             for ($i = 0; $i < mb_strlen($this->person); $i++) {
    00155                 $symbol = mb_substr($this->person, $i, 1);
    00156
    00157                 $newLength = strlen(
    00158                     $this->getEncodedWord($personChunk.$symbol)
    00159                 );
    00160
    00161                 if ($newLength >= self::RFC_MAX_ENCODED_WORD_LENGTH) {
    00162                     $result = $this->appendChunk($result, $personChunk);
    00163
    00164                     $personChunk = null;
    00165                 }
    00166
    00167                 $personChunk .= $symbol;
    00168             }
    00169
    00170             if ($personChunk)
    00171                 $result = $this->appendChunk($result, $personChunk);
    00172
    00173             return $result;
    00174         }
    00175
    00176         private function appendChunk($encodedPerson, $personChunk)
    00177         {
    00178             $crlfSpace = "\015\012 ";
    00179
    00180             return
    00181                 $encodedPerson
    00182                 .($encodedPerson ? $crlfSpace : null)
    00183                 .$this->getEncodedWord($personChunk);
    00184         }
    00185     }
    00186 ?>