Heim > php教程 > php手册 > Hauptteil

Ändern Sie die INI-Konfiguration in den php_php-Grundlagen dynamisch

WBOY
Freigeben: 2016-05-16 08:59:56
Original
2044 Leute haben es durchsucht

1, Konfiguration während der Laufzeit ändern
Wie im vorherigen Artikel erwähnt, kann die Funktion ini_set einige PHP-Konfigurationen während der Ausführung von PHP dynamisch ändern. Beachten Sie, dass dies nur ein Teil davon ist und nicht alle Konfigurationen dynamisch geändert werden können. Informationen zur änderbaren INI-Konfiguration finden Sie unter: http://php.net/manual/zh/configuration.changes.modes.php

Wir betreten direkt die Implementierung von ini_set. Obwohl die Funktion etwas lang ist, ist die Logik sehr klar:

Code kopieren Der Code lautet wie folgt:

PHP_FUNCTION(ini_set)
{
char *varname, *new_value;
int varname_len, new_value_len;
char *old_value;

if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &varname, &varname_len, &new_value, &new_value_len) == FAILURE) {
         zurück;
}

// Den konfigurierten Wert von EG (ini_directives) abrufen
Old_value = zend_ini_string(varname, varname_len + 1, 0);

/* kopieren, um hierher zurückzukehren, da alter es möglicherweise freigibt */
If (old_value) {
RETVAL_STRING(old_value, 1);
} sonst {
RETVAL_FALSE;
}

// Wenn der abgesicherte Modus aktiviert ist, können die folgenden INI-Konfigurationen Dateivorgänge beinhalten und Sie müssen die UID überprüfen
#define _CHECK_PATH(var, var_len, ini) php_ini_check_path(var, var_len, ini, sizeof(ini))
/* Safe_Mode & BasedIR-Prüfung */
If (PG(safe_mode) || PG(open_basedir)) {
If (_CHECK_PATH(varname, varname_len, "error_log") ||
​​​​​​ _CHECK_PATH(varname, varname_len, "java.class.path") ||
​​​​​​ _CHECK_PATH(varname, varname_len, "java.home") ||
​​​​​​ _CHECK_PATH(varname, varname_len, "mail.log") ||
​​​​​​ _CHECK_PATH(varname, varname_len, "java.library.path") ||
​​​​​​​ _CHECK_PATH(varname, varname_len, "vpopmail.directory")) {
If (PG(safe_mode) && (!php_checkuid(new_value, NULL, CHECKUID_CHECK_FILE_AND_DIR))) {
                   zval_dtor(return_value);
RETURN_FALSE;
            }
If (php_check_open_basedir(new_value TSRMLS_CC)) {
                   zval_dtor(return_value);
RETURN_FALSE;
            }
}
}

// Im abgesicherten Modus sind die folgenden INIs geschützt und werden nicht dynamisch geändert
If (PG(safe_mode)) {
If (!strncmp("max_execution_time", varname, sizeof("max_execution_time")) ||
                !strncmp("memory_limit", varname, sizeof("memory_limit")) ||
               !strncmp("child_terminate", varname, sizeof("child_terminate"))
) {
               zval_dtor(return_value);
RETURN_FALSE;
}
}

// Zend_alter_ini_entry_ex aufrufen, um die INI-Konfiguration dynamisch zu ändern
If (zend_alter_ini_entry_ex(varname, varname_len + 1, new_value, new_value_len, PHP_INI_USER, PHP_INI_STAGE_RUNTIME, 0 TSRMLS_CC) == FAILURE) {
          zval_dtor(return_value);
RETURN_FALSE;
}
}

Comme vous pouvez le constater, en plus de quelques travaux de vérification nécessaires, l'essentiel est d'appeler zend_alter_ini_entry_ex.

Nous continuons le suivi dans la fonction zend_alter_ini_entry_ex :

Copier le code Le code est le suivant :

ZEND_API int zend_alter_ini_entry_ex(char *name, uint name_length, char *new_value, uint new_value_length, int modifier_type, int stage, int force_change TSRMLS_DC) /* {{{ */
{
zend_ini_entry *ini_entry;
char *dupliquer ;
zend_bool modifiable ;
zend_bool modifié ;

// Trouver l'ini_entry
correspondant dans EG (ini_directives) If (zend_hash_find(EG(ini_directives), name, name_length, (void **) &ini_entry) == FAILURE) {
        return FAILURE ;
>

// S'il a été modifié et s'il peut être modifié
Modifiable = ini_entry->modifiable;
Modifié = ini_entry->modifié;

if (stage == ZEND_INI_STAGE_ACTIVATE && modifier_type == ZEND_INI_SYSTEM) {
ini_entry->modifiable = ZEND_INI_SYSTEM;
>

// Faut-il forcer la modification
Si (!force_change) {
Si (!(ini_entry->modifiable & modifier_type)) {
              return FAILURE ;
>
>

// EG (modified_ini_directives) est utilisé pour stocker l'ini_entry modifié
// Principalement utilisé pour la récupération
Si (!EG(modified_ini_directives)) {
ALLOC_HASHTABLE(EG(modified_ini_directives));
        zend_hash_init(EG(modified_ini_directives), 8, NULL, NULL, 0);
>
 
//Réservez la valeur dans ini_entry, la longueur de la valeur et la plage modifiable dans orig_xxx
// Pour que ini_entry puisse être restauré à la fin de la requête
Si (!modifié) {
ini_entry->orig_value = ini_entry->value;
ini_entry->orig_value_length = ini_entry->value_length;
ini_entry->orig_modifiable = modifiable;
ini_entry->modifié = 1;
        zend_hash_add(EG(modified_ini_directives), nom, nom_longueur, &ini_entry, sizeof(zend_ini_entry*), NULL);
>

duplicate = estrndup(new_value, new_value_length);

// Appel modifier pour mettre à jour la configuration ini correspondante dans XXX_G
if (!ini_entry->on_modify || ini_entry->on_modify(ini_entry, duplicate, new_value_length, ini_entry->mh_arg1, ini_entry->mh_arg2, ini_entry->mh_arg3, stage TSRMLS_CC) == SUCCÈS) {
                 // Comme ci-dessus, si elle est modifiée plusieurs fois, la valeur précédemment modifiée doit être libérée
Si (modifié && ini_entry->orig_value != ini_entry->value) {
              efree(ini_entry->value);
>
ini_entry->value = dupliquer;
ini_entry->value_length = new_value_length;
} autre {
        efree(duplicata);
        return FAILURE ;
>

retour SUCCÈS ;
>

Il y a 3 logiques que nous devons bien comprendre :

1) Le champ modifié dans ini_entry est utilisé pour indiquer si la configuration a été modifiée dynamiquement. Une fois la configuration ini modifiée, modifié sera défini sur 1. Il y a une section cruciale dans le code ci-dessus :

Copier le code Le code est le suivant :

// Si ini_set est appelé plusieurs fois, orig_value, etc. conservez toujours la valeur d'origine
si (!modifié) {
ini_entry->orig_value = ini_entry->value;
ini_entry->orig_value_length = ini_entry->value_length;
ini_entry->orig_modifiable = modifiable;
ini_entry->modifié = 1;
zend_hash_add(EG(modified_ini_directives), nom, nom_longueur, &ini_entry, sizeof(zend_ini_entry*), NULL);
>

Ce code signifie que peu importe le nombre de fois que nous appelons ini_set dans le code php, seul le premier ini_set entrera dans cette logique et définira la valeur orig_value. A partir du deuxième appel à ini_set, cette branche ne sera plus exécutée car modifiée à ce moment a été mise à 1. Par conséquent, ini_entry->orig_value enregistre toujours la valeur de configuration avant la première modification (c'est-à-dire la configuration la plus originale).

2) Afin que la configuration modifiée par ini_set prenne effet immédiatement, la fonction de rappel on_modify est requise.

Comme mentionné dans l'article précédent, on_modify est appelé pour pouvoir mettre à jour les variables globales du module. Rappelez-vous encore une fois, tout d'abord, la configuration dans les variables globales du module n'est plus de type chaîne. Utilisez bool lorsqu'il doit utiliser bool, et int lorsqu'il doit utiliser int. Deuxièmement, chaque ini_entry stocke l'adresse de la variable globale du module et le décalage correspondant, afin que on_modify puisse modifier rapidement la mémoire. De plus, n'oubliez pas qu'après l'appel de on_modify, ini_entry->value doit encore être mis à jour afin que la valeur de configuration dans EG (ini_directives) soit la plus récente.

3) Une nouvelle table de hachage apparaît ici, EG (modified_ini_directives).

EG (modified_ini_directives) est uniquement utilisé pour stocker les configurations ini modifiées dynamiquement. Si une configuration ini est modifiée dynamiquement, alors elle existe à la fois dans EG (ini_directives) et EG (modified_ini_directives). Puisque chaque ini_entry est marqué d'un champ modifié, n'est-il pas possible de parcourir EG (ini_directives) pour obtenir toutes les configurations modifiées ?

La réponse est oui. Personnellement, je pense que l'EG (modified_ini_directives) ici sert principalement à améliorer les performances. Il suffit de parcourir directement l'EG (modified_ini_directives). De plus, en différant l'initialisation de EG (modified_ini_directives) à zend_alter_ini_entry_ex, vous pouvez également voir les points d'optimisation des performances de PHP en détail.

2, restaurer la configuration
Le temps d'action de ini_set est différent de celui du fichier php.ini. Une fois l'exécution de la requête terminée, ini_set deviendra invalide. De plus, lorsque la fonction ini_restore est appelée dans notre code, la configuration précédemment définie via ini_set deviendra également invalide.

Après l'exécution de chaque requête php, php_request_shutdown sera déclenché et php_request_startup sont deux processus correspondants. Si php est connecté sous Apache/nginx, php_request_shutdown sera appelé à chaque fois qu'une requête http est traitée ; si php est exécuté en mode CLI, php_request_shutdown sera également appelé après l'exécution du script.

Dans php_request_shutdown, nous pouvons voir le processus de récupération pour ini :

Copier le code Le code est le suivant :

/* 7. Arrêtez le scanner/l'exécuteur/le compilateur et restaurez les entrées ini */
zend_deactivate(TSRMLS_C);

Entrez zend_deactivate, vous pouvez voir en outre que la fonction zend_ini_deactivate est appelée et que zend_ini_deactivate est responsable de la restauration de la configuration php.

Copier le code Le code est le suivant :

zend_try {
zend_ini_deactivate(TSRMLS_C);
} zend_end_try();

Regardons de plus près l'implémentation de zend_ini_deactivate :

Copier le code Le code est le suivant :

ZEND_API int zend_ini_deactivate(TSRMLS_D) /* {{{ */
{
If (EG(modified_ini_directives)) {
// Diese Tabelle in EG durchlaufen (modified_ini_directives)
// Zend_restore_ini_entry_wrapper
für jeden ini_entry aufrufen         zend_hash_apply(EG(modified_ini_directives), (apply_func_t) zend_restore_ini_entry_wrapper TSRMLS_CC);
         
             // Recyclingbetrieb
        zend_hash_destroy(EG(modified_ini_directives));
FREE_HASHTABLE(EG(modified_ini_directives));
        EG(modified_ini_directives) = NULL;
}
Rückgabe ERFOLGREICH;
}

Von zend_hash_apply fällt die eigentliche Aufgabe der Wiederherstellung von INI schließlich auf die Callback-Funktion zend_restore_ini_entry_wrapper.

Code kopieren Der Code lautet wie folgt:

static int zend_restore_ini_entry_wrapper(zend_ini_entry **ini_entry TSRMLS_DC)
{
// zend_restore_ini_entry_wrapper ist die Kapselung von zend_restore_ini_entry_cb
zend_restore_ini_entry_cb(*ini_entry, ZEND_INI_STAGE_DEACTIVATE TSRMLS_CC);
Rückgabe 1;
}

static int zend_restore_ini_entry_cb(zend_ini_entry *ini_entry, int stage TSRMLS_DC)
{
int result = FAILURE;

// Nur geänderte INI-Elemente anzeigen
If (ini_entry->modified) {
If (ini_entry->on_modify) {
//Orig_value verwenden, um die relevanten Felder in XXX_G
zurückzusetzen             zend_try {
result = ini_entry->on_modify(ini_entry, ini_entry->orig_value, ini_entry->orig_value_length, ini_entry->mh_arg1, ini_entry->mh_arg2, ini_entry->mh_arg3, stage TSRMLS_CC);
               } zend_end_try();
}
If (stage == ZEND_INI_STAGE_RUNTIME && result == FAILURE) {
                    /* Laufzeitfehler ist in Ordnung */
              return 1;
}
If (ini_entry->value != ini_entry->orig_value) {
              efree(ini_entry->value);
}
         
​​​​ // ini_entry selbst wird auf seinen ursprünglichen Wert zurückgesetzt
ini_entry->value = ini_entry->orig_value;
ini_entry->value_length = ini_entry->orig_value_length;
ini_entry->modifiable = ini_entry->orig_modifiable;
ini_entry->modified = 0;
ini_entry->orig_value = NULL;
ini_entry->orig_value_length = 0;
ini_entry->orig_modifiable = 0;
}
Rückgabe 0;
}

Die Logik ist ziemlich klar, ich glaube, dass die Leser sie verstehen können. Um den Wiederherstellungsprozess der INI-Konfiguration zusammenzufassen:

Code kopieren Der Code lautet wie folgt:

php_request_shutdown--->zend_deactivate--->zend_ini_deactivate--->zend_restore_ini_entry_wrapper--->zend_restore_ini_entry_cb

3. Zerstörung der Konfiguration
Am Ende des Sapi-Lebenszyklus wird beispielsweise Apache heruntergefahren, das CLI-Programm ausgeführt usw. Sobald diese Phase erreicht ist, müssen der zuvor erwähnte Konfigurations-Hash, EG (ini_directives) usw. zerstört und der von ihnen verwendete Speicherplatz freigegeben werden.

1. PHP beendet alle Module nacheinander und ruft UNREGISTER_INI_ENTRIES in PHP_MSHUTDOWN_FUNCTION jedes Moduls auf. UNREGISTER_INI_ENTRIES entspricht REGISTER_INI_ENTRIES, aber UNREGISTER_INI_ENTRIES ist nicht für die Freigabe des globalen Speicherplatzes des Moduls verantwortlich. Der Speicher von XXX_globals wird im statischen Datenbereich platziert und muss nicht manuell recycelt werden.

Die Hauptaufgabe von UNREGISTER_INI_ENTRIES besteht darin, die ini_entry-Konfiguration eines bestimmten Moduls aus der EG-Tabelle (ini_directives) zu löschen. Nach dem Löschen wird der Speicherplatz von ini_entry selbst zurückgefordert, ini_entry->value darf jedoch nicht zurückgefordert werden.

Nachdem PHP_MSHUTDOWN_FUNCTION aller Module einmal UNREGISTER_INI_ENTRIES aufgerufen hat, bleibt nur noch die INI-Konfiguration des Core-Moduls in EG übrig (ini_directives). Zu diesem Zeitpunkt müssen Sie UNREGISTER_INI_ENTRIES manuell aufrufen, um das Löschen der Kernmodulkonfiguration abzuschließen.

Code kopieren Der Code lautet wie folgt:

void php_module_shutdown(TSRMLS_D)
{
...
 
// zend_shutdown fährt nacheinander alle PHP-Module außer Core herunter
// PHP_MSHUTDOWN_FUNCTION
jedes Moduls wird beim Schließen aufgerufen zend_shutdown(TSRMLS_C);
 
...

// Zu diesem Zeitpunkt ist nur noch die Konfiguration des Core-Moduls in EG (ini_directives) übrig
// Hier manuell bereinigen
UNREGISTER_INI_ENTRIES();
 
// Konfigurationshash recyceln
php_shutdown_config();

// EG(ini_directives) recyceln
zend_ini_shutdown(TSRMLS_C);

...
}

Nachdem der manuelle Aufruf von UNREGISTER_INI_ENTRIES abgeschlossen ist, enthält EG (ini_directives) keine Elemente mehr. Theoretisch ist EG (ini_directives) zu diesem Zeitpunkt eine leere Hash-Tabelle.

2. Das Recycling von „configuration_hash“ erfolgt nach EG (ini_directives). Der oben gepostete Code enthält den Funktionsaufruf über php_shutdown_config. php_shutdown_config ist hauptsächlich für das Recycling von Configuration_Hash verantwortlich.

Code kopieren Der Code lautet wie folgt:

int php_shutdown_config(void)
{
// Konfigurationshash recyceln
zend_hash_destroy(&configuration_hash);
 
...
 
Rückgabe ERFOLGREICH;
}

Beachten Sie, dass zend_hash_destroy den Speicherplatz von „configuration_hash“ selbst nicht freigibt. Ebenso wie der globale Speicherplatz des Moduls, auf den XXX_G zugreift, ist auch „configuration_hash“ eine globale Variable und muss nicht manuell recycelt werden.

3. Wenn php_shutdown_config abgeschlossen ist, wurde nur der eigene Speicherplatz von EG (ini_directives) nicht freigegeben. Der letzte Schritt ruft also zend_ini_shutdown auf. zend_ini_shutdown wird verwendet, um EG (ini_directives) freizugeben. Wie oben erwähnt, handelt es sich bei EG (ini_directives) zu diesem Zeitpunkt theoretisch um eine leere Hash-Tabelle, sodass der von der HashTable selbst belegte Speicherplatz freigegeben werden muss.

Code kopieren Der Code lautet wie folgt:

ZEND_API int zend_ini_shutdown(TSRMLS_D)
{
// EG (ini_directives) wird dynamisch Speicherplatz zugewiesen und muss recycelt werden
zend_hash_destroy(EG(ini_directives));
free(EG(ini_directives));
Rückgabe ERFOLGREICH;
}

4, Zusammenfassung
Verwenden Sie ein Bild, um den Prozess im Zusammenhang mit der INI-Konfiguration grob zu beschreiben:

Ändern Sie die INI-Konfiguration in den php_php-Grundlagen dynamisch

Verwandte Etiketten:
Quelle:php.cn
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Beliebte Empfehlungen
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage