[Traduction][Développement d'extensions php et embarquées] Chapitre 13-Paramètres php INI

黄舟
Libérer: 2023-03-05 16:30:02
original
1058 Les gens l'ont consulté


Paramètres INI

et les précédents 1 Comme les variables superglobales et les constantes persistantes que vous avez vues au chapitre 1, les valeurs php.ini doivent être définies dans le bloc MINIT étendu. Cependant, contrairement à d'autres fonctionnalités, la définition des options INI se compose uniquement de simples lignes de démarrage/arrêt.

PHP_MINIT_FUNCTION(sample4)
{
    REGISTER_INI_ENTRIES();
    return SUCCESS;
}
PHP_MSHUTDOWN_FUNCTION(sample4)
{
    UNREGISTER_INI_ENTRIES();
    return SUCCESS;
}
Copier après la connexion

Définir et accéder aux paramètres INI

La commande INI elle-même est au-dessus de la fonction MINIT dans la source fichier de code, défini de manière totalement indépendante à l'aide des macros suivantes, une ou plusieurs instructions INI peuvent être définies entre ces deux macros :

PHP_INI_BEIGN()
PHP_INI_END()
Copier après la connexion

Ces deux fonctions de macro sont similaires à ZEND_BEGIN_MODULE_GLOBALS()/ZEND_END_MODULE_GLOBALS() Cependant, il ne s'agit pas d'une structure typdef, mais d'une organisation-cadre pour la définition d'instances de données statiques :

<. 🎜>

static zend_ini_entry ini_entries[] = {
{0,0,NULL,0,NULL,NULL,NULL,NULL,NULL,0,NULL,0,0,NULL} };
Copier après la connexion

Comme vous pouvez le voir, il définit un vecteur de valeurs zend_ini_entry, se terminant par un enregistrement vide. C'est la même chose que. vous feriez La définition du vecteur statique function_entry vue plus tôt est cohérente.

Paramètres INI simples

Maintenant, vous have Il existe une structure INI utilisée pour définir les instructions INI, ainsi que le mécanisme permettant au moteur d'enregistrer/désinstaller les paramètres INI, afin que nous puissions réellement définir certaines instructions INI pour votre extension. Supposons que votre extension expose une fonction de message d'accueil, comme Identique à. au chapitre 5 "Votre première extension", vous pouvez cependant la personnaliser si vous souhaitez lui dire bonjour :

PHP_FUNCTION(sample4_hello_world)
{
    php_printf("Hello World!\n");
}
Copier après la connexion

La manière la plus simple et la plus directe est de définir une commande INI, et donnez-lui la valeur par défaut "Bonjour tout le monde !" :

#include "php_ini.h"
PHP_INI_BEGIN()
    PHP_INI_ENTRY("sample4.greeting", "Hello World",
                                    PHP_INI_ALL, NULL)
PHP_INI_END()
Copier après la connexion

Vous avez peut-être Je l'ai deviné, les deux premiers paramètres de cette macro représentent le nom de l'instruction INI et sa valeur par défaut. Le troisième paramètre est utilisé pour déterminer si le moteur autorise la modification de l'instruction INI (cela impliquera d'introduire le problème du niveau d'accès). plus loin dans ce chapitre) . Le dernier paramètre est une fonction de rappel qui sera appelée à chaque fois que la valeur de l'instruction INI change. Vous verrez les détails de ce paramètre dans la section Modifier les événements. Remarque sur la traduction : si vous, comme le traducteur, rencontrez des résultats incompatibles avec les résultats attendus du travail original, veuillez ajouter un appel "REGISTER_INI_ENTRIES();" à votre fonction MINIT() pendant le test, et assurez-vous que l'appel est dans votre exécution après avoir alloué un espace global dans MINIT.

Maintenant que vos paramètres INI ont été définis, il ne vous reste plus qu'à l'utiliser dans votre fonction d'accueil .

Assurez-vous de noter que la valeur de char * appartient au moteur et ne doit pas être modifiée. Pour cette raison, définissez votre variable locale utilisée pour stocker temporairement le. INI définissant la valeur comme const Bien sûr, toutes les valeurs INI ne sont pas des chaînes ; il existe d'autres macros pour obtenir des valeurs entières, à virgule flottante et booléennes :

PHP_FUNCTION(sample4_hello_world)
{
    const char *greeting = INI_STR("sample4.greeting");
    php_printf("%s\n", greeting);
}
Copier après la connexion

long lval = INI_INT("sample4.intval");
double dval = INI_FLT("sample4.fltval");
zend_bool bval = INI_BOOL("sample4.boolval");
Copier après la connexion
Habituellement, ce que vous voulez savoir est la valeur actuelle du paramètre INI cependant, en complément, il existe plusieurs macros qui peuvent être utilisées pour lire la valeur non modifiée du paramètre INI ; Paramètre INI :

Dans cet exemple, le nom de l'instruction INI "sample4.greeting" est préfixé par une extension pour garantir qu'elle n'entrera pas en conflit avec les noms d'instructions INI exposés par d'autres extensions privées. ce préfixe n'est pas obligatoire, mais est encouragé pour les extensions publiques pour les versions commerciales ou open source

Niveau d'accès

.

Pour les instructions INI, il existe toujours une valeur par défaut avec laquelle commencer. Dans la plupart des cas, l'idéal est de laisser la valeur par défaut inchangée. Cependant, pour certaines circonstances particulières ou actions spécifiques au sein du script, ces valeurs ​​peut Doit être modifié. Comme le montre le tableau ci-dessous, la valeur de l'instruction INI peut être modifiée aux trois points suivants :



某些设置如果可以在任何地方被修改就没有多大意义了, 比如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()
Copier après la connexion

通过在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);
Copier après la connexion

各个参数的含义见下表:


Niveau d'accès

Signification

SYSTÈME

se trouve dans php.ini , ou apache de httpd.conf fichier de configuration et directives externes, affecter la phase de démarrage du moteur , peut être considéré comme INI défini"global"Valeur.

PERDIR

se trouve dans le fichier de configuration httpd.conf d'Apache > et directive , ou demander le répertoire ou répertoire virtuel où se trouve le script .htaccess fichiers sous l'hôte et d'autres apacheINI défini ailleurs avant de traiter la demande >COMMANDE.

UTILISATEUR

Une fois que le script commence à s'exécuter , ne peut être modifié qu'en appelant la fonction de l'espace utilisateur ini_set( ) INI ensembles .

参数名

含义

entry

pointe vers l'élément de commande INI réellement stocké par le moteur.Cette structure fournit Valeur actuelle , Valeur d'origine , module auquel il appartient , et quelques autres codes ci-dessous (zend_ini_entrystructure structure)Informations répertoriées

new_value

La valeur à définir.Si le processeur renvoie SUCCÈS,Cette valeur sera définie sur entrée->valeur, et si entrée-> orig_value n'a actuellement pas défini, définira la valeur actuelle sur entry->orig_value dans , et définissez la balise entry->modified .La longueur de ce la chaîne est passée new_value_lengthpassing.

mh_arg1, 2, 3

Ces 3 pointeurs correspondent aux pointeurs de données donnés lorsque l'instruction INI est défini (zend_ini_entry3 membres portant le même nom ).en fait ,Ces valeurs sont utilisées par le moteur pour le traitement interne,Vous n'avez pas besoin de vous en soucier.

scène

ZEND_INI_STAGE_ série Une des 5 valeurs : STARTUP, SHUTDOWN, ACTIVATE, DEACTIVATE, RUNTIME Ces constantes correspondent à MINIT, MSHUTDOWN, RINIT, RSHUTDOWN, et à l'exécution du script actif .


核心结构体: zend_ini_entry

struct _zend_ini_entry {
    int module_number;
    int modifiable;
    char *name;
    uint name_length;
    ZEND_INI_MH((*on_modify));
    void *mh_arg1;
    void *mh_arg2;
    void *mh_arg3;

    char *value;
    uint value_length;

    char *orig_value;
    uint orig_value_length;
    int modified;

    void ZEND_INI_DISP(*displayer);
};
Copier après la connexion

展示INI设置

在上一章, 你看到了MINFO函数以及相关的指令用于展示扩展的信息. 由于扩展暴露INI指令是很常见的, 因此引擎提供了一个公共的宏可以放置到PHP_MINFO_FUNCTION()中用于展示INI指令信息.

PHP_MINFO_FUNCTION(sample4)
{
    DISPLAY_INI_ENTRIES();
}
Copier après la connexion

这个宏将迭代PHP_INI_BEGIN()和PHP_INI_END()宏之间定义的INI指令集和, 在一个3列的表格中展示它们的INI指令名, 原始值(全局的), 以及当前值(经过PERDIR指令或ini_set()调用修改后)

默认情况下, 所有的指令都直接以其字符串形式输出. 对于某些指令, 比如布尔值以及用于语法高亮的颜色值, 则在展示处理时应用了其他格式. 这些格式是通过每个INI设置的显示处理器处理的, 它和你看到的OnModify一样是一个动态的回调函数指针.

显示处理器可以使用PHP_INI_ENTRY()宏的扩展版指定, 它接受一个额外的参数. 如果设置为NULL, 则使用展示字符串值的处理器作为默认处理器:

PHP_INI_ENTRY_EX("sample4.greeting", "Hello World", PHP_INI_ALL,
    php_sample4_modify_greeting, php_sample4_display_greeting)
Copier après la connexion

显然, 需要在INI设置定义之前声明这个函数. 和OnModify回调函数一样, 这可以通过一个包装宏以及少量编码完成:

#include "SAPI.h" /* needed for sapi_module */
PHP_INI_DISP(php_sample4_display_greeting)
{
    const char *value = ini_entry->value;

    /* 选择合适的当前值或原始值 */
    if (type == ZEND_INI_DISPLAY_ORIG &&
        ini_entry->modified) {
        value = ini_entry->orig_value;
    }

    /* 使得打招呼的字符串粗体显示(当以HTML方式输出时) */
    if (sapi_module.phpinfo_as_text) {
        php_printf("%s", value);
    } else {
        php_printf("<b>%s</b>", value);
    }
}
Copier après la connexion

绑定到扩展的全局空间

所有的INI指令都在Zend引擎内有一块存储空间, 可以用以跟踪脚本内的变更并进行请求外部的全局设置维护. 在这块存储空间中, 所有的INI指令都以字符串值存储. 你已经知道了, 这些值可以使用INI_INT(), INI_FLT(), INI_BOOL()等宏函数, 很简单的翻译成其他的标量类型.

这个查找和转换过程由于两个原因非常低效: 首先, 每次一个INI的值在获取时, 它必须通过名字在一个HashTable中进行定位. 这种查找方式对于仅在运行时编译的用户空间脚本而言是没有问题的, 但是对于已编译的机器代码源, 运行时做这个工作就毫无意义.

每次请求标量值的时候都需要将底层的字符串值转换到标量值是非常低效的. 因此我们使用你已经学习过的线程安全全局空间作为存储媒介, 每次INI指令值变更时更新它即可. 这样, 所有访问INI指令的代码都只需要查找你的线程安全全局空间结构体中的某个指针即可, 这样就获得了编译期优化的优点.

在你的php_sample4.h文件MODULE_GLOBALS结构体中增加const char *greeting; 接着更新sample4.c中的下面两个方法:

ZEND_INI_MH(php_sample4_modify_greeting)
{
    /* Disallow empty greetings */
    if (new_value_length == 0) {
        return FAILURE;
    }
    SAMPLE4_G(greeting) = new_value;
    return SUCCESS;
}
PHP_FUNCTION(sample4_hello_world)
{
    php_printf("%s\n", SAMPLE4_G(greeting));
}
Copier après la connexion

由于这是对INI访问的一种非常常见的优化方式, 因此引擎暴露了一组专门处理INI指令到全局变量的绑定宏:

STD_PHP_INI_ENTRY_EX("sample4.greeting", "Hello World",
    PHP_INI_ALL, OnUpdateStringUnempty, greeting,
    zend_sample4_globals, sample4_globals,
    php_sample4_display_greeting)
Copier après la connexion


这个宏执行和上面你自己的php_sample4_modify_greeting相同的工作, 但它不需要OnModify回调. 取而代之的是, 它使用了一个泛化的修改回调OnUpdateStringUnempty, 以及信息应该存储的空间. 如果要允许空的greeting指令值, 你可以直接指定OnUpdateString替代OnUpdateStringUnempty.

类似的, INI指令也可以绑定long, double, zend_bool的标量值. 在你的php_sample4.h中MODULE_GLOBALS结构体上增加几个字段:

long mylong;
double mydouble;
zend_bool mybool;
Copier après la connexion

现在在你的PHP_INI_BEGIN()/PHP_INI_END()代码块中使用STD_PHP_INI_ENTRY()宏创建新的INI指令, 它和对应的_EX版本的宏的区别只是显示处理器以及绑定到的值不同.

STD_PHP_INI_ENTRY("sample4.longval", "123",
    PHP_INI_ALL, OnUpdateLong, mylong,
    zend_sample4_globals, sample4_globals)
STD_PHP_INI_ENTRY("sample4.doubleval", "123.456",
    PHP_INI_ALL, OnUpdateDouble, mydouble,
    zend_sample4_globals, sample4_globals)
STD_PHP_INI_ENTRY("sample4.boolval", "1",
    PHP_INI_ALL, OnUpdateBool, mybool,
    zend_sample4_globals, sample4_globals)
Copier après la connexion

这里要注意, 如果调用了DISPLAY_INI_ENTRIES(), 布尔类型的INI指令"sample4.boolval"将和其他设置一样, 被显示为它的字符串值; 然而, 首选的布尔值指令应该被显示为"on"或"off". 要使用这些更加表意的显示, 你可以使用STD_PHP_INI_ENTRY_EX()宏并创建显示处理器, 或者使用另外一个宏:

STD_PHP_INI_BOOLEAN("sample4.boolval", "1",
    PHP_INI_ALL, OnUpdateBool, mybool,
    zend_sample4_globals *, sample4_globals)
Copier après la connexion

这个特定类型的宏是布尔类型特有的, 它提供的是将布尔值转换为"on"/"off"值的显示处理器.

小结

在本章, 你了解了php语言中最古老的特性之一的实现, 它也是阻碍php可移植的罪魁. 对于每个新的INI设置, 都会使得编写可移植代码变得更加复杂. 使用这些特性要非常慎重, 因为扩展以后时钟都要使用它了. 并且, 在使用时要注意不同系统间的行为一致性, 以免在维护时出现不可预期的状况.

接下来的三张, 我们将深入到流API, 开始使用流的实现层和包装操作, 上下文, 过滤器等.

以上就是[翻译][php扩展开发和嵌入式]第13章-php的INI设置 的内容,更多相关内容请关注PHP中文网(www.php.cn)!


Étiquettes associées:
php
source:php.cn
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal
À propos de nous Clause de non-responsabilité Sitemap
Site Web PHP chinois:Formation PHP en ligne sur le bien-être public,Aidez les apprenants PHP à grandir rapidement!