Skip to content
Snippets Groups Projects
Commit e3f42c33 authored by JediKev's avatar JediKev
Browse files

issue: Umlauts In Sender's Name

This addresses issue 4884 where sending an email with Umlauts in the From
Name causes the User's Name and Email to be malformed. This is due to
outdated RFC822 from Pear. This replaces the old RFC822 Pear module with the
latest release so that we are up to date.
parent fe28bc52
No related branches found
No related tags found
No related merge requests found
...@@ -2,31 +2,33 @@ ...@@ -2,31 +2,33 @@
/** /**
* RFC 822 Email address list validation Utility * RFC 822 Email address list validation Utility
* *
* PHP versions 4 and 5 * PHP version 5
* *
* LICENSE: * LICENSE:
* *
* Copyright (c) 2001-2010, Richard Heyes * Copyright (c) 2001-2017, Chuck Hagenbuch & Richard Heyes
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions * modification, are permitted provided that the following conditions
* are met: * are met:
* *
* o Redistributions of source code must retain the above copyright * 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer. * notice, this list of conditions and the following disclaimer.
* o Redistributions in binary form must reproduce the above copyright *
* notice, this list of conditions and the following disclaimer in the * 2. Redistributions in binary form must reproduce the above copyright
* documentation and/or other materials provided with the distribution. * notice, this list of conditions and the following disclaimer in the
* o The names of the authors may not be used to endorse or promote * documentation and/or other materials provided with the distribution.
* products derived from this software without specific prior written *
* permission. * 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* *
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
...@@ -38,9 +40,9 @@ ...@@ -38,9 +40,9 @@
* @package Mail * @package Mail
* @author Richard Heyes <richard@phpguru.org> * @author Richard Heyes <richard@phpguru.org>
* @author Chuck Hagenbuch <chuck@horde.org * @author Chuck Hagenbuch <chuck@horde.org
* @copyright 2001-2010 Richard Heyes * @copyright 2001-2017 Richard Heyes
* @license http://opensource.org/licenses/bsd-license.php New BSD License * @license http://opensource.org/licenses/BSD-3-Clause New BSD License
* @version CVS: $Id: RFC822.php 294749 2010-02-08 08:22:25Z clockwerx $ * @version CVS: $Id$
* @link http://pear.php.net/package/Mail/ * @link http://pear.php.net/package/Mail/
*/ */
...@@ -63,7 +65,7 @@ ...@@ -63,7 +65,7 @@
* *
* @author Richard Heyes <richard@phpguru.org> * @author Richard Heyes <richard@phpguru.org>
* @author Chuck Hagenbuch <chuck@horde.org> * @author Chuck Hagenbuch <chuck@horde.org>
* @version $Revision: 294749 $ * @version $Revision$
* @license BSD * @license BSD
* @package Mail * @package Mail
*/ */
...@@ -141,7 +143,6 @@ class Mail_RFC822 { ...@@ -141,7 +143,6 @@ class Mail_RFC822 {
* Sets up the object. The address must either be set here or when * Sets up the object. The address must either be set here or when
* calling parseAddressList(). One or the other. * calling parseAddressList(). One or the other.
* *
* @access public
* @param string $address The address(es) to validate. * @param string $address The address(es) to validate.
* @param string $default_domain Default domain/host etc. If not supplied, will be set to localhost. * @param string $default_domain Default domain/host etc. If not supplied, will be set to localhost.
* @param boolean $nest_groups Whether to return the structure with groups nested for easier viewing. * @param boolean $nest_groups Whether to return the structure with groups nested for easier viewing.
...@@ -149,7 +150,7 @@ class Mail_RFC822 { ...@@ -149,7 +150,7 @@ class Mail_RFC822 {
* *
* @return object Mail_RFC822 A new Mail_RFC822 object. * @return object Mail_RFC822 A new Mail_RFC822 object.
*/ */
function __construct($address = null, $default_domain = null, $nest_groups = null, $validate = null, $limit = null) public function __construct($address = null, $default_domain = null, $nest_groups = null, $validate = null, $limit = null)
{ {
if (isset($address)) $this->address = $address; if (isset($address)) $this->address = $address;
if (isset($default_domain)) $this->default_domain = $default_domain; if (isset($default_domain)) $this->default_domain = $default_domain;
...@@ -162,7 +163,6 @@ class Mail_RFC822 { ...@@ -162,7 +163,6 @@ class Mail_RFC822 {
* Starts the whole process. The address must either be set here * Starts the whole process. The address must either be set here
* or when creating the object. One or the other. * or when creating the object. One or the other.
* *
* @access public
* @param string $address The address(es) to validate. * @param string $address The address(es) to validate.
* @param string $default_domain Default domain/host etc. * @param string $default_domain Default domain/host etc.
* @param boolean $nest_groups Whether to return the structure with groups nested for easier viewing. * @param boolean $nest_groups Whether to return the structure with groups nested for easier viewing.
...@@ -170,7 +170,7 @@ class Mail_RFC822 { ...@@ -170,7 +170,7 @@ class Mail_RFC822 {
* *
* @return array A structured array of addresses. * @return array A structured array of addresses.
*/ */
function parseAddressList($address = null, $default_domain = null, $nest_groups = null, $validate = null, $limit = null) public function parseAddressList($address = null, $default_domain = null, $nest_groups = null, $validate = null, $limit = null)
{ {
if (!isset($this) || !isset($this->mailRFC822)) { if (!isset($this) || !isset($this->mailRFC822)) {
$obj = new Mail_RFC822($address, $default_domain, $nest_groups, $validate, $limit); $obj = new Mail_RFC822($address, $default_domain, $nest_groups, $validate, $limit);
...@@ -222,11 +222,10 @@ class Mail_RFC822 { ...@@ -222,11 +222,10 @@ class Mail_RFC822 {
/** /**
* Splits an address into separate addresses. * Splits an address into separate addresses.
* *
* @access private
* @param string $address The addresses to split. * @param string $address The addresses to split.
* @return boolean Success or failure. * @return boolean Success or failure.
*/ */
function _splitAddresses($address) protected function _splitAddresses($address)
{ {
if (!empty($this->limit) && count($this->addresses) == $this->limit) { if (!empty($this->limit) && count($this->addresses) == $this->limit) {
return ''; return '';
...@@ -298,11 +297,10 @@ class Mail_RFC822 { ...@@ -298,11 +297,10 @@ class Mail_RFC822 {
/** /**
* Checks for a group at the start of the string. * Checks for a group at the start of the string.
* *
* @access private
* @param string $address The address to check. * @param string $address The address to check.
* @return boolean Whether or not there is a group at the start of the string. * @return boolean Whether or not there is a group at the start of the string.
*/ */
function _isGroup($address) protected function _isGroup($address)
{ {
// First comma not in quotes, angles or escaped: // First comma not in quotes, angles or escaped:
$parts = explode(',', $address); $parts = explode(',', $address);
...@@ -322,12 +320,11 @@ class Mail_RFC822 { ...@@ -322,12 +320,11 @@ class Mail_RFC822 {
/** /**
* A common function that will check an exploded string. * A common function that will check an exploded string.
* *
* @access private
* @param array $parts The exloded string. * @param array $parts The exloded string.
* @param string $char The char that was exploded on. * @param string $char The char that was exploded on.
* @return mixed False if the string contains unclosed quotes/brackets, or the string on success. * @return mixed False if the string contains unclosed quotes/brackets, or the string on success.
*/ */
function _splitCheck($parts, $char) protected function _splitCheck($parts, $char)
{ {
$string = $parts[0]; $string = $parts[0];
...@@ -355,22 +352,19 @@ class Mail_RFC822 { ...@@ -355,22 +352,19 @@ class Mail_RFC822 {
/** /**
* Checks if a string has unclosed quotes or not. * Checks if a string has unclosed quotes or not.
* *
* @access private
* @param string $string The string to check. * @param string $string The string to check.
* @return boolean True if there are unclosed quotes inside the string, * @return boolean True if there are unclosed quotes inside the string,
* false otherwise. * false otherwise.
*/ */
function _hasUnclosedQuotes($string) protected function _hasUnclosedQuotes($string)
{ {
$matches = array(); $string = trim($string);
if (!preg_match_all('/[\\"]/', trim($string), $matches)) $iMax = strlen($string);
return false;
$in_quote = false; $in_quote = false;
$slashes = 0; $i = $slashes = 0;
foreach ($matches[0] as $m) { for (; $i < $iMax; ++$i) {
switch ($m) { switch ($string[$i]) {
case '\\': case '\\':
++$slashes; ++$slashes;
break; break;
...@@ -394,12 +388,11 @@ class Mail_RFC822 { ...@@ -394,12 +388,11 @@ class Mail_RFC822 {
* Checks if a string has an unclosed brackets or not. IMPORTANT: * Checks if a string has an unclosed brackets or not. IMPORTANT:
* This function handles both angle brackets and square brackets; * This function handles both angle brackets and square brackets;
* *
* @access private
* @param string $string The string to check. * @param string $string The string to check.
* @param string $chars The characters to check for. * @param string $chars The characters to check for.
* @return boolean True if there are unclosed brackets inside the string, false otherwise. * @return boolean True if there are unclosed brackets inside the string, false otherwise.
*/ */
function _hasUnclosedBrackets($string, $chars) protected function _hasUnclosedBrackets($string, $chars)
{ {
$num_angle_start = substr_count($string, $chars[0]); $num_angle_start = substr_count($string, $chars[0]);
$num_angle_end = substr_count($string, $chars[1]); $num_angle_end = substr_count($string, $chars[1]);
...@@ -418,16 +411,15 @@ class Mail_RFC822 { ...@@ -418,16 +411,15 @@ class Mail_RFC822 {
/** /**
* Sub function that is used only by hasUnclosedBrackets(). * Sub function that is used only by hasUnclosedBrackets().
* *
* @access private
* @param string $string The string to check. * @param string $string The string to check.
* @param integer &$num The number of occurences. * @param integer &$num The number of occurences.
* @param string $char The character to count. * @param string $char The character to count.
* @return integer The number of occurences of $char in $string, adjusted for backslashes. * @return integer The number of occurences of $char in $string, adjusted for backslashes.
*/ */
function _hasUnclosedBracketsSub($string, &$num, $char) protected function _hasUnclosedBracketsSub($string, &$num, $char)
{ {
$parts = explode($char, $string); $parts = explode($char, $string);
for ($i = 0, $k = count($parts); $i < $k; $i++){ for ($i = 0; $i < count($parts); $i++){
if (substr($parts[$i], -1) == '\\' || $this->_hasUnclosedQuotes($parts[$i])) if (substr($parts[$i], -1) == '\\' || $this->_hasUnclosedQuotes($parts[$i]))
$num--; $num--;
if (isset($parts[$i + 1])) if (isset($parts[$i + 1]))
...@@ -440,11 +432,10 @@ class Mail_RFC822 { ...@@ -440,11 +432,10 @@ class Mail_RFC822 {
/** /**
* Function to begin checking the address. * Function to begin checking the address.
* *
* @access private
* @param string $address The address to validate. * @param string $address The address to validate.
* @return mixed False on failure, or a structured array of address information on success. * @return mixed False on failure, or a structured array of address information on success.
*/ */
function _validateAddress($address) protected function _validateAddress($address)
{ {
$is_group = false; $is_group = false;
$addresses = array(); $addresses = array();
...@@ -485,14 +476,6 @@ class Mail_RFC822 { ...@@ -485,14 +476,6 @@ class Mail_RFC822 {
$addresses[] = $address['address']; $addresses[] = $address['address'];
} }
// Check that $addresses is set, if address like this:
// Groupname:;
// Then errors were appearing.
if (!count($addresses)){
$this->error = 'Empty group.';
return false;
}
// Trim the whitespace from all of the address strings. // Trim the whitespace from all of the address strings.
array_map('trim', $addresses); array_map('trim', $addresses);
...@@ -533,11 +516,10 @@ class Mail_RFC822 { ...@@ -533,11 +516,10 @@ class Mail_RFC822 {
/** /**
* Function to validate a phrase. * Function to validate a phrase.
* *
* @access private
* @param string $phrase The phrase to check. * @param string $phrase The phrase to check.
* @return boolean Success or failure. * @return boolean Success or failure.
*/ */
function _validatePhrase($phrase) protected function _validatePhrase($phrase)
{ {
// Splits on one or more Tab or space. // Splits on one or more Tab or space.
$parts = preg_split('/[ \\x09]+/', $phrase, -1, PREG_SPLIT_NO_EMPTY); $parts = preg_split('/[ \\x09]+/', $phrase, -1, PREG_SPLIT_NO_EMPTY);
...@@ -574,11 +556,10 @@ class Mail_RFC822 { ...@@ -574,11 +556,10 @@ class Mail_RFC822 {
* can split a list of addresses up before encoding personal names * can split a list of addresses up before encoding personal names
* (umlauts, etc.), for example. * (umlauts, etc.), for example.
* *
* @access private
* @param string $atom The string to check. * @param string $atom The string to check.
* @return boolean Success or failure. * @return boolean Success or failure.
*/ */
function _validateAtom($atom) protected function _validateAtom($atom)
{ {
if (!$this->validate) { if (!$this->validate) {
// Validation has been turned off; assume the atom is okay. // Validation has been turned off; assume the atom is okay.
...@@ -607,11 +588,10 @@ class Mail_RFC822 { ...@@ -607,11 +588,10 @@ class Mail_RFC822 {
* Function to validate quoted string, which is: * Function to validate quoted string, which is:
* quoted-string = <"> *(qtext/quoted-pair) <"> * quoted-string = <"> *(qtext/quoted-pair) <">
* *
* @access private
* @param string $qstring The string to check * @param string $qstring The string to check
* @return boolean Success or failure. * @return boolean Success or failure.
*/ */
function _validateQuotedString($qstring) protected function _validateQuotedString($qstring)
{ {
// Leading and trailing " // Leading and trailing "
$qstring = substr($qstring, 1, -1); $qstring = substr($qstring, 1, -1);
...@@ -625,11 +605,10 @@ class Mail_RFC822 { ...@@ -625,11 +605,10 @@ class Mail_RFC822 {
* mailbox = addr-spec ; simple address * mailbox = addr-spec ; simple address
* / phrase route-addr ; name and route-addr * / phrase route-addr ; name and route-addr
* *
* @access public
* @param string &$mailbox The string to check. * @param string &$mailbox The string to check.
* @return boolean Success or failure. * @return boolean Success or failure.
*/ */
function validateMailbox(&$mailbox) public function validateMailbox(&$mailbox)
{ {
// A couple of defaults. // A couple of defaults.
$phrase = ''; $phrase = '';
...@@ -714,11 +693,10 @@ class Mail_RFC822 { ...@@ -714,11 +693,10 @@ class Mail_RFC822 {
* Angle brackets have already been removed at the point of * Angle brackets have already been removed at the point of
* getting to this function. * getting to this function.
* *
* @access private
* @param string $route_addr The string to check. * @param string $route_addr The string to check.
* @return mixed False on failure, or an array containing validated address/route information on success. * @return mixed False on failure, or an array containing validated address/route information on success.
*/ */
function _validateRouteAddr($route_addr) protected function _validateRouteAddr($route_addr)
{ {
// Check for colon. // Check for colon.
if (strpos($route_addr, ':') !== false) { if (strpos($route_addr, ':') !== false) {
...@@ -764,11 +742,10 @@ class Mail_RFC822 { ...@@ -764,11 +742,10 @@ class Mail_RFC822 {
* Function to validate a route, which is: * Function to validate a route, which is:
* route = 1#("@" domain) ":" * route = 1#("@" domain) ":"
* *
* @access private
* @param string $route The string to check. * @param string $route The string to check.
* @return mixed False on failure, or the validated $route on success. * @return mixed False on failure, or the validated $route on success.
*/ */
function _validateRoute($route) protected function _validateRoute($route)
{ {
// Split on comma. // Split on comma.
$domains = explode(',', trim($route)); $domains = explode(',', trim($route));
...@@ -787,11 +764,10 @@ class Mail_RFC822 { ...@@ -787,11 +764,10 @@ class Mail_RFC822 {
* *
* domain = sub-domain *("." sub-domain) * domain = sub-domain *("." sub-domain)
* *
* @access private
* @param string $domain The string to check. * @param string $domain The string to check.
* @return mixed False on failure, or the validated domain on success. * @return mixed False on failure, or the validated domain on success.
*/ */
function _validateDomain($domain) protected function _validateDomain($domain)
{ {
// Note the different use of $subdomains and $sub_domains // Note the different use of $subdomains and $sub_domains
$subdomains = explode('.', $domain); $subdomains = explode('.', $domain);
...@@ -815,11 +791,10 @@ class Mail_RFC822 { ...@@ -815,11 +791,10 @@ class Mail_RFC822 {
* Function to validate a subdomain: * Function to validate a subdomain:
* subdomain = domain-ref / domain-literal * subdomain = domain-ref / domain-literal
* *
* @access private
* @param string $subdomain The string to check. * @param string $subdomain The string to check.
* @return boolean Success or failure. * @return boolean Success or failure.
*/ */
function _validateSubdomain($subdomain) protected function _validateSubdomain($subdomain)
{ {
if (preg_match('|^\[(.*)]$|', $subdomain, $arr)){ if (preg_match('|^\[(.*)]$|', $subdomain, $arr)){
if (!$this->_validateDliteral($arr[1])) return false; if (!$this->_validateDliteral($arr[1])) return false;
...@@ -835,13 +810,12 @@ class Mail_RFC822 { ...@@ -835,13 +810,12 @@ class Mail_RFC822 {
* Function to validate a domain literal: * Function to validate a domain literal:
* domain-literal = "[" *(dtext / quoted-pair) "]" * domain-literal = "[" *(dtext / quoted-pair) "]"
* *
* @access private
* @param string $dliteral The string to check. * @param string $dliteral The string to check.
* @return boolean Success or failure. * @return boolean Success or failure.
*/ */
function _validateDliteral($dliteral) protected function _validateDliteral($dliteral)
{ {
return !preg_match('/(.)[][\x0D\\\\]/', $dliteral, $matches) && $matches[1] != '\\'; return !preg_match('/(.)[][\x0D\\\\]/', $dliteral, $matches) && ((! isset($matches[1])) || $matches[1] != '\\');
} }
/** /**
...@@ -849,11 +823,10 @@ class Mail_RFC822 { ...@@ -849,11 +823,10 @@ class Mail_RFC822 {
* *
* addr-spec = local-part "@" domain * addr-spec = local-part "@" domain
* *
* @access private
* @param string $addr_spec The string to check. * @param string $addr_spec The string to check.
* @return mixed False on failure, or the validated addr-spec on success. * @return mixed False on failure, or the validated addr-spec on success.
*/ */
function _validateAddrSpec($addr_spec) protected function _validateAddrSpec($addr_spec)
{ {
$addr_spec = trim($addr_spec); $addr_spec = trim($addr_spec);
...@@ -880,17 +853,16 @@ class Mail_RFC822 { ...@@ -880,17 +853,16 @@ class Mail_RFC822 {
* Function to validate the local part of an address: * Function to validate the local part of an address:
* local-part = word *("." word) * local-part = word *("." word)
* *
* @access private
* @param string $local_part * @param string $local_part
* @return mixed False on failure, or the validated local part on success. * @return mixed False on failure, or the validated local part on success.
*/ */
function _validateLocalPart($local_part) protected function _validateLocalPart($local_part)
{ {
$parts = explode('.', $local_part); $parts = explode('.', $local_part);
$words = array(); $words = array();
// Split the local_part into words. // Split the local_part into words.
while (count($parts) > 0){ while (count($parts) > 0) {
$words[] = $this->_splitCheck($parts, '.'); $words[] = $this->_splitCheck($parts, '.');
for ($i = 0; $i < $this->index + 1; $i++) { for ($i = 0; $i < $this->index + 1; $i++) {
array_shift($parts); array_shift($parts);
...@@ -899,6 +871,10 @@ class Mail_RFC822 { ...@@ -899,6 +871,10 @@ class Mail_RFC822 {
// Validate each word. // Validate each word.
foreach ($words as $word) { foreach ($words as $word) {
// word cannot be empty (#17317)
if ($word === '') {
return false;
}
// If this word contains an unquoted space, it is invalid. (6.2.4) // If this word contains an unquoted space, it is invalid. (6.2.4)
if (strpos($word, ' ') && $word[0] !== '"') if (strpos($word, ' ') && $word[0] !== '"')
{ {
...@@ -922,7 +898,7 @@ class Mail_RFC822 { ...@@ -922,7 +898,7 @@ class Mail_RFC822 {
* @param string $data Addresses to count * @param string $data Addresses to count
* @return int Approximate count * @return int Approximate count
*/ */
function approximateCount($data) public function approximateCount($data)
{ {
return count(preg_split('/(?<!\\\\),/', $data)); return count(preg_split('/(?<!\\\\),/', $data));
} }
...@@ -940,7 +916,7 @@ class Mail_RFC822 { ...@@ -940,7 +916,7 @@ class Mail_RFC822 {
* @return mixed False if it fails, an indexed array * @return mixed False if it fails, an indexed array
* username/domain if it matches * username/domain if it matches
*/ */
function isValidInetAddress($data, $strict = false) public function isValidInetAddress($data, $strict = false)
{ {
$regex = $strict ? '/^([.0-9a-z_+-]+)@(([0-9a-z-]+\.)+[0-9a-z]{2,})$/i' : '/^([*+!.&#$|\'\\%\/0-9a-z^_`{}=?~:-]+)@(([0-9a-z-]+\.)+[0-9a-z]{2,})$/i'; $regex = $strict ? '/^([.0-9a-z_+-]+)@(([0-9a-z-]+\.)+[0-9a-z]{2,})$/i' : '/^([*+!.&#$|\'\\%\/0-9a-z^_`{}=?~:-]+)@(([0-9a-z-]+\.)+[0-9a-z]{2,})$/i';
if (preg_match($regex, trim($data), $matches)) { if (preg_match($regex, trim($data), $matches)) {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment