[ Index ] |
PHP Cross Reference of Unnamed Project |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * Copyright (c) 2001-2010, Richard Heyes 4 * Copyright 2011-2014 Horde LLC (http://www.horde.org/) 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * o Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * o Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * o The names of the authors may not be used to endorse or promote 17 * products derived from this software without specific prior written 18 * permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 * 32 * RFC822 parsing code adapted from message-address.c and rfc822-parser.c 33 * (Dovecot 2.1rc5) 34 * Original code released under LGPL-2.1 35 * Copyright (c) 2002-2011 Timo Sirainen <tss@iki.fi> 36 * 37 * @category Horde 38 * @copyright 2001-2010 Richard Heyes 39 * @copyright 2002-2011 Timo Sirainen 40 * @copyright 2011-2014 Horde LLC 41 * @license http://www.horde.org/licenses/bsd New BSD License 42 * @package Mail 43 */ 44 45 /** 46 * RFC 822/2822/3490/5322 Email parser/validator. 47 * 48 * @author Richard Heyes <richard@phpguru.org> 49 * @author Chuck Hagenbuch <chuck@horde.org> 50 * @author Michael Slusarz <slusarz@horde.org> 51 * @author Timo Sirainen <tss@iki.fi> 52 * @category Horde 53 * @copyright 2001-2010 Richard Heyes 54 * @copyright 2002-2011 Timo Sirainen 55 * @copyright 2011-2014 Horde LLC 56 * @license http://www.horde.org/licenses/bsd New BSD License 57 * @package Mail 58 */ 59 class Horde_Mail_Rfc822 60 { 61 /** 62 * Valid atext characters. 63 * 64 * @since 2.0.3 65 */ 66 const ATEXT = '!#$%&\'*+-./0123456789=?ABCDEFGHIJKLMNOPQRSTUVWXYZ^_`abcdefghijklmnopqrstuvwxyz{|}~'; 67 68 /** 69 * Excluded (in ASCII): 0-8, 10-31, 34, 40-41, 44, 58-60, 62, 64, 70 * 91-93, 127 71 * 72 * @since 2.0.3 73 */ 74 const ENCODE_FILTER = "\0\1\2\3\4\5\6\7\10\12\13\14\15\16\17\20\21\22\23\24\25\26\27\30\31\32\33\34\35\36\37\"(),:;<>@[\\]\177"; 75 76 /** 77 * The address string to parse. 78 * 79 * @var string 80 */ 81 protected $_data; 82 83 /** 84 * Length of the address string. 85 * 86 * @var integer 87 */ 88 protected $_datalen; 89 90 /** 91 * Comment cache. 92 * 93 * @var string 94 */ 95 protected $_comments = array(); 96 97 /** 98 * List object to return in parseAddressList(). 99 * 100 * @var Horde_Mail_Rfc822_List 101 */ 102 protected $_listob; 103 104 /** 105 * Configuration parameters. 106 * 107 * @var array 108 */ 109 protected $_params = array(); 110 111 /** 112 * Data pointer. 113 * 114 * @var integer 115 */ 116 protected $_ptr; 117 118 /** 119 * Starts the whole process. 120 * 121 * @param mixed $address The address(es) to validate. Either a string, 122 * a Horde_Mail_Rfc822_Object, or an array of 123 * strings and/or Horde_Mail_Rfc822_Objects. 124 * @param array $params Optional parameters: 125 * - default_domain: (string) Default domain/host. 126 * DEFAULT: None 127 * - group: (boolean) Return a GroupList object instead of a List object? 128 * DEFAULT: false 129 * - limit: (integer) Stop processing after this many addresses. 130 * DEFAULT: No limit (0) 131 * - validate: (boolean) Strict validation of personal part data? If 132 * true, throws an Exception on error. If false, attempts 133 * to allow non-ASCII characters and non-quoted strings in 134 * the personal data, and will silently abort if an 135 * unparseable address is found. 136 * DEFAULT: false 137 * 138 * @return Horde_Mail_Rfc822_List A list object. 139 * 140 * @throws Horde_Mail_Exception 141 */ 142 public function parseAddressList($address, array $params = array()) 143 { 144 if ($address instanceof Horde_Mail_Rfc822_List) { 145 return $address; 146 } 147 148 if (empty($params['limit'])) { 149 $params['limit'] = -1; 150 } 151 152 $this->_params = array_merge(array( 153 'default_domain' => null, 154 'validate' => false 155 ), $params); 156 157 $this->_listob = empty($this->_params['group']) 158 ? new Horde_Mail_Rfc822_List() 159 : new Horde_Mail_Rfc822_GroupList(); 160 161 if (!is_array($address)) { 162 $address = array($address); 163 } 164 165 $tmp = array(); 166 foreach ($address as $val) { 167 if ($val instanceof Horde_Mail_Rfc822_Object) { 168 $this->_listob->add($val); 169 } else { 170 $tmp[] = rtrim(trim($val), ','); 171 } 172 } 173 174 if (!empty($tmp)) { 175 $this->_data = implode(',', $tmp); 176 $this->_datalen = strlen($this->_data); 177 $this->_ptr = 0; 178 179 $this->_parseAddressList(); 180 } 181 182 $ret = $this->_listob; 183 unset($this->_listob); 184 185 return $ret; 186 } 187 188 /** 189 * Quotes and escapes the given string if necessary using rules contained 190 * in RFC 2822 [3.2.5]. 191 * 192 * @param string $str The string to be quoted and escaped. 193 * @param string $type Either 'address', or 'personal'. 194 * 195 * @return string The correctly quoted and escaped string. 196 */ 197 public function encode($str, $type = 'address') 198 { 199 switch ($type) { 200 case 'personal': 201 // RFC 2822 [3.4]: Period not allowed in display name 202 $filter = '.'; 203 break; 204 205 case 'address': 206 default: 207 // RFC 2822 [3.4.1]: (HTAB, SPACE) not allowed in address 208 $filter = "\11\40"; 209 break; 210 } 211 212 // Strip double quotes if they are around the string already. 213 // If quoted, we know that the contents are already escaped, so 214 // unescape now. 215 $str = trim($str); 216 if ($str && ($str[0] == '"') && (substr($str, -1) == '"')) { 217 $str = stripslashes(substr($str, 1, -1)); 218 } 219 220 return (strcspn($str, self::ENCODE_FILTER . $filter) != strlen($str)) 221 ? '"' . addcslashes($str, '\\"') . '"' 222 : $str; 223 } 224 225 /** 226 * If an email address has no personal information, get rid of any angle 227 * brackets (<>) around it. 228 * 229 * @param string $address The address to trim. 230 * 231 * @return string The trimmed address. 232 */ 233 public function trimAddress($address) 234 { 235 $address = trim($address); 236 237 return (($address[0] == '<') && (substr($address, -1) == '>')) 238 ? substr($address, 1, -1) 239 : $address; 240 } 241 242 /* RFC 822 parsing methods. */ 243 244 /** 245 * address-list = (address *("," address)) / obs-addr-list 246 */ 247 protected function _parseAddressList() 248 { 249 $limit = $this->_params['limit']; 250 251 while (($this->_curr() !== false) && ($limit-- !== 0)) { 252 try { 253 $this->_parseAddress(); 254 } catch (Horde_Mail_Exception $e) { 255 if ($this->_params['validate']) { 256 throw $e; 257 } 258 ++$this->_ptr; 259 } 260 261 switch ($this->_curr()) { 262 case ',': 263 $this->_rfc822SkipLwsp(true); 264 break; 265 266 case false: 267 // No-op 268 break; 269 270 default: 271 if ($this->_params['validate']) { 272 throw new Horde_Mail_Exception('Error when parsing address list.'); 273 } 274 break; 275 } 276 } 277 } 278 279 /** 280 * address = mailbox / group 281 */ 282 protected function _parseAddress() 283 { 284 $start = $this->_ptr; 285 if (!$this->_parseGroup()) { 286 $this->_ptr = $start; 287 if ($mbox = $this->_parseMailbox()) { 288 $this->_listob->add($mbox); 289 } 290 } 291 } 292 293 /** 294 * group = display-name ":" [mailbox-list / CFWS] ";" [CFWS] 295 * display-name = phrase 296 * 297 * @return boolean True if a group was parsed. 298 * 299 * @throws Horde_Mail_Exception 300 */ 301 protected function _parseGroup() 302 { 303 $this->_rfc822ParsePhrase($groupname); 304 305 if ($this->_curr(true) != ':') { 306 return false; 307 } 308 309 $addresses = new Horde_Mail_Rfc822_GroupList(); 310 311 $this->_rfc822SkipLwsp(); 312 313 while (($chr = $this->_curr()) !== false) { 314 if ($chr == ';') { 315 ++$this->_ptr; 316 317 if (count($addresses)) { 318 $this->_listob->add(new Horde_Mail_Rfc822_Group($groupname, $addresses)); 319 } 320 321 return true; 322 } 323 324 /* mailbox-list = (mailbox *("," mailbox)) / obs-mbox-list */ 325 $addresses->add($this->_parseMailbox()); 326 327 switch ($this->_curr()) { 328 case ',': 329 $this->_rfc822SkipLwsp(true); 330 break; 331 332 case ';': 333 // No-op 334 break; 335 336 default: 337 break 2; 338 } 339 } 340 341 throw new Horde_Mail_Exception('Error when parsing group.'); 342 } 343 344 /** 345 * mailbox = name-addr / addr-spec 346 * 347 * @return mixed Mailbox object if mailbox was parsed, or false. 348 */ 349 protected function _parseMailbox() 350 { 351 $this->_comments = array(); 352 $start = $this->_ptr; 353 354 if (!($ob = $this->_parseNameAddr())) { 355 $this->_comments = array(); 356 $this->_ptr = $start; 357 $ob = $this->_parseAddrSpec(); 358 } 359 360 if ($ob) { 361 $ob->comment = $this->_comments; 362 } 363 364 return $ob; 365 } 366 367 /** 368 * name-addr = [display-name] angle-addr 369 * display-name = phrase 370 * 371 * @return mixed Mailbox object, or false. 372 */ 373 protected function _parseNameAddr() 374 { 375 $this->_rfc822ParsePhrase($personal); 376 377 if ($ob = $this->_parseAngleAddr()) { 378 $ob->personal = $personal; 379 return $ob; 380 } 381 382 return false; 383 } 384 385 /** 386 * addr-spec = local-part "@" domain 387 * 388 * @return mixed Mailbox object. 389 * 390 * @throws Horde_Mail_Exception 391 */ 392 protected function _parseAddrSpec() 393 { 394 $ob = new Horde_Mail_Rfc822_Address(); 395 $ob->mailbox = $this->_parseLocalPart(); 396 397 if ($this->_curr() == '@') { 398 try { 399 $this->_rfc822ParseDomain($host); 400 if (strlen($host)) { 401 $ob->host = $host; 402 } 403 } catch (Horde_Mail_Exception $e) { 404 if (!empty($this->_params['validate'])) { 405 throw $e; 406 } 407 } 408 } 409 410 if (is_null($ob->host)) { 411 if (!is_null($this->_params['default_domain'])) { 412 $ob->host = $this->_params['default_domain']; 413 } elseif (!empty($this->_params['validate'])) { 414 throw new Horde_Mail_Exception('Address is missing domain.'); 415 } 416 } 417 418 return $ob; 419 } 420 421 /** 422 * local-part = dot-atom / quoted-string / obs-local-part 423 * obs-local-part = word *("." word) 424 * 425 * @return string The local part. 426 * 427 * @throws Horde_Mail_Exception 428 */ 429 protected function _parseLocalPart() 430 { 431 if (($curr = $this->_curr()) === false) { 432 throw new Horde_Mail_Exception('Error when parsing local part.'); 433 } 434 435 if ($curr == '"') { 436 $this->_rfc822ParseQuotedString($str); 437 } else { 438 $this->_rfc822ParseDotAtom($str, ',;@'); 439 } 440 441 return $str; 442 } 443 444 /** 445 * "<" [ "@" route ":" ] local-part "@" domain ">" 446 * 447 * @return mixed Mailbox object, or false. 448 * 449 * @throws Horde_Mail_Exception 450 */ 451 protected function _parseAngleAddr() 452 { 453 if ($this->_curr() != '<') { 454 return false; 455 } 456 457 $this->_rfc822SkipLwsp(true); 458 459 if ($this->_curr() == '@') { 460 // Route information is ignored. 461 $this->_parseDomainList(); 462 if ($this->_curr() != ':') { 463 throw new Horde_Mail_Exception('Invalid route.'); 464 } 465 466 $this->_rfc822SkipLwsp(true); 467 } 468 469 $ob = $this->_parseAddrSpec(); 470 471 if ($this->_curr() != '>') { 472 throw new Horde_Mail_Exception('Error when parsing angle address.'); 473 } 474 475 $this->_rfc822SkipLwsp(true); 476 477 return $ob; 478 } 479 480 /** 481 * obs-domain-list = "@" domain *(*(CFWS / "," ) [CFWS] "@" domain) 482 * 483 * @return array Routes. 484 * 485 * @throws Horde_Mail_Exception 486 */ 487 protected function _parseDomainList() 488 { 489 $route = array(); 490 491 while ($this->_curr() !== false) { 492 $this->_rfc822ParseDomain($str); 493 $route[] = '@' . $str; 494 495 $this->_rfc822SkipLwsp(); 496 if ($this->_curr() != ',') { 497 return $route; 498 } 499 ++$this->_ptr; 500 } 501 502 throw new Horde_Mail_Exception('Invalid domain list.'); 503 } 504 505 /* RFC 822 parsing methods. */ 506 507 /** 508 * phrase = 1*word / obs-phrase 509 * word = atom / quoted-string 510 * obs-phrase = word *(word / "." / CFWS) 511 * 512 * @param string &$phrase The phrase data. 513 * 514 * @throws Horde_Mail_Exception 515 */ 516 protected function _rfc822ParsePhrase(&$phrase) 517 { 518 $curr = $this->_curr(); 519 if (($curr === false) || ($curr == '.')) { 520 throw new Horde_Mail_Exception('Error when parsing a group.'); 521 } 522 523 do { 524 if ($curr == '"') { 525 $this->_rfc822ParseQuotedString($phrase); 526 } else { 527 $this->_rfc822ParseAtomOrDot($phrase); 528 } 529 530 $curr = $this->_curr(); 531 if (($curr != '"') && 532 ($curr != '.') && 533 !$this->_rfc822IsAtext($curr)) { 534 break; 535 } 536 537 $phrase .= ' '; 538 } while ($this->_ptr < $this->_datalen); 539 540 $this->_rfc822SkipLwsp(); 541 } 542 543 /** 544 * @param string &$phrase The quoted string data. 545 * 546 * @throws Horde_Mail_Exception 547 */ 548 protected function _rfc822ParseQuotedString(&$str) 549 { 550 if ($this->_curr(true) != '"') { 551 throw new Horde_Mail_Exception('Error when parsing a quoted string.'); 552 } 553 554 while (($chr = $this->_curr(true)) !== false) { 555 switch ($chr) { 556 case '"': 557 $this->_rfc822SkipLwsp(); 558 return; 559 560 case "\n": 561 /* Folding whitespace, remove the (CR)LF. */ 562 if (substr($str, -1) == "\r") { 563 $str = substr($str, 0, -1); 564 } 565 continue; 566 567 case '\\': 568 if (($chr = $this->_curr(true)) === false) { 569 break 2; 570 } 571 break; 572 } 573 574 $str .= $chr; 575 } 576 577 /* Missing trailing '"', or partial quoted character. */ 578 throw new Horde_Mail_Exception('Error when parsing a quoted string.'); 579 } 580 581 /** 582 * dot-atom = [CFWS] dot-atom-text [CFWS] 583 * dot-atom-text = 1*atext *("." 1*atext) 584 * 585 * atext = ; Any character except controls, SP, and specials. 586 * 587 * For RFC-822 compatibility allow LWSP around '.' 588 * 589 * @param string &$str The atom/dot data. 590 * @param string $validate Use these characters as delimiter. 591 * 592 * @throws Horde_Mail_Exception 593 */ 594 protected function _rfc822ParseDotAtom(&$str, $validate = null) 595 { 596 $is_validate = $this->_params['validate']; 597 $valid = false; 598 599 while ($this->_ptr < $this->_datalen) { 600 $chr = $this->_data[$this->_ptr]; 601 602 /* $this->_rfc822IsAtext($chr, $validate); 603 * Optimization: Function would be called excessively in this 604 * loop, so eliminate function call overhead. */ 605 if (($is_validate && !strcspn($chr, self::ATEXT)) || 606 (!$is_validate && strcspn($chr, $validate))) { 607 $str .= $chr; 608 ++$this->_ptr; 609 } elseif (!$valid) { 610 throw new Horde_Mail_Exception('Error when parsing dot-atom.'); 611 } else { 612 $this->_rfc822SkipLwsp(); 613 614 if ($this->_curr() != '.') { 615 return; 616 } 617 $str .= $chr; 618 619 $this->_rfc822SkipLwsp(true); 620 } 621 622 $valid = true; 623 } 624 } 625 626 /** 627 * atom = [CFWS] 1*atext [CFWS] 628 * atext = ; Any character except controls, SP, and specials. 629 * 630 * This method doesn't just silently skip over WS. 631 * 632 * @param string &$str The atom/dot data. 633 * 634 * @throws Horde_Mail_Exception 635 */ 636 protected function _rfc822ParseAtomOrDot(&$str) 637 { 638 $validate = $this->_params['validate']; 639 640 while ($this->_ptr < $this->_datalen) { 641 $chr = $this->_data[$this->_ptr]; 642 if (($chr != '.') && 643 /* !$this->_rfc822IsAtext($chr, ',<:'); 644 * Optimization: Function would be called excessively in this 645 * loop, so eliminate function call overhead. */ 646 !(($validate && !strcspn($chr, self::ATEXT)) || 647 (!$validate && strcspn($chr, ',<:')))) { 648 $this->_rfc822SkipLwsp(); 649 if (!$validate) { 650 $str = trim($str); 651 } 652 return; 653 } 654 655 $str .= $chr; 656 ++$this->_ptr; 657 } 658 } 659 660 /** 661 * domain = dot-atom / domain-literal / obs-domain 662 * domain-literal = [CFWS] "[" *([FWS] dcontent) [FWS] "]" [CFWS] 663 * obs-domain = atom *("." atom) 664 * 665 * @param string &$str The domain string. 666 * 667 * @throws Horde_Mail_Exception 668 */ 669 protected function _rfc822ParseDomain(&$str) 670 { 671 if ($this->_curr(true) != '@') { 672 throw new Horde_Mail_Exception('Error when parsing domain.'); 673 } 674 675 $this->_rfc822SkipLwsp(); 676 677 if ($this->_curr() == '[') { 678 $this->_rfc822ParseDomainLiteral($str); 679 } else { 680 $this->_rfc822ParseDotAtom($str, ';,> '); 681 } 682 } 683 684 /** 685 * domain-literal = [CFWS] "[" *([FWS] dcontent) [FWS] "]" [CFWS] 686 * dcontent = dtext / quoted-pair 687 * dtext = NO-WS-CTL / ; Non white space controls 688 * %d33-90 / ; The rest of the US-ASCII 689 * %d94-126 ; characters not including "[", 690 * ; "]", or "\" 691 * 692 * @param string &$str The domain string. 693 * 694 * @throws Horde_Mail_Exception 695 */ 696 protected function _rfc822ParseDomainLiteral(&$str) 697 { 698 if ($this->_curr(true) != '[') { 699 throw new Horde_Mail_Exception('Error parsing domain literal.'); 700 } 701 702 while (($chr = $this->_curr(true)) !== false) { 703 switch ($chr) { 704 case '\\': 705 if (($chr = $this->_curr(true)) === false) { 706 break 2; 707 } 708 break; 709 710 case ']': 711 $this->_rfc822SkipLwsp(); 712 return; 713 } 714 715 $str .= $chr; 716 } 717 718 throw new Horde_Mail_Exception('Error parsing domain literal.'); 719 } 720 721 /** 722 * @param boolean $advance Advance cursor? 723 * 724 * @throws Horde_Mail_Exception 725 */ 726 protected function _rfc822SkipLwsp($advance = false) 727 { 728 if ($advance) { 729 ++$this->_ptr; 730 } 731 732 while (($chr = $this->_curr()) !== false) { 733 switch ($chr) { 734 case ' ': 735 case "\n": 736 case "\r": 737 case "\t": 738 ++$this->_ptr; 739 continue; 740 741 case '(': 742 $this->_rfc822SkipComment(); 743 break; 744 745 default: 746 return; 747 } 748 } 749 } 750 751 /** 752 * @throws Horde_Mail_Exception 753 */ 754 protected function _rfc822SkipComment() 755 { 756 if ($this->_curr(true) != '(') { 757 throw new Horde_Mail_Exception('Error when parsing a comment.'); 758 } 759 760 $comment = ''; 761 $level = 1; 762 763 while (($chr = $this->_curr(true)) !== false) { 764 switch ($chr) { 765 case '(': 766 ++$level; 767 continue; 768 769 case ')': 770 if (--$level == 0) { 771 $this->_comments[] = $comment; 772 return; 773 } 774 break; 775 776 case '\\': 777 if (($chr = $this->_curr(true)) === false) { 778 break 2; 779 } 780 break; 781 } 782 783 $comment .= $chr; 784 } 785 786 throw new Horde_Mail_Exception('Error when parsing a comment.'); 787 } 788 789 /** 790 * Check if data is an atom. 791 * 792 * @param string $chr The character to check. 793 * @param string $validate If in non-validate mode, use these characters 794 * as the non-atom delimiters. 795 * 796 * @return boolean True if an atom. 797 */ 798 protected function _rfc822IsAtext($chr, $validate = null) 799 { 800 return (!$this->_params['validate'] && !is_null($validate)) 801 ? strcspn($chr, $validate) 802 : !strcspn($chr, self::ATEXT); 803 } 804 805 /* Helper methods. */ 806 807 /** 808 * Return current character. 809 * 810 * @param boolean $advance If true, advance the cursor. 811 * 812 * @return string The current character (false if EOF reached). 813 */ 814 protected function _curr($advance = false) 815 { 816 return ($this->_ptr >= $this->_datalen) 817 ? false 818 : $this->_data[$advance ? $this->_ptr++ : $this->_ptr]; 819 } 820 821 /* Other public methods. */ 822 823 /** 824 * Returns an approximate count of how many addresses are in the string. 825 * This is APPROXIMATE as it only splits based on a comma which has no 826 * preceding backslash. 827 * 828 * @param string $data Addresses to count. 829 * 830 * @return integer Approximate count. 831 */ 832 public function approximateCount($data) 833 { 834 return count(preg_split('/(?<!\\\\),/', $data)); 835 } 836 837 /** 838 * Validates whether an email is of the common internet form: 839 * <user>@<domain>. This can be sufficient for most people. 840 * 841 * Optional stricter mode can be utilized which restricts mailbox 842 * characters allowed to: alphanumeric, full stop, hyphen, and underscore. 843 * 844 * @param string $data Address to check. 845 * @param boolean $strict Strict check? 846 * 847 * @return mixed False if it fails, an indexed array username/domain if 848 * it matches. 849 */ 850 public function isValidInetAddress($data, $strict = false) 851 { 852 $regex = $strict 853 ? '/^([.0-9a-z_+-]+)@(([0-9a-z-]+\.)+[0-9a-z]{2,})$/i' 854 : '/^([*+!.&#$|\'\\%\/0-9a-z^_`{}=?~:-]+)@(([0-9a-z-]+\.)+[0-9a-z]{2,})$/i'; 855 856 return preg_match($regex, trim($data), $matches) 857 ? array($matches[1], $matches[2]) 858 : false; 859 } 860 861 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Thu Aug 11 10:00:09 2016 | Cross-referenced by PHPXref 0.7.1 |