您好,欢迎来到三六零分类信息网!老站,搜索引擎当天收录,欢迎发信息

海内著名CMS: PHPCMS 整站代码分析讲解

2025/3/25 8:21:03发布35次查看
国内著名cms: phpcms 整站代码分析讲解
国内著名cms: phpcms 整站代码分析讲解 ?
2010-05-11 11:28:00|? 分类: 建站 |? 标签: |字号大中小 订阅
原贴地址:http://www.phpchina.com/bbs/thread-47107-1-1.html
作者:逆雪寒
从今天开始.我会一有时间就对phpcms 整站的代码做一个详细的分析.目的很简单.让大家都能在phpchina 里面得到进步.
谢谢.? 代码讲解分析全部是本人.按照本人的知识水平来讲解.如果有说得不对的.请指正.也欢迎指正.大家一起进步.谢谢
希望大家支持哦 ?
首先我对 phpcms 的 头程序文件开始讲解 : include/common.inc.php 这个文件是程序启动的核心文件.
引用:
? $val) $string[$key] = new_addslashes($val);
? return $string;
? }
? 这个函数也是写得贼好。也是同时考虑过滤 字符窜或数组,也是使用了 传归。看下就应该明白了吧。这个不用说了。我们要学下这个思路这个方法方式哦。这样才能进步。
? 哈哈。我们要懂模仿。
? */
? @extract($_post, extr_overwrite);
? @extract($_get, extr_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($cachefileid, 0, 2).'/'; //缓存目录
? $cachefile = $cachefiledir.$cachefileid.'.html'; //缓存文件: xxx.html 格式
? if(file_exists($cachefile) && ($php_time
? { //如果缓存文件存在和缓存没有过期效,那么就返回缓存文件名
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逻辑是做什么的呢? 不知道大家有没见过 这样的网址: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.过了.
? */
继续
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 文件里面是什么来的呢?上菜:
? 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']
? 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) ? 1 : 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
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($memberinfo, extr_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);
恩继续 帖. ?
这个讲? phpcms 的数据库类? 和? phpcms 的文本缓存的实现.看了看
都是很简单的东西.大家看着我注释慢慢看吧.慢慢理解,最好能装了phpcms 在来看.因为这样可以看下它的数据库结构信息.可以帮助理解.
不明白的继续问吧.
首先是数据库类,phpcms 的数据库 分mysql 和mssql 版本.? mssql 版本的我就不说了.? 他们主要的sql 语句不同点就在于我们分页常用到的 limit? 语句.所以.在 mssql 数据库类驱动里.他做了个挺好的封装.让mysql 和mssql在sql语句方面的差异性就很小了.可以说phpcms你可以随便转换数据库只要在代码中换下数据库类驱动就行.
引用:
? connid = @$func($dbhost, $dbuser, $dbpw))
? {
$this->halt('can not connect to mysql server');
? }
? // 当mysql版本为4.1以上时,启用数据库字符集设置
? if($this->version() > '4.1' && $config['dbcharset'])
? {
mysql_query(set names '.$config['dbcharset'].' , $this->connid);
? }
? // 当mysql版本为5.0以上时,设置sql mode,mysql5数据库带了字符集模式。设置下就好
? if($this->version() > '5.0')
? {
mysql_query(set sql_mode='' , $this->connid);
? }
? if($dbname)
? {
if([email=!@mysql_select_db($dbname]!@mysql_select_db($dbname[/email] , $this->connid))
{
? $this->halt('cannot use database '.$dbname);
}
? }
? return $this->connid;
? }
? /**
? * 选择数据库
? * @param string 数据库名
? */
? function select_db($dbname)
? {
? return mysql_select_db($dbname , $this->connid);
? }
? /**
? * 执行sql语句
? * @param string sql语句
? * @param string 默认为空,可选值为 cache unbuffered
? * @param int cache以秒为单位的生命周期
? * @return resource
? */
? function query($sql , $type = '' , $expires = 3600, $dbname = '')
? {
? $func = $type == 'unbuffered' ? 'mysql_unbuffered_query' : 'mysql_query';
? /**
? mysql_unbuffered_query 效率更好。节省内存 看手册
? */
? if(!($query = $func($sql , $this->connid)) && $type != 'silent')
? {
$this->halt('mysql query error', $sql);
? }
? $this->querynum++;
? return $query;
? }
? /**
? * 执行sql语句,只得到一条记录
? * @param string sql语句
? * @param string 默认为空,可选值为 cache unbuffered
? * @param int cache以秒为单位的生命周期
? * @return array
? */
? function get_one($sql, $type = '', $expires = 3600, $dbname = '')
? {
? $query = $this->query($sql, $type, $expires, $dbname);
? $rs = $this->fetch_array($query);
? $this->free_result($query);
? return $rs ;
? }
? /**
? * 从结果集中取得一行作为关联数组
? * @param resource 数据库查询结果资源
? * @param string 定义返回类型
? * @return array
? */
? function fetch_array($query, $result_type = mysql_assoc)
? {
? return mysql_fetch_array($query, $result_type);
? }
? /**
? * 取得前一次 mysql 操作所影响的记录行数
? * @return int
? */
? function affected_rows()
? {
? return mysql_affected_rows($this->connid);
? }
? /**
? * 取得结果集中行的数目
? * @return int
? */
? function num_rows($query)
? {
? return mysql_num_rows($query);
? }
? /**
? * 返回结果集中字段的数目
? * @return int
? */
? function num_fields($query)
? {
? return mysql_num_fields($query);
? }
? /**
? * @return array
? */
? function result($query, $row)
? {
? return @mysql_result($query, $row);
? }
? function free_result($query)
? {
? return mysql_free_result($query);
? }
? /**
? * 取得上一步 insert 操作产生的 id
? * @return int
? */
? function insert_id()
? {
? return mysql_insert_id($this->connid);
? }
? /**
? * @return array
? */
? function fetch_row($query)
? {
? return mysql_fetch_row($query);
? }
? /**
? * @return string
? */
? function version()
? {
? return mysql_get_server_info($this->connid);
? }
? function close()
? {
? return mysql_close($this->connid);
? }
? /**
? * @return string
? */
? function error()
? {
? return @mysql_error($this->connid);
? }
? /**
? * @return int
? */
? function errno()
? {
? return intval(@mysql_errno($this->connid)) ;
? }
? /**
? mysql_errno()? 函数也挺好使的哦。自己试下
? */
? /**
? * 显示mysql错误信息
? */
? function halt($message = '', $sql = '')
? {
? exit(mysql query:$sql
mysql error:.$this->error().
mysql errno:.$this->errno().
message:$message);
? }
? }
? ?>
phpcms的文本缓存实现:
引用:
? ? 写到php文件 ->? 程序中include
? 来吧。开始文本缓存学习
? */
? function cache_all()? //生成所有缓存的总操作函数
? {
? cache_table(); //生成所有的数据库表名,表名是根据数据库里面当前的表明而生成。请看这个函数的详细分析
? require_once phpcms_cachedir.'table.php'; //包含表常量
? cache_common();
? cache_member_group();
? $modules = cache_module();
? $channelids = cache_channel(0);
? $keyids = array_merge($modules, $channelids);
? foreach($keyids as $keyid)
? {
? $catids = cache_categorys($keyid);
? if(is_array($catids))
? {
foreach($catids as $catid)
{
? cache_category($catid);
}
? }
? }
? cache_type(0);
? return true;
? }
? function cache_common()
? {
? global $db;
? $query = $db->query(select module,name,iscore,iscopy,isshare,moduledir,moduledomain from .table_module. where disabled=0); //查询所有能用的模块
? while($r = $db->fetch_array($query))
? {
? $r['linkurl'] = '';
? if($r['module'] != 'phpcms' && $r['iscopy'] == 0) $r['linkurl'] = linkurl($r['moduledomain'] ? dir_path($r['moduledomain']) : $r['moduledir'].'/');
? //如果模块存在目录的就取它目录地址
? unset($r['moduledomain']);
? $key = $r['module'];
? $data[$key] = $r;
? }
? $cache['module'] = $data; //存到缓存数组,等一下一起把 $cache 数组写到文本里去
? $data = array();
? $query = $db->query(select channelid,module,channelname,channeldir,channeldomain,channelpic,introduce,style,islink,linkurl,cat_html_urlruleid,item_html_urlruleid,special_html_urlruleid,cat_php_urlruleid,item_php_urlruleid,special_php_urlruleid from .table_channel. where disabled=0 order by listorder); //罗列能用的频道列表
? while($r = $db->fetch_array($query))
? {
? $r['linkurl'] = linkurl($r['linkurl']);
? $key = $r['channelid'];
? $data[$key] = $r;
? }
? $cache['channel'] = $data; //存到缓存数组
? $data = array();
? $r = $db->get_one(select setting from .table_module. where module='phpcms');
? $cache['phpcms'] = unserialize($r['setting']);
? //查询 phpcms这个模块的设置信息,大家可以看下数据库这个表内容。setting 字段里面的信息是经过serialize 函数窜行化的。
? //所以取出的内容要unserialize 反窜行.我是挺喜欢使用serialize 函数的。他可以实现把一个数组存到数据库或把一个对象存到数据库。或是拿来get传递都行。
? //太强了。大家可以试用下。可能你项目某个地方需要用到哦。
? $fields = array();
? $result = $db->query(select * from .table_field. order by fieldid); //下栽模块的信息,请自己看下这个表的数据就明白
? while($r = $db->fetch_array($result))
? {
? $tablename = $r['tablename'];
? $fields[$tablename] .= ','.$r['name'];
? }
? $cache['field'] = $fields;
? cache_write('common.php', $cache); //开始把$cache 数组写到 common.php 这个文本缓存里。大家可以自己去打开这个文件看下内容。一切了然
? return $cache;
? }
? function cache_update($action='')//更新文本缓存。最好在后台操作使用。因为php的文件flock 文件锁在某些平台使用不是很好。会出现多用户同写一个文件从而破坏缓存文件
? {
? global $db;
? $data=array();
? switch($action)
? {
? case 'keylink';
$query=$db->query(select linktext,linkurl from .table_keylink. where passed=1);
while($r=$db->fetch_array($query)){
? $data[]=$r;
}
? break;
? case 'reword';
$query = $db->query(select word,replacement from .table_reword. where passed=1);
while($r = $db->fetch_array($query))
{
? $data[]=$r;
}
? break;
? default:
$actions = array('keylink','reword');
array_map('cache_update', $actions);
return true;
? }
? cache_write('cache_'.$action.'.php', $data);
? return $data;
? }
? function cache_table()
? {
? global $db,$config;
? $query = $db->query(show tables from `.$config['dbname'].`);
? /**
? 显示数据库里面的所有表名
? */
? while($r = $db->fetch_row($query))
? {
? $table = $r[0];
? if(preg_match(/^.$config['tablepre']./i, $table)) //寻找表前缀等于 $config['tablepre'] (在config.inc.php里设置) @@表前缀还有这个作用 嘿嘿
? {
$tablename = str_replace($config['tablepre'], 'table_', $table);
$data[$tablename] = $table;? //? $data['table_xx'] = xx; 形式 只能意会下了
? }
? }
? $db->free_result($query);? //$db->free_result()? 这个类方法其实是掉用了函数:mysql_free_result() 函数 主要是为了清除数据库大的查询而占用的内存。还是有必要的哦
? if(!is_dir(phpcms_cachedir)) // 常量 phpcms_cachedir 在 common.inc.php 里面定义的。大家不记得了去看看吧。是存放phpcms 缓存目录的路径,这里意思是:如果缓存目录不存在
? {
? dir_create(phpcms_cachedir); //如果缓存目录不存在那么就创建
? dir_create($config['templatescachedir']); //创建编译后的php模板目录,有关phpcms模板引擎编写。在下一章合适就开讲
? /**
? dir_create() 函数为创建 目录函数。phpcms自己封装的,刚看了下。phpcms 挺强。这个函数还可以通过ftp 来创建目录。这样就可以解决一些 开启了安全模式下的服务器对于创建目录等出现的问题
? 因为涉及到php ftp 知识。所以打算讲解到下面再说。
? */
? }
? cache_write('table.php', $data , 'constant'); //很多朋友说找不到phpcms 表常量在那里定义的。就是在这里。
? /**
? cache_write() 函数在global.func.php里面定义的。是把 已经从数据库取出来的数组信息写到 php文本上去。@@文本缓存关键的一步? 废话少说上菜:
? function cache_write($file, $string, $type = 'array')
? {
if(is_array($string)) //检测 $string 内容是字符窜的呢还是数组的,是数组的那就继续 ..
{
? $type = strtolower($type); ?
? if($type == 'array')//然后再判断这个函数的模式标致 ,是否为数组模式,默认为数组模式
? {
$string = ;
//这个太关键了。因为我们把数据库的信息写到文本上去的时候。是以符合php语法的格式写进去的。为什么呢?@@ 十分废话,因为如果不是以php格式写到文件里面去
那么这个php文件怎么能给我们include 进程序运行调用呢? 呵呵。 知道这一点就真的明白文本缓存的实现了。忒简单。 这里使用了个小技巧:使用了 var_export() 函数
这个函数会返回一个变量的字符窜形式。这个函数太有帮助了。如果没有这个函数,我们还要自己想办法实现呢。自己写一次文本缓存就明白了。会碰到这个问题的。 '\n' 这个是
文本文件的换行。初学者 别把
和 '\n' 搞混罗。 一个是html 的 一个是文本文件的
? }
? elseif($type == 'constant') //以内容形式
? {
$data='';
foreach($string as $key => $value) $data .= define('.strtoupper($key).','.addslashes($value).');\n;
$string = ;
如果以内容形式的话。就不是写数组到文本里面了。而是把内容都定义成常量。
? }
}
$strlen = file_put_contents(phpcms_cachedir.$file, $string);//file_put_contents()函数 是php5才支持的 效率最好。建议使用
chmod(phpcms_cachedir.$file, 0777); 设置目录 为可读可写可执行
return $strlen; //返回写到文本的字节数
? }
?
? 再说多一个读 缓存文件的操作函数? :上菜
? 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);
}
读缓存其实就是 include php缓存文件。 讲完走人
? */
? return $data;
? }
? /**
? phpcms 的所有数据库表名 都用根据数据库当前的表名来用常量来进行定义。我认为这样设计不是很好。不够灵活:比如如果我们更改数据库的一个表名的话。
? 那么会出现找不到表的错误信息。而且想要修复还很麻烦。就是说不能随便更改表名了。不推荐大家这样写。我们可以把表名都定义在一个php文件里面。这样我们以后
? 要改某个表名,就很方便了。
? */
? function cache_module($module = '')
? {
? global $db;
? if($module)
? {
? $r = $db->get_one(select setting,module,name,iscopy,moduledir,moduledomain from .table_module. where module='$module'); //模块具体信息
? if($r['setting'])
? {
$setting = unserialize($r['setting']); //讲过了反窜行。因为里面信息是窜行化后再存到数据库的
? }
? $setting['name'] = $r['name'];
? $setting['moduledir'] = $r['moduledir'];
? $setting['moduledomain'] = $r['moduledomain'];
? $setting['linkurl'] = '';
? if($r['module'] != 'phpcms' && $r['iscopy'] == 0)
? {
$setting['linkurl'] = linkurl($r['moduledomain'] ? dir_path($r['moduledomain']) : $r['moduledir'].'/');
? cache_categorys($module);
? }
? unset($r['moduledomain']);
? cache_write($module.'_setting.php', $setting);
? return $setting;
? }
? else
? {
? $query = $db->query(select module from .table_module. where disabled=0 order by moduleid);
? while($r = $db->fetch_array($query))
? {
cache_module($r['module']);
$modules[] = $r['module'];
? }
? return $modules;
? }
? }
? function cache_channel($channelid=0)
? {
? global $db;
? if($channelid)
? {
? $data = $db->get_one(select * from .table_channel. where channelid=$channelid);
? if($data && !$data['islink'])
? {
if($data['setting'])
{
? $setting = unserialize($data['setting']);
? unset($data['setting']);
? $data = is_array($setting) ? array_merge($data, $setting) : $data;
}
$data['linkurl'] = linkurl($data['linkurl']);
cache_write('channel_'.$channelid.'.php', $data);
cache_categorys($channelid);
return $data;
? }
? }
? else
? {
? $query = $db->query(select channelid from .table_channel. where islink=0 and disabled=0 order by channelid);
? while($r = $db->fetch_array($query))
? {
cache_channel($r['channelid']);
$channelids[] = $r['channelid'];
? }
? return $channelids;
? }
? }
? function cache_categorys($keyid)
? {
? global $db,$phpcms,$channel;
? $urlpre = '';
? if(is_numeric($keyid))
? {
? $keyid = intval($keyid);
? $module = $channel[$keyid]['module'];
? $sql = channelid=$keyid ;
? }
? else
? {
? $sql = module='$keyid' ;
? }
引用:
? $catids = $data = array();
? $query = $db->query(select module,channelid,catid,catname,style,introduce,catpic,islink,catdir,linkurl,parentid,arrparentid,parentdir,child,arrchildid,items,itemordertype,itemtarget,ismenu,islist,ishtml,htmldir,prefix,urlruleid,item_prefix,item_html_urlruleid,item_php_urlruleid from .table_category. where $sql order by listorder,catid);
? while($r = $db->fetch_array($query))
? {
? $r['linkurl'] = str_replace($phpcms['index'].'.'.$phpcms['fileext'], '', $r['linkurl']);
$r['linkurl'] = $urlpre ? preg_replace(|^.$urlpre.|, '', $r['linkurl']) : linkurl($r['linkurl']);
? $catid = $r['catid'];
? $data[$catid] = $r;
? $catids[] = $catid;
? }
? if($data) cache_write('categorys_'.$keyid.'.php', $data); //写缓存罗。
? return $catids;
? }
? function cache_category($catid)
? {
? global $db,$phpcms;
? if(!$catid) return false;
? $data = $db->get_one(select * from .table_category. where catid=$catid);
? $setting = unserialize($data['setting']);
? unset($data['setting']);
? $data = is_array($setting) ? array_merge($data, $setting) : $data;
? $data['linkurl'] = linkurl(str_replace($phpcms['index'].'.'.$phpcms['fileext'], '', $data['linkurl']));
? cache_write('category_'.$catid.'.php', $data);
? return $data;
? }
? function cache_type($keyid=0)
? {
? global $db;
? if($keyid)
? {
$result = $db->query(select * from .table_type. where keyid='$keyid');
$data = array();
while($r = $db->fetch_array($result))
{
$r['introduce'] = $r['introduce']? $r['introduce']:' ';
? $data[$r['typeid']] = $r;
}
if($data)
{
cache_write('type_'.$keyid.'.php', $data);
}
? return $data;
? }
? else
? {
? $modules = array();
? $query = $db->query(select module from .table_module. where disabled=0 order by moduleid);
? while($r = $db->fetch_array($query))
? {
$modules[] = $r['module'];
? } ?
? $channelids = array();
? $query = $db->query(select channelid from .table_channel. where islink=0 and disabled=0 order by channelid);
? while($r = $db->fetch_array($query))
? {
$channelids[] = $r['channelid'];
? }
? $modulechannels = array_merge($modules,$channelids);
? foreach($modulechannels as $m)
? {
$result = $db->query(select * from .table_type. where keyid='$m');
$type = array();
while($r = $db->fetch_array($result))
{
? $r['introduce']
该用户其它信息

VIP推荐

免费发布信息,免费发布B2B信息网站平台 - 三六零分类信息网 沪ICP备09012988号-2
企业名录 Product