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

全部博文(264)

文章存档

2011年(1)

2009年(263)

我的朋友

分类:

2009-06-03 15:17:24

这个讲  phpcms 的数据库类  和  phpcms 的文本缓存的实现.看了看

都是很简单的东西.大家看着我注释慢慢看吧.慢慢理解,最好能装了PHPCMS 在来看.因为这样可以看下它的数据库结构信息.可以帮助理解.

不明白的继续问吧.

首先是数据库类,phpcms 的数据库 分mysql 和mssql 版本.  MSSQL 版本的我就不说了.  他们主要的sql 语句不同点就在于我们分页常用到的 limit  语句.所以.在 mssql 数据库类驱动里.他做了个挺好的封装.让MYSQL 和MSSQL在SQL语句方面的差异性就很小了.可以说PHPCMS你可以随便转换数据库只要在代码中换下数据库类驱动就行.
php

/**

mysql数据库类。写得比较简单。也没什么好说的。大家自己看下理解下。

然后就可以跳过了。

*/

defined('IN_PHPCMS') or exit('Access Denied');

/**

这个东西是不是很熟呀。对了。在上一章已经讲过了。也已经在上一章的common.inc.php 启动文件里面定义了  IN_PHPCMS   所以在以下的PHP文件里都检测下是否是人为”跳墙“进来的。是就中断 

*/

/**

* Mysql 数据库类,支持Cache功能

*/

class db_mysql

{

/**

* MySQL 连接标识

* @var resource

*/

var $connid;

/**

* 整型变量用来计算被执行的sql语句数量

* @var int

*/

var $querynum 0;

/**

* 数据库连接,返回数据库连接标识符

* @param string 数据库服务器主机

* @param string 数据库服务器帐号

* @param string 数据库服务器密码

* @param string 数据库名

* @param bool 是否保持持续连接,1为持续连接,0为非持续连接

* @return link_identifier

*/

function connect($dbhost$dbuser$dbpw$dbname$pconnect 0

{

  global 
$CONFIG;

  
$func $pconnect == 'mysql_pconnect' 'mysql_connect';

  
/**

  mysql_pconnect()  为常连接。它和mysql_connect 的区别是 前者在多进程的WEB服务器上效率比较好。但也有瑕疵就是在有关事务和数据表锁方面。详情请查看自己的手册。

  */

  
if(!$this->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 

defined
('IN_PHPCMS') or exit('Access Denied');

/**

这个文件里面全是有关生成文本缓存的函数。文本缓存是个好东西。一般的项目,我们用不着内存缓存 : memcached  ,文本搞定。

原理是这样的: 我们在后台是不是可以设置很多有关网站的参数。而这些参数很多都是固定的。就不变化的。都存到咱的数据库上。而我们程序那里呢

每次都要访问数据库读出参数来进行我们程序中的操作。首先数据库查询是个很耗硬盘IO资源的一个东西,所以文本缓存刚好能减轻数据库那边的承重。

我们在程序开始就把数据库里面的配置都转化为数组 等  放到  php文件里面。这样我们可以直接访问php文件而不用每次都访问数据库了。  php文本缓存其实成了

我们程序和数据库的一个中间件。 所以我们自己写自己的文本缓存的时候其实要实现的很简单:  读数据库  ->  写到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(
$datacache_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'] = $r['introduce']? $r['introduce']:' ';

    
$TYPE[$r['typeid']] = $r;

   }

   
cache_write('type_'.$m.'.php',$TYPE);

  }

  return 
$modulechannels;  

}

}

function 
cache_member_group()

{

global 
$db;

$query $db->query("SELECT * FROM ".TABLE_MEMBER_GROUP." ORDER BY groupid"); //用户组信息

while($r $db->fetch_array($query))

{

  
$groupid $r['groupid'];

  
cache_write('member_group_'.$groupid.'.php'$r);

  
$data[$groupid] = $r;

}

cache_write('member_group.php'$data); //明白了吧。写缓存罗

return $data;

}

function 
cache_banip()

{

global 
$db,$PHP_TIME;

$result $db->query("SELECT ip,overtime FROM ".TABLE_BANIP." WHERE ifban=1 and overtime>=$PHP_TIME order by id desc ");

while(
$r $db->fetch_array($result))

{

  
$data[] = array('ip'=>$r['ip'],'overtime'=>$r['overtime']);

}

$db->free_result($result);

cache_write('banip.php'$data);

return 
$data;

}

?>
阅读(448) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~