phpcms 源码分析二:
这次是逆雪寒的common.inc.php第二部分:
<?php
/*
明天放假了.今天在写点罗.放假没空写了.要陪老婆,大家看了有什么不明白的.可以跟帖问.我懂的我会回答.谢谢
[/php] 继续:: 2007-12-21 吃完中午开始分析了点代码.时间不多.
[php]
/*
代码讲解分析: 逆雪寒. 2007 - 12 - 21
*/ /*
加载整站的配置参数文件。一般的程序都会有这个文件。做什么的呢?比如一些数据库连接地址。用户名,密码等。
需要用到的参数都定义在这个文件里面。这样以后配置变了。我们只要改动下这个文件里面的
变量值就好。是不是很方便呢。呵呵. 在这里说下 require() 这个加载函数。
require 和 include 都是用来加载其他PHP文件用的。但他们是有区别的。
require 函数:是"预解释"函数。就是程序一加载,就执行了require函数。而include 呢。
是个过程加载函数。我们可以在逻辑里比如: if 里面使用include 来动态的加载其他程序片段。而require 就不行。
*/
require PHPCMS_ROOT.'/config.inc.php'; /*
顾名思义: 这个就是加载语言包了。PHP的国际化目前做得最多的。就是直接用PHP文件来实现。
在 phpcms.lang.php 文件里面定义程序中要用到的中文信息。然后在程序一开始就加载。那里程序里面
就可以使用这个文件里面的变量和一切。那么就简单了。模板上就不需要直接写中文信息了。直接用这个文件里面定义的变量等来替换。
从而实现国际化。over!!!最好自己打开这个语言文件再加上自己思考下。就知道。原来如此简单。
*/
require PHPCMS_ROOT.'/languages/'.$CONFIG['language'].'/phpcms.lang.php'; /*
$CONFIG['rootpath'] 这个就是全局配置文件 config.inc.php 文件里面数据库信息。等全部配置信息。
在这里把他们定义为 常量。 为什么需要定义为常量呢。因为作者感觉这样写爽罗。呵呵。其实因为后面
用到这两个变量多。所以干脆定义为常量。方便使用。再多说一个技巧: $CONFIG['rootpath']
其实也可以写成 $CONFIG[rootpath] 但是最好不要这样。为什么呢。因为PHP引擎会先判断 rootpath 是不是常量。
如果不是才会认定 $CONFIG[rootpath] 是数组。 这样性能上就差了一点点了。
再多说一个技巧: 为什么程序多数都用 '' 单引号呢而不用 "" 双引号呢。因为这样效率好, "" 双引号。
php引擎还会先检查里面是否有变量,如果有就解释。而 '' 单引号不会做这一步的检查。而直接就当成字符串了。所以效率上也会有一点点影响哦。
*/
define('PHPCMS_PATH', $CONFIG['rootpath']); define('PHPCMS_CACHEDIR', $CONFIG['cachedir']); /*
$CONFIG['enablephplog'] 是否开启错误日志设置。这个设置在全局配置文件里面.config.inc.php 。
这里使用了 三目运算符 偶最喜欢用了。一些简短的逻辑判断。可以使用 ? : ; 来实现比较简洁
set_error_handler() 这个函数就大有来头了。php4里面的典型自定义程序出错后行为的一个函数。
十分好用。怎么用呢? set_error_handler(函数) 的参数也是一个函数。这个函数。反映了程序出错后行为的。
phpcms_error 函数存在 global.func.php 全局函数里面。
*/
$CONFIG['enablephplog'] ? set_error_handler('phpcms_error')
: error_reporting(E_ERROR | E_WARNING | E_PARSE); /*
就是这个。 现在我们慢慢来干掉他。呵呵 这个自定义出错信息函数默认带有四个参数。 第一个参数 $errno 是程序出错的等级。
第二参数是程序出错的界面信息。第三是出现错误的程序文件名。
第四是 第几行出现错误。第五个参数。要不要都行是当前变量状态的快照.看吧。
我们有这些信息后。想定义怎么样的错误信息给客户看都很容易了是吧?但现在我们是要生成错误日志呢?
这里phpcms 作者是动态生成一个XML文件来做错误日志的。不错不错.
他使用了 in_array() 函数来实现(因为比较简单,自己理解下)
只记录 E_USER_ERROR, E_USER_WARNING, E_USER_NOTICE 这三个级别的错误日志信息。
\n 是文本换行符 \t是制表符. 这里他使用了一个比较漂亮而不常用的函数 wddx_serialize_value ()
wddx 其实也是一种 xml 。 wddx_serialize_value() 这个函数就是把一般变量以XML格式输出。
这样我们就不用自己模拟写xml了。方便吧。呵呵 第一个参数就是: 要格式输出的变量,第二个参数是输出的xml的介绍信息.
下面就是 error_log() 函数。这个函数十分有用了。就是生成错误日志XML文件。不需要我们fopen 了。
方便吧。它还有很多功能。详细的看手册。chmod 设置日志文件的权限是 可读可写可执行。
在php5中。我习惯使用 extends Exception 来定义自己的出错信息。
所以很少用 set_error_handle(). 如果没开启日志功能。
那么 error_reporting(E_ERROR | E_WARNING | E_PARSE) 就运行了。把一般出错信息先出过来。
*/
function phpcms_error($errno, $errmsg, $filename, $linenum, $vars)
{
$filename = str_replace(PHPCMS_ROOT, '.', $filename); $filename = str_replace("\\", '/', $filename); // 把win平台的 \\ 换成 /兼容常见系统的路径 if(!defined('E_STRICT')) define('E_STRICT', 2048); $dt = date('Y-m-d H:i:s'); $errortype = array (
E_ERROR => 'Error',
E_WARNING => 'Warning',
E_PARSE => 'Parsing Error',
E_NOTICE => 'Notice',
E_CORE_ERROR => 'Core Error',
E_CORE_WARNING => 'Core Warning',
E_COMPILE_ERROR => 'Compile Error',
E_COMPILE_WARNING => 'Compile Warning',
E_USER_ERROR => 'User Error',
E_USER_WARNING => 'User Warning',
E_USER_NOTICE => 'User Notice',
E_STRICT => 'Runtime Notice'
); $user_errors = array(E_USER_ERROR, E_USER_WARNING, E_USER_NOTICE); $err = "<errorentry>\n"; $err .= "\t<datetime>" . $dt . "</datetime>\n"; $err .= "\t<errornum>" . $errno . "</errornum>\n"; $err .= "\t<errortype>" . $errortype[$errno] . "</errortype>\n"; $err .= "\t<errormsg>" . $errmsg . "</errormsg>\n"; $err .= "\t<scriptname>" . $filename . "</scriptname>\n"; $err .= "\t<scriptlinenum>" . $linenum . "</scriptlinenum>\n"; if (in_array($errno, $user_errors))
{
$err .= "\t<vartrace>"
. wddx_serialize_value($vars, "Variables")
. "</vartrace>\n";
} $err .= "</errorentry>\n\n"; echo $err; error_log($err, 3, PHPCMS_ROOT.'/data/php_error_log.xml'); chmod(PHPCMS_ROOT.'/data/php_error_log.xml', 0777);
} /*
定义session 的存储路径,session 其实 也是cookie 不过 session 是实现在服务器端的。安全但负载重点。
这样做的好处?效率很好。如果你在虚拟主机的话。大家的session cookie 都放在了php.ini里面设置的默认地方。
文件夹臃肿就会慢罗。是吧。第二就是安全罗。 记得一定要定义在 session_start()函数之前
*/
if($CONFIG['sessionsavepath']) {
session_save_path($CONFIG['sessionsavepath']);
} session_start(); /*
php5开始有时区的概念了。记得就行
*/
if(function_exists('date_default_timezone_set')) {
date_default_timezone_set($CONFIG['timezone']);
} /*
设置页面编码. php编码有: 页面编码。数据库编码。文件内码。如果三码相同就一般不会出现乱码. 文件内码是什么呢?
每个文件都有自己的内部编码。一般都用UTF8比较爽。怎么改变文件内码?你用DW也行 UE 也行。随便。
数据库编码那肯定是要指定的了。mysql5开始也有字符集模式这个最好也设置这样可以兼容更多平台。
页面编码:<meta http-equiv="Content-Type" c /> 这句就是。一般的HTML头文件都有。
那 还需要header('Content-type: text/html; charset='.$CONFIG['charset']);吗?
其实需要的。因为有些自己写的提示层呀。或是文件里没指定页面编码的。就很容易出现乱码那么我们就防范于未然。
header 一个编码过去。那就OK了。多好。
*/
header('Content-type: text/html; charset='.$CONFIG['charset']); /*
函数 getenv() 是获取环境变量。 环境变量: HTTP_CLIENT_IP 是获取客户端的IP 。
但有可能人家是通过代理来访问你的程序的呢。那么这时候就要用 环境变量:
HTTP_X_FORWARDED_FOR 了。 包括 getenv('REMOTE_ADDR') $_SERVER['REMOTE_ADDR']
是获取人家 IP的。反正碰罗。碰到那个能获取就大工告成。
*/
if(getenv('HTTP_CLIENT_IP') &&
strcasecmp(getenv('HTTP_CLIENT_IP'), 'unknown'))
{
$PHP_IP = getenv('HTTP_CLIENT_IP');
} elseif(getenv('HTTP_X_FORWARDED_FOR') &&
strcasecmp(getenv('HTTP_X_FORWARDED_FOR'), 'unknown'))
{
$PHP_IP = getenv('HTTP_X_FORWARDED_FOR');
} elseif(getenv('REMOTE_ADDR') &&
strcasecmp(getenv('REMOTE_ADDR'), 'unknown'))
{
$PHP_IP = getenv('REMOTE_ADDR');
} elseif(isset($_SERVER['REMOTE_ADDR']) &&
$_SERVER['REMOTE_ADDR'] &&
strcasecmp($_SERVER['REMOTE_ADDR'], 'unknown'))
{
$PHP_IP = $_SERVER['REMOTE_ADDR'];
} preg_match("/[\d\.]{7,15}/", $PHP_IP, $ipmatches); $PHP_IP = $ipmatches[0] ? $ipmatches[0] : 'unknown'; $PHP_TIME = time(); /*
获取当前运行的脚本名: 刚开始看是不是有点乱呢。 咋没用if else 呢。
看这样的东西。我们最好从右看到左。这样比较好明白点。$_SERVER['SCRIPT_NAME']
$_SERVER['PHP_SELF'] $_SERVER['ORIG_PATH_INFO'] 这三个服务器全局变量都是获取 当前脚本名的
。主要看服务器当前环境了。那个存在的就获取那个。
isset() 函数 十分有用。 测试一个变量是否已经定义。
注: $a= NULL ; isset($a) 这样会返回false的哦。
注意 isset 和empty 两个函数的用法。用得不好会出大问题的。自己看手册。
*/
$PHP_SELF = isset($_SERVER['PHP_SELF'])
? $_SERVER['PHP_SELF']
: (isset($_SERVER['SCRIPT_NAME'])
? $_SERVER['SCRIPT_NAME']
: $_SERVER['ORIG_PATH_INFO']); $PHP_QUERYSTRING = $_SERVER['QUERY_STRING']; $PHP_DOMAIN = $_SERVER['SERVER_NAME']; $PHP_REFERER = isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : ''; //测试服务器是否启动了ssl 连接如果是的话。就用https://安全连接来进行通行
$PHP_SCHEME = $_SERVER['SERVER_PORT'] == '443' ? 'https://' : 'http://';
$PHP_PORT = $_SERVER['SERVER_PORT'] == '80' ? '' : ':'.$_SERVER['SERVER_PORT']; $PHP_SITEURL = $PHP_SCHEME.$PHP_DOMAIN.$PHP_PORT.PHPCMS_PATH; /*
获取当前脚本的URL
*/
$PHP_URL = $PHP_SCHEME.$PHP_DOMAIN.$PHP_PORT.$PHP_SELF.($PHP_QUERYSTRING ? '?'.$PHP_QUERYSTRING : ''); /*
下面这部分相对复杂了点。但没关系。慢慢讲解. 首先缓存只针对前台.所以我们一开始就判断.这个脚本是运行在前台的而不是在后台 !defined('IN_ADMIN') 来判断.
然后呢.再看客户配置 config.inc.php文件是否开启了缓存. ==2 就是开启了. .接着开始用一系列的规则来找出缓寸的文件名和目录:
以 脚本名:xx.php和后续传递的参数 ?xx=ee&bb=jj 他两的字符串的MD5 .以这个md5串来定义出了缓存目录.和缓存文件 .
接着再判断这个缓存文件是否存在和是否没过缓存有效期.如果没有就返回这个缓存文件的名字.
然后到主菜了. 最后一个if逻辑是做什么的呢? 不知道大家有没见过 这样的网址:http://www.beihai.com/dd.php/xx-23/cc-22.html
他们其实都算是伪静态.优化URL用的.咋看起来还很象静态.爽. 但你可能想.这样的地址.我们写PHP程序的.怎么获取get 变量呢?
最后if 就是解答这个问题的. 先剥离url来获取 传递的字符串.然后 str_replace 来把 '/' '-' 替换成标准的 '&' '='
好象: http://www.beihai.com/dd.php&xx=23&cc=22
看这样你应该看明白了吧.然后用 parse_str() 函数来把xx 变 $xx=23 cc 变 $cc=22
php真是什么都给你想到了.强.看明白了吧.OK.过了.
*/
$db_file = $db_class = 'db_'.$CONFIG['database']; //如果不是在后台。 常量 IN_ADMIN 是后台标志
if(!defined('IN_ADMIN'))
{
if($CONFIG['dbiscache']) {
$db_file .= '_cache';
} // 如果在config.inc.php 里面开启了缓存
if($CONFIG['phpcache'] == '2')
{
//把脚本名和后面的get信息 md5加密,以此来生成下面的缓存目录和缓存文件
$cachefileid = md5($PHP_SELF.'?'.$PHP_QUERYSTRING); //缓存目录
$cachefiledir = PHPCMS_ROOT.'/data/phpcache/'.substr($cachefileid, 0, 2).'/'; //缓存文件: xxx.html 格式
$cachefile = $cachefiledir.$cachefileid.'.html';
if(file_exists($cachefile) &&
($PHP_TIME < @filemtime($cachefile) + $CONFIG['phpcacheexpires']))
{
//如果缓存文件存在和缓存没有过期效,那么就返回缓存文件名
require $cachefile; exit;
}
} //获取传递过来的变量。有什么用的呢?请看下面解释
if($PHP_QUERYSTRING &&
preg_match("/^(.*)\.(htm|html|shtm|shtml)$/", $PHP_QUERYSTRING, $urlvar))
{
parse_str(str_replace(array('/', '-', ' '), array('&', '=', ''), $urlvar[1]));
}
} /*
恩.终于把common.inc.php 这个文件大概讲解完了. 这个文件里面包含了很多东西.都是些挺不错的思想.大家应该好好学习.这样我们写出来的PHP程序会更加强壮.
:lol: ,偶现在晚上都在边陪老婆边看电影边弄linux 的C,还是学习 阶段 所以时间有点紧.白天在公司挤点时间出来分析代码罗. 对于phpcms 我也是第一次接触.以前没装过也没用过.现在也没详细用过.所以我看到代码讲什么我就讲什么.没具体讲PHPCMS的应用等.希望理解. 如果我分析代码分析得不合理.请指出.共同进步学习.谢谢
*/
?>
phpcms 源码分析二:的更多相关文章
- Fresco 源码分析(二) Fresco客户端与服务端交互(1) 解决遗留的Q1问题
4.2 Fresco客户端与服务端的交互(一) 解决Q1问题 从这篇博客开始,我们开始讨论客户端与服务端是如何交互的,这个交互的入口,我们从Q1问题入手(博客按照这样的问题入手,是因为当时我也是从这里 ...
- 框架-springmvc源码分析(二)
框架-springmvc源码分析(二) 参考: http://www.cnblogs.com/leftthen/p/5207787.html http://www.cnblogs.com/leftth ...
- Tomcat源码分析二:先看看Tomcat的整体架构
Tomcat源码分析二:先看看Tomcat的整体架构 Tomcat架构图 我们先来看一张比较经典的Tomcat架构图: 从这张图中,我们可以看出Tomcat中含有Server.Service.Conn ...
- 十、Spring之BeanFactory源码分析(二)
Spring之BeanFactory源码分析(二) 前言 在前面我们简单的分析了BeanFactory的结构,ListableBeanFactory,HierarchicalBeanFactory,A ...
- Vue源码分析(二) : Vue实例挂载
Vue源码分析(二) : Vue实例挂载 author: @TiffanysBear 实例挂载主要是 $mount 方法的实现,在 src/platforms/web/entry-runtime-wi ...
- 多线程之美8一 AbstractQueuedSynchronizer源码分析<二>
目录 AQS的源码分析 该篇主要分析AQS的ConditionObject,是AQS的内部类,实现等待通知机制. 1.条件队列 条件队列与AQS中的同步队列有所不同,结构图如下: 两者区别: 1.链表 ...
- ABP源码分析二:ABP中配置的注册和初始化
一般来说,ASP.NET Web应用程序的第一个执行的方法是Global.asax下定义的Start方法.执行这个方法前HttpApplication 实例必须存在,也就是说其构造函数的执行必然是完成 ...
- spring源码分析(二)Aop
创建日期:2016.08.19 修改日期:2016.08.20-2016.08.21 交流QQ:992591601 参考资料:<spring源码深度解析>.<spring技术内幕&g ...
- ConcurrenHashMap源码分析(二)
本篇博客的目录: 一:put方法源码 二:get方法源码 三:rehash的过程 四:总结 一:put方法的源码 首先,我们来看一下segment内部类中put方法的源码,这个方法它是segment片 ...
随机推荐
- Android 图片处理方法
//压缩图片大小 public static Bitmap compressImage(Bitmap image) { ByteArrayOutputStream baos = new ByteArr ...
- 【Python Network】权威域名服务器级联查询
如果PyDNS库,跳过本地名称服务器,直接向权威名称服务器查询.如baidu.com查询.com域名服务器,并从各个域名服务器中查询下一即域名,并输出相关信息. #! /usr/bin/env pyt ...
- Dom4j的使用(全而好的文章)
版权声明: 本文由冰云完成,首发于CSDN,未经许可,不得使用于任何商业用途. 文中代码部分引用自DOM4J文档. 欢迎转载,但请保持文章及版权声明完整. 如需联络请发邮件:icecloud( ...
- hadoop2.2编程:用ruby跑hadoop的完整实例
Becareful! All nodes include need to install ruby! #!/usr/bin/ruby # Ruby code for map.rb ARGF.eac ...
- CMD命令窗口复制与粘贴
cmd命令提示符窗口中快速复制粘贴的方法常规方法 在“命令提 示符”窗口的任意一处,点击右键,在弹出的快捷菜单中选择“标记”命令. 此时在窗口的左上角处闪烁着一个长方块状的光标,将鼠标移动到希望复制的 ...
- Webform——购物车
购物车主要实现的功能: ①在主页面可以将所有商品显示出来,包括价格,库存. ②点击购买可以累加产品,如果是同一种产品,只会累加每种产品的数量. ③查看购物车,可以查看明细,包括所购物品的名称,价格,数 ...
- .NET程序内,访问私有或者保护成员的技巧
如果是C++,我们可以计算对象内成员的位置,然后偏移指针以访问类型的所有非公开成员.但是.NET对象完全受GC管理,地址根本无法得到,并且也无法通过指针调用方法. 当然... 这是一种很不值得推荐的技 ...
- 【HTML】Intermediate4:Tables:rowspan and colspan
1.</th> header cell As with td elements,these must be enclosed inside tr elements 2.</tr co ...
- 增加eclipse启动的Tomcat内存的方法 tomcat内存增加
增加eclipse启动的Tomcat内存的方法 Tomcat一般默认情况下最大最优内存设置为2G 这种情况下,修改Tomcat\bin\catalina.bat,添加如下内容 set JAVA_OPT ...
- wuzhicms查找:当前页面使用的哪个文件
要查看这个地址的模版.http://www.wuzhicms.com/item-34-2-1.html 首先,我们的这个地址需要是动态的.而不是生成的静态地址. 打开文件: /www/configs/ ...