PHP緩衝技術

一、緩存技術:   

有些信息比方經常不變的,但是還是能變的信息放在緩存中以加快顯示速度,這是很有價值的,所謂的緩存,通俗的理解就是一些保存在服務器端的共用信息.它是於服務器同生死的,我們在保存緩存的時候可以指定下次更新的時間的判斷,比方要在5分鐘更新一次,可以記錄上次更新的時間,和當前時間比較,如果大於 5 分鐘 ,讀取數據庫,更新換成,否則直接讀取緩存數據,當然,緩存需要客戶端用戶激活的,只需一次.

ob_start()函數:打開輸出緩衝區.
     函數格式 void ob_start(void) 
     說明:當緩衝區激活時,所有來自PHP程序的非文件頭信息均不會發送,而是保存在內部緩衝區。爲了輸出緩衝區的內容,可以使用ob_end_flush()或flush()輸出緩衝區的內容。

Flush:刷新緩衝區的內容,輸出。
     函數格式:flush() 
     說明:這個函數經常使用,效率很高。

ob_get_contents :返回內部緩衝區的內容。
     函數格式:string ob_get_contents(void) 
     說明:這個函數會返回當前緩衝區中的內容,如果輸出緩衝區沒有激活,則返回 FALSE.

ob_get_length:返回內部緩衝區的長度。
     函數格式:int ob_get_length(void) 
     說明:這個函數會返回當前緩衝區中的長度;和ob_get_contents一樣,如果輸出緩衝區沒有激活,則返回 FALSE.

ob_end_clean:刪除內部緩衝區的內容,並且關閉內部緩衝區
     函數格式:void ob_end_clean(void) 
     說明:這個函數不會輸出內部緩衝區的內容而是把它刪除

ob_end_flush:發送內部緩衝區的內容到瀏覽器,並且關閉輸出緩衝區
     函數格式:void ob_end_flush(void) 
     說明:這個函數發送輸出緩衝區的內容(如果有的話)

ob_implicit_flush:打開或關閉絕對刷新
     函數格式:void ob_implicit_flush ([int flag]) 
     說明:默認爲關閉緩衝區,打開絕對輸出後,每個腳本輸出都直接發送到瀏覽器,不再需要調用 flush()    

二、文件寫入:   

int fwrite ( resource handle, string string [, int length] )
fwrite() 把 string 的內容寫入 文件指針 handle 處。 如果指定了 length,當寫入了 length 個字節或者寫完了 string 以後,寫入就會停止,視乎先碰到哪種情況。 
fwrite() 返回寫入的字符數,出現錯誤時則返回 FALSE 。 
相關參考官方網站: 文件參考

三、解決方案

思路:開啓 ob_start緩衝,當已經調出數據的時候獲取 ob_get_contents,然後生成靜態頁,ob_end_clean清除緩衝.ok,就這麼來,來看一個例子(php+mysql的結合):

創建數據庫:

  1. CREATE TABLE `bihtml` (  
  2.    `id` int(11) NOT NULL auto_increment,  
  3.    `szdtitle` varchar(16) NOT NULL,  
  4.    `szdcontent` text NOT NULL,  
  5.    PRIMARY KEY   (`id`)    
  6. ) TYPE=MyISAM; 

獲取當前的ID,並導入模板:

 四、說明事項

1: 一般建議管理員添加數據的時候就生成靜態頁面,可以考慮記錄生成的文件名次和路徑.

2: php主要是     ob_starts()和 ob_get_contents,生成靜態頁面的時候很有用,當然也可以考慮調出數據庫直接替換模板裏面的變量也是可以的.

3: 主要的模板使用smarty,phplib都是可以的,smarty使用比較簡易.

一、引論

PHP,一門最近幾年興起的web設計腳本語言,由於它的強大和可伸縮性,近幾年來得到長足的發展,php相比傳統的asp網站,在速度上有絕對的優勢,想mssql轉6萬條數據php如需要40秒,asp不下2分鐘.但是,由於網站的數據越來越多,我們渴求能更快速的調用數據,不必要每次都從數據庫掉,我們可以從其他的地方,比方一個文件,或者某個內存地址,這就是php的緩存技術,也就是Cache技術.

二、分析深入

一般來說,緩存的目的是把數據放在一個地方讓訪問的更快點,毫無疑問,內存是最快的,但是,幾百M的數據能往內存放麼?這不現實,當然,有的時候臨時放如服務器緩存,如ob_start()這個緩存頁面開啓的話在發送文件頭之前頁面內容都被緩存在內存中,知道等頁面輸出自動清楚或者等待ob_get_contents的返回,或者被ob_end_clean顯示的清除,這在靜態頁面的生成中能很好的利用,在模板中能得到很好的體現,我的這篇文章深入的討論了:談PHP生成靜態頁面,這是一種方式,但這是臨時性的,不是解決我們問題的好方法.

另外,在asp中有一對象application,可以保存公用的參數,這也算點緩存,但在php,我至今沒看到開發者產出這種對象,的確,沒必要.asp.net的頁面緩存技術就用的是viewstate,而cache就是文件關聯,(不一定準確),文件被修改,更新緩存,文件沒被修改而且不超時(註釋1),就讀取緩存,返回結果,就是這個思路,看看這個源碼:

下面我打斷這個代碼逐行解釋.

三、程序透析

這個緩存類(類沒什麼好怕的.請繼續看)名稱是cache,有2個屬性:

private $cache_dir;
private $expireTime=180;

$cache_dir是緩存文件所放的相對網站目錄的父目錄, $expireTime(註釋一)是我們緩存的數據過期的時間,主要是這個思路:
當數據或者文件被加載的時候,先判斷緩存文件存在不,返回false ,文件最後修改時間和緩存的時間和比當前時間大不,大的話說明緩存還沒到期,小的話返回false,當返回false的時候,讀取原始數據,寫入緩存文件中,返回數據.

接着看程序:

  1. function __construct($cache_dirname){  
  2. if(!@is_dir($cache_dirname)){  
  3.    if(!@mkdir($cache_dirname,0777)){  
  4.    $this->warn('緩存文件不存在而且不能創建,需要手動創建.');  
  5.    return false;  
  6.    }  
  7. }  
  8. $this->cache_dir = $cache_dirname;  

當類第一次被實例的時候構造默認函數帶參數緩存文件名稱,如文件不存在,創建一個有編輯權限的文件夾,創建失敗的時候拋出異常.然後把cache類的 $cache_dir屬性設置爲這個文件夾名稱,我們的所有緩存文件都是在這個文件夾下面的.

  1. function __destruct(){  
  2. echo 'Cache class bye.';  

這是class類的析構函數,爲了演示,我們輸出一個字符串表示我們釋放cache類資源成功.

  1. function warn($errorstring){  
  2. echo "<b><font color='red'>發生錯誤:<pre>".$errorstring."</pre></font></b>";  

這個方法輸出錯誤信息.

這個方法返回當前url的信息,這是我看國外很多人的cms系統這樣做,主要是緩存x.php?page=1,x.php?page=2,等這種文件的,這裏列出是爲了擴展的這個cache類功能的.

  1. function cache_page($pageurl,$pagedata){  
  2. if(!$fso=fopen($pageurl,'w')){  
  3.    $this->warns('無法打開緩存文件.');//trigger_error  
  4.    return false;  
  5. }  
  6. if(!flock($fso,LOCK_EX)){//LOCK_NB,排它型鎖定  
  7.    $this->warns('無法鎖定緩存文件.');//trigger_error  
  8.    return false;  
  9. }  
  10. if(!fwrite($fso,$pagedata)){//寫入字節流,serialize寫入其他格式  
  11.    $this->warns('無法寫入緩存文件.');//trigger_error  
  12.    return false;  
  13. }  
  14. flock($fso,LOCK_UN);//釋放鎖定  
  15. fclose($fso);  
  16. return true;  

cache_page方法分別傳入的是緩存的文件名稱和數據,這是把數據寫到文件裏的方法,先用fopen打開文件,然後調用句柄鎖定這個文件,然後用fwrite寫入文件,最後釋放這個句柄,任何一步發生錯誤將拋出錯誤. 您可能看到這個註釋:

寫入字節流,serialize寫入其他格式

順便一提的是如果我們要把一個數組,(可以從MySQL數據庫裏面select查詢除了的結果)用serialize函數寫入,用unserialize讀取到原來的類型.

  1. function display_cache($cacheFile){  
  2.              if(!file_exists($cacheFile)){  
  3.      $this->warn('無法讀取緩存文件.');//trigger_error  
  4.      return false;  
  5.              }  
  6.     echo '讀取緩存文件:'.$cacheFile;  
  7. //return unserialize(file_get_contents($cacheFile));  
  8.          $fso = fopen($cacheFile'r');  
  9.          $data = fread($fsofilesize($cacheFile));  
  10.          fclose($fso);  
  11. return $data;  

這是由文件名稱讀取緩存的方法,直接打開文件,讀取全部,如果文件不存在的或者無法讀取的話返回false,當然,你感到不人性的話,可以重新生成緩存.

  1. function readData($cacheFile='default_cache.txt'){  
  2. $cacheFile = $this->cache_dir."/".$cacheFile;  
  3. if(file_exists($cacheFile)&&filemtime($cacheFile)>(time()-$this->expireTime)){  
  4.    $data=$this->display_cache($cacheFile);  
  5.    }else{  
  6.     $data="from here wo can get it from mysql database,update time is <b>".date('l dS /of F Y h:i:s A')."</b>,過期時間是:".date('l dS /of F Y h:i:s A',time()+$this->expireTime)."----------";  
  7.     $this->cache_page($cacheFile,$data);  
  8. }  
  9.    return $data;  

這個函數是我們調用的方法,可以寫成接口的方法,由傳入參數判斷文件存在不,文件最後修改時間+expireTime的時間是不是過了當前時間(大於的話說明沒有過期),如果文件不存在或者已經過期,重新加載原始數據,這裏,爲了簡單期間,我們是直接源是字符串,您可以把cache類繼承某類,取到數據庫的數據.(註釋2)

四、補充說明,結語

註釋一:這個緩存的時間您可以自己調,可以根據時間情況讀取數組,xml,緩存等,請按照您的方便,值得一提的是緩存的時間(也就是緩存的key)也用緩存控制,.這在cms系統中被廣泛使用,他們把要更新的key放在緩存中,非常容易控制全戰.

註釋二:php5開始支持類繼承,這是讓人興奮的,把網站全局休息寫在一個配置的類裏面,再寫與數據層交互的類(如與MySQL交互的類),我們的這個cache類繼承數據交互的類,可以非常容易的讀取數據庫,這是外話,此處不再展開,有時間和大家詳談.

特別說明,這個類文件針對的php5以上版本,其他版本的請不要使用類.

  1. function get_url() {  
  2.          if (!isset($_SERVER['REQUEST_URI'])) {  
  3.                  $url = $_SERVER['REQUEST_URI'];  
  4.          }else{  
  5.                  $url = $_SERVER['SCRIPT_NAME'];  
  6.                  $url .= (!emptyempty($_SERVER['QUERY_STRING'])) ? '?' . $_SERVER['QUERY_STRING'] : '';  
  7.          }  
  8.  
  9.          return $url;  
  1. <?php  
  2. class cache{  
  3. /*  
  4. Class Name: cache  
  5. Description: control to cache data,$cache_out_time is a array to save cache date time out.  
  6. Version: 1.0  
  7. Author: 老農 cjjer  
  8. Last modify:2006-2-26  
  9. Author URL: http://www.cjjer.com  
  10. */ 
  11. private $cache_dir;  
  12. private $expireTime=180;//緩存的時間是 60 秒  
  13. function __construct($cache_dirname){  
  14. if(!@is_dir($cache_dirname)){  
  15.    if(!@mkdir($cache_dirname,0777)){  
  16.    $this->warn('緩存文件不存在而且不能創建,需要手動創建.');  
  17.    return false;  
  18.    }  
  19. }  
  20. $this->cache_dir = $cache_dirname;  
  21. }  
  22. function __destruct(){  
  23. echo 'Cache class bye.';  
  24. }  
  25.  
  26. function get_url() {  
  27.          if (!isset($_SERVER['REQUEST_URI'])) {  
  28.                  $url = $_SERVER['REQUEST_URI'];  
  29.          }else{  
  30.                  $url = $_SERVER['SCRIPT_NAME'];  
  31.                  $url .= (!emptyempty($_SERVER['QUERY_STRING'])) ? '?' . $_SERVER['QUERY_STRING'] : '';  
  32.          }  
  33.  
  34.          return $url;  
  35. }  
  36.  
  37. function warn($errorstring){  
  38. echo "<b><font color='red'>發生錯誤:<pre>".$errorstring."</pre></font></b>";  
  39. }  
  40.  
  41. function cache_page($pageurl,$pagedata){  
  42. if(!$fso=fopen($pageurl,'w')){  
  43.    $this->warns('無法打開緩存文件.');//trigger_error  
  44.    return false;  
  45. }  
  46. if(!flock($fso,LOCK_EX)){//LOCK_NB,排它型鎖定  
  47.    $this->warns('無法鎖定緩存文件.');//trigger_error  
  48.    return false;  
  49. }  
  50. if(!fwrite($fso,$pagedata)){//寫入字節流,serialize寫入其他格式  
  51.    $this->warns('無法寫入緩存文件.');//trigger_error  
  52.    return false;  
  53. }  
  54. flock($fso,LOCK_UN);//釋放鎖定  
  55. fclose($fso);  
  56. return true;  
  57. }  
  58.  
  59. function display_cache($cacheFile){  
  60.              if(!file_exists($cacheFile)){  
  61.      $this->warn('無法讀取緩存文件.');//trigger_error  
  62.      return false;  
  63.              }  
  64.     echo '讀取緩存文件:'.$cacheFile;  
  65. //return unserialize(file_get_contents($cacheFile));  
  66.          $fso = fopen($cacheFile'r');  
  67.          $data = fread($fsofilesize($cacheFile));  
  68.          fclose($fso);  
  69. return $data;  
  70. }  
  71.  
  72. function readData($cacheFile='default_cache.txt'){  
  73. $cacheFile = $this->cache_dir."/".$cacheFile;  
  74. if(file_exists($cacheFile)&&filemtime($cacheFile)>(time()-$this->expireTime)){  
  75.    $data=$this->display_cache($cacheFile);  
  76.    }else{  
  77.     $data="from here wo can get it from mysql database,update time is <b>".date('l dS /of F Y h:i:s A')."</b>,過期時間是:".date('l dS /of F Y h:i:s A',time()+$this->expireTime)."----------";  
  78.     $this->cache_page($cacheFile,$data);  
  79. }  
  80.    return $data;  
  81. }  
  82.  
  83.  
  84. }  
  85. ?> 


 

  1. ob_start();  
  2. $id=_POST['id']  
  3. if(!isset($id)&&is_integer($id))  
  4. {  
  5. @$db=new mysqli('localhost','root','admin','bihtml');  
  6. $result=$db->fetch_one_array("select   * from szd_bi where id='$id'");  
  7.     if(!emptyempty($result))  
  8.     {   
  9.     $tmp->assign(array(  
  10.      "Szdtitle",htmlspecialchars($result['titles']),  
  11.      "Szdcontent",$result['titles']));   
  12.     }  
  13. $tpl->display('default_1.tpl');  
  14. $this_my_f= ob_get_contents(); //此處關鍵  
  15. ob_end_clean();  
  16. $filename = "$id.html";  
  17. if(tohtmlfile_cjjer($filename,$this_my_f))  
  18. echo "生成成功 $filename";  
  19. else 
  20. echo "生成識別";  
  21. }  
  22. }  
  23.  
  24. //把生成文件的過程寫出函數  
  25. function tohtmlfile_cjjer($file_cjjer_name,$file_cjjer_content)  
  26. {  
  27. if (is_file ($file_cjjer_name)){  
  28.    @unlink ($file_cjjer_name);  
  29. }  
  30. $cjjer_handle = fopen ($file_cjjer_name,"w");  
  31. if (!is_writable ($file_cjjer_name)){  
  32.    return false;  
  33. }  
  34. if (!fwrite ($cjjer_handle,$file_cjjer_content)){  
  35.    return false;  
  36. }   
  37. fclose ($cjjer_handle); //關閉指針  
  38. return $file_cjjer_name;  

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章