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 ..  這個是比較靈活的,可以根據需求選擇更加合適的方式

  實際上線項目,還是建議使用框架,安全快捷; 自己模仿定義的框架結構適合學習研究使用,容易遺漏,造成安全隱患,操作不便等問題

下一步:根據博客前端模板,分析創建數據表, 開始搭建博客后台程序,后續首先准備實現 “分類模塊”。既分類的展示,修改,添加,刪除功能


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM