PHP头条
热点:

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


[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 
 * 
 * @package     CodeIgniter 
 * @author      ExpressionEngine Dev Team 
 * @copyright   Copyright (c) 2008 - 2011, EllisLab, Inc. 
 * @license     http://codeigniter.com/user_guide/license.html 
 * @link        http://codeigniter.com 
 * @since       Version 1.0 
 * @filesource 
 */  
  
// ------------------------------------------------------------------------  
  
/** 
 * Output Class 
 * 
 * Responsible 负责 for sending final output to browser 
 * 负责把最终的输出发送到浏览器 
 * @package     CodeIgniter 
 * @subpackage  Libraries 
 * @category    Output 
 * @author      ExpressionEngine Dev Team 
 * @link        http://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  
        // 获取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 ( ! emptyempty($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 
     * 生成一个缓存文件 
     * @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 */  
 

www.phpzy.comtrue/phprm/11525.htmlTechArticleCI框架源码阅读---------Output.php [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 * * @package CodeIgniter * @au...

相关文章

    暂无相关文章
相关频道:

PHP之友评论

今天推荐