读书人

CI框架源码翻阅-Output.php

发布时间: 2013-03-13 10:56:58 作者: rapoo

CI框架源码阅读---------Output.php

<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');/** * CodeIgniter * * An open source application development framework for PHP 5.1.6 or newer * * @packageCodeIgniter * @authorExpressionEngine Dev Team * @copyrightCopyright (c) 2008 - 2011, EllisLab, Inc. * @licensehttp://codeigniter.com/user_guide/license.html * @linkhttp://codeigniter.com * @sinceVersion 1.0 * @filesource */// ------------------------------------/** * Output Class * * Responsible 负责 for sending final output to browser * 负责把最终的输出发送到浏览器 * @packageCodeIgniter * @subpackageLibraries * @categoryOutput * @authorExpressionEngine Dev Team * @linkhttp://codeigniter.com/user_guide/libraries/output.html */class CI_Output {/** * Current output string * 当前输出的字符串 * * @var string * @access protected */protected $final_output;/** * Cache expiration time * 缓存终结的时间 * @var int * @access protected */protected $cache_expiration= 0;/** * List of server headers * 服务器头列表 * @var array * @access protected */protected $headers= array();/** * List of mime types *  * @var array * @access protected */protected $mime_types= array();/** * Determines wether profiler is enabled * 是否启用分析器 * @var book * @access protected */protected $enable_profiler= FALSE;/** * Determines if output compression is enabled * 是否开启输出压缩 * @var bool * @access protected */protected $_zlib_oc= FALSE;/** * List of profiler sections * 分析器列表 * * @var array * @access protected */protected $_profiler_sections = array();/** * Whether or not to parse variables like {elapsed_time} and {memory_usage} * 是否解析变量{elapsed_time} and {memory_usage} * 注意文档说这里有错误详见http://codeigniter.org.cn/user_guide/libraries/output.html * 最下方 * @var bool * @access protected */protected $parse_exec_vars= TRUE;/** * Constructor * */function __construct(){// 返回配置项zlib.output_compression的值并赋给$this->_zlib_oc // 如果配置项中开启了输出压缩功能则$this->_zlib_oc 的值为on$this->_zlib_oc = @ini_get('zlib.output_compression');// Get mime types for later// 获取mimetypeif (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 * 返回当前输出的字符串 * @accesspublic * @returnstring */function get_output(){return $this->final_output;}// --------------------------------/** * Set Output * * Sets the output string * 设置输出的字符串 * @accesspublic * @paramstring * @returnvoid */function set_output($output){$this->final_output = $output;return $this;}// --------------------------------/** * Append Output * 在最终输出字符串后,追加数据 * Appends data onto the output string *  * @accesspublic * @paramstring * @returnvoid */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... * * @accesspublic * @paramstring * @param bool * @returnvoid */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 * @accesspublic * @paramstringextension of the file we're outputting * @returnvoid */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) * @accesspublic * @paramintthe status code * @paramstring * @returnvoid */function set_status_header($code = 200, $text = ''){set_status_header($code, $text);return $this;}// --------------------------------/** * Enable/disable Profiler * 允许你开启或禁用分析器 * @accesspublic * @parambool * @returnvoid */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 * 允许你在评测器启用时,控制(开/关)其特定部分 *  * @accesspublic * @paramarray * @returnvoid */function set_profiler_sections($sections){foreach ($sections as $section => $enable){$this->_profiler_sections[$section] = ($enable !== FALSE) ? TRUE : FALSE;}return $this;}// --------------------------------/** * Set Cache * 设置缓存以及缓存时间  * @accesspublic * @paraminteger 其中 $time 是你希望缓存更新的 分钟 数 * @returnvoid */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. * * @accesspublic * @param string * @returnmixed */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 </body> and </html> tags// we will remove them and add them back after we insert the profile data// 如果存在</body></html>标签,我们将删除,插入我们的性能分析代码后再添加回去if (preg_match("|</body>.*?</html>|is", $output)){$output  = preg_replace("|</body>.*?</html>|is", '', $output);$output .= $CI->profiler->run();$output .= '</body></html>';}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 * 生成一个缓存文件 * @accesspublic * @param string * @returnvoid */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中调用此方法有输出,则 * 本次请求的运行将直接结束,直接以缓存输出作为响应。 *  * @accesspublic * @param objectconfig class * @param objecturi class * @returnvoid */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 timestampif ( ! 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 */

读书人网 >PHP

热点推荐