CI框架源码完全分析之核心文件(输出类)Output.php

CI输出类Output.php的功能是将最终web页面发送给浏览器,这里面的东西可能是你用的最少的。你使用装载器加载了一个视图文件, 这个视图文件的内容会自动传递给输出类对象, 然后呢,在方法执行完毕后会自动调用输出类对象将执行的结果输出.值得注意的是这里面有评测器profiler和file cache的内容。

/**
 * Output类:发送最终的Web页面到所请求的浏览器
 */
class CI_Output {

    /**
     *最终输出结果字符串
     */
    protected $final_output;
    /**
     * 缓存时间
     */
    protected $cache_expiration    = 0;
    /**
     * 头信息
     */
    protected $headers         = array();
    /**
     * mime类型
     */
    protected $mime_types      = array();
    /**
     * 是否开启评测器
     */
    protected $enable_profiler = FALSE;
    /**
     * 是否开启gzip研所
     */
    protected $_zlib_oc            = FALSE;
    /**
     * 开启评测模块
     */
    protected $_profiler_sections = array();
    /**
     * 是否替换变量{elapsed_time}耗时 and {memory_usage}内存耗用
     */
    protected $parse_exec_vars = TRUE;

    /**
     * Constructor
     *
     */
    function __construct()
    {
        $this->_zlib_oc = @ini_get('zlib.output_compression');

        // 引入mime类型配置文件
        if (defined('ENVIRONMENT') AND file_exists(APPPATH.'config/'.ENVIRONMENT.'/mimes.php'))
        {
            include APPPATH.'config/'.ENVIRONMENT.'/mimes.php';
        }
        else
        {
            include APPPATH.'config/mimes.php';
        }


        $this->mime_types = $mimes;

        log_message('debug', "Output Class Initialized");
    }

    // --------------------------------------------------------------------

    /**
     * 返回最终输出结果
     */
    function get_output()
    {
        return $this->final_output;
    }


    /**
     * 设置最终返回结果
     */
    function set_output($output)
    {
        $this->final_output = $output;

        return $this;
    }


    /**
     * 将数据追加到最终输出结果,此方法在Loader.php中被调用。详见Loader.php中的Loader::view()方法及Loader::_ci_load()方法。
     */
    function append_output($output)
    {
        if ($this->final_output == '')
        {
            $this->final_output = $output;
        }
        else
        {
            $this->final_output .= $output;
        }

        return $this;
    }

    // --------------------------------------------------------------------

    /**
     * 设置浏览器最终输出header
     */
    function set_header($header, $replace = TRUE)
    {
        // 如果开启了gzip压缩,那么不会修改content-length header,导致浏览器挂起等待更多数据,直接跳过这种情况
        if ($this->_zlib_oc && strncasecmp($header, 'content-length', 14) == 0)
        {
            return;
        }

        $this->headers[] = array($header, $replace);

        return $this;
    }

    // --------------------------------------------------------------------

    /**
     * 设置Content Type
     */
    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
     */
    function set_status_header($code = 200, $text = '')
    {
        set_status_header($code, $text);

        return $this;
    }

    // --------------------------------------------------------------------

    /**
     * 是否开启评测器
     */
    function enable_profiler($val = TRUE)
    {
        $this->enable_profiler = (is_bool($val)) ? $val : TRUE;

        return $this;
    }

    // --------------------------------------------------------------------

    /**
     * 自定义开启的评测模块
     */
    function set_profiler_sections($sections)
    {
        foreach ($sections as $section => $enable)
        {
            $this->_profiler_sections[$section] = ($enable !== FALSE) ? TRUE : FALSE;
        }

        return $this;
    }

    // --------------------------------------------------------------------

    /**
     * 设置缓存时长,开启文件缓存
     */
    function cache($time)
    {
        $this->cache_expiration = ( ! is_numeric($time)) ? 0 : $time;

        return $this;
    }

    // --------------------------------------------------------------------

    /**
     * 将最终结果输出到浏览器
     */
    function _display($output = '')
    {
        //使用global的原因是_display_cache在Codeigniter.php被使用,Output::_display_cache()调用了_display
        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;
        }

        // --------------------------------------------------------------------

        // 如果开启缓存,生成缓存文件
        if ($this->cache_expiration > 0 && isset($CI) && ! method_exists($CI, '_output'))
        {
            $this->_write_cache($output);
        }

        // --------------------------------------------------------------------

        //系统的总体运行时间和内存消耗就是在这里替换的
        $elapsed = $BM->elapsed_time('total_execution_time_start', 'total_execution_time_end');

        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);
        }

        // --------------------------------------------------------------------

        // 是否开启gzip压缩
        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]);
            }
        }

        // --------------------------------------------------------------------

        //如果没有超级控制器,可以证明当前是在处理一个缓存的输出
        if ( ! isset($CI))
        {
            echo $output;
            log_message('debug', "Final output sent to browser");
            log_message('debug', "Total execution time: ".$elapsed);
            return TRUE;
        }

        // --------------------------------------------------------------------

        // 如果开启评测器,在页面输出结果插入评测器信息
        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
            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();
            }
        }

        // --------------------------------------------------------------------

        // CodeIgniter 允许你给你的控制器增加一个名为 _output() 的方法来接收最终的数据。

                //注意: 如果你的控制器包含一个 _output() 方法,那么它将总是被调用,而不是直接输出最终的数据。这个方法类似于OO里的析构函数,不管你调用任何方法这个方法总是会被执行。
        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);
    }

    // --------------------------------------------------------------------

    /**
     * 写入缓存文件
     * @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 =	$CI->config->item('base_url').
                $CI->config->item('index_page').
                $CI->uri->uri_string();

        $cache_path .= md5($uri); //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
     *
     * @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
        $uri =	$CFG->item('base_url').
                $CFG->item('index_page').
                $URI->uri_string;

        $filepath = $cache_path.md5($uri);

        if ( ! @file_exists($filepath))
        {
            return FALSE;
        }

        if ( ! $fp = @fopen($filepath, FOPEN_READ))
        {
            return FALSE;
        }

        flock($fp, LOCK_SH);

        $cache = '';
        if (filesize($filepath) > 0)
        {
            $cache = fread($fp, filesize($filepath));
        }

        flock($fp, LOCK_UN);
        fclose($fp);

        // 很巧妙处理文件头13834243242TS--->
        if ( ! preg_match("/(\d+TS--->)/", $cache, $match))
        {
            return FALSE;
        }

        // 缓存文件是否过期,过期则删除
        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;
    }


}

转载注明地址: http://www.phpddt.com/php/ci-output.html 尊重他人劳动成果就是尊重自己!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值