PHP 作為“最簡單”的 Web 腳本語言, 在國內的市場越來越大,phper 越來越多,但是感覺大多數人好像沒有考慮到模式問題,什麼樣的設計模式才是最優的,才是最適合自己目前工作的,畢竟效率是最重要的(用省下的時間打游戲,多美啊...)。MVC 應該是首選,www.sourceforge.net 上有好多優秀的基於 MVC 的開源項目,大家可以沖過去研究研究。 前幾天給自己公司網站改版,主要還是文章發布系統,老板說後台我想怎麼設計就怎麼設計,唯一的前提就是快。於是自己搭建了一個簡單的發布系統的框架。如果單純從文章發布系統上講,基本上可以滿足“中小型”企業網站的文章發布系統的要求,後台的總共的php代碼不超過800行,而且支持任意擴充和plugin功能。 廢話不再說了,下面把我的架構講一下,希望對您能有所幫助。 注意:在開始前,需要您下載一個模板處理工具類:“smarttemplate”,並了解一些模板的簡單的使用。 我的測試環境:windows2k/apache2/php4.3.2/smarttemplate類庫 先講一下整個web站點的文件的分布,在後面的章節中將陸續創建並填充下面的目錄和文件 我的服務器的web的根目錄是 “C:/Apache2/htdocs/” 我在下面建立了一個文件夾“cmstest”作為我的網站的主文件夾 文件夾“cmstest”下面的子文件結構是: /config.inc.php /list1.php /list2.php /new.php /add.php /view.php /page.js /src/mysqlUtil.php /src/ArticleUtil.php /src/CoreUtil.php /src/ParseTpl.php /src/lib/smarttemplate/*.* 這個目錄用來存放smarttemplate的類庫的 /smart/template/list1.htm /smart/template/list2.htm /smart/template/new.htm /smart/template/add.htm /smart/template/view.htm /smart/cache/ /smart/temp/ 設計步驟: 考慮自己公司的網站的特點和已經設計的模板的結構,總結要實現的功能,列出清單。 分析功能清單,把功能分類。每一類的功能都是有共同點的,可以通過相同的方法實現的。 根據功能,設計數據庫的表結構 設計一個配置文件config.inc.php, 用來記錄網站的一些基本的信息,包括數據庫名........ 為每一類功能設計數據庫查詢的接口函數,這樣以後相似的操作只要調用這個接口就可以了。這樣避免了以後可能發生的大量的代碼重復的操作,也就達到了代碼復用的目的。 定義自己對模板工具的包裝函數,以後調用的時候就不用管模板工具的使用問題了,只有往自己的包裝函數裡面塞數就可以了。 基礎函數已經ok了,開始輕松的頁面實現和模板的處理了。 我們現在就開始設計一個簡單的系統,看看我是怎麼一步一步地實現一個“最簡單的文章的發布系統”的,當然只是我模擬的一個簡單的項目,實際中一個項目可能比這要復雜的多。 一、分析我的案例: 呵呵,這個客戶項目好簡單的啊,幸福ing.......... list1.php:有三個文章列表和一個按鈕,“php開發文章列表”“php開發熱點文章列表”“ASP開發最新文章”“添加新文章” list2.php:有2個文章列表“asp開發文章列表”“asp開發熱點文章列表” new.php:一個添加文章的表單的頁面 add.php: 處理new.php的表單的頁面 view.php: 文章察看的頁面 二、分析功能 “php開發文章列表”“asp開發文章列表”-------按文章的發布順序,倒序排列顯示,每頁顯示5篇文章 “php開發熱點文章列表”“asp開發熱點文章列表”-------按文章的點擊察看次數排序顯示文章,顯示3篇文章 “asp開發最新文章”按文章的發布順序,倒序排列顯示,顯示3篇文章 “添加新文章”------一個文章的發布功能, 包括文章標題/作者/內容 “文章察看”---------顯示某篇文章內容 綜合的看一下,對功能進行分類包括: 1、文章列表:正常的分頁列表、按點擊數列表、按發布順序的列表 2、文章發布:一個表單的輸入和處理 3、文章察看:讀取顯示文章內容 呵呵,功能的確是太簡單了些。 三、設計數據庫: 數據庫名:cmstest 數據表: CREATE TABLE `article` ( `id` INT NOT NULL AUTO_INCREMENT, `title` VARCHAR( 100 ) NOT NULL , `content` TEXT NOT NULL , `datetime` DATETIME NOT NULL , `clicks` INT( 11 ) , `pid` TINYINT( 2 ) NOT NULL , PRIMARY KEY ( `id` ) ); CREATE TABLE `cat` ( `cid` TINYINT( 2 ) NOT NULL , `cname` VARCHAR( 20 ) NOT NULL , PRIMARY KEY ( `cid` ) ); ------------------------------ article表是文章內容表, ---------------------------- `id` 文章編號 `title` 文章標題 `content` 文章內容 `datetime` 發布時間 `clicks` 點擊數 `pid` 分類表號 ------------------------------ cat表是文章的類別表 ---------------------------- `cid` 分類表號 `cname` 分類名稱 ---------------------------- 上面是表的數據庫結構,光有了這些還不夠,還要有數據 INSERT INTO `cat` VALUES(1, "php開發"),(2, "asp開發"); INSERT INTO `article` VALUES(1, "php開發1", "php開發1內容", "2004-8-1 1:1:1", 0, 1); INSERT INTO `article` VALUES(2, "php開發2", "php開發2內容", "2004-8-2 1:1:1", 0, 1); INSERT INTO `article` VALUES(3, "php開發3", "php開發3內容", "2004-8-3 1:1:1", 4, 1); INSERT INTO `article` VALUES(4, "php開發4", "php開發4內容", "2004-8-4 1:1:1", 3, 1); INSERT INTO `article` VALUES(5, "php開發5", "php開發5內容", "2004-8-5 1:1:1", 2, 1); INSERT INTO `article` VALUES(6, "php開發6", "php開發6內容", "2004-8-6 1:1:1", 1, 1); INSERT INTO `article` VALUES(7, "php開發7", "php開發7內容", "2004-8-7 1:1:1", 0, 1); INSERT INTO `article` VALUES(8, "jsp開發1", "jsp開發1內容", "2004-8-1 1:1:1", 0, 2); INSERT INTO `article` VALUES(9, "jsp開發2", "jsp開發2內容", "2004-8-2 1:1:1", 0, 2); INSERT INTO `article` VALUES(10, "jsp開發3", "jsp開發3內容", "2004-8-3 1:1:1", 4, 2); INSERT INTO `article` VALUES(11, "jsp開發4", "jsp開發4內容", "2004-8-4 1:1:1", 3, 2); INSERT INTO `article` VALUES(12, "jsp開發5", "jsp開發5內容", "2004-8-5 1:1:1", 2, 2); INSERT INTO `article` VALUES(13, "jsp開發6", "jsp開發6內容", "2004-8-6 1:1:1", 1, 2); INSERT INTO `article` VALUES(14, "jsp開發7", "jsp開發7內容", "2004-8-7 1:1:1", 0, 2); 這樣我們的數據庫就設計完了。接下來就開始涉及到具體的實現了。 四、設計config.inc.php文件 這個文件用來設置一些web上通用的數據信息和一些參數,其他的具體的實現頁面都通過這個頁面獲取需要的數據,下面是配置的清單 <?php //數據庫設置 define('DB_USERNAME', 'root'); define('DB_PASSWord', ''); define('DB_HOST', 'localhost'); define('DB_NAME', 'cmstest'); define('DB_PCONNECT', true); // web的基本路經設置 define('CMS_ROOT', 'C:/Apache2/htdocs/cmstest/'); define('CMS_SRCPATH', CMS_ROOT.'src/'); //smarttemplate 模板解析工具的設置 define('SMART_REUSE_CODE', false); define('SMART_TEMPLATE_DIR', CMS_ROOT.'smart/template/'); define('SMART_TEMP_DIR', CMS_ROOT.'smart/temp/'); define('SMART_CACHE_DIR', CMS_ROOT.'smart/cache/'); define('SMART_CACHE_LIFETIME', 100); require_once(CMS_SRCPATH . 'lib/smarttemplate/class.smarttemplate.php'); //要包含的基礎文件,裡面都是一些基本的函數 require_once CMS_SRCPATH.'MysqlUtil.php'; require_once CMS_SRCPATH.'ArticleUtil.php'; require_once CMS_SRCPATH.'CoreUtil.php'; require_once CMS_SRCPATH.'ParseTpl.php'; //session 控制 session_cache_limiter('private_no_eXPire'); session_start(); ?> 其中的 define('CMS_ROOT', 'C:/Apache2/htdocs/cmstest/'); 路經根據自己apach的web路經來改(參照最開始介紹文件夾結構的地方改)。 五、制作功能接口(1) 首先對 mysql 數據庫函數進行包裝,簡化對數據庫操作,網上有很多這樣的開源的類。但是這裡我個人根據自己的需求和習慣,自己對 mysql 的函數進行了包裝,寫得好壞就先不管了。這個地方簡單的看一下就可以了,不同的包裝的類操作是不同的,而且這裡的主要目的是理解這套“架構”,不用太扣代碼。 -------MysqlUtil.php-------- <?php function dbConnect(){ global $cnn; $cnn = (DB_PCONNECT? mysql_pconnect(DB_HOST, DB_NAME, DB_PASSWORD): mysql_connect(DB_HOST, DB_NAME, DB_PASSWORD)) or die('數據庫連接錯誤'); mysql_select_db(DB_NAME, $cnn) or die('數據庫選擇錯誤'); mysql_query("SET AUTOCOMMIT=1"); } function &dbQuery($sql){ global $cnn; $rs = &mysql_query($sql, $cnn); while($item=mysql_fetch_assoc($rs)){ $data[] = $item; } return $data; } function &dbGetRow($sql){ global $cnn; $rs = mysql_query($sql) or die('sql語句執行錯誤'); if(mysql_num_rows($rs)>0) return mysql_fetch_assoc($rs); else return null; } function dbGetOne($sql, $fildName){ $rs = dbGetRow($sql); return sizeof($rs)==null? null: (isset($rs[$fildName])? $rs[$fildName]: null); } function &dbPageQuery($sql, $page=1, $pageSize=20){ if($page===null) return dbQuery($sql); $countSql = preg_replace('SELECT.*FROMi','SELECT COUNT(*) count FROM', $sql); $n = (int)dbGetOne($countSql, 'count'); $data['pageSize'] = (int)$pageSize<1? 20: (int)$pageSize; $data['recordCount'] = $n; $data['pageCount'] = ceil($data['recordCount']/$data['pageSize']); $data['page'] = $data['pageCount']==0? 0: ((int)$page<1? 1: (int)$page); $data['page'] = $data['page']>$data['pageCount']? $data['pageCount']:$data['page']; $data['isFirst'] = $data['page']>1? false: true; $data['isLast'] = $data['page']<$data['pageCount']? false: true; $data['start'] = ($data['page']==0)? 0: ($data['page']-1)*$data['pageSize']+1; $data['end'] = ($data['start']+$data['pageSize']-1); $data['end'] = $data['end']>$data['recordCount']? $data['recordCount']: $data['end']; $data['sql'] = $sql.' LIMIT '.($data['start']-1).','.$data['pageSize']; $data['data'] = &dbQuery($data['sql']); return $data; } function dbExecute($sql){ global $cnn; mysql_query($sql, $cnn) or die('sql語句執行錯誤'); return mysql_affected_rows($cnn); } function dbDisconnect(){ global $cnn; mysql_close($cnn); } function sqlGetOneById($table, $field, $id){ return "SELECT * FROM $table WHERE $field=$id"; } function sqlMakeInsert($table, $data){ $t1 = $t2 = array(); foreach($data as $key=>$value){ $t1[] = $key; $t2[] = "'".addslashes($value)."'"; } return "INSERT INTO $table (".implode(",",$t1).") VALUES(".implode(",",$t2).")"; } function sqlMakeUpdateById($table, $field, $id, $data){ $t1 = array(); foreach($data as $key=>$value){ $t1[] = "$key='".addslashes($value)."'"; } return "UPDATE $table SET ".implode(",", $t1)." WHERE $field=$id"; } function sqlMakeDelById($table, $field, $id){ return "DELETE FROM $table WHERE $field=$id"; } ?> 五、制作功能接口(2) 下面來正式的看看,我們共要實現的功能進行的包裝 ------------ArticleUtil.php---------------- <?php //顯示文章列表的函數 //getArticleList(文章類別, 排序方法, 當前顯示第幾頁, 每頁顯示幾條) function getArticleList($catId, $order, $page, $pageSize){ $sql = "SELECT * FROM article WHERE pid=$catId ORDER BY $order"; return dbPageQuery($sql, $page, $pageSize); } //查詢某個文章的內容 //getArticle(文章編號) function getArticle($id){ $sqlUpdate = "UPDATE article SET clicks=clicks+1 WHERE id=$id"; dbExecute($sqlUpdate); $sql = "SELECT * FROM article WHERE art_id=$id"; return dbGetRow($sql); } //添加文章 //addArticle(文章內容數組) function addArticle($data){ $sql = sqlMakeInsert('article', $data); return dbExecute($sql); } ?> 這段代碼是不是就簡單多了啊?這就是自己對mysql函數進行包裝的好處! 下面來研究一下他們是怎麼實現我們的功能的呢。 “php開發文章列表”--------getArticleList(1, "id DESC", $page, 5) “asp開發文章列表”--------getArticleList(2, "id DESC", $page, 5) “php開發熱點文章列表”----getArticleList(1, "clicks DESC, id DESC", 1, 3) “asp開發熱點文章列表”----getArticleList(2, "clicks DESC, id DESC", 1, 3) “asp開發最新文章”--------getArticleList(2, "id DESC", 1, 3) “添加新文章”-------------addArticle($data) “察看文章”---------------getArticle($id) 六、對smarttemplate類進行包裝 具體的smarttemplate的使用這裡就不講了,不然口水講沒了,都講不完。下面這個是具體的對包裝函數 -------------ParseTpl.php---------------- <?php function renderTpl($viewFile, $data){ $page = new SmartTemplate($viewFile); foreach($data as $key=>$value){ if(isset($value[data])){ $page->assign($key, $value[data]); unset($value[data]); $page->assign($key."_page", $value); } else { $page->assign($key, $value); } } $page->output(); } ?> 七:文章列表察看頁面實現和模板處理 先來看看頁面list1的實現,在list1裡面分頁用了一個page.js文件,這個文件是自己給自己寫的一個js分頁的函數,挺好用的 ---------------page.js--------------- //--------共 20 條記錄,當前 86/99 頁 [1]... [82] [83] [84] [85] [86] [87] [88] [89] [90] ...[99] GO------------------- //recordCount = 20; //show = 20 //pageShow = 11; //pageCount = 100; //pageNow = 86; //pageStr = "?page=_page_"; //document.write(showListPage(recordCount, show, pageCount, pageNow, pageStr)); function showListPage(recordCount, show, pageShow, pageCount, pageNow, pageStr){ if(pageCount<1) pageCount =0; if(pageNow<1) pageNow = 0; str = '共 <B>'+recordCount+'</B> 條記錄,當前 <B>'+pageNow+'/'+pageCount+'</B> 頁 '; if(pageCount<=pageShow){ startHave = false; endHave = false; startNum = 1; endNum = pageCount; } else if(pageNow-1 <= pageShow/2){ startHave = false; endHave = true; startNum = 1; endNum = pageShow-1; } else if(pageCount-pageNow <= pageShow/2){ startHave = true; endHave = false; startNum = pageCount - pageShow + 2; endNum = pageCount; } else { startHave = true; endHave = true; startNum = pageNow - Math.floor((pageShow-2)/2); endNum = startNum + pageShow - 3; } if(startHave){ startStr = " [<A href='"+pageStr.replace("_page_",1)+"'>1</A>]... "; str += startStr; } for(i=startNum; i<=endNum; i++){ if(pageNow==i) str += "[" + i + "]"; else str += " [<A href='" + pageStr.replace("_page_",i) + "'>" + i + "</A>] "; } if(endHave){ endStr = " ...[<A href='" + pageStr.replace("_page_",pageCount) + "'>" + pageCount + "</A>] "; str += endStr; } return str; } --------------list1.htm---------------- <a href="new.php">添加新文章</a><hr> <table> <tr><th>php開發文章</th></tr> <!-- BEGIN phplist --> <tr><td>{id}--<a href="view.php?id={id}">{title}</a></td></tr> <!-- END phplist --> </table> <!-- BEGIN phplist_page --> <script src="page.js" language="javascript"></script> <script language="Javascript"> recordCount = {recordCount}; //總記錄數 show = {pageSize}; //每頁顯示的記錄數量 pageShow = 10; //每頁顯示的分頁連接數量 pageCount = {pageCount}; //總頁數 pageNow = {page}; //當前頁數 pageStr = "?page=_page_"; //頁面連接 document.write(showListPage(recordCount, show, pageShow, pageCount, pageNow, pageStr)); </script> <!-- END phplist_page --> <hr> <table ID="Table1"> <tr><th>php開發熱點文章</th></tr> <!-- BEGIN phphotlist --> <tr><td>{id}--<a href="view.php?id={id}">{title}</a></td></tr> <!-- END phphotlist --> </table><hr> <table ID="Table2"> <tr><th>asp開發最新文章</th></tr> <!-- BEGIN aspnewlist --> <tr><td>{id}--<a href="view.php?id={id}">{title}</a></td></tr> <!-- END aspnewlist --> </table> --------------list1.php---------------- <?php require_once "config.inc.php"; dbConnect(); $data = array(); $data[phplist] = getArticleList(1, "id DESC", (int)$_GET , 5); $data[phphotlist] = getArticleList(1, "clicks DESC, id DESC", 1, 3); $data[aspnewlist] = getArticleList(2, "id DESC", 1, 3); dbDisconnect(); renderTpl('list1.htm', $data); ?> 運行的效果怎麼樣,是不是實現了要求的功能呢。現在我們再做一下改動,在裡面加上“asp開發熱點文章列表”,實現代碼如下 --------------list1.htm---------------- <a href="new.php">添加新文章</a><hr> <table> <tr><th>php開發文章</th></tr> <!-- BEGIN phplist --> <tr><td>{id}--<a href="view.php?id={id}">{title}</a></td></tr> <!-- END phplist --> </table> <!-- BEGIN phplist_page --> <script src="page.js" language="javascript"></script> <script language="javascript"> recordCount = {recordCount}; //總記錄數 show = {pageSize}; //每頁顯示的記錄數量 pageShow = 10; //每頁顯示的分頁連接數量 pageCount = {pageCount}; //總頁數 pageNow = {page}; //當前頁數 pageStr = "?page=_page_"; //頁面連接 document.write(showListPage(recordCount, show, pageShow, pageCount, pageNow, pageStr)); </script> <!-- END phplist_page --> <hr> <table ID="Table1"> <tr><th>php開發熱點文章</th></tr> <!-- BEGIN phphotlist --> <tr><td>{id}--<a href="view.php?id={id}">{title}</a></td></tr> <!-- END phphotlist --> </table><hr> <table ID="Table2"> <tr><th>asp開發最新文章</th></tr> <!-- BEGIN aspnewlist --> <tr><td>{id}--<a href="view.php?id={id}">{title}</a></td></tr> <!-- END aspnewlist --> </table> <table ID="Table3"> <tr><th>asp熱點文章</th></tr> <!-- BEGIN asphotlist --> <tr><td>{id}--<a href="view.php?id={id}">{title}</a></td></tr> <!-- END asphotlist --> </table> --------------list1.php---------------- <?php require_once "config.inc.php"; dbConnect(); $data = array(); $data[phplist] = getArticleList(1, "id DESC", (int)$_GET , 5); $data[phphotlist] = getArticleList(1, "clicks DESC, id DESC", 1, 3); $data[aspnewlist] = getArticleList(2, "id DESC", 1, 3); $data[asphotlist] = getArticleList(2, "clicks DESC, id DESC", 1, 3); dbDisconnect(); renderTpl('list1.htm', $data); ?> 仔細觀察一下前後的區別,list1.php裡面只是簡單的加入了一行的代碼,就實現這個改動,感覺怎麼樣啊?是不是超級簡單。 其實這種設計模式的好處還不只是這點: 1、可以把程序的核心代碼隔離開管理,便於以後程序的管理維護 2、對於程序的可擴展性也很好,假設list1.php中要加入產品列表,我是不是也可以這麼做呢?把對產品的管理也寫成統一的數據庫操作接口,然後簡單的修改模板文件加入產品列表部分,最後在list1.php中加入一行函數調用的代碼,就可以實現。 3、代碼復用,如果您是做中小型企業網站的,那這麼做對您的好處是最大的,因為這種類型的網站的設計結構幾乎是一樣的,您可能只需要更改一下模板的樣式,就可以賺到鈔票了。 這麼看來這種模式是不是給您帶來了很多的好處呢? -----------lsit2.htm--------------- <a href="new.php">添加新文章</a><hr> <table ID="Table1"> <tr><th>asp開發文章</th></tr> <!-- BEGIN asplist --> <tr><td>{id}--<a href="view.php?id={id}">{title}</a></td></tr> <!-- END asplist --> </table> <!-- BEGIN asplist_page --> <script src="page.js" language="javascript"></script> <script language="javascript"> recordCount = {recordCount}; //總記錄數 show = {pageSize}; //每頁顯示的記錄數量 pageShow = 10; //每頁顯示的分頁連接數量 pageCount = {pageCount}; //總頁數 pageNow = {page}; //當前頁數 pageStr = "?page=_page_"; //頁面連接 document.write(showListPage(recordCount, show, pageShow, pageCount, pageNow, pageStr)); </script> <!-- END asplist_page --> <hr> <table ID="Table4"> <tr><th>asp熱點文章</th></tr> <!-- BEGIN asphotlist --> <tr><td>{id}--<a href="view.php?id={id}">{title}</a></td></tr> <!-- END asphotlist --> </table> -----------lsit2.php--------------- <?php require_once "config.inc.php"; dbConnect(); $data = array(); $data[asplist] = getArticleList(2, "id DESC", (int)$_GET , 5); $data[asphotlist] = getArticleList(2, "clicks DESC, id DESC", 1, 3); dbDisconnect(); renderTpl('list2.htm', $data); ?> --------view.htm-------------- <!-- BEGIN content --> 編號:{id}<br>標題:{title}<br>內容:{content} <!-- END content --> --------view.php------------------ <?php require_once "config.inc.php"; dbConnect(); $data = array(); $data[content] = getArticle((int)$_GET[id]); dbDisconnect(); renderTpl('view.htm', $data); ?> 八:文章添加實現和模板處理(萬裡長征的再來一步) ---------------new.htm----------- <form action="add.php" method="post"> 標題:<input type="text" size="20"><br> 內容:<textarea cols="50" rows="4"></textarea><br> <input type="submit" value="提交"> </form> ---------------new.php------------ <?php require_once "config.inc.php"; renderTpl('new.htm', array()); ?> ---------------CoreUtil.php-------------- <?php function doPostVar(&$data){ $keys = array_keys($data); foreach($keys as $key){ $data[$key] = addslashes(Htmlspecialchars(trim($data[$key]))); if($data[$key]==null) $data[$key] = "$key default"; } } ?> ---------------add.htm------------ <!-- BEGIN sUCcess --> {content} <!-- END success --> ---------------add.php------------ <?php require_once "config.inc.php"; dbConnect(); $data = action(); doPostVar($data); addArticle($data); $result[success][content] = "文章添加成功"; dbDisconnect(); renderTpl('add.htm', $result); function action(){ $data = array(); $data[title] = $_POST[title]; $data[content] = $_POST[content]; $data[datetime] = date('Y-m-d H:i:s'); $data[pid] = 1; return $data; } ?> 這樣一個最最簡單的文章的發布系統就完成了,不知道對您有什麼收獲沒有。 九、總結 程序寫完了,大家來總結一下吧,看看實現過程,應該可以說是簡單明了吧。 1、統一實現數據庫訪問接口。更改後台數據庫結構的時候,只要簡單的修改相應的接口函數,其他部分的php代碼根本就不用理會。 2、整個系統php代碼和html代碼分開管理,php代碼前台實現起來也很簡單,你也應該已經可以發現了,基本上是在10行代碼左右。 3、可以任意的擴充功能。用函數對新的功能進行包裝後,在具體的前台的查詢顯示頁面中只有加入對相應的函數的簡單的調用就可以了,一行代碼就搞定了。 4、代碼復用。通過對功能的包裝,減少了大量的不必要的重復代碼工作,效率應該是提高了很多吧? 5、可以移植性。如果將來做其他的網站,要是遇到了和這個項目相同的實現功能,你可以怎麼做呢?把這裡的函數和數據庫結構copy過去,修改一下新項目的模板,是不是就可一完成這個新的項目了呢?根本就不用考慮修改php代碼。 6、結構代碼清晰。別人可以輕易的和你共同開發一個項目,代碼沖突也會減少至最低。 當然實際工作中遇到的情況可能比這個例子復雜的多,但是再復雜的任務都是可以拆分的。 十、後言 不知道大家有沒有學過jsp和servlet這樣的東西,他們有很多優秀的設計思路,值得我們去研究和copy(說句實在話,有時間的都應該去接觸一下java,不是為了學習這門語言而學習,是要學習他的設計模式和優秀的功能實現方式)。jsp至少有兩樣東西對我們很有用,action和filter。 action是主要是處理一些事件邏輯,就像add.php中我們定義的action()函數一樣,用來驗證和獲取表單提交上來的數據。當然這樣寫的代碼量和你以前方法的代碼量是一樣的,好像沒有什麼區別,但是它實現了代碼的分離,結構是不是比你以前的方法清晰很多呢? filter是一個過濾功能,用來過濾和重新定向網絡的訪問,對一些非法的請求和錯誤的請求進行重新的定向。讓我們來通過一個後台管理的程序來看看他具體的作用。 將下面的這個函數copy到你的CoreUtil.php裡面,這個函數是一個後台管理登陸的過濾函數,一個是不在本地緩存web頁面的函數: function windowNoCache($cache){ if(!$cache headers_sent()) return ; header('Expires: '.date('D,d M Y H:i:s',mktime(0,0,0,1,1,2000)).' GMT'); header('Last-Modified:'.gmdate('D,d M Y H:i:s').' GMT'); header('Cache-control: private, no-cache,must-revalidate'); header('Pragma: no-cache'); } function isAdminLogin(){ if($_SESSION[relogin]=="ok") return; if($_SESSION[adminuser]!=SYS_ADMIN_NAME){ $_SESSION[relogin] = "ok"; die("<script language=\"javascript\"> top.location='adminlogin.php'; </script>"); } $_SESSION[relogin] = "no"; } 然後在 根目錄 底下加上如下的文件 ------------adminconfig.inc.php------------ <?php define('SYS_ADMIN_NAME', 'hello'); //後台管理登陸名 define('SYS_ADMIN_PASSWORD', 'hello'); //後台管理登陸密碼 include 'config.inc.php'; windowNoCache(true); isAdminLogin(); ?> ------------adminindex.php---------------- <?php require_once "adminconfig.inc.php"; renderTpl('adminindex.htm', array()); ?> ------------adminlogin.php------------------ <?php include "adminconfig.inc.php"; if($_POST[name]==SYS_ADMIN_NAME && $_POST[code]==SYS_ADMIN_PASSWORD){ $_SESSION[adminuser] = SYS_ADMIN_NAME; header("location: adminindex.php"); }else{ renderTpl('adminlogin.htm', array()); } ?> 在 smart/template 目錄下面加上如下的文件 ------------adminlogin.htm------------------ <form name="form1" method="post" action=""> <input type="text" name="name" size="20" value=""> <input type="password" name="code" size="20" value=""> <input type="submit" name="Submit" value=" 登 陸 "> </form> ------------adminindex.htm---------------- <h2>您好歡迎登陸後台管理</h2> 現在訪問adminindex.php看看會發生什麼事情,然後用adminconfig.inc.php裡面設定的用戶名密碼登陸。這種功能在web的很多地方都可以派上用場,應該是一個好的方法吧。其他的後台訪問的頁面只要也都加載了adminconfig.inc.php ,就不用再考慮後台訪問權限的問題了。 十一 附錄 簡單的隱藏文件的擴展名,搞暈浏覽者,讓他不知道你是用什麼語言編的程序。 就以list1.php為例子吧, 1、我們修改list1.php的名稱為list1.tmp 2、進入命令行窗口(dos窗口),在web的目錄下面建立一個文件,文件名是“.htAccess”。 3、編輯“.htaccess”文件,輸入以下的內容 AddType application/x-httpd-php .tmp 通過浏覽器訪問list1.tmp,看看是不是ok了。