php是单线程,串行的

CI框架源码阅读笔记3 全局函数Common.php
从本篇开始,将深入CI 框架 的内部,一步步去探索这个 框架 的实现、结构和设计。 Common.php文件定义了一系列的 全局 函数 (一般来说, 全局 函数 具有最高的加载优先权,因此大多数的 框架 中BootStrap引导文件都会最先引入 全局 函数 ,以便于之后的处理
从本篇开始,将深入ci框架的内部,一步步去探索这个框架的实现、结构和设计。
Common.php文件定义了一系列的全局函数(一般来说,全局函数具有最高的加载优先权,因此大多数的框架中BootStrap引导文件都会最先引入全局函数,以便于之后的处理工作)。
打开Common.php中,第一行代码就非常诡异:
1 | <span> if </span> ( ! <span>defined</span>( ''BASEPATH'' )) <span> exit </span>( ''No direct script access allowed'' );
|
登录后复制
CI框架源码阅读笔记2 一切的入口 index.php)中,我们已经知道,BASEPATH是在入口文件中定义的常量。这里做这个判断的原因是:避免直接访问文件,而必须由index.php入口文件进入。其实不仅是Common.php,System中所有文件,几乎都要引入这个常量的判断,避免直接的脚本访问:

立即学习“PHP免费学习笔记(深入)”;
本文件中定义的函数如下(查看方式 print_r(get_defined_functions())):

CI中所有全局函数的定义方式都为:
1 2 3 4 5 | <span> if </span> ( ! <span>function_exists</span>( ''func_name'' <span>)){
</span><span> function </span><span> func_name(){
//function body
}
}</span>
|
登录后复制
这样做,是为了防止定义重名函数(之后如果我们要定义系统的全局函数,也都将使用这种定义方式)。下面,一个个展开来看:
1. is_php
这个函数的命名很明显,就是判断当前环境的PHP版本是否是特定的PHP版本(或者高于该版本)
该函数内部有一个static的$_is_php数组变量,用于缓存结果(因为在特定的运行环境中,PHP的版本是已知的且是不变的,所以通过缓存的方式,避免每次调用时都去进行version_compare。这种方式,与一般的分布式缓存(如Redis)的处理思维是一致的,不同的是,这里是使用static数组的方式,而分布式缓存大多使用内存缓存)。
为什么要定义这个函数呢?这是因为,CI框架中有一些配置依赖于PHP的版本和行为(如magic_quotes,PHP 5.3版本之前,该特性用于指定是否开启转义,而PHP5.3之后,该特性已经被废弃)。这就好比是针对不同的浏览器进行Css Hack一样(这里仅仅是比喻,实际上,PHP并没有太多的兼容性问题)。
具体的实现源码:
1 2 3 4 5 6 7 8 9 10 11 | <span> function </span> is_php(<span> $version </span> = ''5.0.0'' <span>)
{
</span><span> static </span> <span> $_is_php </span><span>;
</span><span> $version </span> = (<span>string</span>)<span> $version </span><span>;
</span><span> if </span> ( ! <span>isset</span>(<span> $_is_php </span>[<span> $version </span><span>]))
{
</span><span> $_is_php </span>[<span> $version </span>] = (<span>version_compare</span>(<span>PHP_VERSION</span>, <span> $version </span>) FALSE : <span>TRUE</span><span>;
}
</span><span> return </span> <span> $_is_php </span>[<span> $version </span><span>];
}</span>
|
登录后复制
2. is_really_writable
这个函数用于判断文件或者目录是否真实可写,一般情况下,通过内置函数is_writable()返回的结果是比较可靠的,但是也有一些例外,比如:
(a). Windows中,如果对文件或者目录设置了只读属性,则is_writable返回结果是true,但是却无法写入。
(b). Linux系统中,如果开启了Safe Mode,则也会影响is_writable的结果
因此,本函数的处理是:
如果是一般的Linux系统且没有开启safe mode,则直接调用is_writable
否则:
如果是目录,则尝试在目录中创建一个文件来检查目录是否可写
如果是文件,则尝试以写入模式打开文件,如果无法打开,则返回false
注意,即使是使用fopen检查文件是否可写,也一定记得调用fclose关闭句柄,这是一个好的习惯。
该函数的源码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | <span> function </span> is_really_writable(<span> $file </span><span>)
{
</span><span> //</span><span> If we''re on a Unix server with safe_mode off we call is_writable</span>
<span> if </span> (DIRECTORY_SEPARATOR == ''/'' AND @<span> ini_get </span>( "safe_mode" ) == <span>FALSE</span><span>)
{
</span><span> return </span> <span> is_writable </span>(<span> $file </span><span>);
}
</span><span> //</span><span> For windows servers and safe_mode "on" installations we''ll actually write a file then read it</span>
<span> if </span> (<span> is_dir </span>(<span> $file </span><span>))
{
</span><span> $file </span> = <span>rtrim</span>(<span> $file </span>, ''/'' ). ''/'' .<span>md5</span>(<span>mt_rand</span>(1,100).<span>mt_rand</span>(1,100<span>));
</span><span> if </span> ((<span> $fp </span> = @<span> fopen </span>(<span> $file </span>, FOPEN_WRITE_CREATE)) === <span>FALSE</span><span>)
{
</span><span> return </span> <span>FALSE</span><span>;
}
</span><span>fclose</span>(<span> $fp </span><span>);
@</span><span> chmod </span>(<span> $file </span>,<span> DIR_WRITE_MODE);
@</span><span>unlink</span>(<span> $file </span><span>);
</span><span> return </span> <span>TRUE</span><span>;
}
</span><span> elseif </span> ( ! <span> is_file </span>(<span> $file </span>) OR (<span> $fp </span> = @<span> fopen </span>(<span> $file </span>, FOPEN_WRITE_CREATE)) === <span>FALSE</span><span>)
{
</span><span> return </span> <span>FALSE</span><span>;
}
</span><span>fclose</span>(<span> $fp </span><span>);
</span><span> return </span> <span>TRUE</span><span>;
}</span>
|
登录后复制
3. load_class
这个函数有几个特殊的地方需要重点关注:
(1). 注意这个函数的签名,function &load_class( $class,$directory,$prefix).看到前面那个特殊的&符号没?没错,这个函数返回的是一个class实例的引用. 对该实例的任何改变,都会影响下一次函数调用的结果。
(2). 这个函数也有一个内部的static变量缓存已经加载的类的实例,实现方式类似于单例模式(Singleton)
(3). 函数优先查找APPPATH和BASEPATH中查找类,然后才从$directory中查找类,这意味着,如果directory中存在着同名的类(指除去前缀之后同名),CI加载的实际上是该扩展类。这也意味着,可以对CI的核心进行修改或者扩展。
下面是该函数的源码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | <span> function </span> &load_class(<span> $class </span>, <span> $directory </span> = ''libraries'' , <span> $prefix </span> = ''CI_'' <span>)
{
</span><span> /*</span><span> 缓存加载类的实例 </span><span>*/ </span>
<span> static </span> <span> $_classes </span> = <span> array </span><span>();
</span><span> if </span> (<span>isset</span>(<span> $_classes </span>[<span> $class </span><span>]))
{
</span><span> return </span> <span> $_classes </span>[<span> $class </span><span>];
}
</span><span> $name </span> = <span>FALSE</span><span>;
</span><span> /*</span><span> 先查找系统目录 </span><span>*/ </span>
<span> foreach </span> (<span> array </span>(APPPATH, BASEPATH) <span> as </span> <span> $path </span><span>)
{
</span><span> if </span> (<span> file_exists </span>(<span> $path </span>.<span> $directory </span>. ''/'' .<span> $class </span>. ''.php'' <span>))
{
</span><span> $name </span> = <span> $prefix </span>.<span> $class </span><span>;
</span><span> if </span> (<span> class_exists </span>(<span> $name </span>) === <span>FALSE</span><span>)
{
</span><span> require </span>(<span> $path </span>.<span> $directory </span>. ''/'' .<span> $class </span>. ''.php'' <span>);
}
</span><span> break </span><span>;
}
}
</span><span> /*</span><span> 查找之后并没有立即实例化,而是接着查找扩展目录 </span><span>*/ </span>
<span> if </span> (<span> file_exists </span>(APPPATH.<span> $directory </span>. ''/'' .config_item( ''subclass_prefix'' ).<span> $class </span>. ''.php'' <span>))
{
</span><span> $name </span> = config_item( ''subclass_prefix'' ).<span> $class </span><span>;
</span><span> if </span> (<span> class_exists </span>(<span> $name </span>) === <span>FALSE</span><span>)
{
</span><span> require </span>(APPPATH.<span> $directory </span>. ''/'' .config_item( ''subclass_prefix'' ).<span> $class </span>. ''.php'' <span>);
}
}
</span><span> /*</span><span> 没有找到任何文件 </span><span>*/ </span>
<span> if </span> (<span> $name </span> === <span>FALSE</span><span>)
{
</span><span> exit </span>( ''Unable to locate the specified class: '' .<span> $class </span>. ''.php'' <span>);
}
</span><span> /*</span><span> 将$class计入已加载的类列表 </span><span>*/ </span><span>
is_loaded(</span><span> $class </span><span>);
</span><span> /*</span><span> 取得实例化 </span><span>*/ </span>
<span> $_classes </span>[<span> $class </span>] = <span> new </span> <span> $name </span><span>();
</span><span> return </span> <span> $_classes </span>[<span> $class </span><span>];
}</span>
|
登录后复制
4. is_loaded
这个函数用于追踪所有已加载的class。代码比较简洁,没有太多可讲的地方,这里直接贴出源码:
1 2 3 4 5 6 7 8 9 10 | <span> function </span> &is_loaded(<span> $class </span> = '''' <span>)
{
</span><span> static </span> <span> $_is_loaded </span> = <span> array </span><span>();
</span><span> if </span> (<span> $class </span> != '''' <span>)
{
</span><span> $_is_loaded </span>[<span> strtolower </span>(<span> $class </span>)] = <span> $class </span><span>;
}
</span><span> return </span> <span> $_is_loaded </span><span>;
}</span>
|
登录后复制
5. get_config
这个函数用于加载主配置文件(即位于config/目录下的config.php文件,如果定义了针对特定ENVIRONMENT的config.php文件,则是该文件)。该函数的签名为:
function &get_config($replace = array())
有几个需要注意的点:
(1). 函数只加载主配置文件,而不会加载其他配置文件(这意味着,如果你添加了其他的配置文件,在框架预备完毕之前,不会读取你的配置文件)。在Config组件实例化之前,所有读取主配置文件的工作都由该函数完成。
(2). 该函数支持动态运行的过程中修改Config.php中的条目(配置信息只可能修改一次,因为该函数也有static变量做缓存,若缓存存在,则直接返回配置)
(3). Return $_config[0] = & $config。是config文件中$config的引用,防止改变Config的配置之后,由于该函数的缓存原因,无法读取最新的配置。
这里还有一点无法理解,作者使用了$_config数组来缓存config,而只使用了$_config[0],那么问题来了,为什么不用单一变量代替,即:$_config = & $config; 如果有知道原因的童鞋,麻烦告知一声。
该函数的实现源码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | <span> function </span> &get_config(<span> $replace </span> = <span> array </span><span>())
{
</span><span> static </span> <span> $_config </span><span>;
</span><span> if </span> (<span>isset</span>(<span> $_config </span><span>))
{
</span><span> return </span> <span> $_config </span>[0<span>];
}
</span><span> if </span> ( ! <span>defined</span>( ''ENVIRONMENT'' ) OR ! <span> file_exists </span>(<span> $file_path </span> = APPPATH. ''config/'' .ENVIRONMENT. ''/config.php'' <span>))
{
</span><span> $file_path </span> = APPPATH. ''config/config.php'' <span>;
}
</span><span> if </span> ( ! <span> file_exists </span>(<span> $file_path </span><span>))
{
</span><span> exit </span>( ''The configuration file does not exist.'' <span>);
}
</span><span> require </span>(<span> $file_path </span><span>);
</span><span> if </span> ( ! <span>isset</span>(<span> $config </span>) OR ! <span> is_array </span>(<span> $config </span><span>))
{
</span><span> exit </span>( ''Your config file does not appear to be formatted correctly.'' <span>);
}
</span><span> if </span> (<span> count </span>(<span> $replace </span>) > 0<span>)
{
</span><span> foreach </span> (<span> $replace </span> <span> as </span> <span> $key </span> => <span> $val </span><span>)
{
</span><span> if </span> (<span>isset</span>(<span> $config </span>[<span> $key </span><span>]))
{
</span><span> $config </span>[<span> $key </span>] = <span> $val </span><span>;
}
}
}
</span><span> return </span> <span> $_config </span>[0] =& <span> $config </span><span>;
}</span>
|
登录后复制
6. config_item
这个函数调用了load_config,并获取相应的设置条目。代码比较简洁。不做过多的解释,同样只贴出源码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | <span> function </span> config_item(<span> $item </span><span>)
{
</span><span> static </span> <span> $_config_item </span> = <span> array </span><span>();
</span><span> if </span> ( ! <span>isset</span>(<span> $_config_item </span>[<span> $item </span><span>]))
{
</span><span> $config </span> =&<span> get_config();
</span><span> if </span> ( ! <span>isset</span>(<span> $config </span>[<span> $item </span><span>]))
{
</span><span> return </span> <span>FALSE</span><span>;
}
</span><span> $_config_item </span>[<span> $item </span>] = <span> $config </span>[<span> $item </span><span>];
}
</span><span> return </span> <span> $_config_item </span>[<span> $item </span><span>];
}</span>
|
登录后复制
7. show_error
这是CI定义的可以用来展示错误信息的函数,该函数使用了Exceptions组件(之后我们将看到,CI中都是通过Exceptions组件来管理错误的)来处理错误。
例如,我们可以在自己的应用程序控制器中调用该函数展示错误信息:
1 | <span>Show_error(“trigger error info”);</span>
|
登录后复制
CI框架的错误输出还算是比较美观:

注意该函数不仅仅是显示错误,而且会终止代码的执行(exit)
该函数的源码:
1 2 3 4 5 6 | <span> function </span> show_error(<span> $message </span>, <span> $status_code </span> = 500, <span> $heading </span> = ''An Error Was Encountered'' <span>)
{
</span><span> $_error </span> =& load_class( ''Exceptions'' , ''core'' <span>);
</span><span> echo </span> <span> $_error </span>->show_error(<span> $heading </span>, <span> $message </span>, ''error_general'' , <span> $status_code </span><span>);
</span><span> exit </span><span>;
}</span>
|
登录后复制
8. show_404
没有太多解释的东西,返回404页面
源码:
1 2 3 4 5 6 | <span> function </span> show_404(<span> $page </span> = '''' , <span> $log_error </span> = <span>TRUE</span><span>)
{
</span><span> $_error </span> =& load_class( ''Exceptions'' , ''core'' <span>);
</span><span> $_error </span>->show_404(<span> $page </span>, <span> $log_error </span><span>);
</span><span> exit </span><span>;
}</span>
|
登录后复制
9. log_message
调用Log组件记录log信息,类似Debug。需要注意的是,如果主配置文件中log_threshold被设置为0,则不会记录任何Log信息,该函数的源码:
1 2 3 4 5 6 7 8 9 10 11 12 | <span> function </span> log_message(<span> $level </span> = ''error'' , <span> $message </span>, <span> $php_error </span> = <span>FALSE</span><span>)
{
</span><span> static </span> <span> $_log </span><span>;
</span><span> if </span> (config_item( ''log_threshold'' ) == 0<span>)
{
</span><span> return </span><span>;
}
</span><span> $_log </span> =& load_class( ''Log'' <span>);
</span><span> $_log </span>->write_log(<span> $level </span>, <span> $message </span>, <span> $php_error </span><span>);
}</span>
|
登录后复制
10. set_status_header
CI框架允许你设置HTTP协议的头信息(具体的HTTP状态码和对应含义可以参考:http://blog.csdn.net/ohmygirl/article/details/6922313)。设置方法为:
$this->output->set_status_header(“401”,“lalalala”);(CI的Output组件暴露了set_status_header()对外接口,该接口即是调用set_status_header函数)
值得注意的是,现在很多服务器内部扩展加入了自定义的状态码,如nginx:
1 2 3 4 5 | ngx_string(ngx_http_error_495_page), /* 495,<span> https certificate error */
ngx_string(ngx_http_error_496_page)</span>, /* 496,<span> https no certificate */
ngx_string(ngx_http_error_497_page)</span>, /* 497,<span> http to https */
ngx_string(ngx_http_error_404_page)</span>, /* 498,<span> canceled */
ngx_null_string</span>, /* 499, client has closed connection */
|
登录后复制
所以你在查看服务器的error_log时,如果看到了比较诡异的错误状态码,不要惊慌,这不是bug. 这也说明,如果你要自定义自己的状态码和状态码描述文案,可以在该函数的内部$stati变量中添加自定义的状态码和文案。更多详细的内容,可以查看header函数的manual。
源码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 | <span> function </span> set_status_header(<span> $code </span> = 200, <span> $text </span> = '''' <span>)
{
</span><span> /*</span><span> 所有的已定义状态码和描述文本 </span><span>*/ </span>
<span> $stati </span> = <span> array </span><span>(<br> /* 2xx 成功 */
</span>200 => ''OK'' ,
201 => ''Created'' ,
202 => ''Accepted'' ,
203 => ''Non-Authoritative Information'' ,
204 => ''No Content'' ,
205 => ''Reset Content'' ,
206 => ''Partial Content'' ,
/* 3xx 重定向 */
300 => ''Multiple Choices'' ,
301 => ''Moved Permanently'' ,
302 => ''Found'' ,
304 => ''Not Modified'' ,
305 => ''Use Proxy'' ,
307 => ''Temporary Redirect'' ,
/* 4xx 客户端错误 */
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'' ,
/* 5xx 服务器端错误 */
500 => ''Internal Server Error'' ,
501 => ''Not Implemented'' ,
502 => ''Bad Gateway'' ,
503 => ''Service Unavailable'' ,
504 => ''Gateway Timeout'' ,
505 => ''HTTP Version Not Supported'' <span>
);
</span><span> /*</span><span> 状态码为空或者不是数字,直接抛出错误并退出 </span><span>*/ </span>
<span> if </span> (<span> $code </span> == '''' OR ! <span> is_numeric </span>(<span> $code </span><span>))
{
show_error(</span> ''Status codes must be numeric'' , 500<span>);
}
</span><span> if </span> (<span>isset</span>(<span> $stati </span>[<span> $code </span>]) AND <span> $text </span> == '''' <span>)
{
</span><span> $text </span> = <span> $stati </span>[<span> $code </span><span>];
}
</span><span> /*</span><span> 设置的状态码不在已定义的数组中 </span><span>*/ </span>
<span> if </span> (<span> $text </span> == '''' <span>)
{
show_error(</span> ''No status text available. Please check your status code number or supply your own message text.'' , 500<span>);
}
</span><span> $server_protocol </span> = (<span>isset</span>(<span> $_SERVER </span>[ ''SERVER_PROTOCOL'' ])) ? <span> $_SERVER </span>[ ''SERVER_PROTOCOL'' ] : <span>FALSE</span><span>;
</span><span> /*</span><span> PHP以CGI模式运行 </span><span>*/ </span>
<span> if </span> (<span> substr </span>(<span>php_sapi_name</span>(), 0, 3) == ''cgi'' <span>)
{
</span><span>header</span>( "Status: {<span>$code</span>} {<span>$text</span>}" , <span>TRUE</span><span>);
}
</span><span> elseif </span> (<span> $server_protocol </span> == ''HTTP/1.1'' OR <span> $server_protocol </span> == ''HTTP/1.0'' )<span> /*</span><span> 检查HTTP协议 </span><span>*/ </span><span>
{
</span><span>header</span>(<span> $server_protocol </span>. " {<span>$code</span>} {<span>$text</span>}" , <span>TRUE</span>, <span> $code </span><span>);
}
</span><span> else </span><span>
{
</span><span>header</span>( "HTTP/1.1 {<span>$code</span>} {<span>$text</span>}" , <span>TRUE</span>, <span> $code </span>);<span> /*</span><span> 默认为HTTP/1.1 </span><span>*/ </span><span>
}
}</span>
|
登录后复制
11. _exception_handler
先看函数的签名:
function _exception_handler($severity, $message, $filepath, $line);
$ severity :发生错误的错误码。整数
$message :错误信息。
$filepath :发生错误的文件
$line :错误的行号
这个函数会根据当前设置的error_reporting的设置和配置文件中threshold的设置来决定PHP错误的显示和记录。在CI中,这个函数是作为set_error_handler的callback, 来代理和拦截PHP的错误信息(PHP手册中明确指出:以下级别的错误不能由用户定义的函数来处理: E_ERROR、 E_PARSE、 E_CORE_ERROR、 E_CORE_WARNING、 E_COMPILE_ERROR、 E_COMPILE_WARNING,和在 调用 set_error_handler() 函数所在文件中产生的大多数 E_STRICT 。同样,如果在set_error_handler调用之前发生的错误,也无法被_exception_handler捕获,因为在这之前,_exception_handler尚未注册)。
再看源码实现:
1 2 3 | <span> if </span> (<span> $severity </span> == <span>E_STRICT</span><span>){
</span><span> return </span><span>;
}</span>
|
登录后复制
E_STRICT是PHP5中定义的错误级别,是严格语法模式的错误级别,并不包含在E_STRICT. 由于E_STRICT级别的错误可能会很多,因此,CI的做法是,忽略这类错误。
函数中实际处理和记录错误信息的是Exception组件:
1 | <span> $_error </span> =& load_class( ''Exceptions'' , ''core'' );
|
登录后复制
然后根据当前的error_reporting设置,决定是显示错误(show_php_error)还是记录错误日志(log_exception):
1 2 3 4 | <span> if </span> ((<span> $severity </span> & <span> error_reporting </span>()) == <span> $severity </span><span>)
{
</span><span> $_error </span>->show_php_error(<span> $severity </span>, <span> $message </span>, <span> $filepath </span>, <span> $line </span><span>);
}</span>
|
登录后复制
注意,这里是位运算&而不是逻辑运算&&, 由于PHP中定义的错误常量都是整数,而且是2的整数幂(如
1 E_ERROR
2 E_WARNING
4 E_PARSE
8 E_NOTICE
16 E_CORE_ERROR
...
),因此可以用&方便判断指定的错误级别是否被设置,而在设置的时候,可以通过|运算:
1 2 3 4 5 | <span> /*</span><span> 显示E_ERROR,E_WARNING,E_PARSE错误 </span><span>*/ </span>
<span> error_reporting </span>(<span>E_ERROR</span> | <span>E_WARNING</span> | <span>E_PARSE</span><span>);
</span><span> /*</span><span> 显示除了E_NOTICE之外的错误 </span><span>*/ </span>
<span> error_reporting </span>(<span>E_ALL</span> & ~<span>E_NOTICE</span> | E_STRICE);
|
登录后复制
这与Linux的权限设置rwx的设计思想是一致的(r:4 w:2 x:1)
有时候仅仅显示错误是不够的,还需要记录错误信息到文件:
如果主配置文件config.php中$config[''log_threshold''] == 0,则不记录到文件:
1 2 3 4 | <span> if </span> (config_item( ''log_threshold'' ) == 0<span>)
{
</span><span> return </span><span>;
}</span>
|
登录后复制
否者,记录错误信息到文件(这之中,调用组件Exception去写文件,Exception组件中会调用log_message函数,最终通过Log组件记录错误信息到文件。模块化的一个最大特点是每个组件都负责专门的职责,而模块可能还会暴露接口被其他组件调用。)
最后,贴上完整的源码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | <span> function </span> _exception_handler(<span> $severity </span>, <span> $message </span>, <span> $filepath </span>, <span> $line </span><span>)
{
</span><span> if </span> (<span> $severity </span> == <span>E_STRICT</span><span>)
{
</span><span> return </span><span>;
}
</span><span> $_error </span> =& load_class( ''Exceptions'' , ''core'' <span>);
</span><span> if </span> ((<span> $severity </span> & <span> error_reporting </span>()) == <span> $severity </span><span>)
{
</span><span> $_error </span>->show_php_error(<span> $severity </span>, <span> $message </span>, <span> $filepath </span>, <span> $line </span><span>);
}
</span><span> if </span> (config_item( ''log_threshold'' ) == 0<span>)
{
</span><span> return </span><span>;
}
</span><span> $_error </span>->log_exception(<span> $severity </span>, <span> $message </span>, <span> $filepath </span>, <span> $line </span><span>);
}</span>
|
登录后复制
12. Remove_invisiable_character
这个函数的含义非常明确,就是去除字符串中的不可见字符。这些不可见字符包括:
ASCII码表中的00-31,127(保留09,10,13,分别为tab,换行和回车换行,这些虽然不可见,但却是格式控制字符)。然后通过正则替换去除不可见字符:
1 2 3 4 | <span> do </span><span>{
</span><span> $str </span> = <span>preg_replace</span>(<span> $non_displayables </span>, '''' , <span> $str </span>, -1, <span> $count </span><span>);
}
</span><span> while </span> (<span> $count </span>);
|
登录后复制
理论上将,preg_replace会替换所有的满足正则表达式的部分,这里使用while循环的理由是:可以去除嵌套的不可见字符。如 %%0b0c。如果只执行一次替换的话,剩余的部分%0c依然是不可见字符,所以要迭代去除($count返回替换的次数)。
完整的函数源码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | <span> function </span> remove_invisible_characters(<span> $str </span>, <span> $url_encoded </span> = <span>TRUE</span><span>)
{
</span><span> $non_displayables </span> = <span> array </span><span>();
</span><span> if </span> (<span> $url_encoded </span><span>)
{
</span><span> $non_displayables </span>[] = ''/%0[0-8bcef]/'' ; <span> //</span><span> url encoded 00-08, 11, 12, 14, 15</span>
<span> $non_displayables </span>[] = ''/%1[0-9a-f]/'' ; <span> //</span><span> url encoded 16-31</span>
<span> }
</span><span> $non_displayables </span>[] = ''/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]+/S'' ; <span> //</span><span> 00-08, 11, 12, 14-31, 127</span>
<span> do </span><span>
{
</span><span> $str </span> = <span>preg_replace</span>(<span> $non_displayables </span>, '''' , <span> $str </span>, -1, <span> $count </span><span>);
}</span><span> while </span> (<span> $count </span><span>);
</span><span> return </span> <span> $str </span><span>;
}</span>
|
登录后复制
13. Html_escape
这个函数,实际上是数组中的元素递归调用htmlspecialchars。
函数实现源码:
1 2 3 4 5 6 7 8 9 10 11 | <span> function </span> html_escape(<span> $var </span><span>)
{
</span><span> if </span> (<span> is_array </span>(<span> $var </span><span>))
{
</span><span> return </span> <span> array_map </span>( ''html_escape'' , <span> $var </span><span>);
}
</span><span> else </span><span>
{
</span><span> return </span> <span>htmlspecialchars</span>(<span> $var </span>, ENT_QUOTES, config_item( ''charset'' <span>));
}
}</span>
|
登录后复制
总结一下,Common.php是在各组件加载之前定义的一系列全局函数。这些全局函数的作用是获取配置、跟踪加载class、安全性过滤等。而这么做的目的之一,就是避免组件之间的过多依赖。
参考文献:
PHP引用:http://www.cnblogs.com/xiaochaohuashengmi/archive/2011/09/10/2173092.html
HTTP协议:http://www.cnblogs.com/TankXiao/archive/2012/02/13/2342672.html
单例模式:http://cantellow.iteye.com/blog/838473

DedeCms全局函数 common.func.php 公用函数
DedeCms V5.3 全局函数 common.func.php 公用函数
获得当前的脚本URL
function GetCurUrl()
返回格林威治标准时间
function MyDate($format='Y-m-d H:i:s',$timest=0)
把全角数字转为半角
function GetAlabNum($fnum)
把含HTML的内容转为纯text
function Html2Text($str,$r=0)
把文本转HTML
function Text2Html($txt)
输出Ajax头
function AjaxHead()
中文截取2,单字节截取模式
function cn_substr($str,$slen,$startdd=0)
把标准时间转为Unix时间戳
function GetMkTime($dtime)
获得一个 0000-00-00 00:00:00 标准格式的时间
function GetDateTimeMk($mktime)
获得一个 0000-00-00 标准格式的日期
function GetDateMk($mktime)
获得用户IP
function GetIP()
获取拼音以gbk编码为准
function GetPinyin($str,$ishead=0,$isclose=1)
dedecms通用消息提示框
function ShowMsg($msg,$gourl,$onlymsg=0,$limittime=0)
保存一个cookie
function PutCookie($key,$value,$kptime=0,$pa="/")
删除一个cookie
function DropCookie($key)
获取cookie
function GetCookie($key)
获取验证码
function GetCkVdValue()
过滤前台用户输入的文本内容
// $rptype = 0 表示仅替换 html标记
// $rptype = 1 表示替换 html标记同时去除连续空白字符
// $rptype = 2 表示替换 html标记同时去除所有空白字符
// $rptype = -1 表示仅替换 html危险的标记
function HtmlReplace($str,$rptype=0)
获得某文档的所有tag
function GetTags($aid)
过滤用于搜索的字符串
function FilterSearch($keyword)
处理禁用HTML但允许换行的内容
function TrimMsg($msg)
获取单篇文档信息
function GetOneArchive($aid)
本文章网址:http://www.ppssdd.com/code/6338.html。转载请保留出处,谢谢合作!
今天关于php – Alias类方法作为全局函数和php提供三种全局变量的定义方法,分别是?的分享就到这里,希望大家有所收获,若想了解更多关于c – 在全局函数或全局函数包装的类中实现、ci - 框架中全局函数和PHP内置函数调用的先后问题?、CI框架源码阅读笔记3 全局函数Common.php、DedeCms全局函数 common.func.php 公用函数等相关知识,可以在本站进行查询。