diff options
-rw-r--r-- | .travis.yml | 5 | ||||
-rw-r--r-- | application/config/config.php | 9 | ||||
-rw-r--r-- | application/config/user_agents.php | 1 | ||||
-rw-r--r-- | system/core/CodeIgniter.php | 6 | ||||
-rw-r--r-- | system/core/Log.php | 14 | ||||
-rw-r--r-- | system/core/Output.php | 27 | ||||
-rw-r--r-- | system/core/Router.php | 61 | ||||
-rw-r--r-- | system/core/URI.php | 35 | ||||
-rw-r--r-- | system/helpers/file_helper.php | 12 | ||||
-rw-r--r-- | system/libraries/Email.php | 107 | ||||
-rw-r--r-- | system/libraries/Xmlrpc.php | 10 | ||||
-rw-r--r-- | system/libraries/Zip.php | 12 | ||||
-rw-r--r-- | tests/codeigniter/core/URI_test.php | 15 | ||||
-rw-r--r-- | tests/mocks/autoloader.php | 16 | ||||
-rw-r--r-- | tests/mocks/core/uri.php | 15 | ||||
-rw-r--r-- | user_guide_src/source/changelog.rst | 13 | ||||
-rw-r--r-- | user_guide_src/source/libraries/email.rst | 28 |
17 files changed, 250 insertions, 136 deletions
diff --git a/.travis.yml b/.travis.yml index fa9d5e563..27fe3c670 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,6 +4,7 @@ php: - 5.3 - 5.4 - 5.5 + - hhvm env: - DB=mysql @@ -22,6 +23,10 @@ before_script: script: phpunit --coverage-text --configuration tests/travis/$DB.phpunit.xml +matrix: + allow_failures: + - php: hhvm + branches: only: - develop diff --git a/application/config/config.php b/application/config/config.php index c46839330..ae748defd 100644 --- a/application/config/config.php +++ b/application/config/config.php @@ -141,15 +141,18 @@ $config['subclass_prefix'] = 'MY_'; | Allowed URL Characters |-------------------------------------------------------------------------- | -| This lets you specify with a regular expression which characters are permitted -| within your URLs. When someone tries to submit a URL with disallowed -| characters they will get a warning message. +| This lets you specify which characters are permitted within your URLs. +| When someone tries to submit a URL with disallowed characters they will +| get a warning message. | | As a security measure you are STRONGLY encouraged to restrict URLs to | as few characters as possible. By default only these are allowed: a-z 0-9~%.:_- | | Leave blank to allow all characters -- but only if you are insane. | +| The configured value is actually a regular expression character group +| and it will be executed as: ! preg_match('/^[<permitted_uri_chars>]+$/i +| | DO NOT CHANGE THIS UNLESS YOU FULLY UNDERSTAND THE REPERCUSSIONS!! | */ diff --git a/application/config/user_agents.php b/application/config/user_agents.php index 2af70bf9c..819e42b69 100644 --- a/application/config/user_agents.php +++ b/application/config/user_agents.php @@ -90,6 +90,7 @@ $browsers = array( 'Opera' => 'Opera', 'MSIE' => 'Internet Explorer', 'Internet Explorer' => 'Internet Explorer', + 'Trident.* rv' => 'Internet Explorer', 'Shiira' => 'Shiira', 'Firefox' => 'Firefox', 'Chimera' => 'Chimera', diff --git a/system/core/CodeIgniter.php b/system/core/CodeIgniter.php index 45c3485bf..cc12f149f 100644 --- a/system/core/CodeIgniter.php +++ b/system/core/CodeIgniter.php @@ -163,12 +163,6 @@ defined('BASEPATH') OR exit('No direct script access allowed'); */ $RTR =& load_class('Router', 'core'); - // Set any routing overrides that may exist in the main index file - if (isset($routing)) - { - $RTR->_set_overrides($routing); - } - /* * ------------------------------------------------------ * Instantiate the output class diff --git a/system/core/Log.php b/system/core/Log.php index b2327b8f0..63fef2088 100644 --- a/system/core/Log.php +++ b/system/core/Log.php @@ -175,10 +175,18 @@ class CI_Log { return FALSE; } - $message .= $level.' '.($level === 'INFO' ? ' -' : '-').' '.date($this->_date_fmt).' --> '.$msg."\n"; + $message .= $level.' - '.date($this->_date_fmt).' --> '.$msg."\n"; flock($fp, LOCK_EX); - fwrite($fp, $message); + + for ($written = 0, $length = strlen($message); $written < $length; $written += $result) + { + if (($result = fwrite($fp, substr($message, $written))) === FALSE) + { + break; + } + } + flock($fp, LOCK_UN); fclose($fp); @@ -187,7 +195,7 @@ class CI_Log { @chmod($filepath, FILE_WRITE_MODE); } - return TRUE; + return is_int($result); } } diff --git a/system/core/Output.php b/system/core/Output.php index cdb92b3c6..2ad8e90fa 100644 --- a/system/core/Output.php +++ b/system/core/Output.php @@ -591,7 +591,16 @@ class CI_Output { 'headers' => $this->headers )); - fwrite($fp, $cache_info.'ENDCI--->'.$output); + $output = $cache_info.'ENDCI--->'.$output; + + for ($written = 0, $length = strlen($output); $written < $length; $written += $result) + { + if (($result = fwrite($fp, substr($output, $written))) === FALSE) + { + break; + } + } + flock($fp, LOCK_UN); } else @@ -601,12 +610,20 @@ class CI_Output { } fclose($fp); - @chmod($cache_path, FILE_WRITE_MODE); - log_message('debug', 'Cache file written: '.$cache_path); + if (is_int($result)) + { + @chmod($cache_path, FILE_WRITE_MODE); + log_message('debug', 'Cache file written: '.$cache_path); - // Send HTTP cache-control headers to browser to match file cache settings. - $this->set_cache_header($_SERVER['REQUEST_TIME'], $expire); + // Send HTTP cache-control headers to browser to match file cache settings. + $this->set_cache_header($_SERVER['REQUEST_TIME'], $expire); + } + else + { + @unlink($cache_path); + log_message('error', 'Unable to write the complete cache content at: '.$cache_path); + } } // -------------------------------------------------------------------- diff --git a/system/core/Router.php b/system/core/Router.php index d467d60fd..71530ff07 100644 --- a/system/core/Router.php +++ b/system/core/Router.php @@ -102,9 +102,32 @@ class CI_Router { */ public function __construct() { + global $routing; + $this->config =& load_class('Config', 'core'); $this->uri =& load_class('URI', 'core'); $this->_set_routing(); + + // Set any routing overrides that may exist in the main index file + if (isset($routing) && is_array($routing)) + { + if (isset($routing['directory'])) + { + $this->set_directory($routing['directory']); + } + + if ( ! empty($routing['controller'])) + { + $this->set_class($routing['controller']); + } + + if (isset($routing['function'])) + { + $routing['function'] = empty($routing['function']) ? 'index' : $routing['function']; + $this->set_method($routing['function']); + } + } + log_message('debug', 'Router Class Initialized'); } @@ -131,16 +154,16 @@ class CI_Router { { if (isset($_GET[$this->config->item('directory_trigger')]) && is_string($_GET[$this->config->item('directory_trigger')])) { - $this->set_directory(trim($this->uri->_filter_uri($_GET[$this->config->item('directory_trigger')]))); + $this->set_directory(trim($this->uri->filter_uri($_GET[$this->config->item('directory_trigger')]))); $segments[] = $this->directory; } - $this->set_class(trim($this->uri->_filter_uri($_GET[$this->config->item('controller_trigger')]))); + $this->set_class(trim($this->uri->filter_uri($_GET[$this->config->item('controller_trigger')]))); $segments[] = $this->class; if ( ! empty($_GET[$this->config->item('function_trigger')]) && is_string($_GET[$this->config->item('function_trigger')])) { - $this->set_method(trim($this->uri->_filter_uri($_GET[$this->config->item('function_trigger')]))); + $this->set_method(trim($this->uri->filter_uri($_GET[$this->config->item('function_trigger')]))); $segments[] = $this->method; } } @@ -519,38 +542,6 @@ class CI_Router { return $this->directory; } - // -------------------------------------------------------------------- - - /** - * Set controller overrides - * - * @param array $routing Route overrides - * @return void - */ - public function _set_overrides($routing) - { - if ( ! is_array($routing)) - { - return; - } - - if (isset($routing['directory'])) - { - $this->set_directory($routing['directory']); - } - - if ( ! empty($routing['controller'])) - { - $this->set_class($routing['controller']); - } - - if (isset($routing['function'])) - { - $routing['function'] = empty($routing['function']) ? 'index' : $routing['function']; - $this->set_method($routing['function']); - } - } - } /* End of file Router.php */ diff --git a/system/core/URI.php b/system/core/URI.php index 5e4c80a00..3d6d202c0 100644 --- a/system/core/URI.php +++ b/system/core/URI.php @@ -70,6 +70,15 @@ class CI_URI { public $rsegments = array(); /** + * Permitted URI chars + * + * PCRE character group allowed in URI segments + * + * @var string + */ + protected $_permitted_uri_chars; + + /** * Class constructor * * Simply globalizes the $RTR object. The front @@ -81,6 +90,12 @@ class CI_URI { public function __construct() { $this->config =& load_class('Config', 'core'); + + if ($this->config->item('enable_query_strings') !== TRUE OR is_cli()) + { + $this->_permitted_uri_chars = $this->config->item('permitted_uri_chars'); + } + log_message('debug', 'URI Class Initialized'); } @@ -303,23 +318,19 @@ class CI_URI { * @param string $str * @return string */ - public function _filter_uri($str) + public function filter_uri($str) { - if ($str !== '' && $this->config->item('permitted_uri_chars') != '' && $this->config->item('enable_query_strings') === FALSE) + if ( ! empty($str) && ! empty($this->_permitted_uri_chars) && ! preg_match('/^['.$this->_permitted_uri_chars.']+$/i', $str)) { - // preg_quote() in PHP 5.3 escapes -, so the str_replace() and addition of - to preg_quote() is to maintain backwards - // compatibility as many are unaware of how characters in the permitted_uri_chars will be parsed as a regex pattern - if ( ! preg_match('|^['.str_replace(array('\\-', '\-'), '-', preg_quote($this->config->item('permitted_uri_chars'), '-')).']+$|i', $str)) - { - show_error('The URI you submitted has disallowed characters.', 400); - } + show_error('The URI you submitted has disallowed characters.', 400); } // Convert programatic characters to entities and return return str_replace( - array('$', '(', ')', '%28', '%29'), // Bad - array('$', '(', ')', '(', ')'), // Good - $str); + array('$', '(', ')', '%28', '%29'), // Bad + array('$', '(', ')', '(', ')'), // Good + $str + ); } // -------------------------------------------------------------------- @@ -365,7 +376,7 @@ class CI_URI { foreach (explode('/', preg_replace('|/*(.+?)/*$|', '\\1', $this->uri_string)) as $val) { // Filter segments for security - $val = trim($this->_filter_uri($val)); + $val = trim($this->filter_uri($val)); if ($val !== '') { diff --git a/system/helpers/file_helper.php b/system/helpers/file_helper.php index 4b45a62d0..0587740b1 100644 --- a/system/helpers/file_helper.php +++ b/system/helpers/file_helper.php @@ -79,11 +79,19 @@ if ( ! function_exists('write_file')) } flock($fp, LOCK_EX); - fwrite($fp, $data); + + for ($written = 0, $length = strlen($data); $written < $length; $written += $result) + { + if (($result = fwrite($fp, substr($data, $written))) === FALSE) + { + break; + } + } + flock($fp, LOCK_UN); fclose($fp); - return TRUE; + return is_int($result); } } diff --git a/system/libraries/Email.php b/system/libraries/Email.php index efdbfd7c1..f4efff882 100644 --- a/system/libraries/Email.php +++ b/system/libraries/Email.php @@ -710,18 +710,42 @@ class CI_Email { /** * Assign file attachments * - * @param string $filename + * @param string $file Can be local path, URL or buffered content * @param string $disposition = 'attachment' * @param string $newname = NULL * @param string $mime = '' * @return CI_Email */ - public function attach($filename, $disposition = '', $newname = NULL, $mime = '') + public function attach($file, $disposition = '', $newname = NULL, $mime = '') { + if ($mime === '') + { + if (strpos($file, '://') === FALSE && ! file_exists($file)) + { + $this->_set_error_message('lang:email_attachment_missing', $file); + return FALSE; + } + + if ( ! $fp = @fopen($file, FOPEN_READ)) + { + $this->_set_error_message('lang:email_attachment_unreadable', $file); + return FALSE; + } + + $file_content = stream_get_contents($fp); + $mime = $this->_mime_types(pathinfo($file, PATHINFO_EXTENSION)); + fclose($fp); + } + else + { + $file_content =& $file; // buffered file + } + $this->_attachments[] = array( - 'name' => array($filename, $newname), + 'name' => array($file, $newname), 'disposition' => empty($disposition) ? 'attachment' : $disposition, // Can also be 'inline' Not sure if it matters - 'type' => $mime + 'type' => $mime, + 'content' => chunk_split(base64_encode($file_content)) ); return $this; @@ -730,6 +754,35 @@ class CI_Email { // -------------------------------------------------------------------- /** + * Set and return attachment Content-ID + * + * Useful for attached inline pictures + * + * @param string $filename + * @return string + */ + 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]['cid'] = uniqid(basename($this->_attachments[$i]['name'][0]).'@'); + return $this->_attachments[$i]['cid']; + } + } + + return FALSE; + } + + // -------------------------------------------------------------------- + + /** * Add a Header Item * * @param string @@ -1361,47 +1414,22 @@ class CI_Email { $filename = $this->_attachments[$i]['name'][0]; $basename = ($this->_attachments[$i]['name'][1] === NULL) ? basename($filename) : $this->_attachments[$i]['name'][1]; - $ctype = $this->_attachments[$i]['type']; - $file_content = ''; - - if ($ctype === '') - { - if ( ! file_exists($filename)) - { - $this->_set_error_message('lang:email_attachment_missing', $filename); - return FALSE; - } - - $file = filesize($filename) +1; - - if ( ! $fp = fopen($filename, FOPEN_READ)) - { - $this->_set_error_message('lang:email_attachment_unreadable', $filename); - return FALSE; - } - - $ctype = $this->_mime_types(pathinfo($filename, PATHINFO_EXTENSION)); - $file_content = fread($fp, $file); - fclose($fp); - } - else - { - $file_content =& $this->_attachments[$i]['name'][0]; - } $attachment[$z++] = '--'.$this->_atc_boundary.$this->newline - .'Content-type: '.$ctype.'; ' + .'Content-type: '.$this->_attachments[$i]['type'].'; ' .'name="'.$basename.'"'.$this->newline .'Content-Disposition: '.$this->_attachments[$i]['disposition'].';'.$this->newline - .'Content-Transfer-Encoding: base64'.$this->newline; + .'Content-Transfer-Encoding: base64'.$this->newline + .(empty($this->_attachments[$i]['cid']) ? '' : 'Content-ID: <'.$this->_attachments[$i]['cid'].'>'.$this->newline); - $attachment[$z++] = chunk_split(base64_encode($file_content)); + $attachment[$z++] = $this->_attachments[$i]['content']; } $body .= implode($this->newline, $attachment).$this->newline.'--'.$this->_atc_boundary.'--'; $this->_finalbody = ($this->_get_protocol() === 'mail') ? $body : $hdr.$this->newline.$this->newline.$body; + return TRUE; } @@ -2069,7 +2097,16 @@ class CI_Email { */ protected function _send_data($data) { - if ( ! fwrite($this->_smtp_connect, $data.$this->newline)) + $data .= $this->newline; + for ($written = 0, $length = strlen($data); $written < $length; $written += $result) + { + if (($result = fwrite($this->_smtp_connect, substr($data, $written))) === FALSE) + { + break; + } + } + + if ($result === FALSE) { $this->_set_error_message('lang:email_smtp_data_failure', $data); return FALSE; diff --git a/system/libraries/Xmlrpc.php b/system/libraries/Xmlrpc.php index 2fd12599e..ab907e706 100644 --- a/system/libraries/Xmlrpc.php +++ b/system/libraries/Xmlrpc.php @@ -724,7 +724,15 @@ class XML_RPC_Client extends CI_Xmlrpc .'Content-Length: '.strlen($msg->payload).$r.$r .$msg->payload; - if ( ! fwrite($fp, $op, strlen($op))) + for ($written = 0, $length = strlen($op); $written < $length; $written += $result) + { + if (($result = fwrite($fp, substr($op, $written))) === FALSE) + { + break; + } + } + + if ($result === FALSE) { error_log($this->xmlrpcstr['http_error']); return new XML_RPC_Response(0, $this->xmlrpcerr['http_error'], $this->xmlrpcstr['http_error']); diff --git a/system/libraries/Zip.php b/system/libraries/Zip.php index 250ee02cd..b10b0bb0f 100644 --- a/system/libraries/Zip.php +++ b/system/libraries/Zip.php @@ -403,11 +403,19 @@ class CI_Zip { } flock($fp, LOCK_EX); - fwrite($fp, $this->get_zip()); + + for ($written = 0, $data = $this->get_zip(), $length = strlen($data); $written < $length; $written += $result) + { + if (($result = fwrite($fp, substr($data, $written))) === FALSE) + { + break; + } + } + flock($fp, LOCK_UN); fclose($fp); - return TRUE; + return is_int($result); } // -------------------------------------------------------------------- diff --git a/tests/codeigniter/core/URI_test.php b/tests/codeigniter/core/URI_test.php index 7fa0e6265..99d79bbd2 100644 --- a/tests/codeigniter/core/URI_test.php +++ b/tests/codeigniter/core/URI_test.php @@ -112,11 +112,10 @@ class URI_test extends CI_TestCase { public function test_filter_uri() { - $this->uri->config->set_item('enable_query_strings', FALSE); - $this->uri->config->set_item('permitted_uri_chars', 'a-z 0-9~%.:_\-'); + $this->uri->_set_permitted_uri_chars('a-z 0-9~%.:_\-'); $str_in = 'abc01239~%.:_-'; - $str = $this->uri->_filter_uri($str_in); + $str = $this->uri->filter_uri($str_in); $this->assertEquals($str, $str_in); } @@ -126,11 +125,9 @@ class URI_test extends CI_TestCase { public function test_filter_uri_escaping() { // ensure escaping even if dodgey characters are permitted + $this->uri->_set_permitted_uri_chars('a-z 0-9~%.:_\-()$'); - $this->uri->config->set_item('enable_query_strings', FALSE); - $this->uri->config->set_item('permitted_uri_chars', 'a-z 0-9~%.:_\-()$'); - - $str = $this->uri->_filter_uri('$destroy_app(foo)'); + $str = $this->uri->filter_uri('$destroy_app(foo)'); $this->assertEquals($str, '$destroy_app(foo)'); } @@ -142,8 +139,8 @@ class URI_test extends CI_TestCase { $this->setExpectedException('RuntimeException'); $this->uri->config->set_item('enable_query_strings', FALSE); - $this->uri->config->set_item('permitted_uri_chars', 'a-z 0-9~%.:_\-'); - $this->uri->_filter_uri('$this()'); + $this->uri->_set_permitted_uri_chars('a-z 0-9~%.:_\-'); + $this->uri->filter_uri('$this()'); } // -------------------------------------------------------------------- diff --git a/tests/mocks/autoloader.php b/tests/mocks/autoloader.php index 3d216da1f..cc0a2e2f7 100644 --- a/tests/mocks/autoloader.php +++ b/tests/mocks/autoloader.php @@ -89,21 +89,7 @@ function autoload($class) if ( ! file_exists($file)) { - $trace = debug_backtrace(); - - if ($trace[2]['function'] === 'class_exists' OR $trace[2]['function'] === 'file_exists') - { - // If the autoload call came from `class_exists` or `file_exists`, - // we skipped and return FALSE - return FALSE; - } - elseif (($autoloader = spl_autoload_functions()) && end($autoloader) !== __FUNCTION__) - { - // If there was other custom autoloader, passed away - return FALSE; - } - - throw new InvalidArgumentException("Unable to load {$class}."); + return FALSE; } include_once($file); diff --git a/tests/mocks/core/uri.php b/tests/mocks/core/uri.php index 11078587b..96ec5afa1 100644 --- a/tests/mocks/core/uri.php +++ b/tests/mocks/core/uri.php @@ -10,12 +10,23 @@ class Mock_Core_URI extends CI_URI { // set predictable config values $test->ci_set_config(array( 'index_page' => 'index.php', - 'base_url' => 'http://example.com/', - 'subclass_prefix' => 'MY_' + 'base_url' => 'http://example.com/', + 'subclass_prefix' => 'MY_', + 'enable_query_strings' => FALSE, + 'permitted_uri_chars' => 'a-z 0-9~%.:_\-' )); $this->config = new $cls; + if ($this->config->item('enable_query_strings') !== TRUE OR is_cli()) + { + $this->_permitted_uri_chars = $this->config->item('permitted_uri_chars'); + } + } + + public function _set_permitted_uri_chars($value) + { + $this->_permitted_uri_chars = $value; } }
\ No newline at end of file diff --git a/user_guide_src/source/changelog.rst b/user_guide_src/source/changelog.rst index 0e656a10d..5a779cc90 100644 --- a/user_guide_src/source/changelog.rst +++ b/user_guide_src/source/changelog.rst @@ -332,10 +332,12 @@ Release Date: Not Released - :doc:`Email Library <libraries/email>` changes include: - - Added custom filename to ``Email::attach()`` as ``$this->email->attach($filename, $disposition, $newname)``. - - Added possibility to send attachment as buffer string in ``Email::attach()`` as ``$this->email->attach($buffer, $disposition, $newname, $mime)``. + - Added a custom filename parameter to ``attach()`` as ``$this->email->attach($filename, $disposition, $newname)``. + - Added possibility to send attachment as buffer string in ``attach()`` as ``$this->email->attach($buffer, $disposition, $newname, $mime)``. + - Added possibility to attach remote files by passing a URL. + - Added method ``attachment_cid()`` to enable embedding inline attachments into HTML. - Added dsn (delivery status notification) option. - - Renamed method _set_header() to set_header() and made it public to enable adding custom headers in the :doc:`Email Library <libraries/email>`. + - Renamed method ``_set_header()`` to ``set_header()`` and made it public to enable adding custom headers. - Successfully sent emails will automatically clear the parameters. - Added a *return_path* parameter to the ``from()`` method. - Removed the second parameter (character limit) from internal method ``_prep_quoted_printable()`` as it is never used. @@ -344,7 +346,7 @@ Release Date: Not Released - Removed unused protected method ``_get_ip()`` (:doc:`Input Library <libraries/input>`'s ``ip_address()`` should be used anyway). - Internal method ``_prep_q_encoding()`` now utilizes PHP's *mbstring* and *iconv* extensions (when available) and no longer has a second (``$from``) argument. - Added an optional parameter to ``print_debugger()`` to allow specifying which parts of the message should be printed ('headers', 'subject', 'body'). - - Added SMTP keepalive option to avoid opening the connection for each ``Email::send()``. Accessible as ``$smtp_keepalive``. + - Added SMTP keepalive option to avoid opening the connection for each ``send()`` call. Accessible as ``$smtp_keepalive``. - Public method ``set_header()`` now filters the input by removing all "\\r" and "\\n" characters. - :doc:`Pagination Library <libraries/pagination>` changes include: @@ -389,6 +391,7 @@ Release Date: Not Released - :doc:`URI Library <libraries/uri>` changes include: + - Renamed method ``_filter_uri()`` to ``filter_uri()`` and removed the ``preg_quote()`` call from it. - Changed private methods to protected so that MY_URI can override them. - Renamed internal method ``_parse_cli_args()`` to ``_parse_argv()``. - Renamed internal method ``_detect_uri()`` to ``_parse_request_uri()``. @@ -461,6 +464,7 @@ Release Date: Not Released - Added possibility to route requests using callbacks. - Added a new reserved route (*translate_uri_dashes*) to allow usage of dashes in the controller and method URI segments. - Deprecated methods ``fetch_directory()``, ``fetch_class()`` and ``fetch_method()`` in favor of their respective public properties. + - Removed method ``_set_overrides()`` and moved its logic to the class constructor. - :doc:`Language Library <libraries/language>` changes include: @@ -666,6 +670,7 @@ Bug fixes for 3.0 - Fixed a bug (#346) - with ``$config['global_xss_filtering']`` turned on, the ``$_GET``, ``$_POST``, ``$_COOKIE`` and ``$_SERVER`` superglobals were overwritten during initialization time, resulting in XSS filtering being either performed twice or there was no possible way to get the original data, even though options for this do exist. - Fixed an edge case (#555) - incorrect browser version was reported for Opera 10+ due to a non-standard user-agent string. - Fixed a bug (#133) - :doc:`Text Helper <helpers/text_helper>` :func:`ascii_to_entities()` stripped the last character if it happens to be in the extended ASCII group. +- Fixed a bug (#2822) - ``fwrite()`` was used incorrectly throughout the whole framework, allowing incomplete writes when writing to a network stream and possibly a few other edge cases. Version 2.1.4 ============= diff --git a/user_guide_src/source/libraries/email.rst b/user_guide_src/source/libraries/email.rst index 39629ece1..86f440a74 100644 --- a/user_guide_src/source/libraries/email.rst +++ b/user_guide_src/source/libraries/email.rst @@ -247,8 +247,8 @@ $this->email->attach() ---------------------- Enables you to send an attachment. Put the file path/name in the first -parameter. Note: Use a file path, not a URL. For multiple attachments -use the method multiple times. For example:: +parameter. For multiple attachments use the method multiple times. +For example:: $this->email->attach('/path/to/photo1.jpg'); $this->email->attach('/path/to/photo2.jpg'); @@ -259,6 +259,10 @@ otherwise use a custom disposition:: $this->email->attach('image.jpg', 'inline'); +You can use URL:: + + $this->email->attach('http://example.com/filename.pdf'); + If you'd like to use a custom file name, you can use the third paramater:: $this->email->attach('filename.pdf', 'attachment', 'report.pdf'); @@ -269,6 +273,26 @@ parameter as mime-type:: $this->email->attach($buffer, 'attachment', 'report.pdf', 'application/pdf'); +$this->email->attachment_cid() +------------------------------ + +Sets and returns an attachment's Content-ID, which enables your to embed an inline +(picture) attachment into HTML. First parameter must be attached file. + +:: + + $filename = '/img/photo1.jpg'; + $this->email->attach($filename); + foreach ($list as $address) + { + $this->email->to($address); + $cid = $this->email->attach_cid($filename); + $this->email->message('<img src='cid:". $cid ."' alt="photo1" />'); + $this->email->send(); + } + +CID for each Email have to be create again to be unique. + $this->email->print_debugger() ------------------------------ |