ホームページ バックエンド開発 PHPチュートリアル CI フレームワークのソース コード レビュー - Output.php

CI フレームワークのソース コード レビュー - Output.php

Jun 13, 2016 pm 12:52 PM
cache gt output return this

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
 *
 * @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 ( ! 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
	 * 生成一个缓存文件
	 * @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 */
ログイン後にコピー

このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

AI Hentai Generator

AI Hentai Generator

AIヘンタイを無料で生成します。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

Huawei GT3 ProとGT4の違いは何ですか? Huawei GT3 ProとGT4の違いは何ですか? Dec 29, 2023 pm 02:27 PM

多くのユーザーはスマートウォッチを選ぶときにファーウェイブランドを選択しますが、その中でもファーウェイ GT3pro と GT4 は非常に人気のある選択肢であり、多くのユーザーはファーウェイ GT3pro と GT4 の違いに興味を持っています。 Huawei GT3pro と GT4 の違いは何ですか? 1. 外観 GT4: 46mm と 41mm、材質はガラスミラー + ステンレススチールボディ + 高解像度ファイバーバックシェルです。 GT3pro: 46.6mm および 42.9mm、材質はサファイアガラス + チタンボディ/セラミックボディ + セラミックバックシェルです。 2. 健全な GT4: 最新の Huawei Truseen5.5+ アルゴリズムを使用すると、結果はより正確になります。 GT3pro: ECG 心電図と血管と安全性を追加

C言語のreturnの使い方を詳しく解説 C言語のreturnの使い方を詳しく解説 Oct 07, 2023 am 10:58 AM

C 言語における return の使い方は、 1. 戻り値の型が void の関数については、return 文を使用して関数の実行を早期に終了することができます; 2. 戻り値の型が void ではない関数については、 return ステートメントは、関数の実行を終了するためのものです。結果は呼び出し元に返されます。 3. 関数の実行を早期に終了します。関数内で return ステートメントを使用して、関数の実行を早期に終了することもできます。関数が値を返さない場合。

入社してキャッシュとは何かを理解した 入社してキャッシュとは何かを理解した Jul 31, 2023 pm 04:03 PM

実際は次のようなものです。当時、私のリーダーは私に perf ハードウェア パフォーマンス監視タスクを与えました。perf を使用するプロセス中に、コマンド perf list を入力すると、次の情報が表示されました。私のタスクは、これらのキャッシュ イベントを有効にすることです。しかし重要なのは、これらのミスやロードが何を意味するのか全く分からないということです。

修正: Windows 11 で Snipping ツールが機能しない 修正: Windows 11 で Snipping ツールが機能しない Aug 24, 2023 am 09:48 AM

Windows 11 で Snipping Tool が機能しない理由 問題の根本原因を理解すると、適切な解決策を見つけるのに役立ちます。 Snipping Tool が正しく動作しない主な理由は次のとおりです。 フォーカス アシスタントがオンになっている: これにより、Snipping Tool が開かなくなります。破損したアプリケーション: 起動時にスニッピング ツールがクラッシュする場合は、破損している可能性があります。古いグラフィック ドライバー: 互換性のないドライバーは、スニッピング ツールに干渉する可能性があります。他のアプリケーションからの干渉: 実行中の他のアプリケーションが Snipping Tool と競合する可能性があります。証明書の有効期限が切れています: アップグレード プロセス中のエラーにより、この問題が発生する可能性があります。これらの簡単な解決策は、ほとんどのユーザーに適しており、特別な技術知識は必要ありません。 1. Windows および Microsoft Store アプリを更新する

Javaのreturn文とfinally文の実行順序は何ですか? Javaのreturn文とfinally文の実行順序は何ですか? Apr 25, 2023 pm 07:55 PM

ソースコード: publicclassReturnFinallyDemo{publicstaticvoidmain(String[]args){System.out.println(case1());}publicstaticintcase1(){intx;try{x=1;returnx;}finally{x=3;}}}#出力 上記のコードの出力は、単純に次のように結論付けることができます:finally の前に return が実行されます。バイトコード レベルで何が起こるかを見てみましょう。以下は、case1 メソッドのバイトコードの一部をインターセプトし、ソース コードを比較して、各命令の意味に注釈を付けます。

iPhoneでApp Storeに接続できないエラーを修正する方法 iPhoneでApp Storeに接続できないエラーを修正する方法 Jul 29, 2023 am 08:22 AM

パート 1: 最初のトラブルシューティング手順 Apple のシステムステータスを確認する: 複雑な解決策を掘り下げる前に、基本から始めましょう。問題はデバイスにあるのではなく、Apple のサーバーがダウンしている可能性があります。 Apple のシステム ステータス ページにアクセスして、AppStore が適切に動作しているかどうかを確認してください。問題があれば、Apple が修正してくれるのを待つしかありません。インターネット接続を確認します。「AppStore に接続できません」問題は接続不良が原因である場合があるため、安定したインターネット接続があることを確認してください。 Wi-Fi とモバイル データを切り替えるか、ネットワーク設定をリセットしてみてください ([一般] > [リセット] > [ネットワーク設定のリセット] > [設定])。 iOS バージョンを更新します。

キャッシュを使用するとコンピュータの速度が向上するのはなぜですか? キャッシュを使用するとコンピュータの速度が向上するのはなぜですか? Dec 09, 2020 am 11:28 AM

キャッシュを使用すると、CPU の待ち時間が短縮されるため、コンピューターの速度が向上します。キャッシュは、CPU とメイン メモリ DRAM の間に位置する小さいながらも高速なメモリです。キャッシュの機能はCPUのデータ入出力速度を高めることであり、キャッシュは容量は小さいが速度が速く、メモリは速度は低いが容量が大きいため、スケジューリングアルゴリズムを最適化することでシステムのパフォーマンスを向上させることができます。大幅に改善されました。

キャッシュとは何ですか? キャッシュとは何ですか? Nov 25, 2022 am 11:48 AM

キャッシュはキャッシュメモリと呼ばれ、中央処理装置とメインメモリの間にある高速かつ小容量のメモリで、通常は高速SRAMで構成され、CPU向けのこの種のローカルメモリが導入されています。 CPU とメモリ間の速度差がシステム パフォーマンスに及ぼす影響を軽減または排除します。キャッシュ容量は小さいですが高速、メモリ速度は遅いですが容量は大きく、スケジューリングアルゴリズムを最適化することでシステムのパフォーマンスが大幅に向上します。

See all articles