`

PHP大型Web应用入门(一) [转]

阅读更多

这里所说的“大型”应用不是说像Google、eBay、Yahoo这类大型网站的具体实施,我也没有意图劝说读者放弃自己的概念和信仰,只是希望大家的系统可以运行得更快更流畅,可以承载更多的用户在线,希望可以给PHP的初学者一点帮助。
关于PHP的执行效率,网上的专题文章很多,多以PHP、Java几个阵营的争论开始,以一个不确定的期待结束,很少看见一个明确的结论。确实,程序的执行效率是很难从比较中得出的。应用的方面不同,执行环境不同,效率的差别会差得比较大。而且效率也是需要权衡的,大家都知道汇编语言很底层,可以写出非常高效的程序,但是我还很少,应该说是几乎没看过有人用汇编做Web开发,而且有能力用汇编写出高效程序的人似乎都是值得大家仰视的,哈哈~我们没有必要去讨论PHP和汇编到底差多少,只要知道自己的PHP和别人的PHP差多少就可以了。

首先,先要明确这篇文章的前提:必须有一台或更多的可以被自己操纵的服务器,而不是虚拟主机空间。毕竟可以在虚拟主机上运行的通用系统已经有了很多经典的作品和成熟的框架,效率挖掘已经被前辈们做得非常出色了,它们的很多理念也被现在很多PHP用户继承和发展,越来越多的所谓“框架”也像满天繁星一样,我也不想再去写那个,因为第一我自己的水平也不怎么样,写不出什么新鲜玩意来,写出来也招人笑,第二是写这个的文章太多了,说法也太多了,混乱是造成很多富有激情的未来天才程序员夭折的最大元凶。
在独立服务器上执行的程序和在虚拟主机上可以运行的程序在效率优化方面有着很大差别。您当然可以把一套discuz不加修改地安装在一台甚至一堆独立服务器上,不过,它真的得到最大的性能优化吗,您真的对得起这一堆服务器吗?
独立服务器指的是,使用者对这台机器有完全的控制权,包括安装、删除软件,配置系统参数甚至修改源代码。基于这样一个开放的硬件平台,性能也不仅仅是体现在速度上,还包括安全性、稳定性等。和虚拟主机不同,用户必须自己配置Web服务器参数,安装和配置PHP、数据库,以及安装各种乱七八糟的东西(我喜欢这么说),当然还要对它们负责。

首先提出几个名词:执行时间、模板、数据库封装、Cache、Buffer、Hash、守护进程、crontab。
执行时间,谁都知道,就是一个程序从执行开始到执行结束所用的时间。因为Web是瞬时的、无状态的,所以执行时间是Web程序执行效率的一个指标,它并不适合衡量C/S程序或者后台守护的程序,因为它们很多都是持续运行的。页面执行时间的一个典型例子就是Discuz论坛页面最下方的时间显式,通常Discuz都是几毫秒到几十毫秒,和所用的平台、数据量和当前系统压力有关。
模板大家再熟悉不过,虽然有很多人只是在用,但是不知道为什么在用。模板在传统上来说是划分逻辑层的一种途径,在MVC上结构里,它把表示层和下层分离,在实际使用中,它方便程序员和界面设计人员分工合作。然而,现在很多场合中,由于模板的不当使用,它非但没有起到促进程序员和界面设计人员分工合作,反倒成为程序员和美工互相仇视的罪魁(我好像在以前的帖子里这样说过),很多人在抱怨他们不得不花很多时间在整理模板上。
数据库封装似乎和Java的关系更大,它对多种数据库系统提供一个统一调用接口,通常是一些封装好的类,这些类有时也完成一些比如SQL检查、过滤等工作。PHPLIB里的DB封装、PEAR DB、Adodb等都很有名,用的人也很多。
Cache和Buffer看起来好像是一种东西,Cache叫做缓存而Buffer叫做缓冲。在硬件概念中,Cache的用途是连接两种速度不同的设备,比如寄存器和内存、CPU和PCI-Bus、IDE总线和硬盘。Buffer的原意是类似弹簧的一种缓冲器,用来减轻或吸收冲击的震动的东西。Buffer是一种数据预存取的方式,它用于临时存储数据并以与接收速度不同的速度传输。Buffer的更新方式可以是按时间间隔自动刷新,而Cache则更讲究“命中率”,将当前时间段使用频繁的少量数据放到高速设备中方便读写。在程序开发中,固然没有什么高速、低速设备,不过数据源是可以有不同读写效率的。对于少量数据,文本文件的读写通常就要比数据库存取效率好,而同样是文本文件读写,在tmpfs上的效率就要比直接的磁盘IO效率好。Buffer更多地体现在进程通信和队列上,很多时候并不是因为接收方没有能力更快地读取,而是没有必要更快地读取。
守护进程是一种在后台连续执行的程序,它通常是起到监视、控制流程、对外提供服务等作用。比如Apache本身就可以被理解成一个守护进程,虽然它实际上是由很多个经常更新的进程组成(主进程是固定的)。
Crontab是UNIX/Linux的定时程序,有点像Windows的“计划任务”,它设定在多少个时间间隔后或者是某一个时间点执行特定的程序。它通常用来完成自动更新、清除临时数据等一段时间自动执行一次的操作。
另外一个比较特别的概念(说它特别是相对于习惯了通用系统开发的人来说),是当我们拥有了一台独立的服务器之后,完全没必要把自己局限在PHP所能提供的功能范围内,当我们不知不觉地成为系统的主人后,要努力发现到这一点,我们有很多东西可以用的。PHP不是万能的(这简直是一定的),对于它的功能上的不足,完全可以用Perl来弥补,Perl做为一种通用语言,可以提供更多的功能选择,砂砾一样密的模块给这个随意得有些变态的语言提供了无穷的能量。对于PHP性能上的不足,完全可以用C来补充。PHP的根本就是由C继承来,PHP本身也是由C开发,用C来做PHP的扩展是完全合理的。
Linux本身就是由C和Perl在支撑(我这样说完全不是为了夸大Perl的地位,大家可以去看看一个标准的Linux中有多少Perl脚本,离开Perl之后这个系统是不是觉得像个残疾人)。PHP从C中继承了大部分的语法,从Perl中学习了大部分Web特性、函数和那个貌似与开源很矛盾的“$”符号(PHP早期就是一个Perl脚本)。

我发现我很能写废话,哈哈……
下面来分析我在使用的一些代码(注:Linux独立服务器适用。我好像已经放弃对Windows和虚拟主机做大型开发很长时间了)。里面使用了一些也许很熟悉也许很陌生也许很变态的方法。我的系统是RedHat AS3,没有什么特别的,PHP版本是4.4.0,MySQL是4.1。我从来没有刻意地去写一些必须用到PHP5的新特性的代码,除非真的必须用到。
我的Web根目录在/www下,Apache、PHP都是默认安装在/usr/local/下,MySQL是下载的编译好的二进制版本,我也一样把它丢在那里。因为只是用于测试,我不想它看起来很乱,至于在实际项目中,尤其是多台服务器的情况下,需要好好地部署一下你的系统。
为了使系统的结构清晰一些,我把需要使用的文件都放在了二级目录下面。
下面是通用头文件/includes/kernel/common.inc.php的一些片断:



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

<?php
list( $usec ,  $sec ) =  explode ( " " ,  microtime ());
$page_time_start  =  $usec  +  $sec ;
?>
这两行大家可能都会比较熟悉,这是计算程序的开始执行时间的。在程序结束之前,还会再计算一下这个,为的是得出程序执行所耗费的时间。如果你不在意这些,可以放心地把它注释掉。

<?php
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(它常会带来危险并使人感到困惑),我们要把它随便设置的那些全局变量删掉。

<?php
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 );
?>
上面的一陀,显而易见,它在做转义过滤所有来自客户端的输入。

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

<?php
// 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文件


<?php
// 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中设置。

<?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 );
?>
创建成功后,记得把密码清空

<?php
// We do not need this any longer, unset for safety purposes
unset( $global_db_pass );
?>
创建日志对象

<?php
// Init Log
$log  = new  BsmLog  ( 'bsg' );
?>
这又是一个精彩部分,创建一个共享内存对象

<?php
// Init the Shared Memory
$shm  = new  BsmShm ;
if (
$shm -> shm_id ) {
    
define  ( 'SHM_SUPPORT' ,  true );
}
?>
如果系统是第一次运行,则在共享内存中标记一个运行标志SHM_VAR_SYS_RUN = true(系统的constants.inc.php是常量表,里面定义了系统要使用的常量)

<?php
if ( defined  ( 'SHM_SUPPORT' ) && !@ $shm -> get_var  ( SHM_VAR_SYS_RUN )) {
    
$shm -> put_var  ( SHM_VAR_SYS_RUN ,  true );
}
?>

分享到:
评论

相关推荐

    PHP从入门到精通

    除此之外,理解MVC(Model-View-Controller)设计模式对于构建大型Web应用至关重要。这种模式将业务逻辑、数据和用户界面分离,提高了代码的可读性和可维护性。框架如Laravel、Symfony和CodeIgniter等,都是基于MVC...

    PHP和MySQL Web开发第4版pdf以及源码

    16.5.4 Web应用的商业主机服务 16.6 数据库服务器的安全性 16.6.1 用户和权限系统 16.6.2发送数据至服务器 16.6.3 连接服务器 16.6.4 运行服务器 16.7 保护网络 16.7.1 安装防火墙 16.7.2使用隔离区域(DMZ) 16.7.3...

    PHP从入门到精通(第3版)完整高清版

    通过阅读《PHP从入门到精通(第3版)》这本书,读者将不仅能够掌握PHP编程的基本技能,还能了解到PHP在实际项目中的应用技巧,为成为一名熟练的PHP开发者奠定坚实的基础。书中的实例和练习题可以帮助读者巩固所学知识...

    php教程从入门到精通

    《PHP教程从入门到精通》知识点详析 一、PHP基础概述 PHP,全称超文本预处理器(Hypertext Preprocessor),是一种广泛使用的...无论是构建网站、开发API还是参与大型Web应用的开发,扎实的PHP基础都是不可或缺的。

    PHP精华教程 php入门提高的经典教材

    【PHP 知识点详解】 PHP(Hypertext Preprocessor,超文本预处理器)是一种广泛应用于Web开发的开源脚本语言,...无论你是要创建简单的动态页面,还是构建复杂的Web应用程序,PHP都有足够的能力和灵活性来满足需求。

    php初级入门教程

    从给定的文件信息中,我们可以提取到关于PHP初级入门教程的关键知识点,下面将详细解析这些知识点: ### PHP初级入门教程概述 ...无论是构建简单的个人网站还是复杂的Web应用,PHP都是一个值得信赖的选择。

    数据库MySQL入门.pdf

    1. WEB应用:MySQL是WEB应用方面最好的RDBMS应用软件之一。 2. 数据仓库:MySQL支持大型数据库,支持5000万条记录的数据仓库。 3. 企业级应用:MySQL是甲骨文公司旗下的产品,广泛应用于企业级软件开发中。 MySQL的...

    java web 从入门到放弃

    ### Java Web 从入门到放弃 #### 一、基本概念 ##### 1.1 Web 开发 - **静态 Web**:静态网页是指那些内容固定、不会根据用户的不同操作或访问而变化的网页。例如,纯 HTML 页面就是典型的静态网页。这类网页在...

    PHP5.3入门经典(Beginning PHP 5.3)源码+中文PDF+英文PDF

    这本书旨在帮助读者快速掌握PHP编程语言,从而能够开发出功能丰富的Web应用程序。源码文件和PDF版本的提供,无论是中文版还是英文版,都为学习者提供了方便的参考和实践资料。 PHP是一种广泛使用的开源服务器端脚本...

    PHP和MySQL Web开发(原书第4版)—源代码

    PHP的优点在于其灵活性和高效性,能够处理大量并发请求,是构建大型Web应用的理想选择。 MySQL则是一款流行的开源关系型数据库管理系统,以其高速、稳定和易于管理著称。它支持SQL标准,提供各种数据类型和索引选项...

    探索动态Web开发的基石-PHP:从入门到精通

    内容概要:本文全面介绍了PHP作为世界上最流行的服务器端脚本语言之一的地位和发展历程,覆盖了PHP的...本文旨在帮助开发者全方位地理解和运用PHP,无论是进行简单的小型项目还是大型的企业级应用开发,都能从中受益。

    PHP和MySQL WEB开发(第4版)

    16.5.4 Web应用的商业主机服务 16.6 数据库服务器的安全性 16.6.1 用户和权限系统 16.6.2发送数据至服务器 16.6.3 连接服务器 16.6.4 运行服务器 16.7 保护网络 16.7.1 安装防火墙 16.7.2使用隔离区域(DMZ) 16.7.3...

    php 入门教程.docx

    - **意义**:这样的设计确保了PHP能够适应不同类型的Web应用开发需求,提供了广泛的集成可能性。 5. **强大的功能** - **定义**:PHP不仅可以处理表单数据,还能生成动态页面,并且可以与数据库进行交互。 - **...

    PHP从入门到精通视频教程讲解

    - **项目搭建**:介绍如何从零开始搭建一个完整的Web应用项目。 - **用户认证系统**:实现用户注册、登录功能,包括表单验证、密码加密存储等。 - **会话管理**:session的工作原理及使用方法,如何在多个页面间共享...

    PHP快速入门与商用项目培训

    《PHP快速入门与商用项目培训》是一门专为PHP初学者设计的教程,旨在帮助学习者迅速掌握PHP Web开发的基础知识,并将所学应用于实际商业项目。PHP是一种广泛使用的开源脚本语言,尤其在Web开发领域,其简洁的语法和...

    php从入门到精通

    《PHP入门到精通》是一本全面且深入的教程,旨在...通过这个《PHP入门到精通》的学习,你将不仅能够编写简单的PHP脚本,还能具备开发大型Web项目的能力。不断实践和探索,才能真正精通PHP,成为一位优秀的Web开发者。

    PHP入门教程-自学必备

    本教程旨在为初学者提供一个全面且实用的PHP入门指南,帮助大家快速掌握PHP编程基础,实现从零开始到能够独立编写简单Web应用的转变。 一、PHP简介 PHP是一种服务器端的脚本语言,主要用于Web开发,可以嵌入HTML中...

Global site tag (gtag.js) - Google Analytics