Chinaunix首页 | 论坛 | 博客
  • 博客访问: 198660
  • 博文数量: 264
  • 博客积分: 6010
  • 博客等级: 准将
  • 技术积分: 2740
  • 用 户 组: 普通用户
  • 注册时间: 2009-06-03 13:25
文章分类

全部博文(264)

文章存档

2011年(1)

2009年(263)

我的朋友

分类:

2009-06-03 15:13:12

首先我对 PHPCMS 的 头程序文件开始讲解 : include/common.inc.php   这个文件是程序启动的核心文件.
php

/**

代码讲解分析: 逆雪寒. 2007 - 12 - 20 

*/

$mtime explode(' 'microtime());  

$phpcms_starttime $mtime[1] + $mtime[0];

/**

计算脚本开始运行的时间。很常见的写法。最后结算还在程序运行的终点位置。讲到了在给各位说。

*/

unset($LANG$_REQUEST$HTTP_ENV_VARS$HTTP_POST_VARS$HTTP_GET_VARS$HTTP_POST_FILES$HTTP_COOKIE_VARS);

/**

把  $HTTP_ENV_VARS $HTTP_POST_VARS 全局变量设置为 NULL  因为php4.1.0以上默认以 $_POST 来替代。unset后防止程序运行在低版本会出现安全等问题。比如变量注入

*/

set_magic_quotes_runtime(0); 

//地球人都知道。关了字符窜入库自动转意 比如  my name is on'x     转成  my name is on \'x  为了最大的程序性能所以我们关掉吧~哈哈

define('IN_PHPCMS'TRUE); 

/**

程序入口标记。为什么需要这个东西呢。就好比你进一个小区,保安大哥哥肯定要你签字或是挂个鸟牌证明你是从正门进来的。

防止你翻墙进入去偷东西搞破坏。这个入口标记也有这个功能。 在这里定义了一个常量 IN_PHPCMS 为 TRUE ,然后我在其他程序文件里面检查这个标记。如果不存在或不为真,

那么就基本可以肯定你这个家伙是个小偷来的。 人可能翻墙进入。但程序怎么翻墙呢。只要在php.ini文件里面激 活 allow_url_fopen选项,include() 就可以包含 URL 地址了。你想下如果你有个 放密码的PHP文件。如果给人家 include 了以后。你怕不怕。

*/

define('PHPCMS_ROOT'str_replace("\\"'/'substr(dirname(__FILE__), 0, -8)));

/**

为了程序产品的跨平台。自动获取程序的安装目录路径 ,定义为 PHPCMS_ROOT 常量。方便以后程序使用。建议大家都这样做哦

*/

require PHPCMS_ROOT.'/include/global.func.php';  

/**

包含 全局函数 global.func.php 文件。里面放了些程序全局都有需要用的函数.大家看到了吧。  常量 PHPCMS_ROOT 已经发挥作用。 这样程序给人家发布到了 二级目录下。也不需要人家手动改整站根目录路径了。

自己好好理解下。。。。。

*/

$search_arr = array("/ union /i","/ select /i","/ update /i","/ outfile /i","/ or /i");

/**

("/ union /i")  这个是正则的写法?不懂正则的自己百度找教程来学。 这里不详细说了

*/

$replace_arr = array(' union ',' select ',' update ',' outfile ',' or ');

/**

看这个意思很明了。 union :连接两条SQL语句。 outfile : 主要用来导出数据库资料到其他介质上。

干啥字要定义这两个变量呢? 在 global.func.php 文件(前面已经加载)里面有个函数 strip_sql() 各位可以看下。 

function strip_sql($string)

{

global $search_arr,$replace_arr;

return is_array($string) ? array_map('strip_sql', $string) : preg_replace($search_arr, $replace_arr, $string);

}

函数里面定义了这两个变量为 global全局变量。 那么函数里就可以直接使用了。  先讲解下这个函数吧。 顾名思义这个函数是过滤字符窜里面的SQL语句使得关键的SQL语句单词失效。

主要过滤那些SQL语句呢。 主要是这几个关键字: union  select  update outfile  or 等。因为这几个SQL字是极度容易在$_GET传输中给截注.

这个函数写得实在精妙。  is_array 来判断 $string 是否为数组。如果 是  就 array_map() 函数来递归过滤 $string数组里面的每一个单元. 每个单元是一个字符窜吧?

当递归调用 strip_sql() 以后 is_array()判断 $string 肯定为假了,因为$string已经不是数组而是字符窜。所以 执行 preg_replace()函数。这个函数很好理解了。就是替换了。

*/

$_POST strip_sql($_POST);

$_GET strip_sql($_GET);

$_COOKIE strip_sql($_COOKIE);

/**

使用strip_sql()函数来过滤 $_POST  $_GET   $_COOKIE;

一般不是开源的站。很少过SQL关键字过滤。不过这个也是冒很大风险的。

*/

unset($search_arr$replace_arr);

/**

unset 使用过但以后不需要的变量。这个是很好的习惯。第一不会浪费内存。如果变量存了大量的数据字节,而后你的程序是一直不需要用的。那么

就会很浪费内存。拉底程序性能 . 哈哈。真很书面。反正是好习惯我们都要学习的拉。

*/

$magic_quotes_gpc get_magic_quotes_gpc(); // get_magic_quotes_gpc()检测gpc是否系统自动转意。 gpc 是什么呢? GET POST COOKIE 来来去去就这几个东西罗。会返回 真或假

if(!$magic_quotes_gpc)

{

$_POST new_addslashes($_POST);

$_GET new_addslashes($_GET);

}

/**

判断一下系统是否打开了自动对gpc进行转意这个选择。如果是的话,就不需要我们自动转意了。如果不是那么还是要老百姓的手段。自己动手丰衣足食。

来看下也是在global.func.php 文件里面定义的这个函数: 其实是一个封装好的php的 addslashes() 函数的函数。PHP都自己有了为什么还要自己封装成函数呢?

理由很简单。为了以后的扩展更改容易罗。如果我们一开始就全部用 addslashes() 这个函数来对 ' 进行转意的话。那么以后随着程序的发展。我可能想多过滤个 ^ * ( )之类的

那如何是好呢?所以为了以后孩子的成长。我们还是最好封起来吧。 记住:以后有可能会边的东西。最好都封装成模块。函数 。类。 这样程序的灵活度就上去了。

function new_addslashes($string)

{

if(!is_array($string)) return addslashes($string);

foreach($string as $key => $val) $string[$key] = new_addslashes($val);

return $string;

}

这个函数也是写得贼好。也是同时考虑过滤 字符窜或数组,也是使用了 传归。看下就应该明白了吧。这个不用说了。我们要学下这个思路这个方法方式哦。这样才能进步。

哈哈。我们要懂模仿。

*/

@extract($_POSTEXTR_OVERWRITE);

@
extract($_GETEXTR_OVERWRITE);

/**

嘿。 extract 前面加个 @鸡蛋做什么呢??抑制错误的。还不懂的话。自己百度了。

为什么用extract()函数呢.  平时我们程序 是不是要常使用 $_POST  $_GET来获取传递的变量呀。是不是感觉贼麻烦呀。

比如 $_POST['xx']  这样接受是挺好。但写多了很麻烦是吧。我是感觉麻烦。我现在想直接就 $xx就可以获取传递过来的东西。那怎么办呢。

就用了 extract()函数来实现这么一个技巧。 这个技巧在discuz 论坛上也有应用。

*/

unset($_POST$_GET);

/**

unset() 好处不用说了吧。 释放 $_POST $_GET 数组 ,因为已经不需要他们了。

*/

?>



明天放假了.今天在写点罗.放假没空写了.要陪老婆,大家看了有什么不明白的.可以跟帖问.我懂的我会回答.谢谢
复制代码
继续::

2007-12-21

吃完中午开始分析了点代码.时间不多.
/**

代码讲解分析: 逆雪寒. 2007 - 12 - 21 

*/

require PHPCMS_ROOT.'/config.inc.php';

/**

加栽整站的配置参数文件。一般的程序都会有这个文件。做什么的呢?比如一些数据库连接地址。用户名,密码等。需要用到的参数都定义在这个文件里面。这样以后配置变了。我们只要改动下这个文件里面的

变量值就好。是不是很方便呢。呵呵.  在这里说下 require() 这个加载函数。 require 和 include 都是用来加载其 他PHP文件用的。但他们是有区别的。 require 函数:是"预解释"函数。就是程序一加载,就执行了require函数。而 include  呢。是个过程加载函数。我们可以在逻辑里比如: if 里面使用include 来动态的加载其他程序片段。而require 就不 行。*/

require PHPCMS_ROOT.'/languages/'.$CONFIG['language'].'/phpcms.lang.php';

/**

顾名思义: 这个就是加载语言包了。PHP的国际化目前做得最多的。就是直接用PHP文件来实现。 在 phpcms.lang.php 文件里面定义程序中要用到的中文信息。然后在程序一开始就加载。那里程序里面

就可以使用这个文件里面的变量和一切。那么就简单了。模板上就不需要直接写中文信息了。直接用这个文件里面定义的变量等来替换。从而实现国际化。over!!!最好自己打开这个语言文件再加上自己思考下。就知道。原来如此简单。

*/

define('PHPCMS_PATH'$CONFIG['rootpath']);

define('PHPCMS_CACHEDIR'$CONFIG['cachedir']);

/**

$CONFIG['rootpath']  这个就是全局配置文件 config.inc.php 文件里面数据库信息。等全部配置信息。在这里把他们定义为 常量。 为什么需要定义为常量呢。因为作者感觉这样写爽罗。呵呵。其实因为后面

用到这两个变量多。所以干脆定义为常量。方便使用。再多说一个技巧: $CONFIG['rootpath']  其实也可以写成  $CONFIG[rootpath]  但是最好不要这样。为什么呢。因为PHP引擎会先判断  rootpath 是不是常量。如果不是才会认定      $CONFIG[rootpath]  是数组。 这样性能上就差了一点点了。 再多说一个技巧: 为什么程序多数都用 '' 单引号呢而不用 "" 双引号呢。因为这样效率好, "" 双引号。

php引擎还会先检查里面是否有变量,如果有就解释。而 '' 单引号不会做这一步的检查。而直接就当成字符窜了。所以效率上也会有一点点影响哦。

*/

$CONFIG['enablephplog'] ? set_error_handler('phpcms_error') : error_reporting(E_ERROR E_WARNING E_PARSE);

/**

$CONFIG['enablephplog']  是否开启错误日志设置。这个设置在全局配置文件里面.config.inc.php 。 这里使用了 三目运算符   偶最喜欢用了。一些简短的逻辑判断。可以使用 ? : ; 来实现比较简洁

set_error_handler() 这个函数就大有来头了。php4里面的典型自定义程序出错后行为的一个函数。十分好用。怎么用呢? set_error_handler(函数) 的参数也是一个函数。这个函数。反映了程序出错后行为的。

phpcms_error 函数存在 global.func.php 全局函数里面。



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 = "\n";

$err .= "\t" . $dt . "\n";

$err .= "\t" . $errno . "\n";

$err .= "\t" . $errortype[$errno] . "\n";

$err .= "\t" . $errmsg . "\n";

$err .= "\t" . $filename . "\n";

$err .= "\t" . $linenum . "\n";

if (in_array($errno, $user_errors))

{

    $err .= "\t" . wddx_serialize_value($vars, "Variables") . "\n";

}

$err .= "
\n\n";

echo $err;

error_log($err, 3, PHPCMS_ROOT.'/data/php_error_log.xml');

chmod(PHPCMS_ROOT.'/data/php_error_log.xml', 0777);

}

就是这个鸟蛋。 现在我们慢慢来干掉他。呵呵   这个自定义出错信息函数默认带有四个参数。 第一个参数 $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) 就运行了。把一般出错信息先出过来。

*/

if($CONFIG['sessionsavepath']) session_save_path($CONFIG['sessionsavepath']);

/**

定义session 的存储路径,session 其实 也是cookie 不过 session 是实现在服务器端的。安全但负载重点。这样做的好处?效率很好。如果你在虚拟主机的话。大家的session cookie 都放在了php.ini里面设置的默认地方。文件夹臃肿就会慢罗。是吧。第二就是安全罗。 记得一定要定义在 session_start()函数之前

*/

session_start();

if(
function_exists('date_default_timezone_set')) date_default_timezone_set($CONFIG['timezone']);

/**

php5开始有时区的概念了。记得就行

*/

header('Content-type: text/html; charset='.$CONFIG['charset']);

/**

设置页面编码.  php编码有: 页面编码。数据库编码。文件内码。如果三码相同就一般不会出现乱码. 文件内码是什么呢?每个文件都有自己的内部编码。一般都用UTF8比较爽。怎么改变文件内码?你用DW也行  UE 也行。随便。 数据库编码那肯定是要指定的了。mysql5开始也有字符集模式这个最好也设置这样可以兼容更多平台。

页面编码:  这句就是。一般的HTML头文件都有。 那 还需要header('Content-type: text/html; charset='.$CONFIG['charset']);吗?   其实需要的。因为有些自己写的提示层呀。或是文件里没指定页面编码的。就很容易出现乱码那么我们就防范于未然。 header 一个编码过去。那就OK 了。多好。

*/

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';

/**

函数 getenv() 是获取环境变量。  环境变量: HTTP_CLIENT_IP 是获取客户端的IP 。但有可能人家是通过代理来访问你的程序的呢。那么这时候就要用 环境变量:

HTTP_X_FORWARDED_FOR  了。 包括  getenv('REMOTE_ADDR')  $_SERVER['REMOTE_ADDR']  都是获取人家  IP的。反正碰罗。碰到那个能获取就大工告成。

*/

$PHP_TIME time();

$PHP_SELF = isset($_SERVER['PHP_SELF']) ? $_SERVER['PHP_SELF'] : (isset($_SERVER['SCRIPT_NAME']) ? $_SERVER['SCRIPT_NAME'] : $_SERVER['ORIG_PATH_INFO']);

/**

获取当前运行的脚本名:  刚开始看是不是有点乱呢。 咋没用if else 呢。 看这样的东西。我们最好从右看到左。这样比较好明白 点。$_SERVER['SCRIPT_NAME'] $_SERVER['PHP_SELF']  $_SERVER['ORIG_PATH_INFO'] 这 三个服务器全局变量都是获取 当前脚本名的。主要看服务器当前环境了。那个存在的就获取那个。

isset() 函数 十分有用。 测试一个变量是否已经定义。 注: $a= NULL ; isset($a) 这样会返回false的哦。 注意 isset 和empty 两个函数的用法。用得不好会出大问题的。自己看手册。  

*/

$PHP_QUERYSTRING $_SERVER['QUERY_STRING'];

$PHP_DOMAIN $_SERVER['SERVER_NAME'];

$PHP_REFERER = isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : '';

$PHP_SCHEME $_SERVER['SERVER_PORT'] == '443' 'https://' 'http://'; //测试服务器是否启动了ssl 连接如果是的话。就用https://安全连接来进行通行

$PHP_PORT $_SERVER['SERVER_PORT'] == '80' '' ':'.$_SERVER['SERVER_PORT'];

$PHP_SITEURL $PHP_SCHEME.$PHP_DOMAIN.$PHP_PORT.PHPCMS_PATH;

$PHP_URL $PHP_SCHEME.$PHP_DOMAIN.$PHP_PORT.$PHP_SELF.($PHP_QUERYSTRING '?'.$PHP_QUERYSTRING '');

/**

获取当前脚本的URL

*/

$db_file $db_class 'db_'.$CONFIG['database'];

if(!
defined('IN_ADMIN')) //如果不是在后台。 常量 IN_ADMIN 是后台标志

{

if(
$CONFIG['dbiscache']) $db_file .= '_cache';

if(
$CONFIG['phpcache'] == '2') // 如果在config.inc.php 里面开启了缓存

{

  
$cachefileid md5($PHP_SELF.'?'.$PHP_QUERYSTRING); //把脚本名和后面的get信息 md5加密,以此来生成下面的缓存目录和缓存文件

  
$cachefiledir PHPCMS_ROOT.'/data/phpcache/'.substr($cachefileid02).'/'; //缓存目录

  
$cachefile $cachefiledir.$cachefileid.'.html'; //缓存文件: xxx.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]));

}

}

/**

上面这部分相对复杂了点。但没关系。慢慢讲解. 首先缓存只针对前台.所以我们一开始就判断.这个脚本是运行在前台的而不是在后台 !defined('IN_ADMIN') 来判断.

然后呢.再看客户配置 config.inc.php文件是否开启了缓存. ==2 就是开启了. .接着开始用一系列的规则来找出缓寸的文件名 和目录: 以 脚本名:xx.php和后续传递的参数 ?xx=ee&bb=jj 他两的字符窜的MD5 .以这个md5窜来定义出了缓存目录. 和缓存文件 .接着再判断这个缓存文件是否存在和是否没过缓存有效期.如果没有就返回这个缓存文件的名字.

然后到主菜了. 最后一个if逻辑是做什么的呢? 不知道大家有没见过 这样的网址:[url= /dd.php/xx]/dd.php/xx[/url]-23/cc-22.html  他们其实都算是伪 静态.优化URL用的.咋看起来还很象静态.爽. 但你可能想.这样的地址.我们写PHP程序的.怎么获取get 变量呢?  最后if 就是解答这个问 题的. 先剥离url来获取  传递的字符窜.然后 str_replace 来把 '/'  '-'  替换成标准的  '&' '='  好 象:   [url=/dd.php&xx=23&cc=22]/dd.php&xx=23&cc=22[/url]   看这样你应该看明白了吧.然后用 parse_str() 函数来把xx 变 $xx=23   cc 变 $cc=22    php真是什么都给 你想到了.强.看明白了吧.OK.过了.

*/


复制代码
恩.终于把common.inc.php 这个文件大概讲解完了. 这个文件里面包含了很多东西.都是些挺不错的思想.大家应该好好学习.这样我们写出来的PHP程序会更加强壮.
,偶现在晚上都在边陪老婆边看电影边弄linux 的C,还是学习 阶段  所以时间有点紧.白天在公司挤点时间出来分析代码罗.

对于phpcms 我也是第一次接触.以前没装过也没用过.现在也没详细用过.所以我看到代码讲什么我就讲什么.没具体讲PHPCMS的应用等.希望理解.

如果我分析代码分析得不合理.请指出.功能进步学习.谢谢require PHPCMS_ROOT.'/include/'.$db_file.'.class.php'; // 包含数据库操作类,下章详说

require PHPCMS_ROOT.'/include/tag.func.php' //遇到再说

require PHPCMS_ROOT.'/include/extension.inc.php'; //遇到再说

$db = new $db_class;   // 实例化数据库类

$db->connect($CONFIG['dbhost'], $CONFIG['dbuser'], $CONFIG['dbpw'], $CONFIG['dbname'], $CONFIG['pconnect']); //连接数据库@_@

$db->iscache $CONFIG['dbiscache']; //是否开启SQL缓存

$db->expires $CONFIG['dbexpires']; //缓存时间

if(!cache_read('table.php'))

{

require_once 
PHPCMS_ROOT.'/include/cache.func.php';

    
cache_all(); //生成所有缓存

}

/**

cache_read() 函数 读缓存文件函数存在 global.func.php 里面.上菜先:

function cache_read($file, $mode = 'i')

{

$cachefile = PHPCMS_CACHEDIR.$file;

if(!file_exists($cachefile)) return array();

return $mode == 'i' ? include $cachefile : file_get_contents($cachefile);

}

就这么简单.文本缓存,在一些大的开源的PHP项目中经常见到.主要是为了减轻数据库的负荷的. 比如在程序启动文件里面,就把一些后台配置的常 用信息缓存到php文件里面.然后在以后的程序就可以直接使用而不用每次都访问数据库了.但对经常要更新的信息.最好不要用文本缓存这形式,因为PHP文 件内置的文件锁flock()不是很好用.大系统中多用户同时写访问的时候有可能会把缓存文件破坏.大系统建议使用 memcached   mysql5.1 分区  mysql 主从 来实现负载均衡 @=@ 废话太多了. 这个函数很简单.自己看下就明白了.如果缓存和模式变 量 $mode 是否为 i 是就include 不是就 把文件以字符窜形式读到内存中.

如果 cache_read()找不到缓存文件'table.php'就会返回false,那么就 加栽 cache.func.php  文件.它里面是些创建缓存的一些函数. 然后呢执行 cache_all()函数生成所有的常用信息缓存.

关于phpcms 的缓存更详细包括生成原理.打算在弄完启动文件common.inc.php 后再开篇写个详细的.  

*/

$CACHE cache_read('common.php'); 

/**

加载 common.php 缓存文件里面的变量(数据) 这样我们不用从数据库读了每次.是吧

common.php 文件里面是什么来的呢?上菜:


return array (

  'module' => 

  array (

    'phpcms' => 

    array (

      'module' => 'phpcms',

      'name' => 'phpcms',

      'iscore' => '1',

      'iscopy' => '0',

      'isshare' => '0',

      'moduledir' => '',

      'linkurl' => '',

    ),

    'member' => 

    array (

      'module' => 'member',

      'name' => '会员',

      'iscore' => '1',

      'iscopy' => '0',

      'isshare' => '0',

      'moduledir' => 'member',

      'linkurl' => '/phpcms/member/',

    ),

    'article' => 

    array (

      'module' => 'article',

      'name' => '文章',

      'iscore' => '0',

      'iscopy' => '1',

      'isshare' => '0',

      'moduledir' => 'article',

      'linkurl' => '',

    )

?>

看到了吧.这个就是全部从数据库里面生成的文本缓存信息.我们不用每次都连接数据库读数据库.而只要访问里面的数组就可以得到一些配置信息.

这个就是文本缓存的作用了,至于怎么会生成这个文本缓存文件的.我会另外开一篇来介绍。

*/

$MODULE $CACHE['module']; //缓存中的数据

$CHANNEL $CACHE['channel'];

$PHPCMS $CACHE['phpcms'];

$FIELD $CACHE['field'];

unset(
$CACHE$ipmatches$CONFIG['timezone'], $CONFIG['cachedir'], $CONFIG['dbhost'], $CONFIG['dbuser'], $CONFIG['dbpw'], $CONFIG['pconnect'], $CONFIG['dbiscache'], $CONFIG['dbexpires']);

/**

unset 掉不需要用的变量.

*/

if($PHPCMS['enablebanip'] && ip_banned($PHP_IP)) showmessage($LANG['administrator_banned_this_IP']);

/**

$PHPCMS['enablebanip'] 是什么.不用说应该知道了吧.这个就是后台里面设置是否开启过滤IP访问的功能.(因为我没用过 phpcms,我是按照代码猜的,不对的请指出)从这里就看出了文本缓存也有他的作用的。 ip_banned()函数是什么呢.上菜再说:

function ip_banned($ip)

{

global $PHP_TIME; //前面定义过的.当前的时间

$ipbanneds = cache_read('banip.php');

if(!is_array($ipbanneds)) return FALSE;

foreach($ipbanneds as $v)

{

  if($v['overtime'] < $PHP_TIME) return FALSE;

  if($ip == $v['ip'] || preg_match("/^".str_replace('.', '[.]', $v['ip'])."$/", $ip)) return TRUE;

}

}

里面也用到了 cache_read() 这个函数,还是读banip.php 这个文件.banip.php这个文件里面存着你在后台甚至的要过滤的IP列表.

里面的逻辑比较简单.自己消化下了.不明白跟帖问

showmessage() 函数是提示出错信息封装好的一个函数. 国家化的 $LANG['administrator_banned_this_IP']这个看到了吧.这个就是读语言包里面的.这样我们就可以出好多个语言版本的程序拉.

*/

$TEMP $MOD $CHA $CATEGORY $CAT = array();

$ftp $enableftp $tags $html 0;

/**

初始化变量.这个是好习惯我们要模仿.

*/

if(!isset($mod))

{

$mod 'phpcms'//phpcms 是默认加载的模块

}

elseif(
$mod != 'phpcms')

{

isset(
$MODULE[$mod]) or exit($LANG['module_not_exists']); // 从缓存中读加载的模块是否开启

/**

这个写法,我十分喜欢,平时也用.   xx && dd ; xx and dd  ;与运算要同时两边都为真整个公式才为 真,就是利用这个原理. ; xx || dd ; xx or dd  或运算只要一个条件满足就不会执行下一个条件而继续执行下去. 这样写是不是很 酷.  

*/

$MOD cache_read($mod.'_setting.php'); //开始加载这个模块的一些常用配置数值。 phpcms 对应的每个模块都有一个缓存配置文件。@@ 怪不得速度那么快

@include PHPCMS_ROOT.'/languages/'.(defined('IN_ADMIN') ? $CONFIG['adminlanguage'].'/'.$mod.'_admin.lang.php' $CONFIG['language'].'/'.$mod.'.lang.php');

/**

加载想对应的模块语言包.

*/

}

if(!isset(
$forward)) $forward $PHP_REFERER//记录前一个URL地址。估计以后下面程序有需要用这个变量

$dosubmit = isset($dosubmit) ? 0//记录是否有表单提交过.也是以后有用

$channelid = isset($channelid) ? intval($channelid) : 0//记录当前频道的id  如果$channelid 没有 isset 那么就为 0. intval() 十分有用。数字和数字的比较加减速度会快很多。记得哦

$skindir PHPCMS_PATH.'templates/'.$CONFIG['defaulttemplate'].'/skins/'.$CONFIG['defaultskin']; //加载默认phpcms皮肤

if($PHPCMS['enablegzip'] && function_exists('ob_gzhandler'))

{

(
$CONFIG['phpcache'] || defined('SHOWJS')) ? ob_start() : ob_start('ob_gzhandler');

}

else

{

$PHPCMS['enablegzip'] = 0;

ob_start();

}

/**

$PHPCMS['enablegzip']   这个变量就是存在于 phpcms_setting.php 文件里。上面已经说过了。每个模块都有相对应的模块配置缓存文件(是从数据库copy过来的信息) 这个变量标致 是否开启 压缩传输。

压缩传输,听名字就知道。就是把数据按照一定的算法压缩小罗。然后再传送到客户端。这样就可以在有限的带宽中传输更大的数据拉。当然速度快了不 少。压缩的数据到了你的浏览器,它就自动解压缩,老版本的一些浏览器不支持解压缩哦。不过现在还有谁用很久的浏览器呢。用法很简单的:看上面就知道:

首先判断下,看客户老大们是否在后台选择了这个模块的压缩传输(如果是的话。自然的已经加载到了相对应的文本缓存文件里面拉) 标 致:$PHPCMS['enablegzip']  和 判断 回调函数 ob_gzhandler 是否开启,  ob_gzhandler 其实不算 是个函数。看手册说明。 就这么简单。它只是一个专门给 ob_start() 做回调使用的一个参数函数。详细请看下手册。别偷懒哦,在程序开头 ob_start('ob_gzhandler')就算是开始压缩传输了;判断完了 如果为真。就继续下面的代码:



($CONFIG['phpcache'] || defined('SHOWJS')) ? ob_start() : ob_start('ob_gzhandler');

看代码phpcms 是这样的: 如果用户在后台开启了压缩传输。而用户又开启了 页面缓存。那么就默认不使用压缩传输了。我也不知道为什么这样设计。我测试了下。后台开启压缩传输。又同时又使用页面缓存。没发现有什么问题。@@ 

如果没开启压缩传输,那么我们就ob_start(); 使用session 之前必须要 ob_start() ; 而且在ob_start() 之前不能有任何的 头文件发送和输出。比如:echo header等要不会出错的哦。

*/

$_userid 0

$_username '';

$_groupid 3;

$_arrgroupid = array();

$phpcms_auth getcookie('auth');

/**

$_userid,$_username,$_groupid  这几个记录用户信息的变量初始化,不初始化危险就太大了。@@ 如果给人家$_GET一个 _userid 变量过来。那么就会把我们这个变量覆盖。但是我们如果给这几个变量一个值,

那么按照就近原则。就算你GET个变量过来。你也一样改不了我原来的变量值。大家好好自己想下。就会明白了。

getcookie() 这个自定义函数在 global.func.php文件里定义的。上菜:

function getcookie($var)

{

global $CONFIG;

$var = $CONFIG['cookiepre'].$var;

return isset($_COOKIE[$var]) ? $_COOKIE[$var] : FALSE;

}

这个函数用来提取我们设置的cookie 值. $CONFIG['cookiepre']  在 config.inc.php 文件里面设置,cookie 名的前缀.  函数很简单。一看就明白不说了。

*/

if($phpcms_auth)

{

$phpcms_auth_key md5($PHPCMS['authkey'].$_SERVER['HTTP_USER_AGENT']);

list(
$_userid$_password$_answer) = $phpcms_auth explode("\t"phpcms_auth($phpcms_auth'DECODE')) : array(0'''');

/**

  list() = array(); 用户大家自己试下。 意会下

  phpcms_auth()  是加密和解密 函数,  因为cookie 是存在于客户端。十分危险呀。 你看连用户的密码也存在cookie 不加密能行吗。但是呢加密后又要能解密。因为用户名和用户密码我们往下操作要

  获取的。 这个函数存在于 global.func.php 文件里面。大家想了解这个算法的自己去看下吧。挺简单的。 其实就是围绕着  $phpcms_auth_key  这个变量来加密解密和discuz 的cookie 机制差不。

  $phpcms_auth_key = md5($PHPCMS['authkey'].$_SERVER['HTTP_USER_AGENT']);  看$PHPCMS['authkey'], 估计后台有个 cookie 加密值让你填,然后以这个值和 $_SERVER['HTTP_USER_AGENT'](系统信息)

*/

$_userid intval($_userid);

if(
$_userid 0$_userid 0//读出的cookie 的用户id 如果是 小于0 

if($_userid//如果 cookie 保存的这个uid 存在,那么开始按照这个ID来查数据库用户表 来取出用户信息

{

  
$memberinfo $db->get_one("SELECT username,password,groupid,arrgroupid,email,chargetype,begindate,enddate,money,point,credit,newmessages FROM ".TABLE_MEMBER." WHERE userid=$_userid LIMIT 0,1");

  
/**

  phpcms 封装好的数据库类,下篇开讲这个大家就大概看行了。  大家看下 select  sql语句。 也可以学习下。 首先最好不要使用 select * from xx  的 * 形式,除非你想获取所有字段的记录。只罗列你要的字段。这样在数据量大的查询中。速度明显上去。    常量: TABLE_MEMBER  定义了表名。这样做有什么好处呢?想都知道了,为了以后变更表名方便而定义为常量。这个东西那里来的。估计在一个文件里面定义好的。遇到了再讲吧懒得找了。

  */

  
if($memberinfo && $memberinfo['password'] == $_password)  //用查询出来的密码和 cookie 中存在的密码想对比.为了在效率: 在比较前 先判断查询是否成功先。很多phper往往忽略。

  
{

   if(
$memberinfo['groupid'] == 2)  //如果用户属于的组的ID 为 2  那么这个用户是被管理员禁止访问的了。

   
{

                
mkcookie('auth'''); // 清除cookie 

    
showmessage($LANG['userid_banned_by_administrator']); //提示出错菜单

   
}

   @
extract($memberinfoEXTR_PREFIX_ALL''); //又来这招,应该明白了吧各位老大:把字段 变成 我们能直接使用的变量

   
unset($memberinfo$_password$_answer);

   
$_arrgroupid $_arrgroupid array_filter(explode(','$_arrgroupid)) : array();  //把 字段为 arrgroupid  值为 FALSE 过滤掉。array_filter()不带回调参数的用法,请看手册。

  
}

  else

  {

   
mkcookie('auth''');

  }

  
/**

经过上面的读cookie 和查数据库用户信息后。当确定这个用户信息是合法以后。就会自动登陆了。比如phpchina论坛。当你登陆后没注销。下次访问的时候还是登陆状态。就是这个原理。记得模仿哦

  这里详细解释下 mkcookie ()函数  上菜:

  function mkcookie($var, $value = '', $time = 0)

  {

   global $CONFIG,$PHP_TIME;

   $time = $time > 0 ? $time : (empty($value) ? $PHP_TIME - 3600 : 0);

   $s = $_SERVER['SERVER_PORT'] == '443' ? 1 : 0;

   $var = $CONFIG['cookiepre'].$var;

   return setcookie($var, $value, $time, $CONFIG['cookiepath'], $CONFIG['cookiedomain'], $s);

  }

  $time  为cookie 的存活时间:  如果为 0  就是关闭浏览器 cookie 就自动失效 ,  $PHP_TIME 在前 面定义了:当前时间。   $PHP_TIME -3600  减去3600秒。就是一个小时前的意思,那肯定是设置cookie 失效的意思了。

  $s  变量是 获取 是否开启SSL安全传输的标致。 cookie 有一个参数是ssl传输的。如果服务器已经opensll 了那么我们肯定不能浪费这么好的安全资源了。

  $var cookie名的前缀,主要防止混淆。

  $CONFIG['cookiedomain']  这个家伙在 config.inc.php里面已经配置的了。定义为: '/'   意 思就是说 在当前域 的所有目录的PHP程序都能访问这个COOKIE ,还有限制目录访问COOKIE 的弄法。具体请 看 setcookie () 函数手册上说明。

  */

  

}

}

unset(
$db_class$db_file$phpcms_auth$phpcms_auth_key$memberinfo);
阅读(195) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~