From 8e138eced12fa88da721cc9b840fe4aa02c9e031 Mon Sep 17 00:00:00 2001 From: Andrey Andreev Date: Mon, 31 Aug 2015 15:23:42 +0300 Subject: Fix #4073 --- system/libraries/Email.php | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) (limited to 'system/libraries/Email.php') diff --git a/system/libraries/Email.php b/system/libraries/Email.php index 459c8f590..acf3629c3 100644 --- a/system/libraries/Email.php +++ b/system/libraries/Email.php @@ -1869,20 +1869,26 @@ class CI_Email { return FALSE; } - $this->_send_command('from', $this->clean_email($this->_headers['From'])); + if ( ! $this->_send_command('from', $this->clean_email($this->_headers['From']))) + { + return FALSE; + } foreach ($this->_recipients as $val) { - $this->_send_command('to', $val); + if ( ! $this->_send_command('to', $val)) + { + return FALSE; + } } if (count($this->_cc_array) > 0) { foreach ($this->_cc_array as $val) { - if ($val !== '') + if ($val !== '' && ! $this->_send_command('to', $val)) { - $this->_send_command('to', $val); + return FALSE; } } } @@ -1891,14 +1897,17 @@ class CI_Email { { foreach ($this->_bcc_array as $val) { - if ($val !== '') + if ($val !== '' && ! $this->_send_command('to', $val)) { - $this->_send_command('to', $val); + return FALSE; } } } - $this->_send_command('data'); + if ( ! $this->_send_command('data')) + { + return FALSE; + } // perform dot transformation on any lines that begin with a dot $this->_send_data($this->_header_str.preg_replace('/^\./m', '..$1', $this->_finalbody)); -- cgit v1.2.3-24-g4f1b From 3368cebeb6682013c44be7a03d3b3dac0f5c8973 Mon Sep 17 00:00:00 2001 From: Andrey Andreev Date: Fri, 30 Oct 2015 12:25:15 +0200 Subject: Fix #4192 --- system/libraries/Email.php | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) (limited to 'system/libraries/Email.php') diff --git a/system/libraries/Email.php b/system/libraries/Email.php index acf3629c3..ebff7567a 100644 --- a/system/libraries/Email.php +++ b/system/libraries/Email.php @@ -1563,11 +1563,10 @@ class CI_Email { if ($this->charset === 'UTF-8') { - if (MB_ENABLED === TRUE) - { - return mb_encode_mimeheader($str, $this->charset, 'Q', $this->crlf); - } - elseif (ICONV_ENABLED === TRUE) + // Note: We used to have mb_encode_mimeheader() as the first choice + // here, but it turned out to be buggy and unreliable. DO NOT + // re-add it! -- Narf + if (ICONV_ENABLED === TRUE) { $output = @iconv_mime_encode('', $str, array( @@ -1590,6 +1589,10 @@ class CI_Email { $chars = iconv_strlen($str, 'UTF-8'); } + elseif (MB_ENABLED === TRUE) + { + $chars = mb_strlen($str, 'UTF-8'); + } } // We might already have this set for UTF-8 -- cgit v1.2.3-24-g4f1b From b06b5c46ef59534cb3d0eb7e9b95c0c5720ee5e5 Mon Sep 17 00:00:00 2001 From: Andrey Andreev Date: Mon, 16 Nov 2015 13:37:58 +0200 Subject: Fix #4244 --- system/libraries/Email.php | 31 ++++++++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) (limited to 'system/libraries/Email.php') diff --git a/system/libraries/Email.php b/system/libraries/Email.php index ebff7567a..034586ac9 100644 --- a/system/libraries/Email.php +++ b/system/libraries/Email.php @@ -1469,6 +1469,20 @@ class CI_Email { */ protected function _prep_quoted_printable($str) { + // ASCII code numbers for "safe" characters that can always be + // used literally, without encoding, as described in RFC 2049. + // http://www.ietf.org/rfc/rfc2049.txt + static $ascii_safe_chars = array( + // ' ( ) + , - . / : = ? + 39, 40, 41, 43, 44, 45, 46, 47, 58, 61, 63, + // numbers + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, + // upper-case letters + 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, + // lower-case letters + 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122 + ); + // We are intentionally wrapping so mail servers will encode characters // properly and MUAs will behave, so {unwrap} must go! $str = str_replace(array('{unwrap}', '{/unwrap}'), '', $str); @@ -1516,14 +1530,25 @@ class CI_Email { $ascii = ord($char); // Convert spaces and tabs but only if it's the end of the line - if ($i === ($length - 1) && ($ascii === 32 OR $ascii === 9)) + if ($ascii === 32 OR $ascii === 9) { - $char = $escape.sprintf('%02s', dechex($ascii)); + if ($i === ($length - 1)) + { + $char = $escape.sprintf('%02s', dechex($ascii)); + } } - elseif ($ascii === 61) // encode = signs + // DO NOT move this below the $ascii_safe_chars line! + // + // = (equals) signs are allowed by RFC2049, but must be encoded + // as they are the encoding delimiter! + elseif ($ascii === 61) { $char = $escape.strtoupper(sprintf('%02s', dechex($ascii))); // =3D } + elseif ( ! in_array($ascii, $ascii_safe_chars, TRUE)) + { + $char = $escape.strtoupper(sprintf('%02s', dechex($ascii))); + } // If we're at the character limit, add the line to the output, // reset our temp variable, and keep on chuggin' -- cgit v1.2.3-24-g4f1b From 9d84d3cb5cb2dd4044e57bfcbe81c423adab6d7c Mon Sep 17 00:00:00 2001 From: Andrey Andreev Date: Wed, 30 Dec 2015 21:50:20 +0200 Subject: Fix #4343 --- system/libraries/Email.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'system/libraries/Email.php') diff --git a/system/libraries/Email.php b/system/libraries/Email.php index 034586ac9..754dd1784 100644 --- a/system/libraries/Email.php +++ b/system/libraries/Email.php @@ -1854,8 +1854,7 @@ class CI_Email { // is popen() enabled? if ( ! function_usable('popen') OR FALSE === ($fp = @popen( - $this->mailpath.' -oi -f '.$this->clean_email($this->_headers['From']) - .' -t -r '.$this->clean_email($this->_headers['Return-Path']) + $this->mailpath.' -oi -f '.$this->clean_email($this->_headers['From']).' -t' , 'w')) ) // server probably has popen disabled, so nothing we can do to get a verbose error. { -- cgit v1.2.3-24-g4f1b From 125ef4751080a2118cb203357d77687699e3eb25 Mon Sep 17 00:00:00 2001 From: Andrey Andreev Date: Mon, 11 Jan 2016 12:33:00 +0200 Subject: [ci skip] Bump year to 2016 --- system/libraries/Email.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'system/libraries/Email.php') diff --git a/system/libraries/Email.php b/system/libraries/Email.php index 754dd1784..c8859b9c3 100644 --- a/system/libraries/Email.php +++ b/system/libraries/Email.php @@ -6,7 +6,7 @@ * * This content is released under the MIT License (MIT) * - * Copyright (c) 2014 - 2015, British Columbia Institute of Technology + * Copyright (c) 2014 - 2016, British Columbia Institute of Technology * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -29,7 +29,7 @@ * @package CodeIgniter * @author EllisLab Dev Team * @copyright Copyright (c) 2008 - 2014, EllisLab, Inc. (http://ellislab.com/) - * @copyright Copyright (c) 2014 - 2015, British Columbia Institute of Technology (http://bcit.ca/) + * @copyright Copyright (c) 2014 - 2016, British Columbia Institute of Technology (http://bcit.ca/) * @license http://opensource.org/licenses/MIT MIT License * @link http://codeigniter.com * @since Version 1.0.0 -- cgit v1.2.3-24-g4f1b From bd202c91b0e9cf0a8c93bcaa71df9574f5909346 Mon Sep 17 00:00:00 2001 From: Andrey Andreev Date: Mon, 11 Jan 2016 12:50:18 +0200 Subject: [ci skip] Update codeigniter.com links to https --- system/libraries/Email.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'system/libraries/Email.php') diff --git a/system/libraries/Email.php b/system/libraries/Email.php index c8859b9c3..ad4c02ff8 100644 --- a/system/libraries/Email.php +++ b/system/libraries/Email.php @@ -31,7 +31,7 @@ * @copyright Copyright (c) 2008 - 2014, EllisLab, Inc. (http://ellislab.com/) * @copyright Copyright (c) 2014 - 2016, British Columbia Institute of Technology (http://bcit.ca/) * @license http://opensource.org/licenses/MIT MIT License - * @link http://codeigniter.com + * @link https://codeigniter.com * @since Version 1.0.0 * @filesource */ @@ -46,7 +46,7 @@ defined('BASEPATH') OR exit('No direct script access allowed'); * @subpackage Libraries * @category Libraries * @author EllisLab Dev Team - * @link http://codeigniter.com/user_guide/libraries/email.html + * @link https://codeigniter.com/user_guide/libraries/email.html */ class CI_Email { -- cgit v1.2.3-24-g4f1b From 1924e879b165fb119847a49a7a5eab2f28295fa2 Mon Sep 17 00:00:00 2001 From: Andrey Andreev Date: Mon, 11 Jan 2016 12:55:34 +0200 Subject: [ci skip] Update ellislab.com links to https too --- system/libraries/Email.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'system/libraries/Email.php') diff --git a/system/libraries/Email.php b/system/libraries/Email.php index ad4c02ff8..007f9b431 100644 --- a/system/libraries/Email.php +++ b/system/libraries/Email.php @@ -28,7 +28,7 @@ * * @package CodeIgniter * @author EllisLab Dev Team - * @copyright Copyright (c) 2008 - 2014, EllisLab, Inc. (http://ellislab.com/) + * @copyright Copyright (c) 2008 - 2014, EllisLab, Inc. (https://ellislab.com/) * @copyright Copyright (c) 2014 - 2016, British Columbia Institute of Technology (http://bcit.ca/) * @license http://opensource.org/licenses/MIT MIT License * @link https://codeigniter.com -- cgit v1.2.3-24-g4f1b From c70216d560d85adf907d9941868a0d8d3df868ca Mon Sep 17 00:00:00 2001 From: Andrey Andreev Date: Wed, 20 Jan 2016 17:25:13 +0200 Subject: Fix #4391 --- system/libraries/Email.php | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) (limited to 'system/libraries/Email.php') diff --git a/system/libraries/Email.php b/system/libraries/Email.php index 007f9b431..ed6f737a1 100644 --- a/system/libraries/Email.php +++ b/system/libraries/Email.php @@ -574,14 +574,18 @@ class CI_Email { $this->validate_email($this->_str_to_array($replyto)); } - if ($name === '') - { - $name = $replyto; - } - - if (strpos($name, '"') !== 0) + if ($name !== '') { - $name = '"'.$name.'"'; + // only use Q encoding if there are characters that would require it + if ( ! preg_match('/[\200-\377]/', $name)) + { + // add slashes for non-printing characters, slashes, and double quotes, and surround it in double quotes + $name = '"'.addcslashes($name, "\0..\37\177'\"\\").'"'; + } + else + { + $name = $this->_prep_q_encoding($name); + } } $this->set_header('Reply-To', $name.' <'.$replyto.'>'); -- cgit v1.2.3-24-g4f1b From 92d8eb2acf7204d01f595081551a4b08c4660cf3 Mon Sep 17 00:00:00 2001 From: Robert Angyal Date: Sun, 17 Apr 2016 06:48:22 +0200 Subject: Fixes #4583 by separating attachments to related and mixed multiparts Signed-off-by: Robert Angyal --- system/libraries/Email.php | 135 +++++++++++++++++++++++++++++++++------------ 1 file changed, 101 insertions(+), 34 deletions(-) (limited to 'system/libraries/Email.php') diff --git a/system/libraries/Email.php b/system/libraries/Email.php index ed6f737a1..ef9b58b61 100644 --- a/system/libraries/Email.php +++ b/system/libraries/Email.php @@ -149,13 +149,6 @@ class CI_Email { */ public $charset = 'utf-8'; - /** - * Multipart message - * - * @var string 'mixed' (in the body) or 'related' (separate) - */ - public $multipart = 'mixed'; // "mixed" (in the body) or "related" (separate) - /** * Alternative message (for HTML messages only) * @@ -274,6 +267,13 @@ class CI_Email { */ protected $_atc_boundary = ''; + /** + * Related Attachment boundary + * + * @var string + */ + protected $_rel_boundary = ''; + /** * Final headers to send * @@ -766,7 +766,8 @@ class CI_Email { 'name' => array($file, $newname), 'disposition' => empty($disposition) ? 'attachment' : $disposition, // Can also be 'inline' Not sure if it matters 'type' => $mime, - 'content' => chunk_split(base64_encode($file_content)) + 'content' => chunk_split(base64_encode($file_content)), + 'multipart' => 'mixed' ); return $this; @@ -784,15 +785,11 @@ class CI_Email { */ public function attachment_cid($filename) { - if ($this->multipart !== 'related') - { - $this->multipart = 'related'; // Thunderbird need this for inline images - } - for ($i = 0, $c = count($this->_attachments); $i < $c; $i++) { if ($this->_attachments[$i]['name'][0] === $filename) { + $this->_attachments[$i]['multipart'] = 'related'; $this->_attachments[$i]['cid'] = uniqid(basename($this->_attachments[$i]['name'][0]).'@'); return $this->_attachments[$i]['cid']; } @@ -945,6 +942,7 @@ class CI_Email { { $this->_alt_boundary = 'B_ALT_'.uniqid(''); // multipart/alternative $this->_atc_boundary = 'B_ATC_'.uniqid(''); // attachment boundary + $this->_rel_boundary = 'B_REL_'.uniqid(''); // related attachment boundary } // -------------------------------------------------------------------- @@ -1391,7 +1389,7 @@ class CI_Email { case 'plain-attach' : - $hdr .= 'Content-Type: multipart/'.$this->multipart.'; boundary="'.$this->_atc_boundary.'"'; + $hdr .= 'Content-Type: multipart/mixed; boundary="'.$this->_atc_boundary.'"'; if ($this->_get_protocol() === 'mail') { @@ -1406,18 +1404,45 @@ class CI_Email { .$this->newline .$this->_body.$this->newline.$this->newline; + $attachment_prepared = $this->_prep_attachments($this->_attachments, $this->_atc_boundary); + break; case 'html-attach' : - $hdr .= 'Content-Type: multipart/'.$this->multipart.'; boundary="'.$this->_atc_boundary.'"'; + $attachments_indexed_by_multipart = $this->_attachments_indexed_by_multipart(); + $attachments_related = $attachments_indexed_by_multipart['related']; + $attachments_mixed = $attachments_indexed_by_multipart['mixed']; + $prepared_attachment_parts = array(); + + if (isset($attachments_mixed) && count($attachments_mixed) > 0) + { + $hdr .= 'Content-Type: multipart/mixed; boundary="'.$this->_atc_boundary.'"'; + + array_push($prepared_attachment_parts, $this->_prep_attachments($attachments_mixed, $this->_atc_boundary)); + $last_boundary = $this->_atc_boundary; + } + + if (isset($attachments_related) && count($attachments_related) > 0) + { + $target_container =& $hdr; + if (isset($last_boundary)) { + $target_container =& $body; + $target_container .= '--' . $last_boundary . $this->newline; + } + $target_container .= 'Content-Type: multipart/related; boundary="'.$this->_rel_boundary.'"'; + + array_unshift($prepared_attachment_parts, $this->_prep_attachments($attachments_related, $this->_rel_boundary)); + $last_boundary = $this->_rel_boundary; + } if ($this->_get_protocol() === 'mail') { $this->_header_str .= $hdr; } + if (strlen(body) > 0) $body .= $this->newline.$this->newline; $body .= $this->_get_mime_message().$this->newline.$this->newline - .'--'.$this->_atc_boundary.$this->newline + .'--'.$last_boundary.$this->newline .'Content-Type: multipart/alternative; boundary="'.$this->_alt_boundary.'"'.$this->newline.$this->newline .'--'.$this->_alt_boundary.$this->newline @@ -1432,27 +1457,12 @@ class CI_Email { .$this->_prep_quoted_printable($this->_body).$this->newline.$this->newline .'--'.$this->_alt_boundary.'--'.$this->newline.$this->newline; - break; - } - - $attachment = array(); - for ($i = 0, $c = count($this->_attachments), $z = 0; $i < $c; $i++) - { - $filename = $this->_attachments[$i]['name'][0]; - $basename = ($this->_attachments[$i]['name'][1] === NULL) - ? basename($filename) : $this->_attachments[$i]['name'][1]; - - $attachment[$z++] = '--'.$this->_atc_boundary.$this->newline - .'Content-type: '.$this->_attachments[$i]['type'].'; ' - .'name="'.$basename.'"'.$this->newline - .'Content-Disposition: '.$this->_attachments[$i]['disposition'].';'.$this->newline - .'Content-Transfer-Encoding: base64'.$this->newline - .(empty($this->_attachments[$i]['cid']) ? '' : 'Content-ID: <'.$this->_attachments[$i]['cid'].'>'.$this->newline); + $attachment_prepared = implode($this->newline.$this->newline, $prepared_attachment_parts); - $attachment[$z++] = $this->_attachments[$i]['content']; + break; } - $body .= implode($this->newline, $attachment).$this->newline.'--'.$this->_atc_boundary.'--'; + $body .= $attachment_prepared; $this->_finalbody = ($this->_get_protocol() === 'mail') ? $body : $hdr.$this->newline.$this->newline.$body; @@ -1462,6 +1472,63 @@ class CI_Email { // -------------------------------------------------------------------- + /** + * Returns attachments mapped by multipart type + * + * @return array + */ + protected function _attachments_indexed_by_multipart() + { + foreach ($this->_attachments as $attachment) + { + $multipart = $attachment['multipart']; + if (!isset($attachments_indexed[$multipart])) + { + $attachments_indexed[$multipart] = array(); + } + array_push($attachments_indexed[$multipart], $attachment); + } + + return $attachments_indexed; + } + + // -------------------------------------------------------------------- + + /** + * Prepares attachment string + * + * @param array $attachments + * @param string $boundary Multipart boundary string + * @return string + */ + protected function _prep_attachments($attachments, $boundary) + { + if (!isset($attachments) || count($attachments) === 0) return ''; + + $attachment_parts = array(); + foreach ($attachments as $attachment) + { + $filename = $attachment['name'][0]; + $basename = ($attachment['name'][1] === NULL) + ? basename($filename) : $attachment['name'][1]; + + array_push( + $attachment_parts, + '--'.$boundary.$this->newline + .'Content-type: '.$attachment['type'].'; ' + .'name="'.$basename.'"'.$this->newline + .'Content-Disposition: '.$attachment['disposition'].';'.$this->newline + .'Content-Transfer-Encoding: base64'.$this->newline + .(empty($attachment['cid']) ? '' : 'Content-ID: <'.$attachment['cid'].'>'.$this->newline), + $attachment['content'] + ); + } + + return implode($this->newline, $attachment_parts).$this->newline.'--'.$boundary.'--'; + } + + // -------------------------------------------------------------------- + /** * Prep Quoted Printable * -- cgit v1.2.3-24-g4f1b From 832fd00b10f2fb236e0bf5b770d3298e6fedee64 Mon Sep 17 00:00:00 2001 From: Robert Angyal Date: Wed, 20 Apr 2016 05:20:15 +0200 Subject: #4583 Fix code style issues Signed-off-by: Robert Angyal --- system/libraries/Email.php | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) (limited to 'system/libraries/Email.php') diff --git a/system/libraries/Email.php b/system/libraries/Email.php index ef9b58b61..cbb48f525 100644 --- a/system/libraries/Email.php +++ b/system/libraries/Email.php @@ -767,7 +767,7 @@ class CI_Email { 'disposition' => empty($disposition) ? 'attachment' : $disposition, // Can also be 'inline' Not sure if it matters 'type' => $mime, 'content' => chunk_split(base64_encode($file_content)), - 'multipart' => 'mixed' + 'multipart' => 'mixed' ); return $this; @@ -1413,6 +1413,7 @@ class CI_Email { $attachments_related = $attachments_indexed_by_multipart['related']; $attachments_mixed = $attachments_indexed_by_multipart['mixed']; $prepared_attachment_parts = array(); + $last_boundary = NULL; if (isset($attachments_mixed) && count($attachments_mixed) > 0) { @@ -1425,7 +1426,8 @@ class CI_Email { if (isset($attachments_related) && count($attachments_related) > 0) { $target_container =& $hdr; - if (isset($last_boundary)) { + if (isset($last_boundary)) + { $target_container =& $body; $target_container .= '--' . $last_boundary . $this->newline; } @@ -1440,7 +1442,10 @@ class CI_Email { $this->_header_str .= $hdr; } - if (strlen(body) > 0) $body .= $this->newline.$this->newline; + if (strlen(body) > 0) + { + $body .= $this->newline.$this->newline; + } $body .= $this->_get_mime_message().$this->newline.$this->newline .'--'.$last_boundary.$this->newline @@ -1475,7 +1480,7 @@ class CI_Email { /** * Returns attachments mapped by multipart type * - * @return array + * @return array */ protected function _attachments_indexed_by_multipart() { @@ -1497,13 +1502,16 @@ class CI_Email { /** * Prepares attachment string * - * @param array $attachments - * @param string $boundary Multipart boundary string - * @return string + * @param array $attachments + * @param string $boundary Multipart boundary string + * @return string */ protected function _prep_attachments($attachments, $boundary) { - if (!isset($attachments) || count($attachments) === 0) return ''; + if (!isset($attachments) OR count($attachments) === 0) + { + return ''; + } $attachment_parts = array(); foreach ($attachments as $attachment) -- cgit v1.2.3-24-g4f1b From ed458fbdb36f8d8d7bd7d818dbb2983485e86b3c Mon Sep 17 00:00:00 2001 From: Robert Angyal Date: Thu, 28 Apr 2016 10:26:56 +0200 Subject: #4583 Refactor according to the suggestions commented on Pull Request Signed-off-by: Robert Angyal --- system/libraries/Email.php | 68 ++++++++++++++++++++-------------------------- 1 file changed, 30 insertions(+), 38 deletions(-) (limited to 'system/libraries/Email.php') diff --git a/system/libraries/Email.php b/system/libraries/Email.php index cbb48f525..e35c48ec4 100644 --- a/system/libraries/Email.php +++ b/system/libraries/Email.php @@ -1406,34 +1406,34 @@ class CI_Email { $attachment_prepared = $this->_prep_attachments($this->_attachments, $this->_atc_boundary); - break; + break; case 'html-attach' : $attachments_indexed_by_multipart = $this->_attachments_indexed_by_multipart(); - $attachments_related = $attachments_indexed_by_multipart['related']; - $attachments_mixed = $attachments_indexed_by_multipart['mixed']; $prepared_attachment_parts = array(); $last_boundary = NULL; - if (isset($attachments_mixed) && count($attachments_mixed) > 0) + if ( ! empty($attachments_indexed_by_multipart['mixed'])) { $hdr .= 'Content-Type: multipart/mixed; boundary="'.$this->_atc_boundary.'"'; - array_push($prepared_attachment_parts, $this->_prep_attachments($attachments_mixed, $this->_atc_boundary)); + $prepared_attachment_parts[] = $this->_prep_attachments($attachments_indexed_by_multipart['mixed'], $this->_atc_boundary); $last_boundary = $this->_atc_boundary; } - if (isset($attachments_related) && count($attachments_related) > 0) + if ( ! empty($attachments_indexed_by_multipart['related'])) { - $target_container =& $hdr; + $rel_boundary_header = 'Content-Type: multipart/related; boundary="'.$this->_rel_boundary.'"'; if (isset($last_boundary)) { - $target_container =& $body; - $target_container .= '--' . $last_boundary . $this->newline; + $body .= '--' . $last_boundary . $this->newline . $rel_boundary_header; + } + else + { + $hdr .= $rel_boundary_header; } - $target_container .= 'Content-Type: multipart/related; boundary="'.$this->_rel_boundary.'"'; - array_unshift($prepared_attachment_parts, $this->_prep_attachments($attachments_related, $this->_rel_boundary)); + array_unshift($prepared_attachment_parts, $this->_prep_attachments($attachments_indexed_by_multipart['related'], $this->_rel_boundary)); $last_boundary = $this->_rel_boundary; } @@ -1442,10 +1442,7 @@ class CI_Email { $this->_header_str .= $hdr; } - if (strlen(body) > 0) - { - $body .= $this->newline.$this->newline; - } + strlen($body) && $body .= $this->newline.$this->newline; $body .= $this->_get_mime_message().$this->newline.$this->newline .'--'.$last_boundary.$this->newline @@ -1464,7 +1461,7 @@ class CI_Email { $attachment_prepared = implode($this->newline.$this->newline, $prepared_attachment_parts); - break; + break; } $body .= $attachment_prepared; @@ -1487,11 +1484,8 @@ class CI_Email { foreach ($this->_attachments as $attachment) { $multipart = $attachment['multipart']; - if (!isset($attachments_indexed[$multipart])) - { - $attachments_indexed[$multipart] = array(); - } - array_push($attachments_indexed[$multipart], $attachment); + isset($attachments_indexed[$multipart]) OR $attachments_indexed[$multipart] = array(); + $attachments_indexed[$multipart][] = $attachment; } return $attachments_indexed; @@ -1508,31 +1502,29 @@ class CI_Email { */ protected function _prep_attachments($attachments, $boundary) { - if (!isset($attachments) OR count($attachments) === 0) + if (empty($attachments)) { return ''; } - $attachment_parts = array(); - foreach ($attachments as $attachment) + $attachment = array(); + for ($i = 0, $c = count($attachments), $z = 0; $i < $c; $i++) { - $filename = $attachment['name'][0]; - $basename = ($attachment['name'][1] === NULL) - ? basename($filename) : $attachment['name'][1]; + $filename = $attachments[$i]['name'][0]; + $basename = ($attachments[$i]['name'][1] === NULL) + ? basename($filename) : $attachments[$i]['name'][1]; + + $attachment[$z++] = '--'.$boundary.$this->newline + .'Content-type: '.$attachments[$i]['type'].'; ' + .'name="'.$basename.'"'.$this->newline + .'Content-Disposition: '.$attachments[$i]['disposition'].';'.$this->newline + .'Content-Transfer-Encoding: base64'.$this->newline + .(empty($attachments[$i]['cid']) ? '' : 'Content-ID: <'.$attachments[$i]['cid'].'>'.$this->newline); - array_push( - $attachment_parts, - '--'.$boundary.$this->newline - .'Content-type: '.$attachment['type'].'; ' - .'name="'.$basename.'"'.$this->newline - .'Content-Disposition: '.$attachment['disposition'].';'.$this->newline - .'Content-Transfer-Encoding: base64'.$this->newline - .(empty($attachment['cid']) ? '' : 'Content-ID: <'.$attachment['cid'].'>'.$this->newline), - $attachment['content'] - ); + $attachment[$z++] = $attachments[$i]['content']; } - return implode($this->newline, $attachment_parts).$this->newline.'--'.$boundary.'--'; + return implode($this->newline, $attachment).$this->newline.'--'.$boundary.'--'; } // -------------------------------------------------------------------- -- cgit v1.2.3-24-g4f1b From 5277583e7336675d02665ff77359b41e782853ce Mon Sep 17 00:00:00 2001 From: Robert Angyal Date: Wed, 4 May 2016 16:33:25 +0200 Subject: #4583 Refactor according to the suggestions commented on Pull Request Signed-off-by: Robert Angyal --- system/libraries/Email.php | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) (limited to 'system/libraries/Email.php') diff --git a/system/libraries/Email.php b/system/libraries/Email.php index e35c48ec4..4fd1107c5 100644 --- a/system/libraries/Email.php +++ b/system/libraries/Email.php @@ -1404,20 +1404,17 @@ class CI_Email { .$this->newline .$this->_body.$this->newline.$this->newline; - $attachment_prepared = $this->_prep_attachments($this->_attachments, $this->_atc_boundary); + $body .= $this->_prep_attachments($this->_attachments, $this->_atc_boundary); break; case 'html-attach' : $attachments_indexed_by_multipart = $this->_attachments_indexed_by_multipart(); - $prepared_attachment_parts = array(); $last_boundary = NULL; if ( ! empty($attachments_indexed_by_multipart['mixed'])) { $hdr .= 'Content-Type: multipart/mixed; boundary="'.$this->_atc_boundary.'"'; - - $prepared_attachment_parts[] = $this->_prep_attachments($attachments_indexed_by_multipart['mixed'], $this->_atc_boundary); $last_boundary = $this->_atc_boundary; } @@ -1426,14 +1423,12 @@ class CI_Email { $rel_boundary_header = 'Content-Type: multipart/related; boundary="'.$this->_rel_boundary.'"'; if (isset($last_boundary)) { - $body .= '--' . $last_boundary . $this->newline . $rel_boundary_header; + $body .= '--'.$last_boundary.$this->newline.$rel_boundary_header; } else { $hdr .= $rel_boundary_header; } - - array_unshift($prepared_attachment_parts, $this->_prep_attachments($attachments_indexed_by_multipart['related'], $this->_rel_boundary)); $last_boundary = $this->_rel_boundary; } @@ -1459,12 +1454,15 @@ class CI_Email { .$this->_prep_quoted_printable($this->_body).$this->newline.$this->newline .'--'.$this->_alt_boundary.'--'.$this->newline.$this->newline; - $attachment_prepared = implode($this->newline.$this->newline, $prepared_attachment_parts); + ( ! empty($attachments_indexed_by_multipart['related'])) && $body .= $this->newline.$this->newline + .$this->_prep_attachments($attachments_indexed_by_multipart['related'], $this->_rel_boundary); + + ( ! empty($attachments_indexed_by_multipart['mixed'])) && $body .= $this->newline.$this->newline + .$this->_prep_attachments($attachments_indexed_by_multipart['mixed'], $this->_atc_boundary); break; } - $body .= $attachment_prepared; $this->_finalbody = ($this->_get_protocol() === 'mail') ? $body : $hdr.$this->newline.$this->newline.$body; -- cgit v1.2.3-24-g4f1b From 8425319eb523ee50b11b06b97738c5a46def84e4 Mon Sep 17 00:00:00 2001 From: Andrey Andreev Date: Mon, 9 May 2016 12:24:52 +0300 Subject: [ci skip] Fix #4613 --- system/libraries/Email.php | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'system/libraries/Email.php') diff --git a/system/libraries/Email.php b/system/libraries/Email.php index ed6f737a1..cdfb43bb5 100644 --- a/system/libraries/Email.php +++ b/system/libraries/Email.php @@ -2153,6 +2153,11 @@ class CI_Email { return FALSE; } + if ($this->smtp_keepalive) + { + $this->_smtp_auth = FALSE; + } + return TRUE; } -- cgit v1.2.3-24-g4f1b From 8c95c3d6d1b589771890e5383c3e0f78a58303e9 Mon Sep 17 00:00:00 2001 From: Andrey Andreev Date: Mon, 9 May 2016 12:35:41 +0300 Subject: [ci skip] Minor optimizations to CI_Email --- system/libraries/Email.php | 50 ++++++++++++++++++---------------------------- 1 file changed, 19 insertions(+), 31 deletions(-) (limited to 'system/libraries/Email.php') diff --git a/system/libraries/Email.php b/system/libraries/Email.php index cdfb43bb5..6ff3efad9 100644 --- a/system/libraries/Email.php +++ b/system/libraries/Email.php @@ -147,7 +147,7 @@ class CI_Email { * * @var string */ - public $charset = 'utf-8'; + public $charset = 'UTF-8'; /** * Multipart message @@ -408,47 +408,24 @@ class CI_Email { public function __construct(array $config = array()) { $this->charset = config_item('charset'); - - if (count($config) > 0) - { - $this->initialize($config); - } - else - { - $this->_smtp_auth = ! ($this->smtp_user === '' && $this->smtp_pass === ''); - } - + $this->initialize($config); $this->_safe_mode = ( ! is_php('5.4') && ini_get('safe_mode')); - $this->charset = strtoupper($this->charset); log_message('info', 'Email Class Initialized'); } // -------------------------------------------------------------------- - /** - * Destructor - Releases Resources - * - * @return void - */ - public function __destruct() - { - if (is_resource($this->_smtp_connect)) - { - $this->_send_command('quit'); - } - } - - // -------------------------------------------------------------------- - /** * Initialize preferences * - * @param array + * @param array $config * @return CI_Email */ - public function initialize($config = array()) + public function initialize(array $config = array()) { + $this->clear(); + foreach ($config as $key => $val) { if (isset($this->$key)) @@ -465,9 +442,9 @@ class CI_Email { } } } - $this->clear(); - $this->_smtp_auth = ! ($this->smtp_user === '' && $this->smtp_pass === ''); + $this->charset = strtoupper($this->charset); + $this->_smtp_auth = isset($this->smtp_user[0], $this->smtp_pass[0]); return $this; } @@ -2347,4 +2324,15 @@ class CI_Email { return 'application/x-unknown-content-type'; } + // -------------------------------------------------------------------- + + /** + * Destructor + * + * @return void + */ + public function __destruct() + { + is_resource($this->_smtp_connect) && $this->_send_command('quit'); + } } -- cgit v1.2.3-24-g4f1b From 21a41ba37b9248291939cf4c801ac0f27982668e Mon Sep 17 00:00:00 2001 From: Andrey Andreev Date: Wed, 25 May 2016 15:27:39 +0300 Subject: [ci skip] Refactor changes from PR #4585 Related: #4583 --- system/libraries/Email.php | 165 +++++++++++++++++++-------------------------- 1 file changed, 70 insertions(+), 95 deletions(-) (limited to 'system/libraries/Email.php') diff --git a/system/libraries/Email.php b/system/libraries/Email.php index 4fd1107c5..21b62fea0 100644 --- a/system/libraries/Email.php +++ b/system/libraries/Email.php @@ -253,27 +253,6 @@ class CI_Email { */ protected $_finalbody = ''; - /** - * multipart/alternative boundary - * - * @var string - */ - protected $_alt_boundary = ''; - - /** - * Attachment boundary - * - * @var string - */ - protected $_atc_boundary = ''; - - /** - * Related Attachment boundary - * - * @var string - */ - protected $_rel_boundary = ''; - /** * Final headers to send * @@ -933,20 +912,6 @@ class CI_Email { // -------------------------------------------------------------------- - /** - * Set Message Boundary - * - * @return void - */ - protected function _set_boundaries() - { - $this->_alt_boundary = 'B_ALT_'.uniqid(''); // multipart/alternative - $this->_atc_boundary = 'B_ATC_'.uniqid(''); // attachment boundary - $this->_rel_boundary = 'B_REL_'.uniqid(''); // related attachment boundary - } - - // -------------------------------------------------------------------- - /** * Get the Message ID * @@ -1014,9 +979,9 @@ class CI_Email { { if ($this->mailtype === 'html') { - return (count($this->_attachments) === 0) ? 'html' : 'html-attach'; + return empty($this->_attachments) ? 'html' : 'html-attach'; } - elseif ($this->mailtype === 'text' && count($this->_attachments) > 0) + elseif ($this->mailtype === 'text' && ! empty($this->_attachments)) { return 'plain-attach'; } @@ -1322,7 +1287,6 @@ class CI_Email { $this->_body = $this->word_wrap($this->_body); } - $this->_set_boundaries(); $this->_write_headers(); $hdr = ($this->_get_protocol() === 'mail') ? $this->newline : ''; @@ -1330,7 +1294,7 @@ class CI_Email { switch ($this->_get_content_type()) { - case 'plain' : + case 'plain': $hdr .= 'Content-Type: text/plain; charset='.$this->charset.$this->newline .'Content-Transfer-Encoding: '.$this->_get_encoding(); @@ -1347,7 +1311,7 @@ class CI_Email { return; - case 'html' : + case 'html': if ($this->send_multipart === FALSE) { @@ -1356,14 +1320,16 @@ class CI_Email { } else { - $hdr .= 'Content-Type: multipart/alternative; boundary="'.$this->_alt_boundary.'"'; + $boundary = uniqid('B_ALT_'); + $hdr .= 'Content-Type: multipart/alternative; boundary="'.$boundary.'"'; $body .= $this->_get_mime_message().$this->newline.$this->newline - .'--'.$this->_alt_boundary.$this->newline + .'--'.$boundary.$this->newline .'Content-Type: text/plain; charset='.$this->charset.$this->newline .'Content-Transfer-Encoding: '.$this->_get_encoding().$this->newline.$this->newline - .$this->_get_alt_message().$this->newline.$this->newline.'--'.$this->_alt_boundary.$this->newline + .$this->_get_alt_message().$this->newline.$this->newline + .'--'.$boundary.$this->newline .'Content-Type: text/html; charset='.$this->charset.$this->newline .'Content-Transfer-Encoding: quoted-printable'.$this->newline.$this->newline; @@ -1382,14 +1348,15 @@ class CI_Email { if ($this->send_multipart !== FALSE) { - $this->_finalbody .= '--'.$this->_alt_boundary.'--'; + $this->_finalbody .= '--'.$boundary.'--'; } return; - case 'plain-attach' : + case 'plain-attach': - $hdr .= 'Content-Type: multipart/mixed; boundary="'.$this->_atc_boundary.'"'; + $boundary = uniqid('B_ATC_'); + $hdr .= 'Content-Type: multipart/mixed; boundary="'.$boundary.'"'; if ($this->_get_protocol() === 'mail') { @@ -1398,29 +1365,32 @@ class CI_Email { $body .= $this->_get_mime_message().$this->newline .$this->newline - .'--'.$this->_atc_boundary.$this->newline + .'--'.$boundary.$this->newline .'Content-Type: text/plain; charset='.$this->charset.$this->newline .'Content-Transfer-Encoding: '.$this->_get_encoding().$this->newline .$this->newline .$this->_body.$this->newline.$this->newline; - $body .= $this->_prep_attachments($this->_attachments, $this->_atc_boundary); + $this->_append_attachments($body, $boundary); break; - case 'html-attach' : + case 'html-attach': - $attachments_indexed_by_multipart = $this->_attachments_indexed_by_multipart(); + $alt_boundary = uniqid('B_ALT_'); $last_boundary = NULL; - if ( ! empty($attachments_indexed_by_multipart['mixed'])) + if ($this->_attachments_have_multipart('mixed')) { - $hdr .= 'Content-Type: multipart/mixed; boundary="'.$this->_atc_boundary.'"'; - $last_boundary = $this->_atc_boundary; + $atc_boundary = uniqid('B_ATC_'); + $hdr .= 'Content-Type: multipart/mixed; boundary="'.$atc_boundary.'"'; + $last_boundary = $atc_boundary; } - if ( ! empty($attachments_indexed_by_multipart['related'])) + if ($this->_attachments_have_multipart('related')) { - $rel_boundary_header = 'Content-Type: multipart/related; boundary="'.$this->_rel_boundary.'"'; + $rel_boundary = uniqid('B_REL_'); + $rel_boundary_header = 'Content-Type: multipart/related; boundary="'.$rel_boundary.'"'; + if (isset($last_boundary)) { $body .= '--'.$last_boundary.$this->newline.$rel_boundary_header; @@ -1429,7 +1399,8 @@ class CI_Email { { $hdr .= $rel_boundary_header; } - $last_boundary = $this->_rel_boundary; + + $last_boundary = $rel_boundary; } if ($this->_get_protocol() === 'mail') @@ -1441,24 +1412,32 @@ class CI_Email { $body .= $this->_get_mime_message().$this->newline.$this->newline .'--'.$last_boundary.$this->newline - .'Content-Type: multipart/alternative; boundary="'.$this->_alt_boundary.'"'.$this->newline.$this->newline - .'--'.$this->_alt_boundary.$this->newline + .'Content-Type: multipart/alternative; boundary="'.$alt_boundary.'"'.$this->newline.$this->newline + .'--'.$alt_boundary.$this->newline .'Content-Type: text/plain; charset='.$this->charset.$this->newline .'Content-Transfer-Encoding: '.$this->_get_encoding().$this->newline.$this->newline - .$this->_get_alt_message().$this->newline.$this->newline.'--'.$this->_alt_boundary.$this->newline + .$this->_get_alt_message().$this->newline.$this->newline + .'--'.$alt_boundary.$this->newline .'Content-Type: text/html; charset='.$this->charset.$this->newline .'Content-Transfer-Encoding: quoted-printable'.$this->newline.$this->newline .$this->_prep_quoted_printable($this->_body).$this->newline.$this->newline - .'--'.$this->_alt_boundary.'--'.$this->newline.$this->newline; + .'--'.$alt_boundary.'--'.$this->newline.$this->newline; - ( ! empty($attachments_indexed_by_multipart['related'])) && $body .= $this->newline.$this->newline - .$this->_prep_attachments($attachments_indexed_by_multipart['related'], $this->_rel_boundary); + // multipart/mixed attachments + if ( ! empty($atc_boundary)) + { + $body .= $this->newline.$this->newline; + $this->_append_attachments($body, $atc_boundary, 'mixed'); + } - ( ! empty($attachments_indexed_by_multipart['mixed'])) && $body .= $this->newline.$this->newline - .$this->_prep_attachments($attachments_indexed_by_multipart['mixed'], $this->_atc_boundary); + if ( ! empty($rel_boundary)) + { + $body .= $this->newline.$this->newline; + $this->_append_attachments($body, $rel_boundary, 'related'); + } break; } @@ -1472,21 +1451,17 @@ class CI_Email { // -------------------------------------------------------------------- - /** - * Returns attachments mapped by multipart type - * - * @return array - */ - protected function _attachments_indexed_by_multipart() + protected function _attachments_have_multipart($type) { - foreach ($this->_attachments as $attachment) + foreach ($this->_attachments as &$attachment) { - $multipart = $attachment['multipart']; - isset($attachments_indexed[$multipart]) OR $attachments_indexed[$multipart] = array(); - $attachments_indexed[$multipart][] = $attachment; + if ($attachment[$i]['multipart'] === $type) + { + return TRUE; + } } - return $attachments_indexed; + return FALSE; } // -------------------------------------------------------------------- @@ -1494,35 +1469,35 @@ class CI_Email { /** * Prepares attachment string * - * @param array $attachments - * @param string $boundary Multipart boundary string + * @param string $body Message body to append to + * @param string $boundary Multipart boundary + * @param string $multipart When provided, only attachments of this type will be processed * @return string */ - protected function _prep_attachments($attachments, $boundary) + protected function _append_attachments(&$body, $boundary, $multipart = null) { - if (empty($attachments)) + for ($i = 0, $c = count($this->_attachments); $i < $c; $i++) { - return ''; - } + if (isset($multipart) && $this->_attachments[$i]['multipart'] !== $multipart) + { + continue; + } - $attachment = array(); - for ($i = 0, $c = count($attachments), $z = 0; $i < $c; $i++) - { - $filename = $attachments[$i]['name'][0]; - $basename = ($attachments[$i]['name'][1] === NULL) - ? basename($filename) : $attachments[$i]['name'][1]; + $name = isset($this->_attachments[$i]['name'][1]) + ? $this->_attachments[$i]['name'][1] + : basename($this->_attachments[$i]['name'][0]); - $attachment[$z++] = '--'.$boundary.$this->newline - .'Content-type: '.$attachments[$i]['type'].'; ' - .'name="'.$basename.'"'.$this->newline - .'Content-Disposition: '.$attachments[$i]['disposition'].';'.$this->newline + $body .= '--'.$boundary.$this->newline + .'Content-Type: '.$this->_attachments[$i]['type'].'; name="'.$name.'"'.$this->newline + .'Content-Disposition: '.$this->_attachments[$i]['disposition'].';'.$this->newline .'Content-Transfer-Encoding: base64'.$this->newline - .(empty($attachments[$i]['cid']) ? '' : 'Content-ID: <'.$attachments[$i]['cid'].'>'.$this->newline); - - $attachment[$z++] = $attachments[$i]['content']; + .(empty($this->_attachments[$i]['cid']) ? '' : 'Content-ID: <'.$this->_attachments[$i]['cid'].'>'.$this->newline.$this->newline) + .$this->_attachments[$i]['content'].$this->newline; } - return implode($this->newline, $attachment).$this->newline.'--'.$boundary.'--'; + // $name won't be set if no attachments were appended, + // and therefore a boundary wouldn't be necessary + empty($name) OR $body .= '--'.$boundary.'--'; } // -------------------------------------------------------------------- -- cgit v1.2.3-24-g4f1b From e341601efed83a2c9cdca72de30de43a7ae12e1d Mon Sep 17 00:00:00 2001 From: Robert Angyal Date: Sat, 4 Jun 2016 12:12:28 +0200 Subject: Update Email.php --- system/libraries/Email.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'system/libraries/Email.php') diff --git a/system/libraries/Email.php b/system/libraries/Email.php index 21b62fea0..0a55e1841 100644 --- a/system/libraries/Email.php +++ b/system/libraries/Email.php @@ -1426,17 +1426,17 @@ class CI_Email { .$this->_prep_quoted_printable($this->_body).$this->newline.$this->newline .'--'.$alt_boundary.'--'.$this->newline.$this->newline; - // multipart/mixed attachments - if ( ! empty($atc_boundary)) + if ( ! empty($rel_boundary)) { $body .= $this->newline.$this->newline; - $this->_append_attachments($body, $atc_boundary, 'mixed'); + $this->_append_attachments($body, $rel_boundary, 'related'); } - if ( ! empty($rel_boundary)) + // multipart/mixed attachments + if ( ! empty($atc_boundary)) { $body .= $this->newline.$this->newline; - $this->_append_attachments($body, $rel_boundary, 'related'); + $this->_append_attachments($body, $atc_boundary, 'mixed'); } break; @@ -1455,7 +1455,7 @@ class CI_Email { { foreach ($this->_attachments as &$attachment) { - if ($attachment[$i]['multipart'] === $type) + if ($attachment['multipart'] === $type) { return TRUE; } -- cgit v1.2.3-24-g4f1b From 3c42279598dfdd4832b1411f4a94355f2025db4b Mon Sep 17 00:00:00 2001 From: Andrey Andreev Date: Mon, 6 Jun 2016 09:44:50 +0300 Subject: Merge branch 'feature/email-attachments' into develop --- system/libraries/Email.php | 194 +++++++++++++++++++++++++++------------------ 1 file changed, 117 insertions(+), 77 deletions(-) (limited to 'system/libraries/Email.php') diff --git a/system/libraries/Email.php b/system/libraries/Email.php index 6ff3efad9..f8772c656 100644 --- a/system/libraries/Email.php +++ b/system/libraries/Email.php @@ -149,13 +149,6 @@ class CI_Email { */ public $charset = 'UTF-8'; - /** - * Multipart message - * - * @var string 'mixed' (in the body) or 'related' (separate) - */ - public $multipart = 'mixed'; // "mixed" (in the body) or "related" (separate) - /** * Alternative message (for HTML messages only) * @@ -260,20 +253,6 @@ class CI_Email { */ protected $_finalbody = ''; - /** - * multipart/alternative boundary - * - * @var string - */ - protected $_alt_boundary = ''; - - /** - * Attachment boundary - * - * @var string - */ - protected $_atc_boundary = ''; - /** * Final headers to send * @@ -743,7 +722,8 @@ class CI_Email { 'name' => array($file, $newname), 'disposition' => empty($disposition) ? 'attachment' : $disposition, // Can also be 'inline' Not sure if it matters 'type' => $mime, - 'content' => chunk_split(base64_encode($file_content)) + 'content' => chunk_split(base64_encode($file_content)), + 'multipart' => 'mixed' ); return $this; @@ -761,15 +741,11 @@ class CI_Email { */ public function attachment_cid($filename) { - if ($this->multipart !== 'related') - { - $this->multipart = 'related'; // Thunderbird need this for inline images - } - for ($i = 0, $c = count($this->_attachments); $i < $c; $i++) { if ($this->_attachments[$i]['name'][0] === $filename) { + $this->_attachments[$i]['multipart'] = 'related'; $this->_attachments[$i]['cid'] = uniqid(basename($this->_attachments[$i]['name'][0]).'@'); return $this->_attachments[$i]['cid']; } @@ -913,19 +889,6 @@ class CI_Email { // -------------------------------------------------------------------- - /** - * Set Message Boundary - * - * @return void - */ - protected function _set_boundaries() - { - $this->_alt_boundary = 'B_ALT_'.uniqid(''); // multipart/alternative - $this->_atc_boundary = 'B_ATC_'.uniqid(''); // attachment boundary - } - - // -------------------------------------------------------------------- - /** * Get the Message ID * @@ -993,9 +956,9 @@ class CI_Email { { if ($this->mailtype === 'html') { - return (count($this->_attachments) === 0) ? 'html' : 'html-attach'; + return empty($this->_attachments) ? 'html' : 'html-attach'; } - elseif ($this->mailtype === 'text' && count($this->_attachments) > 0) + elseif ($this->mailtype === 'text' && ! empty($this->_attachments)) { return 'plain-attach'; } @@ -1301,7 +1264,6 @@ class CI_Email { $this->_body = $this->word_wrap($this->_body); } - $this->_set_boundaries(); $this->_write_headers(); $hdr = ($this->_get_protocol() === 'mail') ? $this->newline : ''; @@ -1309,7 +1271,7 @@ class CI_Email { switch ($this->_get_content_type()) { - case 'plain' : + case 'plain': $hdr .= 'Content-Type: text/plain; charset='.$this->charset.$this->newline .'Content-Transfer-Encoding: '.$this->_get_encoding(); @@ -1326,7 +1288,7 @@ class CI_Email { return; - case 'html' : + case 'html': if ($this->send_multipart === FALSE) { @@ -1335,14 +1297,16 @@ class CI_Email { } else { - $hdr .= 'Content-Type: multipart/alternative; boundary="'.$this->_alt_boundary.'"'; + $boundary = uniqid('B_ALT_'); + $hdr .= 'Content-Type: multipart/alternative; boundary="'.$boundary.'"'; $body .= $this->_get_mime_message().$this->newline.$this->newline - .'--'.$this->_alt_boundary.$this->newline + .'--'.$boundary.$this->newline .'Content-Type: text/plain; charset='.$this->charset.$this->newline .'Content-Transfer-Encoding: '.$this->_get_encoding().$this->newline.$this->newline - .$this->_get_alt_message().$this->newline.$this->newline.'--'.$this->_alt_boundary.$this->newline + .$this->_get_alt_message().$this->newline.$this->newline + .'--'.$boundary.$this->newline .'Content-Type: text/html; charset='.$this->charset.$this->newline .'Content-Transfer-Encoding: quoted-printable'.$this->newline.$this->newline; @@ -1361,14 +1325,15 @@ class CI_Email { if ($this->send_multipart !== FALSE) { - $this->_finalbody .= '--'.$this->_alt_boundary.'--'; + $this->_finalbody .= '--'.$boundary.'--'; } return; - case 'plain-attach' : + case 'plain-attach': - $hdr .= 'Content-Type: multipart/'.$this->multipart.'; boundary="'.$this->_atc_boundary.'"'; + $boundary = uniqid('B_ATC_'); + $hdr .= 'Content-Type: multipart/mixed; boundary="'.$boundary.'"'; if ($this->_get_protocol() === 'mail') { @@ -1377,59 +1342,83 @@ class CI_Email { $body .= $this->_get_mime_message().$this->newline .$this->newline - .'--'.$this->_atc_boundary.$this->newline + .'--'.$boundary.$this->newline .'Content-Type: text/plain; charset='.$this->charset.$this->newline .'Content-Transfer-Encoding: '.$this->_get_encoding().$this->newline .$this->newline .$this->_body.$this->newline.$this->newline; - break; - case 'html-attach' : + $this->_append_attachments($body, $boundary); - $hdr .= 'Content-Type: multipart/'.$this->multipart.'; boundary="'.$this->_atc_boundary.'"'; + break; + case 'html-attach': + + $alt_boundary = uniqid('B_ALT_'); + $last_boundary = NULL; + + if ($this->_attachments_have_multipart('mixed')) + { + $atc_boundary = uniqid('B_ATC_'); + $hdr .= 'Content-Type: multipart/mixed; boundary="'.$atc_boundary.'"'; + $last_boundary = $atc_boundary; + } + + if ($this->_attachments_have_multipart('related')) + { + $rel_boundary = uniqid('B_REL_'); + $rel_boundary_header = 'Content-Type: multipart/related; boundary="'.$rel_boundary.'"'; + + if (isset($last_boundary)) + { + $body .= '--'.$last_boundary.$this->newline.$rel_boundary_header; + } + else + { + $hdr .= $rel_boundary_header; + } + + $last_boundary = $rel_boundary; + } if ($this->_get_protocol() === 'mail') { $this->_header_str .= $hdr; } + strlen($body) && $body .= $this->newline.$this->newline; $body .= $this->_get_mime_message().$this->newline.$this->newline - .'--'.$this->_atc_boundary.$this->newline + .'--'.$last_boundary.$this->newline - .'Content-Type: multipart/alternative; boundary="'.$this->_alt_boundary.'"'.$this->newline.$this->newline - .'--'.$this->_alt_boundary.$this->newline + .'Content-Type: multipart/alternative; boundary="'.$alt_boundary.'"'.$this->newline.$this->newline + .'--'.$alt_boundary.$this->newline .'Content-Type: text/plain; charset='.$this->charset.$this->newline .'Content-Transfer-Encoding: '.$this->_get_encoding().$this->newline.$this->newline - .$this->_get_alt_message().$this->newline.$this->newline.'--'.$this->_alt_boundary.$this->newline + .$this->_get_alt_message().$this->newline.$this->newline + .'--'.$alt_boundary.$this->newline .'Content-Type: text/html; charset='.$this->charset.$this->newline .'Content-Transfer-Encoding: quoted-printable'.$this->newline.$this->newline .$this->_prep_quoted_printable($this->_body).$this->newline.$this->newline - .'--'.$this->_alt_boundary.'--'.$this->newline.$this->newline; + .'--'.$alt_boundary.'--'.$this->newline.$this->newline; - break; - } - - $attachment = array(); - for ($i = 0, $c = count($this->_attachments), $z = 0; $i < $c; $i++) - { - $filename = $this->_attachments[$i]['name'][0]; - $basename = ($this->_attachments[$i]['name'][1] === NULL) - ? basename($filename) : $this->_attachments[$i]['name'][1]; + if ( ! empty($rel_boundary)) + { + $body .= $this->newline.$this->newline; + $this->_append_attachments($body, $rel_boundary, 'related'); + } - $attachment[$z++] = '--'.$this->_atc_boundary.$this->newline - .'Content-type: '.$this->_attachments[$i]['type'].'; ' - .'name="'.$basename.'"'.$this->newline - .'Content-Disposition: '.$this->_attachments[$i]['disposition'].';'.$this->newline - .'Content-Transfer-Encoding: base64'.$this->newline - .(empty($this->_attachments[$i]['cid']) ? '' : 'Content-ID: <'.$this->_attachments[$i]['cid'].'>'.$this->newline); + // multipart/mixed attachments + if ( ! empty($atc_boundary)) + { + $body .= $this->newline.$this->newline; + $this->_append_attachments($body, $atc_boundary, 'mixed'); + } - $attachment[$z++] = $this->_attachments[$i]['content']; + break; } - $body .= implode($this->newline, $attachment).$this->newline.'--'.$this->_atc_boundary.'--'; $this->_finalbody = ($this->_get_protocol() === 'mail') ? $body : $hdr.$this->newline.$this->newline.$body; @@ -1439,6 +1428,57 @@ class CI_Email { // -------------------------------------------------------------------- + protected function _attachments_have_multipart($type) + { + foreach ($this->_attachments as &$attachment) + { + if ($attachment['multipart'] === $type) + { + return TRUE; + } + } + + return FALSE; + } + + // -------------------------------------------------------------------- + + /** + * Prepares attachment string + * + * @param string $body Message body to append to + * @param string $boundary Multipart boundary + * @param string $multipart When provided, only attachments of this type will be processed + * @return string + */ + protected function _append_attachments(&$body, $boundary, $multipart = null) + { + for ($i = 0, $c = count($this->_attachments); $i < $c; $i++) + { + if (isset($multipart) && $this->_attachments[$i]['multipart'] !== $multipart) + { + continue; + } + + $name = isset($this->_attachments[$i]['name'][1]) + ? $this->_attachments[$i]['name'][1] + : basename($this->_attachments[$i]['name'][0]); + + $body .= '--'.$boundary.$this->newline + .'Content-Type: '.$this->_attachments[$i]['type'].'; name="'.$name.'"'.$this->newline + .'Content-Disposition: '.$this->_attachments[$i]['disposition'].';'.$this->newline + .'Content-Transfer-Encoding: base64'.$this->newline + .(empty($this->_attachments[$i]['cid']) ? '' : 'Content-ID: <'.$this->_attachments[$i]['cid'].'>'.$this->newline.$this->newline) + .$this->_attachments[$i]['content'].$this->newline; + } + + // $name won't be set if no attachments were appended, + // and therefore a boundary wouldn't be necessary + empty($name) OR $body .= '--'.$boundary.'--'; + } + + // -------------------------------------------------------------------- + /** * Prep Quoted Printable * -- cgit v1.2.3-24-g4f1b From 0c821bbeb549077eb5c0550e6de6df0adba3d4fa Mon Sep 17 00:00:00 2001 From: Andrey Andreev Date: Tue, 19 Jul 2016 16:04:02 +0300 Subject: Fix #4712 --- system/libraries/Email.php | 33 +++++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 10 deletions(-) (limited to 'system/libraries/Email.php') diff --git a/system/libraries/Email.php b/system/libraries/Email.php index f8772c656..be89d6569 100644 --- a/system/libraries/Email.php +++ b/system/libraries/Email.php @@ -1919,6 +1919,7 @@ class CI_Email { if ( ! $this->_send_command('from', $this->clean_email($this->_headers['From']))) { + $this->_smtp_end(); return FALSE; } @@ -1926,6 +1927,7 @@ class CI_Email { { if ( ! $this->_send_command('to', $val)) { + $this->_smtp_end(); return FALSE; } } @@ -1936,6 +1938,7 @@ class CI_Email { { if ($val !== '' && ! $this->_send_command('to', $val)) { + $this->_smtp_end(); return FALSE; } } @@ -1947,6 +1950,7 @@ class CI_Email { { if ($val !== '' && ! $this->_send_command('to', $val)) { + $this->_smtp_end(); return FALSE; } } @@ -1954,6 +1958,7 @@ class CI_Email { if ( ! $this->_send_command('data')) { + $this->_smtp_end(); return FALSE; } @@ -1963,29 +1968,37 @@ class CI_Email { $this->_send_data('.'); $reply = $this->_get_smtp_data(); - $this->_set_error_message($reply); + $this->_smtp_end(); + if (strpos($reply, '250') !== 0) { $this->_set_error_message('lang:email_smtp_error', $reply); return FALSE; } - if ($this->smtp_keepalive) - { - $this->_send_command('reset'); - } - else - { - $this->_send_command('quit'); - } - return TRUE; } // -------------------------------------------------------------------- + /** + * SMTP End + * + * Shortcut to send RSET or QUIT depending on keep-alive + * + * @return void + */ + protected function _smtp_end() + { + ($this->smtp_keepalive) + ? $this->_send_command('reset') + : $this->_send_command('quit'); + } + + // -------------------------------------------------------------------- + /** * SMTP Connect * -- cgit v1.2.3-24-g4f1b From a838279625becfba98ccb7635d35c67297129c42 Mon Sep 17 00:00:00 2001 From: Andrey Andreev Date: Thu, 28 Jul 2016 16:40:12 +0300 Subject: Remove dead code written for PHP 5.2 --- system/libraries/Email.php | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) (limited to 'system/libraries/Email.php') diff --git a/system/libraries/Email.php b/system/libraries/Email.php index be89d6569..5049578ed 100644 --- a/system/libraries/Email.php +++ b/system/libraries/Email.php @@ -1514,14 +1514,7 @@ class CI_Email { // which only works with "\n". if ($this->crlf === "\r\n") { - if (is_php('5.3')) - { - return quoted_printable_encode($str); - } - elseif (function_exists('imap_8bit')) - { - return imap_8bit($str); - } + return quoted_printable_encode($str); } // Reduce multiple spaces & remove nulls -- cgit v1.2.3-24-g4f1b From 9b0f5fa0339eb1f74ff06e769d71e5911ba2be06 Mon Sep 17 00:00:00 2001 From: Andrey Andreev Date: Mon, 1 Aug 2016 13:54:06 +0300 Subject: [ci skip] Fix #4739 --- system/libraries/Email.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'system/libraries/Email.php') diff --git a/system/libraries/Email.php b/system/libraries/Email.php index 5049578ed..315200344 100644 --- a/system/libraries/Email.php +++ b/system/libraries/Email.php @@ -1468,7 +1468,8 @@ class CI_Email { .'Content-Type: '.$this->_attachments[$i]['type'].'; name="'.$name.'"'.$this->newline .'Content-Disposition: '.$this->_attachments[$i]['disposition'].';'.$this->newline .'Content-Transfer-Encoding: base64'.$this->newline - .(empty($this->_attachments[$i]['cid']) ? '' : 'Content-ID: <'.$this->_attachments[$i]['cid'].'>'.$this->newline.$this->newline) + .(empty($this->_attachments[$i]['cid']) ? '' : 'Content-ID: <'.$this->_attachments[$i]['cid'].'>'.$this->newline) + .$this->newline .$this->_attachments[$i]['content'].$this->newline; } -- cgit v1.2.3-24-g4f1b From a309badf3a73f427af030e790e5080347da67372 Mon Sep 17 00:00:00 2001 From: Kristaps V Date: Fri, 12 Aug 2016 17:55:36 +0300 Subject: Fix custom user agent not working Signed-off-by: Kristaps V --- system/libraries/Email.php | 1 + 1 file changed, 1 insertion(+) (limited to 'system/libraries/Email.php') diff --git a/system/libraries/Email.php b/system/libraries/Email.php index 50d0cd04e..426731135 100644 --- a/system/libraries/Email.php +++ b/system/libraries/Email.php @@ -1206,6 +1206,7 @@ class CI_Email { */ protected function _build_headers() { + $this->set_header('User-Agent', $this->useragent); $this->set_header('X-Sender', $this->clean_email($this->_headers['From'])); $this->set_header('X-Mailer', $this->useragent); $this->set_header('X-Priority', $this->_priorities[$this->priority]); -- cgit v1.2.3-24-g4f1b From 50e87ec848f27bb5e40093ade2b67dc104679fb9 Mon Sep 17 00:00:00 2001 From: Igor Ostapchuk Date: Sun, 21 Aug 2016 16:28:28 +0300 Subject: return fix --- system/libraries/Email.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'system/libraries/Email.php') diff --git a/system/libraries/Email.php b/system/libraries/Email.php index 50d0cd04e..6a7e2b3a7 100644 --- a/system/libraries/Email.php +++ b/system/libraries/Email.php @@ -1202,7 +1202,7 @@ class CI_Email { /** * Build final headers * - * @return string + * @return void */ protected function _build_headers() { @@ -2046,7 +2046,7 @@ class CI_Email { * * @param string * @param string - * @return string + * @return bool */ protected function _send_command($cmd, $data = '') { -- cgit v1.2.3-24-g4f1b From 1927709235ed11f51b700abcb390b660e2762053 Mon Sep 17 00:00:00 2001 From: Andrey Andreev Date: Mon, 22 Aug 2016 11:34:56 +0300 Subject: Merge pull request #4778 from antydemant/patch-1 [ci skip] Docblock return type corrections --- system/libraries/Email.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'system/libraries/Email.php') diff --git a/system/libraries/Email.php b/system/libraries/Email.php index 315200344..7f49c1b3d 100644 --- a/system/libraries/Email.php +++ b/system/libraries/Email.php @@ -1202,7 +1202,7 @@ class CI_Email { /** * Build final headers * - * @return string + * @return void */ protected function _build_headers() { @@ -2046,7 +2046,7 @@ class CI_Email { * * @param string * @param string - * @return string + * @return bool */ protected function _send_command($cmd, $data = '') { -- cgit v1.2.3-24-g4f1b From 4e2cdec6ff4b4af5f994be4c348ad3b9a9a2942f Mon Sep 17 00:00:00 2001 From: Andrey Andreev Date: Fri, 28 Oct 2016 14:19:08 +0300 Subject: Improve byte-safety --- system/libraries/Email.php | 87 ++++++++++++++++++++++++++++++++++++---------- 1 file changed, 68 insertions(+), 19 deletions(-) (limited to 'system/libraries/Email.php') diff --git a/system/libraries/Email.php b/system/libraries/Email.php index 7f49c1b3d..676bbcafb 100644 --- a/system/libraries/Email.php +++ b/system/libraries/Email.php @@ -374,6 +374,13 @@ class CI_Email { 5 => '5 (Lowest)' ); + /** + * mbstring.func_override flag + * + * @var bool + */ + protected static $func_override; + // -------------------------------------------------------------------- /** @@ -390,6 +397,8 @@ class CI_Email { $this->initialize($config); $this->_safe_mode = ( ! is_php('5.4') && ini_get('safe_mode')); + isset(self::$func_override) OR self::$func_override = (extension_loaded('mbstring') && ini_get('mbstring.func_override')); + log_message('info', 'Email Class Initialized'); } @@ -1037,7 +1046,7 @@ class CI_Email { { if (function_exists('idn_to_ascii') && $atpos = strpos($email, '@')) { - $email = substr($email, 0, ++$atpos).idn_to_ascii(substr($email, $atpos)); + $email = self::substr($email, 0, ++$atpos).idn_to_ascii(self::substr($email, $atpos)); } return (bool) filter_var($email, FILTER_VALIDATE_EMAIL); @@ -1154,7 +1163,7 @@ class CI_Email { { // Is the line within the allowed character count? // If so we'll join it to the output and continue - if (mb_strlen($line) <= $charlim) + if (self::strlen($line) <= $charlim) { $output .= $line.$this->newline; continue; @@ -1170,10 +1179,10 @@ class CI_Email { } // Trim the word down - $temp .= mb_substr($line, 0, $charlim - 1); - $line = mb_substr($line, $charlim - 1); + $temp .= self::substr($line, 0, $charlim - 1); + $line = self::substr($line, $charlim - 1); } - while (mb_strlen($line) > $charlim); + while (self::strlen($line) > $charlim); // If $temp contains data it means we had to split up an over-length // word into smaller chunks so we'll add it back to our current line @@ -1385,7 +1394,7 @@ class CI_Email { $this->_header_str .= $hdr; } - strlen($body) && $body .= $this->newline.$this->newline; + self::strlen($body) && $body .= $this->newline.$this->newline; $body .= $this->_get_mime_message().$this->newline.$this->newline .'--'.$last_boundary.$this->newline @@ -1532,7 +1541,7 @@ class CI_Email { foreach (explode("\n", $str) as $line) { - $length = strlen($line); + $length = self::strlen($line); $temp = ''; // Loop through each character in the line to add soft-wrap @@ -1567,7 +1576,7 @@ class CI_Email { // If we're at the character limit, add the line to the output, // reset our temp variable, and keep on chuggin' - if ((strlen($temp) + strlen($char)) >= 76) + if ((self::strlen($temp) + self::strlen($char)) >= 76) { $output .= $temp.$escape.$this->crlf; $temp = ''; @@ -1582,7 +1591,7 @@ class CI_Email { } // get rid of extra CRLF tacked onto the end - return substr($output, 0, strlen($this->crlf) * -1); + return self::substr($output, 0, self::strlen($this->crlf) * -1); } // -------------------------------------------------------------------- @@ -1624,7 +1633,7 @@ class CI_Email { // iconv_mime_encode() will always put a header field name. // We've passed it an empty one, but it still prepends our // encoded string with ': ', so we need to strip it. - return substr($output, 2); + return self::substr($output, 2); } $chars = iconv_strlen($str, 'UTF-8'); @@ -1636,10 +1645,10 @@ class CI_Email { } // We might already have this set for UTF-8 - isset($chars) OR $chars = strlen($str); + isset($chars) OR $chars = self::strlen($str); $output = '=?'.$this->charset.'?Q?'; - for ($i = 0, $length = strlen($output); $i < $chars; $i++) + for ($i = 0, $length = self::strlen($output); $i < $chars; $i++) { $chr = ($this->charset === 'UTF-8' && ICONV_ENABLED === TRUE) ? '='.implode('=', str_split(strtoupper(bin2hex(iconv_substr($str, $i, 1, $this->charset))), 2)) @@ -1647,11 +1656,11 @@ class CI_Email { // RFC 2045 sets a limit of 76 characters per line. // We'll append ?= to the end of each line though. - if ($length + ($l = strlen($chr)) > 74) + if ($length + ($l = self::strlen($chr)) > 74) { $output .= '?='.$this->crlf // EOL .' =?'.$this->charset.'?Q?'.$chr; // New line - $length = 6 + strlen($this->charset) + $l; // Reset the length for the new line + $length = 6 + self::strlen($this->charset) + $l; // Reset the length for the new line } else { @@ -1744,14 +1753,14 @@ class CI_Email { if ($i === $float) { - $chunk[] = substr($set, 1); + $chunk[] = self::substr($set, 1); $float += $this->bcc_batch_size; $set = ''; } if ($i === $c-1) { - $chunk[] = substr($set, 1); + $chunk[] = self::substr($set, 1); } } @@ -2109,7 +2118,7 @@ class CI_Email { $this->_debug_msg[] = '
'.$cmd.': '.$reply.'
'; - if ((int) substr($reply, 0, 3) !== $resp) + if ((int) self::substr($reply, 0, 3) !== $resp) { $this->_set_error_message('lang:email_smtp_error', $reply); return FALSE; @@ -2196,9 +2205,9 @@ class CI_Email { protected function _send_data($data) { $data .= $this->newline; - for ($written = $timestamp = 0, $length = strlen($data); $written < $length; $written += $result) + for ($written = $timestamp = 0, $length = self::strlen($data); $written < $length; $written += $result) { - if (($result = fwrite($this->_smtp_connect, substr($data, $written))) === FALSE) + if (($result = fwrite($this->_smtp_connect, self::substr($data, $written))) === FALSE) { break; } @@ -2382,4 +2391,44 @@ class CI_Email { { is_resource($this->_smtp_connect) && $this->_send_command('quit'); } + + // -------------------------------------------------------------------- + + /** + * Byte-safe strlen() + * + * @param string $str + * @return int + */ + protected static function strlen($str) + { + return (self::$func_override) + ? mb_strlen($str, '8bit') + : strlen($str); + } + + // -------------------------------------------------------------------- + + /** + * Byte-safe substr() + * + * @param string $str + * @param int $start + * @param int $length + * @return string + */ + protected static function substr($str, $start, $length = NULL) + { + if (self::$func_override) + { + // mb_substr($str, $start, null, '8bit') returns an empty + // string on PHP 5.3 + isset($length) OR $length = ($start >= 0 ? self::strlen($str) - $start : -$start); + return mb_substr($str, $start, $length, '8bit'); + } + + return isset($length) + ? substr($str, $start, $length) + : substr($str, $start); + } } -- cgit v1.2.3-24-g4f1b From 8db01f13809a92bac7bc95b02893175d7654d627 Mon Sep 17 00:00:00 2001 From: Andrey Andreev Date: Thu, 1 Dec 2016 14:06:57 +0200 Subject: Fix #4844 --- system/libraries/Email.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'system/libraries/Email.php') diff --git a/system/libraries/Email.php b/system/libraries/Email.php index 676bbcafb..2e6f5be90 100644 --- a/system/libraries/Email.php +++ b/system/libraries/Email.php @@ -1878,7 +1878,7 @@ class CI_Email { // is popen() enabled? if ( ! function_usable('popen') OR FALSE === ($fp = @popen( - $this->mailpath.' -oi -f '.$this->clean_email($this->_headers['From']).' -t' + $this->mailpath.' -oi -f '.escapeshellarg($this->clean_email($this->_headers['From'])).' -t' , 'w')) ) // server probably has popen disabled, so nothing we can do to get a verbose error. { -- cgit v1.2.3-24-g4f1b From d76431db46e04d650c1c538493021cdf336d1301 Mon Sep 17 00:00:00 2001 From: Andrey Andreev Date: Thu, 1 Dec 2016 14:23:40 +0200 Subject: Switch CI_Email::$validate to On by default Relevant: #4844 --- system/libraries/Email.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'system/libraries/Email.php') diff --git a/system/libraries/Email.php b/system/libraries/Email.php index 162cc7777..90a68f129 100644 --- a/system/libraries/Email.php +++ b/system/libraries/Email.php @@ -161,7 +161,7 @@ class CI_Email { * * @var bool */ - public $validate = FALSE; + public $validate = TRUE; /** * X-Priority header value. -- cgit v1.2.3-24-g4f1b From 24c866628d0ce5463d7e8b4eba512fa9e7752dfd Mon Sep 17 00:00:00 2001 From: Andrey Andreev Date: Wed, 14 Dec 2016 16:14:13 +0200 Subject: Drop all PHP 5.3-related code --- system/libraries/Email.php | 36 +++--------------------------------- 1 file changed, 3 insertions(+), 33 deletions(-) (limited to 'system/libraries/Email.php') diff --git a/system/libraries/Email.php b/system/libraries/Email.php index 90a68f129..1191e2350 100644 --- a/system/libraries/Email.php +++ b/system/libraries/Email.php @@ -225,13 +225,6 @@ class CI_Email { // -------------------------------------------------------------------- - /** - * Whether PHP is running in safe mode. Initialized by the class constructor. - * - * @var bool - */ - protected $_safe_mode = FALSE; - /** * Subject header * @@ -395,7 +388,6 @@ class CI_Email { { $this->charset = config_item('charset'); $this->initialize($config); - $this->_safe_mode = ( ! is_php('5.4') && ini_get('safe_mode')); isset(self::$func_override) OR self::$func_override = (extension_loaded('mbstring') && ini_get('mbstring.func_override')); @@ -676,18 +668,6 @@ class CI_Email { public function message($body) { $this->_body = rtrim(str_replace("\r", '', $body)); - - /* strip slashes only if magic quotes is ON - if we do it with magic quotes OFF, it strips real, user-inputted chars. - - NOTE: In PHP 5.4 get_magic_quotes_gpc() will always return 0 and - it will probably not exist in future versions at all. - */ - if ( ! is_php('5.4') && get_magic_quotes_gpc()) - { - $this->_body = stripslashes($this->_body); - } - return $this; } @@ -1854,16 +1834,9 @@ class CI_Email { $this->_recipients = implode(', ', $this->_recipients); } - if ($this->_safe_mode === TRUE) - { - return mail($this->_recipients, $this->_subject, $this->_finalbody, $this->_header_str); - } - else - { - // most documentation of sendmail using the "-f" flag lacks a space after it, however - // we've encountered servers that seem to require it to be in place. - return mail($this->_recipients, $this->_subject, $this->_finalbody, $this->_header_str, '-f '.$this->clean_email($this->_headers['Return-Path'])); - } + // most documentation of sendmail using the "-f" flag lacks a space after it, however + // we've encountered servers that seem to require it to be in place. + return mail($this->_recipients, $this->_subject, $this->_finalbody, $this->_header_str, '-f '.$this->clean_email($this->_headers['Return-Path'])); } // -------------------------------------------------------------------- @@ -2421,9 +2394,6 @@ class CI_Email { { if (self::$func_override) { - // mb_substr($str, $start, null, '8bit') returns an empty - // string on PHP 5.3 - isset($length) OR $length = ($start >= 0 ? self::strlen($str) - $start : -$start); return mb_substr($str, $start, $length, '8bit'); } -- cgit v1.2.3-24-g4f1b From fced25f5728ce81fe810216fcaa4ccec7523f6c9 Mon Sep 17 00:00:00 2001 From: Master Yoda Date: Sat, 31 Dec 2016 08:46:18 -0800 Subject: Update copyright data to 2017 --- system/libraries/Email.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'system/libraries/Email.php') diff --git a/system/libraries/Email.php b/system/libraries/Email.php index 1191e2350..fbf0cb7dc 100644 --- a/system/libraries/Email.php +++ b/system/libraries/Email.php @@ -6,7 +6,7 @@ * * This content is released under the MIT License (MIT) * - * Copyright (c) 2014 - 2016, British Columbia Institute of Technology + * Copyright (c) 2014 - 2017, British Columbia Institute of Technology * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -29,7 +29,7 @@ * @package CodeIgniter * @author EllisLab Dev Team * @copyright Copyright (c) 2008 - 2014, EllisLab, Inc. (https://ellislab.com/) - * @copyright Copyright (c) 2014 - 2016, British Columbia Institute of Technology (http://bcit.ca/) + * @copyright Copyright (c) 2014 - 2017, British Columbia Institute of Technology (http://bcit.ca/) * @license http://opensource.org/licenses/MIT MIT License * @link https://codeigniter.com * @since Version 1.0.0 -- cgit v1.2.3-24-g4f1b From da60e9bc66ec90970fbd2dfd08b0a6e66b9f5f5f Mon Sep 17 00:00:00 2001 From: Master Yoda Date: Sat, 31 Dec 2016 08:46:18 -0800 Subject: Update copyright data to 2017 --- system/libraries/Email.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'system/libraries/Email.php') diff --git a/system/libraries/Email.php b/system/libraries/Email.php index 2e6f5be90..4ab873586 100644 --- a/system/libraries/Email.php +++ b/system/libraries/Email.php @@ -6,7 +6,7 @@ * * This content is released under the MIT License (MIT) * - * Copyright (c) 2014 - 2016, British Columbia Institute of Technology + * Copyright (c) 2014 - 2017, British Columbia Institute of Technology * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -29,7 +29,7 @@ * @package CodeIgniter * @author EllisLab Dev Team * @copyright Copyright (c) 2008 - 2014, EllisLab, Inc. (https://ellislab.com/) - * @copyright Copyright (c) 2014 - 2016, British Columbia Institute of Technology (http://bcit.ca/) + * @copyright Copyright (c) 2014 - 2017, British Columbia Institute of Technology (http://bcit.ca/) * @license http://opensource.org/licenses/MIT MIT License * @link https://codeigniter.com * @since Version 1.0.0 -- cgit v1.2.3-24-g4f1b From a9600161a845c6f26eebd9822ae7d799b89c8a00 Mon Sep 17 00:00:00 2001 From: Andrey Andreev Date: Thu, 5 Jan 2017 17:35:28 +0200 Subject: Address #4963 Would supersede PR #4966 --- system/libraries/Email.php | 54 ++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 47 insertions(+), 7 deletions(-) (limited to 'system/libraries/Email.php') diff --git a/system/libraries/Email.php b/system/libraries/Email.php index 4ab873586..e25015450 100644 --- a/system/libraries/Email.php +++ b/system/libraries/Email.php @@ -1842,6 +1842,33 @@ class CI_Email { // -------------------------------------------------------------------- + /** + * Validate email for shell + * + * Applies stricter, shell-safe validation to email addresses. + * Introduced to prevent RCE via sendmail's -f option. + * + * @see https://github.com/bcit-ci/CodeIgniter/issues/4963 + * @see https://gist.github.com/Zenexer/40d02da5e07f151adeaeeaa11af9ab36 + * @license https://creativecommons.org/publicdomain/zero/1.0/ CC0 1.0, Public Domain + * + * Credits for the base concept go to Paul Buonopane + * + * @param string $email + * @return bool + */ + protected function _validate_email_for_shell(&$email) + { + if (function_exists('idn_to_ascii') && $atpos = strpos($email, '@')) + { + $email = self::substr($email, 0, ++$atpos).idn_to_ascii(self::substr($email, $atpos)); + } + + return (filter_var($email, FILTER_VALIDATE_EMAIL) === $email && preg_match('#\A[a-z0-9._+-]+@[a-z0-9.-]{1,253}\z#i', $email)); + } + + // -------------------------------------------------------------------- + /** * Send using mail() * @@ -1854,7 +1881,11 @@ class CI_Email { $this->_recipients = implode(', ', $this->_recipients); } - if ($this->_safe_mode === TRUE) + // _validate_email_for_shell() below accepts by reference, + // so this needs to be assigned to a variable + $from = $this->clean_email($this->_headers['Return-Path']); + + if ($this->_safe_mode === TRUE || ! $this->_validate_email_for_shell($from)) { return mail($this->_recipients, $this->_subject, $this->_finalbody, $this->_header_str); } @@ -1862,7 +1893,7 @@ class CI_Email { { // most documentation of sendmail using the "-f" flag lacks a space after it, however // we've encountered servers that seem to require it to be in place. - return mail($this->_recipients, $this->_subject, $this->_finalbody, $this->_header_str, '-f '.$this->clean_email($this->_headers['Return-Path'])); + return mail($this->_recipients, $this->_subject, $this->_finalbody, $this->_header_str, '-f '.$from); } } @@ -1875,13 +1906,22 @@ class CI_Email { */ protected function _send_with_sendmail() { + // _validate_email_for_shell() below accepts by reference, + // so this needs to be assigned to a variable + $from = $this->clean_email($this->_headers['From']); + if ($this->_validate_email_for_shell($from)) + { + $from = '-f '.$from; + } + else + { + $from = ''; + } + // is popen() enabled? - if ( ! function_usable('popen') - OR FALSE === ($fp = @popen( - $this->mailpath.' -oi -f '.escapeshellarg($this->clean_email($this->_headers['From'])).' -t' - , 'w')) - ) // server probably has popen disabled, so nothing we can do to get a verbose error. + if ( ! function_usable('popen') OR FALSE === ($fp = @popen($this->mailpath.' -oi '.$from.' -t', 'w'))) { + // server probably has popen disabled, so nothing we can do to get a verbose error. return FALSE; } -- cgit v1.2.3-24-g4f1b From 6a5b5e7a426d4ab0055223011727cd382ec72b43 Mon Sep 17 00:00:00 2001 From: Andrey Andreev Date: Fri, 6 Jan 2017 13:45:55 +0200 Subject: Merge pull request #4765 from viitols/develop Fix CI_Email not sending User-Agent header --- system/libraries/Email.php | 1 + 1 file changed, 1 insertion(+) (limited to 'system/libraries/Email.php') diff --git a/system/libraries/Email.php b/system/libraries/Email.php index e25015450..a5a707917 100644 --- a/system/libraries/Email.php +++ b/system/libraries/Email.php @@ -1215,6 +1215,7 @@ class CI_Email { */ protected function _build_headers() { + $this->set_header('User-Agent', $this->useragent); $this->set_header('X-Sender', $this->clean_email($this->_headers['From'])); $this->set_header('X-Mailer', $this->useragent); $this->set_header('X-Priority', $this->_priorities[$this->priority]); -- cgit v1.2.3-24-g4f1b From cba132d7146785db1ba5fb303b723a95b119d07d Mon Sep 17 00:00:00 2001 From: Andrey Andreev Date: Fri, 6 Jan 2017 13:48:48 +0200 Subject: [ci skip] Don't set User-Agent header in CI_Email::clear() Ref: #4765 --- system/libraries/Email.php | 1 - 1 file changed, 1 deletion(-) (limited to 'system/libraries/Email.php') diff --git a/system/libraries/Email.php b/system/libraries/Email.php index a5a707917..117c4845f 100644 --- a/system/libraries/Email.php +++ b/system/libraries/Email.php @@ -458,7 +458,6 @@ class CI_Email { $this->_headers = array(); $this->_debug_msg = array(); - $this->set_header('User-Agent', $this->useragent); $this->set_header('Date', $this->_set_date()); if ($clear_attachments !== FALSE) -- cgit v1.2.3-24-g4f1b