zoukankan      html  css  js  c++  java
  • php源码建博客4--实现MVC结构微型框架

    主要:

    1. 常量优化路径
    2. 自动加载类
    3. 优化入口文件
    4. 安全访问项目目录

    --------------文件结构:--------------------------------------
    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 master
    2 $ 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 public
    10      */
    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 -A
    2 $  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 void
    74      */
    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 <?php
    2 /**
    3  * 入口文件
    4  */
    5 
    6 require_once './Frame/Init.class.php';
    7 Init::run();

    3) 提交代码

    1 $  git add -A
    2 $  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 ..  这个是比较灵活的,可以根据需求选择更加合适的方式

      实际上线项目,还是建议使用框架,安全快捷; 自己模仿定义的框架结构适合学习研究使用,容易遗漏,造成安全隐患,操作不便等问题

    下一步:根据博客前端模板,分析创建数据表, 开始搭建博客后台程序,后续首先准备实现 “分类模块”。既分类的展示,修改,添加,删除功能

  • 相关阅读:
    python基础:内置函数zip,map,filter
    python基础:网络编程
    python基础:异常捕捉
    jQuery demo
    day14 jQuery
    day13 JS Dom
    页面垂直方向出现两个滚动条问题?
    修复npm ERR! cb()never called!的错误;This is an error with npm itself. Please report this error at:
    vue——解决“You may use special comments to disable some warnings. Use // eslint-disable-next-line to ignore the next line. Use /* eslint-disable */ to ignore all warnings in a file. ” eslint报错,取消文件的rules
    原型链
  • 原文地址:https://www.cnblogs.com/yangp67/p/9262793.html
Copyright © 2011-2022 走看看