summaryrefslogtreecommitdiffstats
path: root/system
diff options
context:
space:
mode:
Diffstat (limited to 'system')
-rw-r--r--system/core/Config.php1
-rw-r--r--system/core/Input.php85
-rw-r--r--system/core/Security.php26
-rw-r--r--system/database/drivers/mssql/mssql_driver.php2
-rw-r--r--system/helpers/string_helper.php2
-rw-r--r--system/language/english/ftp_lang.php2
-rw-r--r--system/libraries/Email.php2
-rw-r--r--system/libraries/Encryption.php887
-rw-r--r--system/libraries/Form_validation.php7
-rw-r--r--system/libraries/Javascript.php1
-rw-r--r--system/libraries/Pagination.php4
-rw-r--r--system/libraries/Session/drivers/Session_cookie.php69
-rw-r--r--system/libraries/Table.php72
13 files changed, 1013 insertions, 147 deletions
diff --git a/system/core/Config.php b/system/core/Config.php
index a0e830abe..93c950e2e 100644
--- a/system/core/Config.php
+++ b/system/core/Config.php
@@ -332,6 +332,7 @@ class CI_Config {
/**
* System URL
*
+ * @deprecated 3.0.0 Encourages insecure practices
* @return string
*/
public function system_url()
diff --git a/system/core/Input.php b/system/core/Input.php
index ccb70daec..35ce5f12f 100644
--- a/system/core/Input.php
+++ b/system/core/Input.php
@@ -152,8 +152,20 @@ class CI_Input {
* @param bool $xss_clean Whether to apply XSS filtering
* @return mixed
*/
- protected function _fetch_from_array(&$array, $index = '', $xss_clean = NULL)
+ protected function _fetch_from_array(&$array, $index = NULL, $xss_clean = NULL)
{
+ // If $index is NULL, it means that the whole $array is requested
+ if ($index === NULL)
+ {
+ $output = array();
+ foreach (array_keys($array) as $key)
+ {
+ $output[$key] = $this->_fetch_from_array($array, $key, $xss_clean);
+ }
+
+ return $output;
+ }
+
is_bool($xss_clean) OR $xss_clean = $this->_enable_xss;
if (isset($array[$index]))
@@ -202,26 +214,6 @@ class CI_Input {
*/
public function get($index = NULL, $xss_clean = NULL)
{
- is_bool($xss_clean) OR $xss_clean = $this->_enable_xss;
-
- // Check if a field has been provided
- if ($index === NULL)
- {
- if (empty($_GET))
- {
- return array();
- }
-
- $get = array();
-
- // loop through the full _GET array
- foreach (array_keys($_GET) as $key)
- {
- $get[$key] = $this->_fetch_from_array($_GET, $key, $xss_clean);
- }
- return $get;
- }
-
return $this->_fetch_from_array($_GET, $index, $xss_clean);
}
@@ -236,26 +228,6 @@ class CI_Input {
*/
public function post($index = NULL, $xss_clean = NULL)
{
- is_bool($xss_clean) OR $xss_clean = $this->_enable_xss;
-
- // Check if a field has been provided
- if ($index === NULL)
- {
- if (empty($_POST))
- {
- return array();
- }
-
- $post = array();
-
- // Loop through the full _POST array and return it
- foreach (array_keys($_POST) as $key)
- {
- $post[$key] = $this->_fetch_from_array($_POST, $key, $xss_clean);
- }
- return $post;
- }
-
return $this->_fetch_from_array($_POST, $index, $xss_clean);
}
@@ -268,10 +240,8 @@ class CI_Input {
* @param bool $xss_clean Whether to apply XSS filtering
* @return mixed
*/
- public function post_get($index = '', $xss_clean = NULL)
+ public function post_get($index, $xss_clean = NULL)
{
- is_bool($xss_clean) OR $xss_clean = $this->_enable_xss;
-
return isset($_POST[$index])
? $this->post($index, $xss_clean)
: $this->get($index, $xss_clean);
@@ -286,10 +256,8 @@ class CI_Input {
* @param bool $xss_clean Whether to apply XSS filtering
* @return mixed
*/
- public function get_post($index = '', $xss_clean = NULL)
+ public function get_post($index, $xss_clean = NULL)
{
- is_bool($xss_clean) OR $xss_clean = $this->_enable_xss;
-
return isset($_GET[$index])
? $this->get($index, $xss_clean)
: $this->post($index, $xss_clean);
@@ -304,10 +272,8 @@ class CI_Input {
* @param bool $xss_clean Whether to apply XSS filtering
* @return mixed
*/
- public function cookie($index = '', $xss_clean = NULL)
+ public function cookie($index = NULL, $xss_clean = NULL)
{
- is_bool($xss_clean) OR $xss_clean = $this->_enable_xss;
-
return $this->_fetch_from_array($_COOKIE, $index, $xss_clean);
}
@@ -320,10 +286,8 @@ class CI_Input {
* @param bool $xss_clean Whether to apply XSS filtering
* @return mixed
*/
- public function server($index = '', $xss_clean = NULL)
+ public function server($index, $xss_clean = NULL)
{
- is_bool($xss_clean) OR $xss_clean = $this->_enable_xss;
-
return $this->_fetch_from_array($_SERVER, $index, $xss_clean);
}
@@ -338,23 +302,14 @@ class CI_Input {
* @param bool $xss_clean Whether to apply XSS filtering
* @return mixed
*/
- public function input_stream($index = '', $xss_clean = NULL)
+ public function input_stream($index = NULL, $xss_clean = NULL)
{
- is_bool($xss_clean) OR $xss_clean = $this->_enable_xss;
-
// The input stream can only be read once, so we'll need to check
// if we have already done that first.
- if (is_array($this->_input_stream))
- {
- return $this->_fetch_from_array($this->_input_stream, $index, $xss_clean);
- }
-
- // Parse the input stream in our cache var
- parse_str(file_get_contents('php://input'), $this->_input_stream);
if ( ! is_array($this->_input_stream))
{
- $this->_input_stream = array();
- return NULL;
+ parse_str(file_get_contents('php://input'), $this->_input_stream);
+ is_array($this->_input_stream) OR $this->_input_stream = array();
}
return $this->_fetch_from_array($this->_input_stream, $index, $xss_clean);
diff --git a/system/core/Security.php b/system/core/Security.php
index cbff38b30..beb7f56e0 100644
--- a/system/core/Security.php
+++ b/system/core/Security.php
@@ -147,6 +147,9 @@ class CI_Security {
'(document|(document\.)?window)\.(location|on\w*)',
'expression\s*(\(|&\#40;)', // CSS and IE
'vbscript\s*:', // IE, surprise!
+ 'wscript\s*:', // IE
+ 'jscript\s*:', // IE
+ 'vbs\s*:', // IE
'Redirect\s+30\d',
"([\"'])?data\s*:[^\\1]*?base64[^\\1]*?,[^\\1]*?\\1?"
);
@@ -356,7 +359,11 @@ class CI_Security {
*
* Note: Use rawurldecode() so it does not remove plus signs
*/
- $str = rawurldecode($str);
+ do
+ {
+ $str = rawurldecode($str);
+ }
+ while (preg_match('/%[0-9a-f]{2,}/i', $str));
/*
* Convert character entities to ASCII
@@ -415,8 +422,9 @@ class CI_Security {
* These words are compacted back to their correct state.
*/
$words = array(
- 'javascript', 'expression', 'vbscript', 'script', 'base64',
- 'applet', 'alert', 'document', 'write', 'cookie', 'window'
+ 'javascript', 'expression', 'vbscript', 'jscript', 'wscript',
+ 'vbs', 'script', 'base64', 'applet', 'alert', 'document',
+ 'write', 'cookie', 'window', 'confirm', 'prompt'
);
foreach ($words as $word)
@@ -446,12 +454,12 @@ class CI_Security {
if (preg_match('/<a/i', $str))
{
- $str = preg_replace_callback('#<a[\s\d"\'`;/=,\(]+([^>]*?)(?:>|$)#si', array($this, '_js_link_removal'), $str);
+ $str = preg_replace_callback('#<a[\s\d"\'`;/=,\(\\\\]+([^>]*?)(?:>|$)#si', array($this, '_js_link_removal'), $str);
}
if (preg_match('/<img/i', $str))
{
- $str = preg_replace_callback('#<img[\s\d"\'`;/=,\(]+([^>]*?)(?:\s?/?>|$)#si', array($this, '_js_img_removal'), $str);
+ $str = preg_replace_callback('#<img[\s\d"\'`;/=,\(\\\\]+([^>]*?)(?:\s?/?>|$)#si', array($this, '_js_img_removal'), $str);
}
if (preg_match('/script|xss/i', $str))
@@ -475,7 +483,7 @@ class CI_Security {
* So this: <blink>
* Becomes: &lt;blink&gt;
*/
- $naughty = 'alert|applet|audio|basefont|base|behavior|bgsound|blink|body|embed|expression|form|frameset|frame|head|html|ilayer|iframe|input|button|select|isindex|layer|link|meta|keygen|object|plaintext|style|script|textarea|title|math|video|svg|xml|xss';
+ $naughty = 'alert|prompt|confirm|applet|audio|basefont|base|behavior|bgsound|blink|body|embed|expression|form|frameset|frame|head|html|ilayer|iframe|input|button|select|isindex|layer|link|meta|keygen|object|plaintext|style|script|textarea|title|math|video|svg|xml|xss';
$str = preg_replace_callback('#<(/*\s*)('.$naughty.')([^><]*)([><]*)#is', array($this, '_sanitize_naughty_html'), $str);
/*
@@ -490,7 +498,7 @@ class CI_Security {
* For example: eval('some code')
* Becomes: eval&#40;'some code'&#41;
*/
- $str = preg_replace('#(alert|cmd|passthru|eval|exec|expression|system|fopen|fsockopen|file|file_get_contents|readfile|unlink)(\s*)\((.*?)\)#si',
+ $str = preg_replace('#(alert|prompt|confirm|cmd|passthru|eval|exec|expression|system|fopen|fsockopen|file|file_get_contents|readfile|unlink)(\s*)\((.*?)\)#si',
'\\1\\2&#40;\\3&#41;',
$str);
@@ -745,7 +753,7 @@ class CI_Security {
protected function _js_link_removal($match)
{
return str_replace($match[1],
- preg_replace('#href=.*?(?:alert\(|alert&\#40;|javascript:|livescript:|mocha:|charset=|window\.|document\.|\.cookie|<script|<xss|data\s*:)#si',
+ preg_replace('#href=.*?(?:(?:alert|prompt|confirm)(?:\(|&\#40;)|javascript:|livescript:|mocha:|charset=|window\.|document\.|\.cookie|<script|<xss|data\s*:)#si',
'',
$this->_filter_attributes(str_replace(array('<', '>'), '', $match[1]))
),
@@ -770,7 +778,7 @@ class CI_Security {
protected function _js_img_removal($match)
{
return str_replace($match[1],
- preg_replace('#src=.*?(?:alert\(|alert&\#40;|javascript:|livescript:|mocha:|charset=|window\.|document\.|\.cookie|<script|<xss|base64\s*,)#si',
+ preg_replace('#src=.*?(?:(?:alert|prompt|confirm)(?:\(|&\#40;)|javascript:|livescript:|mocha:|charset=|window\.|document\.|\.cookie|<script|<xss|base64\s*,)#si',
'',
$this->_filter_attributes(str_replace(array('<', '>'), '', $match[1]))
),
diff --git a/system/database/drivers/mssql/mssql_driver.php b/system/database/drivers/mssql/mssql_driver.php
index 0836fa802..49711fec9 100644
--- a/system/database/drivers/mssql/mssql_driver.php
+++ b/system/database/drivers/mssql/mssql_driver.php
@@ -311,7 +311,7 @@ class CI_DB_mssql_driver extends CI_DB {
.' FROM '.$this->escape_identifiers('sysobjects')
.' WHERE '.$this->escape_identifiers('type')." = 'U'";
- if ($prefix_limit !== FALSE AND $this->dbprefix !== '')
+ if ($prefix_limit !== FALSE && $this->dbprefix !== '')
{
$sql .= ' AND '.$this->escape_identifiers('name')." LIKE '".$this->escape_like_str($this->dbprefix)."%' "
.sprintf($this->_like_escape_str, $this->_like_escape_chr);
diff --git a/system/helpers/string_helper.php b/system/helpers/string_helper.php
index 12f818fda..4be7f294b 100644
--- a/system/helpers/string_helper.php
+++ b/system/helpers/string_helper.php
@@ -188,7 +188,7 @@ if ( ! function_exists('random_string'))
*
* Useful for generating passwords or hashes.
*
- * @param string type of random string. basic, alpha, alunum, numeric, nozero, unique, md5, encrypt and sha1
+ * @param string type of random string. basic, alpha, alnum, numeric, nozero, unique, md5, encrypt and sha1
* @param int number of characters
* @return string
*/
diff --git a/system/language/english/ftp_lang.php b/system/language/english/ftp_lang.php
index 042ab55df..f0e89ff69 100644
--- a/system/language/english/ftp_lang.php
+++ b/system/language/english/ftp_lang.php
@@ -26,7 +26,7 @@
*/
defined('BASEPATH') OR exit('No direct script access allowed');
-$lang['ftp_no_connection'] = 'Unable to locate a valid connection ID. Please make sure you are connected before peforming any file routines.';
+$lang['ftp_no_connection'] = 'Unable to locate a valid connection ID. Please make sure you are connected before performing any file routines.';
$lang['ftp_unable_to_connect'] = 'Unable to connect to your FTP server using the supplied hostname.';
$lang['ftp_unable_to_login'] = 'Unable to login to your FTP server. Please check your username and password.';
$lang['ftp_unable_to_mkdir'] = 'Unable to create the directory you have specified.';
diff --git a/system/libraries/Email.php b/system/libraries/Email.php
index f4efff882..88925e03f 100644
--- a/system/libraries/Email.php
+++ b/system/libraries/Email.php
@@ -822,7 +822,7 @@ class CI_Email {
* @param string
* @return CI_Email
*/
- public function set_alt_message($str = '')
+ public function set_alt_message($str)
{
$this->alt_message = (string) $str;
return $this;
diff --git a/system/libraries/Encryption.php b/system/libraries/Encryption.php
new file mode 100644
index 000000000..3a5409839
--- /dev/null
+++ b/system/libraries/Encryption.php
@@ -0,0 +1,887 @@
+<?php
+/**
+ * CodeIgniter
+ *
+ * An open source application development framework for PHP 5.2.4 or newer
+ *
+ * NOTICE OF LICENSE
+ *
+ * Licensed under the Open Software License version 3.0
+ *
+ * This source file is subject to the Open Software License (OSL 3.0) that is
+ * bundled with this package in the files license.txt / license.rst. It is
+ * also available through the world wide web at this URL:
+ * http://opensource.org/licenses/OSL-3.0
+ * If you did not receive a copy of the license and are unable to obtain it
+ * through the world wide web, please send an email to
+ * licensing@ellislab.com so we can send you a copy immediately.
+ *
+ * @package CodeIgniter
+ * @author EllisLab Dev Team
+ * @copyright Copyright (c) 2008 - 2013, EllisLab, Inc. (http://ellislab.com/)
+ * @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
+ * @link http://codeigniter.com
+ * @since Version 3.0
+ * @filesource
+ */
+defined('BASEPATH') OR exit('No direct script access allowed');
+
+/**
+ * CodeIgniter Encryption Class
+ *
+ * Provides two-way keyed encryption via PHP's MCrypt and/or OpenSSL extensions.
+ *
+ * @package CodeIgniter
+ * @subpackage Libraries
+ * @category Libraries
+ * @author Andrey Andreev
+ * @link http://codeigniter.com/user_guide/libraries/encryption.html
+ */
+class CI_Encryption {
+
+ /**
+ * Encryption cipher
+ *
+ * @var string
+ */
+ protected $_cipher = 'aes-128';
+
+ /**
+ * Cipher mode
+ *
+ * @var string
+ */
+ protected $_mode = 'cbc';
+
+ /**
+ * Cipher handle
+ *
+ * @var mixed
+ */
+ protected $_handle;
+
+ /**
+ * Encryption key
+ *
+ * @var string
+ */
+ protected $_key;
+
+ /**
+ * PHP extension to be used
+ *
+ * @var string
+ */
+ protected $_driver;
+
+ /**
+ * List of usable drivers (PHP extensions)
+ *
+ * @var array
+ */
+ protected $_drivers = array();
+
+ /**
+ * List of available modes
+ *
+ * @var array
+ */
+ protected $_modes = array(
+ 'mcrypt' => array(
+ 'cbc' => 'cbc',
+ 'ecb' => 'ecb',
+ 'ofb' => 'nofb',
+ 'ofb8' => 'ofb',
+ 'cfb' => 'ncfb',
+ 'cfb8' => 'cfb',
+ 'ctr' => 'ctr',
+ 'stream' => 'stream'
+ ),
+ 'openssl' => array(
+ 'cbc' => 'cbc',
+ 'ecb' => 'ecb',
+ 'ofb' => 'ofb',
+ 'cfb' => 'cfb',
+ 'cfb8' => 'cfb8',
+ 'ctr' => 'ctr',
+ 'stream' => '',
+ 'gcm' => 'gcm',
+ 'xts' => 'xts'
+ )
+ );
+
+ /**
+ * List of supported HMAC algorightms
+ *
+ * name => digest size pairs
+ *
+ * @var array
+ */
+ protected $_digests = array(
+ 'sha224' => 28,
+ 'sha256' => 32,
+ 'sha384' => 48,
+ 'sha512' => 64
+ );
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Class constructor
+ *
+ * @param array $params Configuration parameters
+ * @return void
+ */
+ public function __construct(array $params = array())
+ {
+ $this->_drivers = array(
+ 'mcrypt' => defined('MCRYPT_DEV_URANDOM'),
+ // While OpenSSL is available for PHP 5.3.0, an IV parameter
+ // for the encrypt/decrypt functions is only available since 5.3.3
+ 'openssl' => (is_php('5.3.3') && extension_loaded('openssl'))
+ );
+
+ if ( ! $this->_drivers['mcrypt'] && ! $this->_drivers['openssl'])
+ {
+ return show_error('Encryption: Unable to find an available encryption driver.');
+ }
+
+ $this->initialize($params);
+ if ( ! isset($this->_key) && strlen($key = config_item('encryption_key')) > 0)
+ {
+ $this->_key = $key;
+ }
+
+ log_message('debug', 'Encryption Class Initialized');
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Initialize
+ *
+ * @param array $params Configuration parameters
+ * @return CI_Encryption
+ */
+ public function initialize(array $params)
+ {
+ if ( ! empty($params['driver']))
+ {
+ if (isset($this->_drivers[$params['driver']]))
+ {
+ if ($this->_drivers[$params['driver']])
+ {
+ $this->_driver = $params['driver'];
+ }
+ else
+ {
+ log_message('error', "Encryption: Driver '".$params['driver']."' is not available.");
+ }
+ }
+ else
+ {
+ log_message('error', "Encryption: Unknown driver '".$params['driver']."' cannot be configured.");
+ }
+ }
+
+ if (empty($this->_driver))
+ {
+ $this->_driver = ($this->_drivers['openssl'] === TRUE)
+ ? 'openssl'
+ : 'mcrypt';
+
+ log_message('debug', "Encryption: Auto-configured driver '".$this->_driver."'.");
+ }
+
+ empty($params['key']) OR $this->_key = $params['key'];
+ $this->{'_'.$this->_driver.'_initialize'}($params);
+ return $this;
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Initialize MCrypt
+ *
+ * @param array $params Configuration parameters
+ * @return void
+ */
+ protected function _mcrypt_initialize($params)
+ {
+ if ( ! empty($params['cipher']))
+ {
+ $params['cipher'] = strtolower($params['cipher']);
+ $this->_cipher_alias($params['cipher']);
+
+ if ( ! in_array($params['cipher'], mcrypt_list_algorithms(), TRUE))
+ {
+ log_message('error', 'Encryption: MCrypt cipher '.strtoupper($params['cipher']).' is not available.');
+ }
+ else
+ {
+ $this->_cipher = $params['cipher'];
+ }
+ }
+
+ if ( ! empty($params['mode']))
+ {
+ $params['mode'] = strtolower($params['mode']);
+ if ( ! isset($this->_modes['mcrypt'][$params['mode']]))
+ {
+ log_message('error', 'Encryption: MCrypt mode '.strtotupper($params['mode']).' is not available.');
+ }
+ else
+ {
+ $this->_mode = $this->_modes['mcrypt'][$params['mode']];
+ }
+ }
+
+ if (isset($this->_cipher, $this->_mode))
+ {
+ if (is_resource($this->_handle)
+ && (strtolower(mcrypt_enc_get_algorithms_name($this->_handle)) !== $this->_cipher
+ OR strtolower(mcrypt_enc_get_modes_name($this->_handle)) !== $this->_mode)
+ )
+ {
+ mcrypt_module_close($this->_handle);
+ }
+
+ if ($this->_handle = mcrypt_module_open($this->_cipher, '', $this->_mode, ''))
+ {
+ log_message('debug', 'Encryption: MCrypt cipher '.strtoupper($this->_cipher).' initialized in '.strtoupper($this->_mode).' mode.');
+ }
+ else
+ {
+ log_message('error', 'Encryption: Unable to initialize MCrypt with cipher '.strtoupper($this->_cipher).' in '.strtoupper($this->_mode).' mode.');
+ }
+ }
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Initialize OpenSSL
+ *
+ * @param array $params Configuration parameters
+ * @return void
+ */
+ protected function _openssl_initialize($params)
+ {
+ if ( ! empty($params['cipher']))
+ {
+ $params['cipher'] = strtolower($params['cipher']);
+ $this->_cipher_alias($params['cipher']);
+ $this->_cipher = $params['cipher'];
+ }
+
+ if ( ! empty($params['mode']))
+ {
+ $params['mode'] = strtolower($params['mode']);
+ if ( ! isset($this->_modes['openssl'][$params['mode']]))
+ {
+ log_message('error', 'Encryption: OpenSSL mode '.strtotupper($params['mode']).' is not available.');
+ }
+ else
+ {
+ $this->_mode = $this->_modes['openssl'][$params['mode']];
+ }
+ }
+
+ if (isset($this->_cipher, $this->_mode))
+ {
+ // This is mostly for the stream mode, which doesn't get suffixed in OpenSSL
+ $handle = empty($this->_mode)
+ ? $this->_cipher
+ : $this->_cipher.'-'.$this->_mode;
+
+ if ( ! in_array($handle, openssl_get_cipher_methods(), TRUE))
+ {
+ $this->_handle = NULL;
+ log_message('error', 'Encryption: Unable to initialize OpenSSL with method '.strtoupper($handle).'.');
+ }
+ else
+ {
+ $this->_handle = $handle;
+ log_message('debug', 'Encryption: OpenSSL initialized with method '.strtoupper($handle).'.');
+ }
+ }
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Encrypt
+ *
+ * @param string $data Input data
+ * @param array $params Input parameters
+ * @return string
+ */
+ public function encrypt($data, array $params = NULL)
+ {
+ if (($params = $this->_get_params($params)) === FALSE)
+ {
+ return FALSE;
+ }
+
+ isset($params['key']) OR $params['key'] = $this->hkdf($this->_key, 'sha512', NULL, strlen($this->_key), 'encryption');
+
+ if (($data = $this->{'_'.$this->_driver.'_encrypt'}($data, $params)) === FALSE)
+ {
+ return FALSE;
+ }
+
+ $params['base64'] && $data = base64_encode($data);
+
+ if (isset($params['hmac_digest']))
+ {
+ isset($params['hmac_key']) OR $params['hmac_key'] = $this->hkdf($this->_key, 'sha512', NULL, NULL, 'authentication');
+ return hash_hmac($params['hmac_digest'], $data, $params['hmac_key'], ! $params['base64']).$data;
+ }
+
+ return $data;
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Encrypt via MCrypt
+ *
+ * @param string $data Input data
+ * @param array $params Input parameters
+ * @return string
+ */
+ protected function _mcrypt_encrypt($data, $params)
+ {
+ if ( ! is_resource($params['handle']))
+ {
+ return FALSE;
+ }
+ elseif ( ! isset($params['iv']))
+ {
+ // The greater-than-1 comparison is mostly a work-around for a bug,
+ // where 1 is returned for ARCFour instead of 0.
+ $params['iv'] = (($iv_size = mcrypt_enc_get_iv_size($params['handle'])) > 1)
+ ? mcrypt_create_iv($iv_size, MCRYPT_DEV_URANDOM)
+ : NULL;
+ }
+
+ // CAST-128 compatibility (http://tools.ietf.org/rfc/rfc2144.txt)
+ //
+ // RFC2144 says that keys shorter than 16 bytes are to be padded with
+ // zero bytes to 16 bytes, but (surprise) MCrypt doesn't do that.
+ if ($params['cipher'] === 'cast-128' && ($kl = strlen($params['key'])) < 16)
+ {
+ $params['key'] .= str_repeat("\x0", 16 - $kl);
+ }
+
+ if (mcrypt_generic_init($params['handle'], $params['key'], $params['iv']) < 0)
+ {
+ if ($params['handle'] !== $this->_handle)
+ {
+ mcrypt_module_close($params['handle']);
+ }
+
+ return FALSE;
+ }
+
+ // Use PKCS#7 padding in order to ensure compatibility with OpenSSL
+ // and other implementations outside of PHP.
+ if (in_array(strtolower(mcrypt_enc_get_modes_name($params['handle'])), array('cbc', 'ecb'), TRUE))
+ {
+ $block_size = mcrypt_enc_get_block_size($params['handle']);
+ $pad = $block_size - (strlen($data) % $block_size);
+ $data .= str_repeat(chr($pad), $pad);
+ }
+
+ // Work-around for yet another strange behavior in MCrypt.
+ //
+ // When encrypting in ECB mode, the IV is ignored. Yet
+ // mcrypt_enc_get_iv_size() returns a value larger than 0
+ // even if ECB is used AND mcrypt_generic_init() complains
+ // if you don't pass an IV with length equal to the said
+ // return value.
+ //
+ // This probably would've been fine (even though still wasteful),
+ // but OpenSSL isn't that dumb and we need to make the process
+ // portable, so ...
+ $data = (mcrypt_enc_get_modes_name($params['handle']) !== 'ECB')
+ ? $params['iv'].mcrypt_generic($params['handle'], $data)
+ : mcrypt_generic($params['handle'], $data);
+
+ mcrypt_generic_deinit($params['handle']);
+ if ($params['handle'] !== $this->_handle)
+ {
+ mcrypt_module_close($params['handle']);
+ }
+
+ return $data;
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Encrypt via OpenSSL
+ *
+ * @param string $data Input data
+ * @param array $params Input parameters
+ * @return string
+ */
+ protected function _openssl_encrypt($data, $params)
+ {
+ if (empty($params['handle']))
+ {
+ return FALSE;
+ }
+ elseif ( ! isset($params['iv']))
+ {
+ $params['iv'] = ($iv_size = openssl_cipher_iv_length($params['handle']))
+ ? openssl_random_pseudo_bytes($iv_size)
+ : NULL;
+ }
+
+ $data = openssl_encrypt(
+ $data,
+ $params['handle'],
+ $params['key'],
+ 1, // DO NOT TOUCH!
+ $params['iv']
+ );
+
+ if ($data === FALSE)
+ {
+ return FALSE;
+ }
+
+ return $params['iv'].$data;
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Decrypt
+ *
+ * @param string $data Encrypted data
+ * @param array $params Input parameters
+ * @return string
+ */
+ public function decrypt($data, array $params = NULL)
+ {
+ if (($params = $this->_get_params($params)) === FALSE)
+ {
+ return FALSE;
+ }
+
+ if (isset($params['hmac_digest']))
+ {
+ // This might look illogical, but it is done during encryption as well ...
+ // The 'base64' value is effectively an inverted "raw data" parameter
+ $digest_size = ($params['base64'])
+ ? $this->_digests[$params['hmac_digest']] * 2
+ : $this->_digests[$params['hmac_digest']];
+
+ if (strlen($data) <= $digest_size)
+ {
+ return FALSE;
+ }
+
+ $hmac_input = substr($data, 0, $digest_size);
+ $data = substr($data, $digest_size);
+
+ isset($params['hmac_key']) OR $params['hmac_key'] = $this->hkdf($this->_key, 'sha512', NULL, NULL, 'authentication');
+ $hmac_check = hash_hmac($params['hmac_digest'], $data, $params['hmac_key'], ! $params['base64']);
+
+ // Time-attack-safe comparison
+ $diff = 0;
+ for ($i = 0; $i < $digest_size; $i++)
+ {
+ $diff |= ord($hmac_input[$i]) ^ ord($hmac_check[$i]);
+ }
+
+ if ($diff !== 0)
+ {
+ return FALSE;
+ }
+ }
+
+ if ($params['base64'])
+ {
+ $data = base64_decode($data);
+ }
+
+ if (isset($params['iv']) && strncmp($params['iv'], $data, $iv_size = strlen($params['iv'])) === 0)
+ {
+ $data = substr($data, $iv_size);
+ }
+
+ isset($params['key']) OR $params['key'] = $this->hkdf($this->_key, 'sha512', NULL, strlen($this->_key), 'encryption');
+
+ return $this->{'_'.$this->_driver.'_decrypt'}($data, $params);
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Decrypt via MCrypt
+ *
+ * @param string $data Encrypted data
+ * @param array $params Input parameters
+ * @return string
+ */
+ protected function _mcrypt_decrypt($data, $params)
+ {
+ if ( ! is_resource($params['handle']))
+ {
+ return FALSE;
+ }
+ elseif ( ! isset($params['iv']))
+ {
+ // The greater-than-1 comparison is mostly a work-around for a bug,
+ // where 1 is returned for ARCFour instead of 0.
+ if (($iv_size = mcrypt_enc_get_iv_size($params['handle'])) > 1)
+ {
+ if (mcrypt_enc_get_modes_name($params['handle']) !== 'ECB')
+ {
+ $params['iv'] = substr($data, 0, $iv_size);
+ $data = substr($data, $iv_size);
+ }
+ else
+ {
+ // MCrypt is dumb and this is ignored, only size matters
+ $params['iv'] = str_repeat("\x0", $iv_size);
+ }
+ }
+ else
+ {
+ $params['iv'] = NULL;
+ }
+ }
+
+ // CAST-128 compatibility (http://tools.ietf.org/rfc/rfc2144.txt)
+ //
+ // RFC2144 says that keys shorter than 16 bytes are to be padded with
+ // zero bytes to 16 bytes, but (surprise) MCrypt doesn't do that.
+ if ($params['cipher'] === 'cast-128' && ($kl = strlen($params['key'])) < 16)
+ {
+ $params['key'] .= str_repeat("\x0", 16 - $kl);
+ }
+
+ if (mcrypt_generic_init($params['handle'], $params['key'], $params['iv']) < 0)
+ {
+ if ($params['handle'] !== $this->_handle)
+ {
+ mcrypt_module_close($params['handle']);
+ }
+
+ return FALSE;
+ }
+
+ $data = mdecrypt_generic($params['handle'], $data);
+ // Remove PKCS#7 padding, if necessary
+ if (in_array(strtolower(mcrypt_enc_get_modes_name($params['handle'])), array('cbc', 'ecb'), TRUE))
+ {
+ $data = substr($data, 0, -ord($data[strlen($data)-1]));
+ }
+
+ mcrypt_generic_deinit($params['handle']);
+ if ($params['handle'] !== $this->_handle)
+ {
+ mcrypt_module_close($params['handle']);
+ }
+
+ return $data;
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Decrypt via OpenSSL
+ *
+ * @param string $data Encrypted data
+ * @param array $params Input parameters
+ * @return string
+ */
+ protected function _openssl_decrypt($data, $params)
+ {
+ if ( ! isset($params['iv']))
+ {
+ if ($iv_size = openssl_cipher_iv_length($params['handle']))
+ {
+ $params['iv'] = substr($data, 0, $iv_size);
+ $data = substr($data, $iv_size);
+ }
+ else
+ {
+ $params['iv'] = NULL;
+ }
+ }
+
+ return empty($params['handle'])
+ ? FALSE
+ : openssl_decrypt(
+ $data,
+ $params['handle'],
+ $params['key'],
+ 1, // DO NOT TOUCH!
+ $params['iv']
+ );
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Get params
+ *
+ * @param array $params Input parameters
+ * @return array
+ */
+ protected function _get_params($params)
+ {
+ if (empty($params))
+ {
+ return isset($this->_cipher, $this->_mode, $this->_key, $this->_handle)
+ ? array(
+ 'handle' => $this->_handle,
+ 'cipher' => $this->_cipher,
+ 'mode' => $this->_mode,
+ 'key' => NULL,
+ 'base64' => TRUE,
+ 'hmac_digest' => ($this->_mode !== 'gcm' ? 'sha512' : NULL),
+ 'hmac_key' => NULL
+ )
+ : FALSE;
+ }
+ elseif ( ! isset($params['cipher'], $params['mode'], $params['key']))
+ {
+ return FALSE;
+ }
+
+ if (isset($params['mode']))
+ {
+ $params['mode'] = strtolower($params['mode']);
+ if ( ! isset($this->_modes[$this->_driver][$params['mode']]))
+ {
+ return FALSE;
+ }
+ else
+ {
+ $params['mode'] = $this->_modes[$this->_driver][$params['mode']];
+ }
+ }
+
+ if ($params['mode'] === 'gcm' OR (isset($params['hmac']) && $params['hmac'] === FALSE))
+ {
+ $params['hmac_digest'] = $params['hmac_key'] = NULL;
+ }
+ else
+ {
+ if ( ! isset($params['hmac_key']))
+ {
+ return FALSE;
+ }
+ elseif (isset($params['hmac_digest']))
+ {
+ $params['hmac_digest'] = strtolower($params['hmac_digest']);
+ if ( ! isset($this->_digests[$params['hmac_digest']]))
+ {
+ return FALSE;
+ }
+ }
+ else
+ {
+ $params['hmac_digest'] = 'sha512';
+ }
+ }
+
+ $params = array(
+ 'handle' => NULL,
+ 'cipher' => $params['cipher'],
+ 'mode' => $params['mode'],
+ 'key' => $params['key'],
+ 'iv' => isset($params['iv']) ? $params['iv'] : NULL,
+ 'base64' => isset($params['raw_data']) ? ! $params['raw_data'] : FALSE,
+ 'hmac_digest' => $params['hmac_digest'],
+ 'hmac_key' => $params['hmac_key']
+ );
+
+ $this->_cipher_alias($params['cipher']);
+ $params['handle'] = ($params['cipher'] !== $this->_cipher OR $params['mode'] !== $this->_mode)
+ ? $this->{'_'.$this->_driver.'_get_handle'}($params['cipher'], $params['mode'])
+ : $this->_handle;
+
+ return $params;
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Get MCrypt handle
+ *
+ * @param string $cipher Cipher name
+ * @param string $mode Encryption mode
+ * @return resource
+ */
+ protected function _mcrypt_get_handle($cipher, $mode)
+ {
+ return mcrypt_module_open($cipher, '', $mode, '');
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Get OpenSSL handle
+ *
+ * @param string $cipher Cipher name
+ * @param string $mode Encryption mode
+ * @return string
+ */
+ protected function _openssl_get_handle($cipher, $mode)
+ {
+ // OpenSSL methods aren't suffixed with '-stream' for this mode
+ return ($mode === 'stream')
+ ? $cipher
+ : $cipher.'-'.$mode;
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Cipher alias
+ *
+ * Tries to translate cipher names between MCrypt and OpenSSL's "dialects".
+ *
+ * @param string $cipher Cipher name
+ * @return void
+ */
+ protected function _cipher_alias(&$cipher)
+ {
+ static $dictionary;
+
+ if (empty($dictionary))
+ {
+ $dictionary = array(
+ 'mcrypt' => array(
+ 'aes-128' => 'rijndael-128',
+ 'aes-192' => 'rijndael-128',
+ 'aes-256' => 'rijndael-128',
+ 'des3-ede3' => 'tripledes',
+ 'bf' => 'blowfish',
+ 'cast5' => 'cast-128',
+ 'rc4' => 'arcfour',
+ 'rc4-40' => 'arcfour'
+ ),
+ 'openssl' => array(
+ 'rijndael-128' => 'aes-128',
+ 'tripledes' => 'des-ede3',
+ 'blowfish' => 'bf',
+ 'cast-128' => 'cast5',
+ 'arcfour' => 'rc4-40',
+ 'rc4' => 'rc4-40'
+ )
+ );
+
+ // Notes:
+ //
+ // - Rijndael-128 is, at the same time all three of AES-128,
+ // AES-192 and AES-256. The only difference between them is
+ // the key size. Rijndael-192, Rijndael-256 on the other hand
+ // also have different block sizes and are NOT AES-compatible.
+ //
+ // - Blowfish is said to be supporting key sizes between
+ // 4 and 56 bytes, but it appears that between MCrypt and
+ // OpenSSL, only those of 16 and more bytes are compatible.
+ // Also, don't know what MCrypt's 'blowfish-compat' is.
+ //
+ // - CAST-128/CAST5 produces a longer cipher when encrypted via
+ // OpenSSL, but (strangely enough) can be decrypted by either
+ // extension anyway.
+ // Also, RFC2144 says that the cipher supports key sizes
+ // between 5 and 16 bytes by the implementation actually
+ // zero-padding them to 16 bytes, but MCrypt doesn't do that.
+ //
+ // - RC4 (ARCFour) has a strange implementation under OpenSSL.
+ // Its 'rc4-40' cipher method seems to work flawlessly, yet
+ // there's another one, 'rc4' that only works with a 16-byte key.
+ //
+ // - DES is compatible, but doesn't need an alias.
+ //
+ // Other seemingly matching ciphers between MCrypt, OpenSSL:
+ //
+ // - RC2 is NOT compatible and only an obscure forum post
+ // confirms that it is MCrypt's fault.
+ }
+
+ if (isset($dictionary[$this->_driver][$cipher]))
+ {
+ $cipher = $dictionary[$this->_driver][$cipher];
+ }
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * HKDF
+ *
+ * @link https://tools.ietf.org/rfc/rfc5869.txt
+ * @param $key Input key
+ * @param $digest A SHA-2 hashing algorithm
+ * @param $salt Optional salt
+ * @param $length Output length (defaults to the selected digest size)
+ * @param $info Optional context/application-specific info
+ * @return string A pseudo-random key
+ */
+ public function hkdf($key, $digest = 'sha512', $salt = NULL, $length = NULL, $info = '')
+ {
+ if ( ! isset($this->_digests[$digest]))
+ {
+ return FALSE;
+ }
+
+ if (empty($length) OR ! is_int($length))
+ {
+ $length = $this->_digests[$digest];
+ }
+ elseif ($length > (255 * $this->_digests[$digest]))
+ {
+ return FALSE;
+ }
+
+ isset($salt) OR $salt = str_repeat("\0", $this->_digests[$digest]);
+
+ $prk = hash_hmac($digest, $key, $salt, TRUE);
+ $key = '';
+ for ($key_block = '', $block_index = 1; strlen($key) < $length; $block_index++)
+ {
+ $key_block = hash_hmac($digest, $key_block.$info.chr($block_index), $prk, TRUE);
+ $key .= $key_block;
+ }
+
+ return substr($key, 0, $length);
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * __get() magic
+ *
+ * @param string $key Property name
+ * @return mixed
+ */
+ public function __get($key)
+ {
+ // Because aliases
+ if ($key === 'mode')
+ {
+ return array_search($this->_mode, $this->_modes[$this->_driver], TRUE);
+ }
+ elseif (in_array($key, array('cipher', 'driver', 'drivers', 'digests'), TRUE))
+ {
+ return $this->{'_'.$key};
+ }
+
+ return NULL;
+ }
+
+}
+
+/* End of file Encryption.php */
+/* Location: ./system/libraries/Encryption.php */ \ No newline at end of file
diff --git a/system/libraries/Form_validation.php b/system/libraries/Form_validation.php
index 58485916c..7c441409f 100644
--- a/system/libraries/Form_validation.php
+++ b/system/libraries/Form_validation.php
@@ -252,7 +252,7 @@ class CI_Form_validation {
* each array due to the limitations of CI's singleton
*
* @param array $data
- * @return void
+ * @return CI_Form_validation
*/
public function set_data(array $data)
{
@@ -260,6 +260,8 @@ class CI_Form_validation {
{
$this->validation_data = $data;
}
+
+ return $this;
}
// --------------------------------------------------------------------
@@ -1536,7 +1538,7 @@ class CI_Form_validation {
* Prevents subsequent validation routines from being affected by the
* results of any previous validation routine due to the CI singleton.
*
- * @return void
+ * @return CI_Form_validation
*/
public function reset_validation()
{
@@ -1545,6 +1547,7 @@ class CI_Form_validation {
$this->_error_array = array();
$this->_error_messages = array();
$this->error_string = '';
+ return $this;
}
}
diff --git a/system/libraries/Javascript.php b/system/libraries/Javascript.php
index 26a16850c..34a216c22 100644
--- a/system/libraries/Javascript.php
+++ b/system/libraries/Javascript.php
@@ -34,6 +34,7 @@ defined('BASEPATH') OR exit('No direct script access allowed');
* @category Javascript
* @author EllisLab Dev Team
* @link http://codeigniter.com/user_guide/libraries/javascript.html
+ * @deprecated 3.0.0 This was never a good idea in the first place.
*/
class CI_Javascript {
diff --git a/system/libraries/Pagination.php b/system/libraries/Pagination.php
index c6ffd03d4..f67cb47f8 100644
--- a/system/libraries/Pagination.php
+++ b/system/libraries/Pagination.php
@@ -314,7 +314,7 @@ class CI_Pagination {
* Initialize Preferences
*
* @param array $params Initialization parameters
- * @return void
+ * @return CI_Pagination
*/
public function initialize($params = array())
{
@@ -342,6 +342,8 @@ class CI_Pagination {
}
}
}
+
+ return $this;
}
// --------------------------------------------------------------------
diff --git a/system/libraries/Session/drivers/Session_cookie.php b/system/libraries/Session/drivers/Session_cookie.php
index c8dfad6c9..79712ad94 100644
--- a/system/libraries/Session/drivers/Session_cookie.php
+++ b/system/libraries/Session/drivers/Session_cookie.php
@@ -240,7 +240,7 @@ class CI_Session_cookie extends CI_Session_driver {
// Do we need encryption? If so, load the encryption class
if ($this->sess_encrypt_cookie === TRUE)
{
- $this->CI->load->library('encrypt');
+ $this->CI->load->library('encryption');
}
// Check for database
@@ -383,38 +383,41 @@ class CI_Session_cookie extends CI_Session_driver {
return FALSE;
}
- $len = strlen($session) - 40;
-
- if ($len < 0)
+ if ($this->sess_encrypt_cookie === TRUE)
{
- log_message('debug', 'The session cookie was not signed.');
- return FALSE;
+ $session = $this->CI->encryption->decrypt($session);
+ if ($session === FALSE)
+ {
+ log_message('error', 'Session: Unable to decrypt the session cookie, possibly due to a HMAC mismatch.');
+ return FALSE;
+ }
}
-
- // Check cookie authentication
- $hmac = substr($session, $len);
- $session = substr($session, 0, $len);
-
- // Time-attack-safe comparison
- $hmac_check = hash_hmac('sha1', $session, $this->encryption_key);
- $diff = 0;
- for ($i = 0; $i < 40; $i++)
+ else
{
- $diff |= ord($hmac[$i]) ^ ord($hmac_check[$i]);
- }
+ if (($len = strlen($session) - 40) <= 0)
+ {
+ log_message('error', 'Session: The session cookie was not signed.');
+ return FALSE;
+ }
- if ($diff !== 0)
- {
- log_message('error', 'The session cookie data did not match what was expected.');
- $this->sess_destroy();
- return FALSE;
- }
+ // Check cookie authentication
+ $hmac = substr($session, $len);
+ $session = substr($session, 0, $len);
- // Check for encryption
- if ($this->sess_encrypt_cookie === TRUE)
- {
- // Decrypt the cookie data
- $session = $this->CI->encrypt->decode($session);
+ // Time-attack-safe comparison
+ $hmac_check = hash_hmac('sha1', $session, $this->encryption_key);
+ $diff = 0;
+ for ($i = 0; $i < 40; $i++)
+ {
+ $diff |= ord($hmac[$i]) ^ ord($hmac_check[$i]);
+ }
+
+ if ($diff !== 0)
+ {
+ log_message('error', 'Session: HMAC mismatch. The session cookie data did not match what was expected.');
+ $this->sess_destroy();
+ return FALSE;
+ }
}
// Unserialize the session array
@@ -731,11 +734,13 @@ class CI_Session_cookie extends CI_Session_driver {
if ($this->sess_encrypt_cookie === TRUE)
{
- $cookie_data = $this->CI->encrypt->encode($cookie_data);
+ $cookie_data = $this->CI->encryption->encrypt($cookie_data);
+ }
+ else
+ {
+ // Require message authentication
+ $cookie_data .= hash_hmac('sha1', $cookie_data, $this->encryption_key);
}
-
- // Require message authentication
- $cookie_data .= hash_hmac('sha1', $cookie_data, $this->encryption_key);
$expire = ($this->sess_expire_on_close === TRUE) ? 0 : $this->sess_expiration + time();
diff --git a/system/libraries/Table.php b/system/libraries/Table.php
index b77fcf19d..1d4320855 100644
--- a/system/libraries/Table.php
+++ b/system/libraries/Table.php
@@ -117,7 +117,7 @@ class CI_Table {
/**
* Set the template
*
- * @param array
+ * @param array $template
* @return bool
*/
public function set_template($template)
@@ -139,12 +139,13 @@ class CI_Table {
* Can be passed as an array or discreet params
*
* @param mixed
- * @return void
+ * @return CI_Table
*/
public function set_heading($args = array())
{
$args = func_get_args();
$this->heading = $this->_prep_args($args);
+ return $this;
}
// --------------------------------------------------------------------
@@ -155,9 +156,9 @@ class CI_Table {
* columns. This allows a single array with many elements to be
* displayed in a table that has a fixed column count.
*
- * @param array
- * @param int
- * @return void
+ * @param array $array
+ * @param int $col_limit
+ * @return array
*/
public function make_columns($array = array(), $col_limit = 0)
{
@@ -202,12 +203,13 @@ class CI_Table {
*
* Can be passed as an array or discreet params
*
- * @param mixed
- * @return void
+ * @param mixed $value
+ * @return CI_Table
*/
public function set_empty($value)
{
$this->empty_cells = $value;
+ return $this;
}
// --------------------------------------------------------------------
@@ -218,12 +220,13 @@ class CI_Table {
* Can be passed as an array or discreet params
*
* @param mixed
- * @return void
+ * @return CI_Table
*/
public function add_row($args = array())
{
$args = func_get_args();
$this->rows[] = $this->_prep_args($args);
+ return $this;
}
// --------------------------------------------------------------------
@@ -271,8 +274,8 @@ class CI_Table {
/**
* Add a table caption
*
- * @param string
- * @return void
+ * @param string $caption
+ * @return CI_Table
*/
public function set_caption($caption)
{
@@ -284,7 +287,7 @@ class CI_Table {
/**
* Generate the table
*
- * @param mixed
+ * @param mixed $table_data
* @return string
*/
public function generate($table_data = NULL)
@@ -417,13 +420,14 @@ class CI_Table {
/**
* Clears the table arrays. Useful if multiple tables are being generated
*
- * @return void
+ * @return CI_Table
*/
public function clear()
{
- $this->rows = array();
- $this->heading = array();
- $this->auto_heading = TRUE;
+ $this->rows = array();
+ $this->heading = array();
+ $this->auto_heading = TRUE;
+ return $this;
}
// --------------------------------------------------------------------
@@ -528,31 +532,31 @@ class CI_Table {
protected function _default_template()
{
return array(
- 'table_open' => '<table border="0" cellpadding="4" cellspacing="0">',
+ 'table_open' => '<table border="0" cellpadding="4" cellspacing="0">',
- 'thead_open' => '<thead>',
- 'thead_close' => '</thead>',
+ 'thead_open' => '<thead>',
+ 'thead_close' => '</thead>',
- 'heading_row_start' => '<tr>',
- 'heading_row_end' => '</tr>',
- 'heading_cell_start' => '<th>',
- 'heading_cell_end' => '</th>',
+ 'heading_row_start' => '<tr>',
+ 'heading_row_end' => '</tr>',
+ 'heading_cell_start' => '<th>',
+ 'heading_cell_end' => '</th>',
- 'tbody_open' => '<tbody>',
- 'tbody_close' => '</tbody>',
+ 'tbody_open' => '<tbody>',
+ 'tbody_close' => '</tbody>',
- 'row_start' => '<tr>',
- 'row_end' => '</tr>',
- 'cell_start' => '<td>',
- 'cell_end' => '</td>',
+ 'row_start' => '<tr>',
+ 'row_end' => '</tr>',
+ 'cell_start' => '<td>',
+ 'cell_end' => '</td>',
- 'row_alt_start' => '<tr>',
- 'row_alt_end' => '</tr>',
- 'cell_alt_start' => '<td>',
- 'cell_alt_end' => '</td>',
+ 'row_alt_start' => '<tr>',
+ 'row_alt_end' => '</tr>',
+ 'cell_alt_start' => '<td>',
+ 'cell_alt_end' => '</td>',
- 'table_close' => '</table>'
- );
+ 'table_close' => '</table>'
+ );
}
}