In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-04-06 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)06/03 Report--
Editor to share with you how to dynamically modify the ini configuration in php, I believe most people do not know much about it, so share this article for your reference, I hope you can learn a lot after reading this article, let's go to know it!
1, change the configuration at run time
As mentioned in the previous article, the ini_set function can dynamically modify part of the configuration of php during the execution of php. Note that only some and not all configurations can be modified dynamically. For modifiable ini configurations, see: http://php.net/manual/zh/configuration.changes.modes.php
Let's go straight to the implementation of ini_set. The function is a bit long, but the logic is clear:
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) {
Return
}
/ / go to EG (ini_directives) to get the configured value
Old_value = zend_ini_string (varname, varname_len + 1,0)
/ * copy to return here, because alter might free it! * /
If (old_value) {
RETVAL_STRING (old_value, 1)
} else {
RETVAL_FALSE
}
/ / if safe mode is enabled, the following ini configurations may involve file operations and need to be assisted in checking uid
# define _ CHECK_PATH (var, var_len, ini) php_ini_check_path (var, var_len, ini, sizeof (ini))
/ * safe_mode & basedir check * /
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
}
}
}
/ / in safe mode, the following ini are protected from dynamic modification
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
}
}
/ / call zend_alter_ini_entry_ex to dynamically modify the ini configuration
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
}
}
As you can see, apart from some necessary verification work, the main thing is to call zend_alter_ini_entry_ex.
Let's follow up on the zend_alter_ini_entry_ex function:
The copy code is as follows:
ZEND_API int zend_alter_ini_entry_ex (char * name, 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 * duplicate
Zend_bool modifiable
Zend_bool modified
/ / find the corresponding ini_entry in EG (ini_directives)
If (zend_hash_find (EG (ini_directives), name, name_length, (void * *) & ini_entry) = = FAILURE) {
Return FAILURE
}
/ / whether it has been modified and can be modified
Modifiable = ini_entry- > modifiable
Modified = ini_entry- > modified
If (stage = = ZEND_INI_STAGE_ACTIVATE & & modify_type = = ZEND_INI_SYSTEM) {
Ini_entry- > modifiable = ZEND_INI_SYSTEM
}
/ / whether to force the modification
If (! force_change) {
If (! (ini_entry- > modifiable & modify_type)) {
Return FAILURE
}
}
/ / EG (modified_ini_directives) is used to store the modified ini_entry
/ / mainly used for recovery
If (! EG (modified_ini_directives)) {
ALLOC_HASHTABLE (EG (modified_ini_directives))
Zend_hash_init (EG (modified_ini_directives), 8, NULL, NULL, 0)
}
/ / keep the value in ini_entry, the length of the value, and the modifiable range to orig_xxx.
/ / so that the ini_entry can be restored at the end of the request
If (! modified) {
Ini_entry- > orig_value = ini_entry- > value
Ini_entry- > orig_value_length = ini_entry- > value_length
Ini_entry- > orig_modifiable = modifiable
Ini_entry- > modified = 1
Zend_hash_add (EG (modified_ini_directives), name, name_length, & ini_entry, sizeof (zend_ini_entry*), NULL)
}
Duplicate = estrndup (new_value, new_value_length)
/ / call modify to update the corresponding ini configuration in 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) = = SUCCESS) {
/ / same as above, if you modify it multiple times, you need to release the previously modified value.
If (modified & & ini_entry- > orig_value! = ini_entry- > value) {
Efree (ini_entry- > value)
}
Ini_entry- > value = duplicate
Ini_entry- > value_length = new_value_length
} else {
Efree (duplicate)
Return FAILURE
}
Return SUCCESS
}
There are three logical points that we need to understand carefully:
1) the modified field in ini_entry is used to indicate whether the configuration has been dynamically modified. Once the ini configuration is modified, the modified is set to 1. There is a key paragraph in the above code:
The copy code is as follows:
/ / if ini_set is called multiple times, orig_value and others always maintain the original value
If (! modified) {
Ini_entry- > orig_value = ini_entry- > value
Ini_entry- > orig_value_length = ini_entry- > value_length
Ini_entry- > orig_modifiable = modifiable
Ini_entry- > modified = 1
Zend_hash_add (EG (modified_ini_directives), name, name_length, & ini_entry, sizeof (zend_ini_entry*), NULL)
}
This code indicates that no matter how many times we call ini_set in the php code, only the first time we ini_set will enter this logic and set up the orig_value. From the second call to ini_set, the branch will not be executed again, because the modified has already been set to 1. Therefore, ini_entry- > orig_value always saves the configuration value (that is, the original configuration) before the first modification.
2) in order for the configuration modified by ini_set to take effect immediately, the on_modify callback function is required.
As mentioned in the previous article, on_modify is called to be able to update the global variables of the module. Recall that, first of all, the configuration in the module's global variables is no longer a string type, instead of using bool with bool and int with int. Secondly, the address of the global variable of the module and the corresponding offset are stored in each ini_entry, so that the on_modify can modify the memory very quickly. Also don't forget that after the on_modify call, you still need to further update ini_entry- > value so that the configuration values in EG (ini_directives) are up to date.
3) A new hash table, EG (modified_ini_directives), appears here.
EG (modified_ini_directives) is only used to store dynamically modified ini configurations. If an ini configuration is dynamically modified, it exists in both EG (ini_directives) and EG (modified_ini_directives). Since every ini_entry is marked with a modified field, isn't it possible to iterate through EG (ini_directives) to get all the modified configurations?
The answer is yes. Personally, I think that the main purpose of EG (modified_ini_directives) here is to improve performance, so it is enough to traverse EG (modified_ini_directives) directly. In addition, by deferring the initialization of EG (modified_ini_directives) to zend_alter_ini_entry_ex, you can also see the performance optimization point of php in detail.
2. Restore the configuration
The action time of the ini_set is different from that of the php.ini file, and once the request execution is completed, the ini_set will be invalid. In addition, when the ini_restore function is called in our code, the configuration previously set through ini_set will also be invalidated.
After each php request is executed, php_request_shutdown is triggered, which is two corresponding processes to php_request_startup. If the php is hooked under apache/nginx, php_request_shutdown; is called every time a http request is processed. If php runs in CLI mode, php_request_shutdown is also called after the script is executed.
In php_request_shutdown, we can see the recovery processing for ini:
The copy code is as follows:
/ * 7. Shutdown scanner/executor/compiler and restore ini entries * /
Zend_deactivate (TSRMLS_C)
When you enter zend_deactivate, you can further see that the zend_ini_deactivate function is called, and zend_ini_deactivate is responsible for restoring the configuration of php.
The copy code is as follows:
Zend_try {
Zend_ini_deactivate (TSRMLS_C)
} zend_end_try ()
Let's take a look at the implementation of zend_ini_deactivate:
The copy code is as follows:
ZEND_API int zend_ini_deactivate (TSRMLS_D) / * {{* /
{
If (EG (modified_ini_directives)) {
/ / traverse the table in EG (modified_ini_directives)
/ / call zend_restore_ini_entry_wrapper for each ini_entry
Zend_hash_apply (EG (modified_ini_directives), (apply_func_t) zend_restore_ini_entry_wrapper TSRMLS_CC)
/ / Recycling operation
Zend_hash_destroy (EG (modified_ini_directives))
FREE_HASHTABLE (EG (modified_ini_directives))
EG (modified_ini_directives) = NULL
}
Return SUCCESS
}
From the zend_hash_apply point of view, the real task of restoring ini finally falls to the zend_restore_ini_entry_wrapper callback function.
The copy code is as follows:
Static int zend_restore_ini_entry_wrapper (zend_ini_entry * * ini_entry TSRMLS_DC)
{
/ / zend_restore_ini_entry_wrapper is the encapsulation of zend_restore_ini_entry_cb
Zend_restore_ini_entry_cb (* ini_entry, ZEND_INI_STAGE_DEACTIVATE TSRMLS_CC)
Return 1
}
Static int zend_restore_ini_entry_cb (zend_ini_entry * ini_entry, int stage TSRMLS_DC)
{
Int result = FAILURE
/ / only look at the modified ini entries
If (ini_entry- > modified) {
If (ini_entry- > on_modify) {
/ / use orig_value to reset the relevant fields in the XXX_G
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) {
/ * runtime failure is OK * /
Return 1
}
If (ini_entry- > value! = ini_entry- > orig_value) {
Efree (ini_entry- > value)
}
/ / ini_entry itself returns to the original value
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
}
Return 0
}
The logic is quite clear. I believe readers can understand it. Summarize the recovery process for ini configuration:
The copy code is as follows:
Php_request_shutdown--- > zend_deactivate--- > zend_ini_deactivate--- > zend_restore_ini_entry_wrapper--- > zend_restore_ini_entry_cb
3. Destroy the configuration
At the end of the sapi life cycle, such as apache shutdown, cli program execution completed, and so on. Once at this stage, the previously mentioned configuration_hash,EG (ini_directives) and so on need to be destroyed, and the memory space used needs to be released.
1 UNREGISTER_INI_ENTRIES php terminates all modules in turn, calling UNREGISTER_INI_ENTRIES in the PHP_MSHUTDOWN_FUNCTION of each module. UNREGISTER_INI_ENTRIES corresponds to REGISTER_INI_ENTRIES, but UNREGISTER_INI_ENTRIES is not responsible for releasing the global space of the module. XXX_globals is stored on the static data area without artificial recycling.
The main thing UNREGISTER_INI_ENTRIES does is to remove the ini_entry configuration of a module from the EG (ini_directives) table. After deletion, ini_entry 's own space will be reclaimed, but ini_entry- > value will not necessarily be reclaimed.
When the PHP_MSHUTDOWN_FUNCTION of all modules calls UNREGISTER_INI_ENTRIES once, only the ini configuration of the Core module is left in EG (ini_directives). At this point, you need to manually call UNREGISTER_INI_ENTRIES to delete the configuration of the Core module.
The copy code is as follows:
Void php_module_shutdown (TSRMLS_D)
{
...
/ / zend_shutdown shuts down all php modules except Core in turn
/ / the PHP_MSHUTDOWN_FUNCTION of each module is called when it is closed
Zend_shutdown (TSRMLS_C)
...
/ / so far, only the configuration of the Core module is left in EG (ini_directives)
/ / manually clean up here.
UNREGISTER_INI_ENTRIES ()
/ / Recycle configuration_hash
Php_shutdown_config ()
/ / Recycle EG (ini_directives)
Zend_ini_shutdown (TSRMLS_C)
...
}
When the manual call to UNREGISTER_INI_ENTRIES is complete, EG (ini_directives) no longer contains any elements, and in theory, EG (ini_directives) is an empty hash table.
2Recycling of the php_shutdown_config announcement hash takes place after EG (ini_directives), and the code posted above contains function calls about php_shutdown_config. Php_shutdown_config is mainly responsible for recycling configuration_hash.
The copy code is as follows:
Int php_shutdown_config (void)
{
/ / Recycle configuration_hash
Zend_hash_destroy & configuration_hash)
...
Return SUCCESS
}
Note that zend_hash_destroy does not free up the space of the configuration_hash itself. Like the module global space accessed by XXX_G, configuration_hash is a global variable that does not need to be manually recycled.
3, when the php_shutdown_config is complete, only EG (ini_directives)'s own space has not been released. So the last step calls zend_ini_shutdown. Zend_ini_shutdown is used to release EG (ini_directives). As mentioned earlier, the EG (ini_directives) at this time is theoretically an empty hash table, so the space occupied by the HashTable itself needs to be freed.
The copy code is as follows:
ZEND_API int zend_ini_shutdown (TSRMLS_D)
{
/ / EG (ini_directives) is a dynamically allocated space that needs to be recycled
Zend_hash_destroy (EG (ini_directives))
Free (EG (ini_directives))
Return SUCCESS
}
The above is all the contents of the article "how to dynamically modify ini configuration in php". Thank you for reading! I believe we all have a certain understanding, hope to share the content to help you, if you want to learn more knowledge, welcome to follow the industry information channel!
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.