diff --git a/application/config/autoload.php b/application/config/autoload.php index 7baafdf2e..562be354e 100644 --- a/application/config/autoload.php +++ b/application/config/autoload.php @@ -62,7 +62,7 @@ | $autoload['libraries'] = array('user_agent' => 'ua'); */ -$autoload['libraries'] = array('database', 'session'); +$autoload['libraries'] = array('database'); /* diff --git a/application/config/constants.php b/application/config/constants.php index 2c813ced6..ca94609a4 100644 --- a/application/config/constants.php +++ b/application/config/constants.php @@ -93,7 +93,7 @@ // Bonfire-specific Constants // ----------------------------------------------------------------------------- -define('BONFIRE_VERSION', 'v0.7.2'); +define('BONFIRE_VERSION', 'v0.7.3'); // ----------------------------------------------------------------------------- // The 'App Area' allows you to specify the base folder used for all of the contexts diff --git a/application/core/Authenticated_Controller.php b/application/core/Authenticated_Controller.php index 179db7df9..6d4ebea08 100644 --- a/application/core/Authenticated_Controller.php +++ b/application/core/Authenticated_Controller.php @@ -1,45 +1,38 @@ -autoload['helpers'][] = 'form'; + $this->autoload['libraries'][] = 'Template'; + $this->autoload['libraries'][] = 'Assets'; + $this->autoload['libraries'][] = 'form_validation'; - /** - * Class constructor setup login restriction and load various libraries - * - */ - public function __construct() - { - $this->autoload['helpers'][] = 'form'; - $this->autoload['libraries'][] = 'Template'; - $this->autoload['libraries'][] = 'Assets'; - $this->autoload['libraries'][] = 'form_validation'; - - parent::__construct(); - - $this->form_validation->set_error_delimiters('', ''); - - }//end construct() - - //-------------------------------------------------------------------- + parent::__construct(); + $this->form_validation->CI =& $this; + $this->form_validation->set_error_delimiters('', ''); + } } - -/* End of file Authenticated_Controller.php */ -/* Location: ./application/core/Authenticated_Controller.php */ \ No newline at end of file diff --git a/application/hooks/App_hooks.php b/application/hooks/App_hooks.php index c9e539093..a4430f995 100644 --- a/application/hooks/App_hooks.php +++ b/application/hooks/App_hooks.php @@ -7,7 +7,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 * @link http://cibonfire.com * @since Version 1.0 @@ -32,6 +32,8 @@ class App_hooks '/users/logout', ); + protected $isInstalled = false; + /** * @var object The CodeIgniter core object. */ @@ -60,6 +62,15 @@ class App_hooks public function __construct() { $this->ci =& get_instance(); + + if (is_object($this->ci)) { + $this->isInstalled = $this->ci->config->item('bonfire.installed'); + if (! $this->isInstalled) { + // Is Bonfire installed? + $this->ci->load->library('installer_lib'); + $this->isInstalled = $this->ci->installer_lib->is_installed(); + } + } } /** @@ -144,14 +155,11 @@ public function checkSiteStatus() public function prepRedirect() { if (! class_exists('CI_Session', false)) { - if (substr(CI_VERSION, 0, 1) == '2') { - $this->ci->load->library('session'); - } else { - $this->ci->load->driver('session'); - } + $this->ci->load->library('session'); } - if (! in_array($this->ci->uri->ruri_string(), $this->ignore_pages)) { + $ruriString = '/' . ltrim(str_replace($this->ci->router->directory, '', $this->ci->uri->ruri_string()), '/'); + if (! in_array($ruriString, $this->ignore_pages)) { $this->ci->session->set_userdata('previous_page', current_url()); } } @@ -166,6 +174,10 @@ public function prepRedirect() */ public function saveRequested() { + if (! $this->isInstalled) { + return; + } + // If the CI_Session class is not loaded, this might be a controller that // doesn't extend any of Bonfire's controllers. In that case, try to do // this the old fashioned way and add it straight to the session. @@ -173,11 +185,7 @@ public function saveRequested() if (! class_exists('CI_Session', false)) { if (is_object(get_instance())) { // If an instance is available, just load the session lib. - if (substr(CI_VERSION, 0, 1) == '2') { - $this->ci->load->library('session'); - } else { - $this->ci->load->driver('session'); - } + $this->ci->load->library('session'); } elseif (get_instance() === null) { // If an instance is not available... @@ -208,8 +216,13 @@ public function saveRequested() // Either the session library was available all along or it has been loaded, // so determine whether the current URL is in the ignore_pages array and, // if it is not, set it as the requested page in the session. + // + // Output of uri->ruri_string() is considerably different in CI 3 when using + // the BF_Router, so the following normalizes the output for the comparison + // with $this->ignore_pages. - if (! in_array($this->ci->uri->ruri_string(), $this->ignore_pages)) { + $ruriString = '/' . ltrim(str_replace($this->ci->router->directory, '', $this->ci->uri->ruri_string()), '/'); + if (! in_array($ruriString, $this->ignore_pages)) { $this->ci->session->set_userdata('requested_page', current_url()); } } diff --git a/application/language/english/bf_form_validation_lang.php b/application/language/english/bf_form_validation_lang.php new file mode 100644 index 000000000..9101ab3c7 --- /dev/null +++ b/application/language/english/bf_form_validation_lang.php @@ -0,0 +1,32 @@ +config['base_url'] == '') { - if (isset($_SERVER['HTTP_HOST'])) + // 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'])) { $base_url = (empty($_SERVER['HTTPS']) OR strtolower($_SERVER['HTTPS']) === 'off') ? 'http' : 'https'; $base_url .= '://'. $_SERVER['HTTP_HOST']; - $base_url .= str_replace(basename($_SERVER['SCRIPT_NAME']), '', $_SERVER['SCRIPT_NAME']); + $base_url .= substr($_SERVER['SCRIPT_NAME'], 0, strpos($_SERVER['SCRIPT_NAME'], basename($_SERVER['SCRIPT_FILENAME']))); } else diff --git a/bonfire/codeigniter/core/Security.php b/bonfire/codeigniter/core/Security.php old mode 100644 new mode 100755 index 244ff8dd1..4c265d4d6 --- a/bonfire/codeigniter/core/Security.php +++ b/bonfire/codeigniter/core/Security.php @@ -4,13 +4,13 @@ * * An open source application development framework for PHP 5.1.6 or newer * - * @package CodeIgniter - * @author EllisLab Dev Team - * @copyright Copyright (c) 2008 - 2014, EllisLab, Inc. - * @copyright Copyright (c) 2014 - 2015, British Columbia Institute of Technology (http://bcit.ca/) - * @license http://codeigniter.com/user_guide/license.html - * @link http://codeigniter.com - * @since Version 1.0 + * @package CodeIgniter + * @author EllisLab Dev Team + * @copyright Copyright (c) 2008 - 2014, EllisLab, Inc. + * @copyright Copyright (c) 2014 - 2015, British Columbia Institute of Technology (http://bcit.ca/) + * @license http://codeigniter.com/user_guide/license.html + * @link http://codeigniter.com + * @since Version 1.0 * @filesource */ @@ -19,855 +19,855 @@ /** * Security Class * - * @package CodeIgniter - * @subpackage Libraries - * @category Security - * @author EllisLab Dev Team - * @link http://codeigniter.com/user_guide/libraries/security.html + * @package CodeIgniter + * @subpackage Libraries + * @category Security + * @author EllisLab Dev Team + * @link http://codeigniter.com/user_guide/libraries/security.html */ class CI_Security { - /** - * Random Hash for protecting URLs - * - * @var string - * @access protected - */ - protected $_xss_hash = ''; - /** - * Random Hash for Cross Site Request Forgery Protection Cookie - * - * @var string - * @access protected - */ - protected $_csrf_hash = ''; - /** - * Expiration time for Cross Site Request Forgery Protection Cookie - * Defaults to two hours (in seconds) - * - * @var int - * @access protected - */ - protected $_csrf_expire = 7200; - /** - * Token name for Cross Site Request Forgery Protection Cookie - * - * @var string - * @access protected - */ - protected $_csrf_token_name = 'ci_csrf_token'; - /** - * Cookie name for Cross Site Request Forgery Protection Cookie - * - * @var string - * @access protected - */ - protected $_csrf_cookie_name = 'ci_csrf_token'; - /** - * List of never allowed strings - * - * @var array - * @access protected - */ - protected $_never_allowed_str = array( - 'document.cookie' => '[removed]', - 'document.write' => '[removed]', - '.parentNode' => '[removed]', - '.innerHTML' => '[removed]', - '-moz-binding' => '[removed]', - '' => '-->', - ' '<![CDATA[', - '' => '<comment>' - ); - - /* never allowed, regex replacement */ - /** - * List of never allowed regex replacement - * - * @var array - * @access protected - */ - protected $_never_allowed_regex = array( - 'javascript\s*:', - '(document|(document\.)?window)\.(location|on\w*)', - 'expression\s*(\(|&\#40;)', // CSS and IE - 'vbscript\s*:', // IE, surprise! - 'wscript\s*:', // IE - 'jscript\s*:', // IE - 'vbs\s*:', // IE - 'Redirect\s+30\d:', - "([\"'])?data\s*:[^\\1]*?base64[^\\1]*?,[^\\1]*?\\1?" - ); - - /** - * Constructor - * - * @return void - */ - public function __construct() - { - // Is CSRF protection enabled? - if (config_item('csrf_protection') === TRUE) - { - // CSRF config - foreach (array('csrf_expire', 'csrf_token_name', 'csrf_cookie_name') as $key) - { - if (FALSE !== ($val = config_item($key))) - { - $this->{'_'.$key} = $val; - } - } - - // Append application specific cookie prefix - if (config_item('cookie_prefix')) - { - $this->_csrf_cookie_name = config_item('cookie_prefix').$this->_csrf_cookie_name; - } - - // Set the CSRF hash - $this->_csrf_set_hash(); - } - - log_message('debug', "Security Class Initialized"); - } - - // -------------------------------------------------------------------- - - /** - * Verify Cross Site Request Forgery Protection - * - * @return object - */ - public function csrf_verify() - { - // If it's not a POST request we will set the CSRF cookie - if (strtoupper($_SERVER['REQUEST_METHOD']) !== 'POST') - { - return $this->csrf_set_cookie(); - } - - // Do the tokens exist in both the _POST and _COOKIE arrays? - if ( ! isset($_POST[$this->_csrf_token_name], $_COOKIE[$this->_csrf_cookie_name])) - { - $this->csrf_show_error(); - } - - // Do the tokens match? - if ($_POST[$this->_csrf_token_name] != $_COOKIE[$this->_csrf_cookie_name]) - { - $this->csrf_show_error(); - } - - // We kill this since we're done and we don't want to - // polute the _POST array - unset($_POST[$this->_csrf_token_name]); - - // Nothing should last forever - unset($_COOKIE[$this->_csrf_cookie_name]); - $this->_csrf_set_hash(); - $this->csrf_set_cookie(); - - log_message('debug', 'CSRF token verified'); - - return $this; - } - - // -------------------------------------------------------------------- - - /** - * Set Cross Site Request Forgery Protection Cookie - * - * @return object - */ - public function csrf_set_cookie() - { - $expire = time() + $this->_csrf_expire; - $secure_cookie = (config_item('cookie_secure') === TRUE) ? 1 : 0; - - if ($secure_cookie && (empty($_SERVER['HTTPS']) OR strtolower($_SERVER['HTTPS']) === 'off')) - { - return FALSE; - } - - setcookie($this->_csrf_cookie_name, $this->_csrf_hash, $expire, config_item('cookie_path'), config_item('cookie_domain'), $secure_cookie); - - log_message('debug', "CRSF cookie Set"); - - return $this; - } - - // -------------------------------------------------------------------- - - /** - * Show CSRF Error - * - * @return void - */ - public function csrf_show_error() - { - show_error('The action you have requested is not allowed.'); - } - - // -------------------------------------------------------------------- - - /** - * Get CSRF Hash - * - * Getter Method - * - * @return string self::_csrf_hash - */ - public function get_csrf_hash() - { - return $this->_csrf_hash; - } - - // -------------------------------------------------------------------- - - /** - * Get CSRF Token Name - * - * Getter Method - * - * @return string self::csrf_token_name - */ - public function get_csrf_token_name() - { - return $this->_csrf_token_name; - } - - // -------------------------------------------------------------------- - - /** - * XSS Clean - * - * Sanitizes data so that Cross Site Scripting Hacks can be - * prevented. This function does a fair amount of work but - * it is extremely thorough, designed to prevent even the - * most obscure XSS attempts. Nothing is ever 100% foolproof, - * of course, but I haven't been able to get anything passed - * the filter. - * - * Note: This function should only be used to deal with data - * upon submission. It's not something that should - * be used for general runtime processing. - * - * This function was based in part on some code and ideas I - * got from Bitflux: http://channel.bitflux.ch/wiki/XSS_Prevention - * - * To help develop this script I used this great list of - * vulnerabilities along with a few other hacks I've - * harvested from examining vulnerabilities in other programs: - * http://ha.ckers.org/xss.html - * - * @param mixed string or array - * @param bool - * @return string - */ - public function xss_clean($str, $is_image = FALSE) - { - // Is the string an array? - if (is_array($str)) - { - while (list($key) = each($str)) - { - $str[$key] = $this->xss_clean($str[$key]); - } - - return $str; - } - - //Remove Invisible Characters - $str = remove_invisible_characters($str); - - /* - * URL Decode - * - * Just in case stuff like this is submitted: - * - * Google - * - * Note: Use rawurldecode() so it does not remove plus signs - */ - do - { - $str = rawurldecode($str); - } - while (preg_match('/%[0-9a-f]{2,}/i', $str)); - - /* - * Convert character entities to ASCII - * - * This permits our tests below to work reliably. - * We only convert entities that are within tags since - * these are the ones that will pose security problems. - */ - $str = preg_replace_callback("/[^a-z0-9>]+[a-z0-9]+=([\'\"]).*?\\1/si", array($this, '_convert_attribute'), $str); - $str = preg_replace_callback('/<\w+.*/si', array($this, '_decode_entity'), $str); - - // Remove Invisible Characters Again! - $str = remove_invisible_characters($str); - - /* - * Convert all tabs to spaces - * - * This prevents strings like this: ja vascript - * NOTE: we deal with spaces between characters later. - * NOTE: preg_replace was found to be amazingly slow here on - * large blocks of data, so we use str_replace. - */ - $str = str_replace("\t", ' ', $str); - - // Capture converted string for later comparison - $converted_string = $str; - - // Remove Strings that are never allowed - $str = $this->_do_never_allowed($str); - - /* - * Makes PHP tags safe - * - * Note: XML tags are inadvertently replaced too: - * - * '), array('<?', '?>'), $str); - } - - /* - * Compact any exploded words - * - * This corrects words like: j a v a s c r i p t - * These words are compacted back to their correct state. - */ - $words = array( - 'javascript', 'expression', 'vbscript', 'jscript', 'wscript', - 'vbs', 'script', 'base64', 'applet', 'alert', 'document', - 'write', 'cookie', 'window', 'confirm', 'prompt' - ); - - foreach ($words as $word) - { - $word = implode('\s*', str_split($word)).'\s*'; - - // We only want to do this when it is followed by a non-word character - // That way valid stuff like "dealer to" does not become "dealerto" - $str = preg_replace_callback('#('.substr($word, 0, -3).')(\W)#is', array($this, '_compact_exploded_words'), $str); - } - - /* - * Remove disallowed Javascript in links or img tags - * We used to do some version comparisons and use of stripos(), - * but it is dog slow compared to these simplified non-capturing - * preg_match(), especially if the pattern exists in the string - * - * Note: It was reported that not only space characters, but all in - * the following pattern can be parsed as separators between a tag name - * and its attributes: [\d\s"\'`;,\/\=\(\x00\x0B\x09\x0C] - * ... however, remove_invisible_characters() above already strips the - * hex-encoded ones, so we'll skip them below. - */ - do - { - $original = $str; - - if (preg_match('/]+([^>]*?)(?:>|$)#si', array($this, '_js_link_removal'), $str); - } - - if (preg_match('/]*?)(?:\s?/?>|$)#si', array($this, '_js_img_removal'), $str); - } - - if (preg_match('/script|xss/i', $str)) - { - $str = preg_replace('##si', '[removed]', $str); - } - } - 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 - * - * If a tag containing any of the words in the list - * below is found, the tag gets converted to entities. - * - * 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); - - /* - * Sanitize naughty scripting elements - * - * Similar to above, only instead of looking for - * tags it looks for PHP and JavaScript commands - * that are disallowed. Rather than removing the - * code, it simply converts the parenthesis to entities - * rendering the code un-executable. - * - * For example: eval('some code') - * Becomes: eval('some code') - */ - $str = preg_replace( - '#(alert|prompt|confirm|cmd|passthru|eval|exec|expression|system|fopen|fsockopen|file|file_get_contents|readfile|unlink)(\s*)\((.*?)\)#si', - '\\1\\2(\\3)', - $str - ); - - // Final clean up - // This adds a bit of extra precaution in case - // something got through the above filters - $str = $this->_do_never_allowed($str); - - /* - * Images are Handled in a Special Way - * - Essentially, we want to know that after all of the character - * conversion is done whether any unwanted, likely XSS, code was found. - * If not, we return TRUE, as the image is clean. - * However, if the string post-conversion does not matched the - * string post-removal of XSS, then it fails, as there was unwanted XSS - * code found and removed/changed during processing. - */ - - if ($is_image === TRUE) - { - return ($str === $converted_string); - } - - log_message('debug', "XSS Filtering completed"); - return $str; - } - - // -------------------------------------------------------------------- - - /** - * Random Hash for protecting URLs - * - * @return string - */ - public function xss_hash() - { - if ($this->_xss_hash == '') - { - mt_srand(); - $this->_xss_hash = md5(time() + mt_rand(0, 1999999999)); - } - - return $this->_xss_hash; - } - - // -------------------------------------------------------------------- - - /** - * HTML Entities Decode - * - * This function is a replacement for html_entity_decode() - * - * The reason we are not using html_entity_decode() by itself is because - * while it is not technically correct to leave out the semicolon - * at the end of an entity most browsers will still interpret the entity - * correctly. html_entity_decode() does not convert entities without - * semicolons, so we are left with our own little solution here. Bummer. - * - * @param string - * @param string - * @return string - */ - public function entity_decode($str, $charset='UTF-8') - { - if (strpos($str, '&') === FALSE) - { - return $str; - } - - static $_entities; - - isset($charset) OR $charset = strtoupper(config_item('charset')); - $flag = is_php('5.4') - ? ENT_COMPAT | ENT_HTML5 - : ENT_COMPAT; - - do - { - $str_compare = $str; - - // Decode standard entities, avoiding false positives - if (preg_match_all('/\&[a-z]{2,}(?![a-z;])/i', $str, $matches)) - { - if ( ! isset($_entities)) - { - $_entities = array_map( - 'strtolower', - is_php('5.3.4') - ? get_html_translation_table(HTML_ENTITIES, $flag, $charset) - : get_html_translation_table(HTML_ENTITIES, $flag) - ); - - // If we're not on PHP 5.4+, add the possibly dangerous HTML 5 - // entities to the array manually - if ($flag === ENT_COMPAT) - { - $_entities[':'] = ':'; - $_entities['('] = '('; - $_entities[')'] = '&rpar'; - $_entities["\n"] = '&newline;'; - $_entities["\t"] = '&tab;'; - } - } - - $replace = array(); - $matches = array_unique(array_map('strtolower', $matches[0])); - for ($i = 0, $c = count($matches); $i < $c; $i++) - { - if (($char = array_search($matches[$i].';', $_entities, TRUE)) !== FALSE) - { - $replace[$matches[$i]] = $char; - } - } - - $str = str_ireplace(array_keys($replace), array_values($replace), $str); - } - - // Decode numeric & UTF16 two byte entities - $str = html_entity_decode( - preg_replace('/(&#(?:x0*[0-9a-f]{2,5}(?![0-9a-f;])|(?:0*\d{2,4}(?![0-9;]))))/iS', '$1;', $str), - $flag, - $charset - ); - } - while ($str_compare !== $str); - return $str; - } - - // -------------------------------------------------------------------- - - /** - * Filename Security - * - * @param string - * @param bool - * @return string - */ - public function sanitize_filename($str, $relative_path = FALSE) - { - $bad = array( - '../', '', '<', '>', - "'", '"', '&', '$', '#', - '{', '}', '[', ']', '=', - ';', '?', '%20', '%22', - '%3c', // < - '%253c', // < - '%3e', // > - '%0e', // > - '%28', // ( - '%29', // ) - '%2528', // ( - '%26', // & - '%24', // $ - '%3f', // ? - '%3b', // ; - '%3d' // = - ); - - if ( ! $relative_path) - { - $bad[] = './'; - $bad[] = '/'; - } - - $str = remove_invisible_characters($str, FALSE); - - do - { - $old = $str; - $str = str_replace($bad, '', $str); - } - while ($old !== $str); - - return stripslashes($str); - } - - // ---------------------------------------------------------------- - - /** - * Compact Exploded Words - * - * Callback function for xss_clean() to remove whitespace from - * things like j a v a s c r i p t - * - * @param type - * @return type - */ - protected function _compact_exploded_words($matches) - { - return preg_replace('/\s+/s', '', $matches[1]).$matches[2]; - } - - // -------------------------------------------------------------------- - - /* - * Remove Evil HTML Attributes (like evenhandlers and style) - * - * 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: - * - * - * @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 - */ - protected function _remove_evil_attributes($str, $is_image) - { - // All javascript event handlers (e.g. onload, onclick, onmouseover), style, and xmlns - $evil_attributes = array('on\w*', 'style', 'xmlns', 'formaction', 'form', 'xlink:href'); - - if ($is_image === 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)]); - } - - do { - $count = 0; - $attribs = array(); - - // find occurrences of illegal attribute strings with quotes (042 and 047 are octal quotes) - preg_match_all('/(?]*)/is', $str, $matches, PREG_SET_ORDER); - - foreach ($matches as $attr) - { - $attribs[] = preg_quote($attr[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); - } - - } - 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]); - } - - // -------------------------------------------------------------------- - - /** - * JS Link Removal - * - * Callback function for xss_clean() to sanitize links - * This limits the PCRE backtracks, making it more performance friendly - * and prevents PREG_BACKTRACK_LIMIT_ERROR from being triggered in - * PHP 5.2+ on link-heavy strings - * - * @param array - * @return string - */ - protected function _js_link_removal($match) - { - return str_replace( - $match[1], - preg_replace( - '#href=.*?(?:(?:alert|prompt|confirm)(?:\(|&\#40;)|javascript:|livescript:|mocha:|charset=|window\.|document\.|\.cookie|_filter_attributes(str_replace(array('<', '>'), '', $match[1])) - ), - $match[0] - ); - } - - // -------------------------------------------------------------------- - - /** - * JS Image Removal - * - * Callback function for xss_clean() to sanitize image tags - * This limits the PCRE backtracks, making it more performance friendly - * and prevents PREG_BACKTRACK_LIMIT_ERROR from being triggered in - * PHP 5.2+ on image tag heavy strings - * - * @param array - * @return string - */ - 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])) - ), - $match[0] - ); - } - - // -------------------------------------------------------------------- - - /** - * Attribute Conversion - * - * Used as a callback for XSS Clean - * - * @param array - * @return string - */ - protected function _convert_attribute($match) - { - return str_replace(array('>', '<', '\\'), array('>', '<', '\\\\'), $match[0]); - } - - // -------------------------------------------------------------------- - - /** - * Filter Attributes - * - * Filters tag attributes for consistency and safety - * - * @param string - * @return string - */ - protected function _filter_attributes($str) - { - $out = ''; - - if (preg_match_all('#\s*[a-z\-]+\s*=\s*(\042|\047)([^\\1]*?)\\1#is', $str, $matches)) - { - foreach ($matches[0] as $match) - { - $out .= preg_replace("#/\*.*?\*/#s", '', $match); - } - } - - return $out; - } - - // -------------------------------------------------------------------- - - /** - * HTML Entity Decode Callback - * - * Used as a callback for XSS Clean - * - * @param array - * @return string - */ - protected function _decode_entity($match) - { - // Protect GET variables in URLs - // 901119URL5918AMP18930PROTECT8198 - $match = preg_replace('|\&([a-z\_0-9\-]+)\=([a-z\_0-9\-/]+)|i', $this->xss_hash().'\\1=\\2', $match[0]); - - // Decode, then un-protect URL GET vars - return str_replace( - $this->xss_hash(), - '&', - $this->entity_decode($match, strtoupper(config_item('charset'))) - ); - } - - // ---------------------------------------------------------------------- - - /** - * Do Never Allowed - * - * A utility function for xss_clean() - * - * @param string - * @return string - */ - protected function _do_never_allowed($str) - { - $str = str_replace(array_keys($this->_never_allowed_str), $this->_never_allowed_str, $str); - - foreach ($this->_never_allowed_regex as $regex) - { - $str = preg_replace('#'.$regex.'#is', '[removed]', $str); - } - - return $str; - } - - // -------------------------------------------------------------------- - - /** - * Set Cross Site Request Forgery Protection Cookie - * - * @return string - */ - protected function _csrf_set_hash() - { - if ($this->_csrf_hash == '') - { - // If the cookie exists we will use it's value. - // We don't necessarily want to regenerate it with - // each page load since a page could contain embedded - // sub-pages causing this feature to fail - if (isset($_COOKIE[$this->_csrf_cookie_name]) && - preg_match('#^[0-9a-f]{32}$#iS', $_COOKIE[$this->_csrf_cookie_name]) === 1) - { - return $this->_csrf_hash = $_COOKIE[$this->_csrf_cookie_name]; - } - - return $this->_csrf_hash = md5(uniqid(rand(), TRUE)); - } - - return $this->_csrf_hash; - } + /** + * Random Hash for protecting URLs + * + * @var string + * @access protected + */ + protected $_xss_hash = ''; + /** + * Random Hash for Cross Site Request Forgery Protection Cookie + * + * @var string + * @access protected + */ + protected $_csrf_hash = ''; + /** + * Expiration time for Cross Site Request Forgery Protection Cookie + * Defaults to two hours (in seconds) + * + * @var int + * @access protected + */ + protected $_csrf_expire = 7200; + /** + * Token name for Cross Site Request Forgery Protection Cookie + * + * @var string + * @access protected + */ + protected $_csrf_token_name = 'ci_csrf_token'; + /** + * Cookie name for Cross Site Request Forgery Protection Cookie + * + * @var string + * @access protected + */ + protected $_csrf_cookie_name = 'ci_csrf_token'; + /** + * List of never allowed strings + * + * @var array + * @access protected + */ + protected $_never_allowed_str = array( + 'document.cookie' => '[removed]', + 'document.write' => '[removed]', + '.parentNode' => '[removed]', + '.innerHTML' => '[removed]', + '-moz-binding' => '[removed]', + '' => '-->', + ' '<![CDATA[', + '' => '<comment>' + ); + + /* never allowed, regex replacement */ + /** + * List of never allowed regex replacement + * + * @var array + * @access protected + */ + protected $_never_allowed_regex = array( + 'javascript\s*:', + '(document|(document\.)?window)\.(location|on\w*)', + 'expression\s*(\(|&\#40;)', // CSS and IE + 'vbscript\s*:', // IE, surprise! + 'wscript\s*:', // IE + 'jscript\s*:', // IE + 'vbs\s*:', // IE + 'Redirect\s+30\d:', + "([\"'])?data\s*:[^\\1]*?base64[^\\1]*?,[^\\1]*?\\1?" + ); + + /** + * Constructor + * + * @return void + */ + public function __construct() + { + // Is CSRF protection enabled? + if (config_item('csrf_protection') === TRUE) + { + // CSRF config + foreach (array('csrf_expire', 'csrf_token_name', 'csrf_cookie_name') as $key) + { + if (FALSE !== ($val = config_item($key))) + { + $this->{'_'.$key} = $val; + } + } + + // Append application specific cookie prefix + if (config_item('cookie_prefix')) + { + $this->_csrf_cookie_name = config_item('cookie_prefix').$this->_csrf_cookie_name; + } + + // Set the CSRF hash + $this->_csrf_set_hash(); + } + + log_message('debug', "Security Class Initialized"); + } + + // -------------------------------------------------------------------- + + /** + * Verify Cross Site Request Forgery Protection + * + * @return object + */ + public function csrf_verify() + { + // If it's not a POST request we will set the CSRF cookie + if (strtoupper($_SERVER['REQUEST_METHOD']) !== 'POST') + { + return $this->csrf_set_cookie(); + } + + // Do the tokens exist in both the _POST and _COOKIE arrays? + if ( ! isset($_POST[$this->_csrf_token_name], $_COOKIE[$this->_csrf_cookie_name])) + { + $this->csrf_show_error(); + } + + // Do the tokens match? + if ($_POST[$this->_csrf_token_name] != $_COOKIE[$this->_csrf_cookie_name]) + { + $this->csrf_show_error(); + } + + // We kill this since we're done and we don't want to + // polute the _POST array + unset($_POST[$this->_csrf_token_name]); + + // Nothing should last forever + unset($_COOKIE[$this->_csrf_cookie_name]); + $this->_csrf_set_hash(); + $this->csrf_set_cookie(); + + log_message('debug', 'CSRF token verified'); + + return $this; + } + + // -------------------------------------------------------------------- + + /** + * Set Cross Site Request Forgery Protection Cookie + * + * @return object + */ + public function csrf_set_cookie() + { + $expire = time() + $this->_csrf_expire; + $secure_cookie = (config_item('cookie_secure') === TRUE) ? 1 : 0; + + if ($secure_cookie && (empty($_SERVER['HTTPS']) OR strtolower($_SERVER['HTTPS']) === 'off')) + { + return FALSE; + } + + setcookie($this->_csrf_cookie_name, $this->_csrf_hash, $expire, config_item('cookie_path'), config_item('cookie_domain'), $secure_cookie); + + log_message('debug', "CRSF cookie Set"); + + return $this; + } + + // -------------------------------------------------------------------- + + /** + * Show CSRF Error + * + * @return void + */ + public function csrf_show_error() + { + show_error('The action you have requested is not allowed.'); + } + + // -------------------------------------------------------------------- + + /** + * Get CSRF Hash + * + * Getter Method + * + * @return string self::_csrf_hash + */ + public function get_csrf_hash() + { + return $this->_csrf_hash; + } + + // -------------------------------------------------------------------- + + /** + * Get CSRF Token Name + * + * Getter Method + * + * @return string self::csrf_token_name + */ + public function get_csrf_token_name() + { + return $this->_csrf_token_name; + } + + // -------------------------------------------------------------------- + + /** + * XSS Clean + * + * Sanitizes data so that Cross Site Scripting Hacks can be + * prevented. This function does a fair amount of work but + * it is extremely thorough, designed to prevent even the + * most obscure XSS attempts. Nothing is ever 100% foolproof, + * of course, but I haven't been able to get anything passed + * the filter. + * + * Note: This function should only be used to deal with data + * upon submission. It's not something that should + * be used for general runtime processing. + * + * This function was based in part on some code and ideas I + * got from Bitflux: http://channel.bitflux.ch/wiki/XSS_Prevention + * + * To help develop this script I used this great list of + * vulnerabilities along with a few other hacks I've + * harvested from examining vulnerabilities in other programs: + * http://ha.ckers.org/xss.html + * + * @param mixed string or array + * @param bool + * @return string + */ + public function xss_clean($str, $is_image = FALSE) + { + // Is the string an array? + if (is_array($str)) + { + while (list($key) = each($str)) + { + $str[$key] = $this->xss_clean($str[$key]); + } + + return $str; + } + + //Remove Invisible Characters + $str = remove_invisible_characters($str); + + /* + * URL Decode + * + * Just in case stuff like this is submitted: + * + * Google + * + * Note: Use rawurldecode() so it does not remove plus signs + */ + do + { + $str = rawurldecode($str); + } + while (preg_match('/%[0-9a-f]{2,}/i', $str)); + + /* + * Convert character entities to ASCII + * + * This permits our tests below to work reliably. + * We only convert entities that are within tags since + * these are the ones that will pose security problems. + */ + $str = preg_replace_callback("/[^a-z0-9>]+[a-z0-9]+=([\'\"]).*?\\1/si", array($this, '_convert_attribute'), $str); + $str = preg_replace_callback('/<\w+.*/si', array($this, '_decode_entity'), $str); + + // Remove Invisible Characters Again! + $str = remove_invisible_characters($str); + + /* + * Convert all tabs to spaces + * + * This prevents strings like this: ja vascript + * NOTE: we deal with spaces between characters later. + * NOTE: preg_replace was found to be amazingly slow here on + * large blocks of data, so we use str_replace. + */ + $str = str_replace("\t", ' ', $str); + + // Capture converted string for later comparison + $converted_string = $str; + + // Remove Strings that are never allowed + $str = $this->_do_never_allowed($str); + + /* + * Makes PHP tags safe + * + * Note: XML tags are inadvertently replaced too: + * + * '), array('<?', '?>'), $str); + } + + /* + * Compact any exploded words + * + * This corrects words like: j a v a s c r i p t + * These words are compacted back to their correct state. + */ + $words = array( + 'javascript', 'expression', 'vbscript', 'jscript', 'wscript', + 'vbs', 'script', 'base64', 'applet', 'alert', 'document', + 'write', 'cookie', 'window', 'confirm', 'prompt' + ); + + foreach ($words as $word) + { + $word = implode('\s*', str_split($word)).'\s*'; + + // We only want to do this when it is followed by a non-word character + // That way valid stuff like "dealer to" does not become "dealerto" + $str = preg_replace_callback('#('.substr($word, 0, -3).')(\W)#is', array($this, '_compact_exploded_words'), $str); + } + + /* + * Remove disallowed Javascript in links or img tags + * We used to do some version comparisons and use of stripos(), + * but it is dog slow compared to these simplified non-capturing + * preg_match(), especially if the pattern exists in the string + * + * Note: It was reported that not only space characters, but all in + * the following pattern can be parsed as separators between a tag name + * and its attributes: [\d\s"\'`;,\/\=\(\x00\x0B\x09\x0C] + * ... however, remove_invisible_characters() above already strips the + * hex-encoded ones, so we'll skip them below. + */ + do + { + $original = $str; + + if (preg_match('/]+([^>]*?)(?:>|$)#si', array($this, '_js_link_removal'), $str); + } + + if (preg_match('/]*?)(?:\s?/?>|$)#si', array($this, '_js_img_removal'), $str); + } + + if (preg_match('/script|xss/i', $str)) + { + $str = preg_replace('##si', '[removed]', $str); + } + } + 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 + * + * If a tag containing any of the words in the list + * below is found, the tag gets converted to entities. + * + * 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); + + /* + * Sanitize naughty scripting elements + * + * Similar to above, only instead of looking for + * tags it looks for PHP and JavaScript commands + * that are disallowed. Rather than removing the + * code, it simply converts the parenthesis to entities + * rendering the code un-executable. + * + * For example: eval('some code') + * Becomes: eval('some code') + */ + $str = preg_replace( + '#(alert|prompt|confirm|cmd|passthru|eval|exec|expression|system|fopen|fsockopen|file|file_get_contents|readfile|unlink)(\s*)\((.*?)\)#si', + '\\1\\2(\\3)', + $str + ); + + // Final clean up + // This adds a bit of extra precaution in case + // something got through the above filters + $str = $this->_do_never_allowed($str); + + /* + * Images are Handled in a Special Way + * - Essentially, we want to know that after all of the character + * conversion is done whether any unwanted, likely XSS, code was found. + * If not, we return TRUE, as the image is clean. + * However, if the string post-conversion does not matched the + * string post-removal of XSS, then it fails, as there was unwanted XSS + * code found and removed/changed during processing. + */ + + if ($is_image === TRUE) + { + return ($str === $converted_string); + } + + log_message('debug', "XSS Filtering completed"); + return $str; + } + + // -------------------------------------------------------------------- + + /** + * Random Hash for protecting URLs + * + * @return string + */ + public function xss_hash() + { + if ($this->_xss_hash == '') + { + mt_srand(); + $this->_xss_hash = md5(time() + mt_rand(0, 1999999999)); + } + + return $this->_xss_hash; + } + + // -------------------------------------------------------------------- + + /** + * HTML Entities Decode + * + * This function is a replacement for html_entity_decode() + * + * The reason we are not using html_entity_decode() by itself is because + * while it is not technically correct to leave out the semicolon + * at the end of an entity most browsers will still interpret the entity + * correctly. html_entity_decode() does not convert entities without + * semicolons, so we are left with our own little solution here. Bummer. + * + * @param string + * @param string + * @return string + */ + public function entity_decode($str, $charset='UTF-8') + { + if (strpos($str, '&') === FALSE) + { + return $str; + } + + static $_entities; + + isset($charset) OR $charset = strtoupper(config_item('charset')); + $flag = is_php('5.4') + ? ENT_COMPAT | ENT_HTML5 + : ENT_COMPAT; + + do + { + $str_compare = $str; + + // Decode standard entities, avoiding false positives + if (preg_match_all('/\&[a-z]{2,}(?![a-z;])/i', $str, $matches)) + { + if ( ! isset($_entities)) + { + $_entities = array_map( + 'strtolower', + is_php('5.3.4') + ? get_html_translation_table(HTML_ENTITIES, $flag, $charset) + : get_html_translation_table(HTML_ENTITIES, $flag) + ); + + // If we're not on PHP 5.4+, add the possibly dangerous HTML 5 + // entities to the array manually + if ($flag === ENT_COMPAT) + { + $_entities[':'] = ':'; + $_entities['('] = '('; + $_entities[')'] = ')'; + $_entities["\n"] = '&newline;'; + $_entities["\t"] = '&tab;'; + } + } + + $replace = array(); + $matches = array_unique(array_map('strtolower', $matches[0])); + foreach ($matches as &$match) + { + if (($char = array_search($match.';', $_entities, TRUE)) !== FALSE) + { + $replace[$match] = $char; + } + } + + $str = str_ireplace(array_keys($replace), array_values($replace), $str); + } + + // Decode numeric & UTF16 two byte entities + $str = html_entity_decode( + preg_replace('/(&#(?:x0*[0-9a-f]{2,5}(?![0-9a-f;])|(?:0*\d{2,4}(?![0-9;]))))/iS', '$1;', $str), + $flag, + $charset + ); + } + while ($str_compare !== $str); + return $str; + } + + // -------------------------------------------------------------------- + + /** + * Filename Security + * + * @param string + * @param bool + * @return string + */ + public function sanitize_filename($str, $relative_path = FALSE) + { + $bad = array( + '../', '', '<', '>', + "'", '"', '&', '$', '#', + '{', '}', '[', ']', '=', + ';', '?', '%20', '%22', + '%3c', // < + '%253c', // < + '%3e', // > + '%0e', // > + '%28', // ( + '%29', // ) + '%2528', // ( + '%26', // & + '%24', // $ + '%3f', // ? + '%3b', // ; + '%3d' // = + ); + + if ( ! $relative_path) + { + $bad[] = './'; + $bad[] = '/'; + } + + $str = remove_invisible_characters($str, FALSE); + + do + { + $old = $str; + $str = str_replace($bad, '', $str); + } + while ($old !== $str); + + return stripslashes($str); + } + + // ---------------------------------------------------------------- + + /** + * Compact Exploded Words + * + * Callback function for xss_clean() to remove whitespace from + * things like j a v a s c r i p t + * + * @param type + * @return type + */ + protected function _compact_exploded_words($matches) + { + return preg_replace('/\s+/s', '', $matches[1]).$matches[2]; + } + + // -------------------------------------------------------------------- + + /* + * Remove Evil HTML Attributes (like evenhandlers and style) + * + * 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: + * + * + * @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 + */ + protected function _remove_evil_attributes($str, $is_image) + { + // 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'); + + if ($is_image === 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)]); + } + + do { + $count = 0; + $attribs = array(); + + // find occurrences of illegal attribute strings with quotes (042 and 047 are octal quotes) + preg_match_all('/(?]*)/is', $str, $matches, PREG_SET_ORDER); + + foreach ($matches as $attr) + { + $attribs[] = preg_quote($attr[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); + } + + } + 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]); + } + + // -------------------------------------------------------------------- + + /** + * JS Link Removal + * + * Callback function for xss_clean() to sanitize links + * This limits the PCRE backtracks, making it more performance friendly + * and prevents PREG_BACKTRACK_LIMIT_ERROR from being triggered in + * PHP 5.2+ on link-heavy strings + * + * @param array + * @return string + */ + protected function _js_link_removal($match) + { + return str_replace( + $match[1], + preg_replace( + '#href=.*?(?:(?:alert|prompt|confirm)(?:\(|&\#40;)|javascript:|livescript:|mocha:|charset=|window\.|document\.|\.cookie|_filter_attributes(str_replace(array('<', '>'), '', $match[1])) + ), + $match[0] + ); + } + + // -------------------------------------------------------------------- + + /** + * JS Image Removal + * + * Callback function for xss_clean() to sanitize image tags + * This limits the PCRE backtracks, making it more performance friendly + * and prevents PREG_BACKTRACK_LIMIT_ERROR from being triggered in + * PHP 5.2+ on image tag heavy strings + * + * @param array + * @return string + */ + 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])) + ), + $match[0] + ); + } + + // -------------------------------------------------------------------- + + /** + * Attribute Conversion + * + * Used as a callback for XSS Clean + * + * @param array + * @return string + */ + protected function _convert_attribute($match) + { + return str_replace(array('>', '<', '\\'), array('>', '<', '\\\\'), $match[0]); + } + + // -------------------------------------------------------------------- + + /** + * Filter Attributes + * + * Filters tag attributes for consistency and safety + * + * @param string + * @return string + */ + protected function _filter_attributes($str) + { + $out = ''; + + if (preg_match_all('#\s*[a-z\-]+\s*=\s*(\042|\047)([^\\1]*?)\\1#is', $str, $matches)) + { + foreach ($matches[0] as $match) + { + $out .= preg_replace("#/\*.*?\*/#s", '', $match); + } + } + + return $out; + } + + // -------------------------------------------------------------------- + + /** + * HTML Entity Decode Callback + * + * Used as a callback for XSS Clean + * + * @param array + * @return string + */ + protected function _decode_entity($match) + { + // Protect GET variables in URLs + // 901119URL5918AMP18930PROTECT8198 + $match = preg_replace('|\&([a-z\_0-9\-]+)\=([a-z\_0-9\-/]+)|i', $this->xss_hash().'\\1=\\2', $match[0]); + + // Decode, then un-protect URL GET vars + return str_replace( + $this->xss_hash(), + '&', + $this->entity_decode($match, strtoupper(config_item('charset'))) + ); + } + + // ---------------------------------------------------------------------- + + /** + * Do Never Allowed + * + * A utility function for xss_clean() + * + * @param string + * @return string + */ + protected function _do_never_allowed($str) + { + $str = str_replace(array_keys($this->_never_allowed_str), $this->_never_allowed_str, $str); + + foreach ($this->_never_allowed_regex as $regex) + { + $str = preg_replace('#'.$regex.'#is', '[removed]', $str); + } + + return $str; + } + + // -------------------------------------------------------------------- + + /** + * Set Cross Site Request Forgery Protection Cookie + * + * @return string + */ + protected function _csrf_set_hash() + { + if ($this->_csrf_hash == '') + { + // If the cookie exists we will use it's value. + // We don't necessarily want to regenerate it with + // each page load since a page could contain embedded + // sub-pages causing this feature to fail + if (isset($_COOKIE[$this->_csrf_cookie_name]) && + preg_match('#^[0-9a-f]{32}$#iS', $_COOKIE[$this->_csrf_cookie_name]) === 1) + { + return $this->_csrf_hash = $_COOKIE[$this->_csrf_cookie_name]; + } + + return $this->_csrf_hash = md5(uniqid(rand(), TRUE)); + } + + return $this->_csrf_hash; + } } diff --git a/bonfire/controllers/Install.php b/bonfire/controllers/Install.php index 273cc9c47..0167178ea 100644 --- a/bonfire/controllers/Install.php +++ b/bonfire/controllers/Install.php @@ -1,65 +1,95 @@ lang->load('application'); + + // Make sure the template library doesn't try to use sessions. $this->load->library('template'); + Template::setSessionUse(false); + $this->load->library('assets'); $this->load->library('events'); + $this->load->helper('application'); - $this->lang->load('application'); + // Disable hooks, since they may rely on an installed environment. get_instance()->hooks->enabled = false; - } - public function index() - { + // Load the Installer library. $this->lang->load('install'); $this->load->library('installer_lib'); + } - $data = array(); - - // PHP Version Check - $data['php_min_version'] = '5.3'; - $data['php_acceptable'] = $this->installer_lib->php_acceptable($data['php_min_version']); - $data['php_version'] = $this->installer_lib->php_version; - - // Curl Enabled? - $data['curl_enabled'] = $this->installer_lib->cURL_enabled(); - - // Files/Folders writeable? - $data['folders'] = $this->installer_lib->check_folders(); - $data['files'] = $this->installer_lib->check_files(); - - Template::set($data); - + /** + * Get some basic information about the environment before installation. + * + * @return void + */ + public function index() + { if ($this->installer_lib->is_installed()) { $this->load->library('users/auth'); $this->load->library('settings/settings_lib'); } + $data = array(); + $data['curl_enabled'] = $this->installer_lib->cURL_enabled(); + $data['files'] = $this->installer_lib->check_files(); + $data['folders'] = $this->installer_lib->check_folders(); + $data['php_acceptable'] = $this->installer_lib->php_acceptable($this->minVersionPhp); + $data['php_min_version'] = $this->minVersionPhp; + $data['php_version'] = $this->installer_lib->php_version; + + Template::set($data); Template::render(); } /** - * Handles the basic installation of the migrations into the database - * if available, and displays the current status. + * Handle the basic installation of the migrations into the database, if available, + * and display the current status. * * @return void */ public function do_install() { - $this->load->library('installer_lib'); - $this->lang->load('install'); - - // Make sure we're not installed already, - // otherwise attackers could take advantage - // and recreate the admin account. + // Make sure the application is not installed already, otherwise attackers + // could take advantage and recreate the admin account. if ($this->installer_lib->is_installed()) { show_error('This application has already been installed. Cannot install again.'); } @@ -69,10 +99,8 @@ public function do_install() show_error(lang('in_need_db_settings')); } - // Run our migrations - $this->load->library('migrations/migrations'); - - if ($this->installer_lib->setup()) { + // If setup fails, it will return an error message. + if ($this->installer_lib->setup() === true) { define('BF_DID_INSTALL', true); } diff --git a/bonfire/core/BF_Loader.php b/bonfire/core/BF_Loader.php index 30fcb7b7c..3cf432e6c 100644 --- a/bonfire/core/BF_Loader.php +++ b/bonfire/core/BF_Loader.php @@ -225,6 +225,89 @@ protected function _ci_load_class($class, $params = null, $object_name = null) } } + + /** + * 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 + $searchResult = array_search(BASEPATH, $paths); + if ($searchResult !== false) { + unset($paths[$searchResult]); + } + // array_pop($paths); // APPPATH (needs to be the first path checked) + $searchResult = array_search(APPPATH, $paths); + if ($searchResult !== false) { + unset($paths[$searchResult]); + } + 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 + $myLibraryName = config_item('subclass_prefix').$library_name; + foreach (array("BF_{$library_name}", $myLibraryName) as $subclass) { + foreach ($paths as $path) { + if (file_exists($path = "{$path}libraries/{$file_path}{$subclass}.php")) { + include_once($path); + if (class_exists($subclass, false)) { + $prefix = $subclass == $myLibraryName ? config_item('subclass_prefix') : 'BF_'; + break; + } else { + log_message('debug', "{$path} exists, but does not declare {$subclass}"); + } + } + } + } + + return $this->_ci_init_library($library_name, $prefix, $params, $object_name); + } + /** * Checks for the existence of a class extension when loading a library. * diff --git a/bonfire/core/BF_Model.php b/bonfire/core/BF_Model.php index 1fe98d597..5c06528fe 100644 --- a/bonfire/core/BF_Model.php +++ b/bonfire/core/BF_Model.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 @@ -22,9 +22,9 @@ * overriden by module models. This helps to maintain a standard interface to * program to, and makes module creation faster. * - * @package Bonfire\Core\Models\BF_Model - * @author Bonfire Dev Team - * @link http://cibonfire.com/docs/bonfire/bonfire_models + * @package Bonfire\Core\Models\BF_Model + * @author Bonfire Dev Team + * @link http://cibonfire.com/docs/bonfire/bonfire_models */ class BF_Model extends CI_Model { @@ -575,6 +575,7 @@ public function update($where = null, $data = null) return true; } + $this->error = sprintf(lang('bf_model_db_error'), $this->get_db_error_message()); return false; } @@ -619,11 +620,15 @@ public function update_batch($data = null, $index = null) } $result = $this->db->update_batch($this->table_name, $data, $index); - if (empty($result)) { - return true; + + // CI 2 returns null on success, CI 3 returns the number of affected rows. + // Both return false on failure, or display the DB error message. + if ($result === false) { + $this->error = sprintf(lang('bf_model_db_error'), $this->get_db_error_message()); + return false; } - return false; + return true; } /** diff --git a/bonfire/docs/changelog.md b/bonfire/docs/changelog.md index 2225a875d..85614df8a 100644 --- a/bonfire/docs/changelog.md +++ b/bonfire/docs/changelog.md @@ -2,6 +2,49 @@ ## Under development +### 0.7.3 + +#### New Features: +* If you are not using the installer, add `$config['bonfire.installed'] = "1";` to `/application/config/application.php`. +* Added `Template::setSessionUse($useSession = true)`, deprecated `Template::$ignore_session`. Note that the parameter accepted by `setSessionUse()` would be the opposite value of that used with `$ignore_session`. +* Added `form_validation->reset_validation()` support for CI 2 (in `BF_Form_Validation`, in CI 3 the method calls the parent method, in case of any future changes). +* Added `\application\language\english\bf_form_validation_lang.php` to store custom form validation language entries. This file is automatically loaded by the `BF_Form_validation` library when calling `$this->form_validation->run()`. + +#### Closes Issues: +* #1110 `BF_Form_validation` not loaded in CI3 +* #1109 Mobule Builder not using `lang(module_field_name)` for create/edit views. +* #1108 Can't create new user using CI3 +* #1107 No model error generated for a failed update +* #1106 Settings controller displays error message on success. +* #1105 Doc searching - preg_match error when directory is encountered +* #1103 Installation using CI 3.0 fails due to use of sessions before CI 3 session table is created. +* #1033 Email sending test makes subnav bar crash + +#### Additional Changes: +* Upgraded CI to v2.2.2. +* Fixes an issue when creating new roles which caused permissions to modify the new role not to be created/added to the admin/current user. +* Fixes issues with Emailer not displaying saved settings properly. +* Fixes issues with Add/Remove Shortcuts in UI module. +* Fixes result of `BF_Model->update_batch()` when the update completed successfully in CI 3, or failed in CI 2. +* Database module: + * Fixed display of validation errors on backup. + * Added message indicating user submitted index with the separator selected in the dropdown. +* CI 3 compatibility improvements: + * Fix Runtime Notice for Users Settings: Only variables should be passed by reference. + * Don't use `$this->load->driver('session')`, and don't check for the CI version before loading the session library. + * Normalize the output of `uri->ruri_string()` before checking it in `App_hooks` (may be needed elsewhere). + * Fix loading of `BF_`-prefixed libraries when a `MY_`-prefixed library is not present. + * Don't display developer documentation for modules in the application docs. +* Installer improvements: + * Updated a number of migrations to remove session use. + * Removed session from autoload. + * `bonfire.installed` setting added to application config by the installer. + * `App_hooks` disables session use when `bonfire.installed` is not found. + +#### Known Issues: + +## Released versions + ### 0.7.2 #### New Features: @@ -66,8 +109,6 @@ #### Known Issues: -## Released versions - ### 0.7.1 #### New Features: diff --git a/bonfire/docs/template.md b/bonfire/docs/template.md index c2b2b8f89..d95c671cd 100644 --- a/bonfire/docs/template.md +++ b/bonfire/docs/template.md @@ -196,6 +196,13 @@ The optional `$default_theme` allows you to also set a default theme to use in c Sets the view to be rendered in the content block. +### setSessionUse($useSession = true) + +Enable/disable the library's use of sessions. +This is primarily used by the installer (when sessions are not likely to be available), but is also useful for testing. + +If `$useSession` is `true`, the library will use sesssions; if `false`, the library will not use sessions. + ### theme() Returns the name of the active theme. @@ -260,10 +267,12 @@ An array of named blocks and the path/filename of the view for each block. A boolean value which controls the library's output of debug messages. -### $ignore_session +### $ignore_session *Deprecated* A boolean value which disables the library's use of sessions, primarily for unit testing. +Use `setSessionUse()` instead. Note that `setSessionUse()` expects the opposite value of `$ignore_session`, so `setSessionUse(false)` is equivalent to setting `$ignore_session = true`. + ### $layout *Deprecated* The layout into which views will be rendered. diff --git a/bonfire/docs/upgrade/073.md b/bonfire/docs/upgrade/073.md new file mode 100644 index 000000000..3652907a3 --- /dev/null +++ b/bonfire/docs/upgrade/073.md @@ -0,0 +1,24 @@ +# Upgrading Bonfire + +## 0.7.2 to 0.7.3 + +1. Update/install the files in the `/bonfire` directory. +2. Update `/application/config/autoload.php` (be sure to migrate your customizations). +3. Update `/application/hooks/App_hooks.php`. +4. Add `\application\language\english\bf_form_validation_lang.php` +5. The following have been deprecated: + + + + + + + + + + + + + +
0.7.20.7.3
Template::$ignore_sessionTemplate::setSessionUse(! $ignore_session)
+6. If you are not using the installer, add `$config['bonfire.installed'] = "1";` to `/application/config/application.php`. diff --git a/bonfire/libraries/BF_Form_validation.php b/bonfire/libraries/BF_Form_validation.php index 3f12d81e3..bcdde2de0 100644 --- a/bonfire/libraries/BF_Form_validation.php +++ b/bonfire/libraries/BF_Form_validation.php @@ -8,8 +8,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 @@ -21,9 +21,9 @@ * This class extends the CodeIgniter core Form_validation library to add extra * functionality used in Bonfire. * - * @package Bonfire\Libraries\BF_Form_validation - * @author Bonfire Dev Team - * @link http://cibonfire.com/docs/guides + * @package Bonfire\Libraries\BF_Form_validation + * @author Bonfire Dev Team + * @link http://cibonfire.com/docs */ class BF_Form_validation extends CI_Form_validation { @@ -66,6 +66,32 @@ public function has_error($field = null) return ! empty($this->_field_data[$field]['error']); } + /** + * Reset validation vars + * + * Prevents subsequent validation routines from being affected by the results + * of any previous validation routine due to the CI singleton. + * + * This method can be removed when compatibility with CI 2 is no longer needed, + * as the method already exists in CI 3. + * + * @return $this + */ + public function reset_validation() + { + // Just in case the parent method changes at some point in the future. + if (substr(CI_VERSION, 0, 1) != '2') { + return parent::reset_validation(); + } + + $this->_field_data = array(); + $this->_config_rules = array(); + $this->_error_array = array(); + $this->_error_messages = array(); + $this->error_string = ''; + return $this; + } + /** * Performs the actual form validation * @@ -76,6 +102,7 @@ public function has_error($field = null) */ public function run($module = '', $group = '') { + $this->CI->lang->load('bf_form_validation'); is_object($module) && $this->CI =& $module; return parent::run($group); } @@ -327,4 +354,3 @@ public function valid_password($str) return true; } } -/* End of file : /libraries/BF_Form_validation.php */ diff --git a/bonfire/libraries/Installer_lib.php b/bonfire/libraries/Installer_lib.php index 209daa9b3..05ecb6258 100755 --- a/bonfire/libraries/Installer_lib.php +++ b/bonfire/libraries/Installer_lib.php @@ -20,7 +20,6 @@ * @author Bonfire Dev Team * @link http://cibonfire.com/docs/developer/installation */ - class Installer_lib { /** @var boolean Indicates whether the default database settings were found. */ @@ -87,6 +86,44 @@ public function __construct($config = array()) { $this->ci =& get_instance(); $this->curl_update = $this->cURL_enabled(); + $this->php_version = phpversion(); + } + + /** + * Check an array of files/folders to see if they are writable and return the + * results in a format usable in the requirements check step of the installation. + * + * Note that this only returns the data in the format expected by the Install + * controller if called via check_folders() and check_files(). Otherwise, the + * files and folders are intermingled unless they are passed as input. + * + * @param array $filesAndFolders An array of paths to files/folders to check. + * + * @return array An associative array with the path as key and boolean value + * indicating whether the path is writable. + */ + public function checkWritable(array $filesAndFolders = array()) + { + if (empty($filesAndFolders)) { + $filesAndFolders = array_merge($this->writable_files, $this->writable_folders); + } + + $this->ci->load->helper('file'); + + $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. + if (strpos($fileOrFolder, 'public/') === 0) { + $realpath = FCPATH . preg_replace('{^public/}', '', $fileOrFolder); + } else { + $realpath = str_replace('application/', '', APPPATH) . $fileOrFolder; + } + + $data[$fileOrFolder] = is_really_writable($realpath); + } + + return $data; } /** @@ -99,7 +136,6 @@ public function __construct($config = array()) */ public function php_acceptable($version = null) { - $this->php_version = phpversion(); return version_compare($this->php_version, $version, '>='); } @@ -309,23 +345,7 @@ public function check_folders($folders = null) $folders = $this->writable_folders; } - // Load the file helper - $this->ci->load->helper('file'); - - $data = array(); - foreach ($folders as $folder) { - // If it starts with 'public/', then that represents the web root. - // Otherwise, try to locate it from the main folder. - if (strpos($folder, 'public/') === 0) { - $realpath = FCPATH . preg_replace('{^public/}', '', $folder); - } else { - $realpath = str_replace('application/', '', APPPATH) . $folder; - } - - $data[$folder] = is_really_writable($realpath); - } - - return $data; + return $this->checkWritable($folders); } /** @@ -342,30 +362,14 @@ public function check_files($files = null) $files = $this->writable_files; } - // Load the file helper - $this->ci->load->helper('file'); - - $data = array(); - foreach ($files as $file) { - // If it starts with 'public/', then that represents the web root. - // Otherwise, try to locate it from the main folder. - if (strpos($file, 'public/') === 0) { - $realpath = $this->FCPATH . preg_replace('{^public/}', '', $file); - } else { - $realpath = str_replace('application/', '', APPPATH) . $file; - } - - $data[$file] = is_really_writable($realpath); - } - - return $data; + return $this->checkWritable($files); } /** - * Perform the actual installation of the database, creates the config files, + * Perform the actual installation of the database, create the config files, * and install the user account. * - * @return string|bool + * @return string|boolean True on successful installation, else an error message. */ public function setup() { @@ -473,6 +477,11 @@ public function setup() $msg = 'Installed On: ' . date('r') . "\n"; write_file($filename, $msg); + $config_array = array( + 'bonfire.installed' => true, + ); + write_config('application', $config_array, '', APPPATH); + return true; } diff --git a/bonfire/libraries/Template.php b/bonfire/libraries/Template.php index 65317adae..4ffc76781 100644 --- a/bonfire/libraries/Template.php +++ b/bonfire/libraries/Template.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 @@ -17,14 +17,14 @@ /** * Template * - * The Template class makes the creation of consistently themed web pages across your - * entire site simple and as automatic as possible. + * The Template class makes the creation of consistently themed web pages across + * an entire site simple and as automatic as possible. * - * It supports parent/child themes, controller-named automatic overrides, and more. + * Supports parent/child themes, controller-named automatic overrides, and more. * * @package Bonfire\Libraries\Template - * @author Bonfire Dev Team - * @version 3.0 + * @author Bonfire Dev Team + * @version 3.0 * @link http://cibonfire.com/docs/developer/layouts_and_views */ class Template @@ -35,15 +35,24 @@ class Template /** @var boolean Set the debug mode on the template to output messages. */ public static $debug = false; - /** @var boolean Disable Session use, primarily for unit testing. */ + /** + * Disable Session use, primarily for unit testing. + * + * @deprecated since 0.7.3 use setSessionUse(). This will likely become a protected + * property in a future version. Note that setSessionUse() expects the opposite + * value of $ignore_session, so setSessionUse(false) is equivalent to setting + * $ignore_session = true. + * + * @var boolean + */ public static $ignore_session = false; - /** + /** * @var string The layout into which views will be rendered. * * @deprecated since 0.7.1 This will become a protected property. Use setLayout() * and getLayout(). - */ + */ public static $layout; /** @var boolean When true, CI's Parser will be used to parse the views. */ @@ -60,7 +69,7 @@ class Template protected static $current_view; /** @var array Variable names and their values to be passed into the views. */ - protected static $data = array(); + protected static $data = array(); /** @var string The default theme ('template.default_theme' in the config). */ protected static $default_theme = ''; @@ -68,65 +77,65 @@ class Template /** @var string Prefix added to debug messages in the log. */ protected static $log_prefix = '[Template] '; - /** + /** * @var array Status message. * The 'type' stores the type of message. * The 'message' stores the message itself. - */ + */ protected static $message; /** @var string CI's default view path. */ - protected static $orig_view_path; + protected static $orig_view_path; /** @var array The paths to the themes. */ protected static $theme_paths = array(); /** @var {CI} An instance of the CI super object. */ - private static $ci; + private static $ci; //-------------------------------------------------------------------------- - /** - * This constructor is here purely for CI's benefit, as this is a static class. - * - * @return void - */ - public function __construct() - { - self::$ci =& get_instance(); + /** + * This constructor is here purely for CI's benefit, as this is a static class. + * + * @return void + */ + public function __construct() + { + self::$ci =& get_instance(); - self::init(); + self::init(); } - /** + /** * Grabs an instance of the CI superobject, loads the Ocular config file, and * sets our default layout. - * - * @return void - */ - public static function init() - { - // If the application config file hasn't been loaded, do it now + * + * @return void + */ + public static function init() + { + // If the application config file hasn't been loaded, do it now if (! self::$ci->config->item('template.theme_paths')) { - self::$ci->config->load('application'); - } + self::$ci->config->load('application'); + } - // Store our settings - self::$default_theme = self::$ci->config->item('template.default_theme'); + // Store our settings + self::$default_theme = self::$ci->config->item('template.default_theme'); self::$layout = self::$ci->config->item('template.default_layout'); - self::$parse_views = self::$ci->config->item('template.parse_views'); + self::$parse_views = self::$ci->config->item('template.parse_views'); self::$site_path = self::$ci->config->item('template.site_path'); self::$theme_paths = self::$ci->config->item('template.theme_paths'); log_message('debug', 'Template library loaded'); } - /** + /** * Get the name of the layout into which the views will be rendered. * * The default layout is stored in the config file as 'template.default_layout'. - * + * * @return string */ public static function getLayout() @@ -142,14 +151,30 @@ public static function getLayout() * application. * * @param string $layout The name of the layout. - * - * @return void - */ + * + * @return void + */ public static function setLayout($layout) - { + { self::$layout = $layout; } + /** + * Enable/disable the library's use of sessions. + * + * This is primarily used by the installer (when sessions are not likely to + * be available), but is also useful for testing. + * + * @param boolean $useSession If true, the library uses sessions. If false, + * the library will not use sessions. + * + * @return void + */ + public static function setSessionUse($useSession = true) + { + self::$ignore_session = ! $useSession; + } + /** * Renders the specified layout. * @@ -165,7 +190,7 @@ public static function setLayout($layout) public static function render($layout = null) { // Determine whether to override the current layout. - $layout = empty($layout) ? self::$layout : $layout; + $layout = empty($layout) ? self::$layout : $layout; // If the current view has not been set, use the current controller/method. $controller = self::$ci->router->class; @@ -175,12 +200,12 @@ public static function render($layout = null) // Override the layout if this is an AJAX request. if (self::$ci->input->is_ajax_request()) { - $layout = self::$ci->config->item('template.ajax_layout'); + $layout = self::$ci->config->item('template.ajax_layout'); // $controller is passed to load_view to set a controller-based override // of the layout, which should not be done for AJAX requests. $controller = ''; - } + } // Time to render the layout. $output = ''; @@ -190,21 +215,21 @@ public static function render($layout = null) show_error("Unable to find theme layout: {$layout}"); } - Events::trigger('after_layout_render', $output); + Events::trigger('after_layout_render', $output); - self::$ci->output->set_output($output); + self::$ci->output->set_output($output); } - /** + /** * Renders the current view into the layout. - * + * * The name of the view is usually based on the controller/action being run. * @see render(). - * - * @return string A string containing the output of the render process. - */ - public static function content() - { + * + * @return string A string containing the output of the render process. + */ + public static function content() + { self::debug_message('Current View = ' . self::$current_view); $output = ''; @@ -216,201 +241,201 @@ public static function content() $output ); - Events::trigger('after_page_render', $output); + Events::trigger('after_page_render', $output); - return $output; + return $output; } //-------------------------------------------------------------------------- - // !BLOCKS + // !BLOCKS //-------------------------------------------------------------------------- - /** - * Stores the block named $name in the blocks array for later rendering. - * The $current_view variable is the name of an existing view. If it is empty, - * your script should still function as normal. - * - * @param string $block_name The name of the block. Must match the name in the block() method. - * @param string $view_name The name of the view file to render. - * - * @return void - */ + /** + * Stores the block named $name in the blocks array for later rendering. + * The $current_view variable is the name of an existing view. If it is empty, + * your script should still function as normal. + * + * @param string $block_name The name of the block. Must match the name in the block() method. + * @param string $view_name The name of the view file to render. + * + * @return void + */ public static function set_block($block_name = '', $view_name = '') - { + { if (! empty($block_name)) { - self::$blocks[$block_name] = $view_name; - } + self::$blocks[$block_name] = $view_name; + } } - /** - * Renders a "block" to the view. - * + /** + * Renders a "block" to the view. + * * A block is a partial view contained in a view file in the application/views * folder. It can be used for sidebars, headers, footers, or any other recurring * element within a site. It is recommended to set a default when calling this * function within a layout. The default will be rendered if no methods override * the view (using the set_block() method). - * - * @param string $block_name The name of the block to render. + * + * @param string $block_name The name of the block to render. * @param string $default_view The view to render if no other view has been set * with the set_block() method. - * @param array $data An array of data to pass to the view. + * @param array $data An array of data to pass to the view. * @param bool $themed Whether we should look in the themes or standard * view locations. - * - * @return void - */ + * + * @return void + */ public static function block($block_name = '', $default_view = '', $data = array(), $themed = false) - { + { if (empty($block_name)) { - self::debug_message('No block name provided.'); - return; - } + self::debug_message('No block name provided.'); + return; + } // Use $default_view if the block has not been set. - $block_view_name = isset(self::$blocks[$block_name]) ? self::$blocks[$block_name] : $default_view; + $block_view_name = isset(self::$blocks[$block_name]) ? self::$blocks[$block_name] : $default_view; if (empty($block_view_name) && empty($default_view)) { self::debug_message("No default block provided for `{$block_name}`"); - return; - } + return; + } self::debug_message("Looking for block: {$block_view_name}."); $output = ''; self::load_view($block_view_name, $data, false, $themed, $output); - echo $output; + echo $output; } //-------------------------------------------------------------------------- - // !THEME PATHS + // !THEME PATHS //-------------------------------------------------------------------------- - /** + /** * Theme paths allow you to have multiple locations for themes to be stored. * This might be used for separating themes for different sub-applications, * or a core theme and user-submitted themes. - * - * @param string $path A new path where themes can be found. - * + * + * @param string $path A new path where themes can be found. + * * @return bool Returns true if the path already exists. Otherwise, returns * false, even if the path was successfully added... - */ + */ public static function add_theme_path($path = null) - { + { if (empty($path) || ! is_string($path)) { return false; - } + } - // Make sure the path has a '/' at the end. + // Make sure the path has a '/' at the end. if (substr($path, -1) != '/') { - $path .= '/'; - } + $path .= '/'; + } - // If the path already exists, we're done here. + // If the path already exists, we're done here. if (isset(self::$theme_paths[$path])) { return true; - } + } // Make sure the folder actually exists. if (is_dir(self::$site_path . $path)) { - array_push(self::$theme_paths, $path); + array_push(self::$theme_paths, $path); return false; - } + } self::debug_message("Cannot add theme path: '{$path}' does not exist"); return false; - } - - /** - * Remove the theme path - * - * @param string $path The path to remove from the theme paths. - * - * @return void - */ + } + + /** + * Remove the theme path + * + * @param string $path The path to remove from the theme paths. + * + * @return void + */ public static function remove_theme_path($path = null) - { + { if (empty($path) || ! is_string($path)) { - return; - } + return; + } if (isset(self::$theme_paths[$path])) { - unset(self::$theme_paths[$path]); - } + unset(self::$theme_paths[$path]); + } } - /** + /** * Stores the name of the active theme to use. This theme should be relative * to one of the 'template.theme_paths' folders. - * - * @param string $theme The name of the active theme. - * @param string $default_theme (Optional) The name of the desired default theme. - * - * @return void - */ + * + * @param string $theme The name of the active theme. + * @param string $default_theme (Optional) The name of the desired default theme. + * + * @return void + */ public static function set_theme($theme = null, $default_theme = null) - { + { if (empty($theme) || ! is_string($theme)) { - return; - } + return; + } - // Make sure a trailing slash is there + // Make sure a trailing slash is there if (substr($theme, -1) !== '/') { - $theme .= '/'; - } + $theme .= '/'; + } - self::$active_theme = $theme; + self::$active_theme = $theme; - // Default theme? + // Default theme? if (! empty($default_theme) && is_string($default_theme)) { - self::set_default_theme($default_theme); - } + self::set_default_theme($default_theme); + } } - /** + /** * Stores the name of the default theme to use. This theme should be relative * to one of the template.theme_paths folders. - * - * @param string $theme The name of the desired default theme to use. - * - * @return void - */ + * + * @param string $theme The name of the desired default theme to use. + * + * @return void + */ public static function set_default_theme($theme = null) - { + { if (empty($theme) || ! is_string($theme)) { - return; - } + return; + } - // Make sure a trailing slash is there + // Make sure a trailing slash is there if (substr($theme, -1) !== '/') { - $theme .= '/'; - } + $theme .= '/'; + } - self::$default_theme = $theme; + self::$default_theme = $theme; } - /** - * Returns the active theme. - * - * @return string The name of the active theme. - */ - public static function theme() - { + /** + * Returns the active theme. + * + * @return string The name of the active theme. + */ + public static function theme() + { return empty(self::$active_theme) ? self::$default_theme : self::$active_theme; } - /** - * Returns the full url to a file in the currently active theme. - * - * @param string $resource Path to a resource in the theme - * - * @return string The full url (including http://) to the resource. - */ + /** + * Returns the full url to a file in the currently active theme. + * + * @param string $resource Path to a resource in the theme + * + * @return string The full url (including http://) to the resource. + */ public static function theme_url($resource = '') - { - $url = base_url(); + { + $url = base_url(); // Add theme path and theme. $url .= self::$theme_paths[0] . '/' . self::theme(); @@ -418,151 +443,151 @@ public static function theme_url($resource = '') // Cleanup, just to be safe. $url = str_replace(array('//', ':/'), array('/', '://'), $url); - return $url . $resource; + return $url . $resource; } - /** - * Set the current view to render. - * - * @param string $view The name of the view file to render as content. - * - * @return void - */ + /** + * Set the current view to render. + * + * @param string $view The name of the view file to render as content. + * + * @return void + */ public static function set_view($view = null) - { + { if (empty($view) || ! is_string($view)) { - return; - } + return; + } - self::$current_view = $view; + self::$current_view = $view; } - /** - * Makes it easy to save information to be rendered within the views. - * + /** + * Makes it easy to save information to be rendered within the views. + * * This should probably be updated to clarify the intended functionality when * an array is passed into $var_name and $value is ''. * * @todo If $var_name is an array and $value != '', the else condition will * probably be problematic. - * - * @param string $var_name The name of the variable to set - * @param mixed $value The value to set it to. - * - * @return void - */ + * + * @param string $var_name The name of the variable to set + * @param mixed $value The value to set it to. + * + * @return void + */ public static function set($var_name = '', $value = '') - { + { if (is_array($var_name) && $value == '') { foreach ($var_name as $key => $val) { self::$data[$key] = $val; - } + } } else { - self::$data[$var_name] = $value; + self::$data[$var_name] = $value; } } - /** + /** * Returns a variable that has been previously set, or false if not exists. - * As of 3.0, will also return class properties. - * - * @param string $var_name The name of the data item to return. - * - * @return mixed The value of the class property or view data. - */ + * As of 3.0, will also return class properties. + * + * @param string $var_name The name of the data item to return. + * + * @return mixed The value of the class property or view data. + */ public static function get($var_name = null) - { + { if (empty($var_name)) { return false; - } + } - // First, is it a class property? + // First, is it a class property? if (isset(self::$$var_name)) { - return self::$$var_name; - } + return self::$$var_name; + } if (isset(self::$data[$var_name])) { - return self::$data[$var_name]; - } + return self::$data[$var_name]; + } return false; } - /** + /** * Enable/disable passing views through CI's Parser. - * + * * @param boolean $parse If true, the views will be parsed. * @return void - */ + */ public function parse_views($parse = false) - { - self::$parse_views = (bool) $parse; + { + self::$parse_views = (bool) $parse; } - /** - * Sets a status message (for displaying small success/error messages). - * + /** + * Sets a status message (for displaying small success/error messages). + * * This function is used in place of the session->flashdata function to allow * the message to show up without requiring a page refresh. * * @param string $message The text of the message. * @param string $type The type of message, usually added as the value of * the class attribute on the message's container. - * - * @return void - */ + * + * @return void + */ public static function set_message($message = '', $type = 'info') - { + { if (empty($message)) { return; - } + } if (! self::$ignore_session && isset(self::$ci->session)) { self::$ci->session->set_flashdata('message', "{$type}::{$message}"); - } + } self::$message = array('type' => $type, 'message' => $message); } - /** - * Displays a status message (small success/error messages). - * + /** + * Displays a status message (small success/error messages). + * * If data exists in 'message' session flashdata, that will override any other * messages. Renders the message based on the template provided in the config * file ('template.message_template'). - * - * @param string $message A string to be the message. (Optional) If included, will override any other messages in the system. - * @param string $type The class to attached to the div. (i.e. 'information', 'attention', 'error', 'success') - * - * @return string A string with the results of inserting the message into the message template. - */ + * + * @param string $message A string to be the message. (Optional) If included, will override any other messages in the system. + * @param string $type The class to attached to the div. (i.e. 'information', 'attention', 'error', 'success') + * + * @return string A string with the results of inserting the message into the message template. + */ public static function message($message = '', $type = 'information') - { - // Does session data exist? + { + // Does session data exist? if (empty($message) && ! self::$ignore_session - && class_exists('CI_Session') + && class_exists('CI_Session', false) ) { - $message = self::$ci->session->flashdata('message'); + $message = self::$ci->session->flashdata('message'); if (! empty($message)) { // Split out the message parts - $temp_message = explode('::', $message); - $type = $temp_message[0]; - $message = $temp_message[1]; + $temp_message = explode('::', $message); + $type = $temp_message[0]; + $message = $temp_message[1]; - unset($temp_message); - } + unset($temp_message); + } } // If message is empty, check the $message property. if (empty($message)) { if (empty(self::$message['message'])) { - return ''; - } + return ''; + } - $message = self::$message['message']; - $type = self::$message['type']; - } + $message = self::$message['message']; + $type = self::$message['type']; + } // Get the message template and replace the placeholders. $template = str_replace( @@ -573,27 +598,27 @@ public static function message($message = '', $type = 'information') // Clear the session data to prevent extra messages. (This was a very rare // occurence, but clearing should resolve the problem.) - if (! self::$ignore_session && class_exists('CI_Session')) { - self::$ci->session->set_flashdata('message', ''); - } + if (! self::$ignore_session && class_exists('CI_Session', false)) { + self::$ci->session->set_flashdata('message', ''); + } - return $template; + return $template; } - /** + /** * Like CodeIgniter redirect(), but uses javascript if needed to redirect out * of an ajax request. - * + * * @param string $url The url to redirect to. If not a full url, will wrap it * in site_url(). - * - * @return void - */ + * + * @return void + */ public static function redirect($url = null) - { + { if (! preg_match('#^https?://#i', $url)) { - $url = site_url($url); - } + $url = site_url($url); + } if (! self::$ci->input->is_ajax_request()) { header("Location: {$url}"); @@ -601,37 +626,37 @@ public static function redirect($url = null) // The default header specifies the content type as HTML, which requires // certain elements to be considered valid. No content is included, // so use a content type which does not require any. - header("Content-Type: text/plain"); + header("Content-Type: text/plain"); } else { // Output URL in a known location and escape it for safety. - echo '
'; + echo '
'; // Now JS can grab the URL and perform the redirect. - echo << window.location = document.getElementById('url').getAttribute('data-url'); EOF; - } + } - exit(); + exit(); } - /** + /** * Load a view based on the current themes. - * - * @param string $view The view to load. - * @param array $data An array of data elements to be made available to the views - * @param string $override The name of a view to check for first (used for controller-based layouts) - * @param bool $is_themed Whether it should check in the theme folder first. - * @param object $output A pointer to the variable to store the output of the loaded view into. - * - * @return void - */ + * + * @param string $view The view to load. + * @param array $data An array of data elements to be made available to the views + * @param string $override The name of a view to check for first (used for controller-based layouts) + * @param bool $is_themed Whether it should check in the theme folder first. + * @param object $output A pointer to the variable to store the output of the loaded view into. + * + * @return void + */ public static function load_view($view = null, $data = null, $override = '', $is_themed = true, &$output) - { + { if (empty($view)) { return ''; } @@ -640,110 +665,110 @@ public static function load_view($view = null, $data = null, $override = '', $is $data = self::$data; } - $output = ''; + $output = ''; if ($is_themed) { - // First check for the overridden file... + // First check for the overridden file... if (! empty($override)) { - $output = self::find_file($override, $data); - } + $output = self::find_file($override, $data); + } // If it wasn't found, try the standard view if (empty($output)) { - $output = self::find_file($view, $data); - } + $output = self::find_file($view, $data); + } - // Should it be parsed? + // Should it be parsed? if (self::$parse_views === true) { - if (! class_exists('CI_Parser')) { + if (! class_exists('CI_Parser', false)) { self::$ci->load->library('parser'); } $output = self::$ci->parser->parse($output, $data, true, false); } } else { - // Just a normal view (possibly from a module, though.) + // Just a normal view (possibly from a module, though.) // First check within the themes... - $output = self::find_file($view, $data); + $output = self::find_file($view, $data); // If it wasn't found, go for the default. if (empty($output)) { - self::$ci->load->_ci_view_path = self::$orig_view_path; + self::$ci->load->_ci_view_path = self::$orig_view_path; if (self::$parse_views === true) { - if (! class_exists('CI_Parser')) { - self::$ci->load->library('parser'); - } + if (! class_exists('CI_Parser', false)) { + self::$ci->load->library('parser'); + } $output = self::$ci->parser->parse($view, $data, true); } else { $output = self::$ci->load->view($view, $data, true); - } - } - self::$ci->load->_ci_view_path = self::$orig_view_path; + } + } + self::$ci->load->_ci_view_path = self::$orig_view_path; } } //-------------------------------------------------------------------------- - // !PRIVATE METHODS + // !PRIVATE METHODS //-------------------------------------------------------------------------- - /** - * Searches through the the active theme and the default theme to try to find - * a view file. If found, it returns the rendered view. - * - * @access private - * - * @param string $view The name of the view to find. - * @param array $data An array of key/value pairs to pass to the views. - * - * @return string The content of the file, if found, else empty. - */ + /** + * Searches through the the active theme and the default theme to try to find + * a view file. If found, it returns the rendered view. + * + * @access private + * + * @param string $view The name of the view to find. + * @param array $data An array of key/value pairs to pass to the views. + * + * @return string The content of the file, if found, else empty. + */ private static function find_file($view = null, $data = null) - { + { if (empty($view)) { return false; - } + } if (! empty($data)) { - $data = (array)$data; - } + $data = (array)$data; + } $view_path = ''; // The location of the file. $view_file = "{$view}.php"; // filename for the view - $active_theme_set = ! empty(self::$active_theme); // Is the active theme set? + $active_theme_set = ! empty(self::$active_theme); // Is the active theme set? // In most cases, self::$theme_paths will only include one location. // When it does not, the last will take precedence for the search. // Reverse the $theme_paths array and break the loop when the file is found. - $theme_locations = array_reverse(self::$theme_paths); + $theme_locations = array_reverse(self::$theme_paths); // Search through the theme locations. foreach ($theme_locations as $path) { $site_theme_path = self::$site_path . "{$path}/"; // First, check the active theme - $active_theme_path = $site_theme_path . self::$active_theme; + $active_theme_path = $site_theme_path . self::$active_theme; self::debug_message("[Find File] Looking for view in active theme: '{$active_theme_path}{$view_file}'"); if ($active_theme_set && is_file($active_theme_path . $view_file)) { // If the view was found, set the view path and exit the loop. - $view_path = $active_theme_path; + $view_path = $active_theme_path; self::debug_message("Found '{$view}' in Active Theme."); - break; - } + break; + } // Next, check the default theme. - $default_theme_path = $site_theme_path . self::$default_theme; + $default_theme_path = $site_theme_path . self::$default_theme; self::debug_message("[Find File] Looking for view in default theme: '{$default_theme_path}{$view_file}'"); if (is_file($default_theme_path . $view_file)) { // If the view was found, set the view path and exit the loop. - $view_path = $default_theme_path; + $view_path = $default_theme_path; self::debug_message("Found '{$view}' in Default Theme."); - break; - } - } + break; + } + } // If $view_path is empty, the view was not found. if (empty($view_path)) { @@ -753,36 +778,38 @@ private static function find_file($view = null, $data = null) // Parse or render the view based on current settings. // Clean up the view path, to be safe. - $view_path = str_replace('//', '/', $view_path); + $view_path = str_replace('//', '/', $view_path); self::debug_message("[Find File] Rendering file at: '{$view_path}{$view_file}'"); // Get the output of the view. if (self::$parse_views === true) { $data = array_merge((array) $data, self::$ci->load->_ci_cached_vars); - } + } - return self::$ci->load->_ci_load(array( - '_ci_path' => $view_path . $view_file, - '_ci_vars' => $data, - '_ci_return' => true, - )); - } + return self::$ci->load->_ci_load( + array( + '_ci_path' => $view_path . $view_file, + '_ci_vars' => $data, + '_ci_return' => true, + ) + ); + } - /** + /** * Debugging script to echo out message to the Console (if loaded) and to the * log files. * * By default it will only log the messages if self::$debug == true, but this * behaviour can be modified by passing $force as true. - * + * * @param string $message The message to log. * @param boolean $force If false, will respect self::$debug setting. If * true, will force the message to be logged. - * + * * @return void - */ + */ protected static function debug_message($message, $force = false) - { + { // Only echo the message when in debug mode. if (self::$debug) { echo $message; @@ -790,7 +817,7 @@ protected static function debug_message($message, $force = false) // Log the message in debug mode or when $force is true. if ($force || self::$debug) { - logit(self::$log_prefix . $message); + logit(self::$log_prefix . $message); } } } @@ -822,7 +849,7 @@ function theme_view($view = null, $data = null, $ignore_mobile = false) return ''; } - $output =''; + $output =''; // If allowed, try to load the mobile version of the file. if (! $ignore_mobile) { @@ -831,15 +858,15 @@ function theme_view($view = null, $data = null, $ignore_mobile = false) $ci->load->library('user_agent'); if ($ci->agent->is_mobile()) { Template::load_view("mobile_{$view}", $data, null, true, $output); - } - } + } + } // If output is empty, either mobile is ignored or no mobile file was found. if (empty($output)) { Template::load_view($view, $data, null, true, $output); - } + } - return $output; + return $output; } /** @@ -861,17 +888,17 @@ function theme_view($view = null, $data = null, $ignore_mobile = false) function check_class($item = '', $class_only = false) { if (strtolower(get_instance()->router->class) == strtolower($item)) { - return $class_only ? 'active' : 'class="active"'; - } + return $class_only ? 'active' : 'class="active"'; + } - return ''; + return ''; } /** * A simple helper method for checking menu items against the current method * (controller action) (as far as the Router knows). * - * @param string $item The name of the method to check against. Can be an array of names. + * @param string $item The name of the method to check against. Can be an array of names. * @param bool $class_only If true, will only return 'active'. If false, will return 'class="active"'. * * @return string Either 'active'/'class="active"' or an empty string. @@ -880,10 +907,10 @@ function check_method($item, $class_only = false) { $items = is_array($item) ? $item : array($item); if (in_array(get_instance()->router->fetch_method(), $items)) { - return $class_only ? 'active' : 'class="active"'; - } + return $class_only ? 'active' : 'class="active"'; + } - return ''; + return ''; } /** @@ -918,18 +945,18 @@ function check_segment($segment_num, $item, $class_only = false) */ function breadcrumb($my_segments = null, $wrap = false, $echo = true) { - $ci =& get_instance(); + $ci =& get_instance(); if (empty($my_segments) || ! is_array($my_segments)) { - if (! class_exists('CI_URI')) { - $ci->load->library('uri'); - } - $segments = $ci->uri->segment_array(); - $total = $ci->uri->total_segments(); + if (! class_exists('CI_URI', false)) { + $ci->load->library('uri'); + } + $segments = $ci->uri->segment_array(); + $total = $ci->uri->total_segments(); } else { - $segments = $my_segments; - $total = count($my_segments); - } + $segments = $my_segments; + $total = count($my_segments); + } // Are these segments in the admin section of the site? $home_link = site_url(is_array($segments) && in_array(SITE_AREA, $segments) ? SITE_AREA : ''); @@ -945,12 +972,12 @@ function breadcrumb($my_segments = null, $wrap = false, $echo = true) } else { /** @todo Use a lang() value in place of home. */ $output = "
home {$separator}"; - } + } - $url = ''; - $count = 0; + $url = ''; + $count = 0; - // URI BASED BREADCRUMB + // URI BASED BREADCRUMB if (empty($my_segments) || ! is_array($my_segments)) { foreach ($segments as $segment) { $url .= "/{$segment}"; @@ -962,18 +989,18 @@ function breadcrumb($my_segments = null, $wrap = false, $echo = true) $output .= "
  • {$currentSegment}
  • " . PHP_EOL; } else { $output .= $currentSegment . PHP_EOL; - } + } } else { $currentSegment = str_replace('_', ' ', ucfirst(mb_strtolower($segment))); if ($wrap === true) { $output .= "
  • {$currentSegment}{$separator}
  • " . PHP_EOL; } else { $output .= "{$currentSegment}{$separator}" . PHP_EOL; - } - } - } + } + } + } } else { - // USER-SUPPLIED BREADCRUMB + // USER-SUPPLIED BREADCRUMB foreach ($my_segments as $title => $uri) { $url .= "/{$uri}"; ++$count; @@ -984,26 +1011,26 @@ function breadcrumb($my_segments = null, $wrap = false, $echo = true) $output .= "
  • {$currentTitle}
  • " . PHP_EOL; } else { $output .= $currentTitle; - } + } } else { $currentTitle = str_replace('_', ' ', ucfirst(mb_strtolower($title))); if ($wrap === true) { $output .= "
  • {$currentTitle}{$separator}
  • " . PHP_EOL; } else { $output .= "{$currentTitle}{$separator}" . PHP_EOL; - } - } - } - } + } + } + } + } if ($wrap === true) { $output .= "" . PHP_EOL; - } + } if ($echo === true) { - echo $output; + echo $output; return; - } + } return $output; } diff --git a/bonfire/migrations/003_Permission_system_upgrade.php b/bonfire/migrations/003_Permission_system_upgrade.php index e5797528e..93370edf4 100644 --- a/bonfire/migrations/003_Permission_system_upgrade.php +++ b/bonfire/migrations/003_Permission_system_upgrade.php @@ -1,275 +1,262 @@ - array( - 'type' => 'TINYINT', - 'constraint' => 1, - 'default' => 0, + /**************************************************************** + * Field definitions + */ + /** + * @var array New fields to add to the Permissions table + */ + private $permissions_fields = array( + 'Site_Signin_Offline' => array( + 'type' => 'TINYINT', + 'constraint' => 1, + 'default' => 0, 'null' => false, - ), - ); + ), + ); - /** - * @var array Fields to modify in the Permissions table - */ - private $permissions_modify_fields = array( - 'Site_Statistics_View' => array( - 'name' => 'Site_Reports_View', - 'type' => 'TINYINT', - 'constraint' => 1, - 'default' => 0, + /** + * @var array Fields to modify in the Permissions table + */ + private $permissions_modify_fields = array( + 'Site_Statistics_View' => array( + 'name' => 'Site_Reports_View', + 'type' => 'TINYINT', + 'constraint' => 1, + 'default' => 0, 'null' => false, - ), - ); + ), + ); - /** - * @var array Fields to modify in the Permissions table during Uninstall - */ - private $permissions_modify_fields_down = array( - 'Site_Reports_View' => array( - 'name' => 'Site_Statistics_View', - 'type' => 'TINYINT', - 'constraint' => 1, - 'default' => 0, + /** + * @var array Fields to modify in the Permissions table during Uninstall + */ + private $permissions_modify_fields_down = array( + 'Site_Reports_View' => array( + 'name' => 'Site_Statistics_View', + 'type' => 'TINYINT', + 'constraint' => 1, + 'default' => 0, 'null' => false, - ), - ); + ), + ); - /** - * @var array Fields to drop from the permissions table - */ - private $permissions_drop_fields = array( - 'Site_Appearance_View' => array( - 'type' => 'TINYINT', - 'constraint' => 1, - 'default' => 0, + /** + * @var array Fields to drop from the permissions table + */ + private $permissions_drop_fields = array( + 'Site_Appearance_View' => array( + 'type' => 'TINYINT', + 'constraint' => 1, + 'default' => 0, 'null' => false, - ), - ); + ), + ); - /** - * @var array Fields for the new Permissions table - */ - private $permissions_new_fields = array( - 'permission_id' => array( - 'type' => 'INT', - 'constraint' => 11, - 'auto_increment' => true, - 'null' => false, - ), - 'name' => array( - 'type' => 'VARCHAR', - 'constraint' => 30, - 'null' => false, - ), - 'description' => array( - 'type' =>'VARCHAR', - 'constraint' => 100, - 'null' => false, - ), - 'status' => array( - 'type' => 'ENUM', - 'constraint' => "'active','inactive','deleted'", - 'default' => 'active', - 'null' => false, - ), - ); + /** + * @var array Fields for the new Permissions table + */ + private $permissions_new_fields = array( + 'permission_id' => array( + 'type' => 'INT', + 'constraint' => 11, + 'auto_increment' => true, + 'null' => false, + ), + 'name' => array( + 'type' => 'VARCHAR', + 'constraint' => 30, + 'null' => false, + ), + 'description' => array( + 'type' =>'VARCHAR', + 'constraint' => 100, + 'null' => false, + ), + 'status' => array( + 'type' => "ENUM('active','inactive','deleted')", + 'default' => 'active', + 'null' => false, + ), + ); - /** - * @var array Fields for the role_permissions table - */ - private $role_permissions_fields = array( - 'role_id' => array( - 'type' => 'INT', - 'constraint' => 11, - 'null' => false, - ), - 'permission_id' => array( - 'type' => 'INT', - 'constraint' => 11, - 'null' => false, - ), - ); + /** + * @var array Fields for the role_permissions table + */ + private $role_permissions_fields = array( + 'role_id' => array( + 'type' => 'INT', + 'constraint' => 11, + 'null' => false, + ), + 'permission_id' => array( + 'type' => 'INT', + 'constraint' => 11, + 'null' => false, + ), + ); - /**************************************************************** - * Data for Insert/Update - */ - /** - * @var array Data to update the permissions table - */ - private $permissions_data = array( - 'Site_Signin_Offline' => 1, - ); + /**************************************************************** + * Data for Insert/Update + */ + /** + * @var array Data to update the permissions table + */ + private $permissions_data = array( + 'Site_Signin_Offline' => 1, + ); - /** - * @var int The role_id of the Administrator role - */ - private $admin_role_id = 1; + /** + * @var int The role_id of the Administrator role + */ + private $admin_role_id = 1; - /**************************************************************** - * Migration methods - */ - /** - * Install this migration - */ - public function up() - { - /* Take care of a few preliminaries before updating */ - // Add new Site_Signin_Offline permission - if ( ! $this->db->field_exists('Site_Signin_Offline', $this->permissions_table)) - { + /**************************************************************** + * Migration methods + */ + /** + * Install this migration + */ + public function up() + { + /* Take care of a few preliminaries before updating */ + // Add new Site_Signin_Offline permission + if (! $this->db->field_exists('Site_Signin_Offline', $this->permissions_table)) { $this->dbforge->add_column($this->permissions_table, $this->permissions_fields); - $this->db->where('role_id', $this->admin_role_id) + $this->db->where('role_id', $this->admin_role_id) ->update($this->permissions_table, $this->permissions_data); -/* $prefix = $this->db->dbprefix; - $this->db->query("UPDATE {$prefix}permissions SET `Site.Signin.Offline`=1 WHERE `role_id`=1"); -*/ } - // Rename Site_Statistics_View to Site_Reports_View - if ($this->db->field_exists('Site_Statistics_View', $this->permissions_table)) - { - $this->dbforge->modify_column($this->permissions_table, $this->permissions_modify_fields); -// $this->db->query("ALTER TABLE {$prefix}permissions CHANGE `Site.Statistics.View` `Site.Reports.View` TINYINT(1) DEFAULT 0 NOT NULL"); + // Rename Site_Statistics_View to Site_Reports_View + if ($this->db->field_exists('Site_Statistics_View', $this->permissions_table)) { + $this->dbforge->modify_column($this->permissions_table, $this->permissions_modify_fields); } - // Remove Site.Appearance.View - if ($this->db->field_exists('Site_Appearance_View', $this->permissions_table)) - { - foreach ($this->permissions_drop_fields as $column_name => $column_def) - { - $this->dbforge->drop_column($this->permissions_table, $column_name); + // Remove Site.Appearance.View + if ($this->db->field_exists('Site_Appearance_View', $this->permissions_table)) { + foreach ($this->permissions_drop_fields as $column_name => $column_def) { + $this->dbforge->drop_column($this->permissions_table, $column_name); } -// $this->db->query("ALTER TABLE {$prefix}permissions DROP COLUMN `Site.Appearance.View`"); } - /* Do the actual update. */ - // get the current permissions assigned to each role - $permission_query = $this->db->get($this->permissions_table); + // Do the actual update. + // + // Get the current permissions assigned to each role. + $permission_query = $this->db->get($this->permissions_table); - // get the field names in the current permissions table - $permissions_fields = $permission_query->list_fields(); + // Get the field names in the current permissions table. + $permissions_fields = $permission_query->list_fields(); - $old_permissions_array = array(); - foreach ($permission_query->result_array() as $row) - { - $old_permissions_array[$row['role_id']] = $row; - } + $old_permissions_array = array(); + foreach ($permission_query->result_array() as $row) { + $old_permissions_array[$row['role_id']] = $row; + } - // modify the permissions table - $this->dbforge->rename_table($this->permissions_table, $this->permissions_old_table); + // Modify the permissions table. + $this->dbforge->rename_table($this->permissions_table, $this->permissions_old_table); - // create the new permissions table - $this->dbforge->add_field($this->permissions_new_fields); - $this->dbforge->add_key('permission_id', TRUE); - $this->dbforge->create_table($this->permissions_table); + // Create the new permissions table. + $this->dbforge->add_field($this->permissions_new_fields); + $this->dbforge->add_key('permission_id', true); + $this->dbforge->create_table($this->permissions_table); - // add records for each of the old permissions - $old_permissions_records = array(); - foreach ($permissions_fields as $field) - { - // if this is not the role_id or permission_id field, - // replace underscores with '.' to generate the permission names - if ($field != 'role_id' && $field != 'permission_id') - { + // add records for each of the old permissions + $old_permissions_records = array(); + foreach ($permissions_fields as $field) { + // If this is not the role_id or permission_id field, replace underscores + // with '.' to generate the permission names. + if ($field != 'role_id' && $field != 'permission_id') { $permission_name = str_replace('_', '.', $field); - $old_permissions_records[] = array( - 'name' => $permission_name, - 'description' => '', - ); - } - } + $old_permissions_records[] = array( + 'name' => $permission_name, + 'description' => '', + ); + } + } - // Add permissions to access permissions settings - $old_permissions_records[] = array( - 'name' => 'Permissions.Settings.View', - 'description' => 'Allow access to view the Permissions menu unders Settings Context' - ); - $old_permissions_records[] = array( - 'name' => 'Permissions.Settings.Manage', - 'description' => 'Allow access to manage the Permissions in the system', - ); - $this->db->insert_batch($this->permissions_table, $old_permissions_records); + // Add permissions to access permissions settings. + $old_permissions_records[] = array( + 'name' => 'Permissions.Settings.View', + 'description' => 'Allow access to view the Permissions menu unders Settings Context' + ); + $old_permissions_records[] = array( + 'name' => 'Permissions.Settings.Manage', + 'description' => 'Allow access to manage the Permissions in the system', + ); + $this->db->insert_batch($this->permissions_table, $old_permissions_records); - // create the new role_permissions table - $this->dbforge->add_field($this->role_permissions_fields); - $this->dbforge->add_key('role_id', TRUE); - $this->dbforge->add_key('permission_id', TRUE); - $this->dbforge->create_table($this->role_permissions_table); + // create the new role_permissions table + $this->dbforge->add_field($this->role_permissions_fields); + $this->dbforge->add_key('role_id', true); + $this->dbforge->add_key('permission_id', true); + $this->dbforge->create_table($this->role_permissions_table); - // add records to allow access to the permissions by the roles - adding records to role_permissions - // get the current list of permissions - $new_permission_query = $this->db->get($this->permissions_table); - $role_permissions_records = array(); + // Add records to allow access to the permissions by the roles. + // + // Get the current list of permissions. + $new_permission_query = $this->db->get($this->permissions_table); + $role_permissions_records = array(); - // loop through the current permissions - foreach ($new_permission_query->result_array() as $permission_rec) - { + // Loop through the current permissions. + foreach ($new_permission_query->result_array() as $permission_rec) { $old_permission_name = str_replace('.', '_', $permission_rec['name']); - // loop through the old permissions - foreach ($old_permissions_array as $role_id => $role_permissions) - { - // if the role had access to this permission then give it access again - if (isset($role_permissions[$old_permission_name]) && $role_permissions[$old_permission_name] == 1) - { - $role_permissions_records[] = array( - 'role_id' => $role_id, - 'permission_id' => $permission_rec['permission_id'], - ); - } - } + // Loop through the old permissions. + foreach ($old_permissions_array as $role_id => $role_permissions) { + // Keep existing role permissions. + if (isset($role_permissions[$old_permission_name]) + && $role_permissions[$old_permission_name] == 1 + ) { + $role_permissions_records[] = array( + 'role_id' => $role_id, + 'permission_id' => $permission_rec['permission_id'], + ); + } + } - // give the administrator access to the new "Permissions" permissions - if ($permission_rec['name'] == 'Permissions.Settings.View' + // Give the administrator access to the new "Permissions" permissions + if ($permission_rec['name'] == 'Permissions.Settings.View' || $permission_rec['name'] == 'Permissions.Settings.Manage' || $permission_rec['name'] == 'Bonfire.Permissions.Manage' - ) - { - $role_permissions_records[] = array( - 'role_id' => $this->admin_role_id, - 'permission_id' => $permission_rec['permission_id'], - ); - } - } + ) { + $role_permissions_records[] = array( + 'role_id' => $this->admin_role_id, + 'permission_id' => $permission_rec['permission_id'], + ); + } + } + + $this->db->insert_batch($this->role_permissions_table, $role_permissions_records); + } - $this->db->insert_batch($this->role_permissions_table, $role_permissions_records); - } + /** + * Uninstall this migration + */ + public function down() + { + // Drop the tables. + $this->dbforge->drop_table($this->permissions_table); + $this->dbforge->drop_table($this->role_permissions_table); - /** - * Uninstall this migration - */ - public function down() - { - // Drop our tables - $this->dbforge->drop_table($this->permissions_table); - $this->dbforge->drop_table($this->role_permissions_table); + // Rename the old permissions table. + $this->dbforge->rename_table($this->permissions_old_table, $this->permissions_table); - // Rename the old permissions table - $this->dbforge->rename_table($this->permissions_old_table, $this->permissions_table); - // Rename Site_Reports_View to Site_Statistics_View - $this->dbforge->modify_column($this->permissions_table, $this->permissions_modify_fields_down); - } -} \ No newline at end of file + // Rename Site_Reports_View to Site_Statistics_View. + $this->dbforge->modify_column($this->permissions_table, $this->permissions_modify_fields_down); + } +} diff --git a/bonfire/migrations/009_Add_module_permissions.php b/bonfire/migrations/009_Add_module_permissions.php index 89fc26dad..a51995dc4 100644 --- a/bonfire/migrations/009_Add_module_permissions.php +++ b/bonfire/migrations/009_Add_module_permissions.php @@ -1,94 +1,99 @@ - 'Bonfire.Modules.Add', - 'description' => 'Allow creation of modules with the builder.', - ), - array( - 'name' => 'Bonfire.Modules.Delete', - 'description' => 'Allow deletion of modules.', - ), - ); + /**************************************************************** + * Data for Insert + */ + /** + * @var array The permissions data to insert + */ + private $permissions_data = array( + array( + 'name' => 'Bonfire.Modules.Add', + 'description' => 'Allow creation of modules with the builder.', + ), + array( + 'name' => 'Bonfire.Modules.Delete', + 'description' => 'Allow deletion of modules.', + ), + ); - /** - * @var int The role_id of the Administrator role - */ - private $admin_role_id = 1; + /** + * @var int The role_id of the Administrator role + */ + private $admin_role_id = 1; - /**************************************************************** - * Migration methods - */ - /** - * Install this migration - */ - public function up() - { - $this->load->library('session'); + /**************************************************************** + * Migration methods + */ + /** + * Install this migration + */ + public function up() + { + // Add administrators to module permissions. + $assign_role = array($this->admin_role_id); + if (class_exists('CI_Session', false)) { + if ($this->session->userdata('role_id')) { + $assign_role[] = $this->session->userdata('role_id'); + } + } - // add administrators to module permissions - $assign_role = $this->session->userdata('role_id') ? $this->session->userdata('role_id') : $this->admin_role_id; + $role_data = array(); + foreach ($this->permissions_data as $data) { + $this->db->insert($this->permissions_table, $data); + $permissionId = $this->db->insert_id(); + foreach ($assign_role as $roleId) { + $role_data[] = array( + 'role_id' => $roleId, + 'permission_id' => $permissionId, + ); + } + } - $role_data = array(); - foreach ($this->permissions_data as $data) - { - $this->db->insert($this->permissions_table, $data); - $role_data[] = array( - 'role_id' => $assign_role, - 'permission_id' => $this->db->insert_id(), - ); - } - $this->db->insert_batch($this->role_permissions_table, $role_data); - } + $this->db->insert_batch($this->role_permissions_table, $role_data); + } - /** - * Uninstall this migration - */ - public function down() - { - $permission_names = array(); - foreach ($this->permissions_data as $data) - { - $permission_names[] = $data['name']; - } + /** + * Uninstall this migration + */ + public function down() + { + $permission_names = array(); + foreach ($this->permissions_data as $data) { + $permission_names[] = $data['name']; + } - $query = $this->db->select('permission_id') - ->where_in('name', $permission_names) - ->get($this->permissions_table); + $query = $this->db->select('permission_id') + ->where_in('name', $permission_names) + ->get($this->permissions_table); - $permission_ids = array(); - foreach ($query->result_array() as $row) - { - $permission_ids[] = $row['permission_id']; - } - $this->db->where_in('permission_id', $permission_ids) - ->delete($this->role_permissions_table); + $permission_ids = array(); + foreach ($query->result_array() as $row) { + $permission_ids[] = $row['permission_id']; + } - $this->db->where_in('name', $permission_names) - ->delete($this->permissions_table); - } -} \ No newline at end of file + $this->db->where_in('permission_id', $permission_ids) + ->delete($this->role_permissions_table); + + $this->db->where_in('name', $permission_names) + ->delete($this->permissions_table); + } +} diff --git a/bonfire/migrations/010_Permissions_to_manage_role_permissions.php b/bonfire/migrations/010_Permissions_to_manage_role_permissions.php index b5c1739bb..f5d023e9c 100644 --- a/bonfire/migrations/010_Permissions_to_manage_role_permissions.php +++ b/bonfire/migrations/010_Permissions_to_manage_role_permissions.php @@ -1,138 +1,143 @@ - array( - 'type' => 'VARCHAR', - 'constraint' => 255, - 'null' => false, - ), - ); - - /** - * @var array Field definition to restore - */ - private $permissions_fields_down = array( - 'name' => array( - 'type' => 'VARCHAR', - 'constraint' => 30, - 'null' => false, - ), - ); - - /** - * @var int The role_id of the Administrator role - */ - private $admin_role_id = 1; - - /**************************************************************** - * Migration methods - */ - /** - * Install this migration - */ - public function up() - { - $this->load->library('session'); - - // name field in permissions table is too short bump it up to 255 - $this->dbforge->modify_column($this->permissions_table, $this->permissions_fields); - - $roles = $this->db->select('role_name')->get($this->roles_table)->result(); - $role_permissions_data = array(); - if (isset($roles) && is_array($roles) && count($roles)) - { - // give the new permissions to the current role (or administrators if fresh install) - $assign_role = $this->session->userdata('role_id') ? $this->session->userdata('role_id') : $this->admin_role_id; - foreach ($roles as $role) - { - // add the permission - $permissions_data = array( - 'name' => 'Permissions.' . ucwords($role->role_name) . '.Manage', - 'description' => 'To manage the access control permissions for the ' . ucwords($role->role_name) . ' role.', - ); - $this->db->insert($this->permissions_table, $permissions_data); - - // give current role (or administrators if fresh install) full right to manage permissions - $role_permissions_data[] = array( - 'role_id' => $assign_role, - 'permission_id' => $this->db->insert_id(), - ); - } - - if ( ! empty($role_permissions_data)) - { - $this->db->insert_batch($this->role_permissions_table, $role_permissions_data); - } - } - } - - /** - * Uninstall this migration - */ - public function down() - { - $roles = $this->role_model->find_all(); - if (isset($roles) && is_array($roles) && count($roles)) - { - $permission_ids = array(); - $permission_names = array(); - foreach ($roles as $role) - { - // delete any but that has any of these permissions from the role_permissions table - $query = $this->db->select('permission_id') - ->where('name', 'Permissions.' . $role->role_name . '.Manage') - ->get($this->permissions_table); - - foreach ($query->result_array() as $row) - { - $permission_id[] = $row['permission_id']; - } - //delete the role - $permission_names[] = 'Permissions.' . $role->role_name . '.Manage'; - } - if ( ! empty($permission_ids)) - { - $this->db->where_in('permission_id', $permission_ids) - ->delete($this->role_permissions_table); - } - - if ( ! empty($permission_names)) - { - $this->db->where_in('name', $permission_names) - ->delete($this->permissions_table); - } - } - - // restore the shorter table field size back to 30 - $this->dbforge->modify_column($this->permissions_table, $this->permissions_fields_down); - } -} \ No newline at end of file + /**************************************************************** + * Table names + */ + /** + * @var string Name of the Permissions table + */ + private $permissions_table = 'permissions'; + + /** + * @var string Name of the Role_Permissions table + */ + private $role_permissions_table = 'role_permissions'; + + /** + * @var string Name of the Roles table + */ + private $roles_table = 'roles'; + + /**************************************************************** + * Field definitions + */ + /** + * @var array Field to modify + */ + private $permissions_fields = array( + 'name' => array( + 'type' => 'VARCHAR', + 'constraint' => 255, + 'null' => false, + ), + ); + + /** + * @var array Field definition to restore + */ + private $permissions_fields_down = array( + 'name' => array( + 'type' => 'VARCHAR', + 'constraint' => 30, + 'null' => false, + ), + ); + + /** + * @var int The role_id of the Administrator role + */ + private $admin_role_id = 1; + + /**************************************************************** + * Migration methods + */ + /** + * Install this migration + */ + public function up() + { + // Permissions table's name field is too short, bump it up to 255. + $this->dbforge->modify_column($this->permissions_table, $this->permissions_fields); + + $roles = $this->db->select('role_name') + ->get($this->roles_table) + ->result(); + + $role_permissions_data = array(); + if (! empty($roles) && is_array($roles)) { + // Give the new permissions to the current role + // (or administrators if fresh install). + $assign_role = array($this->admin_role_id); + if (class_exists('CI_Session', false)) { + if ($this->session->userdata('role_id')) { + $assign_role[] = $this->session->userdata('role_id'); + } + } + + foreach ($roles as $role) { + // Add the permission + $permissions_data = array( + 'name' => 'Permissions.' . ucwords($role->role_name) . '.Manage', + 'description' => 'To manage the access control permissions for the ' . ucwords($role->role_name) . ' role.', + ); + $this->db->insert($this->permissions_table, $permissions_data); + + // Give roles full right to manage permissions. + $permissionId = $this->db->insert_id(); + foreach ($assign_role as $roleId) { + $role_permissions_data[] = array( + 'role_id' => $roleId, + 'permission_id' => $permissionId, + ); + } + } + + if (! empty($role_permissions_data)) { + $this->db->insert_batch($this->role_permissions_table, $role_permissions_data); + } + } + } + + /** + * Uninstall this migration + */ + public function down() + { + $roles = $this->role_model->find_all(); + if (! empty($roles) && is_array($roles)) { + $permission_ids = array(); + $permission_names = array(); + foreach ($roles as $role) { + // Delete any of these permissions from the role_permissions table. + $query = $this->db->select('permission_id') + ->where('name', "Permissions.{$role->role_name}.Manage") + ->get($this->permissions_table); + + foreach ($query->result() as $row) { + $permission_id[] = $row->permission_id; + } + + // Delete the role. + $permission_names[] = "Permissions.{$role->role_name}.Manage"; + } + + if (! empty($permission_ids)) { + $this->db->where_in('permission_id', $permission_ids) + ->delete($this->role_permissions_table); + } + + if (! empty($permission_names)) { + $this->db->where_in('name', $permission_names) + ->delete($this->permissions_table); + } + } + + // Restore the shorter table field size back to 30. + $this->dbforge->modify_column($this->permissions_table, $this->permissions_fields_down); + } +} diff --git a/bonfire/migrations/011_Permissions_to_manage_activities.php b/bonfire/migrations/011_Permissions_to_manage_activities.php index 0bcd95cf5..15d72c936 100644 --- a/bonfire/migrations/011_Permissions_to_manage_activities.php +++ b/bonfire/migrations/011_Permissions_to_manage_activities.php @@ -1,4 +1,4 @@ - array( - 'type' => 'TINYINT', - 'constraint' => 12, - 'default' => 0, - 'null' => false, - ), - ); - - /**************************************************************** - * Data to Insert - */ - /** - * @var array Permissions data to insert - */ - private $permissions_data = array( - array( - 'name' => 'Bonfire.Activities.Manage', - 'description' => 'Allow users to access the Activities Reports', - ), - array( - 'name' => 'Activities.Own.View', - 'description' => 'To view the users own activity logs', - ), - array( - 'name' => 'Activities.Own.Delete', - 'description' => 'To delete the users own activity logs', - ), - array( - 'name' => 'Activities.User.View', - 'description' => 'To view the user activity logs', - ), - array( - 'name' => 'Activities.User.Delete', - 'description' => 'To delete the user activity logs, except own', - ), - array( - 'name' => 'Activities.Module.View', - 'description' => 'To view the module activity logs', - ), - array( - 'name' => 'Activities.Module.Delete', - 'description' => 'To delete the module activity logs', - ), - array( - 'name' => 'Activities.Date.View', - 'description' => 'To view the users own activity logs', - ), - array( - 'name' => 'Activities.Date.Delete' , - 'description' => 'To delete the dated activity logs', - ), - ); - - /** - * @var int The role_id of the Administrator role - */ - private $admin_role_id = 1; - - /**************************************************************** - * Migration methods - */ - /** - * Install this migration - */ - public function up() - { - $this->load->library('session'); - - // add the soft deletes column, made it (12) to accomodate time stamp change coming - $this->dbforge->add_column($this->activities_table, $this->activities_fields); - - $this->db->insert_batch($this->permissions_table, $this->permissions_data); - - // give current role (or administrators if fresh install) full right to manage permissions - $assign_role = $this->session->userdata('role_id') ? $this->session->userdata('role_id') : $this->admin_role_id; - - $permission_names = array(); - foreach ($this->permissions_data as $permission) - { - $permission_names[] = $permission['name']; - } - - $permissions = $this->db->select('permission_id') - ->where_in('name', $permission_names) - ->get($this->permissions_table) - ->result(); - - if (isset($permissions) && is_array($permissions) && count($permissions)) - { - $permissions_data = array(); - foreach ($permissions as $perm) - { - $permissions_data[] = array( - 'role_id' => $assign_role, - 'permission_id' => $perm->permission_id, - ); - } - - if ( ! empty($permissions_data)) - { - $this->db->insert_batch($this->role_permissions_table, $permissions_data); - } - } - } - - /** - * Uninstall this migration - */ - public function down() - { - $permission_names = array(); - foreach ($this->permissions_data as $permission) - { - $permission_names[] = $permission['name']; - } - - $query = $this->db->select('permission_id') - ->where_in('name', $permission_names) - ->get($this->permissions_table) - ->result(); - - $permission_ids = array(); - // delete these permissions from the role_permissions table - foreach ($query->result_array() as $row) - { - $permission_ids[] = $row['permission_id']; - } - - if ( ! empty($permission_ids)) - { - $this->db->where_in('permission_id', $permission_ids) - ->delete($this->role_permissions_table); - } - - //delete the permissions - $this->db->where_in('name', $permission_names) - ->delete($this->permissions_table); - - // drop the added deleted column - foreach ($this->activities_fields as $column_name => $column_def) - { - $this->dbforge->drop_column($this->activities_table, $column_name); - } - } -} \ No newline at end of file + /**************************************************************** + * Table names + */ + /** + * @var string Name of the Activities table + */ + private $activities_table = 'activities'; + + /** + * @var string Name of the Permissions table + */ + private $permissions_table = 'permissions'; + + /** + * @var string Name of the Role_permissions table + */ + private $role_permissions_table = 'role_permissions'; + + /**************************************************************** + * Field definitions + */ + /** + * @var array Fields to be added to the Activities table + */ + private $activities_fields = array( + 'deleted' => array( + 'type' => 'TINYINT', + 'constraint' => 12, + 'default' => 0, + 'null' => false, + ), + ); + + /**************************************************************** + * Data to Insert + */ + /** + * @var array Permissions data to insert + */ + private $permissions_data = array( + array( + 'name' => 'Bonfire.Activities.Manage', + 'description' => 'Allow users to access the Activities Reports', + ), + array( + 'name' => 'Activities.Own.View', + 'description' => 'To view the users own activity logs', + ), + array( + 'name' => 'Activities.Own.Delete', + 'description' => 'To delete the users own activity logs', + ), + array( + 'name' => 'Activities.User.View', + 'description' => 'To view the user activity logs', + ), + array( + 'name' => 'Activities.User.Delete', + 'description' => 'To delete the user activity logs, except own', + ), + array( + 'name' => 'Activities.Module.View', + 'description' => 'To view the module activity logs', + ), + array( + 'name' => 'Activities.Module.Delete', + 'description' => 'To delete the module activity logs', + ), + array( + 'name' => 'Activities.Date.View', + 'description' => 'To view the users own activity logs', + ), + array( + 'name' => 'Activities.Date.Delete' , + 'description' => 'To delete the dated activity logs', + ), + ); + + /** + * @var int The role_id of the Administrator role + */ + private $admin_role_id = 1; + + /**************************************************************** + * Migration methods + */ + /** + * Install this migration + */ + public function up() + { + // Add the soft deletes column, made it (12) to accomodate time stamp. + $this->dbforge->add_column($this->activities_table, $this->activities_fields); + + $this->db->insert_batch($this->permissions_table, $this->permissions_data); + + // Give current role (or administrators if fresh install) full right to manage permissions + $assign_role = array($this->admin_role_id); + if (class_exists('CI_Session', false)) { + if ($this->session->userdata('role_id')) { + $assign_role[] = $this->session->userdata('role_id'); + } + } + + $permission_names = array(); + foreach ($this->permissions_data as $permission) { + $permission_names[] = $permission['name']; + } + + $permissions = $this->db->select('permission_id') + ->where_in('name', $permission_names) + ->get($this->permissions_table) + ->result(); + + if (! empty($permissions) && is_array($permissions)) { + $permissions_data = array(); + foreach ($permissions as $perm) { + foreach ($assign_role as $roleId) { + $permissions_data[] = array( + 'role_id' => $roleId, + 'permission_id' => $perm->permission_id, + ); + } + } + + if (! empty($permissions_data)) { + $this->db->insert_batch($this->role_permissions_table, $permissions_data); + } + } + } + + /** + * Uninstall this migration + */ + public function down() + { + $permission_names = array(); + foreach ($this->permissions_data as $permission) { + $permission_names[] = $permission['name']; + } + + $query = $this->db->select('permission_id') + ->where_in('name', $permission_names) + ->get($this->permissions_table) + ->result(); + + // Delete these permissions from the role_permissions table. + $permission_ids = array(); + foreach ($query->result_array() as $row) { + $permission_ids[] = $row['permission_id']; + } + + if (! empty($permission_ids)) { + $this->db->where_in('permission_id', $permission_ids) + ->delete($this->role_permissions_table); + } + + // Delete the permissions. + $this->db->where_in('name', $permission_names) + ->delete($this->permissions_table); + + // Drop the added deleted column. + foreach ($this->activities_fields as $column_name => $column_def) { + $this->dbforge->drop_column($this->activities_table, $column_name); + } + } +} diff --git a/bonfire/migrations/024_Remove_old_schema_table.php b/bonfire/migrations/024_Remove_old_schema_table.php index d85dfe1f6..6038bc806 100644 --- a/bonfire/migrations/024_Remove_old_schema_table.php +++ b/bonfire/migrations/024_Remove_old_schema_table.php @@ -1,4 +1,4 @@ - array( - 'type' => 'int', - 'constraint' => 4, - 'default' => 0, - 'null' => false, - ), - 'app_version' => array( - 'type' => 'int', - 'constraint' => 4, - 'default' => 0, - 'null' => false, - ), - ); + /** + * @var array Fields used to rebuild the table in down() + */ + private $fields = array( + 'version' => array( + 'type' => 'int', + 'constraint' => 4, + 'default' => 0, + 'null' => false, + ), + 'app_version' => array( + 'type' => 'int', + 'constraint' => 4, + 'default' => 0, + 'null' => false, + ), + ); - /** - * @var array Default data to insert into the table in down() - */ - private $data = array( - 'version' => 11, - 'app_version' => 0, - ); + /** + * @var array Default data to insert into the table in down() + */ + private $data = array( + 'version' => 11, + 'app_version' => 0, + ); - /**************************************************************** - * Migration methods - */ - /** - * Install this migration - */ - public function up() - { - $this->dbforge->drop_table($this->table_name); - } + /**************************************************************** + * Migration methods + */ + /** + * Install this migration + */ + public function up() + { + if ($this->db->table_exists($this->table_name)) { + $this->dbforge->drop_table($this->table_name); + } + } - /** - * Uninstall this migration - */ - public function down() - { - $this->dbforge->add_field($this->fields); - $this->dbforge->create_table($this->table_name); + /** + * Uninstall this migration + */ + public function down() + { + $this->dbforge->add_field($this->fields); + $this->dbforge->create_table($this->table_name); - $this->db->insert($this->table_name, $this->data); - } -} \ No newline at end of file + $this->db->insert($this->table_name, $this->data); + } +} diff --git a/bonfire/modules/activities/controllers/Reports.php b/bonfire/modules/activities/controllers/Reports.php index 78211d8ac..9c1f9fbcd 100644 --- a/bonfire/modules/activities/controllers/Reports.php +++ b/bonfire/modules/activities/controllers/Reports.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 @@ -19,22 +19,22 @@ * * Allow the administrator to view the activity logs. * - * @package Bonfire\Modules\Activities\Controllers\Reports - * @author Bonfire Dev Team - * @link http://cibonfire.com/docs/activities + * @package Bonfire\Modules\Activities\Controllers\Reports + * @author Bonfire Dev Team + * @link http://cibonfire.com/docs/developer/activities */ class Reports extends Admin_Controller { - private $permissionDeleteDate = 'Activities.Date.Delete'; - private $permissionDeleteModule = 'Activities.Module.Delete'; - private $permissionDeleteOwn = 'Activities.Own.Delete'; - private $permissionDeleteUser = 'Activities.User.Delete'; - private $permissionSiteReportsView = 'Site.Reports.View'; - private $permissionViewActivities = 'Bonfire.Activities.View'; - private $permissionViewDate = 'Activities.Date.View'; - private $permissionViewModule = 'Activities.Module.View'; - private $permissionViewOwn = 'Activities.Own.View'; - private $permissionViewUser = 'Activities.User.View'; + private $permissionDeleteDate = 'Activities.Date.Delete'; + private $permissionDeleteModule = 'Activities.Module.Delete'; + private $permissionDeleteOwn = 'Activities.Own.Delete'; + private $permissionDeleteUser = 'Activities.User.Delete'; + private $permissionSiteReportsView = 'Site.Reports.View'; + private $permissionViewActivities = 'Bonfire.Activities.View'; + private $permissionViewDate = 'Activities.Date.View'; + private $permissionViewModule = 'Activities.Module.View'; + private $permissionViewOwn = 'Activities.Own.View'; + private $permissionViewUser = 'Activities.User.View'; private $hasPermissionDeleteOwn; private $hasPermissionViewDate; @@ -42,34 +42,38 @@ class Reports extends Admin_Controller private $hasPermissionViewOwn; private $hasPermissionViewUser; - /** - * Constructor - * - * @return void - */ - public function __construct() - { - parent::__construct(); + /** + * Constructor + * + * @return void + */ + public function __construct() + { + parent::__construct(); - $this->auth->restrict($this->permissionSiteReportsView); - $this->auth->restrict($this->permissionViewActivities); + $this->auth->restrict($this->permissionSiteReportsView); + $this->auth->restrict($this->permissionViewActivities); - $this->lang->load('activities/activities'); - $this->lang->load('datatable'); + $this->lang->load('activities/activities'); + $this->lang->load('datatable'); $this->load->model('activities/activity_model'); - Assets::add_js(array( - 'bootstrap', - 'jquery.dataTables', - 'bootstrap-dataTables', - )); - Assets::add_js($this->load->view('reports/activities_js', null, true), 'inline'); + Assets::add_js( + array( + 'bootstrap', + 'jquery.dataTables', + 'bootstrap-dataTables', + ) + ); + Assets::add_js($this->load->view('reports/activities_js', null, true), 'inline'); - Assets::add_css(array( - 'datatable', - 'bootstrap-dataTables', - )); + Assets::add_css( + array( + 'datatable', + 'bootstrap-dataTables', + ) + ); // Check the permissions, store the results. $this->hasPermissionDeleteOwn = $this->auth->has_permission($this->permissionDeleteOwn); @@ -82,26 +86,25 @@ public function __construct() || $this->hasPermissionViewModule || $this->hasPermissionViewDate ) { - Template::set_block('sub_nav', 'reports/_sub_nav'); - } - - Template::set('toolbar_title', lang('activities_title')); - } - - /** - * List all activity logs and allow the user to change the log threshold. - * - * @return void - */ - public function index() - { + Template::set_block('sub_nav', 'reports/_sub_nav'); + } + + Template::set('toolbar_title', lang('activities_title')); Template::set('hasPermissionDeleteOwn', $this->hasPermissionDeleteOwn); Template::set('hasPermissionViewDate', $this->hasPermissionViewDate); Template::set('hasPermissionViewModule', $this->hasPermissionViewModule); Template::set('hasPermissionViewOwn', $this->hasPermissionViewOwn); Template::set('hasPermissionViewUser', $this->hasPermissionViewUser); + } - if ($this->hasPermissionViewUser + /** + * List all activity logs and allow the user to change the log threshold. + * + * @return void + */ + public function index() + { + if ($this->hasPermissionViewUser || $this->hasPermissionViewModule || $this->hasPermissionViewDate ) { @@ -118,101 +121,104 @@ public function index() Template::set('hasPermissionDeleteModule', $this->auth->has_permission($this->permissionDeleteModule)); Template::set('hasPermissionDeleteUser', $this->auth->has_permission($this->permissionDeleteUser)); - Template::set( + Template::set( 'activities', $this->activity_model->where($this->activity_model->get_table() . '.' . $this->activity_model->get_deleted_field(), 0) + ->order_by($this->activity_model->get_created_field(), 'asc') ->find_all() ); - Template::set('modules', Modules::list_modules()); + $modules = Modules::list_modules(); + sort($modules); + Template::set('modules', $modules); Template::set('top_modules', $this->activity_model->findTopModules(5)); Template::set('top_users', $this->activity_model->findTopUsers(5)); - Template::set( + Template::set( 'users', $this->user_model->where($this->user_model->get_table() . '.' . $this->user_model->get_deleted_field(), 0) ->order_by('username', 'asc') ->find_all() ); - Template::render(); - } elseif ($this->hasPermissionViewOwn) { - $this->activity_own(); - } - } - - /** - * Display the activities for the specified user. - * - * @return void - */ - public function activity_user() - { - if ($this->hasPermissionViewUser) { + Template::render(); + } elseif ($this->hasPermissionViewOwn) { + $this->activity_own(); + } + } + + /** + * Display the activities for the specified user. + * + * @return void + */ + public function activity_user() + { + if ($this->hasPermissionViewUser) { return $this->getActivity(); - } - - $this->activityRestricted(); - } - - /** - * Display the activities for the current user. - * - * @return void - */ - public function activity_own() - { - if ($this->hasPermissionViewOwn) { + } + + $this->activityRestricted(); + } + + /** + * Display the activities for the current user. + * + * @return void + */ + public function activity_own() + { + if ($this->hasPermissionViewOwn) { return $this->getActivity('activity_own', $this->auth->user_id()); - } - - $this->activityRestricted(); - } - - /** - * Display the activities for the specified module. - * - * @return void - */ - public function activity_module() - { - if ($this->hasPermissionViewModule) { + } + + $this->activityRestricted(); + } + + /** + * Display the activities for the specified module. + * + * @return void + */ + public function activity_module() + { + if ($this->hasPermissionViewModule) { return $this->getActivity('activity_module'); - } + } $this->activityRestricted(); - } - - /** - * Display the activities before the specified date. - * - * @return void - */ - public function activity_date() - { + } + + /** + * Display the activities before the specified date. + * + * @return void + */ + public function activity_date() + { if ($this->auth->has_permission('Activities.Date.View')) { return $this->getActivity('activity_date'); - } - - $this->activityRestricted(); - } - - /** - * Delete the entries in the activity log for the specified area. - * - * @return void - */ - public function delete() - { + } + + $this->activityRestricted(); + } + + /** + * Delete the entries in the activity log for the specified area. + * + * @return void + */ + public function delete() + { $this->deleteActivity( $this->input->post('action'), $this->input->post('which') ); - redirect(SITE_AREA . '/reports/activities'); - } + redirect(SITE_AREA . '/reports/activities'); + } - //-------------------------------------------------------------------- - // !PRIVATE METHODS - //-------------------------------------------------------------------- + //-------------------------------------------------------------------- + // !PRIVATE METHODS + //-------------------------------------------------------------------- /** * The user attempted to do something which he/she is not permitted to do. @@ -227,55 +233,53 @@ private function activityRestricted() redirect(SITE_AREA . '/reports/activities'); } - /** - * Delete the entries in the activity log for the specified area. - * - * @param string $action The area we are in - * @param string $which A specific value to match, or "all" - * - * @return void - */ + /** + * Delete the entries in the activity log for the specified area. + * + * @param string $action The area we are in + * @param string $which A specific value to match, or "all" + * + * @return void + */ private function deleteActivity($action, $which) - { + { // This is before the permission check because the permission check - // takes longer and depends on the value of $action - if (empty($action)) { - Template::set_message(lang('activities_delete_no_section'), 'error'); - return; - } + // takes longer and depends on the value of $action. + if (empty($action)) { + Template::set_message(lang('activities_delete_no_section'), 'error'); + return; + } - // Check for permission to delete this + // Check for permission to delete this $permission = ucfirst(str_replace('activity_', '', $action)); if (! $this->auth->has_permission("Activities.{$permission}.Delete")) { - Template::set_message(lang('activities_restricted'), 'error'); - return; - } - - if (empty($which)) { - Template::set_message(lang('activities_delete_no_value'), 'error'); - return; - } - - // Change the where statement based on $action - switch ($action) { - case 'activity_date': - $value = 'activity_id'; - break; - - case 'activity_module': - $value = 'module'; - break; - - default: - $value = 'user_id'; - break; - } + Template::set_message(lang('activities_restricted'), 'error'); + return; + } + + if (empty($which)) { + Template::set_message(lang('activities_delete_no_value'), 'error'); + return; + } + + // Change the where statement based on $action + switch ($action) { + case 'activity_date': + $value = 'activity_id'; + break; + case 'activity_module': + $value = 'module'; + break; + default: + $value = 'user_id'; + break; + } // Set the where clause for the delete $deleteWhere = array(); if ($which == 'all') { $deleteWhere["{$value} !="] = 'tsTyImbdOBOgwIqtb94N4Gr6ctatWVDnmYC3NfIfczzxPs0xZLNBnQs38dzBYn8'; - } elseif ($value == 'activity_id') { + } elseif ($value == 'activity_id') { $deleteWhere["{$value} <"] = $which; } else { $deleteWhere[$value] = $which; @@ -288,162 +292,163 @@ private function deleteActivity($action, $which) $affected = $this->activity_model->delete_where($deleteWhere); - if (is_numeric($affected)) { - Template::set_message(sprintf(lang('activities_deleted'), $affected), 'success'); - $this->activity_model->log_activity($this->auth->user_id(), sprintf(lang('activities_act_deleted'), $affected), 'activities'); - } elseif (isset($affected)) { - Template::set_message(lang('activities_nothing'), 'attention'); - } else { - Template::set_message(sprintf(lang('activities_delete_error'), $this->activity_model->error), 'error'); - } - } - - /** - * Get activity based on parameters passed - * + if (is_numeric($affected)) { + Template::set_message(sprintf(lang('activities_deleted'), $affected), 'success'); + $this->activity_model->log_activity($this->auth->user_id(), sprintf(lang('activities_act_deleted'), $affected), 'activities'); + } elseif (isset($affected)) { + Template::set_message(lang('activities_nothing'), 'attention'); + } else { + Template::set_message(sprintf(lang('activities_delete_error'), $this->activity_model->error), 'error'); + } + } + + /** + * Get activity based on parameters passed + * * @param string $which Which filter to use. * @param bool $filterValue Value to filter by - * - * @return void - */ + * + * @return void + */ private function getActivity($which = 'activity_user', $filterValue = false) - { + { $postedWhichSelect = $this->input->post("{$which}_select"); // Check whether $filterValue has anything in it if ($filterValue === false) { $filterValue = $postedWhichSelect == '' ? $this->uri->segment(5) : $postedWhichSelect; - } + } - if (isset($_POST['delete'])) { + if (isset($_POST['delete'])) { $this->deleteActivity($which, $filterValue); - } + } - $activityDeletedField = $this->activity_model->get_deleted_field(); - $activityTable = $this->activity_model->get_table(); - $userDeletedField = $this->user_model->get_deleted_field(); - $userKey = $this->user_model->get_key(); - $userTable = $this->user_model->get_table(); + $activityDeletedField = $this->activity_model->get_deleted_field(); + $activityTable = $this->activity_model->get_table(); + $userDeletedField = $this->user_model->get_deleted_field(); + $userKey = $this->user_model->get_key(); + $userTable = $this->user_model->get_table(); - // Set default values - $name = lang('activities_all'); - $options = array('all' => $name); + // Set default values + $name = lang('activities_all'); + $options = array('all' => $name); // Find the $options and $name based on activity type ($which) - switch ($which) { - case 'activity_module': - $modules = Modules::list_modules(); + switch ($which) { + case 'activity_module': + $modules = Modules::list_modules(); + + // Setup the list of modules for the filter in a separate list, + // so it can be sorted and 'All' will remain at the top of the list. + $mods = array(); + foreach ($modules as $mod) { + $mods[$mod] = $mod; + if ($filterValue == $mod) { + $name = ucwords($mod); + } + } - // Sort modules by key (module directory name) - ksort($modules); + // Sort list of modules by name. + ksort($mods); - // Setup the list of modules for the filter. - foreach ($modules as $mod) { - $options[$mod] = $mod; - if ($filterValue == $mod) { - $name = ucwords($mod); - } - } - $where = 'module'; + // Merge the list of modules with the options array. + $options = array_merge($options, $mods); + $where = 'module'; Template::set('hasPermissionDeleteModule', $this->auth->has_permission($this->permissionDeleteModule)); break; - - case 'activity_date': - foreach ($this->activity_model->find_all_by($activityDeletedField, 0) as $e) { - $options[$e->activity_id] = $e->created_on; + case 'activity_date': + foreach ($this->activity_model->find_all_by($activityDeletedField, 0) as $e) { + $options[$e->activity_id] = $e->created_on; if ($filterValue == $e->activity_id) { - $name = $e->created_on; - } - } - $where = 'activity_id'; + $name = $e->created_on; + } + } + $where = 'activity_id'; Template::set('hasPermissionDeleteDate', $this->auth->has_permission($this->permissionDeleteDate)); - break; - - case 'activity_own': - // no break; - default: - if ($this->hasPermissionViewUser) { + break; + case 'activity_own': + default: + if ($this->hasPermissionViewUser) { // Use the same order_by for the user drop-down/select as is // used on the index page $this->user_model->where("{$userTable}.{$userDeletedField}", 0) ->order_by('username', 'asc'); foreach ($this->user_model->find_all() as $e) { - $options[$e->id] = $e->username; + $options[$e->id] = $e->username; if ($filterValue == $e->id) { - $name = $e->username; - } - } + $name = $e->username; + } + } Template::set('hasPermissionDeleteUser', $this->auth->has_permission($this->permissionDeleteUser)); - } elseif ($this->hasPermissionViewOwn) { - $options = array(); - $options[$this->auth->user_id()] = $this->auth->user()->username; - $name = $this->auth->user()->username; - } - $where = 'user_id'; - break; - } - - // Set vars for the view - Template::set( + } elseif ($this->hasPermissionViewOwn) { + $options = array(); + $options[$this->auth->user_id()] = $this->auth->user()->username; + $name = $this->auth->user()->username; + } + $where = 'user_id'; + break; + } + + // Set vars for the view + Template::set( 'vars', array( - 'which' => $which, - 'view_which' => ucwords(lang(str_replace('activity_', 'activities_', $which))), - 'name' => $name, - 'delete_action' => $where, + 'which' => $which, + 'view_which' => ucwords(lang(str_replace('activity_', 'activities_', $which))), + 'name' => $name, + 'delete_action' => $where, 'delete_id' => $filterValue, ) ); $this->activity_model->order_by($where, 'asc'); - // Apply the filter, if there is one + // Apply the filter, if there is one if (empty($filterValue) || $filterValue == 'all') { $total = $this->activity_model->count_by("{$activityTable}.{$activityDeletedField}", 0); } else { - $where = $where == 'activity_id' ? 'activity_id <' : $where; + $where = $where == 'activity_id' ? 'activity_id <' : $where; $total = $this->activity_model->where($where, $filterValue) ->where("{$activityTable}.{$activityDeletedField}", 0) ->count_by($where, $filterValue); - // Set this again for use in the main query + // Set this again for use in the main query $this->activity_model->where($where, $filterValue); - } + } - // Does user have permission to see own records? + // Does user have permission to see own records? if (! $this->hasPermissionViewOwn) { $this->activity_model->where("{$activityTable}.user_id !=", $this->auth->user_id()); - } + } + + // Pagination + $this->load->library('pagination'); - // Pagination - $this->load->library('pagination'); + $offset = $this->input->get('per_page'); + $limit = $this->settings_lib->item('site.list_limit'); - $offset = $this->input->get('per_page'); - $limit = $this->settings_lib->item('site.list_limit'); + $this->pager['base_url'] = current_url() . '?'; + $this->pager['total_rows'] = $total; + $this->pager['per_page'] = $limit; + $this->pager['page_query_string'] = true; - $this->pager['base_url'] = current_url() . '?'; - $this->pager['total_rows'] = $total; - $this->pager['per_page'] = $limit; - $this->pager['page_query_string'] = true; + $this->pagination->initialize($this->pager); - $this->pagination->initialize($this->pager); + $activityCreated = $this->activity_model->get_created_field(); - // Get the activities - $this->activity_model->select(array( - 'activity', - 'module', - 'activities.created_on AS created', - 'username', - )) + // Get the activities + $this->activity_model->select( + array('activity', 'module', "{$activityTable}.{$activityCreated} AS created", 'username') + ) ->where("{$activityTable}.{$activityDeletedField}", 0) ->join($userTable, "{$activityTable}.user_id = {$userTable}.{$userKey}", 'left') - ->order_by('activity_id', 'desc') // Most recent on top + ->order_by("{$activityTable}.{$activityCreated}", 'desc') // Most recent on top ->limit($limit, $offset); Template::set('activity_content', $this->activity_model->find_all()); - Template::set('filter', $postedWhichSelect); - Template::set('select_options', $options); + Template::set('filter', $postedWhichSelect); + Template::set('select_options', $options); Template::set('hasPermissionViewDate', $this->hasPermissionViewDate); Template::set('hasPermissionViewModule', $this->hasPermissionViewModule); @@ -451,8 +456,8 @@ private function getActivity($which = 'activity_user', $filterValue = false) Template::set('hasPermissionViewOwn', $this->hasPermissionViewOwn); Template::set('hasPermissionDeleteOwn', $this->hasPermissionDeleteOwn); - Template::set_view('reports/view'); - Template::render(); - } + Template::set_view('reports/view'); + Template::render(); + } } /* /activities/controllers/reports.php */ diff --git a/bonfire/modules/activities/views/reports/_sub_nav.php b/bonfire/modules/activities/views/reports/_sub_nav.php index ea08b616f..e0caa81dd 100644 --- a/bonfire/modules/activities/views/reports/_sub_nav.php +++ b/bonfire/modules/activities/views/reports/_sub_nav.php @@ -1,10 +1,5 @@ uri->segment(4); $activitiesReportsUrl = site_url(SITE_AREA . '/reports/activities'); $pageUser = 'activity_user'; @@ -14,25 +9,25 @@ ?> \ No newline at end of file diff --git a/bonfire/modules/activities/views/reports/index.php b/bonfire/modules/activities/views/reports/index.php index 8cd4aae55..798d302a9 100644 --- a/bonfire/modules/activities/views/reports/index.php +++ b/bonfire/modules/activities/views/reports/index.php @@ -2,12 +2,7 @@ $hasPermissionDeleteDate = isset($hasPermissionDeleteDate) ? $hasPermissionDeleteDate : false; $hasPermissionDeleteModule = isset($hasPermissionDeleteModule) ? $hasPermissionDeleteModule : false; -$hasPermissionDeleteOwn = isset($hasPermissionDeleteOwn) ? $hasPermissionDeleteOwn : false; $hasPermissionDeleteUser = isset($hasPermissionDeleteUser) ? $hasPermissionDeleteUser : false; -$hasPermissionViewDate = isset($hasPermissionViewDate) ? $hasPermissionViewDate : false; -$hasPermissionViewModule = isset($hasPermissionViewModule) ? $hasPermissionViewModule : false; -$hasPermissionViewOwn = isset($hasPermissionViewOwn) ? $hasPermissionViewOwn : false; -$hasPermissionViewUser = isset($hasPermissionViewUser) ? $hasPermissionViewUser : false; $activitiesReportsPage = SITE_AREA . '/reports/activities'; $activitiesReportsUrl = site_url($activitiesReportsPage); @@ -79,7 +74,9 @@

    - + +

    + @@ -96,8 +93,6 @@
    - -

    @@ -105,7 +100,9 @@

    - + +

    + @@ -122,23 +119,19 @@
    - -

    +

    - -

    - @@ -225,5 +218,6 @@
    - -
    \ No newline at end of file + + @@ -47,9 +46,9 @@

    diff --git a/bonfire/modules/builder/views/files/view_default.php b/bonfire/modules/builder/views/files/view_default.php index 1568c0c6d..5969e8fbb 100644 --- a/bonfire/modules/builder/views/files/view_default.php +++ b/bonfire/modules/builder/views/files/view_default.php @@ -10,127 +10,121 @@ $viewFields = ''; for ($counter = 1; $field_total >= $counter; $counter++) { - // Only build on fields that have data entered. - if (set_value("view_field_label$counter") == null) { - continue; - } + // Only build on fields that have data entered. + if (set_value("view_field_label$counter") == null) { + continue; + } - $maxlength = null; - $validation_rules = $this->input->post("validation_rules{$counter}"); - $field_label = set_value("view_field_label$counter"); - $field_name = set_value("view_field_name$counter"); - $form_name = "{$field_prefix}{$field_name}"; - $field_type = set_value("view_field_type$counter"); + $maxlength = null; + $validation_rules = $this->input->post("validation_rules{$counter}"); + $field_label = set_value("view_field_label$counter"); + $field_name = set_value("view_field_name$counter"); + $form_name = "{$field_prefix}{$field_name}"; + $field_type = set_value("view_field_type$counter"); - $required = ''; - $required_attribute = false; + $required = ''; + $required_attribute = false; // Validation rules for this fieldset - if (is_array($validation_rules)) { - foreach ($validation_rules as $key => $value) { - if ($value == 'required') { - $required = ". lang('bf_form_label_required')"; - $required_attribute = true; - } - } - } - - // Type of field - switch ($field_type) { - case 'textarea': - $viewFields .= PHP_EOL . " -
    \"> - 'control-label')); ?> -
    - '{$form_name}', 'id' => '{$form_name}', 'rows' => '5', 'cols' => '80', 'value' => set_value('$form_name', isset(\${$module_name_lower}->{$field_name}) ? \${$module_name_lower}->{$field_name} : '')" . ($required_attribute ? ", 'required' => 'required'" : "") . ")); ?> - -
    -
    "; - break; - - case 'radio': - $viewFields .= PHP_EOL . " -
    \"> - 'control-label', 'id' => '{$form_name}_label')); ?> -
    - - - -
    -
    "; - break; - - case 'select': - // Use CI form helper here as it makes selects/dropdowns easier - $select_options = array(); - if (set_value("db_field_length_value$counter") != null) { - $select_options = explode(',', set_value("db_field_length_value$counter")); - } - $viewFields .= PHP_EOL . ' - $option) { - $viewFields .= ' - ' . strip_slashes($option) . ' => ' . strip_slashes($option) . ','; - } - $viewFields .= " - ); - echo form_dropdown(array('name' => '{$form_name}'" . ($required_attribute ? ", 'required' => 'required'" : "") . "), \$options, set_value('{$form_name}', isset(\${$module_name_lower}->{$field_name}) ? \${$module_name_lower}->{$field_name} : ''), '{$field_label}{$required}'); - ?>"; - break; - - case 'checkbox': - $viewFields .= PHP_EOL . " -
    \"> -
    - + if (is_array($validation_rules)) { + foreach ($validation_rules as $key => $value) { + if ($value == 'required') { + $required = ". lang('bf_form_label_required')"; + $required_attribute = true; + } + } + } + + // Type of field + switch ($field_type) { + case 'textarea': + $viewFields .= PHP_EOL . " +
    \"> + 'control-label')); ?> +
    + '{$form_name}', 'id' => '{$form_name}', 'rows' => '5', 'cols' => '80', 'value' => set_value('$form_name', isset(\${$module_name_lower}->{$field_name}) ? \${$module_name_lower}->{$field_name} : '')" . ($required_attribute ? ", 'required' => 'required'" : "") . ")); ?> -
    -
    "; - break; - - case 'input': - // no break; - case('password'): - // no break; - default: +
    +
    "; + break; + case 'radio': + $viewFields .= PHP_EOL . " +
    \"> + 'control-label', 'id' => '{$form_name}_label')); ?> +
    + + + +
    +
    "; + break; + case 'select': + // Use CI form helper here as it makes selects/dropdowns easier + $select_options = array(); + if (set_value("db_field_length_value$counter") != null) { + $select_options = explode(',', set_value("db_field_length_value$counter")); + } + $viewFields .= PHP_EOL . ' + $option) { + $viewFields .= ' + ' . strip_slashes($option) . ' => ' . strip_slashes($option) . ','; + } + $viewFields .= " + ); + echo form_dropdown(array('name' => '{$form_name}'" . ($required_attribute ? ", 'required' => 'required'" : "") . "), \$options, set_value('{$form_name}', isset(\${$module_name_lower}->{$field_name}) ? \${$module_name_lower}->{$field_name} : ''), lang('{$module_name_lower}_field_{$field_name}') . '{$required}'); + ?>"; + break; + case 'checkbox': + $viewFields .= PHP_EOL . " +
    \"> +
    + + +
    +
    "; + break; + case 'input': + case 'password': + default: $type = $field_type == 'input' ? 'text' : 'password'; - $db_field_type = set_value("db_field_type$counter"); + $db_field_type = set_value("db_field_type$counter"); $max = set_value("db_field_length_value$counter"); - if ($max != null) { - if (in_array($db_field_type, $realNumberTypes)) { + if ($max != null) { + if (in_array($db_field_type, $realNumberTypes)) { // Constraints for real number types are expected to be in // the format of 'precision,scale', but the standard allows // 'precision', where a scale of 0 is implied (therefore // no decimal point is used) - $len = explode(',', $max); - $max = $len[0]; - if ( ! empty($len[1])) { - $max++; // Add 1 to allow for the decimal point + $len = explode(',', $max); + $max = $len[0]; + if (! empty($len[1])) { + ++$max; // Add 1 to allow for the decimal point. } - } + } $maxlength = "maxlength='{$max}'"; - } + } - $viewFields .= PHP_EOL . " -
    \"> - 'control-label')); ?> -
    - {$field_name}) ? \${$module_name_lower}->{$field_name} : ''); ?>\" /> - -
    -
    "; - break; - } + $viewFields .= PHP_EOL . " +
    \"> + 'control-label')); ?> +
    + {$field_name}) ? \${$module_name_lower}->{$field_name} : ''); ?>\" /> + +
    +
    "; + break; + } } //------------------------------------------------------------------------------ @@ -138,14 +132,14 @@ //------------------------------------------------------------------------------ $delete = ''; if ($action_name != 'create') { - $delete_permission = preg_replace("/[ -]/", "_", ucfirst($module_name)) . '.' . ucfirst($controller_name) . '.Delete'; - $delete = " - auth->has_permission('{$delete_permission}')) : ?> - - - "; + $delete_permission = preg_replace("/[ -]/", "_", ucfirst($module_name)) . '.' . ucfirst($controller_name) . '.Delete'; + $delete = " + auth->has_permission('{$delete_permission}')) : ?> + + + "; } //------------------------------------------------------------------------------ @@ -153,16 +147,14 @@ //------------------------------------------------------------------------------ echo "
    - × -

    - -

    - + × +

    + +

    +
    -

    {$module_name}

    - uri->uri_string(), 'class=\"form-horizontal\"'); ?> -
    +

    {$module_name}

    + uri->uri_string(), 'class=\"form-horizontal\"'); ?> +
    {$viewFields}
    -
    - \" /> - - - {$delete} -
    +
    + \" /> + + + {$delete} +
    -
    "; \ No newline at end of file +"; diff --git a/bonfire/modules/database/config/config.php b/bonfire/modules/database/config/config.php index 8b1c28788..8a6e495d0 100644 --- a/bonfire/modules/database/config/config.php +++ b/bonfire/modules/database/config/config.php @@ -1,12 +1,13 @@ array( - 'developer' => 'database/developer/menu', - ), - 'author' => 'Bonfire Team', - 'description' => 'Provides tools for working with your database(s).', - 'menu_topic' => array( - 'developer' => 'lang:bf_menu_db_tools', - ), -); \ No newline at end of file + 'author' => 'Bonfire Team', + 'description' => 'Provides tools for working with your database(s).', + 'version' => '0.7.3', + 'menus' => array( + 'developer' => 'database/developer/menu', + ), + 'menu_topic' => array( + 'developer' => 'lang:bf_menu_db_tools', + ), +); diff --git a/bonfire/modules/database/controllers/Developer.php b/bonfire/modules/database/controllers/Developer.php index daefc58a8..7b2901d4b 100644 --- a/bonfire/modules/database/controllers/Developer.php +++ b/bonfire/modules/database/controllers/Developer.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 @@ -18,42 +18,42 @@ * Various tools to manage the Database tables. * * @package Bonfire\Modules\Database\Controllers\Developer - * @author Bonfire Dev Team + * @author Bonfire Dev Team * @link http://cibonfire.com/docs/developer */ class Developer extends Admin_Controller { /** @var string Path to the backups (relative to APPPATH) */ - private $backup_folder = 'db/backups/'; + private $backup_folder = 'db/backups/'; //-------------------------------------------------------------------------- - /** - * Constructor - * - * @return void - */ - public function __construct() - { - parent::__construct(); + /** + * Constructor + * + * @return void + */ + public function __construct() + { + parent::__construct(); - $this->auth->restrict('Bonfire.Database.Manage'); + $this->auth->restrict('Bonfire.Database.Manage'); $this->lang->load('database'); - $this->backup_folder = APPPATH . $this->backup_folder; + $this->backup_folder = APPPATH . $this->backup_folder; Assets::add_module_css('database', 'database'); - Template::set_block('sub_nav', 'developer/_sub_nav'); + Template::set_block('sub_nav', 'developer/_sub_nav'); } - /** + /** * Display a list of tables in the database. - * - * @return void - */ - public function index() - { + * + * @return void + */ + public function index() + { // Set the default toolbar_title for this page. The actions may change it. Template::set('toolbar_title', lang('database_title_maintenance')); @@ -62,84 +62,87 @@ public function index() // true to indicate that this method should not prep the form. $hideForm = false; if (isset($_POST['action'])) { - $checked = $this->input->post('checked'); + $checked = $this->input->post('checked'); switch ($this->input->post('action')) { - case 'backup': + case 'backup': $hideForm = $this->backup($checked); - break; - - case 'repair': - $this->repair($checked); - break; - - case 'optimize': - $this->optimize(); - break; - - case 'drop': + break; + case 'repair': + $this->repair($checked); + break; + case 'optimize': + $this->optimize(); + break; + case 'drop': $hideForm = $this->drop($checked); - break; - } - } + break; + default: + Template::set_message(lang('database_action_unknown'), 'warning'); + } + } if (! $hideForm) { // Load number helper for byte_format() function. - $this->load->helper('number'); + $this->load->helper('number'); Template::set('tables', $this->showTableStatus()); - } + } - Template::render(); + Template::render(); } - /** - * Browse the DB tables - * - * @param string $table Name of the table to browse - * - * @return void - */ - public function browse($table = '') - { + /** + * Browse the DB tables. + * + * Displays the table data when the user selects one of the linked table names + * from the index. + * + * @param string $table Name of the table to browse + * + * @return void + */ + public function browse($table = '') + { if (empty($table)) { Template::set_message(lang('database_no_table_name'), 'error'); redirect(SITE_AREA . '/developer/database'); - } + } - $query = $this->db->get($table); + $query = $this->db->get($table); if ($query->num_rows()) { - Template::set('rows', $query->result()); - } + Template::set('rows', $query->result()); + } - Template::set('query', $this->db->last_query()); + Template::set('num_rows', $query->num_rows()); + Template::set('query', $this->db->last_query()); Template::set('toolbar_title', sprintf(lang('database_browse'), $table)); - Template::render(); + Template::render(); } - /** - * List the existing backups - * - * @return void - */ - public function backups() - { + /** + * List the existing backups. + * + * @return void + */ + public function backups() + { if (isset($_POST['delete'])) { - // Make sure something is selected to delete - $checked = $this->input->post('checked'); + // Make sure something is selected to delete. + $checked = $this->input->post('checked'); if (empty($checked) || ! is_array($checked)) { // No files selected. Template::set_message(lang('database_backup_delete_none'), 'error'); } else { - // Delete the files. + // Delete the files. $failed = 0; foreach ($checked as $file) { $deleted = unlink($this->backup_folder . $file); if (! $deleted) { ++$failed; } - } + } $deletedCount = sprintf(lang('database_backup_deleted_count'), count($checked) - $failed); if ($failed == 0) { @@ -149,73 +152,73 @@ public function backups() "{$deletedCount}
    " . lang('database_backup_deleted_error'), 'error' ); - } - } - } + } + } + } // Load the number helper for the byte_format() function used in the view. $this->load->helper('number'); - // Get a list of existing backup files - $this->load->helper('file'); - Template::set('backups', get_dir_file_info($this->backup_folder)); + // Get a list of existing backup files + $this->load->helper('file'); + Template::set('backups', get_dir_file_info($this->backup_folder)); Template::set('toolbar_title', lang('database_title_backups')); - Template::render(); + Template::render(); } - /** - * Performs the actual backup. - * - * @param array $tables Array of tables - * - * @return bool - */ + /** + * Performs the actual backup. + * + * @param array $tables Array of tables + * + * @return bool + */ public function backup($tables = null) - { + { if (! empty($tables) && is_array($tables)) { // set_view() is used because execution most likely came here from index() // rather than via redirect or post. - Template::set_view('developer/backup'); + Template::set_view('developer/backup'); // Set the selected tables in the form. - Template::set('tables', $tables); + Template::set('tables', $tables); Template::set('file', ENVIRONMENT . '_backup_' . date('Y-m-j_His')); Template::set('toolbar_title', lang('database_title_backup_create')); // Return to index() and display the backup form. return true; - } + } if (isset($_POST['backup'])) { // The backup form has been posted, perform validation. - $this->load->library('form_validation'); + $this->load->library('form_validation'); $this->form_validation->set_rules('file_name', 'lang:database_filename', 'required|trim|max_length[220]'); $this->form_validation->set_rules('drop_tables', 'lang:database_drop_tables', 'required|trim|one_of[0,1]'); $this->form_validation->set_rules('add_inserts', 'lang:database_add_inserts', 'required|trim|one_of[0,1]'); $this->form_validation->set_rules('file_type', 'lang:database_compress_type', 'required|trim|one_of[txt,gzip,zip]'); - $this->form_validation->set_rules('tables', 'lang:database_tables', 'required|is_array'); + $this->form_validation->set_rules('tables[]', 'lang:database_tables', 'required'); if ($this->form_validation->run() !== false) { // Perform the backup. - $this->load->dbutil(); + $this->load->dbutil(); $format = $_POST['file_type']; $basename = $_POST['file_name'] . '.' . ($format == 'gzip' ? 'gz' : $format); $filename = "{$this->backup_folder}{$basename}"; - $prefs = array( + $prefs = array( 'add_drop' => ($_POST['drop_tables'] == '1'), 'add_insert' => ($_POST['add_inserts'] == '1'), 'format' => $format, - 'filename' => $filename, + 'filename' => $filename, 'tables' => $_POST['tables'], - ); - $backup =& $this->dbutil->backup($prefs); + ); + $backup = $this->dbutil->backup($prefs); - $this->load->helper('file'); - write_file($filename, $backup); + $this->load->helper('file'); + write_file($filename, $backup); if (file_exists($filename)) { Template::set_message( @@ -228,61 +231,60 @@ public function backup($tables = null) ); } else { Template::set_message(lang('database_backup_failure'), 'error'); - } + } redirect(SITE_AREA . '/developer/database'); - } + } // Validation failed. - Template::set('tables', $this->input->post('tables')); + Template::set('tables', $this->input->post('tables')); Template::set_message(lang('database_backup_failure_validation'), 'error'); - } + } Template::set('toolbar_title', lang('database_title_backup_create')); - Template::render(); + Template::render(); } - /** - * Do a force download on a backup file. - * - * @param string $filename Name of the file to download - * - * @return void - */ + /** + * Do a force download on a backup file. + * + * @param string $filename Name of the file to download. + * + * @return void + */ public function get_backup($filename = null) - { + { // CSRF could try `../../dev/temperamental-special-file` or `COM1` and the // possibility of that happening should really be prevented. if (preg_match('{[\\/]}', $filename) || ! fnmatch('*.*', $filename)) { - $this->security->csrf_show_error(); - } + $this->security->csrf_show_error(); + } $backupFile = "{$this->backup_folder}{$filename}"; - if (file_exists($backupFile)) { - $data = file_get_contents($backupFile); + if (! file_exists($backupFile)) { + Template::set_message(sprintf(lang('database_get_backup_error'), $filename), 'error'); + redirect(SITE_AREA . '/developer/database/backups'); + } - $this->load->helper('download'); - force_download($filename, $data); + $data = file_get_contents($backupFile); - redirect(SITE_AREA . '/developer/database/backups'); - } + $this->load->helper('download'); + force_download($filename, $data); - // File doesn't exist. - Template::set_message(sprintf(lang('database_get_backup_error'), $filename), 'error'); redirect(SITE_AREA . '/developer/database/backups'); } - /** - * Perform a restore from a database backup. - * - * @param string $filename Name of the file to restore - * - * @return void - */ + /** + * Perform a restore from a database backup. + * + * @param string $filename Name of the file to restore. + * + * @return void + */ public function restore($filename = null) - { - Template::set('filename', $filename); + { + Template::set('filename', $filename); if (isset($_POST['restore']) && ! empty($filename)) { $backupFile = "{$this->backup_folder}{$filename}"; @@ -300,10 +302,10 @@ public function restore($filename = null) $queryResults = array(); $currentQuery = ''; foreach ($file as $line) { - // Skip it if it's a comment + // Skip it if it's a comment. if (substr(trim($line), 0, 1) == '#') { continue; - } + } // Add this line to the current query. $currentQuery .= $line; @@ -311,99 +313,47 @@ public function restore($filename = null) // If there is no semicolon at the end, move on to the next line. if (substr(trim($line), -1, 1) != ';') { continue; - } + } // Found a semicolon, perform the query and store the results. if ($this->db->query($currentQuery)) { $queryResults[] = sprintf(lang('database_restore_out_successful'), $currentQuery); } else { $queryResults[] = sprintf(lang('database_restore_out_unsuccessful'), $currentQuery); - } + } - // Reset $currentQuery and start again. + // Reset $currentQuery and move on to the next line. $currentQuery = ''; - } + } - // Output the results + // Output the results. Template::set('results', implode('
    ', $queryResults)); - } + } // Show verification screen. - Template::set_view('developer/restore'); + Template::set_view('developer/restore'); Template::set('toolbar_title', lang('database_title_restore')); - Template::render(); } - /** - * Repair database tables. - * - * @param array $tables The names of tables to repair. - * - * @return void - */ - private function repair($tables = null) - { - if (empty($tables) || ! is_array($tables)) { - // No tables selected - Template::set_message(lang('database_repair_none'), 'error'); - redirect(SITE_AREA . '/developer/database'); - } - - $this->load->dbutil(); - - // Repair the tables, tracking the number of failures. - $failed = 0; - foreach ($tables as $table) { - if (! $this->dbutil->repair_table($table)) { - ++$failed; - } - } - - Template::set_message( - sprintf(lang('database_repair_success'), count($tables) - $failed, count($tables)), - $failed == 0 ? 'success' : 'info' - ); - - redirect(SITE_AREA . '/developer/database'); - } - - /** - * Optimize the entire database - * - * @return void - */ - private function optimize() - { - $this->load->dbutil(); - - if ($result = $this->dbutil->optimize_database()) { - Template::set_message(lang('database_optimize_success'), 'success'); - } else { - Template::set_message(lang('database_optimize_failure'), 'error'); - } - - redirect(SITE_AREA . '/developer/database'); - } - - /** - * Drop database tables. - * - * @param array $tables Array of table to drop - * - * @return bool - */ + /** + * Drop database tables. + * + * @param array $tables Array of table to drop + * + * @return bool + */ public function drop($tables = null) - { + { if (! empty($tables)) { // set_view() is used because execution most likely came here from index() // rather than via redirect or post. Template::set_view('developer/drop'); - Template::set('tables', $tables); + Template::set('tables', $tables); // Return to index() and display the verification screen. return true; - } + } if (empty($_POST['tables']) || ! is_array($_POST['tables'])) { // No tables were selected. @@ -412,22 +362,22 @@ public function drop($tables = null) } // Delete the tables.... - $this->load->dbforge(); + $this->load->dbforge(); $notDropped = 0; foreach ($_POST['tables'] as $table) { // dbforge automatically adds the prefix, so remove it, if present. // This may cause problems if there is a table with the prefix duplicated, // e.g. bf_bf_table. - $prefix = $this->db->dbprefix; + $prefix = $this->db->dbprefix; if (strncmp($table, $prefix, strlen($prefix)) === 0) { - $table = substr($table, strlen($prefix)); + $table = substr($table, strlen($prefix)); } if (@$this->dbforge->drop_table($table) === false) { ++$notDropped; - } - } + } + } $tableCount = count($_POST['tables']) - $notDropped; Template::set_message( @@ -439,7 +389,62 @@ public function drop($tables = null) ); redirect(SITE_AREA . '/developer/database'); - } + } + + //-------------------------------------------------------------------------- + // Private methods. + //-------------------------------------------------------------------------- + + /** + * Repair database tables. + * + * @param array $tables The names of tables to repair. + * + * @return void + */ + private function repair($tables = null) + { + if (empty($tables) || ! is_array($tables)) { + // No tables selected + Template::set_message(lang('database_repair_none'), 'error'); + redirect(SITE_AREA . '/developer/database'); + } + + $this->load->dbutil(); + + // Repair the tables, tracking the number of failures. + $failed = 0; + foreach ($tables as $table) { + if (! $this->dbutil->repair_table($table)) { + ++$failed; + } + } + + Template::set_message( + sprintf(lang('database_repair_success'), count($tables) - $failed, count($tables)), + $failed == 0 ? 'success' : 'info' + ); + + redirect(SITE_AREA . '/developer/database'); + } + + /** + * Optimize the entire database. + * + * @return void + */ + private function optimize() + { + $this->load->dbutil(); + + if ($result = $this->dbutil->optimize_database()) { + Template::set_message(lang('database_optimize_success'), 'success'); + } else { + Template::set_message(lang('database_optimize_failure'), 'error'); + } + + redirect(SITE_AREA . '/developer/database'); + } /** * Get the data returned by MySQL's 'SHOW TABLE STATUS'. @@ -450,7 +455,7 @@ public function drop($tables = null) * in the database. */ private function showTableStatus() - { + { // Since the table is built from a database-specific query, check the platform // to allow for other methods of generating the table. $platform = strtolower($this->db->platform()); @@ -461,7 +466,7 @@ private function showTableStatus() if (in_array($platform, array('mysql', 'mysqli', 'bfmysqli'))) { return $this->db->query('SHOW TABLE STATUS')->result(); - } + } // --------------------------------------------------------------------- // All other databases. @@ -495,4 +500,3 @@ private function showTableStatus() return $tables; } } -/* end /database/controllers/developer.php */ diff --git a/bonfire/modules/database/language/english/database_lang.php b/bonfire/modules/database/language/english/database_lang.php index 72ba72b75..92200a98d 100644 --- a/bonfire/modules/database/language/english/database_lang.php +++ b/bonfire/modules/database/language/english/database_lang.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 @@ -103,6 +103,14 @@ $lang['database_tables'] = 'Tables'; $lang['database_total_results'] = 'Total Results: %s'; +$lang['database_backup_tables'] = 'Backup Tables'; + +$lang['database_validation_errors_heading'] = 'Please fix the following errors:'; +$lang['database_action_unknown'] = 'An unsupported action was selected.'; + +$lang['form_validation_database_filename'] = 'File Name'; +$lang['form_validation_database_tables'] = 'Tables'; + // ----------------------------------------------------------------------------- // The remaining items appear to no longer be in use... // ----------------------------------------------------------------------------- diff --git a/bonfire/modules/database/views/developer/backup.php b/bonfire/modules/database/views/developer/backup.php index 6749140c0..a5106d328 100644 --- a/bonfire/modules/database/views/developer/backup.php +++ b/bonfire/modules/database/views/developer/backup.php @@ -1,5 +1,14 @@
    - + +
    + × +

    +

    +
    +

    @@ -8,64 +17,65 @@ echo form_open(SITE_AREA . '/developer/database/backup', 'class="form-horizontal"'); ?>
    - + - -
    + +

    -
    +
    -
    +
    -
    -
    +
    +
    -
    - +
    + -
    -
    +
    +
    -
    - + - + -
    -
    + +
    -
    - - + -
    -
    -
    +
    + +
    -
    -
    -

    : - -

    -
    + +
    + +
    + +
    +
    -
    - +
    + -
    - + diff --git a/bonfire/modules/database/views/developer/backups.php b/bonfire/modules/database/views/developer/backups.php index f89072c99..edca7cf2f 100644 --- a/bonfire/modules/database/views/developer/backups.php +++ b/bonfire/modules/database/views/developer/backups.php @@ -7,47 +7,47 @@
    -

    -
    -

    +
    + uri->uri_string()); ?> - - - - - +
    + + + + - - - - - - - - - - + + + + + + + + + $atts) : - // If the index.html file is present, don't display it + // If the index.html file is present, don't display it. if ($file == 'index.html') { continue; } ?> - - - + + + - - - - -
    - - -
    + + +
    - + + + + + diff --git a/bonfire/modules/database/views/developer/browse.php b/bonfire/modules/database/views/developer/browse.php index f71af99b4..44d986ccf 100644 --- a/bonfire/modules/database/views/developer/browse.php +++ b/bonfire/modules/database/views/developer/browse.php @@ -1,31 +1,32 @@
    -

    :

    -

    +

    :

    +

    - +
    - +
    -

    +

    - - - - $value) : ?> - - - - - - - - $value) : ?> - - - - - -
    + + + + $value) : ?> + + + + + + + + $value) : ?> + + + + + +
    -

    -
    -
    +
    diff --git a/bonfire/modules/docs/controllers/Docs.php b/bonfire/modules/docs/controllers/Docs.php index 6854d3492..3aa57ef4b 100644 --- a/bonfire/modules/docs/controllers/Docs.php +++ b/bonfire/modules/docs/controllers/Docs.php @@ -1,5 +1,28 @@ docsGroup == 'search') { $this->docsGroup = false; - } elseif ($this->docsGroup == 'developer' + } elseif ($this->docsGroup == $this->docsTypeBf && ! $this->showDevDocs && ENVIRONMENT != 'development' ) { @@ -144,9 +167,9 @@ private function build_sidebar() // Get the list of docs based on the current docs group // (application-specific or developer docs) - if ($this->docsGroup == 'application') { + if ($this->docsGroup == $this->docsTypeApp) { $data['docs'] = $this->get_folder_files(APPPATH . $this->docsDir, $this->docsTypeApp); - } elseif ($this->docsGroup == 'developer') { + } elseif ($this->docsGroup == $this->docsTypeBf) { $data['docs'] = $this->get_folder_files(BFPATH . $this->docsDir, $this->docsTypeBf); } @@ -186,7 +209,7 @@ private function get_folder_files($folder, $type, $ignoredFolders = array()) // If the toc file does not exist, build the links by listing the files // in the directory (and any sub-directories) $this->load->helper('directory'); - $map = directory_map($folder); + $map = bcDirectoryMap($folder); // If directory_map can not open the directory or find any files inside // the directory, return an empty array. @@ -265,6 +288,7 @@ private function get_module_docs() } } } + ksort($docs_modules); return $docs_modules; } diff --git a/bonfire/modules/docs/libraries/docsearch.php b/bonfire/modules/docs/libraries/docsearch.php index c53170386..87605be26 100644 --- a/bonfire/modules/docs/libraries/docsearch.php +++ b/bonfire/modules/docs/libraries/docsearch.php @@ -1,4 +1,19 @@ -ci =& get_instance(); $this->ci->load->helper('text'); - $this->ci->load->library('CommonMark'); } - //-------------------------------------------------------------------- - /** * The entry point for performing a search of the documentation. * @@ -75,27 +74,22 @@ public function __construct () * * @return array|null */ - public function search ($terms=null, $folders=array()) + public function search ($terms = null, $folders = array()) { - if (empty($terms) || empty($folders)) - { - return NULL; + if (empty($terms) || empty($folders)) { + return null; } $this->ci->load->helper('directory'); $results = array(); - - foreach ($folders as $folder) - { - $results = array_merge($results, $this->search_folder($terms, $folder) ); + foreach ($folders as $folder) { + $results = array_merge($results, $this->search_folder($terms, $folder)); } return $results; } - //-------------------------------------------------------------------- - /** * Searches a single directory worth of files. * @@ -104,70 +98,65 @@ public function search ($terms=null, $folders=array()) * * @return array The results. */ - private function search_folder ($term, $folder) + private function search_folder($term, $folder) { $results = array(); - $map = directory_map($folder, 2); // Make sure we have something to work with. - if ( ! is_array($map) || (is_array($map) && ! count($map))) - { + if (empty($map) || ! is_array($map)) { return array(); } // Loop over each file and search the contents for our term. - foreach ($map as $dir => $file) - { + foreach ($map as $dir => $file) { $file_count = 0; - if (in_array($file, $this->skip_files)) - { + if (in_array($file, $this->skip_files)) { continue; } // Is it a folder? - if (is_array($dir) && count($dir)) - { - $results = array_merge($results, $this->search_folder($terms, $folder .'/'. $dir)); + if (is_array($file) && count($file)) { + $results = array_merge($results, $this->search_folder($term, "{$folder}/{$dir}")); continue; } // Make sure it's the right file type... - if ( ! preg_match("/({$this->allowed_file_types})/i", $file)) - { + if (! preg_match("/({$this->allowed_file_types})/i", $file)) { continue; } - $path = $folder .'/'. $file; - $term_html = htmlentities($term); + $path = $folder .'/'. $file; + $term_html = htmlentities($term); // Read in the file text - $handle = fopen($path, 'r'); - $text = fread($handle, $this->byte_size); + $handle = fopen($path, 'r'); + $text = fread($handle, $this->byte_size); // Do we have a match in here somewhere? - $found = stristr($text, $term) || stristr($text, $term_html); + $found = stristr($text, $term) || stristr($text, $term_html); - if ( ! $found) - { + if (! $found) { continue; } - // Escape our terms to safely use in a preg_match - $excerpt = strip_tags($text); - $term = preg_quote($term); - $term = str_replace("/", "\/", "{$term}"); - $term_html = preg_quote($term_html); - $term_html = str_replace("/", "\/", "{$term_html}"); + // Escape our terms to safely use in a preg_match. + $excerpt = strip_tags($text); + $term = preg_quote($term); + $term = str_replace("/", "\/", "{$term}"); + $term_html = preg_quote($term_html); + $term_html = str_replace("/", "\/", "{$term_html}"); // Add the item to our results with extracts. - if ( preg_match_all("/((\s\S*){0,3})($term|$term_html)((\s?\S*){0,3})/i", $excerpt, $matches, PREG_OFFSET_CAPTURE | PREG_SET_ORDER) ) - { - foreach ($matches as $match) - { - if ($file_count >= $this->max_per_file) - { + if (preg_match_all( + "/((\s\S*){0,3})($term|$term_html)((\s?\S*){0,3})/i", + $excerpt, + $matches, + PREG_OFFSET_CAPTURE | PREG_SET_ORDER + )) { + foreach ($matches as $match) { + if ($file_count >= $this->max_per_file) { continue; } @@ -176,13 +165,13 @@ private function search_folder ($term, $folder) $result_url = str_replace(APPPATH, 'application/', $result_url); $results[] = array( - 'title' => $this->extract_title($excerpt, $file), - 'file' => $folder .'/'. $file, - 'url' => $result_url, - 'extract' => $this->build_extract($excerpt, $term, $match[0][0]) + 'title' => $this->extract_title($excerpt, $file), + 'file' => $folder .'/'. $file, + 'url' => $result_url, + 'extract' => $this->build_extract($excerpt, $term, $match[0][0]) ); - $file_count++; + ++$file_count; } } } @@ -190,8 +179,6 @@ private function search_folder ($term, $folder) return $results; } - //-------------------------------------------------------------------- - /** * Handles extracting the text surrounding our match and basic match formatting. * @@ -201,7 +188,7 @@ private function search_folder ($term, $folder) * * @return string */ - private function build_extract ($excerpt, $term, $match_string) + private function build_extract($excerpt, $term, $match_string) { // Find the character positions within the string that our match was found at. // That way we'll know from what positions before and after this we want to grab it in. @@ -212,12 +199,12 @@ private function build_extract ($excerpt, $term, $match_string) // Adjust our start position $start_offset = $start_offset - $buffer; - if ($start_offset < 0) $start_offset = 0; + if ($start_offset < 0) { + $start_offset = 0; + } $extract = substr($excerpt, $start_offset); - $extract = strip_tags($this->ci->commonmark->convert($extract)); - $extract = character_limiter($extract, $this->excerpt_length); // Wrap the search term in a span we can style. @@ -226,8 +213,6 @@ private function build_extract ($excerpt, $term, $match_string) return $extract; } - //-------------------------------------------------------------------- - /** * Extracts the title from a bit of markdown formatted text. If it doesn't * have an h1 or h2, then it uses the filename. @@ -236,28 +221,24 @@ private function build_extract ($excerpt, $term, $match_string) * @param $file * @return string */ - private function extract_title ($excerpt, $file) + private function extract_title($excerpt, $file) { $title = ''; // Easiest to work if this is split into lines. $lines = explode("\n", $excerpt); - if (is_array($lines) && count($lines)) - { - foreach ($lines as $line) - { - if (strpos($line, '# ') === 0 || strpos($line, '## ') === 0) - { - $title = trim( str_replace('#', '', $line) ); + if (! empty($lines) && is_array($lines)) { + foreach ($lines as $line) { + if (strpos($line, '# ') === 0 || strpos($line, '## ') === 0) { + $title = trim(str_replace('#', '', $line)); break; } } } // If it's empty, we'll use the filename. - if (empty($title)) - { + if (empty($title)) { $title = str_replace('_', ' ', $file); $title = str_replace('.md', ' ', $title); $title = ucwords($title); @@ -265,7 +246,4 @@ private function extract_title ($excerpt, $file) return $title; } - - //-------------------------------------------------------------------- - -} \ No newline at end of file +} diff --git a/bonfire/modules/docs/views/_sidebar.php b/bonfire/modules/docs/views/_sidebar.php index 817b83e08..9efb28282 100644 --- a/bonfire/modules/docs/views/_sidebar.php +++ b/bonfire/modules/docs/views/_sidebar.php @@ -1,7 +1,9 @@
    -
    - + -
    - -
    + ?> +
    + + + -

    'form-horizontal')); ?> @@ -55,8 +55,9 @@
    - - - + \ No newline at end of file diff --git a/bonfire/modules/migrations/config/config.php b/bonfire/modules/migrations/config/config.php index a4e02f3eb..5156606b1 100644 --- a/bonfire/modules/migrations/config/config.php +++ b/bonfire/modules/migrations/config/config.php @@ -1,10 +1,11 @@ 'Helps maintain database versioning.', - 'author' => 'Bonfire Team', - 'menu_topic' => array( - 'developer' => 'lang:bf_menu_db_tools', - ), - 'name' => 'lang:bf_menu_migrations', -); \ No newline at end of file + 'description' => 'Helps maintain database versioning.', + 'author' => 'Bonfire Team', + 'version' => '0.7.3', + 'name' => 'lang:bf_menu_migrations', + 'menu_topic' => array( + 'developer' => 'lang:bf_menu_db_tools', + ), +); diff --git a/bonfire/modules/roles/config/config.php b/bonfire/modules/roles/config/config.php index cdef61405..cf62e8a87 100644 --- a/bonfire/modules/roles/config/config.php +++ b/bonfire/modules/roles/config/config.php @@ -1,7 +1,8 @@ 'Provides Role-Based Access Control for users.', - 'author' => 'Bonfire Team', - 'name' => 'lang:bf_menu_roles', -); \ No newline at end of file + 'author' => 'Bonfire Team', + 'description' => 'Provides Role-Based Access Control for users.', + 'name' => 'lang:bf_menu_roles', + 'version' => '0.7.3', +); diff --git a/bonfire/modules/roles/controllers/Settings.php b/bonfire/modules/roles/controllers/Settings.php index 95e7f114b..6d588fe98 100644 --- a/bonfire/modules/roles/controllers/Settings.php +++ b/bonfire/modules/roles/controllers/Settings.php @@ -1,4 +1,4 @@ -auth->restrict('Site.Settings.View'); - $this->auth->restrict('Bonfire.Roles.View'); - - $this->load->model('role_model'); - $this->lang->load('roles'); - - Assets::add_module_css('roles', 'css/settings.css'); - - Assets::add_js('codeigniter-csrf.js'); - Assets::add_module_js('roles', 'jquery.tablehover.pack.js'); - Assets::add_module_js('roles', 'js/settings.js'); - - // For the render_search_box() - $this->load->helper('ui/ui'); - - Template::set_block('sub_nav', 'settings/_sub_nav'); - } - - /** - * Display a list of all roles - * - * @return void - */ - public function index() - { - // Get User Counts - Template::set('deleted_users', $this->user_model->count_all(true)); - Template::set('role_counts', $this->user_model->count_by_roles()); - Template::set('total_users', $this->user_model->count_all()); - - Template::set('roles', $this->role_model->where('deleted', 0)->find_all()); - - Template::set('toolbar_title', lang("role_manage")); - Template::render(); - } - - /** - * Create a new role in the database - * - * @return void - */ - public function create() - { - $this->auth->restrict('Bonfire.Roles.Add'); - - if (isset($_POST['save'])) { - if ($this->save_role()) { - Template::set_message(lang('role_create_success'), 'success'); - redirect(SITE_AREA . '/settings/roles'); - } else { - Template::set_message(lang('role_create_error') . $this->role_model->error, 'error'); - } - } - - Template::set('contexts', list_contexts(true)); + private $permissionContext = 'Site.Settings.View'; + private $permissionCreate = 'Bonfire.Roles.Add'; + private $permissionEdit = 'Bonfire.Roles.Manage'; + private $permissionView = 'Bonfire.Roles.View'; + + /** + * Setup the required permissions and load required classes + * + * @return void + */ + public function __construct() + { + parent::__construct(); + + $this->auth->restrict($this->permissionContext); + $this->auth->restrict($this->permissionView); + + $this->load->model('role_model'); + $this->lang->load('roles'); + + Assets::add_module_css('roles', 'css/settings.css'); + + Assets::add_js('codeigniter-csrf.js'); + Assets::add_module_js('roles', 'jquery.tablehover.pack.js'); + Assets::add_module_js('roles', 'js/settings.js'); + + // For the render_search_box() + $this->load->helper('ui/ui'); + + Template::set_block('sub_nav', 'settings/_sub_nav'); + } + + /** + * Display a list of all roles + * + * @return void + */ + public function index() + { + // Get User Counts + Template::set('deleted_users', $this->user_model->count_all(true)); + Template::set('role_counts', $this->user_model->count_by_roles()); + Template::set('total_users', $this->user_model->count_all()); + + Template::set('roles', $this->role_model->where('deleted', 0)->find_all()); + + Template::set('toolbar_title', lang('role_manage')); + Template::render(); + } + + /** + * Create a new role in the database + * + * @return void + */ + public function create() + { + $this->auth->restrict($this->permissionCreate); + + if (isset($_POST['save'])) { + if ($this->saveRole()) { + Template::set_message(lang('role_create_success'), 'success'); + if (! empty($this->error)) { + Template::set_message(lang('role_create_error') . $this->error, 'error'); + } + redirect(SITE_AREA . '/settings/roles'); + } + + if (! empty($this->role_model->error)) { + Template::set_message(lang('role_create_error') . $this->role_model->error, 'error'); + } + } + + if (! class_exists('Contexts', false)) { + $this->load->library('ui/contexts'); + } + + Template::set_view('settings/role_form'); + Template::set('contexts', Contexts::getContexts(true)); Template::set('toolbar_title', 'Create New Role'); - Template::set_view('settings/role_form'); - Template::render(); - } - - /** - * Edit a role record - * - * @return void - */ - public function edit() - { - $this->auth->restrict('Bonfire.Roles.Manage'); - - $id = (int)$this->uri->segment(5); - if (empty($id)) { - Template::set_message(lang('role_invalid_id'), 'error'); - redirect(SITE_AREA . '/settings/roles'); - } - - if (isset($_POST['save'])) { - if ($this->save_role('update', $id)) { - Template::set_message(lang('role_edit_success'), 'success'); - redirect(SITE_AREA . '/settings/roles'); - } else { - Template::set_message(lang('role_edit_error') . $this->role_model->error, 'error'); - } - } elseif (isset($_POST['delete'])) { - if ($this->role_model->delete($id)) { - Template::set_message(lang('role_delete_success'), 'success'); - redirect(SITE_AREA . '/settings/roles'); - } else { - Template::set_message(lang('role_delete_error') . $this->role_model->error, 'error'); - } - } - - $role = $this->role_model->find($id); + + Template::render(); + } + + /** + * Edit a role record + * + * @return void + */ + public function edit() + { + $this->auth->restrict($this->permissionEdit); + + $id = (int) $this->uri->segment(5); + if (empty($id)) { + Template::set_message(lang('role_invalid_id'), 'error'); + redirect(SITE_AREA . '/settings/roles'); + } + + if (isset($_POST['save'])) { + if ($this->saveRole('update', $id)) { + Template::set_message(lang('role_edit_success'), 'success'); + redirect(SITE_AREA . '/settings/roles'); + } + if (! empty($this->role_model->error)) { + Template::set_message(lang('role_edit_error') . $this->role_model->error, 'error'); + } + } elseif (isset($_POST['delete'])) { + if ($this->role_model->delete($id)) { + Template::set_message(lang('role_delete_success'), 'success'); + redirect(SITE_AREA . '/settings/roles'); + } + if (! empty($this->role_model->error)) { + Template::set_message(lang('role_delete_error') . $this->role_model->error, 'error'); + } + } + + if (! class_exists('Contexts', false)) { + $this->load->library('ui/contexts'); + } + $title = lang('bf_action_edit') . ' ' . lang('matrix_role'); + $role = $this->role_model->find($id); - Template::set('role', $role); - Template::set('contexts', list_contexts(true)); + Template::set_view('settings/role_form'); + Template::set('contexts', Contexts::getContexts(true)); + Template::set('role', $role); Template::set('toolbar_title', isset($role->role_name) ? "{$title}: {$role->role_name}" : $title); - Template::set_view('settings/role_form'); - Template::render(); - } - - //-------------------------------------------------------------------- - // !HMVC METHODS - //-------------------------------------------------------------------- - - /** - * Build the matrix for display in the role permissions form. - * - * @return string The table(s) of settings, ready to be used in a form. - */ - public function matrix() - { - $id = (int)$this->uri->segment(5); - $role = $this->role_model->find($id); - - // If the ID is empty, we are working with a new role and won't have - // permissions to show. - if ($id == 0) { - return '
    ' . lang('role_new_permission_message') . '
    '; - } + + Template::render(); + } + + //-------------------------------------------------------------------- + // !HMVC METHODS + //-------------------------------------------------------------------- + + /** + * Build the matrix for display in the role permissions form. + * + * @return string The table(s) of settings, ready to be used in a form. + */ + public function matrix() + { + $id = (int) $this->uri->segment(5); + $role = $this->role_model->find($id); + + // ID is empty for a new role, so permissions won't be assigned, yet. + if ($id == 0) { + return '
    ' . lang('role_new_permission_message') . '
    '; + } $auth_failed = ''; $domains = ''; - // Verify role has permission to modify this role's access control - if ($this->auth->has_permission('Permissions.' . ucwords($role->role_name) . '.Manage')) { - $permissions_full = $role->permissions; - $role_permissions = $role->role_permissions; - - $template = array(); - foreach ($permissions_full as $key => $perm) { - $template[$perm->name]['perm_id'] = $perm->permission_id; - $template[$perm->name]['value'] = 0; - if (isset($role_permissions[$perm->permission_id])) { - $template[$perm->name]['value'] = 1; - } - } - - // Extract our pieces from each permission - $domains = array(); - foreach ($template as $key => $value) { - list($domain, $name, $action) = explode('.', $key); - - // Add it to the domain if it's not already there. - if ( ! empty($domain) && ! array_key_exists($domain, $domains)) { - $domains[$domain] = array(); - } - - // Add the preference to the domain array - if (isset($domains[$domain][$name])) { + // Verify role has permission to modify this role's permissions. + if (! $this->auth->has_permission('Permissions.' . ucwords($role->role_name) . '.Manage')) { + $auth_failed = lang('matrix_auth_fail'); + } else { + $permissions_full = $role->permissions; + $role_permissions = $role->role_permissions; + + $template = array(); + foreach ($permissions_full as $key => $perm) { + $template[$perm->name]['perm_id'] = $perm->permission_id; + $template[$perm->name]['value'] = 0; + if (isset($role_permissions[$perm->permission_id])) { + $template[$perm->name]['value'] = 1; + } + } + + // Extract the pieces from each permission. + $domains = array(); + foreach ($template as $key => $value) { + list($domain, $name, $action) = explode('.', $key); + + // Add it to the domain if it's not already there. + if (! empty($domain) && ! array_key_exists($domain, $domains)) { + $domains[$domain] = array(); + } + + // Add the preference to the domain array. + if (isset($domains[$domain][$name])) { $domains[$domain][$name][$action] = $value; } else { - $domains[$domain][$name] = array( - $action => $value - ); - } - - // Store the actions separately for building the table header - if ( ! isset($domains[$domain]['actions'])) { - $domains[$domain]['actions'] = array(); - } - - if ( ! in_array($action, $domains[$domain]['actions'])) { - $domains[$domain]['actions'][] = $action; - } - } - } - // If the role does not have the Manage permission - else { - $auth_failed = lang('matrix_auth_fail'); - } - - // Build the table(s) in the view to make things a little clearer, - // and return it! - return $this->load->view('settings/matrix', array('domains' => $domains, 'authentication_failed' => $auth_failed), true); - } - - //-------------------------------------------------------------------- - // !PRIVATE METHODS - //-------------------------------------------------------------------- - - /** - * Save the role record to the database - * - * @param string $type The type of save operation (insert or edit) - * @param int $id The record ID in the case of edit - * - * @return bool - */ - private function save_role($type = 'insert', $id = 0) - { - if ($type == 'insert') { - $this->form_validation->set_rules('role_name', 'lang:role_name', 'required|trim|unique[roles.role_name]|max_length[60]'); - } else { - $_POST['role_id'] = $id; - $this->form_validation->set_rules('role_name', 'lang:role_name', 'required|trim|unique[roles.role_name,roles.role_id]|max_length[60]'); - } - - $this->form_validation->set_rules('description', 'lang:bf_description', 'trim|max_length[255]'); - $this->form_validation->set_rules('login_destination', 'lang:role_login_destination', 'trim|max_length[255]'); - $this->form_validation->set_rules('default_context', 'lang:role_default_context', 'trim'); - $this->form_validation->set_rules('default', 'lang:role_default_role', 'trim|is_numeric|max_length[1]'); - $this->form_validation->set_rules('can_delete', 'lang:role_can_delete_role', 'trim|is_numeric|max_length[1]'); - - if ($this->form_validation->run() === false) { - return false; - } - - unset($_POST['save']); - - // Grab the permissions from the POST vars, if available. - $permissions = $this->input->post('role_permissions'); - unset($_POST['role_permissions']); - - if ($type == 'insert') { - $id = $this->role_model->insert($_POST); + $domains[$domain][$name] = array( + $action => $value + ); + } + + // Store the actions separately to build the table header. + if (! isset($domains[$domain]['actions'])) { + $domains[$domain]['actions'] = array(); + } + + if (! in_array($action, $domains[$domain]['actions'])) { + $domains[$domain]['actions'][] = $action; + } + } + } + + // Build the table(s) in the view to make things a little clearer, + // and return it! + return $this->load->view( + 'settings/matrix', + array('domains' => $domains, 'authentication_failed' => $auth_failed), + true + ); + } + + //-------------------------------------------------------------------- + // !PRIVATE METHODS + //-------------------------------------------------------------------- + + /** + * Save the role record to the database. + * + * @param string $type The type of save operation (insert or edit). + * @param integer $id The record ID in the case of edit (ignored on insert). + * + * @return boolean + */ + private function saveRole($type = 'insert', $id = 0) + { + $this->form_validation->set_rules($this->role_model->get_validation_rules($type)); + if ($this->form_validation->run() === false) { + return false; + } + + // Grab the permissions and role name from the POST vars, if available. + $permissions = $this->input->post('role_permissions'); + $roleName = $this->input->post('role_name'); + $data = $this->role_model->prep_data($this->input->post()); + + if ($type == 'insert') { + $id = $this->role_model->insert($data); $return = is_numeric($id); - } elseif ($type == 'update') { - $return = $this->role_model->update($id, $_POST); - } + } elseif ($type == 'update') { + $return = $this->role_model->update($id, $data); + } - if ( ! $return) { + if (! $return) { return $return; } - // Add a new management permission for the role. - if ($type == 'insert') { - $roleName = ucwords($this->input->post('role_name')); - $add_perm = array( - 'name' => "Permissions.{$roleName}.Manage", - 'description' => "To manage the access control permissions for the {$roleName} role.", - 'status' => 'active' - ); - - if ($this->permission_model->insert($add_perm)) { - // Give current_role, or admin fallback, new Manage permission - $roleId = false; + // Reset validation so the permission model can use it. + $this->form_validation->reset_validation(); + if (! class_exists('permission_model', false)) { + $this->load->model('permissions/permission_model'); + } + + // Add a new management permission for the role. + $new_perm_name = 'Permissions.' . ucwords($roleName) . '.Manage'; + + 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) { + $this->error = 'There was an error creating the ACL permission.'; + if (! empty($this->permission_model->error)) { + $this->error .= " {$this->permission_model->error}"; + } + } else { + // Give current_role and admin new Manage permission. + $roleIds = array(1); if (class_exists('auth')) { $roleId = $this->auth->role_id(); + if ($roleId != false) { + $rolesIds[] = $roleId; + } + } + + $rolePermissions = array(); + foreach ($roleIds as $roleId) { + $rolePermissions[] = array( + 'role_id' => $roleId, + 'permission_id' => $permissionId, + ); } - $assign_role = $roleId ?: 1; - - $this->db->insert('role_permissions', array( - 'role_id' => $assign_role, - 'permission_id' => $this->db->insert_id(), - )); - } else { - $this->error = 'There was an error creating the ACL permission.'; - } - } - // Update - else { - // Grab the current role model name - $current_name = $this->role_model->find($id)->role_name; - - // update the permission name (did it this way for brevity on the update_where line) - $new_perm_name = 'Permissions.' . ucwords($this->input->post('role_name')) . '.Manage'; - $old_perm_name = 'Permissions.' . ucwords($current_name) . '.Manage'; - $this->permission_model->update_where('name', $old_perm_name, array('name' => $new_perm_name)); - } - - // Save the permissions. - if ($permissions + + // Reset validation so the role_permissions model can use it. + $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; + + // Update the permission name. + $this->permission_model->update_where( + 'name', + 'Permissions.' . ucwords($current_name) . '.Manage', + array('name' => $new_perm_name) + ); + } + + // Reset validation so the role_permissions model can use it. + $this->form_validation->reset_validation(); + + // Save the permissions. + if ($permissions && ! $this->role_permission_model->set_for_role($id, $permissions) ) { - $this->error = 'There was an error saving the permissions.'; - } - - return $return; - } - - /** - * Create a real-time modifiable summary table of all roles and permissions - * - * @return void - */ - public function permission_matrix() - { - // For the permission matrix - $this->load->helper('inflector'); - - Template::set( + $this->error = 'There was an error saving the permissions.'; + } + + return $return; + } + + /** + * Create a real-time modifiable summary table of all roles and permissions + * + * @return void + */ + public function permission_matrix() + { + // For the permission matrix + $this->load->helper('inflector'); + + Template::set( 'matrix_permissions', $this->permission_model->select('permission_id, name') ->order_by('name') ->find_all() ); - Template::set( + Template::set( 'matrix_roles', $this->role_model->select('role_id, role_name') ->where('deleted', 0) ->find_all() ); - $role_permissions = $this->role_permission_model->find_all_role_permissions(); - foreach ($role_permissions as $rp) { - $current_permissions[] = "{$rp->role_id},{$rp->permission_id}"; - } + $role_permissions = $this->role_permission_model->find_all_role_permissions(); + foreach ($role_permissions as $rp) { + $current_permissions[] = "{$rp->role_id},{$rp->permission_id}"; + } - Template::set('matrix_role_permissions', $current_permissions); - Template::set("toolbar_title", lang('matrix_header')); + Template::set('matrix_role_permissions', $current_permissions); + Template::set("toolbar_title", lang('matrix_header')); - Template::set_view('settings/permission_matrix'); - Template::render(); - } + Template::set_view('settings/permission_matrix'); + Template::render(); + } - /** - * Update the role_permissions table. - * - * @return void - */ - public function matrix_update() - { - // Disable the profile for AJAX response - $this->output->enable_profiler(false); + /** + * Update the role_permissions table. + * + * @return void + */ + public function matrix_update() + { + // Disable the profile for AJAX response + $this->output->enable_profiler(false); - $pieces = explode(',', $this->input->post('role_perm')); + $pieces = explode(',', $this->input->post('role_perm')); - if ( ! $this->auth->has_permission('Permissions.' . $this->role_model->find((int)$pieces[0])->role_name . '.Manage')) { - $this->output->set_output(lang("matrix_auth_fail")); + if (! $this->auth->has_permission('Permissions.' . $this->role_model->find((int)$pieces[0])->role_name . '.Manage')) { + $this->output->set_output(lang("matrix_auth_fail")); - return; - } + return; + } // A box was checked - if ($this->input->post('action') == 'true') { - if (is_numeric($this->role_permission_model->create_role_permissions($pieces[0], $pieces[1]))) { - $msg = lang("matrix_insert_success"); - } else { - $msg = lang("matrix_insert_fail") . $this->role_permission_model->error; - } - } - // A box was unchecked - else { - if ($this->role_permission_model->delete_role_permissions($pieces[0], $pieces[1])) { - $msg = lang("matrix_delete_success"); - } else { - $msg = lang("matrix_delete_fail"). $this->role_permission_model->error; - } - } - - $this->output->set_output($msg); - } + if ($this->input->post('action') == 'true') { + if (is_numeric($this->role_permission_model->create_role_permissions($pieces[0], $pieces[1]))) { + $msg = lang("matrix_insert_success"); + } else { + $msg = lang("matrix_insert_fail") . $this->role_permission_model->error; + } + } else { + // A box was unchecked + if ($this->role_permission_model->delete_role_permissions($pieces[0], $pieces[1])) { + $msg = lang("matrix_delete_success"); + } else { + $msg = lang("matrix_delete_fail"). $this->role_permission_model->error; + } + } + + $this->output->set_output($msg); + } } -/* end /bonfire/modules/roles/controllers/settings.php */ \ No newline at end of file diff --git a/bonfire/modules/roles/language/english/roles_lang.php b/bonfire/modules/roles/language/english/roles_lang.php index 0ad2d4972..dc18bfe8b 100644 --- a/bonfire/modules/roles/language/english/roles_lang.php +++ b/bonfire/modules/roles/language/english/roles_lang.php @@ -1,4 +1,4 @@ - +/** + * Roles Language File (Persian) + * + * @package Bonfire\Modules\Roles\Language\Persian + * @author Sajjad Servatjoo + * @author Bonfire Dev Team + * @link http://cibonfire.com/docs/bonfire/roles_and_permissions + */ -$lang['role_intro'] = 'نقش ها به شما امکان می دهند که تعیین کنید کاربران چه کار هایی را میتوانند انجام دهند.'; -$lang['role_manage'] = 'مديريت نقش کاربران'; -$lang['role_no_roles'] = 'هيچ نقشي در سيستم وجود ندارد.'; -$lang['role_create_button'] = 'ايجاد نقش جديد.'; -$lang['role_create_note'] = 'هر کاربري نياز به نقش دارد. از داشتن تمام موارد مورد نياز مطمئن شويد.'; -$lang['role_account_type'] = 'نوع حساب کاربری'; -$lang['role_description'] = 'توزيع حساب کاربري'; -$lang['role_details'] = 'مشخصات نقش'; +$lang['role_intro'] = 'نقش ها به شما امکان می دهند که تعیین کنید کاربران چه کار هایی را میتوانند انجام دهند.'; +$lang['role_manage'] = 'مديريت نقش کاربران'; +$lang['role_no_roles'] = 'هيچ نقشي در سيستم وجود ندارد.'; +$lang['role_create_button'] = 'ايجاد نقش جديد.'; +$lang['role_create_note'] = 'هر کاربري نياز به نقش دارد. از داشتن تمام موارد مورد نياز مطمئن شويد.'; +$lang['role_account_type'] = 'نوع حساب کاربری'; +$lang['role_description'] = 'توزيع حساب کاربري'; +$lang['role_details'] = 'مشخصات نقش'; -$lang['role_name'] = 'نام نقش'; -$lang['role_max_desc_length'] = 'حد اکثر 255 کاراکتر.'; -$lang['role_default_role'] = 'نقش پيش فرض'; -$lang['role_default_note'] = 'اگر تمام کاربران جديد شمامل اين نقش باشند اين گزينه را علامت بزنيد.'; -$lang['role_permissions'] = 'مجوز هاي دسترسي'; -$lang['role_permissions_check_note']= 'تمام مجوز هاي مربوط به اين نقش را علامت بزنيد.'; -$lang['role_save_role'] = 'ذخيره مجوز'; -$lang['role_delete_role'] = 'حذف اين مجوز'; -$lang['role_delete_confirm'] = 'آیا از حذف این مجوز اطمینان دارید؟'; -$lang['role_delete_note'] = 'حذف اين نقش باعث تبديل تمامي کاربران اين نقش به نقش پيشفرض سايت خواهد شد.'; -$lang['role_can_delete_role'] = 'قابل حذف'; -$lang['role_can_delete_note'] = 'آيا اين نقش قابل حذف مي باشد؟'; +$lang['role_name'] = 'نام نقش'; +$lang['role_max_desc_length'] = 'حد اکثر 255 کاراکتر.'; +$lang['role_default_role'] = 'نقش پيش فرض'; +$lang['role_default_note'] = 'اگر تمام کاربران جديد شمامل اين نقش باشند اين گزينه را علامت بزنيد.'; +$lang['role_permissions'] = 'مجوز هاي دسترسي'; +$lang['role_permissions_check_note'] = 'تمام مجوز هاي مربوط به اين نقش را علامت بزنيد.'; +$lang['role_save_role'] = 'ذخيره مجوز'; +$lang['role_delete_role'] = 'حذف اين مجوز'; +$lang['role_delete_confirm'] = 'آیا از حذف این مجوز اطمینان دارید؟'; +$lang['role_delete_note'] = 'حذف اين نقش باعث تبديل تمامي کاربران اين نقش به نقش پيشفرض سايت خواهد شد.'; +$lang['role_can_delete_role'] = 'قابل حذف'; +$lang['role_can_delete_note'] = 'آيا اين نقش قابل حذف مي باشد؟'; -$lang['role_roles'] = 'نقش ها'; -$lang['role_new_role'] = 'نقش جديد'; -$lang['role_new_permission_message'] = 'پس از ایجاد نقش باید مجوز های آن نقش را تعیین کنید.'; -$lang['role_not_used'] = 'استفاده نشده'; +$lang['role_roles'] = 'نقش ها'; +$lang['role_new_role'] = 'نقش جديد'; +$lang['role_new_permission_message'] = 'پس از ایجاد نقش باید مجوز های آن نقش را تعیین کنید.'; +$lang['role_not_used'] = 'استفاده نشده'; -$lang['role_login_destination'] = 'مقصد ورود'; -$lang['role_destination_note'] = 'آدرس محلي از سايت که کاربر پس از ورود به آنجا منتقل شود.'; +$lang['role_login_destination'] = 'مقصد ورود'; +$lang['role_destination_note'] = 'آدرس محلي از سايت که کاربر پس از ورود به آنجا منتقل شود.'; -$lang['matrix_header'] = 'ماتريس مجوزها'; -$lang['matrix_permission'] = 'مجوز دسترسي'; -$lang['matrix_role'] = 'نقش'; -$lang['matrix_note'] = 'جهت افزودن و يا حذف مجوز ها از يک نقش چک باکس ها را انتخاب کنيد و يا از انتخاب در بياوريد.'; -$lang['matrix_insert_success'] = 'مجوز به نقش افزوده شد.'; -$lang['matrix_insert_fail'] = 'مشکلي در افزودن مجوز به نقش پيش آمده است: '; -$lang['matrix_delete_success'] = 'مجوز از نقش گرفته شد.'; -$lang['matrix_delete_fail'] = 'مشکلي در حذف مجوز از نقش بوجود آمده است: '; -$lang['matrix_auth_fail'] = 'شما توانايي مديريت و کنترل مجوز هاي اين نقش را نداريد.'; \ No newline at end of file +$lang['matrix_header'] = 'ماتريس مجوزها'; +$lang['matrix_permission'] = 'مجوز دسترسي'; +$lang['matrix_role'] = 'نقش'; +$lang['matrix_note'] = 'جهت افزودن و يا حذف مجوز ها از يک نقش چک باکس ها را انتخاب کنيد و يا از انتخاب در بياوريد.'; +$lang['matrix_insert_success'] = 'مجوز به نقش افزوده شد.'; +$lang['matrix_insert_fail'] = 'مشکلي در افزودن مجوز به نقش پيش آمده است: '; +$lang['matrix_delete_success'] = 'مجوز از نقش گرفته شد.'; +$lang['matrix_delete_fail'] = 'مشکلي در حذف مجوز از نقش بوجود آمده است: '; +$lang['matrix_auth_fail'] = 'شما توانايي مديريت و کنترل مجوز هاي اين نقش را نداريد.'; + +$lang['form_validation_role_name'] = 'نام نقش'; +$lang['form_validation_role_login_destination'] = 'مقصد ورود'; +$lang['form_validation_role_default_role'] = 'نقش پيش فرض'; +$lang['form_validation_role_can_delete_role'] = 'قابل حذف'; diff --git a/bonfire/modules/roles/language/portuguese/roles_lang.php b/bonfire/modules/roles/language/portuguese/roles_lang.php index 8d3b5ee68..d83da1e4f 100644 --- a/bonfire/modules/roles/language/portuguese/roles_lang.php +++ b/bonfire/modules/roles/language/portuguese/roles_lang.php @@ -1,55 +1,60 @@ - - * @link http://cibonfire.com/docs/guides + * @package Bonfire\Modules\Roles\Language\Russian + * @author Translator < https://github.com/cjmaxik > + * @link http://cibonfire.com/docs/bonfire/roles_and_permissions */ $lang['role_intro'] = 'Роли позволяют распределить права пользователей.'; @@ -65,4 +65,8 @@ $lang['matrix_delete_fail'] = 'Возникла проблема при удалении прав:'; $lang['matrix_auth_fail'] = 'Аутентификация: У вас нет прав контролировать доступ данной роли.'; -/* end of file /roles/language/russian/roles_lang.php */ \ No newline at end of file +$lang['form_validation_role_name'] = 'Имя роли'; +$lang['form_validation_role_login_destination'] = 'Страница после входа'; +$lang['form_validation_role_default_context'] = 'Контекст по умолчанию'; +$lang['form_validation_role_default_role'] = 'Роль по умолчанию'; +$lang['form_validation_role_can_delete_role'] = 'Удаляемая'; diff --git a/bonfire/modules/roles/language/spanish_am/roles_lang.php b/bonfire/modules/roles/language/spanish_am/roles_lang.php index f1f079b6e..57d9d6a02 100644 --- a/bonfire/modules/roles/language/spanish_am/roles_lang.php +++ b/bonfire/modules/roles/language/spanish_am/roles_lang.php @@ -1,64 +1,71 @@ - 'description', + 'label' => 'lang:bf_description', + 'rules' => 'trim|max_length[255]', + ), + array( + 'field' => 'login_destination', + 'label' => 'lang:role_login_destination', + 'rules' => 'trim|max_length[255]', + ), + array( + 'field' => 'default_context', + 'label' => 'lang:role_default_context', + 'rules' => 'trim', + ), + array( + 'field' => 'default', + 'label' => 'lang:role_default_role', + 'rules' => 'trim|is_numeric|max_length[1]', + ), + array( + 'field' => 'can_delete', + 'label' => 'lang:role_can_delete_role', + 'rules' => 'trim|is_numeric|max_length[1]', + ), + ); + + /** @var array Additional validation rules only used on insert. */ + protected $insert_validation_rules = array( + array( + 'field' => 'role_name', + 'label' => 'lang:role_name', + 'rules' => 'required|trim|max_length[60]|unique[roles.role_name]', + ), + ); + + protected $updateValidationRules = array( + array( + 'field' => 'role_name', + 'label' => 'lang:role_name', + 'rules' => 'required|trim|max_length[60]|unique[roles.role_name,roles.role_id]', + ), + ); + + //-------------------------------------------------------------------------- /** * Class constructor. * - * Will load the permission_model, if it's not already loaded. - * * @return void */ public function __construct() { parent::__construct(); - - if (! class_exists('permission_model', false)) { - $this->load->model('permissions/permission_model'); - } } /** * Returns a single role, with an array of permissions. * - * @param int $id An int that matches the role_id of the role in question. + * @param integer $id An int that matches the role_id of the role in question. * - * @return mixed|array An array of information about the role, along with a - * sub-array that contains the role's applicable permissions, or false + * @return boolean|array An array of information about the role, along with + * a sub-array containing the role's applicable permissions, or false. */ public function find($id = null) { @@ -103,7 +139,7 @@ public function find($id = null) * * @param string $name A string with the name of the role. * - * @return object An object with the role and its permissions, or false + * @return boolean|object An object with the role and its permissions, or false. */ public function find_by_name($name = null) { @@ -118,24 +154,49 @@ public function find_by_name($name = null) return $role; } + /** + * Get the validation rules for the model. + * + * This override adds the role_name rule for updates. + * + * @uses $empty_validation_rules Observer to generate validation rules if + * they are empty. + * + * @param string $type The type of validation rules to retrieve: 'update' or + * 'insert'. If 'insert', appends rules set in $insert_validation_rules. + * + * @return array The validation rules for the model or an empty array. + */ + public function get_validation_rules($type = 'update') + { + if ($type != 'update') { + return parent::get_validation_rules($type); + } + + // When updating, add the role_name update rule. + $validationRules = parent::get_validation_rules($type); + $validationRules = array_merge($validationRules, $this->updateValidationRules); + + return $validationRules; + } + /** * A simple update of the role. * * Additionally, this cleans things up when setting this role as the default * role for new users. * - * @param int $id An int, being the role_id - * @param array $data An array of key/value pairs with which to update the db. + * @param integer $id The role id. + * @param array $data Array of key/value pairs with which to update the db. * - * @return bool true on successful update, else false + * @return boolean True on successful update, else false. */ public function update($id = null, $data = null) { - // If this role is set to default, then - // all others to are reset to NOT be default + // If this role is set to default, then set all others to NOT be default. if (isset($data['default']) && $data['default'] == 1) { - $this->db->set('default', 0); - $this->db->update($this->table_name); + $this->db->set('default', 0) + ->update($this->table_name); } return parent::update($id, $data); @@ -144,34 +205,30 @@ public function update($id = null, $data = null) /** * Verifies that a role can be deleted. * - * @param int $role_id The role to verify. + * @param integer $role_id The role to verify. * - * @return bool true if the role can be deleted, else false + * @return boolean True if the role can be deleted, else false. */ public function can_delete_role($role_id = 0) { $this->db->select('can_delete'); - $delete_role = parent::find($role_id); - if ($delete_role->can_delete == 1) { - return true; - } - return false; + return $delete_role->can_delete == 1; } /** * Deletes a role. * - * By default, it will perform a soft_delete and leave the permissions - * untouched. However, if $purge == true, then all permissions related to - * this role are also deleted. + * By default, it will perform a soft_delete and leave the permissions untouched. + * However, if $purge == true, then all permissions related to this role are + * also deleted. * - * @param int $id An integer with the role_id to delete. - * @param bool $purge If false, will perform a soft_delete. If true, will + * @param integer $id An integer with the role_id to delete. + * @param boolean $purge If false, will perform a soft_delete. If true, will * remove the role and related permissions from db. * - * @return bool true on successful delete, else false + * @return boolean True on successful delete, else false. */ public function delete($id = 0, $purge = false) { @@ -192,25 +249,25 @@ public function delete($id = 0, $purge = false) $this->soft_deletes = false; } - // Get the name for permission deletion later + // Get the name for permission deletion later. $role = $this->role_model->find($id); // Delete the record $deleted = parent::delete($id); if ($deleted === true) { - // Update the users to the default role + // Update the users to the default role. if (! class_exists('user_model', false)) { $this->load->model('users/user_model'); } $this->user_model->set_to_default_role($id); - // Delete the role_permissions for this role + // Delete the role_permissions for this role. if (! class_exists('role_permission_model', false)) { $this->load->model('roles/role_permission_model'); } $this->role_permission_model->delete_for_role($id); - // Delete the manage permission for this role + // Delete the manage permission for this role. $permission_name = 'Permissions.' . ucwords($role->role_name) . '.Manage'; if (! class_exists('permission_model', false)) { $this->load->model('permissions/permission_model'); @@ -232,13 +289,14 @@ public function delete($id = 0, $purge = false) if ($purge === true) { $this->soft_deletes = $tempSoftDeletes; } + return $deleted; } /** * Returns the id of the default role. * - * @return int|bool ID of the default role or false + * @return integer|boolean ID of the default role or false. */ public function default_role_id() { @@ -252,9 +310,9 @@ public function default_role_id() return false; } - //-------------------------------------------------------------------- + //-------------------------------------------------------------------------- // !PRIVATE METHODS - //-------------------------------------------------------------------- + //-------------------------------------------------------------------------- /** * Finds the permissions and role_permissions array for a single role. @@ -270,10 +328,13 @@ public function get_role_permissions(&$role) return; } - // Grab the active permissions + // Grab the active permissions. + if (! class_exists('permission_model', false)) { + $this->load->model('permissions/permission_model'); + } $permissions = $this->permission_model->find_all_by('status', 'active'); - // Setup the permissions for the role + // Setup the permissions for the role. $permission_array = array(); foreach ($permissions as $key => $permission) { $permission_array[$permission->name] = $permission; diff --git a/bonfire/modules/roles/views/settings/role_form.php b/bonfire/modules/roles/views/settings/role_form.php index 08c8d2523..4d346fce2 100644 --- a/bonfire/modules/roles/views/settings/role_form.php +++ b/bonfire/modules/roles/views/settings/role_form.php @@ -1,16 +1,14 @@
    - × - + × +
    - uri->uri_string(), 'class="form-horizontal"'); ?> + uri->uri_string(), 'class="form-horizontal"'); ?>
    @@ -42,7 +40,7 @@
    can_delete == 1 && has_permission('Bonfire.Roles.Delete')) : + if (isset($role) + && $role->can_delete == 1 + && has_permission('Bonfire.Roles.Delete') + ) : ?>
    - +
    \ No newline at end of file diff --git a/bonfire/modules/settings/controllers/Settings.php b/bonfire/modules/settings/controllers/Settings.php index a19a89fee..4662e38c4 100644 --- a/bonfire/modules/settings/controllers/Settings.php +++ b/bonfire/modules/settings/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 @@ -25,6 +25,10 @@ */ class Settings extends Admin_Controller { + private $permissionDevView = 'Site.Developer.View'; + private $permissionView = 'Bonfire.Settings.View'; + private $permissionManage = 'Bonfire.Settings.Manage'; + /** * Sets up the permissions and loads required classes * @@ -35,8 +39,8 @@ public function __construct() parent::__construct(); // Restrict access - View and Manage. - $this->auth->restrict('Bonfire.Settings.View'); - $this->auth->restrict('Bonfire.Settings.Manage'); + $this->auth->restrict($this->permissionView); + $this->auth->restrict($this->permissionManage); $this->lang->load('settings'); if (! class_exists('settings_lib', false)) { @@ -62,11 +66,14 @@ public function index() if (isset($_POST['save'])) { if ($this->saveSettings($extended_settings)) { Template::set_message(lang('settings_saved_success'), 'success'); - - redirect(SITE_AREA . '/settings/settings'); + } else { + Template::set_message(lang('settings_error_success'), 'error'); + $settingsError = $this->settings_lib->getError(); + if ($settingsError) { + Template::set_message($settingsError, 'error'); + } } - - Template::set_message(lang('settings_error_success'), 'error'); + redirect(SITE_AREA . '/settings/settings'); } // Read the current settings @@ -81,6 +88,7 @@ public function index() Template::set('languages', list_languages()); Template::set('selected_languages', unserialize($settings['site.languages'])); Template::set('settings', $settings); + Template::set('showDeveloperTab', $this->auth->has_permission($this->permissionDevView)); Template::render(); } @@ -108,7 +116,7 @@ private function saveSettings($extended_settings = array()) $this->form_validation->set_rules('password_force_symbols', 'lang:bf_password_force_symbols', 'trim|numeric'); $this->form_validation->set_rules('password_force_mixed_case', 'lang:bf_password_force_mixed_case', 'trim|numeric'); $this->form_validation->set_rules('password_show_labels', 'lang:bf_password_show_labels', 'trim|numeric'); - $this->form_validation->set_rules('languages[]', 'lang:bf_language', 'required|trim|is_array'); + $this->form_validation->set_rules('languages[]', 'lang:bf_language', 'required|trim'); // Setup the validation rules for any extended settings $extended_data = array(); @@ -165,7 +173,7 @@ private function saveSettings($extended_settings = array()) ); // Save the settings to the DB. - $updated = $this->settings_model->update_batch($data, 'name'); + $updated = $this->settings_lib->update_batch($data); // If the update was successful and there are extended settings to save... if ($updated && ! empty($extended_data)) { diff --git a/bonfire/modules/settings/libraries/Settings_lib.php b/bonfire/modules/settings/libraries/Settings_lib.php index 791d1f314..4a3b40fce 100644 --- a/bonfire/modules/settings/libraries/Settings_lib.php +++ b/bonfire/modules/settings/libraries/Settings_lib.php @@ -38,6 +38,9 @@ class Settings_lib /** @var array Settings cache. */ private static $cache = array(); + /** @var array Error messages. */ + protected static $errors = array(); + /** @var array Hold observers to handle settings drivers */ private static $observers = array(); @@ -103,6 +106,36 @@ public function __set($name, $value) return self::set($name, $value); } + /** + * Get an error message previously set by the library. + * + * @param integer|null $index The index of the error message to retrieve. + * + * @return string|boolean Returns the message at the given index. If no index + * was provided or no error message was found with the given index, returns + * the last error message. If no errors have been set, returns false. + */ + public static function getError($index = null) + { + if (is_null($index) + || ! isset(self::$errors[$index]) + ) { + return end(self::$errors); + } + + return self::$errors[$index]; + } + + /** + * Get the error messages previously set by the library. + * + * @return array An array of error messages, or an empty array. + */ + public static function getErrors() + { + return self::$errors; + } + /** * Retrieve a setting. * @@ -148,18 +181,22 @@ public static function item($name) */ public static function set($name, $value, $module = 'core') { - self::init(); - if (! self::$settingsModelLoaded) { - return false; + self::init(); + + if (! self::$settingsModelLoaded) { + self::$errors[] = 'Settings Model could not be loaded'; + return false; + } } - // Since the cache is originally retrieved from the database, the database - // is updated if the $name is found in the cache. - if (isset(self::$cache[$name])) { + // If the value is cached and found in the database, update the database. + if (isset(self::$cache[$name]) + && self::$ci->settings_model->find_by('name', $name) + ) { $setting = self::$ci->settings_model->update_where('name', $name, array('value' => $value)); } else { - // If $name was not found in the cache, insert the data into the database. + // Otherwise, insert the data. $setting = self::$ci->settings_model->insert( array( 'name' => $name, @@ -180,38 +217,53 @@ public static function set($name, $value, $module = 'core') * @param string $name Name of the setting. * @param string $module Name of the module. * - * @return bool + * @return boolean True if the setting was deleted successfully, else false. */ public static function delete($name, $module = 'core') { - self::init(); - - if (self::$settingsModelLoaded && isset(self::$cache[$name])) { - if (self::$ci->settings_model->delete_where(array('name' => $name, 'module' => $module))) { - unset(self::$cache[$name]); + if (! self::$settingsModelLoaded) { + self::init(); - return true; + if (! self::$settingsModelLoaded) { + self::$errors[] = 'Settings Model could not be loaded.'; + return false; } } + if (! isset(self::$cache[$name])) { + self::$errors[] = 'Error deleting setting: setting not found in cache.'; + return false; + } + + if (self::$ci->settings_model->delete_where(array('name' => $name, 'module' => $module))) { + unset(self::$cache[$name]); + + return true; + } + + self::$errors[] = empty(self::$ci->settings_model->error) ? 'Error deleting setting from the database.' : self::$ci->settings_model->error; + return false; } /** * Get all of the settings. * - * @return array + * @return array|null */ - public function find_all() + public static function find_all() { - if (self::$cache) { - return self::$cache; - } + if (! self::$settingsModelLoaded) { + self::init(); - self::init(); + if (! self::$settingsModelLoaded) { + self::$errors[] = 'Settings Model could not be loaded.'; + return null; + } + } - if (! self::$settingsModelLoaded) { - return null; + if (self::$cache) { + return self::$cache; } $settings = self::$ci->settings_model->find_all(); @@ -230,14 +282,17 @@ public function find_all() * @param string $field Setting column name. * @param string $value Value ot match. * - * @return array + * @return array|null */ - public function find_by($field = null, $value = null) + public static function find_by($field = null, $value = null) { - self::init(); - if (! self::$settingsModelLoaded) { - return null; + self::init(); + + if (! self::$settingsModelLoaded) { + self::$errors[] = 'Settings Model could not be loaded.'; + return null; + } } $settings = self::$ci->settings_model->find_by($field, $value); @@ -256,14 +311,17 @@ public function find_by($field = null, $value = null) * @param string $field Setting column name. * @param string $value Value ot match. * - * @return array + * @return array|null */ - public function find_all_by($field = null, $value = null) + public static function find_all_by($field = null, $value = null) { - self::init(); - if (! self::$settingsModelLoaded) { - return null; + self::init(); + + if (! self::$settingsModelLoaded) { + self::$errors[] = 'Settings Model could not be loaded.'; + return null; + } } $settings = self::$ci->settings_model->find_all_by($field, $value); @@ -276,6 +334,60 @@ public function find_all_by($field = null, $value = null) return $settings; } + /** + * Perform a batch update of settings in the database. Inserts any data not + * already in the database. + * + * @param array $data The settings to update in the database. + * + * @return boolean True on success, false on failure. + */ + public static function update_batch($data) + { + if (! self::$settingsModelLoaded) { + self::init(); + + if (! self::$settingsModelLoaded) { + self::$errors[] = 'Settings Model could not be loaded'; + return false; + } + } + + $index = 'name'; + $internalCache = array(); + $settings = self::$ci->settings_model->find_all(); + foreach ($settings as $setting) { + $internalCache[$setting->name] = $setting->value; + } + + $updateData = array(); + $insertData = array(); + foreach ($data as $record) { + if (isset($internalCache[$record[$index]])) { + $updateData[] = $record; + } else { + $insertData[] = $record; + } + self::$cache[$record[$index]] = $record['value']; + } + + $result = false; + if (! empty($updateData)) { + $result = self::$ci->settings_model->update_batch($updateData, $index); + if (! $result && self::$ci->settings_model->error) { + self::$errors[] = self::$ci->settings_model->error; + } + } + if (! empty($insertData)) { + $result = self::$ci->settings_model->insert_batch($insertData); + if (! $result && self::$ci->settings_model->error) { + self::$errors[] = self::$ci->settings_model->error; + } + } + + return $result; + } + // ------------------------------------------------------------------------- // Add/Remove Observers // ------------------------------------------------------------------------- @@ -312,7 +424,7 @@ public function detach($observer) * * @param string $name The name of the item to retrieve * - * @return bool|string Returns result of setting or false if none. + * @return boolean|string Returns result of setting or false if none. */ function settings_item($name = null) { @@ -323,4 +435,3 @@ function settings_item($name = null) return Settings_lib::item($name); } } -/* end /settings/libraries/settings_lib.php */ diff --git a/bonfire/modules/settings/views/settings/index.php b/bonfire/modules/settings/views/settings/index.php index 0cf907a51..c0d289f6c 100644 --- a/bonfire/modules/settings/views/settings/index.php +++ b/bonfire/modules/settings/views/settings/index.php @@ -1,7 +1,6 @@ auth->has_permission('Site.Developer.View'); $showExtendedSettings = ! empty($extended_settings); if ($showExtendedSettings) { $defaultCountry = 'US'; @@ -45,320 +44,35 @@
    -
    -
    - -
    - -
    - - -
    -
    -
    - -
    - - -
    -
    -
    - -
    - - -
    -
    - -
    - -
    - - ' : '') . lang('bf_top_number_help'); ?> -
    -
    -
    - -
    - - ' : '') . lang('bf_language_help'); ?> -
    -
    -
    + $errorClass)); ?>
    -
    -
    - -
    -
    - - -
    -
    -
    - -
    - - -
    -
    -
    - -
    - - -
    -
    -
    - -
    - - -
    -
    -
    - -
    - - -
    -
    -
    -
    - -
    -
    - -
    - -
    - - ' : '') . lang('bf_password_length_help'); ?> -
    -
    -
    - -
    - - - - -
    -
    -
    - -
    - - ' : '') . lang('bf_password_iterations_note'); ?> -
    -
    -
    - -
    - - -
    -
    -
    + $errorClass)); ?>
    -
    -
    - -
    -
    - - -
    -
    -
    + $errorClass)); ?>
    - -
    -
    - - auth->has_permission($field['permission']) - ) : - $field_control = ''; - switch ($field['form_detail']['type']) { - case 'dropdown': - echo form_dropdown( - $field['form_detail']['settings'], - $field['form_detail']['options'], - set_value($field['name'], isset($settings["ext.{$field['name']}"]) ? $settings["ext.{$field['name']}"] : ''), - $field['label'] - ); - break; - case 'checkbox': - $field_control = form_checkbox( - $field['form_detail']['settings'], - $field['form_detail']['value'], - isset($settings["ext.{$field['name']}"]) && $field['form_detail']['value'] == $settings["ext.{$field['name']}"] - ); - break; - case 'state_select': - if (! is_callable('state_select')) { - $this->load->config('address'); - $this->load->helper('address'); - } - $stateFieldId = $field['name']; - $stateValue = isset($settings["ext.{$field['name']}"]) ? $settings["ext.{$field['name']}"] : $defaultState; - $field_control = state_select( - set_value($field['name'], $stateValue), - $defaultState, - $defaultCountry, - $field['name'], - 'span6 chzn-select' - ); - break; - case 'country_select': - if (! is_callable('country_select')) { - $this->load->config('address'); - $this->load->helper('address'); - } - $countryFieldId = $field['name']; - $countryValue = isset($settings["ext.{$field['name']}"]) ? $settings["ext.{$field['name']}"] : $defaultCountry; - $field_control = country_select( - set_value($field['name'], $countryValue), - $defaultCountry, - $field['name'], - 'span6 chzn-select' - ); - break; - default: - $form_method = "form_{$field['form_detail']['type']}"; - if (is_callable($form_method)) { - echo $form_method( - $field['form_detail']['settings'], - set_value($field['name'], isset($settings["ext.{$field['name']}"]) ? $settings["ext.{$field['name']}"] : ''), - $field['label'] - ); - } - break; - } - - if (! empty($field_control)) : - ?> -
    - -
    - -
    -
    - load->view('users/country_state_js', - array( - 'country_name' => $countryFieldId, - 'country_value' => $countryValue, - 'state_name' => $stateFieldId, - 'state_value' => $stateValue, - ), - true - ), - 'inline' - ); - } - ?> -
    + $errorClass, + 'extendedSettings' => $extended_settings, + 'defaultCountry' => $defaultCountry, + 'defaultState' => $defaultState, + 'countryFieldId' => $countryFieldId, + 'stateFieldId' => $stateFieldId, + ) + ); + ?>
    diff --git a/bonfire/modules/settings/views/settings/index/developer.php b/bonfire/modules/settings/views/settings/index/developer.php new file mode 100644 index 000000000..f91fb1e42 --- /dev/null +++ b/bonfire/modules/settings/views/settings/index/developer.php @@ -0,0 +1,15 @@ +
    + +
    +
    + + +
    +
    +
    \ No newline at end of file diff --git a/bonfire/modules/settings/views/settings/index/extended.php b/bonfire/modules/settings/views/settings/index/extended.php new file mode 100644 index 000000000..fd0915d09 --- /dev/null +++ b/bonfire/modules/settings/views/settings/index/extended.php @@ -0,0 +1,93 @@ +
    + + auth->has_permission($field['permission']) + ) : + $field_control = ''; + switch ($field['form_detail']['type']) { + case 'dropdown': + echo form_dropdown( + $field['form_detail']['settings'], + $field['form_detail']['options'], + set_value($field['name'], isset($settings["ext.{$field['name']}"]) ? $settings["ext.{$field['name']}"] : ''), + $field['label'] + ); + break; + case 'checkbox': + $field_control = form_checkbox( + $field['form_detail']['settings'], + $field['form_detail']['value'], + isset($settings["ext.{$field['name']}"]) && $field['form_detail']['value'] == $settings["ext.{$field['name']}"] + ); + break; + case 'state_select': + if (! is_callable('state_select')) { + $this->load->config('address'); + $this->load->helper('address'); + } + $stateFieldId = $field['name']; + $stateValue = isset($settings["ext.{$field['name']}"]) ? $settings["ext.{$field['name']}"] : $defaultState; + $field_control = state_select( + set_value($field['name'], $stateValue), + $defaultState, + $defaultCountry, + $field['name'], + 'span6 chzn-select' + ); + break; + case 'country_select': + if (! is_callable('country_select')) { + $this->load->config('address'); + $this->load->helper('address'); + } + $countryFieldId = $field['name']; + $countryValue = isset($settings["ext.{$field['name']}"]) ? $settings["ext.{$field['name']}"] : $defaultCountry; + $field_control = country_select( + set_value($field['name'], $countryValue), + $defaultCountry, + $field['name'], + 'span6 chzn-select' + ); + break; + default: + $form_method = "form_{$field['form_detail']['type']}"; + if (is_callable($form_method)) { + echo $form_method( + $field['form_detail']['settings'], + set_value($field['name'], isset($settings["ext.{$field['name']}"]) ? $settings["ext.{$field['name']}"] : ''), + $field['label'] + ); + } + break; + } + + if (! empty($field_control)) : + ?> +
    + +
    + +
    +
    + load->view('users/country_state_js', + array( + 'country_name' => $countryFieldId, + 'country_value' => $countryValue, + 'state_name' => $stateFieldId, + 'state_value' => $stateValue, + ), + true + ), + 'inline' + ); + } + ?> +
    diff --git a/bonfire/modules/settings/views/settings/index/main.php b/bonfire/modules/settings/views/settings/index/main.php new file mode 100644 index 000000000..0bde03599 --- /dev/null +++ b/bonfire/modules/settings/views/settings/index/main.php @@ -0,0 +1,59 @@ +
    + +
    + +
    + + +
    +
    +
    + +
    + + +
    +
    +
    + +
    + + +
    +
    + +
    + +
    + + ' : '') . lang('bf_top_number_help'); ?> +
    +
    +
    + +
    + + ' : '') . lang('bf_language_help'); ?> +
    +
    +
    \ No newline at end of file diff --git a/bonfire/modules/settings/views/settings/index/security.php b/bonfire/modules/settings/views/settings/index/security.php new file mode 100644 index 000000000..4584b021a --- /dev/null +++ b/bonfire/modules/settings/views/settings/index/security.php @@ -0,0 +1,130 @@ +
    + +
    +
    + + +
    +
    +
    + +
    + + +
    +
    +
    + +
    + + +
    +
    +
    + +
    + + +
    +
    +
    + +
    + + +
    +
    +
    +
    + +
    +
    + +
    + +
    + + ' : '') . lang('bf_password_length_help'); ?> +
    +
    +
    + +
    + + + + +
    +
    +
    + +
    + + ' : '') . lang('bf_password_iterations_note'); ?> +
    +
    +
    + +
    + + +
    +
    +
    \ No newline at end of file diff --git a/bonfire/modules/sysinfo/config/config.php b/bonfire/modules/sysinfo/config/config.php index c4ced5d18..474a1ee16 100644 --- a/bonfire/modules/sysinfo/config/config.php +++ b/bonfire/modules/sysinfo/config/config.php @@ -1,7 +1,8 @@ 'Allows users to create translations for any language.', - 'name' => 'lang:bf_menu_sysinfo', - 'author' => 'Bonfire Team' -); \ No newline at end of file + 'description' => 'Allows users to create translations for any language.', + 'name' => 'lang:bf_menu_sysinfo', + 'author' => 'Bonfire Team', + 'version' => '0.7.3', +); diff --git a/bonfire/modules/sysinfo/controllers/Developer.php b/bonfire/modules/sysinfo/controllers/Developer.php index 1003f24a9..86c076db5 100644 --- a/bonfire/modules/sysinfo/controllers/Developer.php +++ b/bonfire/modules/sysinfo/controllers/Developer.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 @@ -17,105 +17,167 @@ /** * Sysinfo Module * - * Displays various system information to the user + * Displays various system information to the user. * - * @package Bonfire\Modules\Sysinfo\Controllers\Developer - * @author Bonfire Dev Team - * @link http://cibonfire.com/docs + * @package Bonfire\Modules\Sysinfo\Controllers\Developer + * @author Bonfire Dev Team + * @link http://cibonfire.com/docs */ class Developer extends Admin_Controller { - /** - * Load required classes - * - * @return void - */ - public function __construct() - { - parent::__construct(); - - // Restrict access - View - $this->auth->restrict('Bonfire.Sysinfo.View'); - - $this->lang->load('sysinfo'); - - Template::set('toolbar_title', lang('sysinfo_system_info')); - - Template::set_block('sub_nav', 'developer/_sub_nav'); - } - - /** - * Display the system information, including Bonfire and PHP versions, - * to the user - * - * @return void - */ - public function index() - { - // Date helper is used for user_time() function in the view + /** + * Load required classes. + * + * @return void + */ + public function __construct() + { + parent::__construct(); + + $this->auth->restrict('Bonfire.Sysinfo.View'); + + $this->lang->load('sysinfo'); + + Template::set('toolbar_title', lang('sysinfo_system_info')); + Template::set_block('sub_nav', 'developer/_sub_nav'); + } + + /** + * Display the system information, including Bonfire and PHP versions. + * + * @return void + */ + public function index() + { + // Date helper is used for user_time(). $this->load->helper('date'); - Template::render(); - } - - /** - * Display the list of modules in the Bonfire installation - * - * @return void - */ - public function modules() - { - $modules = Modules::list_modules(); - $configs = array(); - - foreach ($modules as $module) { - $configs[$module] = Modules::config($module); - - if ( ! isset($configs[$module]['name'])) { - $configs[$module]['name'] = ucwords($module); - } - elseif (strpos($configs[$module]['name'], 'lang:') === 0) { - $configs[$module]['name'] = lang(str_replace('lang:', '', $configs[$module]['name'])); - } - $configs[$module]['name'] = ucwords(str_replace('_', '', $configs[$module]['name'])); - } - - // Sort the list of modules by directory name - ksort($configs); - - Template::set('modules', $configs); - Template::render(); - } - - /** - * Display the PHP info settings to the user - * - * @return void - */ - public function php_info() - { - ob_start(); - - phpinfo(); - - $buffer = ob_get_contents(); - - ob_end_clean(); - - $output = (preg_match("/(.*)<\/body>/is", $buffer, $match)) ? $match['1'] : $buffer; - $output = preg_replace("/.*?<\/a>/", "", $output); - $output = preg_replace("/.*?<\/a>/", "", $output); - $output = preg_replace("/

    PHP License<\/h2>.*?<\/table>/si", "", $output); - $output = preg_replace("/

    PHP License.*?<\/table>/is", "", $output); - $output = preg_replace("//", "", $output); - $output = preg_replace("//", "
    ", $output); - $output = preg_replace("//", "", $output); - $output = preg_replace("//", "", $output); - $output = preg_replace("//", "
    ", $output); - $output = preg_replace("//", "", $output); - $output = preg_replace('/ BONFIRE_VERSION, + 'sysinfo_version_ci' => CI_VERSION, + 'sysinfo_version_php' => phpversion(), + 'sysinfo_time_server' => date($dateFormat), + 'sysinfo_time_local' => user_time(time(), false, $dateFormat), + 'sysinfo_db_name' => $this->db->database, + 'sysinfo_db_server' => $this->db->platform(), + 'sysinfo_db_version' => $this->db->version(), + 'sysinfo_db_charset' => $this->db->char_set, + 'sysinfo_db_collation' => $this->db->dbcollat, + 'sysinfo_basepath' => BASEPATH, + 'sysinfo_apppath' => APPPATH, + 'sysinfo_site_url' => site_url(), + 'sysinfo_environment' => ENVIRONMENT, + ); + + Template::set('info', $data); + Template::render(); + } + + /** + * Display the list of modules in the Bonfire installation. + * + * @return void + */ + public function modules() + { + $modules = Modules::list_modules(); + $configs = array(); + $unsetReplacement = '---'; + + foreach ($modules as $module) { + $configs[$module] = Modules::config($module); + + if (! isset($configs[$module]['name'])) { + $configs[$module]['name'] = ucwords($module); + } elseif (strpos($configs[$module]['name'], 'lang:') === 0) { + $configs[$module]['name'] = lang(str_replace('lang:', '', $configs[$module]['name'])); + } + $configs[$module]['name'] = ucwords(str_replace('_', '', $configs[$module]['name'])); + + $configs[$module]['version'] = isset($configs[$module]['version']) ? $configs[$module]['version'] : $unsetReplacement; + $configs[$module]['description'] = isset($configs[$module]['description']) ? $configs[$module]['description'] : $unsetReplacement; + $configs[$module]['author'] = isset($configs[$module]['author']) ? $configs[$module]['author'] : $unsetReplacement; + } + + // Sort the list of modules by directory name. + ksort($configs); + + Template::set('modules', $configs); + Template::render(); + } + + /** + * Display the PHP info settings to the user + * + * @return void + */ + public function php_info() + { + ob_start(); + phpinfo(); + $buffer = ob_get_contents(); + ob_end_clean(); + + $tableClass = 'table table-striped table-condensed'; + + // Note: this matches the opening div, but leaves the closing tag intact. + // Later, an opening div is inserted into the content which will need the + // closing tag. + $output = (preg_match("/(.*)<\/body>/is", $buffer, $match)) ? $match['1'] : $buffer; + $output = preg_replace("/.*?<\/a>/", "", $output); + $output = preg_replace("/.*?<\/a>/", "", $output); + $output = preg_replace("/

    PHP License<\/h2>.*?<\/table>/si", "", $output); + $output = preg_replace("/

    PHP License.*?<\/table>/is", "", $output); + $output = preg_replace("//", "

    ", $output); + $output = preg_replace("//", "
    ", $output); + $output = preg_replace("//", "", $output); + $output = preg_replace("//", "", $output); + $output = preg_replace("//", "
    ", $output); + $output = preg_replace("//", "", $output); + $output = preg_replace('/(\s+)
    (\s+)

    PHP Version(.*?)<\/h1>(\s+)<\/td><\/tr>(\s+)<\/table>
    /is", + "

    PHP Version:\\3

    ", + $output + ); + + $output = preg_replace( + "/(\s+)
    (\s+)This program makes use of the Zend Scripting Language Engine:
    (.*?)
    <\/td><\/tr>(\s+)<\/table>
    /is", + "

    This program makes use of the Zend Scripting Language Engine:
    \\3

    ", + $output + ); + + $output = preg_replace( + "/

    Configuration<\/h1>/", + "

    Configuration

    ", + $output + ); + $output = preg_replace( + "/

    PHP Credits<\/h1>/", + "

    PHP Credits

    ", + $output + ); + + $output = preg_replace( + "/(\s+)
    mbstring extension makes use of(.*?)<\/th><\/tr>(\s+)<\/table>
    /is", + "

    mbstring extension makes use of\\2

    ", + $output + ); + + $output = preg_replace( + "/(\s+)", $output); + $output = preg_replace("/", $output); + + Template::set('phpinfo', $output); + Template::render(); + } } -/* end /sysinfo/controllers/developer.php */ \ No newline at end of file diff --git a/bonfire/modules/sysinfo/language/english/sysinfo_lang.php b/bonfire/modules/sysinfo/language/english/sysinfo_lang.php index db5b1128c..7857bc728 100644 --- a/bonfire/modules/sysinfo/language/english/sysinfo_lang.php +++ b/bonfire/modules/sysinfo/language/english/sysinfo_lang.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 @@ -17,35 +17,35 @@ /** * Sysinfo language file (English) * - * @package Bonfire\Modules\Sysinfo\Language\English - * @author Bonfire Dev Team - * @link http://cibonfire.com/docs + * @package Bonfire\Modules\Sysinfo\Language\English + * @author Bonfire Dev Team + * @link http://cibonfire.com/docs */ -$lang['sysinfo_system_info'] = 'System Information'; -$lang['sysinfo_system'] = 'System'; -$lang['sysinfo_modules'] = 'Modules'; -$lang['sysinfo_php'] = 'PHP'; +$lang['sysinfo_system_info'] = 'System Information'; +$lang['sysinfo_system'] = 'System'; +$lang['sysinfo_modules'] = 'Modules'; +$lang['sysinfo_php'] = 'PHP'; $lang['sysinfo_installed_mods'] = 'Installed Modules'; $lang['sysinfo_php_info'] = 'PHP Information'; -$lang['sysinfo_mod_name'] = 'Module Name'; -$lang['sysinfo_mod_ver'] = 'Version'; -$lang['sysinfo_mod_desc'] = 'Description'; -$lang['sysinfo_mod_author'] = 'Author'; +$lang['sysinfo_mod_name'] = 'Module Name'; +$lang['sysinfo_mod_ver'] = 'Version'; +$lang['sysinfo_mod_desc'] = 'Description'; +$lang['sysinfo_mod_author'] = 'Author'; -$lang['sysinfo_version_bf'] = 'Bonfire Version'; -$lang['sysinfo_version_ci'] = 'CodeIgniter Version'; -$lang['sysinfo_version_php'] = 'PHP Version'; -$lang['sysinfo_time_server'] = 'Server Time'; -$lang['sysinfo_time_local'] = 'Local Time'; -$lang['sysinfo_db_name'] = 'Database Name'; -$lang['sysinfo_db_server'] = 'Database Server'; -$lang['sysinfo_db_version'] = 'Database Version'; -$lang['sysinfo_db_charset'] = 'Database Charset'; -$lang['sysinfo_db_collation'] = 'Database Collation Charset'; -$lang['sysinfo_basepath'] = 'Base Path'; -$lang['sysinfo_apppath'] = 'App Path'; -$lang['sysinfo_site_url'] = 'Site_URL'; -$lang['sysinfo_environment'] = 'Environment'; \ No newline at end of file +$lang['sysinfo_version_bf'] = 'Bonfire Version'; +$lang['sysinfo_version_ci'] = 'CodeIgniter Version'; +$lang['sysinfo_version_php'] = 'PHP Version'; +$lang['sysinfo_time_server'] = 'Server Time'; +$lang['sysinfo_time_local'] = 'Local Time'; +$lang['sysinfo_db_name'] = 'Database Name'; +$lang['sysinfo_db_server'] = 'Database Server'; +$lang['sysinfo_db_version'] = 'Database Version'; +$lang['sysinfo_db_charset'] = 'Database Charset'; +$lang['sysinfo_db_collation'] = 'Database Collation Charset'; +$lang['sysinfo_basepath'] = 'Base Path'; +$lang['sysinfo_apppath'] = 'App Path'; +$lang['sysinfo_site_url'] = 'Site_URL'; +$lang['sysinfo_environment'] = 'Environment'; diff --git a/bonfire/modules/sysinfo/views/developer/index.php b/bonfire/modules/sysinfo/views/developer/index.php index cb87a33b5..5d51c54d6 100644 --- a/bonfire/modules/sysinfo/views/developer/index.php +++ b/bonfire/modules/sysinfo/views/developer/index.php @@ -1,67 +1,12 @@ -
    -
    (\s+)Phar based on pear\/PHP_Archive(.*?)<\/td><\/tr>(\s+)<\/table>
    /is", + "

    Phar based on pear/PHP_Archive\\3

    ", + $output + ); + + $output = preg_replace("/

    (.*?)<\/h1>/is", "

    \\1

    ", $output); + $output = preg_replace("/

    (.*?)<\/h2>/is", "

    \\1

    ", $output); + + $output = preg_replace("/
    (.*?)<\/td>/is", "\\1(.*?)<\/td>/is", "\\1
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    db->database; ?>
    db->platform(); ?>
    db->version(); ?>
    db->char_set; ?>
    db->dbcollat; ?>
    + + + $val) : ?> + + + + + + +
    \ No newline at end of file diff --git a/bonfire/modules/sysinfo/views/developer/modules.php b/bonfire/modules/sysinfo/views/developer/modules.php index cc8d821eb..804f7cef8 100644 --- a/bonfire/modules/sysinfo/views/developer/modules.php +++ b/bonfire/modules/sysinfo/views/developer/modules.php @@ -1,7 +1,6 @@
    -

    - - +

    +
    @@ -14,12 +13,11 @@ $config) : ?> - - - + + +
    -
    \ No newline at end of file diff --git a/bonfire/modules/sysinfo/views/developer/php_info.php b/bonfire/modules/sysinfo/views/developer/php_info.php index 880b42efb..c0818cff7 100644 --- a/bonfire/modules/sysinfo/views/developer/php_info.php +++ b/bonfire/modules/sysinfo/views/developer/php_info.php @@ -1 +1,10 @@ - + +
    + +
    + \ No newline at end of file diff --git a/bonfire/modules/translate/controllers/Developer.php b/bonfire/modules/translate/controllers/Developer.php index 41b08d2a8..7cf9f9d50 100644 --- a/bonfire/modules/translate/controllers/Developer.php +++ b/bonfire/modules/translate/controllers/Developer.php @@ -6,8 +6,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 @@ -20,20 +20,15 @@ * to add language files for other languages. The user can export current language * files for translation. * - * @package Bonfire\Modules\Translate\Controllers\Developer - * @author Bonfire Dev Team - * @link http://cibonfire.com/docs/guides + * @package Bonfire\Modules\Translate\Controllers\Developer + * @author Bonfire Dev Team + * @link http://cibonfire.com/docs */ - class Developer extends Admin_Controller { - /** - * @vary string[] Array of current languages - */ + /** @var array The names of the current languages. */ private $langs; - //-------------------------------------------------------------------- - /** * Constructor - Load required classes * @@ -62,7 +57,7 @@ public function __construct() * Display a list of all core language files, as well as a list of modules * the user can choose to edit. * - * @param string $transLang The target language for translation + * @param string $transLang The target language for translation. * * @return void */ @@ -75,7 +70,8 @@ public function index($transLang = '') // Selecting a different language? if (isset($_POST['select_lang'])) { - $transLang = $this->input->post('trans_lang') == 'other' ? $this->input->post('new_lang') : $this->input->post('trans_lang'); + $transLang = $this->input->post('trans_lang') == 'other' ? + $this->input->post('new_lang') : $this->input->post('trans_lang'); } // If the selected language is not in the list of languages, add it. @@ -83,14 +79,17 @@ public function index($transLang = '') $this->langs[] = $transLang; } - // Check whether there are custom modules + // Check whether there are custom modules with lang files. $allLangFiles = list_lang_files(); - if (isset($allLangFiles['custom'])) { - Template::set('modules', $allLangFiles['custom']); + $moduleLangFiles = $allLangFiles['custom']; + sort($moduleLangFiles); + Template::set('modules', $moduleLangFiles); } - Template::set('lang_files', $allLangFiles['core']); + $coreLangFiles = $allLangFiles['core']; + sort($coreLangFiles); + Template::set('lang_files', $coreLangFiles); Template::set('languages', $this->langs); Template::set('trans_lang', $transLang); Template::set('toolbar_title', sprintf(lang('translate_title_index'), ucfirst($transLang))); @@ -98,10 +97,10 @@ public function index($transLang = '') } /** - * Allow the user to edit a language file + * Allow the user to edit a language file. * - * @param string $transLang The target language for translation - * @param string $langFile The file to translate + * @param string $transLang The target language for translation. + * @param string $langFile The file to translate. * * @return void */ @@ -114,7 +113,7 @@ public function edit($transLang = '', $langFile = '') if ($langFile) { // Save the file... if (isset($_POST['save'])) { - // If the file saves successfully, redirect to the index + // If the file saves successfully, redirect to the index. if (save_lang_file($langFile, $transLang, $_POST['lang'])) { Template::set_message(lang('translate_save_success'), 'success'); redirect(SITE_AREA . "/developer/translate/index/{$transLang}"); @@ -123,11 +122,11 @@ public function edit($transLang = '', $langFile = '') Template::set_message(lang('translate_save_fail'), 'error'); } - // Get the lang file + // Get the lang file. $orig = load_lang_file($langFile, $origLang); $new = $transLang ? load_lang_file($langFile, $transLang) : $orig; - // Translate + // Translate. if (isset($_POST['translate']) && is_array($_POST['checked'])) { if (isset($_POST['lang'])) { foreach ($_POST['lang'] as $key => $val) { @@ -145,7 +144,7 @@ public function edit($transLang = '', $langFile = '') $cnt = 0; $this->load->library('translate_lib'); - // Attempt to translate each of the selected values + // Attempt to translate each of the selected values. foreach ($_POST['checked'] as $key) { $new[$key] = '* ' . $new[$key]; $val = ''; @@ -161,8 +160,8 @@ public function edit($transLang = '', $langFile = '') $chkd[] = $key; } - // Give up if 5 errors occur without any successful - // attempts, as this may imply network or other issues + // Give up if 5 errors occur without any successful attempts, + // as this may imply network or other issues. if ($errcnt >= 5 && $cnt == 0) { break; } @@ -250,4 +249,3 @@ public function do_export($language = null, $includeCore = false, $includeCustom die(); } } -/* /bonfire/modules/translate/controllers/developer.php */ diff --git a/bonfire/modules/translate/helpers/languages_helper.php b/bonfire/modules/translate/helpers/languages_helper.php index defe58755..64f159172 100644 --- a/bonfire/modules/translate/helpers/languages_helper.php +++ b/bonfire/modules/translate/helpers/languages_helper.php @@ -6,8 +6,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 @@ -18,20 +18,21 @@ * * Includes fucntions to help with the management of the language files. * - * @package Bonfire\Modules\Translate\Helpers\Languages - * @author Bonfire Dev Team - * @link http://cibonfire.com/docs/guides + * @package Bonfire\Modules\Translate\Helpers\Languages + * @author Bonfire Dev Team + * @link http://cibonfire.com/docs */ if (! function_exists('addLanguageLine')) { /** - * Add one or more lines to an existing language file + * Add one or more lines to an existing language file. * - * @param string $filename The name of the file to update - * @param array $line An array of key/value pairs containing the language entries to update/add and the values to set them to - * @param string $language The language of the file to update + * @param string $filename The name of the file to update. + * @param array $line An array of key/value pairs containing the language + * entries to update/add and the values to set them to. + * @param string $language The language of the file to update. * - * @return bool true on successful update, else false + * @return boolean True on successful update, else false. */ function addLanguageLine($filename, $line, $language = 'english') { @@ -51,7 +52,7 @@ function addLanguageLine($filename, $line, $language = 'english') * Lists the existing languages in the system by examining the core * language folders in bonfire/application/language. * - * @return string[] Array of the names of the language directories + * @return array The names of the language directories. */ function list_languages() { @@ -70,57 +71,55 @@ function list_languages() * Searches the application/languages folder as well as all core modules * for folders matching the language name. * - * @param string $language The language + * @param string $language The language. * - * @return array An array of files. + * @return array The filenames. */ function list_lang_files($language = 'english') { - $lang_files = array(); - // Base language files. - $lang_files['core'] = find_lang_files(APPPATH . "language/{$language}/"); + $langFiles = array(); + $langFiles['core'] = find_lang_files(APPPATH . "language/{$language}/"); - // Module directories + // Build the 'core' and 'custom' module lists. $modules = Modules::list_modules(); - // Application Module directories only - $custom_modules = Modules::list_modules(true); - + $appModules = Modules::list_modules(true); foreach ($modules as $module) { - $module_langs = Modules::files($module, 'language'); + $moduleLangs = Modules::files($module, 'language'); $type = 'core'; - if (isset($module_langs[$module]['language'][$language])) { + if (isset($moduleLangs[$module]['language'][$language])) { $path = implode('/', array(Modules::path($module, 'language'), $language)); - $files = find_lang_files($path . '/'); - if (in_array($module, $custom_modules)) { + + // 'core' modules will only be found in $modules, while 'custom' + // modules will be found in both $modules and $appModules. + if (in_array($module, $appModules)) { $type = 'custom'; } if (is_array($files)) { foreach ($files as $file) { - $lang_files[$type][] = $file; + $langFiles[$type][] = $file; } } } } - return $lang_files; + return $langFiles; } } if (! function_exists('find_lang_files')) { /** - * Search a folder for language files + * Search a folder for language files. * * Searches an individual folder for any language files and returns an array - * appropriate for adding to the $lang_files array in the get_lang_files() - * function. + * appropriate for adding to the $langFiles array in the get_lang_files() function. * - * @param string $path The folder to search + * @param string $path The folder to search. * - * @return array An array of files + * @return array Filenames. */ function find_lang_files($path = null) { @@ -141,10 +140,12 @@ function find_lang_files($path = null) /** * Load a single language file into an array. * - * @param string $filename The name of the file to locate. The file will be found by looking in all modules. + * @param string $filename The name of the file to locate. The file will be + * found by looking in all modules. * @param string $language The language to retrieve. * - * @return mixed An array on loading the language file, false on error + * @return mixed The $lang array from the file or false if not found. Returns + * null if $filename is empty. */ function load_lang_file($filename = null, $language = 'english') { @@ -152,7 +153,7 @@ function load_lang_file($filename = null, $language = 'english') return null; } - // Is it a application lang file? Use the English folder to determine. + // Is it an application lang file? Use the English folder to determine. $arFiles = scandir(APPPATH . "language/english/"); if ($filename == 'application_lang.php' || in_array($filename, $arFiles)) { $path = APPPATH . "language/{$language}/{$filename}"; @@ -177,15 +178,19 @@ function load_lang_file($filename = null, $language = 'english') if (! function_exists('save_lang_file')) { /** - * Save a language file + * Save a language file. * - * @param string $filename The name of the file to locate. The file will be found by looking in all modules. - * @param string $language The language to retrieve. - * @param array $settings An array of the language settings - * @param bool $return TRUE to return the contents or FALSE to write to file - * @param bool $allowNewValues if true, new values can be added to the file + * @param string $filename The name of the file to locate. The file will be + * found by looking in all modules. + * @param string $language The language to retrieve. + * @param array $settings An array of the language settings. + * @param boolean $return True to return the contents or false to write to + * the file. + * @param boolean $allowNewValues If true, new values can be added to the file. * - * @return mixed A string when the $return setting is true + * @return boolean|string False if there was a problem loading the file. Otherwise, + * returns true when $return is false or a string containing the file's contents + * when $return is true. */ function save_lang_file($filename = null, $language = 'english', $settings = null, $return = false, $allowNewValues = false) { @@ -281,4 +286,3 @@ function save_lang_file($filename = null, $language = 'english', $settings = nul return false; } } -/* /bonfire/modules/translate/helpers/languages_helper.php */ diff --git a/bonfire/modules/translate/libraries/Translate_lib.php b/bonfire/modules/translate/libraries/Translate_lib.php index 254926a31..ae4c792d9 100644 --- a/bonfire/modules/translate/libraries/Translate_lib.php +++ b/bonfire/modules/translate/libraries/Translate_lib.php @@ -3,45 +3,33 @@ /** * Translate Module Library * - * Provides methods to retrieve translations from external sites + * Provides methods to retrieve translations from external sites. * * @uses Bonfire\Libraries\Curl (CodeIgniter cURL library from Phil Sturgeon) * - * @package Bonfire\Modules\Translate\Libraries\Translate_lib - * @author Bonfire Dev Team - * @link http://guides.cibonfire.com/ - * @todo Update Link to a Docs/Guides on the translate_lib methods + * @package Bonfire\Modules\Translate\Libraries\Translate_lib + * @author Bonfire Dev Team + * @link http://cibonfire.com/docs + * @todo Update Link to a Docs/Guides on the translate_lib methods */ class Translate_lib { - /** - * @var object A pointer to the CodeIgniter instance. - */ + /** @var object A pointer to the CodeIgniter instance. */ protected $ci; - /** - * @var string Last translation result - */ + /** @var string Last translation result. */ public $lastResult = ''; - /** - * @var string Language engine for translation - */ + /** @var string Language engine for translation. */ private $langEngine = 'google'; - /** - * @var string Language code translating from - */ + /** @var string Language code translating from. */ private $langFrom; - /** - * @var string Language code translating to - */ + /** @var string Language code translating to. */ private $langTo; - /** - * @var array URL formats (Google Translate, others) - */ + /** @var array URL formats (Google Translate, others). */ private static $urlFormat = array( 'google' => array( 'url' => 'http://translate.google.com/translate_a/t?client=t&text=%s&hl=en&sl=%s&tl=%s&ie=UTF-8&oe=UTF-8&multires=1&otf=1&pc=1&trs=1&ssel=3&tsel=6&sc=1', @@ -120,7 +108,7 @@ public function translate($text) $this->ci->load->library('curl'); $url = sprintf(self::$urlFormat[$this->langEngine]['url'], rawurlencode($text), $this->langFrom, $this->langTo); $result = $this->ci->curl->simple_get($url); - if ( ! $result) { + if (! $result) { return false; } @@ -128,7 +116,7 @@ public function translate($text) $result = preg_replace('!,+!', ',', $result); // Remove repeated commas $result = str_replace('[,', '[', $result); // Remove extra comma after bracket $resultArray = json_decode($result, true); - if ( ! isset($resultArray[0])) { + if (! isset($resultArray[0])) { return false; } @@ -140,4 +128,3 @@ public function translate($text) return $this->lastResult = $finalResult; } } -/* End of class Translate_lib.php */ \ No newline at end of file diff --git a/bonfire/modules/translate/views/developer/index.php b/bonfire/modules/translate/views/developer/index.php index 3c68e721a..7e92389b3 100644 --- a/bonfire/modules/translate/views/developer/index.php +++ b/bonfire/modules/translate/views/developer/index.php @@ -27,7 +27,7 @@
    'Provides helpers for consistent admin UI features.', - 'author' => 'Bonfire Team', - 'version' => '0.1.0', - 'name' => 'lang:bf_menu_kb_shortcuts', -); \ No newline at end of file + 'author' => 'Bonfire Team', + 'description' => 'Provides helpers for consistent admin UI features.', + 'name' => 'lang:bf_menu_kb_shortcuts', + 'version' => '0.7.3', +); diff --git a/bonfire/modules/ui/controllers/Settings.php b/bonfire/modules/ui/controllers/Settings.php index ccca491a1..268ad2c4d 100644 --- a/bonfire/modules/ui/controllers/Settings.php +++ b/bonfire/modules/ui/controllers/Settings.php @@ -8,8 +8,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,7 @@ * * @package Bonfire\Modules\UI\Controllers\Settings * @author Bonfire Dev Team - * @link http://cibonfire.com/docs/bonfire/keyboard_shortcuts + * @link http://cibonfire.com/docs/developer/keyboard_shortcuts */ class Settings extends Admin_Controller { @@ -103,7 +103,6 @@ private function addShortcut() // Read available shortcuts from the application config. $availableActions = config_item('ui.current_shortcuts'); - if (array_key_exists($action, $availableActions)) { return $this->saveSettings(array($action => $shortcut)); } @@ -118,7 +117,7 @@ private function addShortcut() */ private function removeShortcut() { - $this->form_validation->set_rules('remove_shortcut[]', 'lang:ui_actions', 'required|is_array'); + $this->form_validation->set_rules('remove_shortcut[]', 'lang:ui_actions', 'required'); if ($this->form_validation->run() === false) { return false; } @@ -127,7 +126,6 @@ private function removeShortcut() // Read the current settings $availableActions = $this->settings_lib->find_all_by('module', 'core.ui'); - if (array_key_exists($action, $availableActions)) { return $this->settings_lib->delete($action, 'core.ui'); } @@ -210,4 +208,3 @@ public function _validate_shortcuts($shortcut) return true; } } -/* end /ui/controllers/settings.php */ diff --git a/bonfire/modules/ui/language/english/ui_lang.php b/bonfire/modules/ui/language/english/ui_lang.php index f68e685c1..ac19bdf7c 100644 --- a/bonfire/modules/ui/language/english/ui_lang.php +++ b/bonfire/modules/ui/language/english/ui_lang.php @@ -8,8 +8,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 @@ -23,28 +23,32 @@ * @link http://cibonfire.com/docs/developer/keyboard_shortcuts */ -$lang['ui_keyboard_shortcuts'] = "Keyboard shortcuts are setup in the application config (the 'ui.current_shortcuts' key in /application/config/application.php).
    The currently available shortcuts are:"; -$lang['ui_add_shortcut'] = 'Add Shortcut'; -$lang['ui_remove_shortcut'] = 'Remove'; -$lang['ui_no_shortcuts'] = 'There are no shortcut options setup in the application config.'; -$lang['ui_update_shortcuts'] = 'Save'; - -$lang['ui_action'] = 'Action'; -$lang['ui_actions'] = 'Actions'; - -$lang['ui_shortcut'] = 'Shortcut Key'; -$lang['ui_shortcut_help'] = 'Enter your preferred keys in the field below, e.g. alt+j - see more examples on the Jwerty project page'; -$lang['ui_shortcuts'] = 'Shortcut Keys'; -$lang['ui_current_shortcuts'] = 'Current Shortcuts'; - -$lang['ui_shortcut_success'] = 'Shortcut inserted'; -$lang['ui_shortcut_add_error'] = 'There was an error saving your shortcuts.'; -$lang['ui_shortcut_remove_success'] = 'Your shortcut was successfully removed.'; -$lang['ui_shortcut_remove_error'] = 'There was an error removing your shortcut.'; -$lang['ui_shortcut_save_success'] = 'Your shortcuts were successfully saved.'; -$lang['ui_shortcut_save_error'] = 'There was an error saving your shortcuts.'; -$lang['ui_shortcut_error_exists'] = 'Shortcut already exists'; -$lang['ui_shortcut_error_unavailable'] = 'Action is unavailable'; -$lang['ui_shortcut_error'] = 'Spaces are not allowed in the shortcut keys'; - -$lang['ui_default_title'] = 'UI Settings'; +$lang['ui_keyboard_shortcuts'] = "Keyboard shortcuts are setup in the application config (the 'ui.current_shortcuts' key in /application/config/application.php).
    The currently available shortcuts are:"; +$lang['ui_add_shortcut'] = 'Add Shortcut'; +$lang['ui_remove_shortcut'] = 'Remove'; +$lang['ui_no_shortcuts'] = 'There are no shortcut options setup in the application config.'; +$lang['ui_update_shortcuts'] = 'Save'; + +$lang['ui_action'] = 'Action'; +$lang['ui_actions'] = 'Actions'; + +$lang['ui_shortcut'] = 'Shortcut Key'; +$lang['ui_shortcut_help'] = 'Enter your preferred keys in the field below, e.g. alt+j - see more examples on the Jwerty project page'; +$lang['ui_shortcuts'] = 'Shortcut Keys'; +$lang['ui_current_shortcuts'] = 'Current Shortcuts'; + +$lang['ui_shortcut_success'] = 'Shortcut inserted'; +$lang['ui_shortcut_add_error'] = 'There was an error saving your shortcuts.'; +$lang['ui_shortcut_remove_success'] = 'Your shortcut was successfully removed.'; +$lang['ui_shortcut_remove_error'] = 'There was an error removing your shortcut.'; +$lang['ui_shortcut_save_success'] = 'Your shortcuts were successfully saved.'; +$lang['ui_shortcut_save_error'] = 'There was an error saving your shortcuts.'; +$lang['ui_shortcut_error_exists'] = 'Shortcut already exists'; +$lang['ui_shortcut_error_unavailable'] = 'Action is unavailable'; +$lang['ui_shortcut_error'] = 'Spaces are not allowed in the shortcut keys'; + +$lang['ui_default_title'] = 'UI Settings'; + +$lang['form_validation__validate_shortcuts'] = 'Spaces are not allowed in the shortcut keys'; +$lang['form_validation_ui_shortcuts'] = 'Shortcut Key'; +$lang['form_validation_ui_actions'] = 'Action'; diff --git a/bonfire/modules/users/config/config.php b/bonfire/modules/users/config/config.php index 7fbece31e..92a2a0758 100644 --- a/bonfire/modules/users/config/config.php +++ b/bonfire/modules/users/config/config.php @@ -1,10 +1,11 @@ 'Allows users to exist in Bonfire.', - 'author' => 'Bonfire Team', - 'weights' => array( - 'settings' => 1, - ), - 'name' => 'lang:bf_menu_users', -); \ No newline at end of file + 'author' => 'Bonfire Team', + 'description' => 'Allows users to exist in Bonfire.', + 'name' => 'lang:bf_menu_users', + 'version' => '0.7.3', + 'weights' => array( + 'settings' => 1, + ), +); diff --git a/bonfire/modules/users/controllers/Settings.php b/bonfire/modules/users/controllers/Settings.php index ac8ae8a9c..4c5024a6b 100644 --- a/bonfire/modules/users/controllers/Settings.php +++ b/bonfire/modules/users/controllers/Settings.php @@ -32,19 +32,19 @@ class Settings extends Admin_Controller private $permissionManage = 'Bonfire.Users.Manage'; private $permissionView = 'Bonfire.Users.View'; - /** + /** * Setup the required permissions. - * - * @return void - */ - public function __construct() + * + * @return void + */ + public function __construct() { - parent::__construct(); + parent::__construct(); $this->auth->restrict($this->permissionView); $this->lang->load('users'); - $this->load->model('roles/role_model'); + $this->load->model('roles/role_model'); $this->siteSettings = $this->settings_lib->find_all(); if ($this->siteSettings['auth.password_show_labels'] == 1) { @@ -52,19 +52,19 @@ public function __construct() Assets::add_module_js('users', 'jquery.strength.js'); } - Template::set_block('sub_nav', 'users/settings/_sub_nav'); + Template::set_block('sub_nav', 'users/settings/_sub_nav'); } - /* + /* * Display the user list and manage the user deletions/banning/purge. - * + * * @param string $filter The filter to apply to the list. * @param int $offset The offset from which the list will start. - * - * @return void - */ + * + * @return void + */ public function index($filter = 'all', $offset = 0) - { + { $this->auth->restrict($this->permissionManage); // Fetch roles for the filter and the list. @@ -75,7 +75,7 @@ public function index($filter = 'all', $offset = 0) $orderedRoles = array(); foreach ($roles as $role) { $orderedRoles[$role->role_id] = $role; - } + } Template::set('roles', $orderedRoles); // Perform any actions? @@ -83,26 +83,26 @@ public function index($filter = 'all', $offset = 0) if (isset($_POST[$act])) { $action = "_{$act}"; break; - } - } + } + } // If an action was found, get the checked users and perform the action. if (isset($action)) { $checked = $this->input->post('checked'); if (empty($checked)) { // No users checked. - Template::set_message(lang('us_empty_id'), 'error'); + Template::set_message(lang('us_empty_id'), 'error'); } else { foreach ($checked as $userId) { $this->$action($userId); } - } - } + } + } // Actions done, now display the view. - $where = array('users.deleted' => 0); + $where = array('users.deleted' => 0); - // Filters + // Filters if (preg_match('{first_letter-([A-Z])}', $filter, $matches)) { $filterType = 'first_letter'; $firstLetter = $matches[1]; @@ -112,114 +112,110 @@ public function index($filter = 'all', $offset = 0) $roleId = (int) $matches[1]; } else { $filterType = $filter; - } + } switch ($filterType) { - case 'inactive': - $where['users.active'] = 0; - break; - - case 'banned': - $where['users.banned'] = 1; - break; - - case 'deleted': - $where['users.deleted'] = 1; - break; - - case 'role_id': + case 'inactive': + $where['users.active'] = 0; + break; + case 'banned': + $where['users.banned'] = 1; + break; + case 'deleted': + $where['users.deleted'] = 1; + break; + case 'role_id': $where['users.role_id'] = $roleId; foreach ($roles as $role) { if ($role->role_id == $roleId) { - Template::set('filter_role', $role->role_name); - break; - } - } - break; - - case 'first_letter': + Template::set('filter_role', $role->role_name); + break; + } + } + break; + case 'first_letter': // @todo Determine whether this needs to be changed to become // usable with databases other than MySQL $where['SUBSTRING( LOWER(username), 1, 1)='] = $firstLetter; - break; - - case 'all': - // Nothing to do - break; - - default: + break; + case 'all': + // Nothing to do + break; + default: // Unknown/bad $filterType - show_404("users/index/$filter/"); - } + show_404("users/index/$filter/"); + } - // Fetch the users to display + // Fetch the users to display $this->user_model->limit($this->limit, $offset) ->where($where) - ->select(array( - 'users.id', - 'users.role_id', - 'username', - 'display_name', - 'email', - 'last_login', - 'banned', - 'active', - 'users.deleted', - 'role_name', - )); - Template::set('users', $this->user_model->find_all()); + ->select( + array( + 'users.id', + 'users.role_id', + 'username', + 'display_name', + 'email', + 'last_login', + 'banned', + 'active', + 'users.deleted', + 'role_name', + ) + ); + Template::set('users', $this->user_model->find_all()); // Used as the view's index_url and the base for the pager's base_url. $indexUrl = site_url(SITE_AREA . '/settings/users/index') . '/'; Template::set('index_url', $indexUrl); - // Pagination - $this->load->library('pagination'); + // Pagination + $this->load->library('pagination'); $this->pager['base_url'] = "{$indexUrl}{$filter}/"; - $this->pager['per_page'] = $this->limit; + $this->pager['per_page'] = $this->limit; $this->pager['total_rows'] = $this->user_model->where($where)->count_all(); - $this->pager['uri_segment'] = 6; + $this->pager['uri_segment'] = 6; - $this->pagination->initialize($this->pager); + $this->pagination->initialize($this->pager); Template::set('filter_type', $filterType); - Template::set('toolbar_title', lang('us_user_management')); + Template::set('toolbar_title', lang('us_user_management')); Template::render(); } - /** + /** * Create a new user. - * - * @return void - */ - public function create() - { + * + * @return void + */ + public function create() + { $this->auth->restrict($this->permissionCreate); - $this->load->config('address'); - $this->load->helper('address'); - $this->load->helper('date'); + $this->load->config('address'); + $this->load->helper('address'); + $this->load->helper('date'); - $this->load->config('user_meta'); + $this->load->config('user_meta'); $metaFields = config_item('user_meta_fields'); Template::set('meta_fields', $metaFields); if (isset($_POST['save'])) { if ($id = $this->saveUser('insert', null, $metaFields)) { - $user = $this->user_model->find($id); + $user = $this->user_model->find($id); $logName = empty($user->display_name) ? ($this->settings_lib->item('auth.use_usernames') ? $user->username : $user->email) : $user->display_name; log_activity( $this->auth->user_id(), sprintf(lang('us_log_create'), $user->role_name) . ": {$logName}", 'users' ); - Template::set_message(lang('us_user_created_success'), 'success'); + Template::set_message(lang('us_user_created_success'), 'success'); redirect(SITE_AREA . '/settings/users'); - } - } + } + } if ($this->siteSettings['auth.password_show_labels'] == 1) { Assets::add_js( @@ -236,42 +232,42 @@ public function create() ->find_all() ); Template::set('languages', unserialize($this->settings_lib->item('site.languages'))); - Template::set('toolbar_title', lang('us_create_user')); + Template::set('toolbar_title', lang('us_create_user')); - Template::set_view('users/settings/user_form'); - Template::render(); + Template::set_view('users/settings/user_form'); + Template::render(); } - /** + /** * Edit a user. - * + * * @param number/string $userId The ID of the user to edit. If empty, the * current user will be displayed/edited. - * - * @return void - */ + * + * @return void + */ public function edit($userId = '') - { - $this->load->config('address'); - $this->load->helper('address'); - $this->load->helper('date'); + { + $this->load->config('address'); + $this->load->helper('address'); + $this->load->helper('date'); // If no id is passed in, edit the current user. if (empty($userId)) { $userId = $this->auth->user_id(); - } + } if (empty($userId)) { - Template::set_message(lang('us_empty_id'), 'error'); + Template::set_message(lang('us_empty_id'), 'error'); redirect(SITE_AREA . '/settings/users'); - } + } if ($userId != $this->auth->user_id()) { $this->auth->restrict($this->permissionManage); } - $this->load->config('user_meta'); + $this->load->config('user_meta'); $metaFields = config_item('user_meta_fields'); Template::set('meta_fields', $metaFields); @@ -286,13 +282,13 @@ public function edit($userId = '') lang('us_log_edit') . ": {$logName}", 'users' ); - Template::set_message(lang('us_user_update_success'), 'success'); + Template::set_message(lang('us_user_update_success'), 'success'); // Redirect to the edit page to ensure that a password change // forces a login check. - redirect($this->uri->uri_string()); - } - } + redirect($this->uri->uri_string()); + } + } if (! isset($user)) { Template::set_message( @@ -301,7 +297,7 @@ public function edit($userId = '') ); redirect(SITE_AREA . '/settings/users'); - } + } if ($this->siteSettings['auth.password_show_labels'] == 1) { Assets::add_js( @@ -321,65 +317,65 @@ public function edit($userId = '') Template::set('languages', unserialize($this->settings_lib->item('site.languages'))); Template::set('toolbar_title', lang('us_edit_user')); - Template::set_view('users/settings/user_form'); - Template::render(); + Template::set_view('users/settings/user_form'); + Template::render(); } - /** + /** * Force all users to require a password reset on their next login. - * - * Intended to be used as an AJAX function. - * - * @return void - */ - public function force_password_reset_all() - { + * + * Intended to be used as an AJAX function. + * + * @return void + */ + public function force_password_reset_all() + { $this->auth->restrict($this->permissionManage); if ($this->user_model->force_password_reset()) { // Resets are in place, so log the user out. - $this->auth->logout(); + $this->auth->logout(); - Template::redirect(LOGIN_URL); + Template::redirect(LOGIN_URL); } else { - Template::redirect($this->previous_page); - } - } + Template::redirect($this->previous_page); + } + } //-------------------------------------------------------------------------- // !PRIVATE METHODS //-------------------------------------------------------------------------- - /** + /** * Ban a user or group of users. - * + * * @param int $userId User to ban * @param string $banMessage Set a message indicating the reason the user * was banned. - * - * @return void - */ + * + * @return void + */ private function _ban($userId, $banMessage = '') - { + { $this->user_model->update( $userId, array( - 'banned' => 1, + 'banned' => 1, 'ban_message' => $banMessage ) - ); + ); } - /** + /** * Delete a user or group of users. - * + * * @param int $id User to delete. - * - * @return void - */ - private function _delete($id) - { - $user = $this->user_model->find($id); + * + * @return void + */ + private function _delete($id) + { + $user = $this->user_model->find($id); if (! isset($user)) { Template::set_message(lang('us_invalid_user_id'), 'error'); redirect(SITE_AREA . '/settings/users'); @@ -396,74 +392,74 @@ private function _delete($id) } if ($this->user_model->delete($id)) { - $user = $this->user_model->find($id); + $user = $this->user_model->find($id); $logName = empty($user->display_name) ? ($this->settings_lib->item('auth.use_usernames') ? $user->username : $user->email) : $user->display_name; log_activity( $this->auth->user_id(), lang('us_log_delete') . ": {$logName}", 'users' ); - Template::set_message(lang('us_action_deleted'), 'success'); + Template::set_message(lang('us_action_deleted'), 'success'); } elseif (! empty($this->user_model->error)) { Template::set_message(lang('us_action_not_deleted') . $this->user_model->error, 'error'); - } - } + } + } - /** + /** * Purge the selected users which are already marked as deleted. - * - * @param int $id User to purge - * - * @return void - */ - private function _purge($id) - { + * + * @param int $id User to purge + * + * @return void + */ + private function _purge($id) + { $this->user_model->delete($id, true); - Template::set_message(lang('us_action_purged'), 'success'); + Template::set_message(lang('us_action_purged'), 'success'); - // Purge any user meta for this user, also. - $this->db->where('user_id', $id)->delete('user_meta'); + // Purge any user meta for this user, also. + $this->db->where('user_id', $id)->delete('user_meta'); - // Any modules needing to save data? - Events::trigger('purge_user', $id); + // Any modules needing to save data? + Events::trigger('purge_user', $id); } - /** + /** * Restore the deleted user. - * + * * @param number $id The ID of the user to restore. - * - * @return void - */ - private function _restore($id) - { + * + * @return void + */ + private function _restore($id) + { if ($this->user_model->update($id, array('users.deleted' => 0))) { - Template::set_message(lang('us_user_restored_success'), 'success'); + Template::set_message(lang('us_user_restored_success'), 'success'); } elseif (! empty($this->user_model->error)) { Template::set_message(lang('us_user_restored_error') . $this->user_model->error, 'error'); - } - } + } + } - /** + /** * Save the user. - * + * * @param string $type The type of operation (insert or edit). * @param int $id The id of the user (ignored on insert). * @param array $metaFields Array of meta fields for the user. * @param string $currentRoleName The current role of the user being edited. - * + * * @return bool/int The id of the inserted user or true on successful update. * False if the insert/update failed. - */ + */ private function saveUser($type = 'insert', $id = 0, $metaFields = array(), $currentRoleName = '') - { + { $this->form_validation->set_rules($this->user_model->get_validation_rules($type)); $extraUniqueRule = ''; $usernameRequired = ''; if ($type != 'insert') { - $_POST['id'] = $id; + $_POST['id'] = $id; $extraUniqueRule = ',users.id'; // If a value has been entered for the password, pass_confirm is required. @@ -476,13 +472,13 @@ private function saveUser($type = 'insert', $id = 0, $metaFields = array(), $cur "required|matches[password]" ); } - } + } - if ($this->settings_lib->item('auth.login_type') == 'username' + if ($this->settings_lib->item('auth.login_type') == 'username' || $this->settings_lib->item('auth.use_usernames') ) { $usernameRequired = 'required|'; - } + } $this->form_validation->set_rules('username', 'lang:bf_username', "{$usernameRequired}trim|max_length[30]|unique[users.username{$extraUniqueRule}]"); $this->form_validation->set_rules('email', 'lang:bf_email', "required|trim|valid_email|max_length[254]|unique[users.email{$extraUniqueRule}]"); @@ -490,8 +486,8 @@ private function saveUser($type = 'insert', $id = 0, $metaFields = array(), $cur if (has_permission($this->permissionManage) && has_permission("Permissions.{$currentRoleName}.Manage") ) { - $this->form_validation->set_rules('role_id', 'lang:us_role', 'required|trim|max_length[2]|is_numeric'); - } + $this->form_validation->set_rules('role_id', 'lang:us_role', 'required|trim|max_length[2]|is_numeric'); + } $metaData = array(); foreach ($metaFields as $field) { @@ -500,10 +496,10 @@ private function saveUser($type = 'insert', $id = 0, $metaFields = array(), $cur && $this->auth->role_id() == 1 ) ) { - $this->form_validation->set_rules($field['name'], $field['label'], $field['rules']); + $this->form_validation->set_rules($field['name'], $field['label'], $field['rules']); $metaData[$field['name']] = $this->input->post($field['name']); - } - } + } + } // Setting the payload for Events system. $payload = array('user_id' => $id, 'data' => $this->input->post()); @@ -511,22 +507,22 @@ private function saveUser($type = 'insert', $id = 0, $metaFields = array(), $cur // Event "before_user_validation" to run before the form validation. Events::trigger('before_user_validation', $payload); - if ($this->form_validation->run() === false) { - return false; - } + if ($this->form_validation->run() === false) { + return false; + } // Compile the core user elements to save. $data = $this->user_model->prep_data($this->input->post()); $result = false; - if ($type == 'insert') { + if ($type == 'insert') { $activationMethod = $this->settings_lib->item('auth.user_activation_method'); - // No activation method + // No activation method if ($activationMethod == 0) { - // Activate the user automatically - $data['active'] = 1; - } + // Activate the user automatically + $data['active'] = 1; + } $id = $this->user_model->insert($data); if (is_numeric($id)) { @@ -534,76 +530,77 @@ private function saveUser($type = 'insert', $id = 0, $metaFields = array(), $cur } } else { $result = $this->user_model->update($id, $data); - } + } // Save any meta data for this user. Don't try to save meta data on a // failed insert ($id is not numeric). if (is_numeric($id) && ! empty($metaData)) { $this->user_model->save_meta_for($id, $metaData); - } + } - // Any modules needing to save data? - Events::trigger('save_user', $this->input->post()); + // Any modules needing to save data? + $postData = $this->input->post(); + Events::trigger('save_user', $postData); return $result; } //-------------------------------------------------------------------------- - // ACTIVATION METHODS + // ACTIVATION METHODS //-------------------------------------------------------------------------- - /** + /** * Activate the selected user account. - * + * * @param int $userId The ID of the user to activate. - * - * @return void - */ + * + * @return void + */ private function _activate($userId) - { + { $this->setUserStatus($userId, 1, 0); } - /** + /** * Deactivate the selected user account. - * + * * @param int $userId The ID of the user to deactivate. - * - * @return void - */ + * + * @return void + */ private function _deactivate($userId) - { + { $this->setUserStatus($userId, 0, 0); } - /** + /** * Activate or deactivate a user from the users dashboard. - * + * * @param int $userId The ID of the user to activate/deactivate. * @param int $status 1 = Activate, -1 = Deactivate. * @param int $suppressEmail 1 = Suppress, All others = send email. - * - * @return void - */ + * + * @return void + */ private function setUserStatus($userId = false, $status = 1, $suppressEmail = 0) - { + { if ($userId === false || $userId == -1) { Template::set_message(lang('us_err_no_id'), 'error'); return; } $suppressEmail = isset($suppressEmail) && $suppressEmail == 1; - $result = false; - $type = ''; + $result = false; + $type = ''; // Set the user status (activate/deactivate the user). if ($status == 1) { $result = $this->user_model->admin_activation($userId); - $type = lang('bf_action_activate'); + $type = lang('bf_action_activate'); } else { $result = $this->user_model->admin_deactivation($userId); - $type = lang('bf_action_deactivate'); - } + $type = lang('bf_action_deactivate'); + } if (! $result) { if (! empty($this->user_model->error)) { @@ -624,7 +621,7 @@ private function setUserStatus($userId = false, $status = 1, $suppressEmail = 0) 'users' ); - $message = lang('us_active_status_changed'); + $message = lang('us_active_status_changed'); // If the user was activated and the email is not suppressed, send it. if ($status == 1 && ! $suppressEmail) { @@ -633,17 +630,17 @@ private function setUserStatus($userId = false, $status = 1, $suppressEmail = 0) $data = array( 'to' => $user->email, - 'subject' => lang('us_account_active'), + 'subject' => lang('us_account_active'), 'message' => $this->load->view('_emails/activated', array('link' => site_url(), 'title' => $siteTitle), true), - ); + ); if ($this->emailer->send($data)) { - $message = lang('us_active_email_sent'); + $message = lang('us_active_email_sent'); } else { $message = lang('us_err_no_email') . $this->emailer->error; - } - } - Template::set_message($message, 'success'); - } + } + } + Template::set_message($message, 'success'); + } } /* End of file /users/controllers/settings.php */ diff --git a/bonfire/modules/users/libraries/Auth.php b/bonfire/modules/users/libraries/Auth.php index 2228cf4ad..efaf42b9d 100755 --- a/bonfire/modules/users/libraries/Auth.php +++ b/bonfire/modules/users/libraries/Auth.php @@ -74,12 +74,7 @@ public function __construct() // The users language file is needed for this to work from other modules. $this->ci->lang->load('users/users'); $this->ci->load->model('users/user_model'); - if (substr(CI_VERSION, 0, 1) != '2') { - $this->ci->load->driver('session'); - } else { - $this->ci->load->library('session'); - } - + $this->ci->load->library('session'); // Try to log the user in from session/cookie data. $this->autologin(); @@ -785,8 +780,10 @@ private function loadPermissions() $this->permissions = array(); $perms = $this->ci->permission_model->find_all(); - foreach ($perms as $perm) { - $this->permissions[strtolower($perm->name)] = $perm->permission_id; + if (! empty($perms)) { + foreach ($perms as $perm) { + $this->permissions[strtolower($perm->name)] = $perm->permission_id; + } } return $this->permissions;