您現在的位置: 365建站網 > 365學習 > PHP MVC、模板引擎及權限設計

PHP MVC、模板引擎及權限設計

文章來源:365jz.com     點擊數:686    更新時間:2015-11-25 15:34   參與評論

本文轉自"PHP愛好者":http://www.phpfans.org/?cat=1
一般用到“引擎”兩字都會感覺比較高級,"模板引擎"這四個字聽起來很高深的樣子,類似游戲3D引擎、Zend引擎等,其實都是唬人的,騙外行人的。所以在我初學PHP的那會,也因為這四個字導致了我覺得很難而沒有去看他到底是什么樣一個東西,直到很長時間以后使用Smarty才真正了解模板引擎的原理和作用。Smarty(http://smarty.php.net),PHP官方模板引擎,看名字給人感覺應該很快,其實很慢,即使他有預編譯(另一個看起來很高級的名詞,同樣也是唬人的,下面我會講到這個)。[注:我剛才點開Smarty發現他說他已經不是一個PHP子項目了,汗,看來確實唬人,哈玩笑^_^]。其實在PHP里,模板引擎扮演著View(其實通俗說就是頁面,看英文有時候會給人很高級的錯覺)的角色,這是一個很重要的角色,因為用戶的交互啊,界面效果啊等等都在這里,這是最終用戶看到的你的系統的樣子。

  開頭就說模板引擎,只是跟大家說明一下這個東西其實沒有什么難理解的,明白其原理以后你會發現他是紙老虎,所以你要有信心你會很輕松看完此文。

  為了更好的說明模板引擎所扮演的角色,我不得不也談談MVC。這個話題恐怕互聯網上談及的很多,我也只能根據我的理解來描述,可能有不恰當的地方,歡迎討論。通常的MVC是指Model、View和Controller。也就是模型、視圖和控制器。我理解MVC也是在學了PHP不短時間后了,當時請教老廖(http://qeephp.com),才恍然大悟。

  先來說說Controller,也就是控制器,控制器是個什么東西呢?在PHP里他是扮演一個接收用戶請求,把用戶請求定位到指定數據模型的角色。解釋起來感覺不是很好解釋,來看一個簡單的留言本的例子:

  01.//用戶請求可能是 http://www.example.com/guest.php?module=list 02.$module = $_GET['module']; 03.   04.switch ($module) { 05.    case 'list': 06.        require_once 'list.php'; 07.        break; 08.    case 'add': 09.        require_once 'add.php'; 10.        break; 11.    case 'del': 12.        require_once 'del.php'; 13.        break; 14.    default: 15.        require_once 'list.php'; 16.        break; 17.}

  是不是看起來很簡單好像沒什么東西呀,只是根據用戶的請求參數包含不同的文件而已。沒錯,確實很容易,這個switch語句其實就一個最簡單的控制器的實現。他控制什么?他控制你根據不同的用戶請求參數調用不同的數據模型處理用戶請求。那么這里的list可能是一個留言列表,add是添加留言,del是刪除留言。Controller的傳統實現可以這么簡單,當然現在的很多技巧包括根據不同的用戶請求包含不同的業務邏輯處理類,比如list自動定位到/model/List.class.php這樣的一些技巧性操作等。

  再來說說Model,其實我們一般花比較長時間設計和編寫的也是這塊內容,也就是具體的業務邏輯實現。比如一個留言列表要處理些什么,都是在這里實現。還是直接看一個Model例子比較直觀:

  01.//Guest_List.class.php 02.class Guest_List { 03.    public $page = 1; 04.    public function __construct() { 05.        $this->db = DB::init($GLOBALS['dsn']); 06.        $this->page = (int) $_GET['page']; 07.    } 08.   09.    public function getList() { 10.        $begin = $this->page * 10; 11.        $SQL = "SELECT * FROM guest ORDER BY addTime DESC LIMIT $begin, 10"; 12.        return $this->db->getAll($sql); 13.    } 14.}

  這里的Guest_List就是一個簡單的Model實現,構造函數取得頁數page參數,getList方法查詢留言列表并返回結果集。那么在list.php里可能是這樣調用的:

  1.//list.php 2.require_once 'Guest_List.class.php'; 3.$model = new Guest_List(); 4.$lists = $model->getList();

  嗯,其實很多MVC框架都是這么實現的,只不過可能加了一些自動調用的機制,會根據用戶請求自動調用類,自動執行方法,呵呵。Model大功告成。這里需要明確一點就是,Model只是返回視圖上所可能需要用到的數據,他不負責任何和顯示有關的事情,那么顯示相關的就交給View來做了。我們是不是不知不覺已經把表現和業務邏輯分離了?沒錯,分離就是這么簡單。

  好了,來看看View怎么利用Model返回的數據來顯示頁面吧。最簡單的例子,我們只需要在list.php里增加一行即可。

1.//list.php 2.require_once 'Guest_List.class.php'; 3.$model = new Guest_List(); 4.$lists = $model->getList(); 5.//上面是Model,那么下面就是View 6.require_once 'list.HTML';

  來看看View都做些什么吧,我們用list.html來表示留言列表所展現給用戶的界面文件,用html來命名看起來會更直觀一些,他好像是個html文件,負責輸出html代碼給瀏覽器。來看看list.html可能長什么樣子:

 01.<!--list.html--> 02.<table> 03.  <?php foreach ($lists as $value) { ?> 04.  <tr> 05.    <td><?php echo htmlspecialchars($value['guest_user_name']);?></td> 06.    <td><?php echo date('Y-m-d H:i', $value['guest_date_time']);?></td> 07.    <td><?php echo htmlspecialchars($value['guest_content']);?></td> 08.  </tr> 09.  <?php } ?> 10.</table>

  不難看出來這個文件所做的只不過是遍歷留言數組$lists,然后輸出每一行的留言,對留言的內容處理做了htmlspecialchars和date轉換(與顯示相關的處理),除了和顯示相關的操作,他沒有再做任何業務邏輯了(也不應該有)。

  我發現寫到這里真的沒有什么好寫的了,MVC就是這些(或者再做一些擴展),至于怎么做到表現和業務分離,那么就是在你的Model里只返回數據,也就是你View所需要用到的數據,而你的View拿到這些數據后負責去顯示他就可以了,不應該在你的Model里做顯示和視覺相關的操作,也不應該在你的View里做一些業務邏輯相關的操作,把這兩者分清楚,就自然而然的表現與業務分離了。

  接下來說說負責View的模板引擎吧,其實你在上面應該已經看到了一個最簡陋的模板引擎,那就是View部分的 require_once 語句。厄,實在是太簡單了,模板引擎其實是調度并解析模板的東西,其中調度模板由 require_once 搞定了,那么解析呢?這里由 PHP 引擎本身來搞定了。哈,沒錯,我一直都認為 PHP 是個最好的模板引擎。

  不過還是不得不說說傳統的模板引擎的實現原理,一般來說會有這么幾個步驟:
  1、注冊變量,也就是把從Model返回的數據注冊到模板引擎中,告訴模板引擎這個變量可以使用,其實所謂的注冊也只不過是不得不這么做,因為一般引擎內部函數是沒辦法直接訪問Model返回的變量的(變量作用域的問題),所以不得不加一個注冊操作,把這些變量轉換從模板引擎類的屬性等。
  2、模板解析,就是讀取模板文件,按照模板語法將標簽解析成 PHP 語法,或者執行一些替換操作,用變量內容替換掉模板標簽,其實效果都差不多。
  3、如果不是將變量內容替換掉模板標簽,那么基本上第三步就是將注冊的變量和解析完的模板融合在一起輸出,類似于上面的list.html,是個解析完的文件,然后輸出。

  一般模板引擎還會提供不少用于顯示內容處理的插件,比如日期轉換、字符串處理、生成表格、生成select等,這些給頁面制作提供了一些方便。Smarty還包含了一些頁面緩存機制,也很不錯。

  很多模板引擎都頂著語法簡單的嚎頭,美其名曰降低美工的學習門檻。其實我不得不問,有多少模板是由美工來做的呢?而且對比兩種語法,不覺得 PHP 的簡單循環和輸出有什么難以理解的,對比下面兩種語法:

  1.<!-- <?php foreach ($lists as $value) { ?> --> 2.<?=value['userName']?> 3.<!-- <?php } ?> -->

  和

1.<!-- loop lists value --> 2.{value['userName']} 3.<!-- loop -->

  我左看右看都覺得他們差不多,呵呵,與其再學習一套語法,還不如直接用你已經非常熟悉的PHP呢,為什么要虐待自己呢?而且從可維護性的角度來講,維護PHP語法和維護模板語法,哪種更容易呢?PHP是標準,只要會PHP都知道他怎么寫,表示什么,但是模板引擎千奇百怪的,各種語法都有,不是一個統一的標準,我想誰維護一個從來沒有用過的模板,都需要花不少時間去學習引擎語法。更何況即使模板可以那樣寫,最終還是需要一堆正則替換成PHP語法。我敢肯定,前面寫的哪種模板引擎語法最終會被轉換成它上面那種PHP。其實模板引擎的解析也就是將模板語法轉換成PHP語法的過程。拋開效率來說,多此一舉。就象《C專家編程》作者說的,即使你能用宏把C寫成看起來好像另外一種語言,但是你不要這么做,同樣的這句告誡是否適合于模板引擎呢,它看起來很像另外一種語言。當然我這篇文章不是來批判模板引擎的,哈。它既然存在,也有其存在的道理,某些場合還是不得不用的,比如如果你把模板提供給用戶去制作和使用,那么你不得不采用標簽以限制用戶使用PHP語法,來增強系統安全性。

  再來說效率問題,由于模板引擎要解析模板語法,會用到很多正則匹配和替換,那么在實際運行中是比較消耗系統資源的,而且當模板標簽非常復雜或者嵌套多層的時候,效率是比較低的,因為有了一種處理方法,就是預編譯。所謂的預編譯,就是把帶有模板語法的模板,通過處理,轉換成 PHP 語法的文件,只要模板文件沒有被修改,那么直接包含編譯后的文件即可,這樣就不需要再次替換和匹配,可以大大提高效率,不過由于模板引擎的復雜性,導致編譯后的結果文件仍然比我們一般寫出來的PHP文件復雜得多。所以其實效率還是遠低于直接編寫PHP模板的。有興趣的可以打開一個Smarty編譯過的文件,看看其嵌套,其實要比直接循環來得復雜。

  本文寫到這里也差不多了,具體模板引擎如何編譯如何處理,各個模板引擎的方式都不一樣,有興趣的可以去下載幾個比較經典的引擎看看,比如Smarty。隨后我附上我自己用的PHP模板引擎。

  PS:其實我覺得MVC應該叫做CMV是不是更符合邏輯呢?沒有考證過這個詞的由來^_^。

我的真正PHP模板引擎:

001.<?php 002./** 003. * 模板引擎 004. * 005. * Copyright(c) 2005-2008 by 陳毅鑫(深空). All rights reserved 006. * 007. * To contact the author write to {@link mailto:shenkong@php.net} 008. * 009. * @author 陳毅鑫(深空) 010. * @version $Id: Template.class.php 1687 2008-07-07 01:16:07Z skchen $ 011. * @package Template 012. */ 013.   014.defined('FW') || exit(header('HTTP/1.0 400 Bad Request')); 015.   016.class Template { 017.    protected static $obj; 018.   019.    public $vars; 020.    public $includeFiles; 021.    public $includeFile; 022.    public $templates; 023.    public $template; 024.    public $contents; 025.    protected $_content; 026.    protected $_contents; 027.    protected $_path; 028.   029.    protected function __construct() { 030.        $this->vars = array(); 031.        require_once ROOT_PATH . "lib/template.func.php"; 032.    } 033.   034.    /** 035.     * 初始化模板引擎 036.     * 037.     * @return object 模板引擎對象 038.     */ 039.    public static function &init() { 040.        if (is_null(self::$obj)) { 041.            self::$obj = new Template(); 042.        } 043.        return self::$obj; 044.    } 045.   046.    /** 047.     * 注冊模板變量 048.     * 049.     * 注冊模板變量后在模板里就可以直接使用該變量,注冊與被注冊變量名不一定要一樣 050.     * 如:$template->assign('var', $value); 051.     * 意思是將當前變量$value注冊成模板變量var,在模板里就可以直接調用$val 052.     * 053.     * @param string $var 注冊到模板里的變量名的字符串形式,不包含$ 054.     * @param mixed $value 需要注冊的變量 055.     */ 056.    public function assign($var, $value) { 057.        if (is_array($var)) { 058.            foreach ($var as $key => $val) { 059.                $this->vars[$key] = $val; 060.            } 061.        } else { 062.            $this->vars[$var] = $value; 063.        } 064.    } 065.   066.    /** 067.     * 解析模板文件 068.     * 069.     * 解析模板,并將變量植入模板,解析完后返回字符串結果 070.     * 071.     * @param unknown_type $templates 072.     * @return unknown 073.     */ 074.    public function fetch($templates) { 075.        if (is_array($templates)) { 076.            $this->templates = $templates; 077.        } else { 078.            $this->templates = func_get_args(); 079.        } 080.        extract($this->vars); 081.   082.        $this->_contents = ''; 083.        foreach ($this->templates as $this->template) { 084.            ob_end_clean(); 085.            ob_start(); 086.            $this->_path = $this->getPath($this->template); 087.            require $this->_path; 088.            $this->_content = ob_get_contents(); 089.            ob_end_clean(); 090.            ob_start(); 091.            $this->_contents .= $this->_content; 092.            $this->contents[$this->template] = $this->_content; 093.        } 094.        return $this->_contents; 095.    } 096.   097.    public function getPath($path) { 098.        $path = explode(".", $path); 099.        $num = count($path); 100.        if ($num == 1) { 101.            return ROOT_PATH . "template" . DIRECTORY_SEPARATOR . $path[0] . ".html"; 102.        } elseif ($num > 1) { 103.            $templatePath = ''; 104.            $templatePath = $path[$num - 1]; 105.            array_pop($path); 106.            $templatePath = ROOT_PATH . implode(DIRECTORY_SEPARATOR, $path) . DIRECTORY_SEPARATOR . 'template' . DIRECTORY_SEPARATOR . $templatePath . ".html"; 107.            return $templatePath; 108.        } else { 109.            return false; 110.        } 111.    } 112.   113.    public function display($templates = array()) { 114.        if (!is_array($templates)) { 115.            $templates = func_get_args(); 116.        } 117.        if (empty($templates)) { 118.            foreach ($this->templates as $this->template) { 119.                echo $this->contents[$this->template]; 120.            } 121.        } else { 122.            echo $this->fetch($templates); 123.        } 124.    } 125.} 126.   127.//end of script     01.<?php 02./** 03. * 模板擴充函數 04. * 05. * Copyright(c) 2005 by 陳毅鑫(深空). All rights reserved 06. * 07. * To contact the author write to {@link mailto:shenkong@php.net} 08. * 09. * @author 陳毅鑫(深空) 10. * @version $Id: template.func.php 1687 2008-07-07 01:16:07Z skchen $ 11. * @package Template 12. */ 13.   14.defined('FW') || exit(header('HTTP/1.0 400 Bad Request')); 15.   16./** 17. * 包含模板 18. * 19. * 當你需要在主模板文件里(有些模板引擎稱之為layout布局模板,其實不是所有模板都是布局) 20. * 再包含其他公共模板的時候,使用該函數進行包含,則所有已注冊的變量均可在被包含文件里使 21. * 用,貌似支持多層嵌套,沒有測試過,參數可以使用數組,也可以使用多個參數,如: 22. * <?=includeFile('user.header', 'user.main', 'user.footer')?> 或者 23. * <?=includeFile(array('user.header', 'user.main', 'user.footer'))?> 24. * 25. * @param string|array $filename 模板名(module.templateName形式) 26. */ 27.function includeFile($templates) { 28.    $template = Template::init(); 29.    if (is_array($templates)) { 30.        $template->includeFiles = $templates; 31.    } else { 32.        $template->includeFiles = func_get_args(); 33.    } 34.    extract($template->vars); 35.    foreach ($template->includeFiles as $template->includeFile) { 36.        require $template->getPath($template->includeFile); 37.    } 38.} 39.   40.//end of script  

------------------------------------------------------------------------------------------------------------------------------------------

下面談談權限設計:

 

  PHPChina的專家版在談權限設計,苦于沒有權限回帖,特發此博文談談簡單的權限設計。討論在這里。
  最簡單的權限驗證,應該是登錄態的驗證,如果登錄,則可以怎樣,沒有登錄,則不能怎樣:

  1.if ($isLogin === true) { 2.    //do something 3.} else { 4.    //do nothing 5.}

  一般使用會話或者Cookie來保存登錄態,具體實現不在此文討論范圍。一般權限都和人掛勾,首先識別你是誰,然后看你有能力做什么,然后再確認你的能力在這個地方是否可以使,一個權限驗證算是基本上完成。我們圍繞這幾點來看權限如何去設計。
  首先要能識別操作者是何許人,我們需要一張保存操作者信息的表,也就是通常所說的用戶表。簡單的用戶表如下:

  1.CREATE TABLE user ( 2.    userId int(10) unsigned NOT NULL, 3.    username varchar(255) NOT NULL, 4.    PRIMARY KEY (userId) 5.)

  一般使用一個用戶ID來標識一個唯一的用戶,可以使用數字,或者直接使用用戶名作為主鍵(如果用戶名不重復)。這里我們使用userId來唯一標識一個用戶。
  有了用戶以后,接下來需要確認這個用戶所具有的能力,也就是權限,那么首先我們需要列一下我們的系統總共需要幾個權限,比如增、刪、改、查等。增加一張權限表:

  1.CREATE TABLE permission ( 2.    permissionId int(10) unsigned NOT NULL , 3.    permissionName varchar(255) NOT NULL , 4.    PRIMARY KEY (permissionId) 5.)

  同樣的我們以permissionId作為主鍵來唯一標識一個權限,當然也可以使用permissionName來標識(如果你能確定唯一的話)。我們新增幾條記錄在這張表里:

  1.+--------------+----------------+ 2.| permissionId | permissionName | 3.+--------------+----------------+ 4.|            1 | add            | 5.|            2 | del            | 6.|            3 | modify         | 7.|            4 | select         | 8.+--------------+----------------+

  這里列舉了4個權限,簡單的表示我們的用戶在系統里可能具有的增、刪、改、查4種不同的能力。
  接下來把這些能力賦給用戶,需要一張對應表來保存:

  1.CREATE TABLE userPermission ( 2.    userId int(10) unsigned NOT NULL, 3.    permissionId int(10) unsigned NOT NULL, 4.    PRIMARY KEY (userId, permissionId) 5.)

  其中將userId和permissionId設置為主鍵,表示某個用戶具有某種權限。表內容可能如下:

  01.+--------+--------------+ 02.| userId | permissionId | 03.+--------+--------------+ 04.|      1 |            1 | 05.|      1 |            4 | 06.|      2 |            1 | 07.|      2 |            2 | 08.|      2 |            3 | 09.|      2 |            4 | 10.+--------+--------------+

  以上權限配置表明用戶1具有增、查權限,用戶2具有增、刪、改、查權限(嗯可以猜想用戶1是個普通用戶,用戶2是個管理員)。
  寫到這里,我發現基本的用戶權限系統雛型已經完成了。這么簡單?看起來好像確實就是這么簡單。一個用戶擁有哪些權限,那么只需要勾選相應的權限分配給這個用戶。在驗證權限的時候,取出用戶所擁有的所有權限,然后判斷是否存在該權限即可。
  實際上的權限設計要比這個復雜一些,到底復雜在哪里呢?我們接下來分析。當用戶比較多而且權限數量比較多的時候,你是不是要每個用戶都去勾選一堆權限呢?如何簡化這個操作?OK,用戶組的概念推出。所謂用戶組,就是具有某些權限的一類人的集合。我們賦予用戶組某些權限,然后把這個用戶加到這個用戶組里即可,來看看用戶組長什么樣子:

  1.CREATE TABLE group ( 2.    groupId int(10) unsigned NOT NULL, 3.    groupName varchar(255) NOT NULL, 4.    PRIMARY KEY (groupId) 5.)

  和用戶表類似,我們需要標識一個唯一的組,這里分配一個組ID作為主鍵來標識。內容可能如下:

  1.+---------+-----------+ 2.| groupId | groupName | 3.+---------+-----------+ 4.|       1 | user      | 5.|       2 | admin     | 6.+---------+-----------+

  有了用戶組表后,我們需要把一些權限賦給用戶組,就需要一張用戶組權限表:

  1.CREATE TABLE groupPermission ( 2.    groupId int(10) unsigned NOT NULL, 3.    permissionId int(10) unsigned NOT NULL, 4.    PRIMARY KEY (groupId, permissionId) 5.)

  我們分配增、查權限給user組,分配增、刪、改、查權限給admin組:

  01.+---------+--------------+ 02.| groupId | permissionId | 03.+---------+--------------+ 04.|       1 |            1 | 05.|       1 |            4 | 06.|       2 |            1 | 07.|       2 |            2 | 08.|       2 |            3 | 09.|       2 |            4 | 10.+---------+--------------+

  用戶組表和用戶組所對應的權限表有了,那么要把用戶分配給一個用戶組,就需要一張用戶和組的對應關系表:

  1.CREATE TABLE userGroup ( 2.    userId int(10) unsigned NOT NULL, 3.    groupId int(10) unsigned NOT NULL, 4.    PRIMARY KEY (userId, groupId) 5.)

  把用戶1賦給user組,把用戶2賦給admin組,和一開始我們直接分配權限一樣:

  1.+--------+---------+ 2.| userId | groupId | 3.+--------+---------+ 4.|      1 |       1 | 5.|      2 |       2 | 6.+--------+---------+

  很明顯這里的配置信息相對比userPermission表少很多,這里只需要記錄用戶屬于什么組就可以了,那么檢測用戶權限,就需要查出用戶所在的組,然后再查出這個組(或者這些組)所擁有的權限,就可以得出用戶所具備的權限,再進行驗證即可。當然會比直接查詢userPermission表繞一點點,不過相對比維護成本,這點點消耗不算什么。更何況我們其實仍然可以保存userPermission表,在分配用戶組的時候,同時更新userPermission表即可。
  這里可以看到,除了在分配用戶權限方便以外,當你需要更改某類用戶權限的時候,你只需要更改其所在組的權限,那么這個組下所有成員的權限也會隨之更改,非常方便。
  到這里用戶、用戶組的權限構成基本完成。它能解決大部分問題,可是我發現它仍然有一些小的問題。比如如果某個用戶只有查權限,我不得不再新增一個用戶組,搞得用戶組也很多,怎么辦呢?如果這個用戶屬于普通用戶組,其實可以考慮也分配普通用戶組給這個用戶,然后再從普通用戶組里“扣掉”增權限。要達到這樣的效果,怎么處理呢?
  其實很簡單,我們剛才沒有去掉的userPermission表派上用場,這個表存儲了用戶的實際單個權限,我們只需要增加一個字段標識用戶是擁有這個權限,還是沒有這個權限即可,這樣可以解決兩個問題:一是從現有用戶組中扣掉某些權限,二是在現有用戶組中,再給這個用戶增加用戶組以外的權限。來看一下userPermission表:

  1.CREATE TABLE userPermission ( 2.  userId int(10) unsigned NOT NULL, 3.  permissionId int(10) unsigned NOT NULL, 4.  has enum('yes','no') NOT NULL, 5.  PRIMARY KEY (userId, permissionId) 6.)

  把用戶1的增權限去掉,那么內容可能像這樣:

  01.+--------+--------------+-----+ 02.| userId | permissionId | has | 03.+--------+--------------+-----+ 04.|      1 |            1 | no  | 05.|      1 |            4 | yes | 06.|      2 |            1 | yes | 07.|      2 |            2 | yes | 08.|      2 |            4 | yes | 09.|      2 |            3 | yes | 10.+--------+--------------+-----+

  這個用戶依然在user組里,只不過user組所擁有的2個權限(add, select),他少了個add(ID為1被標記為no)權限而已。
  嗯,這樣做有解決了這個小問題,不過這個功能增強會讓分配權限代碼更復雜一些,不僅要給用戶分配組,還可能需要操作具體權限,讓他有或者讓他沒有相應的權限。
  OK,簡單的權限設計全部完成,只不過,細心的讀者,你是否意識到,還少點什么呢?沒錯,即使到這里,整個權限驗證還少了一塊很重要的部分,那就是用戶擁有這些權限,那么他能在哪里使用這些權限??紤]一個例子,一個論壇版主在他所管理的論壇版塊里擁有刪、改帖子的權限,他在其他非他所管理的版塊就沒有這些權限,可能在其他論壇版塊他像是一個普通用戶一樣,我們上面討論的權限設計如何做到這個驗證呢?那么我個人覺得,權限設計到上面已經完成了,接下去這種情況,屬于業務邏輯層的驗證,我們從權限系統中已經獲得用戶的權限,那么在具體業務邏輯中,和權限進行綁定即可,以上例子可以用一個版塊用戶關系表來解決這個問題:

  1.CREATE TABLE userBoard ( 2.  userId int(10) unsigned NOT NULL, 3.  boardId int(10) unsigned NOT NULL, 4.  PRIMARY KEY (userId, boardId) 5.)

  標記用戶擁有哪些版塊的管理權限,那么在嚴重用戶擁有管理權限的時候,還要看當前版塊是否是用戶管轄內的版塊,最終確定用戶是否有操作權限。那么我將這類和業務邏輯相關的權限分配歸到用戶角色里,同樣可以創建一系列角色,來管理用戶所管轄的范圍,比如超級版主,他也是具有管理刪、改權限,只不過他的權限作用于全論壇,那么普通版主就需要指定論壇,這樣來區分用戶組和角色組我想會使整個權限系統更加清晰。
  到這里,權限驗證全部完成,以上沒有具體實現代碼,我相信這樣已經足夠了,具體的實現代碼和業務邏輯由具體的應用實現吧。


本文轉自PHP愛好者:http://www.phpfans.org/?cat=7

如對本文有疑問,請提交到交流論壇,廣大熱心網友會為你解答??! 點擊進入論壇


發表評論 (686人查看,0條評論)
請自覺遵守互聯網相關的政策法規,嚴禁發布色情、暴力、反動的言論。
用戶名: 驗證碼: 點擊我更換圖片
最新評論
------分隔線----------------------------
自拍偷拍福力视频,偷拍国际精品,麻豆一区福利电影,国产网红视频午夜福利,se视频大全,久久国产AV影院 免费啪视频在线观看视频久18| 性刺激特黄毛片免费视频| 欧美30.40.50熟妇性无码| 久久婷婷五月综合色国产| 色咪在线影院| 国偷自产一区| 免费污站18禁的刺激| 18禁止进入拍拍拍高潮网站| 国产女人高潮抽搐视频360| 久久爱视频这里只有精品100| bgmbgmbgm老太太| 被夫の上司持久侵犯酒井电影| 爆乳喷奶水无码正在播放| 日本精品高清一区二区| A级一片男女牲交| wwxxxxx日本高潮| 国产精品香蕉在线的人| 有钱人喜欢玩孕妇| 色婷婷久久综合中文久久一本| 欧美性色19p| 无遮挡黄漫动漫视频免费| 人妻丰满熟妇av无码区| 久久国产乱子伦精品免费女| 亚洲va在线va天堂va不卡| 坡多野结衣的在线播放| av无码av无码专区| 极品人妻互换| 欧美人与禽交zozo| 午夜性刺激免费看视频| 岳的又大又紧水又多| 国产精品丝袜综合区| http://www.manatsunoyume.com