主要:
- 常量优化路径
- 自动加载类
- 优化入口文件
- 安全访问项目目录
--------------文件结构:--------------------------------------blog
├─App
│ ├─Model 模型
│ │ └─UserModel.class.php 用户模型类
│ ├─View 视图
│ │ ├─Back后台
│ │ │ └─Index
│ │ │ └─index.html 后台首页面
│ │ └─Home前台
│ │ └─User 用户视图目录
│ │ └─login.html 登录表单页面
│ ├─Controller 控制器
│ │ ├─Back后台
│ │ │ └─IndexController.class.php 后台首页控制器
│ │ └─Home前台
│ │ └─UserController.class.php 用户控制器
├─Public 静态公共文件(js,css,images)
│ ├─Plugins 插件
│ │ └─layui 前端框架插件
│ ├─Back后台
│ │ ├─js/ js文件
│ │ ├─css/ css样式文件
│ │ └─image img图片
│ └─Home前台
│ ├─js/ js文件
│ ├─css/ css样式文件
│ └─image img图片
├─Frame 公共使用的类
│ ├─BaseModel.class.php 数据库连接类
│ ├─BaseController.class.php 控制器公共操作(设置编码,信息跳转)
│ ├─FactoryModel.class.php 模型工厂类
│ ├─Init.class.php 初始化应用类
│ └─MySQLDB.class.php 数据库操作工具类
└─index.php 入口文件-----------------------------------------------------------------
上一篇中,提出4个问题待解决,本篇集中解决这4个问题,最终形成完整的微型MVC框架结构, 后续博客项目,或其他项目,均可以直接使用该框架结构进行开发学习。
下载查看该项目源码: https://gitee.com/NewbiesYang/young_blog
常量优化路径
准备: 创建分支
1 $ git checkout master2 $ git checkout -b "MVC"
思路
1)把常用的目录路径定义成常量。如 模型目录,控制器目录等
2)引入类使用定义的常量替代部分路径。 如 include FRAME.BaseModel.class.php
3) 载入视图使用常量替代部分路径 如 include VIEW.‘login.html‘ 简单形式
代码实现
1)操作步骤
step 1: 在入口文件中定义所需要的常量step 2: 控制器中引入视图时, 使用常量进行优化
2) 入口文件中定义常用路径常量 【index.php】
1 <?php 2 /** 3 ?* 入口文件 4 ?*/ 5 $p = !empty($_GET[‘p‘]) ? $_GET[‘p‘] : ‘Home‘; ?//平台 6 $c = !empty($_GET[‘c‘]) ? $_GET[‘c‘] : ‘User‘; ?//控制器 7 $a = !empty($_GET[‘a‘]) ? $_GET[‘a‘] : ‘login‘; //动作 8 ?9 define(‘PLAT‘, $p); ?//平台常量10 define(‘CTR‘, $c); ?//控制器11 define(‘ACTION‘, $a); //动作12 13 14 define(‘DS‘, DIRECTORY_SEPARATOR); //目录分割符15 define(‘ROOT‘, getcwd().DS); ?//当前所在目录 项目目录16 define(‘FRAME‘, ROOT.‘Frame‘.DS);17 define(‘APP‘, ROOT.‘App‘.DS);18 define(‘PUB‘, ROOT.‘Public‘.DS);19 define(‘ADMIN‘, PUB.‘Admin‘.DS);20 define(‘HOME‘, PUB.‘Home‘.DS);21 22 //MVC目录23 define(‘MODEL‘, APP.‘Model‘.DS);24 define(‘VIEW‘, APP.‘View‘.DS.PLAT.DS.CTR.DS);25 define(‘CTRONLLER‘, APP.‘Controller‘.DS.PLAT.DS);26 27 $ctr = $c."Controller";28 29 require_once FRAME.‘Db.class.php‘; ?//数据库操作类30 require_once FRAME.‘BaseModel.class.php‘; ?//基础模型类31 require_once MODEL.‘UserModel.class.php‘; ?//用户模型类32 require_once FRAME.‘FactoryModel.class.php‘;//模型工厂类33 require_once FRAME.‘BaseController.class.php‘; //基础控制器类34 require_once CTRONLLER.$ctr.‘.class.php‘;35 36 37 //实例化控制器38 $userCtr = new $ctr();39 40 $userCtr -> $a();
2) 常量的使用:
后台首页控制器【App/Controller/Admin/IndexController.class.php】
1 <?php 2 /** 3 ?* IndexController控制器类 4 ?* 后台相关操作 5 ?* User: young 6 ?*/ 7 ?8 class IndexController extends BaseController 9 {10 ????//展示后台首页11 ????public function index()12 ????{13 ????????include VIEW.‘index.html‘;14 ????}15 }
用户控制器 登录视图引入路径【App/Controller/Home/UserController.class.php】
1 <?php 2 /** 3 ?* UserController.class.php 用户控制器 4 ?*/ 5 ?6 class UserController ?extends ?BaseController{ 7 ????/** 8 ?????* 展示登录界面 9 ?????* @access public10 ?????*/11 ????public function login()12 ????{13 ????????include VIEW."login.html";14 ????}15 。。。16 。。。17 。。。
3)提交代码
$ ?git add -A$ ?git commit -m "常量使用"
自动加载类
思路
问题: 入口文件中已经require_once 引入6个类,既增加一个需要引入一个,容易遗漏,重复和出错。
解决方法:自动加载类文件
方式1: 使用自动加载类函数__autoload()可以实现自动加载
方式2: 实际项目中,多人开发,根据实用性,更多的是使用 sql_autoload_register()注册函数自动加载
根据目录的特点实现自动加载
Model类文件特点,以Model结尾的类名 substr($className,-5)
Controller文件特点: 以Controller结尾的类名, substr($class,-10)
公共类: 类名没有统一形式,可以将Fame下的公共类放入到数组中,然后判断类是否在数组中, 从而自动加载该目录下的类文件
代码实现
1) 入口文件实现类的自动加载
1 <?php 2 /** 3 ?* 入口文件 4 ?*/ 5 $p = !empty($_GET[‘p‘]) ? $_GET[‘p‘] : ‘Home‘; ?//平台 6 $c = !empty($_GET[‘c‘]) ? $_GET[‘c‘] : ‘User‘; ?//控制器 7 $a = !empty($_GET[‘a‘]) ? $_GET[‘a‘] : ‘login‘; //动作 8 ?9 define(‘PLAT‘, $p); ?//平台常量10 define(‘CTR‘, $c); ?//控制器11 define(‘ACTION‘, $a); //动作12 13 14 define(‘DS‘, DIRECTORY_SEPARATOR); //目录分割符15 define(‘ROOT‘, getcwd().DS); ?//当前所在目录 项目目录16 define(‘FRAME‘, ROOT.‘Frame‘.DS);17 define(‘APP‘, ROOT.‘App‘.DS);18 define(‘PUB‘, ROOT.‘Public‘.DS);19 define(‘ADMIN‘, PUB.‘Admin‘.DS);20 define(‘HOME‘, PUB.‘Home‘.DS);21 22 //MVC目录23 define(‘MODEL‘, APP.‘Model‘.DS);24 define(‘VIEW‘, APP.‘View‘.DS.PLAT.DS.CTR.DS);25 define(‘CTRONLLER‘, APP.‘Controller‘.DS.PLAT.DS);26 27 $ctr = $c."Controller";28 29 spl_autoload_register(‘autoload‘); //注册自动加载函数30 //自动加载类31 /**32 ?* 实自动加载类文件33 ?* @param ?string $className 类名34 ?*/35 function autoload($className)36 {37 ????$upperClassName = strtoupper($className);38 ????$frame = array(‘BaseController‘,‘BaseModel‘,‘Db‘,‘FactoryModel‘);39 ????if(in_array($className, $frame)) { ?//加载公共Frame目录中的类文件40 ????????require_once FRAME."$className.class.php";41 ????} elseif(substr($upperClassName, -5) == ‘MODEL‘){ ?//加载模型Model目录中的类文件42 ????????require_once MODEL."$className.class.php";43 ????} elseif(substr($upperClassName, -10) == ‘CONTROLLER‘){ ?//加载控制器目录中的类文件44 ????????require_once CTRONLLER."$className.class.php";45 ????}46 }47 48 //实例化控制器49 $userCtr = new $ctr();50 $userCtr -> $a();
2) 提交代码
1 $ ?git add -A2 $ ?git commit -m "自动加载类完成"
优化入口文件
思路
问题: 此时,入口文件代码零碎增多,随着后续代码的增加,入口文件会更加臃肿复杂,不易管理
解决方法: 封装入口文件中的操作称为一个类,这样只需要在入口文件调用类的方法即可
创建Init.class.php类文件,放入到Frame中
将入口文件所有操作封装成类方法
loadClass() 设置自动加载函数
autoload()自动加载类
setConst() 定义常量
dispatch() 前端分发器
代码实现
1) 在Frame目录中创建Init.class.php文件, 将入口文件index中的代码复制进行修改为类
【Frame/Init.class.php】
1 <?php 2 /** 3 ?* 应用初始化操作类 4 ?* User: young 5 ?*/ 6 ?7 class Init 8 { 9 ????protected static $frame = array(‘BaseController‘,‘BaseModel‘,‘Db‘,‘FactoryModel‘); //Frame目录公共操作类10 ????public static function run()11 ????{12 ????????//平台13 ????????self::dispatch();14 15 ????????//定义常量16 ????????self::setConst();17 18 ????????//自动加载类19 ????????self::loadClass();20 21 ????????$ctr = CTR."Controller"; ?//拼接控制器名称22 23 ????????//实例化控制器24 ????????$ctrObj = new $ctr();25 ????????$a = ACTION;26 ????????$ctrObj -> $a();27 ????}28 ????/**29 ?????* 设置自动加载类方法30 ?????*/31 ????private static function loadClass()32 ????{33 ????????spl_autoload_register(‘self::autoload‘);34 ????}35 36 ????/**37 ?????* 实现自动加载38 ?????* @param ?string $className 类名39 ?????*/40 ????private static function autoload($className)41 ????{42 ????????$upperClassName = strtoupper($className);43 ????????if(in_array($className, static::$frame)) {44 ????????????require_once FRAME."$className.class.php";45 ????????} elseif(substr($upperClassName, -5) == ‘MODEL‘){46 ????????????require_once MODEL."$className.class.php";47 ????????} elseif(substr($upperClassName, -10) == ‘CONTROLLER‘){48 ????????????require_once CTRONLLER."$className.class.php";49 ????????}50 ????}51 52 ????/**53 ?????* 定义常量54 ?????*/55 ????private static function setConst()56 ????{57 ????????define(‘DS‘, DIRECTORY_SEPARATOR); //目录分割符58 ????????define(‘ROOT‘, getcwd().DS);59 ????????define(‘FRAME‘, ROOT.‘Frame‘.DS);60 ????????define(‘APP‘, ROOT.‘App‘.DS);61 ????????define(‘PUB‘, ROOT.‘Public‘.DS);62 ????????define(‘ADMIN‘, PUB.‘Admin‘.DS);63 ????????define(‘HOME‘, PUB.‘Home‘.DS);64 65 66 ????????define(‘MODEL‘, APP.‘Model‘.DS);67 ????????define(‘VIEW‘, APP.‘View‘.DS.PLAT.DS.CTR.DS);68 ????????define(‘CTRONLLER‘, APP.‘Controller‘.DS.PLAT.DS);69 ????}70 71 ????/**72 ?????* 获取 p c a 的GET值,并设置为常量73 ?????* @return void74 ?????*/75 ????private static function dispatch()76 ????{77 ????????$p = !empty($_GET[‘p‘]) ? $_GET[‘p‘] : ‘Home‘; ?//平台78 ????????$c = !empty($_GET[‘c‘]) ? $_GET[‘c‘] : ‘User‘; ?//控制器79 ????????$a = !empty($_GET[‘a‘]) ? $_GET[‘a‘] : ‘login‘; //动作80 81 ????????define(‘PLAT‘, $p);82 ????????define(‘CTR‘, $c);83 ????????define(‘ACTION‘, $a);84 ????}85 }
2) 入口文件引入初始化类,并调用其方法 【index.php】
1 <?php2 /**3 ?* 入口文件4 ?*/5 6 require_once ‘./Frame/Init.class.php‘;7 Init::run();
3) 提交代码
1 $ ?git add -A2 $ ?git commit -m "优化入口文件,封装初始化类"
安全访问项目目录
思路
问题: 此时,项目中所有目录都是可以通过浏览器访问的,如直接访问Frame/Db.class.php文件 直接可以去查看数据库登录信息,显然是不安全的。
解决方法:
方式1: 在可以访问的文件开始处定义常量,访问是判断是否定义常量defined(..), 没有定义指定常量则直接exit(‘Access Deny‘);
方式2: 开启分布式权限配置,编写.htaccess文件, 如禁止访问, 将该文件放置在禁止访问的目录中
实现
1)使用上述方式2的形式来实现, 站点配置中加入一项(环境搭建时已经加入了): 详细见: PHP源码搭建博客1-环境搭建
apache配置文件httpd-vhosts.conf 中站点配置
1 ?#允许分布式权限配置(允许重写)(.htacess)2 ??AllowOverride All
2) 重启apache后,编写 .htaccess文件, 该文件内容:
deny from all
3) 将.htaccess文件放置禁止访问的目录中。 如App/ , Frame/ 目录下。只用放在第一层即可,内层目录自动不允许直接访问。
4) 访问测试
小结:
主要实现了 引入路径优化, 类的自动加载, 封装优化入口文件,目录访问限制
MVC微型框架到此基本完成。其实还有很多还是可以继续扩展,如
1, 类文件命名此处都用了 .class.php结尾, 实质可以优化直接使用.php结尾
2, 引入命名空间,更方便的加载类
3, 项目中出现错误,此时是直接显示在浏览器上的, 可以写一个日志类,发生错误写入文件或数据库都可
4, 数据库连接信息此处是直接写在DB类和BaseModel中了, 是不安全的。 可以创建一个配置目录,将这些信息写入配置文件,再写一个加载配置文件的类。
5. 此架构目录 ,是在C,V中分平台,如Controller/Home, Controller/Admin; 实际也可以写成 平台下分MVC结构, 如Admin/Controller, Admin/Model, Home/Controller,Home/View .. 这个是比较灵活的,可以根据需求选择更加合适的方式
实际上线项目,还是建议使用框架,安全快捷; 自己模仿定义的框架结构适合学习研究使用,容易遗漏,造成安全隐患,操作不便等问题
下一步:根据博客前端模板,分析创建数据表, 开始搭建博客后台程序,后续首先准备实现 “分类模块”。既分类的展示,修改,添加,删除功能
php源码建博客4--实现MVC结构微型框架
原文地址:https://www.cnblogs.com/yangp67/p/9262793.html