構建可配置PHP應用程序的正確方式(一)
本文舉例說明了創建可配置 PHP 應用程序的幾種方法。文中也探討了應用程序中理想的配置點,并在應用程序過分可配置和過分封閉之間尋求一個平衡點。 如果計劃讓其他人或公司可以使用您的 PHP 應用程序,需要確保該程序是可配置的。至少,要允許用戶以一種 安
本文舉例說明了創建可配置
clearcase/" target="_blank" >cc>PHP 應用程序的幾種方法。文中也探討了應用程序中理想的配置點,并在應用程序過分可配置和過分封閉之間尋求一個平衡點。
如果計劃讓其他人或公司可以使用您的 PHP 應用程序,需要確保該程序是可配置的。至少,要允許用戶以一種
安全的方式設置
數據庫登錄及密碼,從而使其中的材料不會對外公開。
本文展示了幾種用于存儲配置設置及編輯這些設置的技術。另外,文中也為哪些元素需要設為可配置以及如何避免陷入配置過度或者配置不足的困境提供了指導。
使用 INI 文件進行配置 PHP 內建了對配置文件的支持。這是通過 php.ini 文件這樣的初始化文件(INI)機制實現的,在 php.ini 文件中定義了
數據庫連接超時或會話如何存儲等常量。如果愿意的話,可以在這個 php.ini 文件中為應用程序定制配置。為了說明,我將下列代碼行添加到 php.ini 文件中。
myapptempdir=foo
然后,我編寫了一個小 PHP 腳本來讀取這個配置項,如清單 1 所示。
清單 1. ini1.php
<?php function get_template_directory() { $v = get_cfg_var( "myapptempdir" ); return ( $v == null ) ? "tempdir" : $v; }
echo( get_template_directory()."\n" ); ?> |
當在命令行中運行這段代碼時,得到如下結果:
太棒了。但為什么不能用標準的 INI 函數來獲取 myapptempdir 配置項的值呢?我研究了一下,發現在大多數情況下,定制配置項不能使用這些方法來獲取。然而,使用 get_cfg_var 函數卻是可以訪問的。
為使這個方法更加簡單,將對變量的訪問封裝在第二個函數中,該函數使用配置鍵名及一個缺省值作為參數,如下所示。
清單 2. ini2.php
function get_ini_value( $n, $dv ) { $c = get_cfg_var( $n ); return ( $c == null ) ? $dv : $c; }
function get_template_directory() { return get_ini_value( "myapptempdir", "tempdir" ); } |
這是對如何訪問 INI 文件的一個很好的概括,所以,如果要使用一個不同的機制或將這個 INI 文件存儲到其他位置,就不需要為更改大量的函數而大費周折。
我不推薦使用 INI 文件作為應用程序的配置,這有兩個理由。首先,雖然這樣做較容易讀取 INI 文件,但卻幾乎不可能
安全地寫 INI 文件。所以這樣做只適合于只讀配置項。第二,php.ini 文件在
服務器的所有應用程序上共享,所以我認為特定于應用程序的配置項不應該寫在該文件中。
需要對 INI 文件了解什么呢?最重要的是如何重置 include 路徑來添加配置項,如下所示。
清單 3. ini3.php
<?php echo( ini_get("include_path")."\n" ); ini_set("include_path", ini_get("include_path").":./mylib" ); echo( ini_get("include_path")."\n" ); ?> |
在本例中,我將我的本地 mylib 目錄添加到了 include 路徑中,所以能夠從該目錄中 require PHP 文件,而不需要將該路徑添加到 require 語句中。
PHP 中的配置 通常對于在 INI 文件中存儲配置條目的一個替代辦法是使用一個簡單的 PHP 腳本來保持數據。如下是一個樣例。
清單 4. config.php
<?php # Specify the location of the temporary directory # $TEMPLATE_DIRECTORY = "tempdir"; ?> |
使用該常量的代碼如下所示。
清單 5. php.php
<?php require_once 'config.php';
function get_template_directory() { global $TEMPLATE_DIRECTORY; return $TEMPLATE_DIRECTORY; }
echo( get_template_directory()."\n" ); ?> |
該代碼首先包含配置文件(config.php),接著就可以直接使用這些常量了。
使用這項技術有很多優勢。首先,如果某些人僅僅瀏覽 config.php 文件,該頁面是空白的。所以可以將 config.php 放到相同的文件中,并作為
Web應用程序的根。第二,在任何編輯器中都可編輯,并且在一些編輯器中甚至具備語法著色及語法檢查功能。
這項技術的缺點是,這是一個像 INI 文件一樣的只讀技術。將數據從此文件中提取出來是輕而易舉的,但在該 PHP 文件中調整數據卻很困難,在一些情況下甚至是不可能的。
下面的替代方法顯示了如何編寫在本質上既可讀又可寫的配置系統。
文本文件
前面的兩個例子對于只讀配置條目都是合適的,但對于既讀又寫的配置參數來說又如何呢?首先,看看清單 6 中的文本配置文件。
清單 6. config.txt
# My application's configuration file Title=My App TemplateDirectory=tempdir |
這是同 INI 文件相同的文件格式,但我自己編寫了輔助工具。為此,我創建了自己的 Configuration 類,如下所示。
清單 7. text1。PHP
<?php class Configuration { private $configFile = 'config.txt'; private $items = array(); function __construct() { $this->parse(); } function __get($id) { return $this->items[ $id ]; } function parse() { $fh = fopen( $this->configFile, 'r' ); while( $l = fgets( $fh ) ) { if ( preg_match( '/^#/', $l ) == false ) { preg_match( '/^(.*?)=(.*?)$/', $l, $found ); $this->items[ $found[1] ] = $found[2]; } } fclose( $fh ); } }
$c = new Configuration();
echo( $c->TemplateDirectory."\n" ); ?> |
該代碼首先創建了一個 Configuration 對象。該構造函數接下來讀取 config.txt 并用解析過的文件內容來設置局部變量 $items。
該腳本隨后尋找 TemplateDirectory,這并沒有在對象中直接定義。因此,使用設置成 'TemplateDirectory' 的 $id 來調用神奇的 __get 方法,__get 方法針對該鍵返回 $items 數組中的值。
這個 __get 方法特定于 PHP V5 環境,所以此腳本必須在 PHP V5 下運行。實際上,本文中所有的腳本都需要在 PHP V5 下運行。
當在命令行運行此腳本時,能看到下列結果:
一切都在預料之中,該對象讀取 config.txt 文件,然后為 TemplateDirectory 配置項獲得正確的值。
但對于設置一個配置值,應該怎么做呢?在此類中建立一個新方法及一些新的
測試代碼,就能夠得到這個功能,如下所示。
清單 8. text2.php
<?php class Configuration { ...
function __get($id) { return $this->items[ $id ]; }
function __set($id,$v) { $this->items[ $id ] = $v; } function parse() { ... } } $c = new Configuration(); echo( $c->TemplateDirectory."\n" ); $c->TemplateDirectory = 'foobar'; echo( $c->TemplateDirectory."\n" ); ?> |
現在,有了一個 __set 函數,它是 __get 函數的 “堂兄弟”。該函數并不為一個成員變量獲取值,當要設置一個成員變量時,才調用這個函數。底部的
測試代碼設置值并打印出新值。
下面是在命令行中運行此代碼時出現的結果:
% php text2.php tempdir foobar % |
太好了!但如何能將它存儲到文件中,從而將使這個改動固定下來呢?為此,需要寫文件并讀取它。用于寫文件的新函數,如下所示。
清單 9. text3.php
<?php class Configuration { ...
function save() { $nf = ''; $fh = fopen( $this->configFile, 'r' ); while( $l = fgets( $fh ) ) { if ( preg_match( '/^#/', $l ) == false ) { preg_match( '/^(.*?)=(.*?)$/', $l, $found ); $nf .= $found[1]."=".$this->items[$found[1]]."\n"; } else { $nf .= $l; } } fclose( $fh ); copy( $this->configFile, $this->configFile.'.bak' ); $fh = fopen( $this->configFile, 'w' ); fwrite( $fh, $nf ); fclose( $fh ); } }
$c = new Configuration(); echo( $c->TemplateDirectory."\n" ); $c->TemplateDirectory = 'foobar'; echo( $c->TemplateDirectory."\n" ); $c->save(); ?> |
新的 save 函數巧妙地操作 config.txt。我并沒有僅用更新過的配置項重寫文件(這樣會移除掉注釋),而是讀取了這個文件并靈活地重寫了 $items 數組中的內容。這樣的話,就保留了文件中的注釋。
在命令行運行該腳本并輸出文本配置文件中的內容,能夠看到下列輸出。
清單 10. 保存函數輸出
% php text3.php tempdir foobar % cat config.txt # My application's configuration file Title=My App TemplateDirectory=foobar % |
原始的 config.txt 文件現在被新值更新了。
原文轉自:http://www.kjueaiud.com
老湿亚洲永久精品ww47香蕉图片_日韩欧美中文字幕北美法律_国产AV永久无码天堂影院_久久婷婷综合色丁香五月