搜尋
首頁後端開發php教程php源碼之實現MVC結構微型框架

php源碼之實現MVC結構微型框架

Jul 05, 2018 am 09:53 AM
php源碼

這篇文章主要介紹了關於php源碼之實現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[&#39;p&#39;]) ? $_GET[&#39;p&#39;] : &#39;Home&#39;;  //平台 
 6 $c = !empty($_GET[&#39;c&#39;]) ? $_GET[&#39;c&#39;] : &#39;User&#39;;  //控制器 
 7 $a = !empty($_GET[&#39;a&#39;]) ? $_GET[&#39;a&#39;] : &#39;login&#39;; //动作 
 8  
 9 define(&#39;PLAT&#39;, $p);  //平台常量
 10 define(&#39;CTR&#39;, $c);  //控制器
 11 define(&#39;ACTION&#39;, $a); //动作
 12 
 13 
 14 define(&#39;DS&#39;, DIRECTORY_SEPARATOR); //目录分割符
 15 define(&#39;ROOT&#39;, getcwd().DS);  //当前所在目录 项目目录
 16 define(&#39;FRAME&#39;, ROOT.&#39;Frame&#39;.DS);
 17 define(&#39;APP&#39;, ROOT.&#39;App&#39;.DS);
 18 define(&#39;PUB&#39;, ROOT.&#39;Public&#39;.DS);
 19 define(&#39;ADMIN&#39;, PUB.&#39;Admin&#39;.DS);
 20 define(&#39;HOME&#39;, PUB.&#39;Home&#39;.DS);
 21 
 22 //MVC目录
 23 define(&#39;MODEL&#39;, APP.&#39;Model&#39;.DS);
 24 define(&#39;VIEW&#39;, APP.&#39;View&#39;.DS.PLAT.DS.CTR.DS);
 25 define(&#39;CTRONLLER&#39;, APP.&#39;Controller&#39;.DS.PLAT.DS);
 26 
 27 $ctr = $c."Controller";
 28 
 29 require_once FRAME.&#39;Db.class.php&#39;;  //数据库操作类
 30 require_once FRAME.&#39;BaseModel.class.php&#39;;  //基础模型类
 31 require_once MODEL.&#39;UserModel.class.php&#39;;  //用户模型类
 32 require_once FRAME.&#39;FactoryModel.class.php&#39;;//模型工厂类
 33 require_once FRAME.&#39;BaseController.class.php&#39;; //基础控制器类
 34 require_once CTRONLLER.$ctr.&#39;.class.php&#39;;
 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.&#39;index.html&#39;;
 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()可以實現自動載入

          實用性,更多的是使用sql_autoload_register()註冊函數自動加載

  根據目錄的特點實現自動加載

          Model類文件特點,以Model結尾的類名  substr($className,5)
          Controller檔案特色: 以Controller結尾的類別名,substr($class,-10)

    公共類別:類別名稱沒有統一形式,可以將Fame下的公共類別放入數組中,然後判斷類別是否在陣列中, 從而自動載入該目錄下的類別檔案

  程式碼實作

   1)入口檔案實作類別的自動載入

#

 1 <?php 
 2 /** 
 3  * 入口文件 
 4  */ 
 5 $p = !empty($_GET[&#39;p&#39;]) ? $_GET[&#39;p&#39;] : &#39;Home&#39;;  //平台 
 6 $c = !empty($_GET[&#39;c&#39;]) ? $_GET[&#39;c&#39;] : &#39;User&#39;;  //控制器 
 7 $a = !empty($_GET[&#39;a&#39;]) ? $_GET[&#39;a&#39;] : &#39;login&#39;; //动作 
 8  
 9 define(&#39;PLAT&#39;, $p);  //平台常量
 10 define(&#39;CTR&#39;, $c);  //控制器
 11 define(&#39;ACTION&#39;, $a); //动作
 12 
 13 
 14 define(&#39;DS&#39;, DIRECTORY_SEPARATOR); //目录分割符
 15 define(&#39;ROOT&#39;, getcwd().DS);  //当前所在目录 项目目录
 16 define(&#39;FRAME&#39;, ROOT.&#39;Frame&#39;.DS);
 17 define(&#39;APP&#39;, ROOT.&#39;App&#39;.DS);
 18 define(&#39;PUB&#39;, ROOT.&#39;Public&#39;.DS);
 19 define(&#39;ADMIN&#39;, PUB.&#39;Admin&#39;.DS);
 20 define(&#39;HOME&#39;, PUB.&#39;Home&#39;.DS);
 21 
 22 //MVC目录
 23 define(&#39;MODEL&#39;, APP.&#39;Model&#39;.DS);
 24 define(&#39;VIEW&#39;, APP.&#39;View&#39;.DS.PLAT.DS.CTR.DS);
 25 define(&#39;CTRONLLER&#39;, APP.&#39;Controller&#39;.DS.PLAT.DS);
 26 
 27 $ctr = $c."Controller";
 28 
 29 spl_autoload_register(&#39;autoload&#39;); //注册自动加载函数
 30 //自动加载类
 31 /**
 32  * 实自动加载类文件
 33  * @param  string $className 类名
 34  */
 35 function autoload($className)
 36 {
 37     $upperClassName = strtoupper($className);
 38     $frame = array(&#39;BaseController&#39;,&#39;BaseModel&#39;,&#39;Db&#39;,&#39;FactoryModel&#39;);
 39     if(in_array($className, $frame)) {  //加载公共Frame目录中的类文件
 40         require_once FRAME."$className.class.php";
 41     } elseif(substr($upperClassName, -5) == &#39;MODEL&#39;){  //加载模型Model目录中的类文件
 42         require_once MODEL."$className.class.php";
 43     } elseif(substr($upperClassName, -10) == &#39;CONTROLLER&#39;){  //加载控制器目录中的类文件
 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() 自動         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(&#39;BaseController&#39;,&#39;BaseModel&#39;,&#39;Db&#39;,&#39;FactoryModel&#39;); //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(&#39;self::autoload&#39;);
 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) == &#39;MODEL&#39;){
 46             require_once MODEL."$className.class.php";
 47         } elseif(substr($upperClassName, -10) == &#39;CONTROLLER&#39;){
 48             require_once CTRONLLER."$className.class.php";
 49         }
 50     }
 51 
 52     /**
 53      * 定义常量
 54      */
 55     private static function setConst()
 56     {
 57         define(&#39;DS&#39;, DIRECTORY_SEPARATOR); //目录分割符
 58         define(&#39;ROOT&#39;, getcwd().DS);
 59         define(&#39;FRAME&#39;, ROOT.&#39;Frame&#39;.DS);
 60         define(&#39;APP&#39;, ROOT.&#39;App&#39;.DS);
 61         define(&#39;PUB&#39;, ROOT.&#39;Public&#39;.DS);
 62         define(&#39;ADMIN&#39;, PUB.&#39;Admin&#39;.DS);
 63         define(&#39;HOME&#39;, PUB.&#39;Home&#39;.DS);
 64 
 65 
 66         define(&#39;MODEL&#39;, APP.&#39;Model&#39;.DS);
 67         define(&#39;VIEW&#39;, APP.&#39;View&#39;.DS.PLAT.DS.CTR.DS);
 68         define(&#39;CTRONLLER&#39;, APP.&#39;Controller&#39;.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[&#39;p&#39;]) ? $_GET[&#39;p&#39;] : &#39;Home&#39;;  //平台
 78         $c = !empty($_GET[&#39;c&#39;]) ? $_GET[&#39;c&#39;] : &#39;User&#39;;  //控制器
 79         $a = !empty($_GET[&#39;a&#39;]) ? $_GET[&#39;a&#39;] : &#39;login&#39;; //动作
 80 
 81         define(&#39;PLAT&#39;, $p);
 82         define(&#39;CTR&#39;, $c);
 83         define(&#39;ACTION&#39;, $a);
 84     }
 85 }
#########2) 入口檔案引入初始化類,並呼叫其方法【index.php】#########
1 <?php
2 /**
3  * 入口文件
4  */
5 
6 require_once &#39;./Frame/Init.class.php&#39;;
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中文网!

相关推荐:

php源码之区分平台MVC结构的介绍

php源码之实现单入口MVC结构的方法

以上是php源碼之實現MVC結構微型框架的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
您如何防止與會議有關的跨站點腳本(XSS)攻擊?您如何防止與會議有關的跨站點腳本(XSS)攻擊?Apr 23, 2025 am 12:16 AM

要保護應用免受與會話相關的XSS攻擊,需採取以下措施:1.設置HttpOnly和Secure標誌保護會話cookie。 2.對所有用戶輸入進行輸出編碼。 3.實施內容安全策略(CSP)限制腳本來源。通過這些策略,可以有效防護會話相關的XSS攻擊,確保用戶數據安全。

您如何優化PHP會話性能?您如何優化PHP會話性能?Apr 23, 2025 am 12:13 AM

优化PHP会话性能的方法包括:1.延迟会话启动,2.使用数据库存储会话,3.压缩会话数据,4.管理会话生命周期,5.实现会话共享。这些策略能显著提升应用在高并发环境下的效率。

什麼是session.gc_maxlifetime配置設置?什麼是session.gc_maxlifetime配置設置?Apr 23, 2025 am 12:10 AM

theSession.gc_maxlifetimesettinginphpdeterminesthelifespanofsessiondata,setInSeconds.1)它'sconfiguredinphp.iniorviaini_set().2)abalanceisesneededeededeedeedeededto toavoidperformance andunununununexpectedLogOgouts.3)

您如何在PHP中配置會話名?您如何在PHP中配置會話名?Apr 23, 2025 am 12:08 AM

在PHP中,可以使用session_name()函數配置會話名稱。具體步驟如下:1.使用session_name()函數設置會話名稱,例如session_name("my_session")。 2.在設置會話名稱後,調用session_start()啟動會話。配置會話名稱可以避免多應用間的會話數據衝突,並增強安全性,但需注意會話名稱的唯一性、安全性、長度和設置時機。

您應該多久再生一次會話ID?您應該多久再生一次會話ID?Apr 23, 2025 am 12:03 AM

會話ID應在登錄時、敏感操作前和每30分鐘定期重新生成。 1.登錄時重新生成會話ID可防會話固定攻擊。 2.敏感操作前重新生成提高安全性。 3.定期重新生成降低長期利用風險,但需權衡用戶體驗。

如何在PHP中設置會話cookie參數?如何在PHP中設置會話cookie參數?Apr 22, 2025 pm 05:33 PM

在PHP中設置會話cookie參數可以通過session_set_cookie_params()函數實現。 1)使用該函數設置參數,如過期時間、路徑、域名、安全標誌等;2)調用session_start()使參數生效;3)根據需求動態調整參數,如用戶登錄狀態;4)注意設置secure和httponly標誌以提升安全性。

在PHP中使用會議的主要目的是什麼?在PHP中使用會議的主要目的是什麼?Apr 22, 2025 pm 05:25 PM

在PHP中使用會話的主要目的是維護用戶在不同頁面之間的狀態。 1)會話通過session_start()函數啟動,創建唯一會話ID並存儲在用戶cookie中。 2)會話數據保存在服務器上,允許在不同請求間傳遞數據,如登錄狀態和購物車內容。

您如何在子域中分享會議?您如何在子域中分享會議?Apr 22, 2025 pm 05:21 PM

如何在子域名間共享會話?通過設置通用域名的會話cookie實現。 1.在服務器端設置會話cookie的域為.example.com。 2.選擇合適的會話存儲方式,如內存、數據庫或分佈式緩存。 3.通過cookie傳遞會話ID,服務器根據ID檢索和更新會話數據。

See all articles

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

SublimeText3 Linux新版

SublimeText3 Linux新版

SublimeText3 Linux最新版

VSCode Windows 64位元 下載

VSCode Windows 64位元 下載

微軟推出的免費、功能強大的一款IDE編輯器

MinGW - Minimalist GNU for Windows

MinGW - Minimalist GNU for Windows

這個專案正在遷移到osdn.net/projects/mingw的過程中,你可以繼續在那裡關注我們。 MinGW:GNU編譯器集合(GCC)的本機Windows移植版本,可自由分發的導入函式庫和用於建置本機Windows應用程式的頭檔;包括對MSVC執行時間的擴展,以支援C99功能。 MinGW的所有軟體都可以在64位元Windows平台上運作。

Dreamweaver Mac版

Dreamweaver Mac版

視覺化網頁開發工具

DVWA

DVWA

Damn Vulnerable Web App (DVWA) 是一個PHP/MySQL的Web應用程序,非常容易受到攻擊。它的主要目標是成為安全專業人員在合法環境中測試自己的技能和工具的輔助工具,幫助Web開發人員更好地理解保護網路應用程式的過程,並幫助教師/學生在課堂環境中教授/學習Web應用程式安全性。 DVWA的目標是透過簡單直接的介面練習一些最常見的Web漏洞,難度各不相同。請注意,該軟體中