php源碼建博客4--實現MVC結構微型框架
主要:
- 常量優化路徑
- 自動加載類
- 優化入口文件
- 安全訪問項目目錄
--------------文件結構:-------------------------------------- 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 .. 這個是比較靈活的,可以根據需求選擇更加合適的方式
實際上線項目,還是建議使用框架,安全快捷; 自己模仿定義的框架結構適合學習研究使用,容易遺漏,造成安全隱患,操作不便等問題
下一步:根據博客前端模板,分析創建數據表, 開始搭建博客後臺程序,後續首先準備實現 “分類模塊”。既分類的展示,修改,添加,刪除功能
php源碼建博客4--實現MVC結構微型框架