DB.php

最后更新于:2022-04-01 20:46:26

~~~ $dns['scheme'], 'hostname' => (isset($dns['host'])) ? rawurldecode($dns['host']) : '', 'username' => (isset($dns['user'])) ? rawurldecode($dns['user']) : '', 'password' => (isset($dns['pass'])) ? rawurldecode($dns['pass']) : '', 'database' => (isset($dns['path'])) ? rawurldecode(substr($dns['path'], 1)) : '' ); // were additional config items set? // 是否设置了额外的配置项 if (isset($dns['query'])) { // parse_str()解析查询字符串到变量中 parse_str($dns['query'], $extra); foreach ($extra as $key => $val) { // booleans please // 把字符串转换true,false转换为真正boolean值 if (strtoupper($val) == "TRUE") { $val = TRUE; } elseif (strtoupper($val) == "FALSE") { $val = FALSE; } $params[$key] = $val; } } } // No DB specified yet? Beat them senseless... // 没有指定要连接的数据库驱动 if ( ! isset($params['dbdriver']) OR $params['dbdriver'] == '') { show_error('You have not selected a database type to connect to.'); } // Load the DB classes. Note: Since the active record class is optional // we need to dynamically create a class that extends proper parent class // based on whether we're using the active record class or not. // Kudos to Paul for discovering this clever use of eval() // 载入DB类。 注意: 因为active record类是可选的,我们需要动态的去 // 创建一个继承适当的父类(基于我们是否使用active record类) if ($active_record_override !== NULL) { $active_record = $active_record_override; } require_once(BASEPATH.'database/DB_driver.php'); // 启用active_record if ( ! isset($active_record) OR $active_record == TRUE) { require_once(BASEPATH.'database/DB_active_rec.php'); // 动态创建CI_DB类继承自CI_DB_active_record类 if ( ! class_exists('CI_DB')) { eval('class CI_DB extends CI_DB_active_record { }'); } } else { // 动态创建CI_DB直接继承自CI_DB_driver if ( ! class_exists('CI_DB')) { eval('class CI_DB extends CI_DB_driver { }'); } } // 加载响应的数据库驱动 require_once(BASEPATH.'database/drivers/'.$params['dbdriver'].'/'.$params['dbdriver'].'_driver.php'); // Instantiate the DB adapter // 实例化DB适配器 $driver = 'CI_DB_'.$params['dbdriver'].'_driver'; $DB = new $driver($params); // 在DB_driver中的字段,用于指定是否要对数据库驱动进行初始化操作 if ($DB->autoinit == TRUE) { $DB->initialize(); } if (isset($params['stricton']) && $params['stricton'] == TRUE) { $DB->query('SET SESSION sql_mode="STRICT_ALL_TABLES"'); } return $DB; } /* End of file DB.php */ /* Location: ./system/database/DB.php */ ~~~
';

Exceptions

最后更新于:2022-04-01 20:46:24

~~~ 'Error', E_WARNING => 'Warning', E_PARSE => 'Parsing Error', E_NOTICE => 'Notice', E_CORE_ERROR => 'Core Error', E_CORE_WARNING => 'Core Warning', E_COMPILE_ERROR => 'Compile Error', E_COMPILE_WARNING => 'Compile Warning', E_USER_ERROR => 'User Error', E_USER_WARNING => 'User Warning', E_USER_NOTICE => 'User Notice', E_STRICT => 'Runtime Notice' ); /** * Constructor */ public function __construct() { $this->ob_level = ob_get_level(); // Note: Do not log messages from this constructor. } // -------------------------------------------------------------------- /** * Exception Logger * 异常日志的记录 * This function logs PHP generated error messages * 这个函数将记录php产生的错误消息 * @access private * @param string the error severity * @param string the error string * @param string the error filepath * @param string the error line number * @return string */ function log_exception($severity, $message, $filepath, $line) { // 根据错误级别设置错误严重性 $severity = ( ! isset($this->levels[$severity])) ? $severity : $this->levels[$severity]; log_message('error', 'Severity: '.$severity.' --> '.$message. ' '.$filepath.' '.$line, TRUE); } // -------------------------------------------------------------------- /** * 404 Page Not Found Handler * 404 页面 * @access private * @param string the page * @param bool log error yes/no * @return string */ function show_404($page = '', $log_error = TRUE) { $heading = "404 Page Not Found"; $message = "The page you requested was not found."; // By default we log this, but allow a dev to skip it if ($log_error) { log_message('error', '404 Page Not Found --> '.$page); } echo $this->show_error($heading, $message, 'error_404', 404); exit; } // -------------------------------------------------------------------- /** * General Error Page * 一般的错误页面 * This function takes an error message as input * (either as a string or an array) and displays * it using the specified template. * 这个函数将使用指定的模板显示一个错误消息 * @access private * @param string the heading * @param string the message * @param string the template name * @param int the status code * @return string */ function show_error($heading, $message, $template = 'error_general', $status_code = 500) { // 默认是500 set_status_header($status_code); // 组合错误消息 $message = '

'.implode('

', ( ! is_array($message)) ? array($message) : $message).'

'; /* * 如果还没看过core/Loader.php,下面这个判断可能让人有点迷惑。 * ob_get_level()是取得当前缓冲机制的嵌套级别。(缓冲是可以一层嵌一层的。) * 右边的$this->ob_level是在__construct()里面同样通过ob_get_level()被赋值的。 * 也就是说,有可能出现:Exception组件被加载时(也就是应用刚开始运行时) * 的缓冲级别(其实也就是程序最开始的时候的缓冲级别,那时 * 候是还没有ob_start()过的),与发生错误的时候的缓冲级别相差1。 * 在控制器执行$this->load->view("xxx");的时候,实质, * Loader引入并执行这个视图文件的时候,是先把缓冲打开,即 * 先ob_start(),所有输出放到缓冲区(详见:core/Loader.php中的_ci_load()),然后再由Output处理输出。 * 因此,如果是在视图文件发生错误,则就会出现缓冲级别相差1的情况 * 这就会导致输出的内容不仅仅只是这个的错误信息 * 此时先把输出的内容给flush出来,然后再把错误信息输出。 * */ if (ob_get_level() > $this->ob_level + 1) { ob_end_flush(); } ob_start(); include(APPPATH.'errors/'.$template.'.php'); $buffer = ob_get_contents(); ob_end_clean(); return $buffer; } // -------------------------------------------------------------------- /** * Native PHP error handler * 本地php错误处理 * @access private * @param string the error severity * @param string the error string * @param string the error filepath * @param string the error line number * @return string */ function show_php_error($severity, $message, $filepath, $line) { $severity = ( ! isset($this->levels[$severity])) ? $severity : $this->levels[$severity]; $filepath = str_replace("\\", "/", $filepath); // For safety reasons we do not show the full file path if (FALSE !== strpos($filepath, '/')) { $x = explode('/', $filepath); $filepath = $x[count($x)-2].'/'.end($x); } if (ob_get_level() > $this->ob_level + 1) { ob_end_flush(); } ob_start(); include(APPPATH.'errors/error_php.php'); $buffer = ob_get_contents(); ob_end_clean(); echo $buffer; } } // END Exceptions Class /* End of file Exceptions.php */ /* Location: ./system/core/Exceptions.php */ ~~~
';

Model.php

最后更新于:2022-04-01 20:46:22

~~~ $key; } } // END Model Class /* End of file Model.php */ /* Location: ./system/core/Model.php */ ~~~
';

Controller.php

最后更新于:2022-04-01 20:46:19

~~~ $class) { $this->$var =& load_class($class); } // 给超级控制器加载Loader组件,这个组件是它的好助手, // 很多时候你会经常用到$this->load->xxx()的形式加载某个东西, // 这个load就是控制器被构造的时候就伴随存在的。 $this->load =& load_class('Loader', 'core'); // 初始化Loader组件,详细Loader.php $this->load->initialize(); log_message('debug', "Controller Class Initialized"); } public static function &get_instance() { return self::$instance; } } // END Controller class /* End of file Controller.php */ /* Location: ./system/core/Controller.php */ ~~~
';

Lang.php

最后更新于:2022-04-01 20:46:17

~~~ is_loaded和$this->language中去 * @param bool add suffix to $langfile 文件是否添加后缀 * @param string alternative path to look for language file 语言包文件的自定义路径 * @return mixed */ function load($langfile = '', $idiom = '', $return = FALSE, $add_suffix = TRUE, $alt_path = '') { // langfile 文件的.php 后缀去掉 $langfile = str_replace('.php', '', $langfile); // 判断需不需要添加后缀如果需要 // 将_lang. 去掉并再langfile后面添加_lang if ($add_suffix == TRUE) { $langfile = str_replace('_lang.', '', $langfile).'_lang'; } // 为langfile添加.php后缀 $langfile .= '.php'; // 判断当前文件是否被加载过 if (in_array($langfile, $this->is_loaded, TRUE)) { return; } // 获取配置文件的数据 $config =& get_config(); // 如果要使用的语言为空 // 那么 我们将从$config中获取 if ($idiom == '') { $deft_lang = ( ! isset($config['language'])) ? 'english' : $config['language']; $idiom = ($deft_lang == '') ? 'english' : $deft_lang; } // Determine where the language file is and load it // 在自定义路径下寻找语言包并加载 if ($alt_path != '' && file_exists($alt_path.'language/'.$idiom.'/'.$langfile)) { include($alt_path.'language/'.$idiom.'/'.$langfile); } else { // 如果自定义路径下没找到调用get_instance()->load->get_package_paths(TRUE) // 在包路径下寻找 // get_package_paths这个函数在loader.php中 $found = FALSE; foreach (get_instance()->load->get_package_paths(TRUE) as $package_path) { if (file_exists($package_path.'language/'.$idiom.'/'.$langfile)) { include($package_path.'language/'.$idiom.'/'.$langfile); $found = TRUE; break; } } // 如果还没找到就只能报错了 // if ($found !== TRUE) { show_error('Unable to load the requested language file: language/'.$idiom.'/'.$langfile); } } if ( ! isset($lang)) { log_message('error', 'Language file contains no data: language/'.$idiom.'/'.$langfile); return; } if ($return == TRUE) { return $lang; } $this->is_loaded[] = $langfile; $this->language = array_merge($this->language, $lang); unset($lang); log_message('debug', 'Language file loaded: language/'.$idiom.'/'.$langfile); return TRUE; } // -------------------------------------------------------------------- /** * Fetch a single line of text from the language array * 获取一行文本 * @access public * @param string $line the language line * @return string */ function line($line = '') { /* * $this->language 的样子 * $lang['error_email_missing'] = "You must submit an email address"; * $lang['error_url_missing'] = "You must submit a URL"; * $lang['error_username_missing'] = "You must submit a username"; */ $value = ($line == '' OR ! isset($this->language[$line])) ? FALSE : $this->language[$line]; // Because killer robots like unicorns! if ($value === FALSE) { log_message('error', 'Could not find the language line "'.$line.'"'); } return $value; } } // END Language Class /* End of file Lang.php */ /* Location: ./system/core/Lang.php */ ~~~
';

Input.php

最后更新于:2022-04-01 20:46:15

~~~ _allow_get_array = (config_item('allow_get_array') === TRUE); $this->_enable_xss = (config_item('global_xss_filtering') === TRUE); $this->_enable_csrf = (config_item('csrf_protection') === TRUE); // 清除globals变量,在开启了globals_register的情况下,相当于关闭了此配置。 // 开启一道 安全防护 global $SEC; $this->security =& $SEC; // Do we need the UTF-8 class? if (UTF8_ENABLED === TRUE) { global $UNI; $this->uni =& $UNI; } // Sanitize global arrays $this->_sanitize_globals(); } // -------------------------------------------------------------------- /** * Fetch from array * 从$array获取值,如果设置了xss_clean 那么进行过滤 * This is a helper function to retrieve 检索 values from global arrays * 这是一个帮助函数用来从全局数组中检索 * * @access private * @param array * @param string * @param bool * @return string */ function _fetch_from_array(&$array, $index = '', $xss_clean = FALSE) { if ( ! isset($array[$index])) { return FALSE; } if ($xss_clean === TRUE) { return $this->security->xss_clean($array[$index]); } return $array[$index]; } // -------------------------------------------------------------------- /** * Fetch an item from the GET array * 获取过滤后的GET数组 * @access public * @param string * @param bool * @return string */ function get($index = NULL, $xss_clean = FALSE) { // Check if a field has been provided // 检查是否一个字段已经被提供 if ($index === NULL AND ! empty($_GET)) { $get = array(); // loop through the full _GET array // 遍历_GET数组 foreach (array_keys($_GET) as $key) { $get[$key] = $this->_fetch_from_array($_GET, $key, $xss_clean); } return $get; } return $this->_fetch_from_array($_GET, $index, $xss_clean); } // -------------------------------------------------------------------- /** * Fetch an item from the POST array * 获取过滤后的$_POST值 * @access public * @param string * @param bool * @return string */ function post($index = NULL, $xss_clean = FALSE) { // Check if a field has been provided if ($index === NULL AND ! empty($_POST)) { $post = array(); // Loop through the full _POST array and return it foreach (array_keys($_POST) as $key) { $post[$key] = $this->_fetch_from_array($_POST, $key, $xss_clean); } return $post; } return $this->_fetch_from_array($_POST, $index, $xss_clean); } // -------------------------------------------------------------------- /** * Fetch an item from either the GET array or the POST * 从get和post中获取值, post优先 * @access public * @param string The index key * @param bool XSS cleaning * @return string */ function get_post($index = '', $xss_clean = FALSE) { if ( ! isset($_POST[$index]) ) { return $this->get($index, $xss_clean); } else { return $this->post($index, $xss_clean); } } // -------------------------------------------------------------------- /** * Fetch an item from the COOKIE array * 返回过滤后的COOKIE值 * @access public * @param string * @param bool * @return string */ function cookie($index = '', $xss_clean = FALSE) { return $this->_fetch_from_array($_COOKIE, $index, $xss_clean); } // ------------------------------------------------------------------------ /** * Set cookie * * Accepts six parameter, or you can submit an associative * array in the first parameter containing all the values. * 接收6个参数或者接收一个关联数组里面包含所有的值 * @access public * @param mixed * @param string the value of the cookie * @param string the number of seconds until expiration * @param string the cookie domain. Usually: .yourdomain.com * @param string the cookie path * @param string the cookie prefix * @param bool true makes the cookie secure * @return void */ function set_cookie($name = '', $value = '', $expire = '', $domain = '', $path = '/', $prefix = '', $secure = FALSE) { // 如果第一个值是数组 将数组中的值分别赋值给留个参数 if (is_array($name)) { // always leave 'name' in last place, as the loop will break otherwise, due to $$item foreach (array('value', 'expire', 'domain', 'path', 'prefix', 'secure', 'name') as $item) { if (isset($name[$item])) { $$item = $name[$item]; } } } // 如果某个参数为默认值但是config.php中的配置不是默认值 // 则使用config.php中的配置值 if ($prefix == '' AND config_item('cookie_prefix') != '') { $prefix = config_item('cookie_prefix'); } if ($domain == '' AND config_item('cookie_domain') != '') { $domain = config_item('cookie_domain'); } if ($path == '/' AND config_item('cookie_path') != '/') { $path = config_item('cookie_path'); } if ($secure == FALSE AND config_item('cookie_secure') != FALSE) { $secure = config_item('cookie_secure'); } if ( ! is_numeric($expire)) { $expire = time() - 86500; } else { $expire = ($expire > 0) ? time() + $expire : 0; } setcookie($prefix.$name, $value, $expire, $path, $domain, $secure); } // -------------------------------------------------------------------- /** * Fetch an item from the SERVER array * 返回过滤后的$_SERVER值 * @access public * @param string * @param bool * @return string */ function server($index = '', $xss_clean = FALSE) { return $this->_fetch_from_array($_SERVER, $index, $xss_clean); } // -------------------------------------------------------------------- /** * Fetch the IP Address * 返回当前用户的IP。如果IP地址无效,返回0.0.0.0的IP: * @return string */ public function ip_address() { // 如果已经有了ip_address 则返回 if ($this->ip_address !== FALSE) { return $this->ip_address; } $proxy_ips = config_item('proxy_ips'); if ( ! empty($proxy_ips)) { $proxy_ips = explode(',', str_replace(' ', '', $proxy_ips)); foreach (array('HTTP_X_FORWARDED_FOR', 'HTTP_CLIENT_IP', 'HTTP_X_CLIENT_IP', 'HTTP_X_CLUSTER_CLIENT_IP') as $header) { if (($spoof = $this->server($header)) !== FALSE) { // Some proxies typically list the whole chain of IP // addresses through which the client has reached us. // e.g. client_ip, proxy_ip1, proxy_ip2, etc. if (strpos($spoof, ',') !== FALSE) { $spoof = explode(',', $spoof, 2); $spoof = $spoof[0]; } if ( ! $this->valid_ip($spoof)) { $spoof = FALSE; } else { break; } } } $this->ip_address = ($spoof !== FALSE && in_array($_SERVER['REMOTE_ADDR'], $proxy_ips, TRUE)) ? $spoof : $_SERVER['REMOTE_ADDR']; } else { $this->ip_address = $_SERVER['REMOTE_ADDR']; } if ( ! $this->valid_ip($this->ip_address)) { $this->ip_address = '0.0.0.0'; } return $this->ip_address; } // -------------------------------------------------------------------- /** * Validate IP Address * 测试输入的IP地址是不是有效,返回布尔值TRUE或者FALSE。 * 注意:$this->input->ip_address()自动测试输入的IP地址本身格式是不是有效。 * @access public * @param string * @param string ipv4 or ipv6 * @return bool */ public function valid_ip($ip, $which = '') { $which = strtolower($which); // First check if filter_var is available if (is_callable('filter_var')) { switch ($which) { case 'ipv4': $flag = FILTER_FLAG_IPV4; break; case 'ipv6': $flag = FILTER_FLAG_IPV6; break; default: $flag = ''; break; } return (bool) filter_var($ip, FILTER_VALIDATE_IP, $flag); } if ($which !== 'ipv6' && $which !== 'ipv4') { if (strpos($ip, ':') !== FALSE) { $which = 'ipv6'; } elseif (strpos($ip, '.') !== FALSE) { $which = 'ipv4'; } else { return FALSE; } } $func = '_valid_'.$which; return $this->$func($ip); } // -------------------------------------------------------------------- /** * Validate IPv4 Address * 验证ipv4地址 * Updated version suggested by Geert De Deckere * * @access protected * @param string * @return bool */ protected function _valid_ipv4($ip) { $ip_segments = explode('.', $ip); // Always 4 segments needed if (count($ip_segments) !== 4) { return FALSE; } // IP can not start with 0 if ($ip_segments[0][0] == '0') { return FALSE; } // Check each segment foreach ($ip_segments as $segment) { // IP segments must be digits and can not be // longer than 3 digits or greater then 255 if ($segment == '' OR preg_match("/[^0-9]/", $segment) OR $segment > 255 OR strlen($segment) > 3) { return FALSE; } } return TRUE; } // -------------------------------------------------------------------- /** * Validate IPv6 Address * 验证ipv6地址 * @access protected * @param string * @return bool */ protected function _valid_ipv6($str) { // 8 groups, separated by : // 0-ffff per group // one set of consecutive 0 groups can be collapsed to :: $groups = 8; $collapsed = FALSE; $chunks = array_filter( preg_split('/(:{1,2})/', $str, NULL, PREG_SPLIT_DELIM_CAPTURE) ); // Rule out easy nonsense if (current($chunks) == ':' OR end($chunks) == ':') { return FALSE; } // PHP supports IPv4-mapped IPv6 addresses, so we'll expect those as well if (strpos(end($chunks), '.') !== FALSE) { $ipv4 = array_pop($chunks); if ( ! $this->_valid_ipv4($ipv4)) { return FALSE; } $groups--; } while ($seg = array_pop($chunks)) { if ($seg[0] == ':') { if (--$groups == 0) { return FALSE; // too many groups } if (strlen($seg) > 2) { return FALSE; // long separator } if ($seg == '::') { if ($collapsed) { return FALSE; // multiple collapsed } $collapsed = TRUE; } } elseif (preg_match("/[^0-9a-f]/i", $seg) OR strlen($seg) > 4) { return FALSE; // invalid segment } } return $collapsed OR $groups == 1; } // -------------------------------------------------------------------- /** * User Agent * 返回当前用户正在使用的浏览器的user agent信息。 如果不能得到数据,返回FALSE。 * 一般user_agent为空的时候被认定为手机访问,或者curl的抓取,或则会蜘蛛抓取 * @access public * @return string */ function user_agent() { if ($this->user_agent !== FALSE) { return $this->user_agent; } $this->user_agent = ( ! isset($_SERVER['HTTP_USER_AGENT'])) ? FALSE : $_SERVER['HTTP_USER_AGENT']; return $this->user_agent; } // -------------------------------------------------------------------- /** * Sanitize Globals * 清理全局数组 * This function does the following: * 这个函数做了下面的操作: * Unsets $_GET data (if query strings are not enabled) * 销毁$_GET (如果query strings 没有开启) * Unsets all globals if register_globals is enabled * 销毁所有全局数组如果register_globals开启 * * Standardizes newline characters to \n * 标准化换行符\n * @access private * @return void */ function _sanitize_globals() { // It would be "wrong" to unset any of these GLOBALS. // 销毁下面的全局数组将是错误的。 $protected = array('_SERVER', '_GET', '_POST', '_FILES', '_REQUEST', '_SESSION', '_ENV', 'GLOBALS', 'HTTP_RAW_POST_DATA', 'system_folder', 'application_folder', 'BM', 'EXT', 'CFG', 'URI', 'RTR', 'OUT', 'IN'); // Unset globals for securiy.为了安全销毁除了上面之外的全局数组 // This is effectively the same as register_globals = off // 这样的效果和register_globals是相同的 // 经过下面处理后,所有的非保护的全局变量将被删除掉 foreach (array($_GET, $_POST, $_COOKIE) as $global) { if ( ! is_array($global)) { if ( ! in_array($global, $protected)) { global $$global; $$global = NULL; } } else { foreach ($global as $key => $val) { if ( ! in_array($key, $protected)) { global $$key; $$key = NULL; } } } } // Is $_GET data allowed? If not we'll set the $_GET to an empty array // 是否允许$_GET数据? 如果不允许的话,设置$_GET为空数组 if ($this->_allow_get_array == FALSE) { $_GET = array(); } else { if (is_array($_GET) AND count($_GET) > 0) { foreach ($_GET as $key => $val) { $_GET[$this->_clean_input_keys($key)] = $this->_clean_input_data($val); } } } // Clean $_POST Data // 过滤$_POST 数组 if (is_array($_POST) AND count($_POST) > 0) { foreach ($_POST as $key => $val) { $_POST[$this->_clean_input_keys($key)] = $this->_clean_input_data($val); } } // Clean $_COOKIE Data // 过滤$_COOKIE数组 if (is_array($_COOKIE) AND count($_COOKIE) > 0) { // Also get rid of specially treated cookies that might be set by a server // or silly application, that are of no use to a CI application anyway // but that when present will trip our 'Disallowed Key Characters' alarm // http://www.ietf.org/rfc/rfc2109.txt // note that the key names below are single quoted strings, and are not PHP variables unset($_COOKIE['$Version']); unset($_COOKIE['$Path']); unset($_COOKIE['$Domain']); foreach ($_COOKIE as $key => $val) { $_COOKIE[$this->_clean_input_keys($key)] = $this->_clean_input_data($val); } } // Sanitize PHP_SELF $_SERVER['PHP_SELF'] = strip_tags($_SERVER['PHP_SELF']); // CSRF Protection check on HTTP requests // CSRF保护检测http请求 if ($this->_enable_csrf == TRUE && ! $this->is_cli_request()) { $this->security->csrf_verify(); } log_message('debug', "Global POST and COOKIE data sanitized"); } // -------------------------------------------------------------------- /** * Clean Input Data * 过滤input数据 * This is a helper function. It escapes data and * standardizes newline characters to \n * * @access private * @param string * @return string */ function _clean_input_data($str) { if (is_array($str)) { $new_array = array(); foreach ($str as $key => $val) { $new_array[$this->_clean_input_keys($key)] = $this->_clean_input_data($val); } return $new_array; } /* We strip slashes if magic quotes is on to keep things consistent 如果小于PHP5.4版本,并且get_magic_quotes_gpc开启了,则去掉斜线。 NOTE: In PHP 5.4 get_magic_quotes_gpc() will always return 0 and it will probably not exist in future versions at all。 注意:在PHP5.4及之后版本,get_magic_quotes_gpc()将总是返回0, 在后续版本中可能会移除该特性 */ if ( ! is_php('5.4') && get_magic_quotes_gpc()) { $str = stripslashes($str); } // Clean UTF-8 if supported 如果支持清理utf8 if (UTF8_ENABLED === TRUE) { $str = $this->uni->clean_string($str); } // Remove control characters $str = remove_invisible_characters($str); // Should we filter the input data? if ($this->_enable_xss === TRUE) { $str = $this->security->xss_clean($str); } // Standardize newlines if needed if ($this->_standardize_newlines == TRUE) { if (strpos($str, "\r") !== FALSE) { $str = str_replace(array("\r\n", "\r", "\r\n\n"), PHP_EOL, $str); } } return $str; } // -------------------------------------------------------------------- /** * Clean Keys * 过滤键值 * This is a helper function. To prevent malicious users * from trying to exploit keys we make sure that keys are * only named with alpha-numeric text and a few other items. * * @access private * @param string * @return string */ function _clean_input_keys($str) { if ( ! preg_match("/^[a-z0-9:_\/-]+$/i", $str)) { exit('Disallowed Key Characters.'); } // Clean UTF-8 if supported if (UTF8_ENABLED === TRUE) { $str = $this->uni->clean_string($str); } return $str; } // -------------------------------------------------------------------- /** * Request Headers * 返回请求头(header)数组。 * In Apache, you can simply call apache_request_headers(), however for * people running other webservers the function is undefined. * * @param bool XSS cleaning * * @return array */ public function request_headers($xss_clean = FALSE) { // Look at Apache go! if (function_exists('apache_request_headers')) { $headers = apache_request_headers(); } else { $headers['Content-Type'] = (isset($_SERVER['CONTENT_TYPE'])) ? $_SERVER['CONTENT_TYPE'] : @getenv('CONTENT_TYPE'); foreach ($_SERVER as $key => $val) { if (strncmp($key, 'HTTP_', 5) === 0) { $headers[substr($key, 5)] = $this->_fetch_from_array($_SERVER, $key, $xss_clean); } } } // take SOME_HEADER and turn it into Some-Header foreach ($headers as $key => $val) { $key = str_replace('_', ' ', strtolower($key)); $key = str_replace(' ', '-', ucwords($key)); $this->headers[$key] = $val; } return $this->headers; } // -------------------------------------------------------------------- /** * Get Request Header * 返回请求头(request header)数组中某一个元素的值 * Returns the value of a single member of the headers class member * * @param string array key for $this->headers * @param boolean XSS Clean or not * @return mixed FALSE on failure, string on success */ public function get_request_header($index, $xss_clean = FALSE) { if (empty($this->headers)) { $this->request_headers(); } if ( ! isset($this->headers[$index])) { return FALSE; } if ($xss_clean === TRUE) { return $this->security->xss_clean($this->headers[$index]); } return $this->headers[$index]; } // -------------------------------------------------------------------- /** * Is ajax Request? * 判断是否为ajax请求 * Test to see if a request contains the HTTP_X_REQUESTED_WITH header * * @return boolean */ public function is_ajax_request() { return ($this->server('HTTP_X_REQUESTED_WITH') === 'XMLHttpRequest'); } // -------------------------------------------------------------------- /** * Is cli Request? * 判断是否来自cli请求 * Test to see if a request was made from the command line * * @return bool */ public function is_cli_request() { return (php_sapi_name() === 'cli' OR defined('STDIN')); } } /* End of file Input.php */ /* Location: ./system/core/Input.php */ ~~~
';

Security.php

最后更新于:2022-04-01 20:46:12

~~~ '[removed]', 'document.write' => '[removed]', '.parentNode' => '[removed]', '.innerHTML' => '[removed]', 'window.location' => '[removed]', '-moz-binding' => '[removed]', '' => '-->', ' '' => '' ); /* never allowed, regex replacement */ /** * List of never allowed regex replacement * 不允许的正则替换字符串列表 * @var array * @access protected */ protected $_never_allowed_regex = array( 'javascript\s*:', 'expression\s*(\(|&\#40;)', // CSS and IE 'vbscript\s*:', // IE, surprise! 'Redirect\s+302', "([\"'])?data\s*:[^\\1]*?base64[^\\1]*?,[^\\1]*?\\1?" ); /** * Constructor * * @return void */ public function __construct() { // Is CSRF protection enabled? // csrf 是否开启 if (config_item('csrf_protection') === TRUE) { // CSRF config 读取CSRF 配置并赋值给本类下的对应的属性 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 // 添加应用指定的cookie前缀 if (config_item('cookie_prefix')) { $this->_csrf_cookie_name = config_item('cookie_prefix').$this->_csrf_cookie_name; } // Set the CSRF hash // 设置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 // 如果不是post请求我们要设置 CSRF cookie if (strtoupper($_SERVER['REQUEST_METHOD']) !== 'POST') { return $this->csrf_set_cookie(); } // Do the tokens exist in both the _POST and _COOKIE arrays? // 如果请求令牌不存在,调用csrf_show_error 报错 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 // 销毁领牌子,因为我们不想污染_POST 数组 unset($_POST[$this->_csrf_token_name]); // Nothing should last forever // 销毁cookie名 并重新设置hash和cookie 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 * 设置伪造cookie保护跨站请求 * @return object */ public function csrf_set_cookie() { $expire = time() + $this->_csrf_expire; $secure_cookie = (config_item('cookie_secure') === TRUE) ? 1 : 0; // 当存在https时设置cookie if ($secure_cookie && (empty($_SERVER['HTTPS']) OR strtolower($_SERVER['HTTPS']) === 'off')) { return FALSE; } // 设置cookie 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 * 显示CSRF错误 * @return void */ public function csrf_show_error() { show_error('The action you have requested is not allowed.'); } // -------------------------------------------------------------------- /** * Get CSRF Hash * 获取CSRF hash * Getter Method * * @return string self::_csrf_hash */ public function get_csrf_hash() { return $this->_csrf_hash; } // -------------------------------------------------------------------- /** * Get CSRF Token Name * 获取CSRF 令排名 * 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. * 对数据进行过滤,从而可以防止跨站脚本攻击。这个函数做了一些工作,但是它是非常彻底的, * 甚至可以防止大多数模糊的XSS企图。当然,没有什么是100%安全的, * 但是我们在这个过滤器中已经做了所欲我们所能做想到的了。 * * 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); // Validate Entities in URLs // 验证在URL中的字符实体 $str = $this->_validate_entities($str); /* * URL Decode * URL解码 * Just in case stuff like this is submitted: * 防止下面这样的东西提交 * Google * * Note: Use rawurldecode() so it does not remove plus signs * rawurldecode() 不会把加号('+')解码为空格,而 urldecode() 可以。 * */ $str = rawurldecode($str); /* * Convert character entities to ASCII * 把实体字符转换成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-z]+=([\'\"]).*?\\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 * 这用来防止字符串类似于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. * 注意:preg_replace在这里是极其缓慢的对于大块的数据,所以使用str_replace * */ if (strpos($str, "\t") !== FALSE) { $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 * 使PHP标签安全 * Note: XML tags are inadvertently replaced too: * 注意: XML标签也会被无意的替换 * '), 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', 'script', 'base64', 'applet', 'alert', 'document', 'write', 'cookie', 'window' ); foreach ($words as $word) { $temp = ''; for ($i = 0, $wordlen = strlen($word); $i < $wordlen; $i++) { $temp .= substr($word, $i, 1)."\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($temp, 0, -3).')(\W)#is', array($this, '_compact_exploded_words'), $str); } /* * Remove disallowed Javascript in links or img tags * 移除在链接和图片标签中不允许的javascript代码 * We used to do some version comparisons and use of stripos for PHP5, * 我们通常在PHP5中使用stripos做一些版本的比较, * but it is dog slow compared to these simplified non-capturing * 但是特别是当模式在字符串中存在的时候,它要比非捕获的preg_match()慢很多 * preg_match(), especially if the pattern exists in the string */ 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/i", $str) OR preg_match("/xss/i", $str)) { $str = preg_replace("#<(/*)(script|xss)(.*?)\>#si", '[removed]', $str); } } while($original != $str); unset($original); // Remove evil attributes such as style, onclick and xmlns // 移除有害的属性,比如style , onclick , xmlns $str = $this->_remove_evil_attributes($str, $is_image); /* * Sanitize naughty HTML elements * 清理不适当的HTML元素 * If a tag containing any of the words in the list * below is found, the tag gets converted to entities. * 如果一个标签包含任何一个下面列表中的单词,这个标签转换为一个字符实体 * So this: * Becomes: */ $naughty = 'alert|applet|audio|basefont|base|behavior|bgsound|blink|body|embed|expression|form|frameset|frame|head|html|ilayer|iframe|input|isindex|layer|link|meta|object|plaintext|style|script|textarea|title|video|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. * 上面的类似,仅仅替换查询到的类似于PHP和Javascript命令的不被允许的标签 * 胜过移除这些代码,转换这些代码为不可执行的实体更好 * * For example: eval('some code') * Becomes: eval('some code') */ $str = preg_replace('#(alert|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) ? TRUE: FALSE; } log_message('debug', "XSS Filtering completed"); return $str; } // -------------------------------------------------------------------- /** * Random Hash for protecting URLs * 随即生成一个_xss_hssh * @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 * HTML 实体解码 * This function is a replacement for html_entity_decode() * 这个函数用来替换 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. * 当编码字符后没有写;时,大部分浏览器都能够正确的解释代码,但是,html_entity_decode将不会解释它 * html_entity_decode()不会转换没有分号的实体,所以使用自己的解决方案 * @param string * @param string * @return string */ public function entity_decode($str, $charset='UTF-8') { if (stristr($str, '&') === FALSE) { return $str; } $str = html_entity_decode($str, ENT_COMPAT, $charset); $str = preg_replace('~&#x(0*[0-9a-f]{2,5})~ei', 'chr(hexdec("\\1"))', $str); return preg_replace('~&#([0-9]{2,4})~e', 'chr(\\1)', $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); return stripslashes(str_replace($bad, '', $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 * 回调函数,用于xss_clean(),从类似于 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) * 移除有害的html属性,(像事件处理和样式) * It removes the evil attribute and either: * - Everything up until a space * For example, everything between the pipes: * * - Everything inside the quotes * For example, everything between the pipes: * * * @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 // 所有的havascript事件处理器 $evil_attributes = array('on\w*', 'style', 'xmlns', 'formaction'); if ($is_image === TRUE) { /* * Adobe Photoshop puts XML metadata into JFIF images, * including namespacing, so we have to allow this for images. * Adobe Photoshop在JFIF图片中放入了XML元数据 * 包含命名空间,所以我们必须对图片允许这些 */ unset($evil_attributes[array_search('xmlns', $evil_attributes)]); } do { $count = 0; $attribs = array(); // find occurrences of illegal attribute strings without quotes // 找出没有加引号的的不合法的属性 preg_match_all('/('.implode('|', $evil_attributes).')\s*=\s*([^\s>]*)/is', $str, $matches, PREG_SET_ORDER); foreach ($matches as $attr) { $attribs[] = preg_quote($attr[0], '/'); } // find occurrences of illegal 非法 attribute strings with quotes (042 and 047 are octal quotes) // 找出没有引号的不合法属性(042,4,0是八进制引号) preg_match_all("/(".implode('|', $evil_attributes).")\s*=\s*(\042|\047)([^\\2]*?)(\\2)/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 // 替换html标签中的非法属性 if (count($attribs) > 0) { $str = preg_replace("/<(\/?[^><]+?)([^A-Za-z<>\-])(.*?)(".implode('|', $attribs).")(.*?)([\s><])([><]*)/i", '<$1 $3$5$6$7', $str, -1, $count); } } while ($count); return $str; } // -------------------------------------------------------------------- /** * Sanitize Naughty HTML * 消除有害的html * Callback function for xss_clean() to remove naughty HTML elements * * @param array * @return string */ protected function _sanitize_naughty_html($matches) { // encode opening brace $str = '<'.$matches[1].$matches[2].$matches[3]; // encode captured opening or closing brace to prevent recursive vectors $str .= str_replace(array('>', '<'), array('>', '<'), $matches[4]); return $str; } // -------------------------------------------------------------------- /** * JS Link Removal * js链接清理 * 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 * 调用xss_clean 清理连接 * @param array * @return string */ protected function _js_link_removal($match) { return str_replace( $match[1], preg_replace( '#href=.*?(alert\(|alert&\#40;|javascript\:|livescript\:|mocha\:|charset\=|window\.|document\.|\.cookie|_filter_attributes(str_replace(array('<', '>'), '', $match[1])) ), $match[0] ); } // -------------------------------------------------------------------- /** * JS Image Removal * js图片清理 * 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\(|alert&\#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 * html实体解码 * Used as a callback for XSS Clean * * @param array * @return string */ protected function _decode_entity($match) { return $this->entity_decode($match[0], strtoupper(config_item('charset'))); } // -------------------------------------------------------------------- /** * Validate URL entities * 验证URL字符实体 * Called by xss_clean() * * @param string * @return string */ protected function _validate_entities($str) { /* * Protect GET variables in URLs * 保护url中的GET变量 */ // 901119URL5918AMP18930PROTECT8198 $str = preg_replace('|\&([a-z\_0-9\-]+)\=([a-z\_0-9\-]+)|i', $this->xss_hash()."\\1=\\2", $str); /* * Validate standard character entities * 验证标准字符实体 * * Add a semicolon if missing. We do this to enable * the conversion of entities to ASCII later. * 如果没有的话,添加一个分号。这样做是为了以后允许字符实体到ASCII的转换 * */ $str = preg_replace('#(&\#?[0-9a-z]{2,})([\x00-\x20])*;?#i', "\\1;\\2", $str); /* * Validate UTF16 two byte encoding (x00) * 验证UTF16两个字节的编码(x00) * Just as above, adds a semicolon if missing. * 像上面一样如果不存在添加一个分号。 */ $str = preg_replace('#(&\#x?)([0-9A-F]+);?#i',"\\1\\2;",$str); /* * Un-Protect GET variables in URLs * URL中不保护的GET变量 */ $str = str_replace($this->xss_hash(), '&', $str); return $str; } // ---------------------------------------------------------------------- /** * 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 * 设置跨站请求保护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 // 如果Cookie存在,我们将使用原先的值 // 我们不是必须要在每各加载的页面都要更新它,因为当一个页面可能要包含嵌入的子页面时, // 嵌入的子页面会造成这个特性的失败 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; } } /* End of file Security.php */ /* Location: ./system/libraries/Security.php */ ~~~
';

Output.php

最后更新于:2022-04-01 20:46:10

~~~ _zlib_oc // 如果配置项中开启了输出压缩功能则 $this->_zlib_oc 的值为on $this->_zlib_oc = @ini_get('zlib.output_compression'); // Get mime types for later // 获取mimetype if (defined('ENVIRONMENT') AND file_exists(APPPATH.'config/'.ENVIRONMENT.'/mimes.php')) { include APPPATH.'config/'.ENVIRONMENT.'/mimes.php'; } else { include APPPATH.'config/mimes.php'; } // $mimes 是mimes.php中定义的一个数组 $this->mime_types = $mimes; log_message('debug', "Output Class Initialized"); } // -------------------------------------------------------------------- /** * Get Output * 使用这个方法,你可以得到将要输出的数据,并把它保存起来 * Returns the current output string * 返回当前输出的字符串 * @access public * @return string */ function get_output() { return $this->final_output; } // -------------------------------------------------------------------- /** * Set Output * * Sets the output string * 设置输出的字符串 * @access public * @param string * @return void */ function set_output($output) { $this->final_output = $output; return $this; } // -------------------------------------------------------------------- /** * Append Output * 在最终输出字符串后,追加数据 * Appends data onto the output string * * @access public * @param string * @return void */ function append_output($output) { if ($this->final_output == '') { $this->final_output = $output; } else { $this->final_output .= $output; } return $this; } // -------------------------------------------------------------------- /** * Set Header * 使用此方法,允许你设置将会被发送到浏览器的HTTP协议的标头,作用相当于php的标准函数: header()。 * Lets you set a server header which will be outputted with the final display. * 允许您设置一个服务器头用于最终的显示输出。 * Note: If a file is cached, headers will not be sent. We need to figure 计算 out * how to permit header data to be saved with the cache data... * * @access public * @param string * @param bool * @return void */ function set_header($header, $replace = TRUE) { // If zlib.output_compression is enabled it will compress the output, // but it will not modify the content-length header to compensate 补偿 for // the reduction减少 还原, causing the browser to hang waiting for more data. // We'll just skip content-length in those cases. if ($this->_zlib_oc && strncasecmp($header, 'content-length', 14) == 0) { return; } $this->headers[] = array($header, $replace); return $this; } // -------------------------------------------------------------------- /** * Set Content Type Header * 设置Content-Type * @access public * @param string extension of the file we're outputting * @return void */ function set_content_type($mime_type) { if (strpos($mime_type, '/') === FALSE) { $extension = ltrim($mime_type, '.'); // Is this extension supported? if (isset($this->mime_types[$extension])) { $mime_type =& $this->mime_types[$extension]; if (is_array($mime_type)) { $mime_type = current($mime_type); } } } $header = 'Content-Type: '.$mime_type; $this->headers[] = array($header, TRUE); return $this; } // -------------------------------------------------------------------- /** * Set HTTP Status Header * moved to Common procedural functions in 1.7.2 * 允许你手动设置服务器状态头(header) * @access public * @param int the status code * @param string * @return void */ function set_status_header($code = 200, $text = '') { set_status_header($code, $text); return $this; } // -------------------------------------------------------------------- /** * Enable/disable Profiler * 允许你开启或禁用分析器 * @access public * @param bool * @return void */ function enable_profiler($val = TRUE) { $this->enable_profiler = (is_bool($val)) ? $val : TRUE; return $this; } // -------------------------------------------------------------------- /** * Set Profiler Sections * 设置$this->_profiler_sections * Allows override of default / config settings for Profiler section display * 允许你在评测器启用时,控制(开/关)其特定部分 * * @access public * @param array * @return void */ function set_profiler_sections($sections) { foreach ($sections as $section => $enable) { $this->_profiler_sections[$section] = ($enable !== FALSE) ? TRUE : FALSE; } return $this; } // -------------------------------------------------------------------- /** * Set Cache * 设置缓存以及缓存时间 * @access public * @param integer 其中 $time 是你希望缓存更新的 分钟 数 * @return void */ function cache($time) { $this->cache_expiration = ( ! is_numeric($time)) ? 0 : $time; return $this; } // -------------------------------------------------------------------- /** * Display Output * 显示输出 * All "view" data is automatically put into this variable by the controller class: * * $this->final_output * * This function sends the finalized output data to the browser along * with any server headers and profile data. It also stops the * benchmark timer so the page rendering speed and memory usage can be shown. * * @access public * @param string * @return mixed */ function _display($output = '') { // Note: We use globals because we can't use $CI =& get_instance() // since this function is sometimes called by the caching mechanism, // which happens before the CI super object is available. // 注意:我们使用global 是因为我们不能使用$CI =& get_instance() global $BM, $CFG; // Grab the super object if we can. // //当然如果可以拿到超级控制器,我们先拿过来。 if (class_exists('CI_Controller')) { $CI =& get_instance(); } // -------------------------------------------------------------------- // Set the output data // 设置输出数据 if ($output == '') { $output =& $this->final_output; } // -------------------------------------------------------------------- // Do we need to write a cache file? Only if the controller does not have its // own _output() method and we are not dealing with a cache file, which we // can determine by the existence of the $CI object above // 如果缓存时间>0 ,$CI 超级对象存在并且超级对象下面存在_output 方法 // 调用_write_cache 方法,写一个缓存文件 if ($this->cache_expiration > 0 && isset($CI) && ! method_exists($CI, '_output')) { $this->_write_cache($output); } // -------------------------------------------------------------------- // Parse out the elapsed time and memory usage, // then swap the pseudo-variables with the data // 计算代码执行时间和内存使用时间 $elapsed = $BM->elapsed_time('total_execution_time_start', 'total_execution_time_end'); // 如果$this->parse_exec_vars为true,将输出中的{elapsed_time},{memory_usage} // 替换为计算出的时间。 if ($this->parse_exec_vars === TRUE) { $memory = ( ! function_exists('memory_get_usage')) ? '0' : round(memory_get_usage()/1024/1024, 2).'MB'; $output = str_replace('{elapsed_time}', $elapsed, $output); $output = str_replace('{memory_usage}', $memory, $output); } // -------------------------------------------------------------------- // Is compression requested?压缩传输的处理。 if ($CFG->item('compress_output') === TRUE && $this->_zlib_oc == FALSE) { if (extension_loaded('zlib')) { if (isset($_SERVER['HTTP_ACCEPT_ENCODING']) AND strpos($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip') !== FALSE) { ob_start('ob_gzhandler'); } } } // -------------------------------------------------------------------- // Are there any server headers to send? // 有没有服务器头发送? if (count($this->headers) > 0) { foreach ($this->headers as $header) { @header($header[0], $header[1]); } } // -------------------------------------------------------------------- // Does the $CI object exist? // If not we know we are dealing with a cache file so we'll // simply echo out the data and exit. // 如果没有$CI就证明当前是一个缓存的输出,我们只简单的发送数据并退出 if ( ! isset($CI)) { echo $output; log_message('debug', "Final output sent to browser"); log_message('debug', "Total execution time: ".$elapsed); return TRUE; } // -------------------------------------------------------------------- // Do we need to generate profile data? // If so, load the Profile class and run it. // 如果开启了性能分析我们就调用, // 会生成一些报告到页面尾部用于辅助我们调试。 if ($this->enable_profiler == TRUE) { $CI->load->library('profiler'); if ( ! empty($this->_profiler_sections)) { $CI->profiler->set_sections($this->_profiler_sections); } // If the output data contains closing and tags // we will remove them and add them back after we insert the profile data // 如果存在标签,我们将删除,插入我们的性能分析代码后再添加回去 if (preg_match("|.*?|is", $output)) { $output = preg_replace("|.*?|is", '', $output); $output .= $CI->profiler->run(); $output .= ''; } else { $output .= $CI->profiler->run(); } } // -------------------------------------------------------------------- // Does the controller contain a function named _output()? // If so send the output there. Otherwise, echo it. // 如果控制器中有_output 这个方法我们直接调用 // 如果没有直接发送数据到浏览器 if (method_exists($CI, '_output')) { $CI->_output($output); } else { echo $output; // Send it to the browser! } log_message('debug', "Final output sent to browser"); log_message('debug', "Total execution time: ".$elapsed); } // -------------------------------------------------------------------- /** * Write a Cache File * 生成一个缓存文件 * @access public * @param string * @return void */ function _write_cache($output) { // 调用超级对象 $CI =& get_instance(); // 找到缓存路径 $path = $CI->config->item('cache_path'); $cache_path = ($path == '') ? APPPATH.'cache/' : $path; // 如果缓存路径不是一个文件夹或者不可写 ,报错返回。 if ( ! is_dir($cache_path) OR ! is_really_writable($cache_path)) { log_message('error', "Unable to write cache file: ".$cache_path); return; } // 获取$uri $uri = $CI->config->item('base_url'). $CI->config->item('index_page'). $CI->uri->uri_string(); // 生成缓存文件。 $cache_path .= md5($uri); if ( ! $fp = @fopen($cache_path, FOPEN_WRITE_CREATE_DESTRUCTIVE)) { log_message('error', "Unable to write cache file: ".$cache_path); return; } // 计算缓存文件过期时间。 $expire = time() + ($this->cache_expiration * 60); if (flock($fp, LOCK_EX)) { fwrite($fp, $expire.'TS--->'.$output); flock($fp, LOCK_UN); } else { log_message('error', "Unable to secure a file lock for file at: ".$cache_path); return; } fclose($fp); @chmod($cache_path, FILE_WRITE_MODE); log_message('debug', "Cache file written: ".$cache_path); } // -------------------------------------------------------------------- /** * Update/serve a cached file * 在CodeIgniter.php里面有调用此方法,此方法是负责缓存的输出, * 如果在CodeIgniter.php中调用此方法有输出,则 * 本次请求的运行将直接结束,直接以缓存输出作为响应。 * * @access public * @param object config class * @param object uri class * @return void */ function _display_cache(&$CFG, &$URI) { // 取得保存缓存的路径 $cache_path = ($CFG->item('cache_path') == '') ? APPPATH.'cache/' : $CFG->item('cache_path'); // Build the file path. The file name is an MD5 hash of the full URI // 一条准确的路由都会对应一个缓存文件,缓存文件是对应路由字符串的md5密文。 $uri = $CFG->item('base_url'). $CFG->item('index_page'). $URI->uri_string; $filepath = $cache_path.md5($uri); // 如果没有此缓存文件,获取缓存内容失败,则可以返回FALSE。 if ( ! @file_exists($filepath)) { return FALSE; } // 如果有此缓存文件,但是无法读,获取缓存内容失败,同样返回FALSE。 if ( ! $fp = @fopen($filepath, FOPEN_READ)) { return FALSE; } // 打开到缓存文件,并以$fp作为句柄。下一步先取得共享锁(读取)。 flock($fp, LOCK_SH); $cache = ''; if (filesize($filepath) > 0) { $cache = fread($fp, filesize($filepath)); } // 解锁 flock($fp, LOCK_UN); // 关闭文件连接。 fclose($fp); // 下面这个TS--->字样,只是因为CI的缓存文件里面的内容 // 是规定以数字+TS--->开头而已。这个数字是代表创建时间。 // 如果不符合此结构,可视为非CI的缓存文件,或者文件已损坏, // 获取缓存内容失败,返回FALSE。 // Strip out the embedded timestamp if ( ! preg_match("/(\d+TS--->)/", $cache, $match)) { return FALSE; } // Has the file expired? If so we'll delete it. // 判断缓存是否过期,如果过期我们将删除它 if (time() >= trim(str_replace('TS--->', '', $match['1']))) { if (is_really_writable($cache_path)) { @unlink($filepath); log_message('debug', "Cache file has expired. File deleted"); return FALSE; } } // Display the cache $this->_display(str_replace($match['0'], '', $cache)); log_message('debug', "Cache file is current. Sending it to browser."); return TRUE; } } // END Output Class /* End of file Output.php */ /* Location: ./system/core/Output.php */ ~~~
';

Router.php

最后更新于:2022-04-01 20:46:08

~~~ config =& load_class('Config', 'core'); $this->uri =& load_class('URI', 'core'); log_message('debug', "Router Class Initialized"); } // -------------------------------------------------------------------- /** * Set the route mapping * * This function determines 确定,决心 what should be served based on the URI request, * as well as any "routes" that have been set in the routing config file. * 设置默认的路由信息,如果不存在控制器信息,则根据routes.php的设置来加载默认的控制器, * * @access private * @return void */ function _set_routing() { // Are query strings enabled in the config file? Normally CI doesn't utilize 运用 query strings // since URI segments are more search-engine friendly, but they can optionally 视情况 be used. // If this feature is enabled, we will gather the directory/class/method a little differently // 如果项目是允许通过query_strings的形式,并且有通过$_GET的方式请求控制器的话,则以query_string形式路由 // 上面这里为什么还要判断有没有通过get的方式指定控制器? // 其实是因为如果允许query_string的形式请求路由,但是却没有在APPPATH/config/config.php下配置 // controller_trigger,function_trigger,directory_trigger这三项的话,也是不能使用query_strings形式的 // 此时,我们依然会采用“段”的形式。 $segments = array(); if ($this->config->item('enable_query_strings') === TRUE AND isset($_GET[$this->config->item('controller_trigger')])) { //取得目录名,控制名和方法名传递的变量名。这三项都是在config/config.php里面定义的。 if (isset($_GET[$this->config->item('directory_trigger')])) { $this->set_directory(trim($this->uri->_filter_uri($_GET[$this->config->item('directory_trigger')]))); $segments[] = $this->fetch_directory(); } if (isset($_GET[$this->config->item('controller_trigger')])) { $this->set_class(trim($this->uri->_filter_uri($_GET[$this->config->item('controller_trigger')]))); $segments[] = $this->fetch_class(); } if (isset($_GET[$this->config->item('function_trigger')])) { $this->set_method(trim($this->uri->_filter_uri($_GET[$this->config->item('function_trigger')]))); $segments[] = $this->fetch_method(); } } // Load the routes.php file. // 根据当前环境加载APPPATH下面的routes.php if (defined('ENVIRONMENT') AND is_file(APPPATH.'config/'.ENVIRONMENT.'/routes.php')) { include(APPPATH.'config/'.ENVIRONMENT.'/routes.php'); } elseif (is_file(APPPATH.'config/routes.php')) { include(APPPATH.'config/routes.php'); } // 下面的这个$route变量是在routes.php中定义的用来设置默认的控制器和默认的404页面 $this->routes = ( ! isset($route) OR ! is_array($route)) ? array() : $route; unset($route);// 利用完就干掉,过河拆桥,毫不留情。 // Set the default controller so we can display it in the event事件 // the URI doesn't correlated 相关的 to a valid 有效的 controller. // 根据刚才的配置信息,设定默认控制器,没有的话,就为FLASE。 $this->default_controller = ( ! isset($this->routes['default_controller']) OR $this->routes['default_controller'] == '') ? FALSE : strtolower($this->routes['default_controller']); // Were there any query string segments? If so, we'll validate them and bail out since we're done. // 验证有没有通过query string的方式拿到目录名,控制名和方法名其中的任何一个。 // 如果拿到了就直接确定路由返回 if (count($segments) > 0) { // 确定并设置路由。 return $this->_validate_request($segments); } // Fetch the complete URI string // 这个函数的作用是从uri中检测处理,把我们确定路由需要的信息(例如index.php/index/welcome/1后 // 面index/welcome/1这串)放到$this->uri->uri_string中。 $this->uri->_fetch_uri_string(); // Is there a URI string? If not, the default controller specified in the "routes" file will be shown. // 如果uri_string为空的话,那么就用把路由设置为默认的。 /*if ($this->uri->uri_string == '') { return $this->_set_default_controller(); }*/ // Do we need to remove the URL suffix? // 去掉URI后缀,因为CI允许在uri后面加后缀,但它其实对我们寻找路由是多余,而且会造成影响的,所以先去掉。 $this->uri->_remove_url_suffix(); // Compile 编译 the segments into an array // 将uri拆分正段同时对每个段进行过滤,并存入$this->segments[]中 $this->uri->_explode_segments(); // Parse any custom routing that may exist // 处理路由,根据路由设置APPPATH/config/routes.php来 $this->_parse_routes(); // Re-index the segment array so that it starts with 1 rather than 0 // 将uri段索引设置为从1开始 $this->uri->_reindex_segments(); } // -------------------------------------------------------------------- /** * Set the default controller * 设置默认的控制器 * @access private * @return void */ function _set_default_controller() { // 在Router::_set_routing()函数中从配置文件里面读取默认控制器名,如果没有就有FALSE // 本文件的158行 if ($this->default_controller === FALSE) { show_error("Unable to determine what should be displayed. A default route has not been specified in the routing file."); } // Is the method being specified? // 通过判断$this->default_controller有没有/来确定是否有指定的方法 // 如果没有设置为默认方法index if (strpos($this->default_controller, '/') !== FALSE) { $x = explode('/', $this->default_controller); $this->set_class($x[0]); $this->set_method($x[1]); $this->_set_request($x); } else { $this->set_class($this->default_controller); $this->set_method('index'); $this->_set_request(array($this->default_controller, 'index')); } // re-index the routed segments array so it starts with 1 rather than 0 // 重新索引段,使得出来的段以下标1开始保存。 $this->uri->_reindex_segments(); log_message('debug', "No URI present. Default controller set."); } // -------------------------------------------------------------------- /** * Set the Route * 设置路由 * This function takes 取走,预备动作 an array of URI segments as * input, and sets the current class/method * * @access private * @param array * @param bool * @return void */ function _set_request($segments = array()) { // Router::_validate_request()的作用是检测寻找出一个正确存在的路由,并确定它 $segments = $this->_validate_request($segments); // 这个函数是由_set_default_controller总调用的看216-230行会发现这个$segments 是肯定不会为空的 // 那么下面这两句可能是为了防止本方法在其他的地方调用当参数为空的时候调用_set_default_controller() // 再调用回来$segments就不会为空了,因为当$segments为空的时候是不可能进行设置路由的。 if (count($segments) == 0) { return $this->_set_default_controller(); } // 设置类名也就是目录名 $this->set_class($segments[0]); // 如果方法名存在则设置如果不存在则设置为index if (isset($segments[1])) { // A standard method request $this->set_method($segments[1]); } else { // This lets the "routed" segment array identify that the default // index method is being used. $segments[1] = 'index'; } // Update our "routed" segment array to contain the segments. // Note: If there is no custom routing, this array will be // identical to $this->uri->segments // 更新路由的段数组,这里如果没有自定义的路由那么将和$this->uri->segments是一样的 $this->uri->rsegments = $segments; } // -------------------------------------------------------------------- /** * Validates 使有效 the supplied segments. Attempts 企图 to determine 决定 the path to * the controller. * 使提供的段有效并企图决定控制器的路径 * @access private * @param array * @return array */ function _validate_request($segments) { // ?????????????? if (count($segments) == 0) { return $segments; } // Does the requested controller exist in the root folder? // 确定存在$segments[0]是否存在于APPPATH/controllers/文件夹下的php文件 if (file_exists(APPPATH.'controllers/'.$segments[0].'.php')) { return $segments; } // Is the controller in a sub-folder? // $segments[0]是否为APPPATH/controllers下的子目录 if (is_dir(APPPATH.'controllers/'.$segments[0])) { // Set the directory and remove it from the segment array // 如果的确是目录,那么就可以确定路由的目录部分了。 设置目录 $this->set_directory($segments[0]); // 去掉目录部分。进一步进行路由寻找。 $segments = array_slice($segments, 1); // 如果uri请求中除了目录还有其它段,那说明是有请求某指定控制器的。 if (count($segments) > 0) { // Does the requested controller exist in the sub-folder? // 判断请求的$segments[0]是不是在于APPPATH/controllers/的子目录中php文件 if ( ! file_exists(APPPATH.'controllers/'.$this->fetch_directory().$segments[0].'.php')) { // 报错也有两方式,一种是默认的,一种是自义定的。 // 下面这个404_override就是在config/routes.php定义的一个路由找不 // 到时候的默认处理控制器了,如果有定义我们调用它。 if ( ! empty($this->routes['404_override'])) { $x = explode('/', $this->routes['404_override']); // 把刚才设置好的路由的目录部分去掉,因为现在路由是我们定义的404路由。 $this->set_directory(''); // 这里可以看出,我们定义的404路由是不允许放在某个目录下的,只能直接放在controllers/下 $this->set_class($x[0]); $this->set_method(isset($x[1]) ? $x[1] : 'index'); return $x; } else { // 默认404报错 show_404($this->fetch_directory().$segments[0]); } } } else { // 如果uri请求中只有目录我们才会来到这 // Is the method being specified 指定的 in the route? // 下面这个判断只是判断一下$this->default_controller有没有指定方法而已。 if (strpos($this->default_controller, '/') !== FALSE) { $x = explode('/', $this->default_controller); $this->set_class($x[0]); $this->set_method($x[1]); } else { $this->set_class($this->default_controller); $this->set_method('index'); } // Does the default controller exist in the sub-folder? // 判断APPPATH/controllers/目录/下面是否存在默认的方法 if ( ! file_exists(APPPATH.'controllers/'.$this->fetch_directory().$this->default_controller.'.php')) { $this->directory = ''; return array(); } } return $segments; } // If we've gotten 达到 this far 遥远的 it means that the URI does not correlate 使相关联 to a valid // controller class. We will now see if there is an override // 来到这里,就说明了,即找不到controllers/下相应的控制器,也找不到这样的目录。那就报错咯。 if ( ! empty($this->routes['404_override'])) { $x = explode('/', $this->routes['404_override']); $this->set_class($x[0]); $this->set_method(isset($x[1]) ? $x[1] : 'index'); return $x; } // Nothing else to do at this point but show a 404 // 展示一个404页面 show_404($segments[0]); } // -------------------------------------------------------------------- /** * Parse Routes * 解析路由 * This function matches 匹配 any routes that may exist in * the config/routes.php file against 针对,反对 the URI to * determine 决定,决心 if the class/method need to be remapped.重新绘制地图 * * @access private * @return void */ function _parse_routes() { // Turn the segment array into a URI string // 将segments数组转为uri字符串的形式 $uri = implode('/', $this->uri->segments); // Is there a literal 文字的,字面的 match? If so we're done // 如果这个uri是routes.php中定义的那么。。。。。 if (isset($this->routes[$uri])) { return $this->_set_request(explode('/', $this->routes[$uri])); } // Loop through the route array looking for wild-cards foreach ($this->routes as $key => $val) { // Convert wild-cards to RegEx 使用通配符进行正则转换 // 如果$key 中含有:any 转换为.+ , :num 转换为 [0-9]+ $key = str_replace(':any', '.+', str_replace(':num', '[0-9]+', $key)); // Does the RegEx match? 进行正则匹配 // 从这里可以看出如果routes.php 中的$route的key是可以使用:any 或者 :num // 来进行匹配的。举个例子来说 // routes.php 中有 $route['show:any:num'] = 'anynum'; // 这样的两个配置那么我们就可以将showaa123这样的uri匹配到了它对应的值就是anynum if (preg_match('#^'.$key.'$#', $uri)) { // Do we have a back-reference?如果$val中有$并且$key中有( // 这个if的作用我没看懂。。。待高人解救 // 有明白的请发邮箱uuus007@gmail.com if (strpos($val, '$') !== FALSE AND strpos($key, '(') !== FALSE) { // 将uri中能匹配到得字符替换成$val $val = preg_replace('#^'.$key.'$#', $val, $uri); } return $this->_set_request(explode('/', $val)); } } // If we got this far it means we didn't encounter a // matching route so we'll set the site default route // 如果我们走到这一步,这意味着我们没有遇到一个匹配的路由 // 所以我们将设置网站默认路由 $this->_set_request($this->uri->segments); } // -------------------------------------------------------------------- /** * Set the class name * * @access public * @param string * @return void */ function set_class($class) { $this->class = str_replace(array('/', '.'), '', $class); } // -------------------------------------------------------------------- /** * Fetch the current class * * @access public * @return string */ function fetch_class() { return $this->class; } // -------------------------------------------------------------------- /** * Set the method name * * @access public * @param string * @return void */ function set_method($method) { $this->method = $method; } // -------------------------------------------------------------------- /** * Fetch the current method * * @access public * @return string */ function fetch_method() { if ($this->method == $this->fetch_class()) { return 'index'; } return $this->method; } // -------------------------------------------------------------------- /** * Set the directory name * * @access public * @param string * @return void */ function set_directory($dir) { $this->directory = str_replace(array('/', '.'), '', $dir).'/'; } // -------------------------------------------------------------------- /** * Fetch the sub-directory (if any) that contains the requested controller class * * @access public * @return string */ function fetch_directory() { return $this->directory; } // -------------------------------------------------------------------- /** * Set the controller overrides * 控制器覆盖 * 这个函数可以讲目录,控制器,方法重新覆盖一遍。 * @access public * @param array * @return null */ function _set_overrides($routing) { if ( ! is_array($routing)) { return; } if (isset($routing['directory'])) { $this->set_directory($routing['directory']); } if (isset($routing['controller']) AND $routing['controller'] != '') { $this->set_class($routing['controller']); } if (isset($routing['function'])) { $routing['function'] = ($routing['function'] == '') ? 'index' : $routing['function']; $this->set_method($routing['function']); } } } // END Router Class /* End of file Router.php */ /* Location: ./system/core/Router.php */ ~~~
';

URI.php

最后更新于:2022-04-01 20:46:06

~~~ config =& load_class('Config', 'core'); log_message('debug', "URI Class Initialized"); } // -------------------------------------------------------------------- /** * Get the URI String * * @access private * @return string */ function _fetch_uri_string() { // 下面的uri_protocol是在config.php里面的一个配置项, // 其实是问你用哪种方式去检测uri的信息的意思, // 默认是AUTO,自动检测,也就是通过各种方式检测,直至检测到,或者全部方式都检测完。。 if (strtoupper($this->config->item('uri_protocol')) == 'AUTO') { // Is the request coming from the command line? // 开始尝试各种方式,主要有:命令行,REQUEST_URI, PATH_INFO, QUERY_STRING. // 下面会多次出现$this->_set_uri_string($str)这个方法,这个方法没别的,就是把$str经过 // 过滤和修剪后值给$this->uri_string属性,在这里暂时可以理解为就是赋值。 // 如果脚本是在命令行模式下运行的话,那么参数就是通过$_SERVER['argv']来传递。下面的 // $this->_parse_cli_args();就是拿到符合我们需要的路由相关的一些参数 // 如果你没用命令行执行脚本的话,下面这个if暂时可以不用管。 // 这时候我们发现URI类用函数php_sapi_name()来测试不同的环境 // 在apache环境下面输出的结果是“apache2handler”; // 在cgi模式下输出的结果是“cgi-fcgi” // 要是在命令行模式下面运行的话,那么输出的结果是:”cli” if (php_sapi_name() == 'cli' or defined('STDIN')) { $this->_set_uri_string($this->_parse_cli_args()); return; } // Let's try the REQUEST_URI first, this will work in most situations // 查找uri if ($uri = $this->_detect_uri()) { // 如果找到uri 设置$this->uri_string $this->_set_uri_string($uri); return; } // Is there a PATH_INFO variable? // Note: some servers seem 似乎 to have trouble 麻烦 with getenv() so we'll test it two ways // 获取path $_SERVER['PATH_INFO'] 并不是每次请求都会有的所以当没有的时候使用getenv('PATH_INFO') $path = (isset($_SERVER['PATH_INFO'])) ? $_SERVER['PATH_INFO'] : @getenv('PATH_INFO'); if (trim($path, '/') != '' && $path != "/".SELF) { $this->_set_uri_string($path); return; } // No PATH_INFO?... What about QUERY_STRING? // 如果没有找到$_SERVER['PATH_INFO'] 我们使用QUERY_STRING $path = (isset($_SERVER['QUERY_STRING'])) ? $_SERVER['QUERY_STRING'] : @getenv('QUERY_STRING'); if (trim($path, '/') != '') { $this->_set_uri_string($path); return; } // As a last ditch effort lets try using the $_GET array // 如果PATH_INFO和QUERY_STRING都没找到我们只能使用$_GET if (is_array($_GET) && count($_GET) == 1 && trim(key($_GET), '/') != '') { $this->_set_uri_string(key($_GET)); return; } // We've exhausted all our options... // 经过以上的努力我们还没有找到uri那么我们就真的找不到了 $this->uri_string = ''; return; } // 这里重新写了一遍获取uri_protocol 其实我觉得完全可以只获取一次嘛。。。 $uri = strtoupper($this->config->item('uri_protocol')); // 下面就是根据不同的方式来选择不同的办法获取uri了 if ($uri == 'REQUEST_URI') { $this->_set_uri_string($this->_detect_uri()); return; } elseif ($uri == 'CLI') { $this->_set_uri_string($this->_parse_cli_args()); return; } // 如果你定义的uri_protocol是在AUTO REQUEST_URI CLI这三种方式之外的就执行下面这段了。 $path = (isset($_SERVER[$uri])) ? $_SERVER[$uri] : @getenv($uri); $this->_set_uri_string($path); } // -------------------------------------------------------------------- /** * Set the URI String * * @access public * @param string * @return string */ function _set_uri_string($str) { // Filter out control characters // 过滤字符串 remove_invisible_characters 函数式在common.php中 $str = remove_invisible_characters($str, FALSE); // If the URI contains only a slash we'll kill it // 如果字符串只包含一个/则清空 $this->uri_string = ($str == '/') ? '' : $str; } // -------------------------------------------------------------------- /** * Detects the URI * 查找uri * This function will detect the URI automatically and fix the query string * if necessary. 必需品 * 如果有必要的话,这个函数将自动查找uri并且固定查询字符串。 * * @access private * @return string */ private function _detect_uri() { // 如果两个值有一个没有则返回(两个变量是从web server那边来的,碰到一些特别的server程序, 这个是有可能为空的.) if ( ! isset($_SERVER['REQUEST_URI']) OR ! isset($_SERVER['SCRIPT_NAME'])) { return ''; } // 获取uri $uri = $_SERVER['REQUEST_URI']; // 如果SCRIPT_NAME 在$uri 中第一次出现的位置是0 if (strpos($uri, $_SERVER['SCRIPT_NAME']) === 0) { // 去掉uri 和 SCRIPT_NAME 相同的部分 $uri = substr($uri, strlen($_SERVER['SCRIPT_NAME'])); } // 这里作用同上 只是将$_SERVER['SCRIPT_NAME']换成了 // dirname($_SERVER['SCRIPT_NAME']) elseif (strpos($uri, dirname($_SERVER['SCRIPT_NAME'])) === 0) { $uri = substr($uri, strlen(dirname($_SERVER['SCRIPT_NAME']))); } // This section ensures 保证 that even on servers that require the URI // to be in the query string (Nginx) a correct 正确的 // URI is found, and also fixes 修理 the QUERY_STRING server var and $_GET array. // 这部分保证,uri可以被正确的找到即使是在Nginx服务器上,并且还修复了的QUERY_STRING服务器和$ _GET数组。 // 判断$uri的前两个字符是不是?/ if (strncmp($uri, '?/', 2) === 0) { // 去掉前两个字符 $uri = substr($uri, 2); } // 用正册对字符串进行分割 $parts = preg_split('#\?#i', $uri, 2); $uri = $parts[0]; // 如果是能通过上述的正则分割出两段,那么,是通过query_string即?的形式进行路由访问 if (isset($parts[1])) { $_SERVER['QUERY_STRING'] = $parts[1]; // 函数把查询字符串解析到$_GET变量中。 parse_str($_SERVER['QUERY_STRING'], $_GET); } else { $_SERVER['QUERY_STRING'] = ''; $_GET = array(); } // 如果为/,或者为空,有两种情况,要么就是通过query_string即?的形式进行路由访问, // 所以此时$parts[0]就是等于下面两种可能,同时我们 // 已经通过$parts[1]拿到要拿的信息,则可以返回。 // 要么就是以段的形式,但是段的信息为空,即直接访问入口文件而没有 // 任何路由信息的传递,也可以直接返回。 if ($uri == '/' || empty($uri)) { return '/'; } //返回这个url的path部分。 $uri = parse_url($uri, PHP_URL_PATH); // Do some final cleaning of the URI and return it // 将uri中的// ../替换成 / 返回 return str_replace(array('//', '../'), '/', trim($uri, '/')); } // -------------------------------------------------------------------- /** * Parse cli arguments * 解析cli参数 * Take each command line argument and assume it is a URI segment. * 如果你在命令行中这么操作 * php d:/wamp/www/CodeIgniter/index.php welcome index * _parse_cli_args() 返回一个 /welcome/index的字符串 * * @access private * @return string */ private function _parse_cli_args() { // 返回在命令行模式下运行时传递的参数。 // 因为第一个参数是当前文件名,所以从第二个开始才是我们要获取的。 $args = array_slice($_SERVER['argv'], 1); //返回一个由'/'字符串拼接的字符串,因为$this->uri_string是一个字符串。 return $args ? '/' . implode('/', $args) : ''; } // -------------------------------------------------------------------- /** * Filter segments 段 for malicious 恶意 characters * 过滤不合法字符 * @access private * @param string * @return string */ function _filter_uri($str) { if ($str != '' && $this->config->item('permitted_uri_chars') != '' && $this->config->item('enable_query_strings') == FALSE) { // preg_quote() in PHP 5.3 escapes -, so the str_replace() and addition of - to preg_quote() is to maintain 维持 backwards 向后 // compatibility 兼容性 as many are unaware 不知道的 of how characters in the permitted_uri_chars will be parsed as a regex pattern // 大概意思是 由于php5.3.0 字符 - 被增加为需要转义的。 所以这里在使用str_replace()要添加preg_quote()来对-进行转义 if ( ! preg_match("|^[".str_replace(array('\\-', '\-'), '-', preg_quote($this->config->item('permitted_uri_chars'), '-'))."]+$|i", $str)) { show_error('The URI you submitted has disallowed characters.', 400); } } // Convert programatic characters to entities // 转换字符实体 $bad = array('$', '(', ')', '%28', '%29'); $good = array('$', '(', ')', '(', ')'); return str_replace($bad, $good, $str); } // -------------------------------------------------------------------- /** * Remove the suffix from the URL if needed * // 去掉url的我们自定义的后缀。 * @access private * @return void */ function _remove_url_suffix() { if ($this->config->item('url_suffix') != "") { $this->uri_string = preg_replace("|".preg_quote($this->config->item('url_suffix'))."$|", "", $this->uri_string); } } // -------------------------------------------------------------------- /** * Explode the URI Segments. The individual segments will * be stored in the $this->segments array. * 将uri拆分正段同时对每个段进行过滤,并存入$this->segments[]中 * @access private * @return void */ function _explode_segments() { foreach (explode("/", preg_replace("|/*(.+?)/*$|", "\\1", $this->uri_string)) as $val) { // Filter segments for security $val = trim($this->_filter_uri($val)); if ($val != '') { $this->segments[] = $val; } } } // -------------------------------------------------------------------- /** * Re-index Segments 重新索引段 * 使得出来的段以下标1开始保存。这样做可以更简单的使用使用因为段数组和真实的段有个1:1的关系 * This function re-indexes the $this->segment array so that it * starts at 1 rather than 0. Doing so makes it simpler to * use functions like $this->uri->segment(n) since there is * a 1:1 relationship 关系 between the segment array and the actual 真实的 segments. * * @access private * @return void */ function _reindex_segments() { array_unshift($this->segments, NULL); array_unshift($this->rsegments, NULL); unset($this->segments[0]); unset($this->rsegments[0]); } // -------------------------------------------------------------------- /** * Fetch a URI Segment * 获取一个uri段 * This function returns the URI segment based on the number provided.提供 * 这个函数返回一个基于提供的数字uri段 * @access public * @param integer * @param bool * @return string */ function segment($n, $no_result = FALSE) { return ( ! isset($this->segments[$n])) ? $no_result : $this->segments[$n]; } // -------------------------------------------------------------------- /** * Fetch a URI "routed" Segment * 返回确定路由后的某一段 * This function returns the re-routed URI segment (assuming 假设 routing rules 规则 are used) * based on the number provided. If there is no routing this function returns the * same result as $this->segment() * 这个函数返回一个已经路由的基于提供的数字的uri段(假设路由规则已经使用的) * 如果还没与路由这个函数将和$this->segment()是一样的 * * @access public * @param integer * @param bool * @return string */ function rsegment($n, $no_result = FALSE) { return ( ! isset($this->rsegments[$n])) ? $no_result : $this->rsegments[$n]; } // -------------------------------------------------------------------- /** * Generate 产生 a key value pair 一对 from the URI string * 根据uri字符串产生一个键值对的数组 * * This function generates and associative 关联的 array of URI data starting * at the supplied 由。。。提供 segment. For example, if this is your URI: * * example.com/user/search/name/joe/location/UK/gender/male * * You can use this function to generate an array with this prototype: * * array ( * name => joe * location => UK * gender => male * ) * 这个函数由uri段产生一个关联数组 * 例子:如果你的uri是这样的 * example.com/user/search/name/joe/location/UK/gender/male * 那么将产生一个这样的原型 * array ( * name => joe * location => UK * gender => male * ) * @access public * @param integer the starting segment number * @param array an array of default values * @return array */ function uri_to_assoc($n = 3, $default = array()) { return $this->_uri_to_assoc($n, $default, 'segment'); } /** * Identical 完全相同的事物 to above only it uses the re-routed segment array * 跟上一个函数是完全相同的只是它冲洗路由了段数组 (注意看第三个参数) * @access public * @param integer the starting segment number * @param array an array of default values * @return array * */ function ruri_to_assoc($n = 3, $default = array()) { return $this->_uri_to_assoc($n, $default, 'rsegment'); } // -------------------------------------------------------------------- /** * Generate a key value pair from the URI string or Re-routed URI string * 根据uri字符串或者重新路由的uri字符串产生一个键值对数组 * @access private * @param integer the starting segment number 起始段号 * @param array an array of default values * @param string which array we should use * @return array */ function _uri_to_assoc($n = 3, $default = array(), $which = 'segment') { // 区分段数组是不是重新路由的。 if ($which == 'segment') { $total_segments = 'total_segments'; $segment_array = 'segment_array'; } else { $total_segments = 'total_rsegments'; $segment_array = 'rsegment_array'; } // $n 是不是一个数字 if ( ! is_numeric($n)) { return $default; } // 缓存uri段列表中是够存在$n这个key if (isset($this->keyval[$n])) { return $this->keyval[$n]; } // 总段数小于$n if ($this->$total_segments() < $n) { if (count($default) == 0) { return array(); } $retval = array(); foreach ($default as $val) { $retval[$val] = FALSE; } return $retval; } $segments = array_slice($this->$segment_array(), ($n - 1)); $i = 0; $lastval = ''; $retval = array(); foreach ($segments as $seg) { if ($i % 2) { $retval[$lastval] = $seg; } else { $retval[$seg] = FALSE; $lastval = $seg; } $i++; } if (count($default) > 0) { foreach ($default as $val) { if ( ! array_key_exists($val, $retval)) { $retval[$val] = FALSE; } } } // Cache the array for reuse // 缓存数组一遍重用 $this->keyval[$n] = $retval; return $retval; } // -------------------------------------------------------------------- /** * Generate a URI string from an associative 关联数组 array * 根据一个关联数组产生一个uri字符串 * * @access public * @param array an associative array of key/values * @return array */ function assoc_to_uri($array) { $temp = array(); foreach ((array)$array as $key => $val) { $temp[] = $key; $temp[] = $val; } return implode('/', $temp); } // -------------------------------------------------------------------- /** * Fetch a URI Segment and add a trailing 后面的,尾随 slash * 获取一个uri段并且添加一个/ * * @access public * @param integer * @param string * @return string */ function slash_segment($n, $where = 'trailing') { return $this->_slash_segment($n, $where, 'segment'); } // -------------------------------------------------------------------- /** * Fetch a URI Segment and add a trailing slash * 获取一个已经路由的uri段并且添加/ * @access public * @param integer * @param string * @return string */ function slash_rsegment($n, $where = 'trailing') { return $this->_slash_segment($n, $where, 'rsegment'); } // -------------------------------------------------------------------- /** * Fetch a URI Segment and add a trailing slash - helper function * * @access private * @param integer * @param string * @param string * @return string */ function _slash_segment($n, $where = 'trailing', $which = 'segment') { $leading = '/'; $trailing = '/'; if ($where == 'trailing') { $leading = ''; } elseif ($where == 'leading') { $trailing = ''; } return $leading.$this->$which($n).$trailing; } // -------------------------------------------------------------------- /** * Segment Array * 获取段数组 * @access public * @return array */ function segment_array() { return $this->segments; } // -------------------------------------------------------------------- /** * Routed Segment Array * 获取已经路由的段数组 * @access public * @return array */ function rsegment_array() { return $this->rsegments; } // -------------------------------------------------------------------- /** * Total number of segments * 获取段总数 * @access public * @return integer */ function total_segments() { return count($this->segments); } // -------------------------------------------------------------------- /** * Total number of routed segments * 获取已经路由的段的总数 * @access public * @return integer */ function total_rsegments() { return count($this->rsegments); } // -------------------------------------------------------------------- /** * Fetch the entire URI string * * @access public * @return string */ function uri_string() { return $this->uri_string; } // -------------------------------------------------------------------- /** * Fetch the entire Re-routed URI string * * @access public * @return string */ function ruri_string() { return '/'.implode('/', $this->rsegment_array()); } } // END URI Class /* End of file URI.php */ /* Location: ./system/core/URI.php */ ~~~
';

Utf8.php

最后更新于:2022-04-01 20:46:03

文件地址:./system/core/Utf8.php 主要作用:提供utf-8编码的环境支持 1.__construct() 构造函数确定utf8是否被支持 (1)日志记录 Utf8 Class Initialized (2)将CodeIgniter.php中的$CFG调用进当前类。 (3)判断如果正则表达式支持utf8,iconv库已经安装,多字节字符串函数重载没有启用,应用程序字  符集是utf8,那么 (a)记录日志:UTF-8 Support Enabled。 (b)定义常量UTF8_ENABLED 值为 true (c)如果加载了mbstring扩展我们设置内部编码 (d)我们会设置一个标记让我们不用多次使用extension_loaded() 函数 (4)判断如果正则表达式不支持utf8或者iconv库没有安装或者多字节字符串函数重载已经启用或者应用程序字符集不是utf8,那么 (a)记录日志:UTF-8 Support Disabled (b)设置常量UTF8_ENABLED 为false 2.clean_string()  清理utf8编码的字符串 (1)判断如果字符串不是ASCII码 (2)使用iconv函数将字符串转码(关于iconv函数详情见http://www.php.net/manual/zh/function.iconv.php) (3)返回字符串 3.safe_ascii_for_xml() 删除所有在xml中可能导致问题的ASCII码字符,除了水平制表符,换行,回车。 (1) 直接调用remove_invisible_characters()来删除无效的字符并返回。 注:remove_invisible_characters 函数在common.php中定义 4.convert_to_utf8() 将字符串转换为utf8编码 (1)如果iconv函数存在,使用iconv转换 (2)如果mb_convert_encoding函数存在,使用mb_convert_encoding函数转换 (3)如果上面两个函数都不存在则不能转换返回false (4)如果转换完成返回转换后的字符串 5._is_ascii()  测试一个字符串是不是ASCII码 (1) 使用正则拼配返回测试结果。 ~~~ item('charset') == 'UTF-8' // Application charset must be UTF-8 ) { log_message('debug', "UTF-8 Support Enabled"); define('UTF8_ENABLED', TRUE); // set internal 内部 encoding for multibyte 多字节 string functions if necessary 必需的 // and set a flag so we don't have to repeatedly 多次 use extension_loaded() // or function_exists() if (extension_loaded('mbstring')) { define('MB_ENABLED', TRUE); mb_internal_encoding('UTF-8'); } else { define('MB_ENABLED', FALSE); } } else { log_message('debug', "UTF-8 Support Disabled"); define('UTF8_ENABLED', FALSE); } } // -------------------------------------------------------------------- /** * Clean UTF-8 strings * * Ensures 保证 strings are UTF-8 * * @access public * @param string * @return string */ function clean_string($str) { if ($this->_is_ascii($str) === FALSE) { $str = @iconv('UTF-8', 'UTF-8//IGNORE', $str); } return $str; } // -------------------------------------------------------------------- /** * Remove ASCII control characters * * Removes all ASCII control characters except horizontal tabs, * line feeds, and carriage returns, as all others can cause * problems in XML * * @access public * @param string * @return string */ function safe_ascii_for_xml($str) { return remove_invisible_characters($str, FALSE); } // -------------------------------------------------------------------- /** * Convert to UTF-8 * * Attempts 企图 to convert a string to UTF-8 * * @access public * @param string * @param string - input encoding * @return string */ function convert_to_utf8($str, $encoding) { if (function_exists('iconv')) { $str = @iconv($encoding, 'UTF-8', $str); } elseif (function_exists('mb_convert_encoding')) { $str = @mb_convert_encoding($str, 'UTF-8', $encoding); } else { return FALSE; } return $str; } // -------------------------------------------------------------------- /** * Is ASCII? * * Tests if a string is standard 7-bit ASCII or not * * @access public * @param string * @return bool */ function _is_ascii($str) { return (preg_match('/[^\x00-\x7F]/S', $str) == 0); } // -------------------------------------------------------------------- } // End Utf8 Class /* End of file Utf8.php */ /* Location: ./system/core/Utf8.php */ ~~~
';

Config.php

最后更新于:2022-04-01 20:46:01

文件地址:./system/core/Config.php 主要作用:管理配置 1.成员属性$config所有已加载配置的值的列表 2.成员属性$is_loaded所有加载配置文件的列表 3.成员属性$_config_paths当需要加载配置文件的时候搜索路径的列表 4.__construct()构造方法程序会首先自动执行这个方法 它所做的内容主要有两个a)获取配置赋值给成员属性$config b)设置配置中的base_url 5.load($file = '', $use_sections = FALSE, $fail_gracefully = FALSE) 加载配置文件 $file是你自定义的配置文件的文件名,这个文件名没有 .php 的扩展名.  $use_sections如果你需要加载多个自定义配置文件,一般情况下它们会被合并成一个数组。然而,如果在不同的配置文件中存在同名的索引,那么会发生冲突。为了避免这个问题,你可以把第二个参数设置为 TRUE ,这可以使每个配置文件的内容存储在一个单独的数组中,数组的索引就是配置文件的文件名。 $fail_gracefully允许屏蔽当配置文件不存在时产生的错误信息: (0)过滤并设置$file 变量 (1)初始化$founf 为FALSE 用于判断文件是否存在 (2)初始化$loaded为FALSE 用于判断文件是否被加载 (3)检测文件路径如果有环境变量添加环境变量 (4)进入foreach遍历文件路径,并查找文件是否被加载和存在 (5)如果文件不存在跳出foreach循环 (6)加载文件 (7)判断$config是否存在,这个$config 应该是加载的文件中定义的 (8)判断$use_sections 如果为真则将使每个配置文件的内容存储在一个单独的数组中,数组的索引就是配置文件的文件名。 如果为假则所有配置文件会被合并成一个数组 (9)将文件添加进is_loaded数组中,并销毁$config (10)$loaded 设置为true log记录 跳出循环 (11)如果loaded为false并且$fail_gracefully不等于true 显示错误日志 6.item() 获取一个配置项 $item 配置项的名字 $index如果配置是一个数组的时候,这一项是数组索引名字 (1)判断index是否为空 (2)如果index为空,判断$this->config[$item]是否存在,如果不存在返回,存在,赋值给$pref (3)如果index不为空,判断$this->config[$index]是否存在,判断$this->config[$index][$item]是否存在,将$this->config[$index][$item]赋值给$pref (4)返回$pref 7.slash_item()获取一个配置项并添加/ $item配置项的名字 (1)判断配置项是否存在不存在返回false (2)判断配置项是否为空如果是空返回'' (3)在配置值的后面添加/并返回。 8.site_url()该函数得到你网站的 URL,其中包含了你在 config 文件中设置的 "index" 的值。 $uriuri字符串就是访问路径所带的参数 (1) 如果$uri = '' 返回由base_url和index_page组成的url (2) 判断$this->item('enable_query_strings')真假,并返回不同形式的地址。(这一项是在application/config/config.php文件中配置的。用来区分传参方式,如果为false就是默认的传参方式example.com/who/what/where/。如果为true就是 example.com/index.php?c=controller&m=function这样的传参方式。) 9.base_url()该函数返回站点的根 URL,可以在这个函数后拼接一个 URL 路径,用以生成 CSS 或图片文件的 URL。 10._uri_string() 构建uri串让site_url(),base_url()两个函数使用。 11.system_url()该函数得到 system 文件夹的 URL。 12.set_item()  设置一个配置项 13._assign_to_config() 设置多个配置项(以数组的形式key是要设置的配置项的名字,value 是配置项的值) 源码: ~~~ config =& get_config(); log_message('debug', "Config Class Initialized"); // Set the base_url automatically if none was provided 假如 if ($this->config['base_url'] == '') { if (isset($_SERVER['HTTP_HOST'])) { $base_url = isset($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) !== 'off' ? 'https' : 'http'; $base_url .= '://'. $_SERVER['HTTP_HOST']; $base_url .= str_replace(basename($_SERVER['SCRIPT_NAME']), '', $_SERVER['SCRIPT_NAME']); } else { $base_url = 'http://localhost/'; } $this->set_item('base_url', $base_url); } } // -------------------------------------------------------------------- /** * Load Config File * * @access public * @param string the config file name * @param boolean if configuration values should be loaded into their own section * @param boolean true if errors should just return false, false if an error message should be displayed * @return boolean if the file was loaded correctly */ function load($file = '', $use_sections = FALSE, $fail_gracefully = FALSE) { $file = ($file == '') ? 'config' : str_replace('.php', '', $file); $found = FALSE; $loaded = FALSE; $check_locations = defined('ENVIRONMENT') ? array(ENVIRONMENT.'/'.$file, $file) : array($file); foreach ($this->_config_paths as $path) { foreach ($check_locations as $location) { $file_path = $path.'config/'.$location.'.php'; if (in_array($file_path, $this->is_loaded, TRUE)) { $loaded = TRUE; continue 2; } if (file_exists($file_path)) { $found = TRUE; break; } } if ($found === FALSE) { continue; } include($file_path); if ( ! isset($config) OR ! is_array($config)) { if ($fail_gracefully === TRUE) { return FALSE; } show_error('Your '.$file_path.' file does not appear to contain a valid configuration array.'); } if ($use_sections === TRUE) { if (isset($this->config[$file])) { $this->config[$file] = array_merge($this->config[$file], $config); } else { $this->config[$file] = $config; } } else { $this->config = array_merge($this->config, $config); } $this->is_loaded[] = $file_path; unset($config); $loaded = TRUE; log_message('debug', 'Config file loaded: '.$file_path); break; } if ($loaded === FALSE) { if ($fail_gracefully === TRUE) { return FALSE; } show_error('The configuration file '.$file.'.php does not exist.'); } return TRUE; } // -------------------------------------------------------------------- /** * Fetch 取得,拿来 a config file item * * * @access public * @param string the config item name * @param string the index name * @param bool * @return string */ function item($item, $index = '') { if ($index == '') { if ( ! isset($this->config[$item])) { return FALSE; } $pref = $this->config[$item]; } else { if ( ! isset($this->config[$index])) { return FALSE; } if ( ! isset($this->config[$index][$item])) { return FALSE; } $pref = $this->config[$index][$item]; } return $pref; } // -------------------------------------------------------------------- /** * Fetch a config file item - adds slash after item (if item is not empty) * * @access public * @param string the config item name * @param bool * @return string */ function slash_item($item) { if ( ! isset($this->config[$item])) { return FALSE; } if( trim($this->config[$item]) == '') { return ''; } return rtrim($this->config[$item], '/').'/'; } // -------------------------------------------------------------------- /** * Site URL * Returns base_url . index_page [. uri_string] * * @access public * @param string the URI string * @return string */ function site_url($uri = '') { if ($uri == '') { return $this->slash_item('base_url').$this->item('index_page'); } if ($this->item('enable_query_strings') == FALSE) { $suffix = ($this->item('url_suffix') == FALSE) ? '' : $this->item('url_suffix'); return $this->slash_item('base_url').$this->slash_item('index_page').$this->_uri_string($uri).$suffix; } else { return $this->slash_item('base_url').$this->item('index_page').'?'.$this->_uri_string($uri); } } // ------------------------------------------------------------- /** * Base URL * Returns base_url [. uri_string] * * @access public * @param string $uri * @return string */ function base_url($uri = '') { return $this->slash_item('base_url').ltrim($this->_uri_string($uri), '/'); } // ------------------------------------------------------------- /** * Build URI string for use in Config::site_url() and Config::base_url() * * @access protected * @param $uri * @return string */ protected function _uri_string($uri) { if ($this->item('enable_query_strings') == FALSE) { if (is_array($uri)) { $uri = implode('/', $uri); } $uri = trim($uri, '/'); } else { if (is_array($uri)) { $i = 0; $str = ''; foreach ($uri as $key => $val) { $prefix = ($i == 0) ? '' : '&'; $str .= $prefix.$key.'='.$val; $i++; } $uri = $str; } } return $uri; } // -------------------------------------------------------------------- /** * System URL * * @access public * @return string */ function system_url() { $x = explode("/", preg_replace("|/*(.+?)/*$|", "\\1", BASEPATH)); return $this->slash_item('base_url').end($x).'/'; } // -------------------------------------------------------------------- /** * Set a config file item * * @access public * @param string the config item key * @param string the config item value * @return void */ function set_item($item, $value) { $this->config[$item] = $value; } // -------------------------------------------------------------------- /** * Assign to Config * * This function is called by the front controller (CodeIgniter.php) * after the Config class is instantiated. It permits config items * to be assigned or overriden by variables contained in the index.php file * * @access private * @param array * @return void */ function _assign_to_config($items = array()) { if (is_array($items)) { foreach ($items as $key => $val) { $this->set_item($key, $val); } } } } // END CI_Config class /* End of file Config.php */ /* Location: ./system/core/Config.php */ ~~~
';

钩子类hooks.php

最后更新于:2022-04-01 20:45:59

~~~ _initialize(); log_message('debug', "Hooks Class Initialized"); } // -------------------------------------------------------------------- /** * Initialize the Hooks Preferences 参数,首选项 * 初始化钩子 * @access private * @return void */ function _initialize() { $CFG =& load_class('Config', 'core'); // If hooks are not enabled in the config file // there is nothing else to do // 如果配置文件中设置了是不允许hooks,则直接返回退出本函数。 if ($CFG->item('enable_hooks') == FALSE) { return; } // Grab the "hooks" definition file. // 抓取钩子的定义文件 // If there are no hooks, we're done. // 如果没有定义hooks.php没有定义$hook数组我们直接返回 if (defined('ENVIRONMENT') AND is_file(APPPATH.'config/'.ENVIRONMENT.'/hooks.php')) { include(APPPATH.'config/'.ENVIRONMENT.'/hooks.php'); } elseif (is_file(APPPATH.'config/hooks.php')) { include(APPPATH.'config/hooks.php'); } if ( ! isset($hook) OR ! is_array($hook)) { return; } // 将hooks.php 中的$hook数组引用到$this->hooks // 开启$this->enabled $this->hooks =& $hook; $this->enabled = TRUE; } // -------------------------------------------------------------------- /** * Call Hook * 外部其实就是调用这个_call_hook函数进行调用钩子程序。 * 而此方法中再调用_run_hook去执行相应的钩子。 * Calls a particular hook * * @access private * @param string the hook name * @return mixed */ function _call_hook($which = '') { // 判断$this->enabled 是否开启 和 要调用的钩子是否在$htis->hooks中存在。 if ( ! $this->enabled OR ! isset($this->hooks[$which])) { return FALSE; } // 判断要调用的钩子是否是一个二维数组,如果是就遍历执行。 // 如果不是二维数组就直接执行 // 这里说明,在一个挂钩点可以执行多个钩子,就是通过定义二维数组来实现的。 if (isset($this->hooks[$which][0]) AND is_array($this->hooks[$which][0])) { foreach ($this->hooks[$which] as $val) { $this->_run_hook($val); } } else { $this->_run_hook($this->hooks[$which]); } return TRUE; } // -------------------------------------------------------------------- /** * Run Hook * 运行钩子 * Runs a particular 特别的 hook * * @access private * @param array the hook details * @return bool */ function _run_hook($data) { /* * $data 就是我们在APPPATH/config/hook.php 定义的hook数组 * $hook['pre_controller'] = array( * 'class' => 'MyClass', * 'function' => 'Myfunction', * 'filename' => 'Myclass.php', * 'filepath' => 'hooks', * 'params' => array('beer', 'wine', 'snacks') * ); * * 由于每一个钩子肯定是由数组组成的 * 所以这里就判断$data是不是数组如果不是则返回 * */ if ( ! is_array($data)) { return FALSE; } // ----------------------------------- // Safety - Prevents run-away loops // ----------------------------------- // If the script being called happens to have the same // hook call within it a loop can happen // 如果调用某一个hook,执行某些脚本,而有可能这些脚本里面再会触发其它hook // 如果这个其它hook里面又包含了当前 // 的hook,那么就会进入死循环,这个in_progress的存在就是阻止这种情况。 if ($this->in_progress == TRUE) { return; } // ----------------------------------- // 取出data里面的数据,加载 APPPATH.$data['filepath'].$data['filename']; // Set file path // ----------------------------------- if ( ! isset($data['filepath']) OR ! isset($data['filename'])) { return FALSE; } $filepath = APPPATH.$data['filepath'].'/'.$data['filename']; if ( ! file_exists($filepath)) { return FALSE; } // ----------------------------------- // Set class/function name // ----------------------------------- $class = FALSE; $function = FALSE; $params = ''; // 取出$hooks 中的class function params if (isset($data['class']) AND $data['class'] != '') { $class = $data['class']; } if (isset($data['function'])) { $function = $data['function']; } if (isset($data['params'])) { $params = $data['params']; } if ($class === FALSE AND $function === FALSE) { return FALSE; } // ----------------------------------- // Set the in_progress flag // 在开始执行钩子相应的程序之前,先把当前hook的状态设为正在运行中。 // ----------------------------------- $this->in_progress = TRUE; // ----------------------------------- // Call the requested class and/or function // 包含钩子文件并实例化类,调用函数 // ----------------------------------- if ($class !== FALSE) { if ( ! class_exists($class)) { require($filepath); } $HOOK = new $class; $HOOK->$function($params); } else { if ( ! function_exists($function)) { require($filepath); } $function($params); } // 执行相应程序完毕后,重新把当前hook的状态改为非运行中 // 以让它可以再次被触发。 $this->in_progress = FALSE; return TRUE; } } // END CI_Hooks class /* End of file Hooks.php */ /* Location: ./system/core/Hooks.php */ ~~~
';

基准测试类Benchmark.php

最后更新于:2022-04-01 20:45:56

~~~ marker[$name] = microtime(); } // -------------------------------------------------------------------- /** * Calculates the time difference between two marked points. * 计算出两个时间点之间的时间。 * If the first parameter is empty this function instead returns the * {elapsed_time} pseudo-variable 虚假变量. This permits 许可 the full system * execution time to be shown in a template. The output class will * swap the real value for this variable. * * @access public * @param string a particular marked point * @param string a particular marked point * @param integer the number of decimal places * @return mixed */ function elapsed_time($point1 = '', $point2 = '', $decimals = 4) { /* * 如果没有给出明确的时间点,那么会计算出整个程序运行的时间。 * 怎么可以做到计算出整个程序的运行时间的呢?其实执行此计算的是Output组件。 * 而调用Benchmark::elapsed_time();(无参数)的时候,实质上先返回的并不是 * 整个程序运行的时间,也不可能做到,实质返回的是一个{elapsed_time}标签,然后 * Output在处理输出的时候,再计算出整个程序运行时间,因为处理输出阶段程序可以视 * 为处于最后阶段,于是可以近似计算出总时间,然后把输出中的{elapsed_time}替换掉。 * 下面的memory_usage()原理相同。 */ if ($point1 == '') { return '{elapsed_time}'; } if ( ! isset($this->marker[$point1])) { return ''; } if ( ! isset($this->marker[$point2])) { $this->marker[$point2] = microtime(); } //这里为什么要用到list,是因为microtime();返回值是“msec sec”的格式。 list($sm, $ss) = explode(' ', $this->marker[$point1]); list($em, $es) = explode(' ', $this->marker[$point2]); return number_format(($em + $es) - ($sm + $ss), $decimals); } // -------------------------------------------------------------------- /** * Memory Usage * * This function returns the {memory_usage} pseudo-variable. * This permits it to be put it anywhere in a template * without the memory being calculated until the end. * The output class will swap the real value for this variable. * * @access public * @return string */ function memory_usage() { return '{memory_usage}'; } } // END CI_Benchmark class /* End of file Benchmark.php */ /* Location: ./system/core/Benchmark.php */ ~~~
';

系统常量文件constants.php

最后更新于:2022-04-01 20:45:54

文件位置:Location: ./application/config/constants.php 配置系统常量 1、当文件系统工作的时候检查并配置这些首选项 文件系统运行的时候这些默认的值会适当的增加系统的安全性,但是在php或apache的底层单独的为每各用户开一个进程的时候,使用八进制的值永远是正确的 FILE_READ_MODE 读取文件的模式 FILE_WRITE_MODE  写入文件的模式 DIR_READ_MODE   读取目录的模式 DIR_WRITE_MODE写入目录的模式 2、文件流模式 当我们使用fopen()/popen()的时候需要这些模式 define('FOPEN_READ','rb'); define('FOPEN_READ_WRITE','r+b'); define('FOPEN_WRITE_CREATE_DESTRUCTIVE','wb');  define('FOPEN_READ_WRITE_CREATE_DESTRUCTIVE','w+b');  define('FOPEN_WRITE_CREATE','ab'); define('FOPEN_READ_WRITE_CREATE','a+b'); define('FOPEN_WRITE_CREATE_STRICT','xb'); define('FOPEN_READ_WRITE_CREATE_STRICT','x+b'); 文件源码: ~~~ ';

全局函数文件Common.php

最后更新于:2022-04-01 20:45:52

文件位置:Location: ./system/core/Common.php CodeIgniter 使用了一些全局定义的函数来完成操作,在任何情况下你都能够使用这些函数。使用他们不需要载入任何类库或辅助函数。 这些函数主要用于加载基类和执行请求。 1、 第一个函数is_php  判断当前php版本是否大于指定的php版本,有些地方需要用到这个函数 2、 判断文件夹是否有可写权限is_really_writable() 因为函数is_writable()在window和unix中并不可靠,所以要对它进行重新封装 在Windows平台,is_writable()函数在实际没有文件写权限时也返回真。那是因为,只有文件有只读属性时,操作系统才向PHP报告为假。 在unix中当safe_mode为开启状态下也是不可靠的。 这个函数依靠对文件的先行写入来判断是否真的具有写权限。 3、 类注册器load_class() 这是一个单例模式的函数,如果请求的类没有找到会将它设置为一个静态变量,如果以前存在就直接返回。 4、 is_loaded(); 追踪已经加载的类,这个函数被load_class 调用 5、 get_config(); 加载主配置文件 6、 config_item() 返回指定的配置项 7、 show_error错误处理程序 这个函数调用异常处理类并且使用application/errors/error_general.php模板来显示错误 8、 show_404 404页面处理程序  这个函数和show_error函数相似使用application/errors/error_404.php模板来显示的。 9、 log_message(‘级别’, ‘消息’) 记录错误日志 这个函数可以让你将消息写入记录文件中。你必须在第一个参数中选择三个“级别“中的任何一个, 指明它是那一类消息(调试 debug, 错误 error, 信息info)。 第二个参数是消息本身。 他会调用system/libraries/log.php 进行处理 如果这个config_item('log_threshold') 为0 则不进行任何处理,也就不会记录错误日志了 10、set_status_header   设置http状态头 11、_exception_handler   异常处理程序 12、remove_invisible_characters  去除看不见的字 符  这个函数能防止在ASCII字符之间插入空字符,如Java\0script.  13、html_escape 把一些预定义的字符转换为 HTML 实体 它接受字符串和数组。有助于防止跨站脚本攻击(XSS)。 文件源码: ~~~ 5 * we'll set a static variable. * * @access public * @param string * @return bool TRUE if the current version is $version or higher */ if ( ! function_exists('is_php')) { function is_php($version = '5.0.0') { static $_is_php; $version = (string)$version; if ( ! isset($_is_php[$version])) { $_is_php[$version] = (version_compare(PHP_VERSION, $version) < 0) ? FALSE : TRUE; } return $_is_php[$version]; } } // ------------------------------------------------------------------------ /** * Tests for file writability 可写性 * * is_writable() returns TRUE on Windows servers when you really can't write to * the file, based on the read-only attribute. is_writable() is also unreliable 不可靠的 * on Unix servers if safe_mode is on. * * @access private * @return void */ if ( ! function_exists('is_really_writable')) { function is_really_writable($file) { // If we're on a Unix server with safe_mode off we call is_writable if (DIRECTORY_SEPARATOR == '/' AND @ini_get("safe_mode") == FALSE) { return is_writable($file); } // For windows servers and safe_mode "on" installations we'll actually // write a file then read it. Bah... if (is_dir($file)) { $file = rtrim($file, '/').'/'.md5(mt_rand(1,100).mt_rand(1,100)); if (($fp = @fopen($file, FOPEN_WRITE_CREATE)) === FALSE) { return FALSE; } fclose($fp); @chmod($file, DIR_WRITE_MODE); @unlink($file); return TRUE; } elseif ( ! is_file($file) OR ($fp = @fopen($file, FOPEN_WRITE_CREATE)) === FALSE) { return FALSE; } fclose($fp); return TRUE; } } // ------------------------------------------------------------------------ /** * Class registry * * This function acts as 扮演一个 a singleton.单例模式 If the requested class does not * exist it is instantiated and set to a static variable. If it has * previously 以前 been instantiated the variable is returned. * * @access public * @param string the class name being requested * @param string the directory where the class should be found * @param string the class name prefix * @return object */ if ( ! function_exists('load_class')) { function &load_class($class, $directory = 'libraries', $prefix = 'CI_') { static $_classes = array(); // Does the class exist? If so, we're done... if (isset($_classes[$class])) { return $_classes[$class]; } $name = FALSE; // Look for the class first in the local application/libraries folder // then in the native system/libraries folder foreach (array(APPPATH, BASEPATH) as $path) { if (file_exists($path.$directory.'/'.$class.'.php')) { $name = $prefix.$class; if (class_exists($name) === FALSE) { require($path.$directory.'/'.$class.'.php'); } break; } } // Is the request a class extension? If so we load it too if (file_exists(APPPATH.$directory.'/'.config_item('subclass_prefix').$class.'.php')) { $name = config_item('subclass_prefix').$class; if (class_exists($name) === FALSE) { require(APPPATH.$directory.'/'.config_item('subclass_prefix').$class.'.php'); } } // Did we find the class? if ($name === FALSE) { // Note: We use exit() rather then show_error() in order to avoid a // self-referencing loop with the Excptions class exit('Unable to locate the specified class: '.$class.'.php'); } // Keep track of what we just loaded is_loaded($class); $_classes[$class] = new $name(); return $_classes[$class]; } } // -------------------------------------------------------------------- /** * Keeps track 追踪 of which libraries have been loaded. This function is * called by the load_class() function above * * @access public * @return array */ if ( ! function_exists('is_loaded')) { function &is_loaded($class = '') { static $_is_loaded = array(); if ($class != '') { $_is_loaded[strtolower($class)] = $class; } return $_is_loaded; } } // ------------------------------------------------------------------------ /** * Loads the main config.php file * * This function lets us grab 获取 the config file even 甚至 if the Config class * hasn't been instantiated yet * * @access private * @return array */ if ( ! function_exists('get_config')) { function &get_config($replace = array()) { static $_config; if (isset($_config)) { return $_config[0]; } // Is the config file in the environment folder? if ( ! defined('ENVIRONMENT') OR ! file_exists($file_path = APPPATH.'config/'.ENVIRONMENT.'/config.php')) { $file_path = APPPATH.'config/config.php'; } // Fetch 取得、拿来 the config file if ( ! file_exists($file_path)) { exit('The configuration file does not exist.'); } require($file_path); // Does the $config array exist in the file? if ( ! isset($config) OR ! is_array($config)) { exit('Your config file does not appear to be formatted correctly.'); } // Are any values being dynamically replaced? if (count($replace) > 0) { foreach ($replace as $key => $val) { if (isset($config[$key])) { $config[$key] = $val; } } } return $_config[0] =& $config; } } // ------------------------------------------------------------------------ /** * Returns the specified 指定的 config item * * @access public * @return mixed */ if ( ! function_exists('config_item')) { function config_item($item) { static $_config_item = array(); if ( ! isset($_config_item[$item])) { $config =& get_config(); if ( ! isset($config[$item])) { return FALSE; } $_config_item[$item] = $config[$item]; } return $_config_item[$item]; } } // ------------------------------------------------------------------------ /** * Error Handler 处理器、处理程序 * * This function lets us invoke 调用 the exception 异常 class and * display errors using the standard 标准 error template located 地处、处于 * in application/errors/errors.php * This function will send the error page directly to the * browser and exit. * * @access public * @return void */ if ( ! function_exists('show_error')) { function show_error($message, $status_code = 500, $heading = 'An Error Was Encountered') { $_error =& load_class('Exceptions', 'core'); echo $_error->show_error($heading, $message, 'error_general', $status_code); exit; } } // ------------------------------------------------------------------------ /** * 404 Page Handler * * This function is similar 相似的类似的 to the show_error() function above在。。。上面 * However 然而、但是, instead 代替、反而、更换 of the standard 标准、规格、标准版 error * template it displays * 404 errors. * * @access public * @return void */ if ( ! function_exists('show_404')) { function show_404($page = '', $log_error = TRUE) { $_error =& load_class('Exceptions', 'core'); $_error->show_404($page, $log_error); exit; } } // ------------------------------------------------------------------------ /** * Error Logging Interface 界面 * * We use this as a simple mechanism 机制、原理 to access 接近、进入、通道 the logging * class and send messages to be logged. * * @access public * @return void */ if ( ! function_exists('log_message')) { function log_message($level = 'error', $message, $php_error = FALSE) { static $_log; if (config_item('log_threshold') == 0) { return; } $_log =& load_class('Log'); $_log->write_log($level, $message, $php_error); } } // ------------------------------------------------------------------------ /** * Set HTTP Status Header * * @access public * @param int the status code * @param string * @return void */ if ( ! function_exists('set_status_header')) { function set_status_header($code = 200, $text = '') { $stati = array( 200 => 'OK', 201 => 'Created', 202 => 'Accepted', 203 => 'Non-Authoritative Information', 204 => 'No Content', 205 => 'Reset Content', 206 => 'Partial Content', 300 => 'Multiple Choices', 301 => 'Moved Permanently', 302 => 'Found', 304 => 'Not Modified', 305 => 'Use Proxy', 307 => 'Temporary Redirect', 400 => 'Bad Request', 401 => 'Unauthorized', 403 => 'Forbidden', 404 => 'Not Found', 405 => 'Method Not Allowed', 406 => 'Not Acceptable', 407 => 'Proxy Authentication Required', 408 => 'Request Timeout', 409 => 'Conflict', 410 => 'Gone', 411 => 'Length Required', 412 => 'Precondition Failed', 413 => 'Request Entity Too Large', 414 => 'Request-URI Too Long', 415 => 'Unsupported Media Type', 416 => 'Requested Range Not Satisfiable', 417 => 'Expectation Failed', 500 => 'Internal Server Error', 501 => 'Not Implemented', 502 => 'Bad Gateway', 503 => 'Service Unavailable', 504 => 'Gateway Timeout', 505 => 'HTTP Version Not Supported' ); if ($code == '' OR ! is_numeric($code)) { show_error('Status codes must be numeric', 500); } if (isset($stati[$code]) AND $text == '') { $text = $stati[$code]; } if ($text == '') { show_error('No status text available. Please check your status code number or supply your own message text.', 500); } $server_protocol = (isset($_SERVER['SERVER_PROTOCOL'])) ? $_SERVER['SERVER_PROTOCOL'] : FALSE; if (substr(php_sapi_name(), 0, 3) == 'cgi') { header("Status: {$code} {$text}", TRUE); } elseif ($server_protocol == 'HTTP/1.1' OR $server_protocol == 'HTTP/1.0') { header($server_protocol." {$code} {$text}", TRUE, $code); } else { header("HTTP/1.1 {$code} {$text}", TRUE, $code); } } } // -------------------------------------------------------------------- /** * Exception Handler * * This is the custom 自定义的 exception handler that is declaired at the top * of Codeigniter.php. The main reason 原因、理由 we use this is to permit 许可 * PHP errors to be logged in our own log files since the user may * not have access 接近、进入 to server logs. Since this function * effectively 有效地 intercepts 拦截 PHP errors, however,但是 we also need * to display errors based on the current error_reporting level. * We do that with the use of a PHP error template. * * @access private * @return void */ if ( ! function_exists('_exception_handler')) { function _exception_handler($severity, $message, $filepath, $line) { // We don't bother 打扰、麻烦 with "strict" 严格地 notices since they tend 倾向于 to fill up // the log file with excess information that isn't normally very helpful. // For example, if you are running PHP 5 and you use version 4 style // class functions (without prefixes like "public", "private", etc.) // you'll get notices telling you that these have been deprecated. if ($severity == E_STRICT) { return; } $_error =& load_class('Exceptions', 'core'); // Should we display the error? We'll get the current error_reporting // level and add its bits with the severity bits to find out. if (($severity & error_reporting()) == $severity) { $_error->show_php_error($severity, $message, $filepath, $line); } // Should we log the error? No? We're done... if (config_item('log_threshold') == 0) { return; } $_error->log_exception($severity, $message, $filepath, $line); } } // -------------------------------------------------------------------- /** * Remove Invisible 无形的,看不见的 Characters * * This prevents sandwiching 夹层 null characters * between ascii characters, like Java\script. * * @access public * @param string * @return string */ if ( ! function_exists('remove_invisible_characters')) { function remove_invisible_characters($str, $url_encoded = TRUE) { $non_displayables = array(); // every control character except newline (dec 10) // carriage return (dec 13), and horizontal tab (dec 09) if ($url_encoded) { $non_displayables[] = '/%0[0-8bcef]/'; // url encoded 00-08, 11, 12, 14, 15 $non_displayables[] = '/%1[0-9a-f]/'; // url encoded 16-31 } $non_displayables[] = '/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]+/S'; // 00-08, 11, 12, 14-31, 127 do { $str = preg_replace($non_displayables, '', $str, -1, $count); } while ($count); return $str; } } // ------------------------------------------------------------------------ /** * Returns HTML escaped variable * * @access public * @param mixed * @return mixed */ if ( ! function_exists('html_escape')) { function html_escape($var) { if (is_array($var)) { return array_map('html_escape', $var); } else { return htmlspecialchars($var, ENT_QUOTES, config_item('charset')); } } } /* End of file Common.php */ /* Location: ./system/core/Common.php */ ~~~
';

系统初始化文件

最后更新于:2022-04-01 20:45:50

文件位置:Location: ./system/core/CodeIgniter.php CodeIgniter.php 执行流程分析 这是系统初始化文件 1.定义CI版本 2.定义CI分支  这里我认为CI有两个分支一个是Core ,另一个是Reactor。但是这里具体的作用我还没弄白。 3.加载全局函数system/core/common.php 4.加载框架常量  如果定义了ENVIRONMENT常量并且在APPPATH/cofig/下面有以ENVIRONMENT常量为名字的文件夹并且里面存在constants.php则加载这个constants.php 如果没有则直接加载APPPATH/cofig/下面的constants.php 5.定义一个自定义的错误处理函数,让我们用来记录php错误日志 6.如果当前php版本>5.3  则关闭魔术转义 7.设置类前缀(在index.php中可以通过$assign_to_config[]来自定义配置项) 一般的类前缀会在config文件中被设置,这个类前缀可以让CI知道application下的libraries文件夹下哪些的类继承了CI核心类的类,因为CI容许入口文件index.php中覆盖配置文件的配置项,所以程序开始执行之前我们需要知道类前缀是否被覆盖,如果被覆盖了,我们将在所有类加载之前设置它的值。 8.设置脚本执行时间 9.脚本开始执行 加载并实例化基准测试类(类文件:core/Benchmark.php) 记下total_execution_time_start 、loading_time:_base_classes_start这两个时间点 10、如果可以加载并实例化钩子类 (类文件core/Hooks.php)我们就加载并实例化 这需要在钩子是在 application/config/config.php 中开启并在 application/config/hooks.php文件中定义当前的钩子 详情:http://codeigniter.org.cn/user_guide/general/hooks.html 11.加载并实例化配置类 如果我们在index.php中手动的通过$assign_to_config[]来进行配置 12、加载并实例化UTF-8类,这里的顺序是非常重要的UTF-8类必须跟在配置类的后面加载 13、加载并实例化URI类 14、加载并实例化router类,设置router 15、加载并实例化输出类 16、判断有没有缓存文件如果有输出 17、为了防止xss和csrf攻击加载并实例化security类 18、加载并实例化输入类 19、加载并实例化语言包 20、加载并实例化控制器类 get_instance() 这个函数用于实例化控制器类 21、判断是否存在子控制器类 如果存在加载 22、通过控制器去加载本地应用程序下请求的控制器 23、记录loading_time:_base_classes_end时间点 24、进行安全监测 此处有说明:所有的功能不管是应用程序控制器还是加载类可以通过URI调用,控制器function不能用下划线开始 先通过控制器获得加载的类和方法 当加载的类或者方法又或者方法不在CI_Controller这个类中的时候,显示404页面 25、如果设置了pre_controller这个钩子则调用 26、记录请求控制器的时间并且实例化请求的类 27、如果设置了post_controller_constructor这个钩子则调用 28、调用请求的方法 首先监测请求的类中是否有_remap方法,如果有调用 如果没有再判断请求的类中是否有请求的方法如果没有显示404页面 最后调用请求的方法 29、记录控制器执行结束的时间 30、如果设置了post_controller这个钩子则调用 31、将最终的输出发送到浏览器 32、如果设置了post_system钩子则调用 33、判断CI_DB类是否存在还有$CI->db是否设置了值如果为真则关闭数据库连接。 下面是文件源码: ~~~ $assign_to_config['subclass_prefix'])); } /* * ------------------------------------------------------ * Set a liberal 自由主义者 script execution 执行 time limit * ------------------------------------------------------ */ if (function_exists("set_time_limit") == TRUE AND @ini_get("safe_mode") == 0) { @set_time_limit(300); } /* * ------------------------------------------------------ * Start the timer... tick tock tick tock... * ------------------------------------------------------ */ $BM =& load_class('Benchmark', 'core'); $BM->mark('total_execution_time_start'); $BM->mark('loading_time:_base_classes_start'); /* * ------------------------------------------------------ * Instantiate the hooks class * ------------------------------------------------------ */ $EXT =& load_class('Hooks', 'core'); /* * ------------------------------------------------------ * Is there a "pre_system" hook? * ------------------------------------------------------ */ $EXT->_call_hook('pre_system'); /* * ------------------------------------------------------ * Instantiate the config class * ------------------------------------------------------ */ $CFG =& load_class('Config', 'core'); // Do we have any manually 手动的 set config items in the index.php file? if (isset($assign_to_config)) { $CFG->_assign_to_config($assign_to_config); } /* * ------------------------------------------------------ * Instantiate the UTF-8 class * ------------------------------------------------------ * * Note: Order 命令顺序 here is rather 宁可,当然 important as the UTF-8 * class needs to be used very early 早期的,提早 on, but it cannot * properly 适当的、正确的 determine 决定 if UTf-8 can be supported until 在。。。以前 * after the Config class is instantiated. * */ $UNI =& load_class('Utf8', 'core'); /* * ------------------------------------------------------ * Instantiate the URI class * ------------------------------------------------------ */ $URI =& load_class('URI', 'core'); /* * ------------------------------------------------------ * Instantiate the routing class and set the routing * ------------------------------------------------------ */ $RTR =& load_class('Router', 'core'); $RTR->_set_routing(); // Set any routing overrides that may exist in the main index file if (isset($routing)) { $RTR->_set_overrides($routing); } /* * ------------------------------------------------------ * Instantiate the output class * ------------------------------------------------------ */ $OUT =& load_class('Output', 'core'); /* * ------------------------------------------------------ * Is there a valid 有效的 cache file? If so, we're done... * ------------------------------------------------------ */ if ($EXT->_call_hook('cache_override') === FALSE) { if ($OUT->_display_cache($CFG, $URI) == TRUE) { exit; } } /* * ----------------------------------------------------- * Load the security 安全 class for xss and csrf support * ----------------------------------------------------- */ $SEC =& load_class('Security', 'core'); /* * ------------------------------------------------------ * Load the Input class and sanitize 使。。。无害 globals * ------------------------------------------------------ */ $IN =& load_class('Input', 'core'); /* * ------------------------------------------------------ * Load the Language class * ------------------------------------------------------ */ $LANG =& load_class('Lang', 'core'); /* * ------------------------------------------------------ * Load the app controller and local controller * ------------------------------------------------------ * */ // Load the base controller class require BASEPATH.'core/Controller.php'; function &get_instance() { return CI_Controller::get_instance(); } if (file_exists(APPPATH.'core/'.$CFG->config['subclass_prefix'].'Controller.php')) { require APPPATH.'core/'.$CFG->config['subclass_prefix'].'Controller.php'; } // Load the local application controller // Note: The Router class automatically 不经思索的、自动的 validates 确认 the controller // path using the router->_validate_request(). // If this include fails it means 手段、意思是 that 因为、那么 the default controller in // the Routes.php fi.le is not resolving 解析 to something 非常 valid 有效地 if ( ! file_exists(APPPATH.'controllers/'.$RTR->fetch_directory().$RTR->fetch_class().'.php')) { show_error('Unable to load your default controller. Please make sure the controller specified in your Routes.php file is valid.'); } include(APPPATH.'controllers/'.$RTR->fetch_directory().$RTR->fetch_class().'.php'); // Set a mark point for benchmarking 管理标记 $BM->mark('loading_time:_base_classes_end'); /* * ------------------------------------------------------ * Security check * ------------------------------------------------------ * * None of the functions in the app controller or the * loader class can be called via the URI, nor 也不是、也没有 can * controller functions that begin with an underscore 下划线、强调、底线 * 所有的功能不管是应用程序控制器还是加载类可以通过URI调用,控制器function不能用下划线开始 */ $class = $RTR->fetch_class(); $method = $RTR->fetch_method(); if ( ! class_exists($class) OR strncmp($method, '_', 1) == 0 OR in_array(strtolower($method), array_map('strtolower', get_class_methods('CI_Controller'))) ) { if ( ! empty($RTR->routes['404_override'])) { $x = explode('/', $RTR->routes['404_override']); $class = $x[0]; $method = (isset($x[1]) ? $x[1] : 'index'); if ( ! class_exists($class)) { if ( ! file_exists(APPPATH.'controllers/'.$class.'.php')) { show_404("{$class}/{$method}"); } include_once(APPPATH.'controllers/'.$class.'.php'); } } else { show_404("{$class}/{$method}"); } } /* * ------------------------------------------------------ * Is there a "pre_controller" hook? * ------------------------------------------------------ */ $EXT->_call_hook('pre_controller'); /* * ------------------------------------------------------ * Instantiate the requested controller * ------------------------------------------------------ */ // Mark a start point so we can benchmark the controller $BM->mark('controller_execution_time_( '.$class.' / '.$method.' )_start'); $CI = new $class(); /* * ------------------------------------------------------ * Is there a "post_controller_constructor" hook? * ------------------------------------------------------ */ $EXT->_call_hook('post_controller_constructor'); /* * ------------------------------------------------------ * Call the requested method * ------------------------------------------------------ */ // Is there a "remap" 重测图、再交换 function? If so, we call it instead 更换、代替 if (method_exists($CI, '_remap')) { $CI->_remap($method, array_slice($URI->rsegments, 2)); } else { // is_callable() returns TRUE on some versions of PHP 5 for private and protected // methods, so we'll use this workaround 变通方案 for consistent behavior 一致的行为 if ( ! in_array(strtolower($method), array_map('strtolower', get_class_methods($CI)))) { // Check and see if we are using a 404 override and use it. if ( ! empty($RTR->routes['404_override'])) { $x = explode('/', $RTR->routes['404_override']); $class = $x[0]; $method = (isset($x[1]) ? $x[1] : 'index'); if ( ! class_exists($class)) { if ( ! file_exists(APPPATH.'controllers/'.$class.'.php')) { show_404("{$class}/{$method}"); } include_once(APPPATH.'controllers/'.$class.'.php'); unset($CI); $CI = new $class(); } } else { show_404("{$class}/{$method}"); } } // Call the requested method. // Any URI segments 片段 present 礼物、现在、目前 (besides 除了。。。之外 the class/function) // will be passed to the method for convenience 便利、方便 call_user_func_array(array(&$CI, $method), array_slice($URI->rsegments, 2)); } // Mark a benchmark end point $BM->mark('controller_execution_time_( '.$class.' / '.$method.' )_end'); /* * ------------------------------------------------------ * Is there a "post_controller" hook? * ------------------------------------------------------ */ $EXT->_call_hook('post_controller'); /* * ------------------------------------------------------ * Send the final rendered 提出、已渲染的 output to the browser * ------------------------------------------------------ */ if ($EXT->_call_hook('display_override') === FALSE) { $OUT->_display(); } /* * ------------------------------------------------------ * Is there a "post_system" hook? * ------------------------------------------------------ */ $EXT->_call_hook('post_system'); /* * ------------------------------------------------------ * Close the DB connection if one exists * ------------------------------------------------------ */ if (class_exists('CI_DB') AND isset($CI->db)) { $CI->db->close(); } /* End of file CodeIgniter.php */ /* Location: ./system/core/CodeIgniter.php */ ~~~
';

程序入口文件

最后更新于:2022-04-01 20:45:47

最近在学习CI框架,自己在按照代码执行顺序阅读源码。做了一些笔记。与其自己珍藏不如拿出来和大家分享 本人并非大牛,是一名处于成长初期的phper,难免有错误的地方。还希望大家能给予指正。 我的CI版本是2.1.3 csdn好像不能上传文件,我就讲代码放在笔记下面了。 如果觉得能对您有一些可以经常来看,我会不定期更新。知道读完CI源码 程序入口: 1、  应用程序环境设置development  testing production  可以设置这三种环境 2、  对不同的环境应用不同的错误级别 3、  设置系统文件夹名 4、  设置应用程序文件夹名 5、  设置默认控制器(这里被注释掉了,如果想设置直接开启) 6、  设置自定义配置 7、  增强system path的可靠性 a)        设置当前目录保证正确的请求 b)        保证目录后面有/ c)        判断当前系统路径是否存在 8、  开始设置主路径常量 SELF                    当前文件的路径 EXT                    文件扩展名 BASEPATH          系统路径 FCPATH               前端控制器路径 SYSDIR                系统文件夹路径 APPPATH            应用程序文件夹路径 9、调用BASEPATH.'core/CodeIgniter.php'文件进入系统引导程序 ~~~ ';

前言

最后更新于:2022-04-01 20:45:45

> 原文出处:[php CI 框架源码阅读笔记](http://blog.csdn.net/column/details/codeigniter.html) 作者:[liushuai_andy](http://blog.csdn.net/liushuai_andy) **本系列文章经作者授权在看云整理发布,未经作者允许,请勿转载!** # php CI 框架源码阅读笔记 > 按照CI框架的执行流程逐个阅读CI源码
';