INI設定
和上一章你看到的超級全域變數以及持久化常數一樣, php.iniini值必須在執行的MINIT變數和其他特性不同的是, INI選項的定義僅由簡單的啟動/終止線組成.
PHP_MINIT_FUNCTION(sample4) { REGISTER_INI_ENTRIES(); return SUCCESS; } PHP_MSHUTDOWN_FUNCTION(sample4) { UNREGISTER_INI_ENTRIES(); return SUCCESS; }
定義並訪問INI設置
INI指令本身是在源碼文件中MINIT函數上面下面的巨集完全獨立的定義的, 在這兩個巨集之間可以定義一個或多個INI指令:
PHP_INI_BEIGN() PHP_INI_END()
這兩個宏函數和ZEND_BEGIN_MODULE_GLGLGLMOm/ENDEND不過這裡不是typdef一個結構體, 而是對靜態資料實例定義的框架組織:
static zend_ini_entry ini_entries[] = { {0,0,NULL,0,NULL,NULL,NULL,NULL,NULL,0,NULL,0,0,NULL} };
如你所見, 它定義了一個zend_ini_entry值的向量, 以空的向量記錄. 這和你在前面看到的靜態向量function_entry的定義一致.
簡單的INI設定
現在, 你已經有一個INI結構體用於定義INI指令, 以及引擎註冊指令INI設定的機制, 因此我們可以真正的去為你的擴展定義一些INI指令了. 假設你的擴展暴露了一個打招呼的函數, 就像第5章"你的第一個擴展"中一樣, 不過,你想要讓打招呼的話可以自訂:
PHP_FUNCTION(sample4_hello_world) { php_printf("Hello World!\n"); }
最簡單最直接的方式就是定義一個INI指令, 並給它一個預設值"Hello world!":
rrrereee你
可能已經猜到了, 這個宏的前兩個參數表示INI指令的名字和它的默認值. 第三個參數用來確定引擎是否允許這個INI指令被修改(這將涉及到本章後面要介紹的訪問級別問題). 最後一個參數是一個回調函數, 它將在每次INI指令的值發生變化時被調用. 你將在修改事件一節看到這個參數的細節.
譯註: 如果你和譯者一樣遇到結果和原著結果預期不一致時, 請在測試時, 在你的MINIT()函數中增加一句"REGISTER_INI_ENTRIES();"調用, 並確保該調用在你的MINIT中分配全局空間之後執行.
現在你的INI設定已經定義, 只需要在你的打招呼函數中使用就可以了.
#include "php_ini.h" PHP_INI_BEGIN() PHP_INI_ENTRY("sample4.greeting", "Hello World", PHP_INI_ALL, NULL) PHP_INI_END()一定要注意, char *的值是引擎所有的, 一定不要修改. 正因為這樣, 所以將你本地用來臨時儲存INI設定值的變數定義為const修飾. 當然, 並不是所有的INI值都是字串; 還有其他的宏用來取得整數, 浮點型以及布爾型的值:
PHP_FUNCTION(sample4_hello_world) { const char *greeting = INI_STR("sample4.greeting"); php_printf("%s\n", greeting); }
通常你想要知道的是INI設定的當前值; 不過, 作為補充, 存在幾個宏可以用來讀取未經修改的INI設定值:
long lval = INI_INT("sample4.intval"); double dval = INI_FLT("sample4.fltval"); zend_bool bval = INI_BOOL("sample4.boolval");
這個例子中, INI指令的名字"sample4.greeting"增加了擴展名作為前綴, 這樣來保證不會和其他擴展暴露的INI指令名字衝突. 對於私有的擴展來說, 這個前綴不是必須的, 但是對於商業化或開源發布的公開擴展還是鼓勵這樣做的.
訪問級別
對於INI默認指令值值不變; 然而, 對於某些特殊的環境或腳本內特定的動作, 這些值可能需要被修改. 如下表所示, INI指令的值可能在下面3個點被修改:
訪問等級 |
意義 |
|||||||||
php.ini | ,或 apache的httpd.conf設定檔 |
位於Apache的httpd.conf設定檔中 | 去修改||||||||
設定了. INI |
某些设置如果可以在任何地方被修改就没有多大意义了, 比如safe_mode, 如果可以在任何地方去修改, 那么恶意脚本的作者就可以很简单的去禁用safe_mode, 接着去读或修改本不允许操作的文件. 类似的, 某些非安全相关的指令比如register_globals或magic_quotes_gpc, 在脚本中不能被修改, 因为, 在脚本执行时, 它所影响的事情已经发生过了. 这些指令的访问控制是通过PHP_INI_ENTRY()的第三个参数完成的. 在你前面例子中, 使用了PHP_INI_ALL, 它的定义是一个位域操作: PHP_INI_SYSTEM | PHP_INI_PERDIR | PHP_INI_USER. 对于register_globals和magic_quotes_gpc这样的指令, 定义的访问级别为PHP_INI_SYSTEM | PHP_INI_PERDIR. 排除了PHP_INI_USER将导致以这个名字调用ini_set()时最终会失败. 现在, 你可能已经猜到, safe_mode和open_basedir这样的指令应该仅被定义为PHP_INI_SYSTEM. 这样的设置就确保了只有系统管理员可以修改这些值, 因为只有它们可以访问修改php.ini或httpd.conf文件中的配置. 修改事件 当INI指令被修改时, 无论是通过ini_set()函数还是某个perdir指令的处理, 引擎都会为其测试OnModify回调. 修改处理器可以使用ZEND_INI_MH()宏定义, 并通过在OnModify参数上传递函数名附加到INI指令上: ZEND_INI_MH(php_sample4_modify_greeting) { if (new_value_length == 0) { return FAILURE; } return SUCCESS; } PHP_INI_BEGIN() PHP_INI_ENTRY("sample4.greeting", "Hello World", PHP_INI_ALL, php_sample4_modify_greeting) PHP_INI_END() 通过在new_value_length为0时返回FAILURE, 这个修改处理器禁止将greeting设置为空字符串. ZEND_INI_MH()宏产生的整个原型如下: int php_sample4_modify_greeting(zend_ini_entry *entry, char *new_value, uint new_value_length, void *mh_arg1, void *mh_arg2, void *mh_arg3, int stage TSRMLS_DC); 各个参数的含义见下表:
|