Ps:乡下过年回来神清气爽啊~~闲得蛋疼看看简单的框架实现。
另外也有个小小的计划了先….任何问题请轻拍。
第一遍站在开发的角度来读,主要是看功能如何实现。
第二遍站在安全的角度来读,主要是发现这样的写法有何不安全又有何好处。
当前进行:
*akcms
*kiwiphp(号称门户级的框架 – -)
计划中的:
1.Discuz(大型论坛)
2.phpbb(轻量级论坛)
3.Wordpress(传统PHP写法的Blog)
4.ThinkPHP(MVC轻量级框架的实现方式)
======================================开始-蛋疼的分割线======================================
目录结构:
│ index.php
│
└─brophp
│ brophp.php
│
├─bases — 核心类
│
├─classes — 常用方法类
│
├─commons
│ functions.inc.php
│ success
│
└─libs — smarty类
———————————————————————————————–
Index.php:
define(“BROPHP”, “./brophp”); //框架源文件的位置
define(“APP”, “./”); //设置当前应用的目录
require(BROPHP.’/brophp.php’); //加载框架的入口文件
一个单一入口,几乎所有的框架都是这么搞貌似,至少thinkphp是这么来的。
———————————————————————————————–
brophp.php:
header(“Content-Type:text/html;charset=utf-8″); //设置系统的输出字符为utf-8
date_default_timezone_set(“PRC”); //设置时区(中国)
/* 这里没啥好说的,设定编码和市区 */
define(“BROPHP_PATH”, rtrim(BROPHP, '/’).’/’); //BroPHP框架的路径
define(“APP_PATH”, rtrim(APP,’/’).’/’); //用户项目的应用路径
define(“PROJECT_PATH”, dirname(BROPHP_PATH).’/’); //项目的根路径,也就是框架所在的目录
define(“TMPPATH”, str_replace(array(“.”, “/”), “_”, ltrim($_SERVER["SCRIPT_NAME"], '/’)).”/”);
//script_name = /brophp/index.php
//包含系统配置文件
$config=PROJECT_PATH.”config.inc.php”;
if(file_exists($config)){
include $config;
}
//存在config.inc.php就包含,框架第一次运行会自动创建项目所需要的文件。
//设置Debug模式
if(defined(“DEBUG”) && DEBUG==1){
$GLOBALS["debug"]=1; //初例化开启debug
error_reporting(E_ALL ^ E_NOTICE); //输出除了注意的所有错误报告
include BROPHP_PATH.”bases/debug.class.php”; //包含debug类
Debug::start(); //开启脚本计算时间
set_error_handler(array(“Debug”, 'Catcher’)); //设置捕获系统异常
}else{
ini_set('display_errors’, 'Off’); //屏蔽错误输出
ini_set('log_errors’, 'On’); //开启错误日志,将错误报告写入到日志中
ini_set('error_log’, PROJECT_PATH.’runtime/error_log’); //指定错误日志文件
}
/* 设定调试的相关信息 注释也很详细了 */
//包含框架中的函数库文件
include BROPHP_PATH.’commons/functions.inc.php’;
//包含全局的函数库文件,用户可以自己定义函数在这个文件中
$funfile=PROJECT_PATH.”commons/functions.inc.php”;
if(file_exists($funfile))
include $funfile;
/* 如果项目中存在的话,就会包括 commons/functions.inc.php 结合第一次自动创建项目文件,您懂得*/
//设置包含目录(类所在的全部目录), PATH_SEPARATOR 分隔符号 Linux(:) Windows(;)
$include_path=get_include_path(); //原基目录
$include_path.=PATH_SEPARATOR.BROPHP_PATH.”bases/”; //框架中基类所在的目录
$include_path.=PATH_SEPARATOR.BROPHP_PATH.”classes/” ; //框架中扩展类的目录
$include_path.=PATH_SEPARATOR.BROPHP_PATH.”libs/” ; //模板Smarty所在的目录
$include_path.=PATH_SEPARATOR.PROJECT_PATH.”classes/”; //项目中用的到的工具类
$controlerpath=PROJECT_PATH.”runtime/controls/”.TMPPATH; //生成控制器所在的路径
$include_path.=PATH_SEPARATOR.$controlerpath; //当前应用的控制类所在的目录
/* get_include_path为PHP函数,此处就是框架所在目录了,加上分隔符放到$include_path变量中 */
set_include_path($include_path);
/* 包含前面所有的文件,见PHP手册代码:
$path = '/usr/lib/pear’;
set_include_path(get_include_path() . PATH_SEPARATOR . $path);
*/
//自动加载类
function __autoload($className){
if($className==”memcache”){ //如果是系统的Memcache类则不包含
return;
}else if($className==”Smarty”){ //如果类名是Smarty类,则直接包含
include “Smarty.class.php”;
}else{ //如果是其他类,将类名转为小写
include strtolower($className).”.class.php”;
}
Debug::addmsg(“ $className 类”, 1); //在debug中显示自动包含的类
}
/* 然后用__autoload魔术函数自动按类名加载类,如果加载错误的话会利用debug类来输出加载错误的类文件 */
//判断是否开启了页面静态化缓存
if(CSTART==0){
Debug::addmsg(“没有开启页面缓存!(但可以使用)”);
}else{
Debug::addmsg(“开启页面缓存,实现页面静态化!”);
}
//启用memcache缓存
if(!empty($memServers)){
//判断memcache控制是否安装
if(class_exists(“memcache”)){
$mem=new MemcacheModel($memServers);
//判断Memcache服务器是否有异常
if(!$mem->mem_connect_error()){
Debug::addmsg(“连接memcache服务器失败,请检查!”); //debug
}else{
define(“USEMEM”,true);
Debug::addmsg(“启用了Memcache”);
}
}else{
Debug::addmsg(“PHP没有安装memcache扩展模块,请先安装!”); //debug
}
}else{
Debug::addmsg(“没有使用Memcache(为程序的运行速度,建议使用Memcache)”); //debug
}
//如果Memcach开启,设置将Session信息保存在Memcache服务器中
if(defined(“USEMEM”)){
MemSession::start($mem->getMem());
Debug::addmsg(“开启会话Session (使用Memcache保存会话信息)”); //debug
}else{
session_start();
Debug::addmsg(“开启会话Session (但没有使用Memcache,开启Memcache后自动使用)”); //debug
}
/* memcache的相关设定,由于我这个也用得比较少,所以暂时先不看吧 */
Structure::create(); //初使化时,创建项目的目录结构
Prourl::parseUrl(); //解析处理URL
/* 入口点二三,需要详细再看的地方 */
//模板文件中所有要的路径,html\css\javascript\image\link等中用到的路径,从WEB服务器的文档根开始
$spath=dirname($_SERVER["SCRIPT_NAME"]);
if($spath==”/” || $spath==”\\”)
$spath=””;
$GLOBALS["root"]=$spath.’/’; //Web服务器根到项目的根
$GLOBALS["app"]=$_SERVER["SCRIPT_NAME"].’/’; //当前应用脚本文件
$GLOBALS["url"]=$GLOBALS["app"].$_GET["m"].’/’; //访问到当前模块
$GLOBALS["public"]=$GLOBALS["root"].’public/’; //项目的全局资源目录
$GLOBALS["res"]=$GLOBALS["root"].ltrim(APP_PATH, './’).”views/”.TPLSTYLE.”/resource/”; //当前应用模板的资源
//控制器类所在的路径
$srccontrolerfile=APP_PATH.”controls/”.strtolower($_GET["m"]).”.class.php”;
Debug::addmsg(“当前访问的控制器类在项目应用目录下的: $srccontrolerfile 文件!”);
//控制器类的创建
if(file_exists($srccontrolerfile)){
Structure::commoncontroler(APP_PATH.”controls/”,$controlerpath);
Structure::controler($srccontrolerfile, $controlerpath, $_GET["m"]);
$className=ucfirst($_GET["m"]).”Action”;
$controler=new $className();
$controler->run();
}else{
Debug::addmsg(“对不起!你访问的模块不存在,应该在”.APP_PATH.”controls目录下创建文件名为”.strtolower($_GET["m"]).”.class.php的文件,声明一个类名为”.ucfirst($_GET["m"]).”的类!”);
}
/* 通过GET方法开始取控制器类并进行初始化等创建工作,如果出错就提示错误信息 */
//设置输出Debug模式的信息
if(defined(“DEBUG”) && DEBUG==1 && $GLOBALS["debug"]==1){
Debug::stop();
Debug::message();
}
———————————————————————————————–
框架中的commons/functions.inc.php:
p函数主要用于友好的输出调试信息,比如变量等是var_dump函数的封装
D函数用于手动实例化一个类
tosize函数是一个字节转换函数
———————————————————————————————–
然后开始批量包含文件
├─bases
│ action.class.php //继承于MyTpl是控制器的基类
│ db.class.php //抽象类DB,数据库相关操作的基类
│ debug.class.php //各种调试的基类
│ dmysqli.class.php //继承于DB类,数据库的mysqli驱动类
│ dpdo.class.php //继承于DB类,数据库的pdo扩展类
│ memcachemodel.class.php //memcache类,缓存SQL语句
│ memsession.class.php //memcache类,缓存session
│ mytpl.class.php //继承于smarty类,初始化smarty成员方法等
│ prourl.class.php //url解析类
│ structure.class.php //structure类用于自动创建项目等(文件操作相关函数可以看这里)
│ validate.class.php //validate类用于检测数据有效性(xml相关操作,通过解析xml来配置验证方式)
———————————————————————————————–
├─classes
│ fileupload.class.php //继承于Image类,用于文件上传
│ image.class.php //图片处理类,加水印与缩放等操作
│ page.class.php //分页类
│ vcode.class.php //验证码类
———————————————————————————————–
└─libs
│ Config_File.class.php
│ debug.tpl
│ Smarty.class.php
│ Smarty_Compiler.class.php
/* smarty */
———————————————————————————————–
批量包含文件完成之后,进行了memcache的相关操作,这里我还没有学习过,所以暂时先不看了。
接下来是调用了两个类中不同的函数。他们是
Structure::create(); //初使化时,创建项目的目录结构
Prourl::parseUrl(); //解析处理URL
———————————————————————————————–
Structure::create()位于bases/structure.class.php文件中:
此类没有构造函数,create函数是一个静态函数,代码省略部分
static function create(){
self::mkdir(array(PROJECT_PATH.”runtime/”));
//文件锁,一旦生成,就不再创建
$structFile=PROJECT_PATH.”runtime/”.str_replace(“/”,”_”,$_SERVER["SCRIPT_NAME"]); //主入口文件名
if(!file_exists($structFile)) {
$fileName=PROJECT_PATH.”config.inc.php”;
$str=<<
……
st;
self::touch($fileName, $str);
递归调用mkdir函数,此函数循环判断$dirs数组并检测是否已经创建,输出提示信息。
先判断项目目录结构是否创建,没创建则先创建config.inc.php文件(<<
接下来给$dirs赋值,判断debug标记,并且包含刚刚创建的config.inc.php文件
省略部分代码一次类推,最后调用自身类中的 runtime()函数创建项目目录
———————————————————————————————–
Prourl::parseUrl()函数位于bases/prourl.class.php文件中:
此类没有构造函数,parseURL是一个静态函数,代码如下
if (isset($_SERVER['PATH_INFO'])){
//获取 pathinfo
$pathinfo = explode('/’, trim($_SERVER['PATH_INFO'], “/”));
// 获取 control
$_GET['m'] = (!empty($pathinfo[0]) ? $pathinfo[0] : 'index’);
array_shift($pathinfo); //将数组开头的单元移出数组
// 获取 action
$_GET['a'] = (!empty($pathinfo[0]) ? $pathinfo[0] : 'index’);
array_shift($pathinfo); //再将将数组开头的单元移出数组
for($i=0; $i
$_GET[$pathinfo[$i]]=$pathinfo[$i+1];
}
}else{
$_GET["m"]= (!empty($_GET['m']) ? $_GET['m']: 'index’); //默认是index模块
$_GET["a"]= (!empty($_GET['a']) ? $_GET['a'] : 'index’); //默认是index动作
if($_SERVER["QUERY_STRING"]){
$m=$_GET["m"];
unset($_GET["m"]); //去除数组中的m
$a=$_GET["a"];
unset($_GET["a"]); //去除数组中的a
$query=http_build_query($_GET); //形成0=foo&1=bar&2=baz&3=boom&cow=milk格式
//组成新的URL
$url=$_SERVER["SCRIPT_NAME"].”/{$m}/{$a}/”.str_replace(array(“&”,”=”), “/”, $query);
header(“Location:”.$url);
}
}
ps:待细看…
———————————————————————————————–
同时在操作控制器类时候调用了Structure::commoncontroler和Structure::controler,我们再回到
structure.class.php文件中看看他们是如何工作的:
static function commoncontroler($srccontrolerpath,$controlerpath){
$srccommon=$srccontrolerpath.”common.class.php”;
$common=$controlerpath.”common.class.php”;
//如果新控制器不存在, 或原控制器有修改就重新生成
if(!file_exists($common) || filemtime($srccommon) > filemtime($common)){
copy($srccommon, $common);
}
}
如果原项目目录(框架目录)中存在controls/common.class.php,且新项目路没得就拷贝过去。
static function controler($srccontrolerfile,$controlerpath,$m){
$controlerfile=$controlerpath.strtolower($m).”action.class.php”;
//如果新控制器不存在, 或原控制器有修改就重新生成
if(!file_exists($controlerfile) || filemtime($srccontrolerfile) > filemtime($controlerfile)){
//将控制器类中的内容读出来
$classContent=file_get_contents($srccontrolerfile);
//看类中有没有继承父类
$super=’/extends\s+(.+?)\s*{/i’;
//如果已经有父类
if(preg_match($super,$classContent, $arr)) {
$classContent=preg_replace('/class\s+(.+?)\s+extends\s+(.+?)\s*{/i’,’class \1Action extends \2 {',$classContent);
//新生成控制器类
file_put_contents($controlerfile, $classContent);
//没有父类时
}else{
//继承父类Common
$classContent=preg_replace('/class\s+(.+?)\s*{/i’,’class \1Action extends Common {',$classContent);
//生成控制器类
file_put_contents($controlerfile,$classContent);
}
}
}
也是用于生成项目中的控制器类的函数的,有详细注释。
———————————————————————————————–
基本上bropphp.php的几个关键地方都看完了,这也算是框架的入口点,这时访问index.php结合刚才阅读
structrue.class.php中的相关函数,框架就会自动创建项目所需的文件和目录结构了(和ThinkPHP好像~)
创建目录 ./runtime/ 成功.
创建文件 ./config.inc.php 成功.
创建目录 ./classes/ 成功.
创建目录 ./commons/ 成功.
创建目录 ./public 成功.
创建目录 ./public/uploads/ 成功.
创建目录 ./public/css/ 成功.
创建目录 ./public/js/ 成功.
创建目录 ./public/images/ 成功.
创建目录 ./models/ 成功.
创建目录 ./controls/ 成功.
创建目录 ./views/ 成功.
创建目录 ./views/default 成功.
创建目录 ./views/default/public/ 成功.
创建目录 ./views/default/resource/ 成功.
创建目录 ./views/default/resource/css/ 成功.
创建目录 ./views/default/resource/js/ 成功.
创建目录 ./views/default/resource/images/ 成功.
创建文件 ./commons/functions.inc.php 成功.
创建文件 ./controls/common.class.php 成功.
创建文件 ./controls/index.class.php 成功.
———————————————————————————————–
项目目录结构如下:
│ config.inc.php
│ index.php
│
├─classes
├─commons
│ functions.inc.php
│
├─controls
│ common.class.php
│ index.class.php
│
├─models
├─public
│ ├─css
│ ├─images
│ ├─js
│ └─uploads
├─runtime
│ │ error_log
│ │ _brophp_index.php
│ │
│ ├─cache
│ │ └─default
│ ├─comps
│ │ └─default
│ │ └─brophp_index_php
│ ├─controls
│ │ └─brophp_index_php
│ │ common.class.php
│ │ indexaction.class.php
│ │
│ ├─data
│ └─models
│ └─brophp_index_php
└─views
└─default
├─public
│ success.tpl
│
└─resource
├─css
├─images
└─js
———————————————————————————————–
(话说还有action等基本操作没有分析的啊…下回再慢慢看吧….)
———————————————————————————————–
可以说基本该分好都分好,至于什么用它创建项目,框架中有无漏洞等,就等下回继续分解了。
有空再看吧。虽说是发现了类似思想,是eval使用函数而导致的,下回分解欢迎拍砖. :0