Pelajar yang menggunakan PHP tahu bahawa konfigurasi php.ini akan berkuat kuasa sepanjang keseluruhan kitaran hayat SAPI. Semasa pelaksanaan skrip php, jika anda mengubah suai konfigurasi ini secara manual, ia tidak akan berkuat kuasa. Jika anda tidak boleh memulakan semula apache atau nginx pada masa ini, anda hanya boleh memanggil antara muka ini_set secara eksplisit dalam kod php. ini_set ialah fungsi yang disediakan oleh PHP untuk mengubah suai konfigurasi secara dinamik Perlu diingat bahawa konfigurasi yang ditetapkan oleh ini_set dan set konfigurasi dalam fail ini mempunyai julat masa berkesan yang berbeza. Selepas skrip php dilaksanakan, tetapan ini_set akan menjadi tidak sah serta-merta.
Oleh itu, artikel ini dibahagikan kepada dua bahagian Bahagian pertama menerangkan prinsip konfigurasi php.ini, dan bahagian kedua bercakap tentang mengubah suai konfigurasi php secara dinamik.
Konfigurasi php.ini kira-kira akan melibatkan tiga keping data, configuration_hash, EG (ini_directives) dan PG, BG, PCRE_G, JSON_G, XXX_G, dsb. Tidak mengapa jika anda tidak mengetahui maksud ketiga-tiga jenis data ini, ia akan diterangkan secara terperinci di bawah.
1, huraikan fail konfigurasi INI
Memandangkan php.ini perlu berkuat kuasa semasa proses SAPI, kerja menghuraikan fail ini dan membina konfigurasi php sewajarnya mestilah permulaan SAPI. Dalam erti kata lain, ia mesti berlaku semasa proses permulaan PHP. PHP memerlukan konfigurasi ini dijana secara dalaman sebelum sebarang permintaan sebenar tiba.
Dicerminkan ke dalam teras php, iaitu fungsi php_module_startup.
php_module_startup bertanggungjawab terutamanya untuk memulakan php. Ia biasanya dipanggil apabila SAPI bermula. btw, satu lagi fungsi biasa ialah php_request_startup, yang bertanggungjawab untuk memulakan setiap permintaan apabila ia tiba php_module_startup dan php_request_startup adalah dua tindakan ikonik, tetapi analisis mereka di luar skop artikel ini.
Sebagai contoh, apabila php disambungkan ke modul di bawah apache, maka apabila apache bermula, semua modul ini akan diaktifkan, termasuk modul php. Apabila mengaktifkan modul php, php_module_startup akan dipanggil. Fungsi php_module_startup menyelesaikan banyak kerja Setelah panggilan php_module_startup tamat, ini bermakna, OK, php telah dimulakan dan kini boleh menerima permintaan dan bertindak balas.
Dalam fungsi php_module_startup, pelaksanaan yang berkaitan dengan menghurai fail ini ialah:
Seperti yang anda lihat, fungsi php_init_config sebenarnya dipanggil untuk melengkapkan penghuraian fail ini. Kerja penghuraian terutamanya melaksanakan analisis lex&grammar, dan mengekstrak serta menyimpan pasangan kunci dan nilai dalam fail ini. Format php.ini sangat mudah, dengan kunci di sebelah kiri tanda sama dan nilai di sebelah kanan. Setiap kali sepasang kv diekstrak, di manakah php menyimpannya? Jawapannya ialah configuration_hash yang disebutkan tadi.
konfigurasi_hash Jadual Hash statik;
configuration_hash diisytiharkan dalam php_ini.c, iaitu struktur data jenis HashTable. Seperti namanya, ia sebenarnya adalah jadual hash. Sebagai tambahan, configuration_hash tidak boleh diperolehi dalam versi sebelum php5.3 kerana ia adalah pembolehubah statik dalam fail php_ini.c. Kemudian, php5.3 menambah antara muka php_ini_get_configuration_hash, yang mengembalikan &configuration_hash secara langsung, supaya pelbagai sambungan PHP dapat melihat dengan mudah konfigurasi_hash... Alangkah baiknya...
Perhatikan empat perkara:
Pertama, php_init_config tidak akan melakukan sebarang pengesahan selain daripada leksikal dan sintaks. Dalam erti kata lain, jika kita menambah baris hello=world pada fail ini, selagi ini adalah item konfigurasi yang diformat dengan betul, maka configuration_hash akhir akan mengandungi elemen dengan hello kunci dan dunia nilai, dan configuration_hash akan mencerminkan ia ke tahap maksimum ini.
Kedua, fail ini membolehkan kami mengkonfigurasi dalam bentuk tatasusunan. Sebagai contoh, tulis tiga baris berikut dalam fail ini:
Kemudian dalam jadual konfigurasi_hash yang dijana akhir, akan terdapat elemen dengan drift.arr kekunci, dan nilainya ialah tatasusunan yang mengandungi tiga nombor: 1, 2 dan 3. Ini adalah kaedah konfigurasi yang sangat jarang berlaku.
Ketiga, php juga membenarkan kami membina beberapa fail ini tambahan sebagai tambahan kepada fail php.ini lalai ( tepatnya php-%s.ini). Fail ini akan diletakkan dalam direktori tambahan. Direktori ini ditentukan oleh pembolehubah persekitaran PHP_INI_SCAN_DIR Selepas php_init_config menghuraikan php.ini, ia akan mengimbas semula direktori ini dan mencari semua fail .ini dalam direktori untuk analisis. Pasangan nilai kunci kv yang dijana dalam fail tambahan ini juga akan ditambahkan pada konfigurasi_hash.
Ini adalah ciri yang kadang-kadang berguna Katakan kita membangunkan sambungan PHP sendiri tetapi tidak mahu mencampurkan konfigurasi ke dalam php.ini Kita boleh menulis ini yang lain dan memberitahu PHP di mana untuk mencarinya melalui PHP_INI_SCAN_DIR. Sudah tentu, kelemahannya juga jelas, dan ia memerlukan menetapkan pembolehubah persekitaran tambahan untuk menyokongnya. Penyelesaian yang lebih baik adalah untuk pembangun memanggil php_parse_user_ini_file atau zend_parse_ini_file sendiri dalam sambungan untuk menghuraikan fail ini yang sepadan.
Keempat, dalam konfigurasi_hash, kuncinya ialah rentetan, jadi apakah jenis nilainya? Jawapannya juga adalah rentetan (kecuali untuk tatasusunan yang sangat istimewa yang disebutkan di atas). Khususnya, seperti konfigurasi berikut:
Kemudian pasangan nilai kunci yang sebenarnya disimpan dalam konfigurasi_hash akhir ialah:
kunci: "log_errors"
val : ""
kunci: "log_errors_max_len"
val : "1024"
Beri perhatian kepada log_errors, nilai yang disimpannya bukan "0", ia adalah rentetan kosong yang sebenar. Di samping itu, log_errors_max_len bukan nombor, tetapi rentetan 1024.
Pada ketika ini dalam analisis, pada dasarnya semua yang berkaitan dengan menghuraikan fail ini telah dijelaskan dengan jelas. Untuk meringkaskan secara ringkas:
1, parsing ini berlaku dalam peringkat php_module_startup
2. Hasil penghuraian disimpan dalam konfigurasi_hash.
2, konfigurasi digunakan pada modul
Struktur umum PHP boleh dilihat sebagai enjin zend di bahagian bawah, yang bertanggungjawab untuk berinteraksi dengan OS, menyusun kod PHP, menyediakan pengehosan memori, dll. Terdapat banyak modul yang disusun pada lapisan atas zend enjin. Modul teras ialah modul Teras, dan lain-lain termasuk Standard, PCRE, Tarikh, Sesi, dll... Modul ini juga mempunyai nama lain yang dipanggil sambungan php. Kami hanya boleh memahami bahawa setiap modul menyediakan satu set antara muka berfungsi untuk dipanggil oleh pembangun Contohnya, fungsi terbina dalam yang biasa digunakan seperti meletup, memangkas, tatasusunan, dll. disediakan oleh modul Standard.
Mengapa kita perlu bercakap tentang ini adalah kerana dalam php.ini, sebagai tambahan kepada beberapa konfigurasi untuk php itu sendiri, iaitu, untuk modul Teras (seperti safe_mode, display_errors, max_execution_time, dll.), terdapat cukup banyak beberapa konfigurasi untuk modul lain yang berbeza.
Sebagai contoh, modul tarikh, yang menyediakan tarikh, masa, strtotime dan fungsi lain yang biasa. Dalam php.ini, konfigurasi berkaitannya kelihatan seperti:
독립적인 구성을 갖는 이러한 모듈 외에도 zend 엔진도 구성 가능하지만 zend 엔진에는 구성 가능한 항목이 거의 없으며 error_reporting, zend.enable_gc 및 discover_unicode만 있습니다.
이전 섹션에서 언급했듯이 php_module_startup은 ini 파일을 구문 분석하고 Configuration_hash를 생성하는 것이 목적인 php_init_config를 호출합니다. 그러면 다음에는 php_module_startup에서 또 어떤 일이 수행될까요? 분명히 Configuration_hash의 구성은 Zend, Core, Standard, SPL 등과 같은 다양한 모듈에 적용됩니다. 물론, PHP에는 일반적으로 많은 모듈이 포함되어 있고 이러한 모듈은 PHP 시작 중에 순차적으로 시작되기 때문에 이는 밤새 프로세스가 아닙니다. 그런 다음 모듈 A를 구성하는 프로세스는 모듈 A의 시작 프로세스 중에 발생합니다.
확장 개발 경험이 있는 학생들은 모듈 A가 PHP_MINIT_FUNCTION(A)에서 시작된다는 점을 직접적으로 지적할 것입니다.
예, 모듈 A를 구성해야 하는 경우 PHP_MINIT_FUNCTION에서 REGISTER_INI_ENTRIES()를 호출하여 완료할 수 있습니다. REGISTER_INI_ENTRIES는 현재 모듈에 필요한 구성 항목의 이름을 기반으로 사용자가 설정한 구성 값에 대한 구성 해시를 검색하고 이를 모듈 자체 전역 공간에 업데이트합니다.
2.1, 모듈의 전역 공간
configuration_hash의 ini 구성을 각 모듈에 적용하는 방법을 이해하려면 먼저 php 모듈의 전역 공간을 이해해야 합니다. 다양한 PHP 모듈의 경우 자신만의 저장 공간을 열 수 있으며 이 공간은 모듈에서 전체적으로 볼 수 있습니다. 일반적으로 모듈에 필요한 ini 구성을 저장하는 데 사용됩니다. 즉,configuration_hash의 구성 항목은 결국 전역 공간에 저장됩니다. 모듈을 실행하는 동안 모듈에 대한 사용자 설정을 얻으려면 이 전역 공간에 직접 액세스하기만 하면 됩니다. 물론, 모듈 실행 중 중간 데이터를 기록하는 데에도 자주 사용됩니다.
bcmath 모듈을 예로 들어 보겠습니다. bcmath는 수학적 계산을 위한 인터페이스를 제공하는 PHP 모듈입니다. 먼저 ini 구성을 살펴보겠습니다.
bcmath에는 구성 항목이 하나만 있습니다. php.ini에서 bcmath.scale을 사용하여 bcmath 모듈을 구성할 수 있습니다.
다음으로 bcmatch 모듈의 전역 공간 정의를 계속 살펴보세요. php_bcmath.h에는 다음 명령문이 있습니다:
매크로를 확장하면 다음과 같습니다.
사실 zend_bcmath_globals 유형은 bcmath 모듈의 전역 공간 유형입니다. 여기서는 zend_bcmath_globals 구조만 선언되었으며 bcmath.c에는 특정 인스턴스화 정의가 있습니다.
// 확장 후 zend_bcmath_globals bcmath_globals;
ZEND_DECLARE_MODULE_GLOBALS(bcmath)
bcmath_globals 변수의 정의가 ZEND_DECLARE_MODULE_GLOBALS로 완료되었음을 알 수 있습니다.
bcmath_globals는 4개의 필드를 포함하는 실제 전역 공간입니다. 마지막 필드인 bc_precision은 ini 구성의 bcmath.scale에 해당합니다. php.ini에 bcmath.scale 값을 설정한 후 bcmath 모듈을 시작하면 bcmath.scale 값이 bcmath_globals.bc_precision으로 업데이트됩니다.
configuration_hash의 값을 각 모듈에서 정의한 xxx_globals 변수로 업데이트합니다. 이는 소위 모듈에 ini 구성을 적용하는 것입니다. 모듈이 시작되면 이러한 구성이 적용됩니다. 따라서 후속 실행 단계에서 php 모듈은 사용자가 설정한 구성을 가져오기 위해 자체 XXX_globals에만 액세스하면 됩니다.
bcmath_globals, ini 구성 항목에 대한 한 필드 외에 다른 세 필드는 무엇입니까? 이는 모듈 전역 공간의 두 번째 역할입니다. ini 구성에 사용되는 것 외에도 모듈 실행 중에 일부 데이터를 저장할 수도 있습니다.
또 다른 예는 PHP에서 매우 일반적으로 사용되는 모듈인 json 모듈입니다.
json 모듈에는 ini 구성이 필요하지 않으며 전역 공간에는 error_code 필드가 하나만 있는 것을 볼 수 있습니다. error_code는 json_decode 또는 json_encode의 마지막 실행에서 발생한 오류를 기록합니다. json_last_error 함수는 이 error_code를 반환하여 사용자가 오류의 원인을 찾는 데 도움을 줍니다.
모듈 전역 공간 변수에 쉽게 접근하기 위해 PHP는 관례적으로 몇 가지 매크로를 제안했습니다. 예를 들어 json_globals의 error_code에 액세스하려는 경우 물론 json_globals.error_code로 직접 작성할 수 있지만(멀티 스레드 환경에서는 사용할 수 없음) 이를 작성하는 보다 일반적인 방법은 JSON_G 매크로를 정의하는 것입니다.
JSON_Globals.error_code에 접근하기 위해 JSON_G(error_code)를 사용합니다. 이 글의 시작 부분에서 PG, BG, JSON_G, PCRE_G, XXX_G 등을 언급했습니다. 이러한 매크로는 PHP 소스 코드에서도 매우 일반적입니다. 이제 우리는 이를 쉽게 이해할 수 있습니다. PG 매크로는 Core 모듈의 전역 변수에 접근할 수 있고, BG는 Standard 모듈의 전역 변수에 접근할 수 있으며, PCRE_G는 PCRE 모듈의 전역 변수에 접근할 수 있습니다.
2.2. 모듈에 필요한 구성을 확인하는 방법은 무엇입니까?
모듈에 필요한 INI 구성의 종류는 각 모듈에 정의되어 있습니다. 예를 들어 코어 모듈의 경우 다음과 같은 구성 항목 정의가 있습니다.
위 코드는 php-srcmainmain.c 파일의 약 450줄 이상에서 찾을 수 있습니다. ZEND_INI_BEGIN, ZEND_INI_END, PHP_INI_ENTRY_EX, STD_PHP_INI_BOOLEAN 등을 포함하여 많은 매크로가 관련되어 있습니다. 이 기사에서는 하나씩 자세히 설명하지 않고 관심 있는 독자가 직접 분석할 수 있습니다.
위 코드를 매크로 확장하면 다음과 같은 결과를 얻습니다.
구성 항목의 정의는 본질적으로 zend_ini_entry 유형의 배열을 정의한다는 것을 알 수 있습니다. zend_ini_entry 구조 필드의 구체적인 의미는 다음과 같습니다.
문자 *값;
단위 value_length;
단위 orig_value_length;
int orig_modifying; // 구성 항목의 원래 수정 가능
int 수정됨; // 수정되었는지 여부. 수정된 경우 orig_value는 수정 전의 값을 저장합니다.
};
2.3, 모듈에 구성 적용 - REGISTER_INI_ENTRIES
REGISTER_INI_ENTRIES는 다양한 확장 프로그램의 PHP_MINIT_FUNCTION에서 흔히 볼 수 있습니다. REGISTER_INI_ENTRIES는 주로 모듈의 전역 공간 XXX_G를 채우고 구성_해시 값을 XXX_G에 동기화하는 두 가지 작업을 완료하는 일을 담당합니다. 둘째, EG(ini_directives)도 생성합니다.
REGISTER_INI_ENTRIES도 매크로입니다. 확장 후에는 실제로는 zend_register_ini_entries 메소드입니다. zend_register_ini_entries의 구현을 구체적으로 살펴보겠습니다.
''' ''''''''''''''' '''''''아웃''''' 아웃 아웃 아웃 아웃 아웃 아웃 아웃 아웃 아웃'' ''''''''''' 아래를 통해 통과하여 통과하여 통과하여 통과하여 통과하여 out out off out out out through out out through out right out through out out out of to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to 에 에 에 에 에 에에 에에 에에 에에 에에 에에 에에에 에에에 ~와 ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ 중
If (!config_directive_success && hashed_ini_entry->on_modify) {
hashed_ini_entry->on_modify(hashed_ini_entry, hashed_ini_entry->value, hashed_ini_entry->value_length, hashed_ini_entry->mh_arg1, hashed_ini_entry->mh_arg2, hashed_ini_entry-> 3, ZEND_INI_STAGE_STARTUP TSRMLS_CC);
}
p++;
}
성공을 반환합니다.
}
간단히 말하면 위 코드의 논리는 다음과 같이 표현할 수 있습니다.
1. 모듈에서 선언한 ini 구성 항목을 EG(ini_directives)에 추가합니다. ini 구성 항목의 값은 나중에 수정될 수 있습니다.
2.configuration_hash에서 각 모듈에 필요한 ini를 찾아보세요.
찾을 수 있다면 사용자의 ini 파일에 해당 값이 설정되어 있다는 의미이며, 사용자의 설정을 사용한다는 의미입니다.
찾을 수 없다면 문제가 되지 않습니다. 모듈이 ini를 선언할 때 기본값을 가져오기 때문입니다.
3. ini 값을 XX_G에 동기화합니다. 결국, PHP를 실행하는 동안 이러한 XXX_global은 여전히 역할을 합니다. 구체적인 프로세스는 각 ini 구성에 해당하는 on_modify 메소드를 호출하는 것입니다. on_modify는 ini 선언 시 모듈에 의해 지정됩니다.
실제로 함수 포인터인 on_modify를 자세히 살펴보겠습니다. 두 가지 특정 핵심 모듈의 구성 문을 살펴보겠습니다.
log_errors의 경우 on_modify는 OnUpdateBool로 설정되고, log_errors_max_len의 경우 on_modify는 OnUpdateLong으로 설정됩니다.
또한 php.ini의 구성이 다음과 같다고 가정합니다.
OnUpdateBool 함수를 자세히 살펴보겠습니다.
// p는 core_globals의 주소와 log_errors 필드의 오프셋을 나타냅니다.
//얻은 주소는 log_errors 필드의 주소입니다
p = (zend_bool *) (base+(size_t) mh_arg1)
if (new_value_length == 2 && strcasecmp("on", new_value) == 0) {
*p = (zend_bool) 1;
}
else if (new_value_length == 3 && strcasecmp("yes", new_value) == 0) {
*p = (zend_bool) 1;
}
else if (new_value_length == 4 && strcasecmp("true", new_value) == 0) {
*p = (zend_bool) 1;
}
그렇지 않으면 {
//configuration_hash에 저장된 값은 "On"이 아닌 문자열 "1"입니다
// 여기서는 atoi를 사용하여 숫자 1로 변환합니다
*p = (zend_bool) atoi(new_value);
}
성공을 반환합니다.
}
가장 당황스러운 것은 아마도 mh_arg1과 mh_arg2일 것입니다. 실제로 위에서 언급한 zend_ini_entry 정의와 비교하면 mh_arg1과 mh_arg2는 여전히 이해하기 쉽습니다. mh_arg1은 바이트 오프셋을 나타내고, mh_arg2는 XXX_globals의 주소를 나타냅니다. 따라서 (char *)mh_arg2 + mh_arg1의 결과는 XXX_globals의 필드 주소입니다. 특히 이 경우에는 core_globals에서 log_errors의 주소를 계산하는 것입니다. 따라서 OnUpdateBool이 최종적으로
로 실행되면OnUpdateBool을 분석한 후 OnUpdateLong을 보면 한 눈에 알 수 있습니다.
// log_errors_max_len의 주소를 가져옵니다
p = (long *) (base+(size_t) mh_arg1);
// "1024"를 long 타입으로 변환하여 core_globals.log_errors_max_len에 할당
*p = zend_atol(new_value, new_value_length);
성공을 반환합니다.
}
마지막으로 주의할 점은 zend_register_ini_entries 함수에서configuration_hash에 구성이 있는 경우 on_modify가 호출될 때 hashed_ini_entry의 값과 value_length가 업데이트된다는 것입니다. 즉, 사용자가 php.ini에서 구성한 경우 EG(ini_directives)는 실제 구성된 값을 저장합니다. 사용자가 구성되지 않은 경우 EG(ini_directives)는 zend_ini_entry 선언 시 제공된 기본값을 저장합니다.
zend_register_ini_entries의 default_value 변수는 이름이 잘못되어 오해를 일으키기 쉽습니다. 실제로 default_value는 기본값을 의미하는 것이 아니라 사용자가 실제로 설정한 값을 의미합니다.
3, 요약
이제 데이터 구성_hash, EG(ini_directives) 및 PG, BG, PCRE_G, JSON_G, XXX_G...의 세 가지 부분이 모두 명확하게 설명되었습니다.
요약하자면:
1,configuration_hash는 php.ini 파일에 구성을 저장하고 검증을 수행하지 않으며 값은 문자열입니다.
2. EG(ini_directives)는 각 모듈에 정의된 zend_ini_entry를 저장합니다. 사용자가 php.ini(configuration_hash에 존재)에서 구성한 경우 해당 값은configuration_hash의 값으로 대체되며 유형은 여전히 문자열입니다.
3. XXX_G, 이 매크로는 모듈의 전역 공간에 액세스하는 데 사용됩니다. 이 메모리 공간은 ini 구성을 저장하고 on_modify에 지정된 함수를 통해 업데이트될 수 있습니다. 해당 데이터 유형은 XXX_G의 필드 선언에 의해 결정됩니다.