diff --git a/application/config/application.php b/application/config/application.php index dea0c54cf..02137e066 100644 --- a/application/config/application.php +++ b/application/config/application.php @@ -3,11 +3,11 @@ * Bonfire * * An open source project to allow developers to jumpstart their development of - * CodeIgniter applications + * CodeIgniter applications. * * @package Bonfire * @author Bonfire Dev Team - * @copyright Copyright (c) 2011 - 2014, Bonfire Dev Team + * @copyright Copyright (c) 2011 - 2015, Bonfire Dev Team * @license http://opensource.org/licenses/MIT The MIT License * @link http://cibonfire.com * @since Version 1.0 @@ -19,16 +19,15 @@ */ $config['site.default_user_timezone'] = 'UM8'; -//-------------------------------------------------------------------- +//------------------------------------------------------------------------------ // Module Locations -//-------------------------------------------------------------------- -// These paths are checked in the order listed whenever a module is -// attempting to be located, whether it's loading a library, helper, -// or routes file. +//------------------------------------------------------------------------------ +// These paths are checked in the order listed when attempting to locate a module, +// whether loading a library, helper, or routes file. // $config['modules_locations'] = array( realpath(APPPATH) . '/modules/' => '../../application/modules/', - realpath(APPPATH . '../bonfire') . '/modules/' => '../../bonfire/modules/', + realpath(BFPATH) . '/modules/' => '../../bonfire/modules/', ); //------------------------------------------------------------------------------ diff --git a/application/config/autoload.php b/application/config/autoload.php index 562be354e..a75a6be84 100644 --- a/application/config/autoload.php +++ b/application/config/autoload.php @@ -1,5 +1,5 @@ 'ua'); */ - $autoload['libraries'] = array('database'); @@ -69,15 +68,15 @@ | ------------------------------------------------------------------- | Auto-load Drivers | ------------------------------------------------------------------- -| These classes are located in the system/libraries folder or in your -| application/libraries folder within their own subdirectory. They +| These classes are located in system/libraries/ or in your +| application/libraries/ directory, but are also placed inside their +| own subdirectory and they extend the CI_Driver_Library class. They | offer multiple interchangeable driver options. | | Prototype: | | $autoload['drivers'] = array('cache'); */ - $autoload['drivers'] = array(); /* @@ -88,7 +87,6 @@ | | $autoload['helper'] = array('url', 'file'); */ - $autoload['helper'] = array('url', 'language'); /* @@ -103,7 +101,6 @@ | config files. Otherwise, leave it blank. | */ - $autoload['config'] = array('application'); /* @@ -118,7 +115,6 @@ | "codeigniter_lang.php" would be referenced as array('codeigniter'); | */ - $autoload['language'] = array(); /* @@ -127,12 +123,11 @@ | ------------------------------------------------------------------- | Prototype: | -| $autoload['model'] = array('model1', 'model2'); +| $autoload['model'] = array('first_model', 'second_model'); | | You can also supply an alternative model name to be assigned | in the controller: | | $autoload['model'] = array('first_model' => 'first'); */ - $autoload['model'] = array(); diff --git a/application/config/config.php b/application/config/config.php index 42dfe396f..010ffa011 100644 --- a/application/config/config.php +++ b/application/config/config.php @@ -1,5 +1,5 @@ '', - 'hostname' => 'localhost', + 'hostname' => '127.0.0.1', 'username' => '', 'password' => '', 'database' => '', @@ -107,7 +107,6 @@ 'char_set' => 'utf8', 'dbcollat' => 'utf8_general_ci', 'swap_pre' => '', - 'autoinit' => true, 'encrypt' => false, 'compress' => false, 'stricton' => true, diff --git a/application/config/events.php b/application/config/events.php index f1f6fd581..c11894eaa 100644 --- a/application/config/events.php +++ b/application/config/events.php @@ -1,4 +1,4 @@ - 's', '/Ț|Ţ|Ť|Ŧ|τ|Т/' => 'T', '/ț|ţ|ť|ŧ|т/' => 't', + '/Þ|þ/' => 'th', '/Ù|Ú|Û|Ũ|Ū|Ŭ|Ů|Ű|Ų|Ư|Ǔ|Ǖ|Ǘ|Ǚ|Ǜ|Ũ|Ủ|Ụ|Ừ|Ứ|Ữ|Ử|Ự|У/' => 'U', '/ù|ú|û|ũ|ū|ŭ|ů|ű|ų|ư|ǔ|ǖ|ǘ|ǚ|ǜ|υ|ύ|ϋ|ủ|ụ|ừ|ứ|ữ|ử|ự|у/' => 'u', '/Ý|Ÿ|Ŷ|Υ|Ύ|Ϋ|Ỳ|Ỹ|Ỷ|Ỵ|Й/' => 'Y', diff --git a/application/config/hooks.php b/application/config/hooks.php index 8af6c5a31..918c8acdc 100644 --- a/application/config/hooks.php +++ b/application/config/hooks.php @@ -3,16 +3,16 @@ * Define "hooks" to extend CI without hacking the core files. Please see the * user guide for info: * - * @link https://ellislab.com/codeigniter/user-guide/general/hooks.html + * @link http://www.codeigniter.com/user_guide/general/hooks.html */ // Store the requested URL, which will sometimes be different from previous URL. $hook['pre_controller'][] = array( - 'class' => 'App_hooks', + 'class' => 'App_hooks', 'function' => 'saveRequested', - 'filename' => 'App_hooks.php', - 'filepath' => 'hooks', - 'params' => '' + 'filename' => 'App_hooks.php', + 'filepath' => 'hooks', + 'params' => '' ); // Check whether the Composer Autoloader should be used. @@ -26,20 +26,20 @@ // Allow performance of good redirects to previous pages. $hook['post_controller'][] = array( - 'class' => 'App_hooks', + 'class' => 'App_hooks', 'function' => 'prepRedirect', - 'filename' => 'App_hooks.php', - 'filepath' => 'hooks', - 'params' => '' + 'filename' => 'App_hooks.php', + 'filepath' => 'hooks', + 'params' => '' ); - + // Check whether the site is in maintenance mode. $hook['post_controller_constructor'][] = array( - 'class' => 'App_hooks', + 'class' => 'App_hooks', 'function' => 'checkSiteStatus', - 'filename' => 'App_hooks.php', - 'filepath' => 'hooks', - 'params' => '' + 'filename' => 'App_hooks.php', + 'filepath' => 'hooks', + 'params' => '' ); /* End of file /application/config/hooks.php */ diff --git a/application/config/migration.php b/application/config/migration.php index f47548157..c87bd484a 100644 --- a/application/config/migration.php +++ b/application/config/migration.php @@ -25,12 +25,12 @@ | Migration file names may be based on a sequential identifier or on | a timestamp. Options are: | -| 'sequential' = Default migration naming (001_add_blog.php) +| 'sequential' = Sequential migration naming (001_add_blog.php) | 'timestamp' = Timestamp migration naming (20121031104401_add_blog.php) | Use timestamp format YYYYMMDDHHIISS. | -| If this configuration value is missing the Migration library defaults -| to 'sequential' for backward compatibility. +| Note: If this configuration value is missing the Migration library +| defaults to 'sequential' for backward compatibility with CI2. | */ $config['migration_type'] = 'timestamp'; diff --git a/application/config/mimes.php b/application/config/mimes.php index c18312ff3..a35d48940 100644 --- a/application/config/mimes.php +++ b/application/config/mimes.php @@ -1,4 +1,6 @@ - 'application/x-pkcs7', 'cer' => array('application/pkix-cert', 'application/x-x509-ca-cert'), '3g2' => 'video/3gpp2', - '3gp' => 'video/3gp', + '3gp' => array('video/3gp', 'video/3gpp'), 'mp4' => 'video/mp4', 'm4a' => 'audio/x-m4a', 'f4v' => 'video/mp4', @@ -151,6 +153,9 @@ 'jar' => array('application/java-archive', 'application/x-java-application', 'application/x-jar', 'application/x-compressed'), 'svg' => array('image/svg+xml', 'application/xml', 'text/xml'), 'vcf' => 'text/x-vcard', + 'srt' => array('text/srt', 'text/plain'), + 'vtt' => array('text/vtt', 'text/plain'), + 'ico' => array('image/x-icon', 'image/x-ico', 'image/vnd.microsoft.icon') ); if (defined('CI_VERSION') && substr(CI_VERSION, 0, 1) != '2') { diff --git a/application/config/smileys.php b/application/config/smileys.php index 1428d68bc..1eeba4776 100644 --- a/application/config/smileys.php +++ b/application/config/smileys.php @@ -13,7 +13,6 @@ | http://codeigniter.com/user_guide/helpers/smiley_helper.html | */ - $smileys = array( // smiley image name width height alt diff --git a/application/config/user_agents.php b/application/config/user_agents.php index 73592c2a4..ac277374d 100644 --- a/application/config/user_agents.php +++ b/application/config/user_agents.php @@ -10,49 +10,49 @@ | mobile device data. The array keys are used to identify the device | and the array values are used to set the actual name of the item. */ - $platforms = array ( - 'windows nt 6.3' => 'Windows 8.1', - 'windows nt 6.2' => 'Windows 8', - 'windows nt 6.1' => 'Windows 7', - 'windows nt 6.0' => 'Windows Vista', - 'windows nt 5.2' => 'Windows 2003', - 'windows nt 5.1' => 'Windows XP', - 'windows nt 5.0' => 'Windows 2000', - 'windows nt 4.0' => 'Windows NT 4.0', - 'winnt4.0' => 'Windows NT 4.0', - 'winnt 4.0' => 'Windows NT', - 'winnt' => 'Windows NT', - 'windows 98' => 'Windows 98', - 'win98' => 'Windows 98', - 'windows 95' => 'Windows 95', - 'win95' => 'Windows 95', - 'windows phone' => 'Windows Phone', - 'windows' => 'Unknown Windows OS', - 'android' => 'Android', - 'blackberry' => 'BlackBerry', - 'iphone' => 'iOS', - 'ipad' => 'iOS', - 'ipod' => 'iOS', - 'os x' => 'Mac OS X', - 'ppc mac' => 'Power PC Mac', - 'freebsd' => 'FreeBSD', - 'ppc' => 'Macintosh', - 'linux' => 'Linux', - 'debian' => 'Debian', - 'sunos' => 'Sun Solaris', - 'beos' => 'BeOS', - 'apachebench' => 'ApacheBench', - 'aix' => 'AIX', - 'irix' => 'Irix', - 'osf' => 'DEC OSF', - 'hp-ux' => 'HP-UX', - 'netbsd' => 'NetBSD', - 'bsdi' => 'BSDi', - 'openbsd' => 'OpenBSD', - 'gnu' => 'GNU/Linux', - 'unix' => 'Unknown Unix OS', - 'symbian' => 'Symbian OS', + 'windows nt 10.0' => 'Windows 10', + 'windows nt 6.3' => 'Windows 8.1', + 'windows nt 6.2' => 'Windows 8', + 'windows nt 6.1' => 'Windows 7', + 'windows nt 6.0' => 'Windows Vista', + 'windows nt 5.2' => 'Windows 2003', + 'windows nt 5.1' => 'Windows XP', + 'windows nt 5.0' => 'Windows 2000', + 'windows nt 4.0' => 'Windows NT 4.0', + 'winnt4.0' => 'Windows NT 4.0', + 'winnt 4.0' => 'Windows NT', + 'winnt' => 'Windows NT', + 'windows 98' => 'Windows 98', + 'win98' => 'Windows 98', + 'windows 95' => 'Windows 95', + 'win95' => 'Windows 95', + 'windows phone' => 'Windows Phone', + 'windows' => 'Unknown Windows OS', + 'android' => 'Android', + 'blackberry' => 'BlackBerry', + 'iphone' => 'iOS', + 'ipad' => 'iOS', + 'ipod' => 'iOS', + 'os x' => 'Mac OS X', + 'ppc mac' => 'Power PC Mac', + 'freebsd' => 'FreeBSD', + 'ppc' => 'Macintosh', + 'linux' => 'Linux', + 'debian' => 'Debian', + 'sunos' => 'Sun Solaris', + 'beos' => 'BeOS', + 'apachebench' => 'ApacheBench', + 'aix' => 'AIX', + 'irix' => 'Irix', + 'osf' => 'DEC OSF', + 'hp-ux' => 'HP-UX', + 'netbsd' => 'NetBSD', + 'bsdi' => 'BSDi', + 'openbsd' => 'OpenBSD', + 'gnu' => 'GNU/Linux', + 'unix' => 'Unknown Unix OS', + 'symbian' => 'Symbian OS', ); @@ -61,6 +61,7 @@ $browsers = array( 'OPR' => 'Opera', 'Flock' => 'Flock', + 'Edge' => 'Spartan', 'RockMelt' => 'RockMelt', 'Chrome' => 'Chrome', // Opera 10+ always reports Opera/9.80 and appends Version/ to the user agent string @@ -93,57 +94,57 @@ $mobiles = array( // legacy array, old values commented out 'mobileexplorer' => 'Mobile Explorer', - // 'openwave' => 'Open Wave', - // 'opera mini' => 'Opera Mini', - // 'operamini' => 'Opera Mini', - // 'elaine' => 'Palm', + // 'openwave' => 'Open Wave', + // 'opera mini' => 'Opera Mini', + // 'operamini' => 'Opera Mini', + // 'elaine' => 'Palm', 'palmsource' => 'Palm', - // 'digital paths' => 'Palm', - // 'avantgo' => 'Avantgo', - // 'xiino' => 'Xiino', + // 'digital paths' => 'Palm', + // 'avantgo' => 'Avantgo', + // 'xiino' => 'Xiino', 'palmscape' => 'Palmscape', - // 'nokia' => 'Nokia', - // 'ericsson' => 'Ericsson', - // 'blackberry' => 'BlackBerry', - // 'motorola' => 'Motorola', + // 'nokia' => 'Nokia', + // 'ericsson' => 'Ericsson', + // 'blackberry' => 'BlackBerry', + // 'motorola' => 'Motorola', // Phones and Manufacturers - 'motorola' => 'Motorola', - 'nokia' => 'Nokia', - 'palm' => 'Palm', - 'iphone' => 'Apple iPhone', - 'ipad' => 'iPad', - 'ipod' => 'Apple iPod Touch', - 'sony' => 'Sony Ericsson', - 'ericsson' => 'Sony Ericsson', - 'blackberry' => 'BlackBerry', - 'cocoon' => 'O2 Cocoon', - 'blazer' => 'Treo', - 'lg' => 'LG', - 'amoi' => 'Amoi', - 'xda' => 'XDA', - 'mda' => 'MDA', - 'vario' => 'Vario', - 'htc' => 'HTC', - 'samsung' => 'Samsung', - 'sharp' => 'Sharp', - 'sie-' => 'Siemens', - 'alcatel' => 'Alcatel', - 'benq' => 'BenQ', - 'ipaq' => 'HP iPaq', - 'mot-' => 'Motorola', - 'playstation portable' => 'PlayStation Portable', + 'motorola' => 'Motorola', + 'nokia' => 'Nokia', + 'palm' => 'Palm', + 'iphone' => 'Apple iPhone', + 'ipad' => 'iPad', + 'ipod' => 'Apple iPod Touch', + 'sony' => 'Sony Ericsson', + 'ericsson' => 'Sony Ericsson', + 'blackberry' => 'BlackBerry', + 'cocoon' => 'O2 Cocoon', + 'blazer' => 'Treo', + 'lg' => 'LG', + 'amoi' => 'Amoi', + 'xda' => 'XDA', + 'mda' => 'MDA', + 'vario' => 'Vario', + 'htc' => 'HTC', + 'samsung' => 'Samsung', + 'sharp' => 'Sharp', + 'sie-' => 'Siemens', + 'alcatel' => 'Alcatel', + 'benq' => 'BenQ', + 'ipaq' => 'HP iPaq', + 'mot-' => 'Motorola', + 'playstation portable' => 'PlayStation Portable', 'playstation 3' => 'PlayStation 3', 'playstation vita' => 'PlayStation Vita', - 'hiptop' => 'Danger Hiptop', - 'nec-' => 'NEC', - 'panasonic' => 'Panasonic', - 'philips' => 'Philips', - 'sagem' => 'Sagem', - 'sanyo' => 'Sanyo', - 'spv' => 'SPV', - 'zte' => 'ZTE', - 'sendo' => 'Sendo', + 'hiptop' => 'Danger Hiptop', + 'nec-' => 'NEC', + 'panasonic' => 'Panasonic', + 'philips' => 'Philips', + 'sagem' => 'Sagem', + 'sanyo' => 'Sanyo', + 'spv' => 'SPV', + 'zte' => 'ZTE', + 'sendo' => 'Sendo', 'nintendo dsi' => 'Nintendo DSi', 'nintendo ds' => 'Nintendo DS', 'nintendo 3ds' => 'Nintendo 3DS', @@ -152,42 +153,42 @@ 'openweb' => 'OpenWeb', // Operating Systems - 'android' => 'Android', - 'symbian' => 'Symbian', - 'SymbianOS' => 'SymbianOS', - 'elaine' => 'Palm', - 'series60' => 'Symbian S60', - 'windows ce' => 'Windows CE', + 'android' => 'Android', + 'symbian' => 'Symbian', + 'SymbianOS' => 'SymbianOS', + 'elaine' => 'Palm', + 'series60' => 'Symbian S60', + 'windows ce' => 'Windows CE', // Browsers - 'obigo' => 'Obigo', - 'netfront' => 'Netfront Browser', - 'openwave' => 'Openwave Browser', - 'mobilexplorer' => 'Mobile Explorer', - 'operamini' => 'Opera Mini', - 'opera mini' => 'Opera Mini', + 'obigo' => 'Obigo', + 'netfront' => 'Netfront Browser', + 'openwave' => 'Openwave Browser', + 'mobilexplorer' => 'Mobile Explorer', + 'operamini' => 'Opera Mini', + 'opera mini' => 'Opera Mini', 'opera mobi' => 'Opera Mobile', - 'fennec' => 'Firefox Mobile', + 'fennec' => 'Firefox Mobile', // Other - 'digital paths' => 'Digital Paths', - 'avantgo' => 'AvantGo', - 'xiino' => 'Xiino', - 'novarra' => 'Novarra Transcoder', - 'vodafone' => 'Vodafone', - 'docomo' => 'NTT DoCoMo', - 'o2' => 'O2', + 'digital paths' => 'Digital Paths', + 'avantgo' => 'AvantGo', + 'xiino' => 'Xiino', + 'novarra' => 'Novarra Transcoder', + 'vodafone' => 'Vodafone', + 'docomo' => 'NTT DoCoMo', + 'o2' => 'O2', // Fallback - 'mobile' => 'Generic Mobile', - 'wireless' => 'Generic Mobile', - 'j2me' => 'Generic Mobile', - 'midp' => 'Generic Mobile', - 'cldc' => 'Generic Mobile', - 'up.link' => 'Generic Mobile', - 'up.browser' => 'Generic Mobile', - 'smartphone' => 'Generic Mobile', - 'cellphone' => 'Generic Mobile', + 'mobile' => 'Generic Mobile', + 'wireless' => 'Generic Mobile', + 'j2me' => 'Generic Mobile', + 'midp' => 'Generic Mobile', + 'cldc' => 'Generic Mobile', + 'up.link' => 'Generic Mobile', + 'up.browser' => 'Generic Mobile', + 'smartphone' => 'Generic Mobile', + 'cellphone' => 'Generic Mobile', ); // There are hundreds of bots but these are the most common. diff --git a/application/libraries/Profiler.php b/application/libraries/Profiler.php index eaa31dd3e..f4cf6a5bc 100755 --- a/application/libraries/Profiler.php +++ b/application/libraries/Profiler.php @@ -160,10 +160,10 @@ protected function _compile_queries() } $highlight = array( - 'SELECT', 'DISTINCT', 'FROM', 'WHERE', 'and', 'LEFT JOIN', 'ORDER BY', - 'GROUP BY', 'LIMIT', 'INSERT', 'INTO', 'VALUES', 'UPDATE', 'OR ', - 'HAVING', 'OFFSET', 'NOT IN', ' IN', 'LIKE', 'NOT LIKE', - 'COUNT', 'MAX', 'MIN', ' ON', 'AS', 'AVG', 'SUM', '(', ')' + 'SELECT', 'DISTINCT', 'FROM', 'WHERE', 'and', 'LEFT JOIN', 'ORDER BY', + 'GROUP BY', 'LIMIT', 'INSERT', 'INTO', 'VALUES', 'UPDATE', 'OR ', + 'HAVING', 'OFFSET', 'NOT IN', ' IN', 'LIKE', 'NOT LIKE', + 'COUNT', 'MAX', 'MIN', ' ON', ' AS ', 'AVG', 'SUM', '(', ')' ); $output = array(); @@ -173,20 +173,25 @@ protected function _compile_queries() } else { $total = 0; // total query time $counts = array_count_values($db->queries); + $explainSupported = stripos($this->CI->db->platform(), 'mysql') !== false; + $explainPartial = $explainSupported && version_compare($this->CI->db->version(), '5.6.3', '<'); foreach ($db->queries as $key => $val) { $duplicate = false; $time = number_format($db->query_times[$key], 4); $query = $duplicate ? "{$val}" : $val; - $explain = strpos($val, 'SELECT') !== false ? $this->CI->db->query("EXPLAIN {$val}") : null; + $explain = $explainSupported + && stripos($val, 'SELECT') !== false + && ! ($explainPartial && preg_match('/UPDATE|INSERT|DELETE/i', $val) + ) ? $this->CI->db->query("EXPLAIN {$val}") : null; if (! is_null($explain)) { $query .= $this->build_sql_explain($explain->row(), $time); } $total += $db->query_times[$key]; foreach ($highlight as $bold) { - $query = str_replace($bold, "{$bold}", $query); + $query = str_ireplace($bold, "{$bold}", $query); } $output[] = array( diff --git a/application/third_party/MX/Loader.php b/application/third_party/MX/Loader.php index a1133528b..b219e96f7 100644 --- a/application/third_party/MX/Loader.php +++ b/application/third_party/MX/Loader.php @@ -171,7 +171,6 @@ public function library($library, $params = NULL, $object_name = NULL) if ($path === FALSE) { $this->_ci_load_library($library, $params, $object_name); - $_alias = $this->_ci_classes[$class]; } else { diff --git a/application/views/errors/cli/error_exception.php b/application/views/errors/cli/error_exception.php index 75d7f0fad..efa6a66d1 100644 --- a/application/views/errors/cli/error_exception.php +++ b/application/views/errors/cli/error_exception.php @@ -1,25 +1,21 @@ - + An uncaught Exception was encountered -Type: -Message: -Filename: getFile(); ?> +Type: +Message: +Filename: getFile(), "\n"; ?> Line Number: getLine(); ?> Backtrace: - getTrace() as $error): ?> - +getTrace() as $error): ?> + + File: + Line: + Function: + + - File: - Line: - Function: - - - - - \ No newline at end of file + diff --git a/application/views/errors/cli/error_php.php b/application/views/errors/cli/error_php.php index fec91e54f..8a24b6491 100644 --- a/application/views/errors/cli/error_php.php +++ b/application/views/errors/cli/error_php.php @@ -1,25 +1,21 @@ - + A PHP Error was encountered -Severity: -Message: -Filename: -Line Number: +Severity: +Message: +Filename: +Line Number: Backtrace: - - + + + File: + Line: + Function: + + - File: - Line: - Function: - - - - - \ No newline at end of file + diff --git a/bonfire/ci3/core/CodeIgniter.php b/bonfire/ci3/core/CodeIgniter.php index 4c07d2922..71b33f692 100644 --- a/bonfire/ci3/core/CodeIgniter.php +++ b/bonfire/ci3/core/CodeIgniter.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 @@ -28,10 +28,10 @@ * * @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) 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 http://codeigniter.com + * @link https://codeigniter.com * @since Version 1.0.0 * @filesource */ @@ -46,7 +46,7 @@ * @subpackage CodeIgniter * @category Front-controller * @author EllisLab Dev Team - * @link http://codeigniter.com/user_guide/ + * @link https://codeigniter.com/user_guide/ */ /** @@ -55,7 +55,7 @@ * @var string * */ - define('CI_VERSION', '3.0.0'); + define('CI_VERSION', '3.0.6'); /* * ------------------------------------------------------ @@ -359,7 +359,7 @@ * * Returns current CI instance object * - * @return object + * @return CI_Controller */ function &get_instance() { @@ -405,6 +405,7 @@ function &get_instance() } else { + // Check for Bonfire controller if Application controller was not found. if (file_exists(APPPATH.'controllers/'.$RTR->directory.$class.'.php')) { require_once(APPPATH.'controllers/'.$RTR->directory.$class.'.php'); } elseif (file_exists(BFPATH . 'controllers/' . $RTR->directory . $class . '.php')) { diff --git a/bonfire/ci3/core/Common.php b/bonfire/ci3/core/Common.php index 1332317e9..88581ee51 100644 --- a/bonfire/ci3/core/Common.php +++ b/bonfire/ci3/core/Common.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 @@ -28,10 +28,10 @@ * * @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) 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 http://codeigniter.com + * @link https://codeigniter.com * @since Version 1.0.0 * @filesource */ @@ -46,7 +46,7 @@ * @subpackage CodeIgniter * @category Common Functions * @author EllisLab Dev Team - * @link http://codeigniter.com/user_guide/ + * @link https://codeigniter.com/user_guide/ */ // ------------------------------------------------------------------------ @@ -195,7 +195,7 @@ function &load_class($class, $directory = 'libraries', $param = NULL) // Did we find the class? if ($name === FALSE) { - // Note: We use exit() rather then show_error() in order to avoid a + // Note: We use exit() rather than show_error() in order to avoid a // self-referencing loop with the Exceptions class set_status_header(503); echo 'Unable to locate the specified class: '.$class.'.php'; @@ -519,49 +519,53 @@ function set_status_header($code = 200, $text = '') if (empty($text)) { is_int($code) OR $code = (int) $code; - $stati = array( - 200 => 'OK', - 201 => 'Created', - 202 => 'Accepted', - 203 => 'Non-Authoritative Information', - 204 => 'No Content', - 205 => 'Reset Content', - 206 => 'Partial Content', - - 300 => 'Multiple Choices', - 301 => 'Moved Permanently', - 302 => 'Found', - 303 => 'See Other', - 304 => 'Not Modified', - 305 => 'Use Proxy', - 307 => 'Temporary Redirect', - - 400 => 'Bad Request', - 401 => 'Unauthorized', - 403 => 'Forbidden', - 404 => 'Not Found', - 405 => 'Method Not Allowed', - 406 => 'Not Acceptable', - 407 => 'Proxy Authentication Required', - 408 => 'Request Timeout', - 409 => 'Conflict', - 410 => 'Gone', - 411 => 'Length Required', - 412 => 'Precondition Failed', - 413 => 'Request Entity Too Large', - 414 => 'Request-URI Too Long', - 415 => 'Unsupported Media Type', - 416 => 'Requested Range Not Satisfiable', - 417 => 'Expectation Failed', - 422 => 'Unprocessable Entity', - - 500 => 'Internal Server Error', - 501 => 'Not Implemented', - 502 => 'Bad Gateway', - 503 => 'Service Unavailable', - 504 => 'Gateway Timeout', - 505 => 'HTTP Version Not Supported' - ); + $stati = array( + 100 => 'Continue', + 101 => 'Switching Protocols', + + 200 => 'OK', + 201 => 'Created', + 202 => 'Accepted', + 203 => 'Non-Authoritative Information', + 204 => 'No Content', + 205 => 'Reset Content', + 206 => 'Partial Content', + + 300 => 'Multiple Choices', + 301 => 'Moved Permanently', + 302 => 'Found', + 303 => 'See Other', + 304 => 'Not Modified', + 305 => 'Use Proxy', + 307 => 'Temporary Redirect', + + 400 => 'Bad Request', + 401 => 'Unauthorized', + 402 => 'Payment Required', + 403 => 'Forbidden', + 404 => 'Not Found', + 405 => 'Method Not Allowed', + 406 => 'Not Acceptable', + 407 => 'Proxy Authentication Required', + 408 => 'Request Timeout', + 409 => 'Conflict', + 410 => 'Gone', + 411 => 'Length Required', + 412 => 'Precondition Failed', + 413 => 'Request Entity Too Large', + 414 => 'Request-URI Too Long', + 415 => 'Unsupported Media Type', + 416 => 'Requested Range Not Satisfiable', + 417 => 'Expectation Failed', + 422 => 'Unprocessable Entity', + + 500 => 'Internal Server Error', + 501 => 'Not Implemented', + 502 => 'Bad Gateway', + 503 => 'Service Unavailable', + 504 => 'Gateway Timeout', + 505 => 'HTTP Version Not Supported' + ); if (isset($stati[$code])) { @@ -687,7 +691,7 @@ function _exception_handler($exception) * of CodeIgniter.php. The main reason we use this is to simulate * a complete custom exception handler. * - * E_STRICT is purposivly neglected because such events may have + * E_STRICT is purposively neglected because such events may have * been caught. Duplication or none? None is preferred for now. * * @link http://insomanic.me.uk/post/229851073/php-trick-catching-fatal-errors-e-error-with-a @@ -755,14 +759,19 @@ function remove_invisible_characters($str, $url_encoded = TRUE) */ function html_escape($var, $double_encode = TRUE) { - if (empty($var)) - { - return $var; - } + if (empty($var)) + { + return $var; + } if (is_array($var)) { - return array_map('html_escape', $var, array_fill(0, count($var), $double_encode)); + foreach (array_keys($var) as $key) + { + $var[$key] = html_escape($var[$key], $double_encode); + } + + return $var; } return htmlspecialchars($var, ENT_QUOTES, config_item('charset'), $double_encode); @@ -843,19 +852,9 @@ function function_usable($function_name) { if ( ! isset($_suhosin_func_blacklist)) { - if (extension_loaded('suhosin')) - { - $_suhosin_func_blacklist = explode(',', trim(ini_get('suhosin.executor.func.blacklist'))); - - if ( ! in_array('eval', $_suhosin_func_blacklist, TRUE) && ini_get('suhosin.executor.disable_eval')) - { - $_suhosin_func_blacklist[] = 'eval'; - } - } - else - { - $_suhosin_func_blacklist = array(); - } + $_suhosin_func_blacklist = extension_loaded('suhosin') + ? explode(',', trim(ini_get('suhosin.executor.func.blacklist'))) + : array(); } return ! in_array($function_name, $_suhosin_func_blacklist, TRUE); diff --git a/bonfire/ci3/core/Loader.php b/bonfire/ci3/core/Loader.php new file mode 100644 index 000000000..839f82fd6 --- /dev/null +++ b/bonfire/ci3/core/Loader.php @@ -0,0 +1,1445 @@ + TRUE); + + /** + * List of paths to load libraries from + * + * @var array + */ + protected $_ci_library_paths = array(APPPATH, BASEPATH); + + /** + * List of paths to load models from + * + * @var array + */ + protected $_ci_model_paths = array(APPPATH); + + /** + * List of paths to load helpers from + * + * @var array + */ + protected $_ci_helper_paths = array(APPPATH, BASEPATH); + + /** + * List of cached variables + * + * @var array + */ + protected $_ci_cached_vars = array(); + + /** + * List of loaded classes + * + * @var array + */ + protected $_ci_classes = array(); + + /** + * List of loaded models + * + * @var array + */ + protected $_ci_models = array(); + + /** + * List of loaded helpers + * + * @var array + */ + protected $_ci_helpers = array(); + + /** + * List of class name mappings + * + * @var array + */ + protected $_ci_varmap = array( + 'unit_test' => 'unit', + 'user_agent' => 'agent' + ); + + // -------------------------------------------------------------------- + + /** + * Class constructor + * + * Sets component load paths, gets the initial output buffering level. + * + * @return void + */ + public function __construct() + { + $this->_ci_ob_level = ob_get_level(); + $this->_ci_classes =& is_loaded(); + + log_message('info', 'Loader Class Initialized'); + } + + // -------------------------------------------------------------------- + + /** + * Initializer + * + * @todo Figure out a way to move this to the constructor + * without breaking *package_path*() methods. + * @uses CI_Loader::_ci_autoloader() + * @used-by CI_Controller::__construct() + * @return void + */ + public function initialize() + { + $this->_ci_autoloader(); + } + + // -------------------------------------------------------------------- + + /** + * Is Loaded + * + * A utility method to test if a class is in the self::$_ci_classes array. + * + * @used-by Mainly used by Form Helper function _get_validation_object(). + * + * @param string $class Class name to check for + * @return string|bool Class object name if loaded or FALSE + */ + public function is_loaded($class) + { + return array_search(ucfirst($class), $this->_ci_classes, TRUE); + } + + // -------------------------------------------------------------------- + + /** + * Library Loader + * + * Loads and instantiates libraries. + * Designed to be called from application controllers. + * + * @param string $library Library name + * @param array $params Optional parameters to pass to the library class constructor + * @param string $object_name An optional object name to assign to + * @return object + */ + public function library($library, $params = NULL, $object_name = NULL) + { + if (empty($library)) + { + return $this; + } + elseif (is_array($library)) + { + foreach ($library as $key => $value) + { + if (is_int($key)) + { + $this->library($value, $params); + } + else + { + $this->library($key, $params, $value); + } + } + + return $this; + } + + if ($params !== NULL && ! is_array($params)) + { + $params = NULL; + } + + $this->_ci_load_library($library, $params, $object_name); + return $this; + } + + // -------------------------------------------------------------------- + + /** + * Model Loader + * + * Loads and instantiates models. + * + * @param string $model Model name + * @param string $name An optional object name to assign to + * @param bool $db_conn An optional database connection configuration to initialize + * @return object + */ + public function model($model, $name = '', $db_conn = FALSE) + { + if (empty($model)) + { + return $this; + } + elseif (is_array($model)) + { + foreach ($model as $key => $value) + { + is_int($key) ? $this->model($value, '', $db_conn) : $this->model($key, $value, $db_conn); + } + + return $this; + } + + $path = ''; + + // Is the model in a sub-folder? If so, parse out the filename and path. + if (($last_slash = strrpos($model, '/')) !== FALSE) + { + // The path is in front of the last slash + $path = substr($model, 0, ++$last_slash); + + // And the model name behind it + $model = substr($model, $last_slash); + } + + if (empty($name)) + { + $name = $model; + } + + if (in_array($name, $this->_ci_models, TRUE)) + { + return $this; + } + + $CI =& get_instance(); + if (isset($CI->$name)) + { + throw new RuntimeException('The model name you are loading is the name of a resource that is already being used: '.$name); + } + + if ($db_conn !== FALSE && ! class_exists('CI_DB', FALSE)) + { + if ($db_conn === TRUE) + { + $db_conn = ''; + } + + $this->database($db_conn, FALSE, TRUE); + } + + // Note: All of the code under this condition used to be just: + // + // load_class('Model', 'core'); + // + // However, load_class() instantiates classes + // to cache them for later use and that prevents + // MY_Model from being an abstract class and is + // sub-optimal otherwise anyway. + if ( ! class_exists('CI_Model', FALSE)) + { + $app_path = APPPATH.'core'.DIRECTORY_SEPARATOR; + if (file_exists($app_path.'Model.php')) + { + require_once($app_path.'Model.php'); + if ( ! class_exists('CI_Model', FALSE)) + { + throw new RuntimeException($app_path."Model.php exists, but doesn't declare class CI_Model"); + } + } + elseif ( ! class_exists('CI_Model', FALSE)) + { + require_once(BASEPATH.'core'.DIRECTORY_SEPARATOR.'Model.php'); + } + + $class = config_item('subclass_prefix').'Model'; + if (file_exists($app_path.$class.'.php')) + { + require_once($app_path.$class.'.php'); + if ( ! class_exists($class, FALSE)) + { + throw new RuntimeException($app_path.$class.".php exists, but doesn't declare class ".$class); + } + } + } + + $model = ucfirst($model); + if ( ! class_exists($model, FALSE)) + { + foreach ($this->_ci_model_paths as $mod_path) + { + if ( ! file_exists($mod_path.'models/'.$path.$model.'.php')) + { + continue; + } + + require_once($mod_path.'models/'.$path.$model.'.php'); + if ( ! class_exists($model, FALSE)) + { + throw new RuntimeException($mod_path."models/".$path.$model.".php exists, but doesn't declare class ".$model); + } + + break; + } + + if ( ! class_exists($model, FALSE)) + { + throw new RuntimeException('Unable to locate the model you have specified: '.$model); + } + } + elseif ( ! is_subclass_of($model, 'CI_Model')) + { + throw new RuntimeException("Class ".$model." already exists and doesn't extend CI_Model"); + } + + $this->_ci_models[] = $name; + $CI->$name = new $model(); + return $this; + } + + // -------------------------------------------------------------------- + + /** + * Database Loader + * + * @param mixed $params Database configuration options + * @param bool $return Whether to return the database object + * @param bool $query_builder Whether to enable Query Builder + * (overrides the configuration setting) + * + * @return object|bool Database object if $return is set to TRUE, + * FALSE on failure, CI_Loader instance in any other case + */ + public function database($params = '', $return = FALSE, $query_builder = NULL) + { + // Grab the super object + $CI =& get_instance(); + + // Do we even need to load the database class? + if ($return === FALSE && $query_builder === NULL && isset($CI->db) && is_object($CI->db) && ! empty($CI->db->conn_id)) + { + return FALSE; + } + + require_once(BASEPATH.'database/DB.php'); + + if ($return === TRUE) + { + return DB($params, $query_builder); + } + + // Initialize the db variable. Needed to prevent + // reference errors with some configurations + $CI->db = ''; + + // Load the DB class + $CI->db =& DB($params, $query_builder); + return $this; + } + + // -------------------------------------------------------------------- + + /** + * Load the Database Utilities Class + * + * @param object $db Database object + * @param bool $return Whether to return the DB Utilities class object or not + * @return object + */ + public function dbutil($db = NULL, $return = FALSE) + { + $CI =& get_instance(); + + if ( ! is_object($db) OR ! ($db instanceof CI_DB)) + { + class_exists('CI_DB', FALSE) OR $this->database(); + $db =& $CI->db; + } + + require_once(BASEPATH.'database/DB_utility.php'); + require_once(BASEPATH.'database/drivers/'.$db->dbdriver.'/'.$db->dbdriver.'_utility.php'); + $class = 'CI_DB_'.$db->dbdriver.'_utility'; + + if ($return === TRUE) + { + return new $class($db); + } + + $CI->dbutil = new $class($db); + return $this; + } + + // -------------------------------------------------------------------- + + /** + * Load the Database Forge Class + * + * @param object $db Database object + * @param bool $return Whether to return the DB Forge class object or not + * @return object + */ + public function dbforge($db = NULL, $return = FALSE) + { + $CI =& get_instance(); + if ( ! is_object($db) OR ! ($db instanceof CI_DB)) + { + class_exists('CI_DB', FALSE) OR $this->database(); + $db =& $CI->db; + } + + require_once(BASEPATH.'database/DB_forge.php'); + require_once(BASEPATH.'database/drivers/'.$db->dbdriver.'/'.$db->dbdriver.'_forge.php'); + + if ( ! empty($db->subdriver)) + { + $driver_path = BASEPATH.'database/drivers/'.$db->dbdriver.'/subdrivers/'.$db->dbdriver.'_'.$db->subdriver.'_forge.php'; + if (file_exists($driver_path)) + { + require_once($driver_path); + $class = 'CI_DB_'.$db->dbdriver.'_'.$db->subdriver.'_forge'; + } + } + else + { + $class = 'CI_DB_'.$db->dbdriver.'_forge'; + } + + if ($return === TRUE) + { + return new $class($db); + } + + $CI->dbforge = new $class($db); + return $this; + } + + // -------------------------------------------------------------------- + + /** + * View Loader + * + * Loads "view" files. + * + * @param string $view View name + * @param array $vars An associative array of data + * to be extracted for use in the view + * @param bool $return Whether to return the view output + * or leave it to the Output class + * @return object|string + */ + public function view($view, $vars = array(), $return = FALSE) + { + return $this->_ci_load(array('_ci_view' => $view, '_ci_vars' => $this->_ci_object_to_array($vars), '_ci_return' => $return)); + } + + // -------------------------------------------------------------------- + + /** + * Generic File Loader + * + * @param string $path File path + * @param bool $return Whether to return the file output + * @return object|string + */ + public function file($path, $return = FALSE) + { + return $this->_ci_load(array('_ci_path' => $path, '_ci_return' => $return)); + } + + // -------------------------------------------------------------------- + + /** + * Set Variables + * + * Once variables are set they become available within + * the controller class and its "view" files. + * + * @param array|object|string $vars + * An associative array or object containing values + * to be set, or a value's name if string + * @param string $val Value to set, only used if $vars is a string + * @return object + */ + public function vars($vars, $val = '') + { + if (is_string($vars)) + { + $vars = array($vars => $val); + } + + $vars = $this->_ci_object_to_array($vars); + + if (is_array($vars) && count($vars) > 0) + { + foreach ($vars as $key => $val) + { + $this->_ci_cached_vars[$key] = $val; + } + } + + return $this; + } + + // -------------------------------------------------------------------- + + /** + * Clear Cached Variables + * + * Clears the cached variables. + * + * @return CI_Loader + */ + public function clear_vars() + { + $this->_ci_cached_vars = array(); + return $this; + } + + // -------------------------------------------------------------------- + + /** + * Get Variable + * + * Check if a variable is set and retrieve it. + * + * @param string $key Variable name + * @return mixed The variable or NULL if not found + */ + public function get_var($key) + { + return isset($this->_ci_cached_vars[$key]) ? $this->_ci_cached_vars[$key] : NULL; + } + + // -------------------------------------------------------------------- + + /** + * Get Variables + * + * Retrieves all loaded variables. + * + * @return array + */ + public function get_vars() + { + return $this->_ci_cached_vars; + } + + // -------------------------------------------------------------------- + + /** + * Helper Loader + * + * @param string|string[] $helpers Helper name(s) + * @return object + */ + public function helper($helpers = array()) + { + foreach ($this->_ci_prep_filename($helpers, '_helper') as $helper) + { + if (isset($this->_ci_helpers[$helper])) + { + continue; + } + + // Is this a helper extension request? + $ext_helper = config_item('subclass_prefix').$helper; + $ext_loaded = FALSE; + foreach ($this->_ci_helper_paths as $path) + { + if (file_exists($path.'helpers/'.$ext_helper.'.php')) + { + include_once($path.'helpers/'.$ext_helper.'.php'); + $ext_loaded = TRUE; + } + } + + // Look for Bonfire helper extension. + if (file_exists(BFPATH . "helpers/BF_{$helper}.php")) + { + include_once(BFPATH . "helpers/BF_{$helper}.php"); + $ext_loaded = TRUE; + } + + + // If we have loaded extensions - check if the base one is here + if ($ext_loaded === TRUE) + { + $base_helper = BASEPATH.'helpers/'.$helper.'.php'; + if ( ! file_exists($base_helper)) + { + show_error('Unable to load the requested file: helpers/'.$helper.'.php'); + } + + include_once($base_helper); + $this->_ci_helpers[$helper] = TRUE; + log_message('info', 'Helper loaded: '.$helper); + continue; + } + + // No extensions found ... try loading regular helpers and/or overrides + foreach ($this->_ci_helper_paths as $path) + { + if (file_exists($path.'helpers/'.$helper.'.php')) + { + include_once($path.'helpers/'.$helper.'.php'); + + $this->_ci_helpers[$helper] = TRUE; + log_message('info', 'Helper loaded: '.$helper); + break; + } + } + + // unable to load the helper + if ( ! isset($this->_ci_helpers[$helper])) + { + show_error('Unable to load the requested file: helpers/'.$helper.'.php'); + } + } + + return $this; + } + + // -------------------------------------------------------------------- + + /** + * Load Helpers + * + * An alias for the helper() method in case the developer has + * written the plural form of it. + * + * @uses CI_Loader::helper() + * @param string|string[] $helpers Helper name(s) + * @return object + */ + public function helpers($helpers = array()) + { + return $this->helper($helpers); + } + + // -------------------------------------------------------------------- + + /** + * Language Loader + * + * Loads language files. + * + * @param string|string[] $files List of language file names to load + * @param string Language name + * @return object + */ + public function language($files, $lang = '') + { + get_instance()->lang->load($files, $lang); + return $this; + } + + // -------------------------------------------------------------------- + + /** + * Config Loader + * + * Loads a config file (an alias for CI_Config::load()). + * + * @uses CI_Config::load() + * @param string $file Configuration file name + * @param bool $use_sections Whether configuration values should be loaded into their own section + * @param bool $fail_gracefully Whether to just return FALSE or display an error message + * @return bool TRUE if the file was loaded correctly or FALSE on failure + */ + public function config($file, $use_sections = FALSE, $fail_gracefully = FALSE) + { + return get_instance()->config->load($file, $use_sections, $fail_gracefully); + } + + // -------------------------------------------------------------------- + + /** + * Driver Loader + * + * Loads a driver library. + * + * @param string|string[] $library Driver name(s) + * @param array $params Optional parameters to pass to the driver + * @param string $object_name An optional object name to assign to + * + * @return object|bool Object or FALSE on failure if $library is a string + * and $object_name is set. CI_Loader instance otherwise. + */ + public function driver($library, $params = NULL, $object_name = NULL) + { + if (is_array($library)) + { + foreach ($library as $key => $value) + { + if (is_int($key)) + { + $this->driver($value, $params); + } + else + { + $this->driver($key, $params, $value); + } + } + + return $this; + } + elseif (empty($library)) + { + return FALSE; + } + + if ( ! class_exists('CI_Driver_Library', FALSE)) + { + // We aren't instantiating an object here, just making the base class available + require BASEPATH.'libraries/Driver.php'; + } + + // We can save the loader some time since Drivers will *always* be in a subfolder, + // and typically identically named to the library + if ( ! strpos($library, '/')) + { + $library = ucfirst($library).'/'.$library; + } + + return $this->library($library, $params, $object_name); + } + + // -------------------------------------------------------------------- + + /** + * Add Package Path + * + * Prepends a parent path to the library, model, helper and config + * path arrays. + * + * @see CI_Loader::$_ci_library_paths + * @see CI_Loader::$_ci_model_paths + * @see CI_Loader::$_ci_helper_paths + * @see CI_Config::$_config_paths + * + * @param string $path Path to add + * @param bool $view_cascade (default: TRUE) + * @return object + */ + public function add_package_path($path, $view_cascade = TRUE) + { + $path = rtrim($path, '/').'/'; + + array_unshift($this->_ci_library_paths, $path); + array_unshift($this->_ci_model_paths, $path); + array_unshift($this->_ci_helper_paths, $path); + + $this->_ci_view_paths = array($path.'views/' => $view_cascade) + $this->_ci_view_paths; + + // Add config file path + $config =& $this->_ci_get_component('config'); + $config->_config_paths[] = $path; + + return $this; + } + + // -------------------------------------------------------------------- + + /** + * Get Package Paths + * + * Return a list of all package paths. + * + * @param bool $include_base Whether to include BASEPATH (default: FALSE) + * @return array + */ + public function get_package_paths($include_base = FALSE) + { + return ($include_base === TRUE) ? $this->_ci_library_paths : $this->_ci_model_paths; + } + + // -------------------------------------------------------------------- + + /** + * Remove Package Path + * + * Remove a path from the library, model, helper and/or config + * path arrays if it exists. If no path is provided, the most recently + * added path will be removed removed. + * + * @param string $path Path to remove + * @return object + */ + public function remove_package_path($path = '') + { + $config =& $this->_ci_get_component('config'); + + if ($path === '') + { + array_shift($this->_ci_library_paths); + array_shift($this->_ci_model_paths); + array_shift($this->_ci_helper_paths); + array_shift($this->_ci_view_paths); + array_pop($config->_config_paths); + } + else + { + $path = rtrim($path, '/').'/'; + foreach (array('_ci_library_paths', '_ci_model_paths', '_ci_helper_paths') as $var) + { + if (($key = array_search($path, $this->{$var})) !== FALSE) + { + unset($this->{$var}[$key]); + } + } + + if (isset($this->_ci_view_paths[$path.'views/'])) + { + unset($this->_ci_view_paths[$path.'views/']); + } + + if (($key = array_search($path, $config->_config_paths)) !== FALSE) + { + unset($config->_config_paths[$key]); + } + } + + // make sure the application default paths are still in the array + $this->_ci_library_paths = array_unique(array_merge($this->_ci_library_paths, array(APPPATH, BASEPATH))); + $this->_ci_helper_paths = array_unique(array_merge($this->_ci_helper_paths, array(APPPATH, BASEPATH))); + $this->_ci_model_paths = array_unique(array_merge($this->_ci_model_paths, array(APPPATH))); + $this->_ci_view_paths = array_merge($this->_ci_view_paths, array(APPPATH.'views/' => TRUE)); + $config->_config_paths = array_unique(array_merge($config->_config_paths, array(APPPATH))); + + return $this; + } + + // -------------------------------------------------------------------- + + /** + * Internal CI Data Loader + * + * Used to load views and files. + * + * Variables are prefixed with _ci_ to avoid symbol collision with + * variables made available to view files. + * + * @used-by CI_Loader::view() + * @used-by CI_Loader::file() + * @param array $_ci_data Data to load + * @return object + */ + protected function _ci_load($_ci_data) + { + // Set the default data variables + foreach (array('_ci_view', '_ci_vars', '_ci_path', '_ci_return') as $_ci_val) + { + $$_ci_val = isset($_ci_data[$_ci_val]) ? $_ci_data[$_ci_val] : FALSE; + } + + $file_exists = FALSE; + + // Set the path to the requested file + if (is_string($_ci_path) && $_ci_path !== '') + { + $_ci_x = explode('/', $_ci_path); + $_ci_file = end($_ci_x); + } + else + { + $_ci_ext = pathinfo($_ci_view, PATHINFO_EXTENSION); + $_ci_file = ($_ci_ext === '') ? $_ci_view.'.php' : $_ci_view; + + foreach ($this->_ci_view_paths as $_ci_view_file => $cascade) + { + if (file_exists($_ci_view_file.$_ci_file)) + { + $_ci_path = $_ci_view_file.$_ci_file; + $file_exists = TRUE; + break; + } + + if ( ! $cascade) + { + break; + } + } + } + + if ( ! $file_exists && ! file_exists($_ci_path)) + { + show_error('Unable to load the requested file: '.$_ci_file); + } + + // This allows anything loaded using $this->load (views, files, etc.) + // to become accessible from within the Controller and Model functions. + $_ci_CI =& get_instance(); + foreach (get_object_vars($_ci_CI) as $_ci_key => $_ci_var) + { + if ( ! isset($this->$_ci_key)) + { + $this->$_ci_key =& $_ci_CI->$_ci_key; + } + } + + /* + * Extract and cache variables + * + * You can either set variables using the dedicated $this->load->vars() + * function or via the second parameter of this function. We'll merge + * the two types and cache them so that views that are embedded within + * other views can have access to these variables. + */ + if (is_array($_ci_vars)) + { + foreach (array_keys($_ci_vars) as $key) + { + if (strncmp($key, '_ci_', 4) === 0) + { + unset($_ci_vars[$key]); + } + } + + $this->_ci_cached_vars = array_merge($this->_ci_cached_vars, $_ci_vars); + } + extract($this->_ci_cached_vars); + + /* + * Buffer the output + * + * We buffer the output for two reasons: + * 1. Speed. You get a significant speed boost. + * 2. So that the final rendered template can be post-processed by + * the output class. Why do we need post processing? For one thing, + * in order to show the elapsed page load time. Unless we can + * intercept the content right before it's sent to the browser and + * then stop the timer it won't be accurate. + */ + ob_start(); + + // If the PHP installation does not support short tags we'll + // do a little string replacement, changing the short tags + // to standard PHP echo statements. + if ( ! is_php('5.4') && ! ini_get('short_open_tag') && config_item('rewrite_short_tags') === TRUE) + { + echo eval('?>'.preg_replace('/;*\s*\?>/', '; ?>', str_replace(' $this->_ci_ob_level + 1) + { + ob_end_flush(); + } + else + { + $_ci_CI->output->append_output(ob_get_contents()); + @ob_end_clean(); + } + + return $this; + } + + // -------------------------------------------------------------------- + + /** + * Internal CI Library Loader + * + * @used-by CI_Loader::library() + * @uses CI_Loader::_ci_init_library() + * + * @param string $class Class name to load + * @param mixed $params Optional parameters to pass to the class constructor + * @param string $object_name Optional object name to assign to + * @return void + */ + protected function _ci_load_library($class, $params = NULL, $object_name = NULL) + { + // Get the class name, and while we're at it trim any slashes. + // The directory path can be included as part of the class name, + // but we don't want a leading slash + $class = str_replace('.php', '', trim($class, '/')); + + // Was the path included with the class name? + // We look for a slash to determine this + if (($last_slash = strrpos($class, '/')) !== FALSE) + { + // Extract the path + $subdir = substr($class, 0, ++$last_slash); + + // Get the filename from the path + $class = substr($class, $last_slash); + } + else + { + $subdir = ''; + } + + $class = ucfirst($class); + + // Is this a stock library? There are a few special conditions if so ... + if (file_exists(BASEPATH.'libraries/'.$subdir.$class.'.php')) + { + return $this->_ci_load_stock_library($class, $subdir, $params, $object_name); + } + + // Let's search for the requested library file and load it. + foreach ($this->_ci_library_paths as $path) + { + // BASEPATH has already been checked for + if ($path === BASEPATH) + { + continue; + } + + $filepath = $path.'libraries/'.$subdir.$class.'.php'; + + // Safety: Was the class already loaded by a previous call? + if (class_exists($class, FALSE)) + { + // Before we deem this to be a duplicate request, let's see + // if a custom object name is being supplied. If so, we'll + // return a new instance of the object + if ($object_name !== NULL) + { + $CI =& get_instance(); + if ( ! isset($CI->$object_name)) + { + return $this->_ci_init_library($class, '', $params, $object_name); + } + } + + log_message('debug', $class.' class already loaded. Second attempt ignored.'); + return; + } + // Does the file exist? No? Bummer... + elseif ( ! file_exists($filepath)) + { + continue; + } + + include_once($filepath); + return $this->_ci_init_library($class, '', $params, $object_name); + } + + // One last attempt. Maybe the library is in a subdirectory, but it wasn't specified? + if ($subdir === '') + { + return $this->_ci_load_library($class.'/'.$class, $params, $object_name); + } + + // If we got this far we were unable to find the requested class. + log_message('error', 'Unable to load the requested class: '.$class); + show_error('Unable to load the requested class: '.$class); + } + + // -------------------------------------------------------------------- + + /** + * Internal CI Stock Library Loader + * + * @used-by CI_Loader::_ci_load_library() + * @uses CI_Loader::_ci_init_library() + * + * @param string $library Library name to load + * @param string $file_path Path to the library filename, relative to libraries/ + * @param mixed $params Optional parameters to pass to the class constructor + * @param string $object_name Optional object name to assign to + * @return void + */ + protected function _ci_load_stock_library($library_name, $file_path, $params, $object_name) + { + $prefix = 'CI_'; + + if (class_exists($prefix.$library_name, FALSE)) + { + if (class_exists(config_item('subclass_prefix').$library_name, FALSE)) + { + $prefix = config_item('subclass_prefix'); + } + + // Before we deem this to be a duplicate request, let's see + // if a custom object name is being supplied. If so, we'll + // return a new instance of the object + if ($object_name !== NULL) + { + $CI =& get_instance(); + if ( ! isset($CI->$object_name)) + { + return $this->_ci_init_library($library_name, $prefix, $params, $object_name); + } + } + + log_message('debug', $library_name.' class already loaded. Second attempt ignored.'); + return; + } + + $paths = $this->_ci_library_paths; + array_pop($paths); // BASEPATH + array_pop($paths); // APPPATH (needs to be the first path checked) + array_unshift($paths, APPPATH); + + foreach ($paths as $path) + { + if (file_exists($path = $path.'libraries/'.$file_path.$library_name.'.php')) + { + // Override + include_once($path); + if (class_exists($prefix.$library_name, FALSE)) + { + return $this->_ci_init_library($library_name, $prefix, $params, $object_name); + } + else + { + log_message('debug', $path.' exists, but does not declare '.$prefix.$library_name); + } + } + } + + include_once(BASEPATH.'libraries/'.$file_path.$library_name.'.php'); + + // Check for extensions + $subclass = config_item('subclass_prefix').$library_name; + foreach ($paths as $path) + { + if (file_exists($path = $path.'libraries/'.$file_path.$subclass.'.php')) + { + include_once($path); + if (class_exists($subclass, FALSE)) + { + $prefix = config_item('subclass_prefix'); + break; + } + else + { + log_message('debug', $path.' exists, but does not declare '.$subclass); + } + } + } + + return $this->_ci_init_library($library_name, $prefix, $params, $object_name); + } + + // -------------------------------------------------------------------- + + /** + * Internal CI Library Instantiator + * + * @used-by CI_Loader::_ci_load_stock_library() + * @used-by CI_Loader::_ci_load_library() + * + * @param string $class Class name + * @param string $prefix Class name prefix + * @param array|null|bool $config Optional configuration to pass to the class constructor: + * FALSE to skip; + * NULL to search in config paths; + * array containing configuration data + * @param string $object_name Optional object name to assign to + * @return void + */ + protected function _ci_init_library($class, $prefix, $config = FALSE, $object_name = NULL) + { + // Is there an associated config file for this class? Note: these should always be lowercase + if ($config === NULL) + { + // Fetch the config paths containing any package paths + $config_component = $this->_ci_get_component('config'); + + if (is_array($config_component->_config_paths)) + { + $found = FALSE; + foreach ($config_component->_config_paths as $path) + { + // We test for both uppercase and lowercase, for servers that + // are case-sensitive with regard to file names. Load global first, + // override with environment next + if (file_exists($path.'config/'.strtolower($class).'.php')) + { + include($path.'config/'.strtolower($class).'.php'); + $found = TRUE; + } + elseif (file_exists($path.'config/'.ucfirst(strtolower($class)).'.php')) + { + include($path.'config/'.ucfirst(strtolower($class)).'.php'); + $found = TRUE; + } + + if (file_exists($path.'config/'.ENVIRONMENT.'/'.strtolower($class).'.php')) + { + include($path.'config/'.ENVIRONMENT.'/'.strtolower($class).'.php'); + $found = TRUE; + } + elseif (file_exists($path.'config/'.ENVIRONMENT.'/'.ucfirst(strtolower($class)).'.php')) + { + include($path.'config/'.ENVIRONMENT.'/'.ucfirst(strtolower($class)).'.php'); + $found = TRUE; + } + + // Break on the first found configuration, thus package + // files are not overridden by default paths + if ($found === TRUE) + { + break; + } + } + } + } + + $class_name = $prefix.$class; + + // Is the class name valid? + if ( ! class_exists($class_name, FALSE)) + { + log_message('error', 'Non-existent class: '.$class_name); + show_error('Non-existent class: '.$class_name); + } + + // Set the variable name we will assign the class to + // Was a custom class name supplied? If so we'll use it + if (empty($object_name)) + { + $object_name = strtolower($class); + if (isset($this->_ci_varmap[$object_name])) + { + $object_name = $this->_ci_varmap[$object_name]; + } + } + + // Don't overwrite existing properties + $CI =& get_instance(); + if (isset($CI->$object_name)) + { + if ($CI->$object_name instanceof $class_name) + { + log_message('debug', $class_name." has already been instantiated as '".$object_name."'. Second attempt aborted."); + return; + } + + show_error("Resource '".$object_name."' already exists and is not a ".$class_name." instance."); + } + + // Save the class name and object name + $this->_ci_classes[$object_name] = $class; + + // Instantiate the class + $CI->$object_name = isset($config) + ? new $class_name($config) + : new $class_name(); + } + + // -------------------------------------------------------------------- + + /** + * CI Autoloader + * + * Loads component listed in the config/autoload.php file. + * + * @used-by CI_Loader::initialize() + * @return void + */ + protected function _ci_autoloader() + { + if (file_exists(APPPATH.'config/autoload.php')) + { + include(APPPATH.'config/autoload.php'); + } + + if (file_exists(APPPATH.'config/'.ENVIRONMENT.'/autoload.php')) + { + include(APPPATH.'config/'.ENVIRONMENT.'/autoload.php'); + } + + if ( ! isset($autoload)) + { + return; + } + + // Autoload packages + if (isset($autoload['packages'])) + { + foreach ($autoload['packages'] as $package_path) + { + $this->add_package_path($package_path); + } + } + + // Load any custom config file + if (count($autoload['config']) > 0) + { + foreach ($autoload['config'] as $val) + { + $this->config($val); + } + } + + // Autoload helpers and languages + foreach (array('helper', 'language') as $type) + { + if (isset($autoload[$type]) && count($autoload[$type]) > 0) + { + $this->$type($autoload[$type]); + } + } + + // Autoload drivers + if (isset($autoload['drivers'])) + { + $this->driver($autoload['drivers']); + } + + // Load libraries + if (isset($autoload['libraries']) && count($autoload['libraries']) > 0) + { + // Load the database driver. + if (in_array('database', $autoload['libraries'])) + { + $this->database(); + $autoload['libraries'] = array_diff($autoload['libraries'], array('database')); + } + + // Load all other libraries + $this->library($autoload['libraries']); + } + + // Autoload models + if (isset($autoload['model'])) + { + $this->model($autoload['model']); + } + } + + // -------------------------------------------------------------------- + + /** + * CI Object to Array translator + * + * Takes an object as input and converts the class variables to + * an associative array with key/value pairs. + * + * @param object $object Object data to translate + * @return array + */ + protected function _ci_object_to_array($object) + { + return is_object($object) ? get_object_vars($object) : $object; + } + + // -------------------------------------------------------------------- + + /** + * CI Component getter + * + * Get a reference to a specific library or model. + * + * @param string $component Component name + * @return bool + */ + protected function &_ci_get_component($component) + { + $CI =& get_instance(); + return $CI->$component; + } + + // -------------------------------------------------------------------- + + /** + * Prep filename + * + * This function prepares filenames of various items to + * make their loading more reliable. + * + * @param string|string[] $filename Filename(s) + * @param string $extension Filename extension + * @return array + */ + protected function _ci_prep_filename($filename, $extension) + { + if ( ! is_array($filename)) + { + return array(strtolower(str_replace(array($extension, '.php'), '', $filename).$extension)); + } + else + { + foreach ($filename as $key => $val) + { + $filename[$key] = strtolower(str_replace(array($extension, '.php'), '', $val).$extension); + } + + return $filename; + } + } + +} diff --git a/bonfire/codeigniter/core/CodeIgniter.php b/bonfire/codeigniter/core/CodeIgniter.php index 933571829..062472792 100644 --- a/bonfire/codeigniter/core/CodeIgniter.php +++ b/bonfire/codeigniter/core/CodeIgniter.php @@ -34,7 +34,7 @@ * @var string * */ - define('CI_VERSION', '2.2.2'); + define('CI_VERSION', '2.2.6'); /** * CodeIgniter Branch (Core = TRUE, Reactor = FALSE) diff --git a/bonfire/codeigniter/core/Config.php b/bonfire/codeigniter/core/Config.php index 45641faa3..6051b1d8a 100644 --- a/bonfire/codeigniter/core/Config.php +++ b/bonfire/codeigniter/core/Config.php @@ -67,12 +67,10 @@ function __construct() // Set the base_url automatically if none was provided if ($this->config['base_url'] == '') { - // The regular expression is only a basic validation for a valid "Host" header. - // It's not exhaustive, only checks for valid characters. - if (isset($_SERVER['HTTP_HOST']) && preg_match('/^((\[[0-9a-f:]+\])|(\d{1,3}(\.\d{1,3}){3})|[a-z0-9\-\.]+)(:\d+)?$/i', $_SERVER['HTTP_HOST'])) + if (isset($_SERVER['SERVER_ADDR'])) { $base_url = (empty($_SERVER['HTTPS']) OR strtolower($_SERVER['HTTPS']) === 'off') ? 'http' : 'https'; - $base_url .= '://'. $_SERVER['HTTP_HOST']; + $base_url .= '://'.$_SERVER['SERVER_ADDR']; $base_url .= substr($_SERVER['SCRIPT_NAME'], 0, strpos($_SERVER['SCRIPT_NAME'], basename($_SERVER['SCRIPT_FILENAME']))); } diff --git a/bonfire/codeigniter/core/Loader.php b/bonfire/codeigniter/core/Loader.php index 40090db6e..d649416c0 100644 --- a/bonfire/codeigniter/core/Loader.php +++ b/bonfire/codeigniter/core/Loader.php @@ -501,6 +501,7 @@ public function helper($helpers = array()) } $ext_helper = APPPATH.'helpers/'.config_item('subclass_prefix').$helper.'.php'; + $bfHelper = BFPATH . "helpers/BF_{$helper}.php"; // Is this a helper extension request? if (file_exists($ext_helper)) @@ -513,6 +514,11 @@ public function helper($helpers = array()) } include_once($ext_helper); + // Look for Bonfire helper extension. + if (file_exists($bfHelper)) + { + include_once($bfHelper); + } include_once($base_helper); $this->_ci_helpers[$helper] = TRUE; @@ -520,6 +526,13 @@ public function helper($helpers = array()) continue; } + // Look for Bonfire helper extension. + if (file_exists($bfHelper)) + { + include_once($bfHelper); + $this->_ci_helpers[$helper] = TRUE; + } + // Try to load the helper foreach ($this->_ci_helper_paths as $path) { diff --git a/bonfire/codeigniter/core/Security.php b/bonfire/codeigniter/core/Security.php index 4c265d4d6..a30488fac 100755 --- a/bonfire/codeigniter/core/Security.php +++ b/bonfire/codeigniter/core/Security.php @@ -355,7 +355,7 @@ public function xss_clean($str, $is_image = FALSE) $words = array( 'javascript', 'expression', 'vbscript', 'jscript', 'wscript', 'vbs', 'script', 'base64', 'applet', 'alert', 'document', - 'write', 'cookie', 'window', 'confirm', 'prompt' + 'write', 'cookie', 'window', 'confirm', 'prompt', 'eval' ); foreach ($words as $word) @@ -399,12 +399,8 @@ public function xss_clean($str, $is_image = FALSE) } } while($original !== $str); - unset($original); - // Remove evil attributes such as style, onclick and xmlns - $str = $this->_remove_evil_attributes($str, $is_image); - /* * Sanitize naughty HTML elements * @@ -414,8 +410,29 @@ public function xss_clean($str, $is_image = FALSE) * So this: * Becomes: <blink> */ - $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); + $pattern = '#' + .'<((?/*\s*)(?[a-z0-9]+)(?=[^a-z0-9]|$)' // tag start and name, followed by a non-tag character + .'[^\s\042\047a-z0-9>/=]*' // a valid attribute character immediately after the tag would count as a separator + // optional attributes + .'(?(?:[\s\042\047/=]*' // non-attribute characters, excluding > (tag close) for obvious reasons + .'[^\s\042\047>/=]+' // attribute characters + // optional attribute-value + .'(?:\s*=' // attribute-value separator + .'(?:[^\s\042\047=><`]+|\s*\042[^\042]*\042|\s*\047[^\047]*\047|\s*(?U:[^\s\042\047=><`]*))' // single, double or non-quoted value + .')?' // end optional attribute-value group + .')*)' // end optional attributes group + .'[^>]*)(?\>)?#isS'; + + // Note: It would be nice to optimize this for speed, BUT + // only matching the naughty elements here results in + // false positives and in turn - vulnerabilities! + do + { + $old_str = $str; + $str = preg_replace_callback($pattern, array($this, '_sanitize_naughty_html'), $str); + } + while ($old_str !== $str); + unset($old_str); /* * Sanitize naughty scripting elements @@ -626,82 +643,92 @@ protected function _compact_exploded_words($matches) // -------------------------------------------------------------------- - /* - * Remove Evil HTML Attributes (like evenhandlers and style) + /** + * Sanitize Naughty HTML * - * It removes the evil attribute and either: - * - Everything up until a space - * For example, everything between the pipes: - * - * - Everything inside the quotes - * For example, everything between the pipes: - * + * Callback function for xss_clean() to remove naughty HTML elements * - * @param string $str The string to check - * @param boolean $is_image TRUE if this is an image - * @return string The string with the evil attributes removed + * @param array + * @return string */ - protected function _remove_evil_attributes($str, $is_image) + protected function _sanitize_naughty_html($matches) { - // All javascript event handlers (e.g. onload, onclick, onmouseover), style, and xmlns - $evil_attributes = array('on\w*', 'style', 'xmlns', 'formaction', 'form', 'xlink:href', 'FSCommand', 'seekSegmentTime'); + static $naughty_tags = array( + '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' + ); - if ($is_image === TRUE) + static $evil_attributes = array( + 'on\w+', 'style', 'xmlns', 'formaction', 'form', 'xlink:href', 'FSCommand', 'seekSegmentTime' + ); + + // First, escape unclosed tags + if (empty($matches['closeTag'])) + { + return '<'.$matches[1]; + } + // Is the element that we caught naughty? If so, escape it + elseif (in_array(strtolower($matches['tagName']), $naughty_tags, TRUE)) { - /* - * Adobe Photoshop puts XML metadata into JFIF images, - * including namespacing, so we have to allow this for images. - */ - unset($evil_attributes[array_search('xmlns', $evil_attributes)]); + return '<'.$matches[1].'>'; } + // For other tags, see if their attributes are "evil" and strip those + elseif (isset($matches['attributes'])) + { + // We'll store the already fitlered attributes here + $attributes = array(); - do { - $count = 0; - $attribs = array(); + // Attribute-catching pattern + $attributes_pattern = '#' + .'(?[^\s\042\047>/=]+)' // attribute characters + // optional attribute-value + .'(?:\s*=(?[^\s\042\047=><`]+|\s*\042[^\042]*\042|\s*\047[^\047]*\047|\s*(?U:[^\s\042\047=><`]*)))' // attribute-value separator + .'#i'; - // find occurrences of illegal attribute strings with quotes (042 and 047 are octal quotes) - preg_match_all('/(?]*)/is', $str, $matches, PREG_SET_ORDER); + if ( ! preg_match($attributes_pattern, $matches['attributes'], $attribute, PREG_OFFSET_CAPTURE)) + { + // No (valid) attribute found? Discard everything else inside the tag + break; + } - foreach ($matches as $attr) - { - $attribs[] = preg_quote($attr[0], '/'); - } + if ( + // Is it indeed an "evil" attribute? + preg_match($is_evil_pattern, $attribute['name'][0]) + // Or does it have an equals sign, but no value and not quoted? Strip that too! + OR (trim($attribute['value'][0]) === '') + ) + { + $attributes[] = 'xss=removed'; + } + else + { + $attributes[] = $attribute[0][0]; + } - // replace illegal attribute strings that are inside an html tag - if (count($attribs) > 0) - { - $str = preg_replace('/(<]+?)([^A-Za-z<>\-])(.*?)('.implode('|', $attribs).')(.*?)([\s><]?)([><]*)/i', '$1$2 $4$6$7$8', $str, -1, $count); + $matches['attributes'] = substr($matches['attributes'], $attribute[0][1] + strlen($attribute[0][0])); } + while ($matches['attributes'] !== ''); + $attributes = empty($attributes) + ? '' + : ' '.implode(' ', $attributes); + return '<'.$matches['slash'].$matches['tagName'].$attributes.'>'; } - while ($count); - - return $str; - } - - // -------------------------------------------------------------------- - /** - * Sanitize Naughty HTML - * - * Callback function for xss_clean() to remove naughty HTML elements - * - * @param array - * @return string - */ - protected function _sanitize_naughty_html($matches) - { - return '<'.$matches[1].$matches[2].$matches[3] // encode opening brace - // encode captured opening or closing brace to prevent recursive vectors: - .str_replace(array('>', '<'), array('>', '<'), $matches[4]); + return $matches[0]; } // -------------------------------------------------------------------- @@ -724,7 +751,7 @@ protected function _js_link_removal($match) preg_replace( '#href=.*?(?:(?:alert|prompt|confirm)(?:\(|&\#40;)|javascript:|livescript:|mocha:|charset=|window\.|document\.|\.cookie|_filter_attributes(str_replace(array('<', '>'), '', $match[1])) + $this->_filter_attributes($match[1]) ), $match[0] ); @@ -748,9 +775,9 @@ protected function _js_img_removal($match) return str_replace( $match[1], preg_replace( - '#src=.*?(?:(?:alert|prompt|confirm)(?:\(|&\#40;)|javascript:|livescript:|mocha:|charset=|window\.|document\.|\.cookie|_filter_attributes(str_replace(array('<', '>'), '', $match[1])) + $this->_filter_attributes($match[1]) ), $match[0] ); @@ -872,4 +899,4 @@ protected function _csrf_set_hash() } /* End of file Security.php */ -/* Location: ./system/core/Security.php */ \ No newline at end of file +/* Location: ./system/core/Security.php */ diff --git a/bonfire/codeigniter/database/DB_active_rec.php b/bonfire/codeigniter/database/DB_active_rec.php index 0ae21105c..2d01cf71c 100644 --- a/bonfire/codeigniter/database/DB_active_rec.php +++ b/bonfire/codeigniter/database/DB_active_rec.php @@ -895,7 +895,7 @@ public function limit($value, $offset = '') */ public function offset($offset) { - $this->ar_offset = $offset; + $this->ar_offset = (int) $offset; return $this; } diff --git a/bonfire/codeigniter/database/drivers/bfmysqli/bfmysqli_driver.php b/bonfire/codeigniter/database/drivers/bfmysqli/bfmysqli_driver.php index 0d6571988..2804accef 100644 --- a/bonfire/codeigniter/database/drivers/bfmysqli/bfmysqli_driver.php +++ b/bonfire/codeigniter/database/drivers/bfmysqli/bfmysqli_driver.php @@ -8,7 +8,7 @@ * * @package Bonfire * @author Bonfire Dev Team - * @copyright Copyright (c) 2011 - 2014, Bonfire Dev Team + * @copyright Copyright (c) 2011 - 2015, Bonfire Dev Team * @license http://opensource.org/licenses/MIT The MIT License. * @link http://cibonfire.com * @since Version 1.0 diff --git a/bonfire/codeigniter/database/drivers/mysql/mysql_driver.php b/bonfire/codeigniter/database/drivers/mysql/mysql_driver.php index 4e357931b..3f2a9a00a 100644 --- a/bonfire/codeigniter/database/drivers/mysql/mysql_driver.php +++ b/bonfire/codeigniter/database/drivers/mysql/mysql_driver.php @@ -311,18 +311,7 @@ function escape_str($str, $like = FALSE) return $str; } - if (function_exists('mysql_real_escape_string') AND is_resource($this->conn_id)) - { - $str = mysql_real_escape_string($str, $this->conn_id); - } - elseif (function_exists('mysql_escape_string')) - { - $str = mysql_escape_string($str); - } - else - { - $str = addslashes($str); - } + $str = mysql_real_escape_string($str, $this->conn_id); // escape LIKE condition wildcards if ($like === TRUE) diff --git a/bonfire/codeigniter/helpers/captcha_helper.php b/bonfire/codeigniter/helpers/captcha_helper.php index 1dc62cfaf..831b46030 100644 --- a/bonfire/codeigniter/helpers/captcha_helper.php +++ b/bonfire/codeigniter/helpers/captcha_helper.php @@ -107,18 +107,93 @@ function create_captcha($data = '', $img_path = '', $img_url = '', $font_path = // Do we have a "word" yet? // ----------------------------------- - if ($word == '') - { + // ----------------------------------- + // Do we have a "word" yet? + // ----------------------------------- + + if (empty($word)) + { + $word = ''; $pool = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; + $pool_length = strlen($pool); + $rand_max = $pool_length - 1; - $str = ''; - for ($i = 0; $i < 8; $i++) + // PHP7 or a suitable polyfill + if (function_exists('random_int')) { - $str .= substr($pool, mt_rand(0, strlen($pool) -1), 1); + try + { + for ($i = 0; $i < $word_length; $i++) + { + $word .= $pool[random_int(0, $rand_max)]; + } + } + catch (Exception $e) + { + // This means fallback to the next possible + // alternative to random_int() + $word = ''; + } } + } - $word = $str; - } + if (empty($word)) + { + // To avoid numerous get_random_bytes() calls, we'll + // just try fetching as much bytes as we need at once. + if (($bytes = _ci_captcha_get_random_bytes($pool_length)) !== FALSE) + { + $byte_index = $word_index = 0; + while ($word_index < $word_length) + { + if (($rand_index = unpack('C', $bytes[$byte_index++])) > $rand_max) + { + // Was this the last byte we have? + // If so, try to fetch more. + if ($byte_index === $pool_length) + { + // No failures should be possible if + // the first get_random_bytes() call + // didn't return FALSE, but still ... + for ($i = 0; $i < 5; $i++) + { + if (($bytes = _ci_captcha_get_random_bytes($pool_length)) === FALSE) + { + continue; + } + + $byte_index = 0; + break; + } + + if ($bytes === FALSE) + { + // Sadly, this means fallback to mt_rand() + $word = ''; + break; + } + } + + continue; + } + + $word .= $pool[$rand_index]; + $word_index++; + } + } + } + + if (empty($word)) + { + for ($i = 0; $i < $word_length; $i++) + { + $word .= $pool[mt_rand(0, $rand_max)]; + } + } + elseif ( ! is_string($word)) + { + $word = (string) $word; + } // ----------------------------------- // Determine angle and position @@ -239,6 +314,20 @@ function create_captcha($data = '', $img_path = '', $img_url = '', $font_path = return array('word' => $word, 'time' => $now, 'image' => $img); } + + function _ci_captcha_get_random_bytes($length) + { + if (defined('MCRYPT_DEV_URANDOM')) + { + return mcrypt_create_iv($length, MCRYPT_DEV_URANDOM); + } + elseif (function_exists('openssl_random_pseudo_bytes')) + { + return openssl_random_pseudo_bytes($length); + } + + return FALSE; + } } // ------------------------------------------------------------------------ diff --git a/bonfire/codeigniter/language/english/calendar_lang.php b/bonfire/codeigniter/language/english/calendar_lang.php index b95b36eef..3e6312361 100644 --- a/bonfire/codeigniter/language/english/calendar_lang.php +++ b/bonfire/codeigniter/language/english/calendar_lang.php @@ -1,87 +1,51 @@ _module, 'helpers/'); if ($path === false) { - // If the helper was not found in a module, check for a BF_ prefixed - // helper in the Bonfire helpers directory. - if (file_exists(BFPATH . "helpers/BF_{$helper}_helper.php")) { - include_once(BFPATH . "helpers/BF_{$helper}_helper.php"); - } + // If the helper was not found in a module, check the traditional locations. parent::helper($helper); return $this; } diff --git a/bonfire/core/BF_Model.php b/bonfire/core/BF_Model.php index 5c06528fe..d100120d4 100644 --- a/bonfire/core/BF_Model.php +++ b/bonfire/core/BF_Model.php @@ -247,7 +247,7 @@ class BF_Model extends CI_Model * This can be set to avoid a database call if using $this->prep_data() and/or * $this->get_field_info(). * - * @see http://www.codeigniter.com/user_guide/database/fields.html + * @see http://www.codeigniter.com/user_guide/database/metadata.html#retrieve-field-metadata * * Each field's definition should be as follows: array( diff --git a/bonfire/core/BF_Router.php b/bonfire/core/BF_Router.php index 937136d03..b3414524f 100644 --- a/bonfire/core/BF_Router.php +++ b/bonfire/core/BF_Router.php @@ -263,6 +263,17 @@ public function _set_default_controller() } } + /** + * Sets the module path to the 404_override controller. This is pulled from + * the MX Router primarily for use by the _set_default_controller() method. + * + * @return void + */ + protected function _set_404override_controller() + { + $this->_set_module_path($this->routes['404_override']); + } + /** * Set module path. * diff --git a/bonfire/docs/_toc.ini b/bonfire/docs/_toc.ini index 607227658..8e832e39a 100644 --- a/bonfire/docs/_toc.ini +++ b/bonfire/docs/_toc.ini @@ -7,6 +7,10 @@ developer/tut_blog = Simple Blog Tutorial developer/changelog = Change Log [Upgrade Notes] +developer/upgrade/078 = 0.7.7 to 0.7.8 +developer/upgrade/077 = 0.7.6 to 0.7.7 +developer/upgrade/076 = 0.7.5 to 0.7.6 +developer/upgrade/075 = 0.7.4 to 0.7.5 developer/upgrade/074 = 0.7.3 to 0.7.4 developer/upgrade/073 = 0.7.2 to 0.7.3 developer/upgrade/072 = 0.7.1 to 0.7.2 diff --git a/bonfire/docs/changelog.md b/bonfire/docs/changelog.md index 6bc8cb17f..6fb9af8bb 100644 --- a/bonfire/docs/changelog.md +++ b/bonfire/docs/changelog.md @@ -2,6 +2,74 @@ ## Released versions +### 0.7.8 +Upgraded CodeIgniter 2 to 2.2.6 (see the [2.2.6 Upgrade Notes](https://codeigniter.com/userguide2/installation/upgrade_226.html)) +Upgraded CodeIgniter 3 to 3.0.6 (see the [3.0.6 Upgrade Notes](https://codeigniter.com/user_guide/installation/upgrade_306.html)) + +#### New Features: + +#### Closes Issues: +* #1163/1164: Fix /public/tests.php shows "SimpleTest documentation" instead of "Bonfire Tests". +* #1209: Deactivate user results in "user status was not changed" message, though user is deactivated. + +#### Additional Changes: +* Fixed `FOPEN_READ_WRITE_CREATE_DESTRUCTIVE` in constants config. + +#### Known Issues: + +### 0.7.7 +* Upgraded CodeIgniter 3 to 3.0.1 +* Upgraded CodeIgniter 2 to 2.2.4 + +#### New Features: +* MY_*_helper files can now override BF_*_helper files + +#### Closes Issues: +* #1153: Error: "Undefined index: user_agent" caused by out-dated `MX_Loader`. +* #1154: [Builder] Cancel button contains "Content" instead of "content". + +#### Additional Changes: +* `user_meta` view in `users` module updated to make it less likely to have issues with PHP 7. + +#### Known Issues: + +### 0.7.6 + +#### New Features: + +#### Closes Issues: +* #1151: [BF_Router] Call to undefined method `_set_404override_controller()` +* #1150: Changing Role name breaks permissions +* #1149: Blog Tutorial defined `$modified_field` without default value. +* #1147: Unique validation fails on existing role. +* #1144: Emailer lang entries missing when sending mail from users module. +* #1142: Module Builder: Fix #1128 properly (undefined property: Modulebuilder::$load). + +#### Additional Changes: + +#### Known Issues: + +### 0.7.5 + +#### New Features: + +#### Closes Issues: +* #1136 Profiler: MySQL explain update fails on older versions. +* #1131 Modules Library: modules_locations not loaded from application config. +* #1128 Module Builder: Use of `strip_slashes()` without loading the string helper. +* #1118 Settings error when password options are not selected in security tab. + +#### Additional Changes: +* CI Upgraded to v2.2.3: Removed a fallback to `mysql_escape_string()` in the 'mysql' database driver (`escape_str()` method). + +* Builder: Added a note to the create_context page reminding users to add route(s) for the new context. +* Contexts: Fix links when using `$top_level_only` parameter in `render_menu()` +* Docs: update paths in installation docs to reflect 0.6 directory changes. +* Installer: Fix error checking writable directories in APPPATH on Windows +* Profiler: Improved SQL highlighting in Queries tab. + +#### Known Issues: + ### 0.7.4 #### New Features: @@ -572,4 +640,4 @@ Released: August 11, 2011 - write_config() function now writes backups to application/archives like it should have been. ### Version 0.1 - Initial Release -Released: March 30, 2011 \ No newline at end of file +Released: March 30, 2011 diff --git a/bonfire/docs/ci3.md b/bonfire/docs/ci3.md index a0eb63163..f2586a18d 100644 --- a/bonfire/docs/ci3.md +++ b/bonfire/docs/ci3.md @@ -10,7 +10,7 @@ If you run into any problems while testing CI3 with Bonfire, please feel free to If you would like to test it out for yourself, you will need to do the following: - Setup (or update) a Bonfire installation with the latest code from the [develop branch on GitHub](https://github.com/ci-bonfire/Bonfire). Make sure the site is configured and working under CodeIgniter 2.x. -- Download [the latest CI3 release](http://www.codeigniter.com/download) ([CI3.0](https://github.com/bcit-ci/CodeIgniter/archive/3.0rc3.zip) is the latest release at the time of this writing). The more adventurous can download the latest code from [their development branch on GitHub](https://github.com/bcit-ci/CodeIgniter). +- Download [the latest CI3 release](http://www.codeigniter.com/download) ([CI3.0.1](https://github.com/bcit-ci/CodeIgniter/archive/3.0.1.zip) is the latest release at the time of this writing). The more adventurous can download the latest code from [their development branch on GitHub](https://github.com/bcit-ci/CodeIgniter). - Making sure to *not* overwrite the existing files in the /bonfire/ci3/ directory of your working test site, copy the files from the CI3 system directory into the /bonfire/ci3/ directory. (If you do happen to overwrite the files, you can pull them down from the Bonfire GitHub repository.) ## Updating your application diff --git a/bonfire/docs/installation.md b/bonfire/docs/installation.md index 4e48c4dc5..b97265c4f 100644 --- a/bonfire/docs/installation.md +++ b/bonfire/docs/installation.md @@ -1,7 +1,7 @@ # Installing Bonfire ## Overview -Bonfire has a simple installation script that is designed to help you, the developer, get up and running with a minimum of fuss. It is not designed to be used for an end product that you distribute. Installation is a simple process mainly composed of uploading your files and letting Bonfire install its database tables for you. +Bonfire has a simple installation script that is designed to help you, the developer, get up and running with a minimum of fuss. It is not designed to be used for an end product that you distribute. Installation is a simple process mainly composed of uploading your files and letting Bonfire install its database tables for you. ## Upload Your Files @@ -22,26 +22,26 @@ Details on the available options for the `database.php` config file can be found Ensure that you can access the database using the configured settings. While Bonfire's migrations can create the necessary tables for you, it will not create the database in which those tables reside. -If you are using multiple environments (production, testing, and development), you should create a folder matching the environment name inside your config folder. Then copy the existing database.php config file into that folder and set the details for your environment there. +If you are using multiple environments (production, testing, and development), you should create a folder matching the environment name inside your config folder. Then copy the existing `database.php` config file into that folder and set the details for your environment there. -It is possible to set the server's environment by defining a server variable. For example, on an Apache server, you can create a .conf file containing the command `SetEnv CI_ENV production` (or add the command to your site's existing .conf file), which, when enabled, will tell Bonfire that it is running on the production server, and the configuration (e.g. `error_reporting`) will change accordingly. +It is possible to set the server's environment by defining a server variable. For example, on an Apache server, you can create a `.conf` file containing the command `SetEnv CI_ENV production` (or add the command to your site's existing `.conf` file), which, when enabled, will tell Bonfire that it is running on the production server, and the configuration (e.g. `error_reporting`) will change accordingly. ## Write Permissions -Verify that the following folders are writeable during the install process: +Verify that the following folders are writable during the install process: - /bonfire/application/cache - /bonfire/application/logs - /bonfire/application/config - /bonfire/application/archives - /bonfire/application/db/backups - /bonfire/application/db/migrations - /assets/cache + /application/cache + /application/logs + /application/config + /application/archives + /application/db/backups + /application/db/migrations + /public/assets/cache Also, make sure the following file has write permissions: - /bonfire/application/config/application.php + /application/config/application.php @@ -69,7 +69,7 @@ Once your site is installed and configured, you may want to consider taking some * Remove the installer: delete the file `/bonfire/controllers/install.php` from your server (or install/configure your site on a test server and copy the files, without the install controller, to your site's server). * Remove `/public/tests.php` * Disable automatic migrations in the `/application/config/application.php` file. While `migrate.auto_core` and `migrate.auto_app` are disabled by default, it is often convenient to enable this feature during development. Disabling them can improve your page load times, and ensures that migrations are only run when you intentionally run them. -* Restrict write access: while the `/bonfire/application/cache`, `/assets/cache`, and `/bonfire/application/logs` directories should be writable (by your web server), you can remove write access from the config and db directories. This may limit some functionality (for instance DB backups through the Bonfire interface probably won't work if the web server can't write to the `/application/db/backups` directory), so consider the trade-offs for your environment. +* Restrict write access: while the `/application/cache`, `/assets/cache`, and `/application/logs` directories should be writable (by your web server), you can remove write access from the config and db directories. This may limit some functionality (for instance DB backups through the Bonfire interface probably won't work if the web server can't write to the `/application/db/backups` directory), so consider the trade-offs for your environment. * Additionally, if you opened up write access for Builder (to `/application/modules`), you will probably want to disable that capability as well (obviously, the module builder will not work in this case, but you can still use it in a local/dev environment and copy the files to the server). * Restrict database access: you may be able to adjust the permissions for the database user configured for your Bonfire site to remove potentially damaging capabilities like dropping tables. Ideally, you would enable these permissions only when running migrations against your database. diff --git a/bonfire/docs/tut_blog.md b/bonfire/docs/tut_blog.md index d9ed552b6..6e024ebdc 100644 --- a/bonfire/docs/tut_blog.md +++ b/bonfire/docs/tut_blog.md @@ -103,14 +103,15 @@ Create a new file at `blog/migrations/001_Initial_tables.php`. 'null' => false, ), 'modified_on' => array( - 'type' => 'datetime', - 'null' => false, + 'type' => 'datetime', + 'null' => true, + 'default' => '0000-00-00 00:00:00', ), 'deleted' => array( - 'type' => 'tinyint', + 'type' => 'tinyint', 'constraint' => 1, - 'null' => false, - 'default' => 0, + 'null' => false, + 'default' => 0, ), ), ), @@ -304,7 +305,7 @@ Edit the index.php view file to reflect the following: auth->has_permission('Bonfire.Blog.Delete')); + $canDelete = $this->auth->has_permission('Bonfire.Blog.Delete'); if ($canDelete) { ++$numColumns; } diff --git a/bonfire/docs/upgrade/075.md b/bonfire/docs/upgrade/075.md new file mode 100644 index 000000000..b9a52125d --- /dev/null +++ b/bonfire/docs/upgrade/075.md @@ -0,0 +1,14 @@ +# Upgrading Bonfire + +## 0.7.4 to 0.7.5 + +1. Update `/application/config/constants.php` (update BONFIRE_VERSION). +2. Update `/application/libraries/Profiler.php` +3. Replace all files in `/bonfire/codeigniter/` +4. Update `/bonfire/libraries/Installer_lib.php` +5. Update `/bonfire/libraries/Modules.php` +6. Update `/bonfire/modules/builder/language/english/builder_lang.php` +7. Update `/bonfire/modules/builder/libraries/Modulebuilder.php` +8. Update `/bonfire/modules/builder/views/developer/create_context.php` +9. Update `/bonfire/modules/settings/controllers/Settings.php` +10. Update `/bonfire/modules/ui/libraries/Contexts.php` diff --git a/bonfire/docs/upgrade/076.md b/bonfire/docs/upgrade/076.md new file mode 100644 index 000000000..df30efe62 --- /dev/null +++ b/bonfire/docs/upgrade/076.md @@ -0,0 +1,10 @@ +# Upgrading Bonfire + +## 0.7.5 to 0.7.6 + +1. Update `/bonfire/core/BF_Router.php` +2. Update `/bonfire/modules/builder/libraries/Modulebuilder.php` +3. Update `/bonfire/modules/emailer/libraries/Emailer.php` +4. Update `/bonfire/modules/roles/controllers/Settings.php` +5. Update `/bonfire/modules/roles/views/settings/role_form.php` +6. Update `/bonfire/modules/users/libraries/PasswordHash.php` diff --git a/bonfire/docs/upgrade/077.md b/bonfire/docs/upgrade/077.md new file mode 100644 index 000000000..8ae801f32 --- /dev/null +++ b/bonfire/docs/upgrade/077.md @@ -0,0 +1,33 @@ +# Upgrading Bonfire + +## 0.7.6 to 0.7.7 + +* Update `/application/config/application.php` +* Update `/application/config/autoload.php` +* Update `/application/config/config.php` +* Update `/application/config/constants.php` +* Update `/application/config/database.php` +* Update `/application/config/events.php` +* Update `/application/config/foreign_chars.php` +* Update `/application/config/hooks.php` +* Update `/application/config/migration.php` +* Update `/application/config/mimes.php` +* Update `/application/config/smileys.php` +* Update `/application/config/user_agents.php` +* Where relevant, update any of the config files above in environment directories. + +* Update `/application/third_party/MX/Loader.php` + +* Update `/application/views/errors/cli/error_exception.php` +* Update `/application/views/errors/cli/error_php.php` + +* Update all files in `/bonfire/ci3/` + +* Update `/bonfire/codeigniter/core/CodeIgniter.php` +* Update `/bonfire/codeigniter/core/Loader.php` +* Update `/bonfire/codeigniter/database/DB_active_rec.php` + +* Update `/bonfire/core/BF_Loader.php` +* Update `/bonfire/modules/builder/views/files/view_default.php` +* Update `/bonfire/modules/builder/views/files/view_index.php` +* Update `/bonfire/modules/users/views/user_meta.php` diff --git a/bonfire/docs/upgrade/078.md b/bonfire/docs/upgrade/078.md new file mode 100644 index 000000000..2f72bf5f2 --- /dev/null +++ b/bonfire/docs/upgrade/078.md @@ -0,0 +1,19 @@ +# Upgrading Bonfire + +## 0.7.7 to 0.7.8 + +* Update `/application/config/config.php` +* Update `/application/config/constants.php` + +* Update `/bonfire/codeigniter/core/CodeIgniter.php` +* Update `/bonfire/codeigniter/core/Config.php` +* Update `/bonfire/codeigniter/core/Security.php` +* Update `/bonfire/codeigniter/helpers/captcha_helper.php` + +* Update `/bonfire/ci3/core/CodeIgniter.php` +* Update `/bonfire/ci3/core/Common.php` +* Update `/bonfire/ci3/core/Loader.php` + +* Update `/bonfire/modules/users/User_model.php` + +* Update `/tests/run.php` diff --git a/bonfire/libraries/Installer_lib.php b/bonfire/libraries/Installer_lib.php index 05ecb6258..9a593207b 100755 --- a/bonfire/libraries/Installer_lib.php +++ b/bonfire/libraries/Installer_lib.php @@ -113,11 +113,14 @@ public function checkWritable(array $filesAndFolders = array()) $data = array(); foreach ($filesAndFolders as $fileOrFolder) { // If it starts with 'public/', then that represents the web root. - // Otherwise, try to locate it from the main folder. + // Otherwise, try to locate it from the main folder. This does not use + // DIRECTORY_SEPARATOR because the string is supplied by $this->writable_folders + // or $this->writable_files. if (strpos($fileOrFolder, 'public/') === 0) { $realpath = FCPATH . preg_replace('{^public/}', '', $fileOrFolder); } else { - $realpath = str_replace('application/', '', APPPATH) . $fileOrFolder; + // Because this is APPPATH, use DIRECTORY_SEPARATOR instead of '/'. + $realpath = str_replace('application' . DIRECTORY_SEPARATOR, '', APPPATH) . $fileOrFolder; } $data[$fileOrFolder] = is_really_writable($realpath); @@ -272,7 +275,7 @@ public function test_db_connection() */ public function is_installed() { - // If 'install/installed.txt' exists, the app is installed + // If 'config/installed.txt' exists, the app is installed if (is_file(APPPATH . 'config/installed.txt')) { return true; } diff --git a/bonfire/libraries/Modules.php b/bonfire/libraries/Modules.php index 319d64af1..3bf88c779 100644 --- a/bonfire/libraries/Modules.php +++ b/bonfire/libraries/Modules.php @@ -2,10 +2,13 @@ global $CFG; -/* Get module locations from config settings, or use the default module location - * and offset +/* Get module locations from config settings. If not found, load the application + * config file. If still not found, use the default module locations and offsets. */ -is_array(Modules::$locations = $CFG->item('modules_locations')) || Modules::$locations = array( +is_array(Modules::$locations = $CFG->item('modules_locations')) || +($CFG->load('application', false, true) + && is_array(Modules::$locations = $CFG->item('modules_locations')) +) || Modules::$locations = array( realpath(APPPATH) . '/modules/' => '../../application/modules/', realpath(BFPATH) . '/modules/' => '../../bonfire/modules/', ); diff --git a/bonfire/modules/builder/language/english/builder_lang.php b/bonfire/modules/builder/language/english/builder_lang.php index 727f71468..a56cf27be 100644 --- a/bonfire/modules/builder/language/english/builder_lang.php +++ b/bonfire/modules/builder/language/english/builder_lang.php @@ -142,6 +142,7 @@ $lang['mb_roles_label'] = 'Allow for Roles:'; $lang['mb_context_migrate'] = 'Create an Application Migration?'; $lang['mb_context_submit'] = 'Create It'; +$lang['mb_context_create_intro_note'] = 'Note: The builder will not setup routing for the new context. You will usually need to add a route for the new context in /application/config/routes.php.'; // Create Module $lang['mb_module_table_not_exist'] = 'The specified table name does not exist'; @@ -176,4 +177,4 @@ $lang['mb_form_created_by_field_ph'] = 'created_by'; $lang['mb_form_modified_by_field'] = '"Modified By" field name'; $lang['mb_form_modified_by_field_ph'] = 'modified_by'; -$lang['mb_form_use_pagination'] = 'Use pagination library to create pager'; \ No newline at end of file +$lang['mb_form_use_pagination'] = 'Use pagination library to create pager'; diff --git a/bonfire/modules/builder/libraries/Modulebuilder.php b/bonfire/modules/builder/libraries/Modulebuilder.php index daef0bebf..2a3f1ee6a 100644 --- a/bonfire/modules/builder/libraries/Modulebuilder.php +++ b/bonfire/modules/builder/libraries/Modulebuilder.php @@ -690,6 +690,10 @@ private function buildView($data) break; } + if (! function_exists('strip_slashes')) { + $this->CI->load->helper('string'); + } + return $this->CI->load->view("files/view_{$view_name}", $data, true); } diff --git a/bonfire/modules/builder/views/developer/create_context.php b/bonfire/modules/builder/views/developer/create_context.php index ccb1a6c7d..9f8406823 100644 --- a/bonfire/modules/builder/views/developer/create_context.php +++ b/bonfire/modules/builder/views/developer/create_context.php @@ -1,15 +1,11 @@ - -

+

+

- +
×

- +
@@ -24,7 +20,7 @@ ?>
- +
@@ -51,7 +47,13 @@
-  ' . htmlspecialchars(lang('bf_action_cancel')), array('class' => 'btn btn-warning')); ?> +  ' . htmlspecialchars(lang('bf_action_cancel')), + array('class' => 'btn btn-warning') + ); + ?>
\ No newline at end of file diff --git a/bonfire/modules/builder/views/files/view_default.php b/bonfire/modules/builder/views/files/view_default.php index e4477308f..c7dc1b478 100644 --- a/bonfire/modules/builder/views/files/view_default.php +++ b/bonfire/modules/builder/views/files/view_default.php @@ -171,7 +171,7 @@
\" /> - + {$delete}
diff --git a/bonfire/modules/builder/views/files/view_index.php b/bonfire/modules/builder/views/files/view_index.php index e7166156e..518c30acf 100644 --- a/bonfire/modules/builder/views/files/view_index.php +++ b/bonfire/modules/builder/views/files/view_index.php @@ -50,7 +50,7 @@ else { $table_records .= " - {$primary_key_field}, {$pencil_icon} \$record->{$field_name}); ?> + {$primary_key_field}, {$pencil_icon} \$record->{$field_name}); ?> {$field_name}); ?> "; diff --git a/bonfire/modules/emailer/libraries/Emailer.php b/bonfire/modules/emailer/libraries/Emailer.php index 3393a458e..a8e22c081 100644 --- a/bonfire/modules/emailer/libraries/Emailer.php +++ b/bonfire/modules/emailer/libraries/Emailer.php @@ -3,12 +3,13 @@ /** * Bonfire * - * An open source project to allow developers get a jumpstart their development of CodeIgniter applications + * An open source project to allow developers to jumpstart their development of + * CodeIgniter applications. * * @package Bonfire * @author Bonfire Dev Team - * @copyright Copyright (c) 2011 - 2014, Bonfire Dev Team - * @license http://opensource.org/licenses/MIT + * @copyright Copyright (c) 2011 - 2015, Bonfire Dev Team + * @license http://opensource.org/licenses/MIT The MIT License. * @link http://cibonfire.com * @since Version 1.0 * @filesource @@ -32,9 +33,9 @@ * attempted if it called send_email to handle it), the code to send the email * shouldn't be completely separate for these two methods, either. * - * @package Bonfire\Modules\Emailer\Libraries\Emailer - * @author Bonfire Dev Team - * @link http://cibonfire.com/docs/guides + * @package Bonfire\Modules\Emailer\Libraries\Emailer + * @author Bonfire Dev Team + * @link https://github.com/ci-bonfire/Bonfire/blob/develop/bonfire/modules/emailer/docs/developer/index.md */ class Emailer { @@ -82,6 +83,9 @@ class Emailer public function __construct() { $this->ci =& get_instance(); + + // Make sure the emailer_ lang entries are available. + $this->ci->lang->load('emailer/emailer'); } /** diff --git a/bonfire/modules/roles/controllers/Settings.php b/bonfire/modules/roles/controllers/Settings.php index 6d588fe98..1113edf27 100644 --- a/bonfire/modules/roles/controllers/Settings.php +++ b/bonfire/modules/roles/controllers/Settings.php @@ -7,8 +7,8 @@ * * @package Bonfire * @author Bonfire Dev Team - * @copyright Copyright (c) 2011 - 2014, Bonfire Dev Team - * @license http://opensource.org/licenses/MIT + * @copyright Copyright (c) 2011 - 2015, Bonfire Dev Team + * @license http://opensource.org/licenses/MIT The MIT License * @link http://cibonfire.com * @since Version 1.0 * @filesource @@ -22,7 +22,6 @@ * @package Bonfire\Modules\Roles\Controllers\Settings * @author Bonfire Dev Team * @link http://cibonfire.com/docs/bonfire/roles_and_permissions - * */ class Settings extends Admin_Controller { @@ -263,6 +262,8 @@ private function saveRole($type = 'insert', $id = 0) $id = $this->role_model->insert($data); $return = is_numeric($id); } elseif ($type == 'update') { + // Grab the name of the role being updated. + $current_name = $this->role_model->find($id)->role_name; $return = $this->role_model->update($id, $data); } @@ -277,15 +278,13 @@ private function saveRole($type = 'insert', $id = 0) } // Add a new management permission for the role. - $new_perm_name = 'Permissions.' . ucwords($roleName) . '.Manage'; + $add_perm = array( + 'name' => 'Permissions.' . ucwords($roleName) . '.Manage', + 'description' => "To manage the access control permissions for the {$roleName} role.", + 'status' => 'active' + ); if ($type == 'insert') { - $add_perm = array( - 'name' => $new_perm_name, - 'description' => "To manage the access control permissions for the {$roleName} role.", - 'status' => 'active' - ); - $permissionId = $this->permission_model->insert($add_perm); if (! $permissionId) { @@ -315,18 +314,12 @@ private function saveRole($type = 'insert', $id = 0) $this->form_validation->reset_validation(); $this->role_permission_model->insert_batch($rolePermissions); } - } else { - // Update - // - // Grab the name of the role being updated. - $current_name = $this->role_model->find($id)->role_name; - + } elseif ($type == 'update') { // Update the permission name. - $this->permission_model->update_where( - 'name', - 'Permissions.' . ucwords($current_name) . '.Manage', - array('name' => $new_perm_name) - ); + $currentPermission = $this->permission_model->find_by('name', 'Permissions.' . ucwords($current_name) . '.Manage'); + $permissionKey = $this->permission_model->get_key(); + $add_perm['status'] = $currentPermission->status; + $this->permission_model->update($currentPermission->{$permissionKey}, $add_perm); } // Reset validation so the role_permissions model can use it. diff --git a/bonfire/modules/roles/views/settings/role_form.php b/bonfire/modules/roles/views/settings/role_form.php index 4d346fce2..82201d386 100644 --- a/bonfire/modules/roles/views/settings/role_form.php +++ b/bonfire/modules/roles/views/settings/role_form.php @@ -11,6 +11,7 @@ uri->uri_string(), 'class="form-horizontal"'); ?>
+
diff --git a/bonfire/modules/settings/controllers/Settings.php b/bonfire/modules/settings/controllers/Settings.php index 4662e38c4..a9aff45ad 100644 --- a/bonfire/modules/settings/controllers/Settings.php +++ b/bonfire/modules/settings/controllers/Settings.php @@ -149,12 +149,9 @@ private function saveSettings($extended_settings = array()) array('name' => 'auth.name_change_frequency', 'value' => $this->input->post('name_change_frequency')), array('name' => 'auth.name_change_limit', 'value' => $this->input->post('name_change_limit')), array('name' => 'auth.password_min_length', 'value' => $this->input->post('password_min_length')), - array('name' => 'auth.password_force_numbers', 'value' => $this->input->post('password_force_numbers')), - array('name' => 'auth.password_force_symbols', 'value' => $this->input->post('password_force_symbols')), - array( - 'name' => 'auth.password_force_mixed_case', - 'value' => $this->input->post('password_force_mixed_case') - ), + array('name' => 'auth.password_force_numbers', 'value' => $this->input->post('password_force_numbers') ? 1 : 0), + array('name' => 'auth.password_force_symbols', 'value' => $this->input->post('password_force_symbols') ? 1 : 0), + array('name' => 'auth.password_force_mixed_case', 'value' => $this->input->post('password_force_mixed_case') ? 1 : 0), array('name' => 'auth.password_show_labels', 'value' => $this->input->post('password_show_labels') ? 1 : 0), array('name' => 'password_iterations', 'value' => $this->input->post('password_iterations')), diff --git a/bonfire/modules/ui/libraries/Contexts.php b/bonfire/modules/ui/libraries/Contexts.php index f7622986d..b1b588207 100644 --- a/bonfire/modules/ui/libraries/Contexts.php +++ b/bonfire/modules/ui/libraries/Contexts.php @@ -250,7 +250,7 @@ public static function render_menu($mode = 'text', $order_by = 'normal', $top_le self::$parent_class . ' ' . check_class($context, true), site_url(self::$site_area . "/{$context}"), "tb_{$context}", - self::$templateContextMenuAnchorClass, + $top_level_only ? '' : self::$templateContextMenuAnchorClass, $title, str_replace('{dataId}', $context, self::$templateContextMenuExtra), $navTitle, diff --git a/bonfire/modules/users/models/User_model.php b/bonfire/modules/users/models/User_model.php index 51b5285a0..bdecf6fd8 100644 --- a/bonfire/modules/users/models/User_model.php +++ b/bonfire/modules/users/models/User_model.php @@ -7,8 +7,8 @@ * * @package Bonfire * @author Bonfire Dev Team - * @copyright Copyright (c) 2011 - 2015, Bonfire Dev Team - * @license http://opensource.org/licenses/MIT + * @copyright Copyright (c) 2011 - 2016, Bonfire Dev Team + * @license http://opensource.org/licenses/MIT The MIT License * @link http://cibonfire.com * @since Version 1.0 * @filesource @@ -34,16 +34,16 @@ class User_model extends BF_Model /** @var string Name of the roles table. */ protected $roles_table = 'roles'; - /** @var boolean Use soft deletes or not. */ + /** @var bool Use soft deletes or not. */ protected $soft_deletes = true; /** @var string The date format to use. */ protected $date_format = 'datetime'; - /** @var boolean Set the modified time automatically. */ + /** @var bool Set the modified time automatically. */ protected $set_modified = false; - /** @var boolean Skip the validation. */ + /** @var bool Skip the validation. */ protected $skip_validation = true; /** @var array Validation rules. */ @@ -90,7 +90,7 @@ class User_model extends BF_Model ), ); - /** @var Array Additional validation rules only used on insert. */ + /** @var array Additional validation rules only used on insert. */ protected $insert_validation_rules = array( array( 'field' => 'password', @@ -147,10 +147,10 @@ public function __construct() /** * Count the users in the system. * - * @param boolean $get_deleted If true, count users which have been deleted, - * else count users which have not been deleted. + * @param bool $get_deleted If true, count users which have been deleted, else + * count users which have not been deleted. * - * @return integer The number of users found. + * @return int The number of users found. */ public function count_all($get_deleted = false) { @@ -167,11 +167,11 @@ public function count_all($get_deleted = false) /** * Perform a standard delete, but also allow a record to be purged. * - * @param integer $id The ID of the user to delete. - * @param boolean $purge If true, the account will be purged from the system. + * @param int $id The ID of the user to delete. + * @param bool $purge If true, the account will be purged from the system. * If false, performs a standard delete (with soft-deletes enabled). * - * @return boolean True on success, else false. + * @return bool True on success, else false. */ public function delete($id = 0, $purge = false) { @@ -192,9 +192,9 @@ public function delete($id = 0, $purge = false) /** * Find a user's record and role information. * - * @param integer $id The user's ID. + * @param int $id The user's ID. * - * @return boolean|object An object with the user's information. + * @return bool|object An object with the user's information. */ public function find($id = null) { @@ -206,7 +206,7 @@ public function find($id = null) /** * Find all user records and the associated role information. * - * @return boolean An array of objects with each user's information. + * @return bool|array An array of objects with each user's information. */ public function find_all() { @@ -223,7 +223,7 @@ public function find_all() * @param string $value The value to search for. * @param string $type The type of where clause to create ('and' or 'or'). * - * @return boolean|object An object with the user's info, or false on failure. + * @return bool|object An object with the user's info, or false on failure. */ public function find_by($field = null, $value = null, $type = 'and') { @@ -240,7 +240,7 @@ public function find_by($field = null, $value = null, $type = 'and') * 'email' or 'username' must be unique. If 'role_id' is not included, the default * role from the Roles model will be assigned. * - * @return boolean|integer The ID of the new user on success, else false. + * @return bool|int The ID of the new user on success, else false. */ public function insert($data = array()) { @@ -284,10 +284,10 @@ public function insert($data = array()) * - Generate a new password/hash if both password and pass_confirm are provided. * - Store the country code. * - * @param integer $id The user's ID. + * @param int $id The user's ID. * @param array $data An array of key/value pairs to update for the user. * - * @return boolean True if the update succeeded, null on invalid $id, or false + * @return bool True if the update succeeded, null on invalid $id, or false * on failure. */ public function update($id = null, $data = array()) @@ -395,15 +395,15 @@ public function prep_data($post_data) /** * Count the number of users that belong to each role. * - * @return boolean|array An array of objects with the name of each role and + * @return bool|array An array of objects with the name of each role and * the number of users in that role, else false. */ public function count_by_roles() { $this->db->select(array("{$this->roles_table}.role_name", 'count(1) as count')) - ->from($this->table_name) - ->join($this->roles_table, "{$this->roles_table}.role_id = {$this->table_name}.role_id", 'left') - ->group_by("{$this->roles_table}.role_name"); + ->from($this->table_name) + ->join($this->roles_table, "{$this->roles_table}.role_id = {$this->table_name}.role_id", 'left') + ->group_by("{$this->roles_table}.role_name"); $query = $this->db->get(); if ($query->num_rows()) { @@ -416,10 +416,10 @@ public function count_by_roles() /** * Update all users with the current role to have the default role. * - * @param integer $current_role The ID of the role of users which will be set + * @param int $current_role The ID of the role of users which will be set * to the default role. * - * @return boolean True on successful update, else false. + * @return bool True on successful update, else false. */ public function set_to_default_role($current_role) { @@ -451,9 +451,9 @@ public function set_to_default_role($current_role) * Flag one or more user accounts to require a password reset on the user's * next login. * - * @param integer $user_id The ID of the user to flag for password reset. + * @param int $user_id The ID of the user to flag for password reset. * - * @return boolean True if the account was updated successfully, else false. + * @return bool True if the account was updated successfully, else false. */ public function force_password_reset($user_id = null) { @@ -467,10 +467,12 @@ public function force_password_reset($user_id = null) /** * Generates a new password hash for the given password. * - * @param string $old The password to hash. - * @param integer $iterations The number of iterations to use in generating the hash + * @param string $old The password to hash. + * @param int $iterations The number of iterations to use when generating + * the hash. * - * @return array An array with the hashed password and the number of iterations, or false + * @return array An array with the hashed password and the number of iterations, + * or false. */ public function hash_password($old = '', $iterations = 0) { @@ -522,8 +524,8 @@ public function password_hints() /** * Retrieve all meta values defined for a user. * - * @param integer $user_id The ID of the user for which the meta will be retrieved. - * @param array $fields The meta_key names to retrieve. + * @param int $user_id The ID of the user for which the meta will be retrieved. + * @param array $fields The meta_key names to retrieve. * * @return stdClass An object with the key/value pairs, or an empty object. */ @@ -541,7 +543,7 @@ public function find_meta_for($user_id = null, $fields = null) } $query = $this->db->where('user_id', $user_id) - ->get($this->meta_table); + ->get($this->meta_table); if (! $query->num_rows()) { return new stdClass(); } @@ -558,9 +560,9 @@ public function find_meta_for($user_id = null, $fields = null) /** * Locate a single user and the user's meta information. * - * @param integer $user_id The ID of the user to fetch. + * @param int $user_id The ID of the user to fetch. * - * @return boolean|object An object with the user's profile and meta information, + * @return bool|object An object with the user's profile and meta information, * or false on failure. */ public function find_user_and_meta($user_id = null) @@ -601,10 +603,10 @@ public function find_user_and_meta($user_id = null) * ); * $this->user_model->save_meta_for($user_id, $data); * - * @param integer $user_id The ID of the user for which to save the meta data. - * @param array $data An array of key/value pairs to save. + * @param int $user_id The ID of the user for which to save the meta data. + * @param array $data An array of key/value pairs to save. * - * @return boolean True on success, else false. + * @return bool True on success, else false. */ public function save_meta_for($user_id = null, $data = array()) { @@ -634,7 +636,7 @@ public function save_meta_for($user_id = null, $data = array()) // Determine whether the data needs to be updated or inserted. $query = $this->db->where($where) - ->get($this->meta_table); + ->get($this->meta_table); if ($query->num_rows()) { $result = $this->db->update($this->meta_table, $obj, $where); } else { @@ -647,11 +649,7 @@ public function save_meta_for($user_id = null, $data = array()) } } - if ($successCount == count($data)) { - return true; - } - - return false; + return $successCount == count($data); } //-------------------------------------------------------------------------- @@ -679,8 +677,8 @@ public function activate($user_id, $code, $leave_inactive = false) } $query = $this->db->select('id') - ->where('activate_hash', $code) - ->get($this->table_name); + ->where('activate_hash', $code) + ->get($this->table_name); if ($query->num_rows() !== 1) { $this->error = lang('us_err_no_matching_code'); @@ -747,9 +745,9 @@ public function admin_activation($user_id = false) } $query = $this->db->select('id') - ->where('id', $user_id) - ->limit(1) - ->get($this->table_name); + ->where('id', $user_id) + ->limit(1) + ->get($this->table_name); if ($query->num_rows() !== 1) { $this->error = lang('us_err_no_matching_id'); @@ -763,7 +761,7 @@ public function admin_activation($user_id = false) return $result->id; } - $this->error = lang('us_err_user_is_active'); + $this->error = lang('us_err_user_is_active'); return false; } @@ -772,7 +770,7 @@ public function admin_activation($user_id = false) * * @param int $user_id The user ID to deactivate. * - * @return boolean True on success, false on error. + * @return bool True on success, false on error. */ public function admin_deactivation($user_id = false) { @@ -781,11 +779,11 @@ public function admin_deactivation($user_id = false) return false; } - if ($this->deactivate($user_id, 'id', false)) { + if ($this->deactivate($user_id, false)) { return $user_id; } - $this->error = lang('us_err_user_is_inactive'); + $this->error = lang('us_err_user_is_inactive'); return false; } @@ -803,9 +801,9 @@ public function count_inactive_users() /** * Configure activation for the given user based on current user_activation_method. * - * @param number $user_id User's ID. + * @param int $user_id User's ID. * - * @return array A 'message' (string) and 'error' (boolean, true if an error + * @return array A 'message' (string) and 'error' (bool, true if an error * occurred sending the activation email). */ public function set_activation($user_id) @@ -814,14 +812,14 @@ public function set_activation($user_id) $activation_method = $this->settings_lib->item('auth.user_activation_method'); // Prepare user messaging vars - $emailMsgData = array(); - $emailView = ''; - $subject = ''; - $email_mess = ''; - $message = lang('us_email_thank_you'); - $type = 'success'; - $site_title = $this->settings_lib->item('site.title'); - $error = false; + $emailMsgData = array(); + $emailView = ''; + $subject = ''; + $email_mess = ''; + $message = lang('us_email_thank_you'); + $type = 'success'; + $site_title = $this->settings_lib->item('site.title'); + $error = false; $ccAdmin = false; switch ($activation_method) { @@ -835,7 +833,7 @@ public function set_activation($user_id) ); $emailView = '_emails/activated'; - $message .= lang('us_account_active_login'); + $message .= lang('us_account_active_login'); $emailMsgData = array( 'title' => $site_title, @@ -845,13 +843,13 @@ public function set_activation($user_id) case 1: // Email Activiation. // Run the account deactivate to assure everything is set correctly. - $activation_code = $this->deactivate($user_id); + $activation_code = $this->deactivate($user_id); // Create the link to activate membership $activate_link = site_url("activate/{$user_id}"); - $subject = lang('us_email_subj_activate'); - $emailView = '_emails/activate'; - $message .= lang('us_check_activate_email'); + $subject = lang('us_email_subj_activate'); + $emailView = '_emails/activate'; + $message .= lang('us_check_activate_email'); $emailMsgData = array( 'title' => $site_title, @@ -862,9 +860,9 @@ public function set_activation($user_id) case 2: // Admin Activation. $ccAdmin = true; - $subject = lang('us_email_subj_pending'); - $emailView = '_emails/pending'; - $message .= lang('us_admin_approval_pending'); + $subject = lang('us_email_subj_pending'); + $emailView = '_emails/pending'; + $message .= lang('us_admin_approval_pending'); $emailMsgData = array( 'title' => $site_title, @@ -877,9 +875,9 @@ public function set_activation($user_id) // Now send the email $this->load->library('emailer/emailer'); $data = array( - 'to' => $this->find($user_id)->email, - 'subject' => $subject, - 'message' => $email_mess, + 'to' => $this->find($user_id)->email, + 'subject' => $subject, + 'message' => $email_mess, ); if ($this->emailer->send($data)) { @@ -900,8 +898,8 @@ public function set_activation($user_id) } } else { // If the message was not sent successfully, set an error message. - $message .= lang('us_err_no_email') . $this->emailer->error; - $error = true; + $message .= lang('us_err_no_email') . $this->emailer->error; + $error = true; } return array('message' => $message, 'error' => $error); @@ -914,14 +912,14 @@ public function set_activation($user_id) /** * Return the most recent login attempts. * - * @param integer $limit The maximum number of results to return. + * @param int $limit The maximum number of results to return. * - * @return boolean|array An array of objects with the login attempts, or false. + * @return bool|array An array of objects with the login attempts, or false. */ public function get_login_attempts($limit = 15) { $this->db->limit($limit) - ->order_by('login', 'desc'); + ->order_by('login', 'desc'); $query = $this->db->get('login_attempts'); if ($query->num_rows()) { @@ -951,4 +949,3 @@ protected function preFind() ); } } -//end User_model diff --git a/bonfire/modules/users/views/user_meta.php b/bonfire/modules/users/views/user_meta.php index 332a1ba07..961adda74 100644 --- a/bonfire/modules/users/views/user_meta.php +++ b/bonfire/modules/users/views/user_meta.php @@ -28,7 +28,7 @@ echo form_dropdown( $field['form_detail']['settings'], $field['form_detail']['options'], - set_value($field['name'], isset($user->$field['name']) ? $user->$field['name'] : ''), + set_value($field['name'], isset($user->{$field['name']}) ? $user->{$field['name']} : ''), $field['label'] ); elseif ($field['form_detail']['type'] == 'checkbox') : @@ -42,7 +42,7 @@ $field['form_detail']['value'], $field['form_detail']['value'] == set_value( $field['name'], - isset($user->$field['name']) ? $user->$field['name'] : '' + isset($user->{$field['name']}) ? $user->{$field['name']} : '' ) ); ?> @@ -53,7 +53,7 @@ && is_callable('state_select') ) : $stateFieldId = $field['name']; - $stateValue = isset($user->$field['name']) ? $user->$field['name'] : $defaultState; + $stateValue = isset($user->{$field['name']}) ? $user->{$field['name']} : $defaultState; ?>
@@ -74,14 +74,14 @@ && is_callable('country_select') ) : $countryFieldId = $field['name']; - $countryValue = isset($user->$field['name']) ? $user->$field['name'] : $defaultCountry; + $countryValue = isset($user->{$field['name']}) ? $user->{$field['name']} : $defaultCountry; ?>
$field['name']) ? $user->$field['name'] : $defaultCountry), + set_value($field['name'], isset($user->{$field['name']}) ? $user->{$field['name']} : $defaultCountry), $defaultCountry, $field['name'], 'span6 chzn-select' @@ -95,7 +95,7 @@ if (is_callable($form_method)) { echo $form_method( $field['form_detail']['settings'], - set_value($field['name'], isset($user->$field['name']) ? $user->$field['name'] : ''), + set_value($field['name'], isset($user->{$field['name']}) ? $user->{$field['name']} : ''), $field['label'] ); } diff --git a/composer.json b/composer.json index 187c2a641..cd7be8891 100644 --- a/composer.json +++ b/composer.json @@ -1,7 +1,7 @@ { "name": "ci-bonfire/bonfire", "description": "Kickstart your CodeIgniter-based web application development.", - "version": "0.7.1-dev", + "version": "0.7.8", "type": "project", "homepage": "http://cibonfire.com", "license": "MIT", @@ -14,7 +14,7 @@ { "name": "Lonnie Ezell", "email": "lonnieje@gmail.com", - "homepage": "lonnieezell.com", + "homepage": "http://lonnieezell.com", "role": "Project Starter and Lead" } ], @@ -26,4 +26,4 @@ "require": { "php": ">=5.3.0" } -} \ No newline at end of file +} diff --git a/tests/run.php b/tests/run.php index 98cf611f2..f2568112c 100755 --- a/tests/run.php +++ b/tests/run.php @@ -341,6 +341,9 @@ function discover_tests($start_folder=null, $ignore_onlys=false) { foreach ($folders as $folder) { + // remove trailing backslash + $folder = rtrim($folder, DIRECTORY_SEPARATOR); + // Folders get ran back through this function // and will return an array of valid files. // Merge this array with ours and call it good.