Rumah  >  Artikel  >  php教程  >  Ubah suai konfigurasi ini secara dinamik dalam asas php_php

Ubah suai konfigurasi ini secara dinamik dalam asas php_php

WBOY
WBOYasal
2016-05-16 08:59:562021semak imbas

1, tukar konfigurasi semasa masa jalan
Seperti yang dinyatakan dalam artikel sebelumnya, fungsi ini_set boleh mengubah suai secara dinamik beberapa konfigurasi PHP semasa pelaksanaan PHP. Ambil perhatian bahawa tidak semua konfigurasi boleh diubah suai secara dinamik. Mengenai konfigurasi ini yang boleh diubah suai, lihat: http://php.net/manual/zh/configuration.changes.modes.php

Kami pergi terus ke pelaksanaan ini_set Walaupun fungsinya agak panjang, logiknya sangat jelas:

Salin kod Kod adalah seperti berikut:

PHP_FUNCTION(set_ini)
{
char *varname, *new_value;
int varname_len, new_value_len;
char *nilai_lama;

jika (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &varname, &varname_len, &new_value, &new_value_len) == GAGAL) {
         kembali;
}

// Dapatkan nilai yang dikonfigurasikan daripada EG (ini_directives)
Nilai_lama = zend_ini_string(varname, varname_len + 1, 0);

/* salin untuk kembali ke sini, kerana alter mungkin membebaskannya */
Jika (nilai_lama) {
RETVAL_STRING(nilai_lama, 1);
} lain {
RETVAL_FALSE;
}

// Jika mod selamat dihidupkan, konfigurasi ini berikut mungkin melibatkan operasi fail dan anda perlu menyemak uid
#define _CHECK_PATH(var, var_len, ini) php_ini_check_path(var, var_len, ini, sizeof(ini))
/* safe_mode & basedir check */
Jika (PG(safe_mode) || PG(open_basedir)) {
Jika (_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")) {
Jika (PG(safe_mode) && (!php_checkuid(new_value, NULL, CHECKUID_CHECK_FILE_AND_DIR))) {
                   zval_dtor(return_value);
PULANGAN_SALAH;
            }
Jika (php_check_open_basedir(new_value TSRMLS_CC)) {
                   zval_dtor(return_value);
PULANGAN_SALAH;
            }
}
}

// Dalam mod selamat, ini berikut dilindungi dan tidak akan diubah suai secara dinamik
Jika (PG(safe_mode)) {
Jika (!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);
PULANGAN_SALAH;
}
}

// Panggil zend_alter_ini_entry_ex untuk mengubah suai konfigurasi ini secara dinamik
Jika (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);
PULANGAN_SALAH;
}
}

Seperti yang anda lihat, sebagai tambahan kepada beberapa kerja pengesahan yang diperlukan, perkara utama ialah menghubungi zend_alter_ini_entry_ex.

Kami terus membuat susulan dalam fungsi zend_alter_ini_entry_ex:

Salin kod Kod adalah seperti berikut:

ZEND_API int zend_alter_ini_entry_ex(char *nama, uint name_length, char *new_value, uint new_value_length, int modify_type, int stage, int force_change TSRMLS_DC) /* {{{ */
{
zend_ini_entry *ini_entry;
char *pendua;
zend_bool boleh diubah suai;
zend_bool diubah suai;

// Cari ini_entry
yang sepadan dalam EG (ini_directives) Jika (zend_hash_find(EG(ini_directives), nama, nama_panjang, (kosong **) &ini_entry) == GAGAL) {
        kembali GAGAL;
}

// Sama ada ia telah diubah suai dan sama ada ia boleh diubah suai
Boleh diubah suai = ini_entry->modifiable;
Diubah suai = ini_entry->diubah suai;

jika (peringkat == ZEND_INI_STAGE_ACTIVATE && modify_type == ZEND_INI_SYSTEM) {
ini_entry->modifiable = ZEND_INI_SYSTEM;
}

// Sama ada hendak memaksa pengubahsuaian
Jika (!paksa_ubah) {
Jika (!(ini_entry->boleh diubah suai & modify_type)) {
              kembali GAGAL;
}
}

// EG (modified_ini_directives) digunakan untuk menyimpan ini_entry yang diubah suai
// Terutamanya digunakan untuk pemulihan
Jika (!EG(modified_ini_directives)) {
ALLOC_HASHTABLE(EG(modified_ini_directives));
        zend_hash_init(EG(modified_ini_directives), 8, NULL, NULL, 0);
}
 
//Tempah nilai dalam ini_entry, panjang nilai dan julat yang boleh diubah suai ke dalam orig_xxx
// Supaya ini_entry boleh dipulihkan apabila permintaan tamat
Jika (!diubah suai) {
ini_entry->orig_value = ini_entry->value;
ini_entry->orig_value_length = ini_entry->value_length;
ini_entry->orig_modifiable = boleh diubah suai;
ini_entry->diubah suai = 1;
        zend_hash_add(EG(modified_ini_directives), nama, name_length, &ini_entry, sizeof(zend_ini_entry*), NULL);
}

pendua = estrnup(nilai_baru, panjang_nilai_baru);

// Ubah suai panggilan untuk mengemas kini konfigurasi ini yang sepadan dalam XXX_G
jika (!ini_entry->on_modify || ini_entry->on_modify(ini_entry, duplikat, new_value_length, ini_entry->mh_arg1, ini_entry->mh_arg2, ini_entry->mh_argESS_3,) == TS_arg3,) == >                  // Sama seperti di atas, jika diubah suai beberapa kali, nilai yang diubah suai sebelum ini perlu dikeluarkan
Jika (ubah suai && ini_entry->orig_value != ini_entry->value) {
              percuma(ini_entry->value);
}
ini_entry->value = pendua;
ini_entry->value_length = new_value_length;
} lain {
        percuma(pendua);
        kembali GAGAL;
}

kembali BERJAYA;

}

Ada 3 logik yang perlu kita fahami dengan teliti:

1) Medan yang diubah suai dalam ini_entry digunakan untuk menunjukkan sama ada konfigurasi telah diubah suai secara dinamik. Setelah konfigurasi ini diubah suai, diubah suai akan ditetapkan kepada 1. Terdapat bahagian penting dalam kod di atas:

Salin kod Kod adalah seperti berikut:

// Jika ini_set dipanggil beberapa kali, orig_value, dsb. sentiasa mengekalkan nilai asal
jika (!diubah suai) {
ini_entry->orig_value = ini_entry->value;
ini_entry->orig_value_length = ini_entry->value_length;
ini_entry->orig_modifiable = boleh diubah suai;
ini_entry->diubah suai = 1;
​ zend_hash_add(EG(modified_ini_directives), nama, name_length, &ini_entry, sizeof(zend_ini_entry*), NULL);
}

Kod ini bermakna tidak kira berapa kali kita memanggil ini_set dalam kod php, hanya set ini pertama akan memasukkan logik ini dan menetapkan nilai_orig. Bermula dari panggilan kedua ke ini_set, cawangan ini tidak akan dilaksanakan lagi, kerana diubah suai pada masa ini telah ditetapkan kepada 1. Oleh itu, ini_entry->orig_value sentiasa menyimpan nilai konfigurasi sebelum pengubahsuaian pertama (iaitu konfigurasi paling asli).

2) Untuk menjadikan konfigurasi yang diubah suai oleh ini_set berkuat kuasa serta-merta, fungsi panggil balik on_modify diperlukan.

Seperti yang dinyatakan dalam artikel sebelumnya, on_modify dipanggil untuk dapat mengemas kini pembolehubah global modul. Ingat sekali lagi, pertama sekali, konfigurasi dalam pembolehubah global modul bukan lagi daripada jenis rentetan Gunakan bool apabila ia harus menggunakan bool, dan int apabila ia harus menggunakan int. Kedua, setiap ini_entry menyimpan alamat pembolehubah global modul dan offset yang sepadan, supaya on_modify boleh mengubah suai memori dengan cepat. Selain itu, jangan lupa bahawa selepas on_modify dipanggil, ini_entry->value masih perlu dikemas kini dengan lebih lanjut supaya nilai konfigurasi dalam EG (ini_directives) adalah yang terkini.

3) Jadual cincang baharu muncul di sini, Cth (modified_ini_directives).

EG (modified_ini_directives) hanya digunakan untuk menyimpan konfigurasi ini yang diubah suai secara dinamik Jika konfigurasi ini diubah suai secara dinamik, maka ia wujud dalam kedua-dua EG (ini_directives) dan EG (modified_ini_directives). Memandangkan setiap ini_entry ditandakan dengan medan yang diubah suai, bukankah mungkin untuk melintasi EG (ini_directives) untuk mendapatkan semua konfigurasi yang diubah suai?

Jawapannya ya. Secara peribadi, saya merasakan bahawa EG (modified_ini_directives) di sini adalah untuk meningkatkan prestasi secara langsung. Selain itu, dengan menangguhkan permulaan EG (modified_ini_directives) kepada zend_alter_ini_entry_ex, anda juga boleh melihat titik pengoptimuman prestasi PHP secara terperinci.

2, pulihkan konfigurasi
Masa tindakan ini_set adalah berbeza daripada fail php.ini Sebaik sahaja pelaksanaan permintaan tamat, ini_set akan menjadi tidak sah. Selain itu, apabila fungsi ini_restore dipanggil dalam kod kami, konfigurasi yang ditetapkan sebelum ini melalui ini_set juga akan menjadi tidak sah.

Selepas setiap permintaan php dilaksanakan, php_request_shutdown akan dicetuskan dan php_request_startup adalah dua proses yang sepadan. Jika php disambungkan di bawah apache/nginx, php_request_shutdown akan dipanggil setiap kali permintaan http diproses; jika php dijalankan dalam mod CLI, php_request_shutdown juga akan dipanggil selepas skrip dilaksanakan.

Dalam php_request_shutdown, kita dapat melihat pemprosesan pemulihan untuk ini:

Salin kod Kod adalah seperti berikut:

/* 7. Matikan pengimbas/pelaksana/penyusun dan pulihkan entri ini */
zend_deactivate(TSRMLS_C);

Masukkan zend_deactivate, anda boleh melihat lagi bahawa fungsi zend_ini_deactivate dipanggil, dan zend_ini_deactivate bertanggungjawab untuk memulihkan konfigurasi php.

Salin kod Kod adalah seperti berikut:

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

Mari kita lihat dengan lebih dekat pelaksanaan zend_ini_deactivate:

Salin kod Kod adalah seperti berikut:

ZEND_API int zend_ini_deactivate(TSRMLS_D) /* {{{ */
{
Jika (EG(modified_ini_directives)) {
// Lintas jadual ini dalam EG (modified_ini_directives)
// Panggil zend_restore_ini_entry_wrapper
untuk setiap ini_entry         zend_hash_apply(EG(modified_ini_directives), (apply_func_t) zend_restore_ini_entry_wrapper TSRMLS_CC);
         
             // Operasi kitar semula
        zend_hash_destroy(EG(modified_ini_directives));
FREE_HASHTABLE(EG(modified_ini_directives));
        Cth(modified_ini_directives) = NULL;
}
Kembali BERJAYA;
}

Daripada zend_hash_apply, tugas sebenar untuk memulihkan ini akhirnya jatuh kepada fungsi panggil balik zend_restore_ini_entry_wrapper.

Salin kod Kod adalah seperti berikut:

int statik zend_restore_ini_entry_wrapper(zend_ini_entry **ini_entry TSRMLS_DC)
{
// zend_restore_ini_entry_wrapper ialah enkapsulasi zend_restore_ini_entry_cb
zend_restore_ini_entry_cb(*ini_entry, ZEND_INI_STAGE_DEACTIVATE TSRMLS_CC);
Pulangan 1;
}

int statik zend_restore_ini_entry_cb(zend_ini_entry *ini_entry, int stage TSRMLS_DC)
{
int result = GAGAL;

// Hanya lihat item ini yang diubah suai
Jika (ini_entry->diubah suai) {
Jika (ini_entry->on_modify) {
//Gunakan orig_value untuk menetapkan semula medan yang berkaitan dalam XXX_G
            zend_try {
hasil = ini_entry->on_modify(ini_entry, ini_entry->orig_value, ini_entry->asal_value_length, ini_entry->mh_arg1, ini_entry->mh_arg2, ini_entry->_LS,🎉);                } zend_end_try();
}
Jika (peringkat == ZEND_INI_STAGE_RUNTIME && keputusan == GAGAL) {
                    /* kegagalan masa jalan adalah OK */
              kembali 1;
}
Jika (ini_entry->value != ini_entry->orig_value) {
              percuma(ini_entry->value);
}
         
​​​​ // ini_entry sendiri dipulihkan kepada nilai asalnya
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->diubah suai = 0;
ini_entry->orig_value = NULL;
ini_entry->orig_value_length = 0;
ini_entry->orig_modifiable = 0;
}
Pulangan 0;
}

Logiknya agak jelas, saya percaya pembaca boleh memahaminya. Untuk meringkaskan proses pemulihan konfigurasi ini:

Salin kod Kod adalah seperti berikut:
php_request_shutdown--->zend_deactivate--->zend_ini_deactivate--->zend_restore_ini_entry_wrapper--->zend_restore_ini_entry_cb

3. Pemusnahan konfigurasi
Pada penghujung kitaran hayat sapi, sebagai contoh, apache dimatikan, program cli dilaksanakan, dsb. Sebaik sahaja memasuki peringkat ini, konfigurasi_hash yang disebutkan sebelum ini, EG (ini_directives), dll. perlu dimusnahkan, dan ruang memori yang digunakan oleh mereka perlu dilepaskan.

1. PHP akan menamatkan semua modul dalam urutan dan memanggil UNREGISTER_INI_ENTRIES dalam PHP_MSHUTDOWN_FUNCTION setiap modul. UNREGISTER_INI_ENTRIES sepadan dengan REGISTER_INI_ENTRIES, tetapi UNREGISTER_INI_ENTRIES tidak bertanggungjawab untuk melepaskan ruang global modul Memori XXX_globals diletakkan dalam kawasan data statik dan tidak perlu dikitar semula secara manual.

Perkara utama UNREGISTER_INI_ENTRIES lakukan ialah memadamkan konfigurasi ini_entry modul tertentu daripada jadual EG (ini_directives). Selepas pemadaman, ruang ini_entry itu sendiri akan dituntut semula, tetapi ini_entry->value tidak boleh dituntut semula.

Selepas PHP_MSHUTDOWN_FUNCTION semua modul memanggil UNREGISTER_INI_ENTRIES sekali, hanya konfigurasi ini bagi modul Teras yang tinggal dalam EG (ini_directives). Pada masa ini, anda perlu memanggil UNREGISTER_INI_ENTRIES secara manual untuk menyelesaikan pemadaman konfigurasi modul Teras.

Salin kod Kod adalah seperti berikut:

batalkan php_module_shutdown(TSRMLS_D)
{
...
 
// zend_shutdown akan menutup semua modul php kecuali Teras dalam urutan
// PHP_MSHUTDOWN_FUNCTION
setiap modul akan dipanggil apabila ditutup zend_shutdown(TSRMLS_C);
 
...

// Pada ketika ini, hanya konfigurasi modul Teras yang tinggal dalam EG (ini_directives)
// Bersihkan secara manual di sini
NYAHDAFTAR_INI_ENTRIES();
 
// Recycle configuration_hash
php_shutdown_config();

// Kitar Semula EG(ini_directives)
zend_ini_shutdown(TSRMLS_C);

...
}

Selepas panggilan manual ke UNREGISTER_INI_ENTRIES selesai, EG (ini_directives) tidak lagi mengandungi sebarang elemen Secara teorinya, EG (ini_directives) pada masa ini ialah jadual cincang kosong.

2. Kitar semula konfigurasi_hash berlaku selepas EG (ini_directives). php_shutdown_config bertanggungjawab terutamanya untuk mengitar semula configuration_hash.

Salin kod Kod adalah seperti berikut:

int php_shutdown_config(void)
{
// Kitar semula configuration_hash
zend_hash_destroy(&configuration_hash);
 
...
 
Kembali BERJAYA;
}

Perhatikan bahawa zend_hash_destroy tidak melepaskan ruang configuration_hash itu sendiri Seperti ruang global modul yang diakses oleh XXX_G, configuration_hash juga merupakan pembolehubah global dan tidak perlu dikitar semula secara manual.

3. Apabila php_shutdown_config selesai, hanya ruang EG sendiri (ini_directives) belum dikeluarkan. Jadi langkah terakhir memanggil zend_ini_shutdown. zend_ini_shutdown digunakan untuk melepaskan EG (ini_directives). Seperti yang dinyatakan di atas, EG (ini_directives) pada masa ini secara teorinya adalah jadual hash kosong, jadi ruang yang diduduki oleh HashTable itu sendiri perlu dikeluarkan.

Salin kod Kod adalah seperti berikut:

ZEND_API int zend_ini_shutdown(TSRMLS_D)
{
// EG (ini_directives) adalah ruang yang diperuntukkan secara dinamik dan perlu dikitar semula
zend_hash_destroy(EG(ini_directives));
percuma(EG(ini_directives));
Kembali BERJAYA;
}

4, Ringkasan
Gunakan gambar untuk menerangkan secara kasar proses yang berkaitan dengan konfigurasi ini:

Ubah suai konfigurasi ini secara dinamik dalam asas php_php

Kenyataan:
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn