接上一篇:网易blog郁闷限制字符长度太低了。

为了使系统的结构清晰一些,我把需要使用的文件都放在了二级目录下面。

下面是通用头文件/includes/kernel/common.inc.php的一些片断:

if (!defined('IN_BSG')) {

exit;

}

?>

上面的代码保证它只能被合法的程序所调用,而不会被其它的文件include。如果正在执行的程序没有定义一个'IN_BSG'常量,它在include这个common.inc.php之后程序会终止。

list($usec, $sec) = explode(" ", microtime());

$page_time_start = $usec + $sec;

?>

这两行大家可能都会比较熟悉,这是计算程序的开始执行时间的。在程序结束之前,还会再计算一下这个,为的是得出程序执行所耗费的时间。如果你不在意这些,可以放心地把它注释掉。

error_reporting(E_ERROR | E_WARNING | E_PARSE); // This will NOT report uninitialized variables

//error_reporting(E_ALL);

set_magic_quotes_runtime(0);

// Be paranoid with passed vars

if (@ini_get('register_globals')) {

foreach ($_REQUEST as $var_name => $void) {

unset(${$var_name});

}

}

?>

上面这些,是一些基本的设置,包括错误提示级别。如果你的php.ini中打开了register_globals(它常会带来危险并使人感到困惑),我们要把它随便设置的那些全局变量删掉。

if (!get_magic_quotes_gpc()) {

if (is_array($_GET)) {

while (list($k, $v) = each($_GET)) {

if (is_array($_GET[$k])) {

while (list($k2, $v2) = each($_GET[$k])) {

$_GET[$k][$k2] = addslashes($v2);

}

@reset($_GET[$k]);

}

else {

$_GET[$k] = addslashes($v);

}

}

@reset($_GET);

}

if (is_array($_POST)) {

while (list($k, $v) = each($_POST)) {

if (is_array($_POST[$k])) {

while (list($k2, $v2) = each($_POST[$k])) {

$_POST[$k][$k2] = addslashes($v2);

}

@reset($_POST[$k]);

}

else {

$_POST[$k] = addslashes($v);

}

}

@reset($_POST);

}

if (is_array($_COOKIE)) {

while (list($k, $v) = each($_COOKIE)) {

if (is_array($_COOKIE[$k])) {

while (list($k2, $v2) = each($_COOKIE[$k])) {

$_COOKIE[$k][$k2] = addslashes($v2);

}

@reset($_COOKIE[$k]);

}

else {

$_COOKIE[$k] = addslashes($v);

}

}

@reset($_COOKIE);

}

}

define('STRIP', (get_magic_quotes_gpc()) ? true : false);

?>

上面的一陀,显而易见,它在做转义过滤所有来自客户端的输入。

下面的部分是对系统的初始化。之前的部分,可能和普通的程序没什么两样,但是下面这一段,我保证你没见过.

// Init System

require('../../includes/kernel/config.inc.php');

// First Startup? Init the tmpfs

if (!is_dir ($data_root) || !is_dir ($includes_root)) {

if (!is_writable ($tmpfs_root))

die ('TMPFS FAILED!!!');

require_once('../../includes/kernel/pkg.inc.' . $phpEx);

@mkdir ($data_root);

@mkdir ($includes_root);

$pkg = new BsmPkg ();

$pkg->target_dir = $data_root;

$pkg->filename = $tmpfs_pkg_data_filename;

$pkg->unpack_into_dir ();

$pkg->target_dir = $includes_root;

$pkg->filename = $tmpfs_pkg_includes_filename;

$pkg->unpack_into_dir ();

}

?>

包含一个config.inc.php看起来很正常,它里面有一些关于系统的设置参数(这个文件后面会有),然后它会检查$data_root 和$includes_root目录是否存在,并检查$tmpfs_root目录是否可写。这里的$data_root和$includes_root按照规定,是属于$tmpfs_root的下一级目录,而$tmpfs_root是整个系统使用的tmpfs根路径,它负责保存我们系统的临时数据,其中$includes_root用来保存那些需要被执行体包含的include文件,$data_root用来存放Cache、模板编译结果等数据文件。

tmpfs是Linux里的一种特殊分区格式。区别于ext3等,tmpfs创建于内存和交换区上。Linux有一个默认的shm就是tmpfs类型,通常mount在/dev/shm上。tmpfs和ramfs有些相似,不同的是它会用到交换区。

tmpfs的最大好处是IO速度。毕竟纯粹的物理磁盘操作效率无法和内存相比,而且tmpfs使用起来也很方便,它基本不需要做什么其它设置就可以像普通的物理硬盘一样使用,它对程序来说是透明的。

tmpfs的使用方法与Linux挂载其它类型的分区格式一样,可以用mount命令来挂载,也可以在fstab中设置。

* * * * * *

当系统检测到$tmpfs_root确实存在且可写,而$data_root和$include_root不存在,表示这是系统第一次在运行,它会用内置的一个压缩/解压文件的一个类来把事先准备好的data和includes压缩文件解压到$tmpfs_root中,这个类处理的格式是我自创的,它保持了源目录结构,并保存了文件的属性。它也会对每一个文件做文件长度和MD5校验。这个类位于/includes/kernel/pkg.inc.php

这里提及一个细节,我学习了PHPBB中的$phpEx的概念,整个系统中除了调用common.inc.php和config.inc.php外,其它调用php文件的地方都没有写“.php”扩展名,而是用了一个$phpEx变量代替,这个变量的值在config文件中可以修改,这样做的好处是我们随时可以把系统中的php程序改换扩展名。比如我们修改了Apache配置,让php解释器来解释一种叫做.hello的文件,就可以方便地把整个系统的所有被include的php程序扩展名改成.hello,再把config中的$phpEx的值改成“hello”,这样你的系统看起来就像是使用一种没人见过的Hello语言编写的了,哈哈……

includes这个压缩文件中包含了/includes目录中的所有内容,它被解压到$tmpfs_root(我的系统中是/opt/tmp/)中,这样,在/opt/tmp/includes中就有我们想要的所有include文件了,调用它比直接调用/includes要快很多。

下面的部分就是调用已经解压好的一些include文件

// Include Kernel file

require($includes_root . 'db/' . $global_db_dbms . '.' . $phpEx);

require($includes_root . 'kernel/constants.inc.' . $phpEx);

require($includes_root . 'kernel/template.inc.' . $phpEx);

require($includes_root . 'kernel/session.inc.' . $phpEx);

require($includes_root . 'kernel/cache.inc.' . $phpEx);

require($includes_root . 'kernel/log.inc.' . $phpEx);

require($includes_root . 'kernel/shm.inc.' . $phpEx);

require($includes_root . 'function/basic.function.' . $phpEx);

require($includes_root . 'function/file.function.' . $phpEx);

?>

接着创建一个通用的数据库连接$db,它的属性也都在config.inc.php中设置。

// Init the DB Connection

$db = new $sql_db;

// Connect to DB

$db->sql_connect($global_db_host, $global_db_user, $global_db_pass, $global_db_name, $global_db_port, false);

?>

创建成功后,记得把密码清空

// We do not need this any longer, unset for safety purposes

unset($global_db_pass);

?>

创建日志对象

// Init Log

$log = new BsmLog ('bsg');

?>

这又是一个精彩部分,创建一个共享内存对象

// Init the Shared Memory

$shm = new BsmShm;

if ($shm->shm_id) {

define ('SHM_SUPPORT', true);

}

?>

如果系统是第一次运行,则在共享内存中标记一个运行标志SHM_VAR_SYS_RUN = true(系统的constants.inc.php是常量表,里面定义了系统要使用的常量)

if (defined ('SHM_SUPPORT') && !@$shm->get_var (SHM_VAR_SYS_RUN)) {

$shm->put_var (SHM_VAR_SYS_RUN, true);

}

?>

我写了一个Session类,也许它的效率并不很好,我只是写来玩玩……如果你觉得它的效率不行,可以使用系统Session,或者使用Sky同学的SessionD,哈哈——做个广告……

// Init the User Defined Session

$mSession = array ();

$sess = new BsmSession;

$sess->mSession_Start ();

?>

一长串乱七八糟的代码,只是为了获得访问者IP:

// Proc clients' IP address'

if(getenv('HTTP_X_FORWARDED_FOR') != '') {

$client_ip = (!empty($_SERVER['REMOTE_ADDR']) ) ? $_SERVER['REMOTE_ADDR'] : ( (!empty($_ENV['REMOTE_ADDR']) ) ? $_ENV['REMOTE_ADDR'] : $REMOTE_ADDR);

$entries = explode(',', getenv('HTTP_X_FORWARDED_FOR'));

reset($entries);

while (list(, $entry) = each($entries)) {

$entry = trim($entry);

if (preg_match("/^([0-9]+.[0-9]+.[0-9]+.[0-9]+)/", $entry, $ip_list) ) {

$private_ip = array('/^0./', '/^127.0.0.1/', '/^192.168..*/', '/^172.((1[6-9])|(2[0-9])|(3[0-1]))..*/', '/^10..*/', '/^224..*/', '/^240..*/');

$found_ip = preg_replace($private_ip, $client_ip, $ip_list[1]);

if ($client_ip != $found_ip) {

$client_ip = $found_ip;

break;

}

}

}

}

else

{

$client_ip = (!empty($_SERVER['REMOTE_ADDR'])) ? $_SERVER['REMOTE_ADDR'] : ((!empty($_ENV['REMOTE_ADDR'])) ? $_ENV['REMOTE_ADDR'] : $REMOTE_ADDR);

}

?>

获得环境参数的Cache,并返回它的值。环境参数是什么内容要看具体做的是什么,比如它是一个普通网站,参数中可能会包括站点名称、作者、首页布局、使用的模板、几个模块、每个模块显式几行、每行显式几个图片这些值。这些值一般都是在后台中可以修改然后存入数据库中的。cache.inc.php中的 obtain_config函数负责在第一次执行时把它们从数据库中取出,并放到一个可以被更快地访问到的地方,比如shm中,或者是tmpfs上的一个文件,优化它是非常有必要的,因为这批数据被使用得太频繁了。

// Grab global variables, re-cache if necessary

$CONF = obtain_config();

?>

然后是处理gz压缩。下面这些内容是明显通用化的,甚至包括检查php版本。前面我已经说过,我们是在控制自己的独立服务器,所以你完全可以把它简写成你自己需要的样子甚至完全删掉它.

// Setting the ob_gzhandler

if ($CONF['gz_compress']) {

$phpver = phpversion ();

$useragent = (isset ($_SERVER["HTTP_USER_AGENT"])) ? $_SERVER["HTTP_USER_AGENT"] : $HTTP_USER_AGENT;

if ($phpver >= '4.0.4pl1' && (strstr ($useragent, 'compatible') || strstr ($useragent, 'Gecko'))) {

if (extension_loaded ('zlib')) {

ob_start ('ob_gzhandler');

}

}

elseif ($phpver > '4.0') {

if (strstr ($HTTP_SERVER_VARS['HTTP_ACCEPT_ENCODING'], 'gzip')) {

if (extension_loaded ('zlib')) {

ob_start ();

ob_implicit_flush (0);

$mSession['do_gzip'] = true;

header ('Content-Encoding: gzip');

}

}

}

}

else

ob_start ();

?>

下面是初始化模板类,这个模板类~~似乎没人见过,我也没拿出来给人看过,呵呵……

// Init the Template Object

$tpl = new BsmTpl ('../../templates/', $tpl_c_root);

$tpl->set_tpl_name ('seepic'); //seepic是我临时写的一个模板名字,实际使用时应该用的是$CONF里的值。

?>

初始化模板之后是确认语言,因为有可能会用到多语言的语言包文件。

// Confirm Accept Language

$langMeta = isset ($_COOKIE['langMeta']) ? $_COOKIE['langMeta'] : $_SERVER['HTTP_ACCEPT_LANGUAGE'];

if ($_GET['lang']) {

$langMeta = trim ($_GET['lang']);

setcookie ('langMeta', $langMeta, time() + (60 * 60 * 24 * 365), $cookie_path);

}

?>

把最终确认的语言赋值给模板对象,common文件的任务完成了。

include $tpl->set_language ($langMeta);

?>

下面来看看config文件里有什么,我会逐段解释:

// BSM Configuration File.

// Para_DB_Global:

$global_db_dbms = 'mysql4'; //全局数据库连接类型(支持mysql/mysql4/oracle/mssql/odbc/access/pqsql/sqlite等)

$global_db_host = 'localhost'; //数据库服务器地址

$global_db_port = ''; //端口

$global_db_name = 'g'; //数据库名

$global_db_user = 'root'; //数据库用户名

$global_db_pass = 'root'; //连接密码

$global_db_prefix = 'bsg_'; //数据表前缀(我都不知道我写它干什么……整个服务器都是我的)

// Para_DB_Member:

$member_db_dbms = 'sqlite'; //可以再定义一组数据库连接,用了sqlite,比如保存个人信息什么的……呵呵

$member_db_host = 'member.db'; //sqlite的服务器地址就是数据库文件名了

$member_db_port = '';

$member_db_name = '';

$member_db_user = '';

$member_db_pass = '';

$member_db_prefix = 'bsg_';

// Para_DB_Session;

$session_save_handle = 'system'; //也许更多人还是喜欢用mysql的HEAP表保存session

$session_life_time = '60*15';

$session_db_dbms = 'mysql4';

$session_db_host = '';

$session_db_port = '';

$session_db_name = '';

$session_db_user = '';

$session_db_pass = '';

$session_db_table = $global_db_prefix . 'sess';

// Para_Local_Sites: //这是定义的一些绝对路径变量,你可以随便写点什么

$global_site_root = '/www/mine/site/global/';

$member_site_root = '/www/mine/site/member/';

$admin_site_root = '/www/mine/site/admin/';

// Para_Global_Local_Dir

$tmpfs_root = '/opt/tmp/'; //tmpfs的挂载根,具体要看你在mount的时候或者fstab中把它挂到什么地方了

$data_root = $tmpfs_root . 'data/';

//临时数据保存目录

$tpl_c_root = $data_root . 'template/';

//模板编译文件保存目录,可以看见它位于/opt/tmp/data/template/下

$cache_root = $data_root . 'cache/';

//缓存目录

$includes_root = $tmpfs_root . 'includes/';

//include文件保存目录

$tmpfs_pkg_data_filename = '/www/g/dev_tools/start.data.tmpfs.pkg';

$tmpfs_pkg_includes_filename = '/www/g/dev_tools/start.includes.tmpfs.pkg';

//这两个是预先做好的压缩包,包含data和includes需要的文件和目录结构,你可以把它们放在web目录外面

// Para_Runtime_Environment:

$phpEx = 'php'; //这就是$phpEx,哈哈

// Para_Template

// Para_BSM_Session:

$user_sess_base_dir = $data_root . 'user_sess/';

//Session文件保存根目录(如果你用了我的Session类),Session文件在保存时会自己Hash的

$cookie_sess_id_varname = 'BSG_sid';

//在Cookie中的SessionID变量名

$sess_lifetime = 60 * 15; //Session存活时间

// Para_Log:

$log_record_method = 'file'; //日志保存方式

$log_base_dir = $data_root . '/log/';

//日志保存点。虽然它在tmpfs下,不过我们可以有一个守护进程每隔一段时间把它写到磁盘上。或者干脆就把它直接写到磁盘上。因为系统崩溃前夕的Log才最有价值

// Para_Cookie //Cookie设置(如果你需要用它)

$cookie_domain = '';

$cookie_path = '/';

?>

这两个文件基本确立了系统的运行环境,可以看见,里面使用了一些在通用系统中不会有的技术,包括共享内存、tmpfs等。当然还可以根据需要加入memcached支持等。

提及一下我所用到的数据库封装类包,它源自PHPBB3,很遗憾我没有和作者打招呼。使用它并不是因为它比Adodb和PEAR DB好很多,只是因为我熟悉它。其实它的结构很清晰,功能也很简单,不过简单的才是我想要的,我不希望一个类中藏着一大堆我不知道在干什么的代码(比如 Smarty……)

下面举一个例子,来说明tmpfs和shm是如何被系统用到并做缓存来用的。这里是cache.inc.php中的obtain_cache函数:

function obtain_config ()

{

global $db, $global_db_prefix;

$config_cache_file = '../../data/cache/config.cache';

if (defined ('SHM_SUPPORT')) {

global $shm;

@$CONF = $shm->get_var (SHM_VAR_PARA_CACHE);

if ($CONF['cfg_end'] !== 0) {

$sql = "SELECT * FROM {$global_db_prefix}config";

$res = $db->sql_query ($sql);

$CONF = array ();

while ($r = $db->sql_fetchrow ($res)) {

$CONF[$r['config_varname']] = $r['config_value'];

}

$CONF['cfg_end'] = 0;

$shm->put_var (SHM_VAR_PARA_CACHE, $CONF);

}

}

else {

if (!@file_exists ($config_cache_file)) {

$str = " . '$CONF = array (' . "rn";

$sql = "SELECT * FROM {$global_db_prefix}config";

$query = $db->sql_query ($sql);

while ($r = $db->sql_fetchrow ($query)) {

$value = "'" . addslashes ($r['config_value']) . "'";

$str .= "t'" . $r['config_varname'] . "'ttt" . '=> ' . $value . " ,rn";

}

$str .= "t'cfg_end'ttt=> 0rn";

$str .= ");rn?>";

if (!@$fp = fopen ($config_cache_file, 'w'))

return false;

fwrite ($fp, $str);

fclose ($fp);

}

include ($config_cache_file);

}

return $CONF;

}

这个函数分为两个部分,分别对应于shm和文件。首先它会检查系统是否支持共享内存(这个常量是在common.inc.php中已经设置过的),如果支持,函数会在config表中(具体应用中我也不知道你会把它放在哪里)读取所有的变量,并把它们放到一个数组中直接保存到shm里(当然实际操作不是这样简单的),如果系统不支持shm,函数会试图生成一个php文件。当再次调用这个函数时,如果shm里已经有了这个数组存在,或者已经有了这个文件存在的话(前面已经规定这个文件会被保存在tmpfs上),函数会直接返回它们的内容,不必再去读取数据库。

这就是一个简单的cache概念。究竟什么样的数据可以并且适合被cache?这和cache的更新方式有关。cache有定时间隔更新的,有不定时更新的。定时更新的指cache存在若干时间后再次重新生成cache,通常用于统计数据,比如在线人数等。不定时更新的是指生成后就一直保持不变,直到再次检测到不存在或已过期、已损坏等情况出现,通常见于参数调用、模板编译结果等。这些数据的特点是它们都是临时的,可以被丢弃的,比如没人会在乎一个模板是否被重新编译过,除了在编译的那次执行中多占用一点时间。这批可丢弃的数据就可以被放心地保存在内存或者tmpfs中,因为它们不怕丢失,并且随时可以被重建。

php大型博客,PHP大型Web应用入门(二)相关推荐

  1. Flask从入门到做出一个博客的大型教程(一)

    Flask从入门到做出一个博客的大型教程(一) 本项目全部在虚拟环境中运行,因此请参照前面的文章,链接为https://blog.csdn.net/u014793102/article/details ...

  2. Flask从入门到做出一个博客的大型教程(五)

    Flask从入门到做出一个博客的大型教程(五) 在开始之前,先来看下项目的整体结构. flask/ ├── app │ ├── forms.py │ ├── __init__.py │ ├── mod ...

  3. Flask从入门到做出一个博客的大型教程(四)

    Flask从入门到做出一个博客的大型教程(四) 在开始之前,先来看下项目的整体结构. flask ├── app │ ├── forms.py │ ├── __init__.py │ ├── mode ...

  4. 网页制作期末大作业成品 HTML5+CSS大作业——简约个性高逼格博客(5页) web网页制作期末大作业模板

    HTML5+CSS大作业--简约个性高逼格博客(5页) web网页制作期末大作业模板 常见网页设计作业题材有 个人. 美食. 公司. 学校. 旅游. 电商. 宠物. 电器. 茶叶. 家居. 酒店. 舞 ...

  5. 【第0篇】从0-1自建个人博客系统【web端,admin管理端,express后端,Nginx部署】--vue3技术 reac+hook技术 umi4

    [第0篇]从0-1自建个人博客系统[web端,admin管理端,后端] 文章完整地址:http://huxunxun.top/lookArtical?artical_id=18 [序言] 我是一个微小 ...

  6. java开发个人博客过程_java web个人博客开发(四详细设计)

    1.序言 详细设计主要内容在这里是接口设计,即html页面请求到,java后台返回数据的接口.预期实用restful风格,所以接口形式是url+请求参数,数据格式为json.由于文章统计阅读量和博主的 ...

  7. 基于 abp vNext 和 .NET Core 开发博客项目 - Blazor 实战系列(二)

    基于 abp vNext 和 .NET Core 开发博客项目 - Blazor 实战系列(二) 转载于:https://github.com/Meowv/Blog 上一篇搭建了 Blazor 项目并 ...

  8. 基于 abp vNext 和 .NET Core 开发博客项目 - 定时任务最佳实战(二)

    基于 abp vNext 和 .NET Core 开发博客项目 - 定时任务最佳实战(二) 转载于:https://github.com/Meowv/Blog 本篇继续来完成一个全网各大平台的热点新闻 ...

  9. 基于蘑菇博客建设个人SNS网站(二)--后台框架搭建

    在github/gitee上面有很多别人写好的开源框架,选择适合的可以很大的减少开发人员的工作,我的网站用的是gitee上面的明星项目mogu博客,这里是项目地址:https://gitee.com/ ...

最新文章

  1. 基于matlab_simulink的捷联惯性导航系统仿真,基于MATLAB/Simulink的捷联惯性导航系统仿真...
  2. Metasploit编码模块技巧
  3. Hadoop详解(六):MapReduce计算框架详解
  4. MaxCompute Studio使用心得系列3——可视化分析作业运行
  5. 前端 JavaScript 之『节流』的简单代码实现
  6. 蓝牙学习笔记(八)——BLE 4.0 的128Bits/32Bist/16Bits的UUID
  7. C语言:从键盘输入三个数,求最值问题
  8. 显示水晶报表的公用类
  9. 笔记本电脑触摸板操作
  10. element-ui表格的滚动条样式修改(当固定table表格高度时默认滚动条样式太丑)
  11. js检测键盘组合键,禁止F12
  12. 美团外卖【成都】技术团队,招人啦!
  13. 工具 | RaiDrive—将网盘映射为磁盘
  14. 【读书笔记】《贫穷的本质》- [印度] Abhijit Banerjee / [法] Esther Duflo
  15. 【Virtual Box】使用增强功能在Ubuntu系统实现共享文件夹、共享复制粘贴、主机间拖放文件
  16. python是一种什么类型的植物_「蕨类植物」是一种什么类型的植物?
  17. JS 数字 、中文、 英文、判断
  18. Unable to render this definition
  19. 解决 MySQL 5.7.9版本sql_mode=only_full_group_by问题
  20. hp服务器 固件更新网站,hp服务器固件升级

热门文章

  1. 大多数人不知道淘宝天猫有内部优惠卷,能省钱的公众号,购物省钱妙招
  2. 岩板铺地好吗_卧室铺地板还是瓷砖好 这里给你答案
  3. 《麦肯锡教给我的写作武器》摘录
  4. 育儿心得,所有适龄女青年都该看一下
  5. Shell 脚本进阶,经典用法及其案例
  6. JAVA生成纯色背景图-自定义大小-自定义颜色
  7. “搬砖”机器人两天盖一栋房?泥瓦匠表示很心累
  8. SpringMVC接受参数
  9. 【2019 NWERC - E】Expeditious Cubing 【★】
  10. 计算机工作室名字大全,设计工作室名字(精选300个)