In-depth understanding of INI configuration in PHP (1) _php tutorial

Source: Internet
Author: User
Tags configuration php php source code register php sapi

In-depth understanding of INI configuration in PHP (1)


This article does not describe the purpose of an INI configuration item in detail, as explained in the manual. I just want to dig into PHP's implementation mechanism from a specific point of view, which involves some knowledge of the PHP kernel:-) The students who use PHP know that the php.ini configuration will take effect throughout the SAPI life cycle. During the execution of a PHP script, if you manually modify the INI configuration, it will not function. If you cannot restart Apache or Nginx, then you can only explicitly invoke the Ini_set interface in your PHP code. Ini_set is a function that PHP provides to us to dynamically modify the configuration, it is important to note that the configuration set by the Ini_set and the configuration set in the INI file, the time range for which it takes effect is not the same. After the execution of the PHP script is complete, the Ini_set settings are invalidated. Therefore, this article intends to divide two articles, the first one describes the php.ini configuration principle, the second chapter on dynamic modification of PHP configuration. The configuration of php.ini will roughly involve three pieces of data, Configuration_hash,eg (ini_directives) and PG, BG, Pcre_g, Json_g, xxx_g, etc. If it is not clear that the meaning of these three kinds of data is not related, the following will be explained in detail. 1, parsing ini configuration file because php.ini needs to be in effect during the SAPI process, parsing the INI file and building the PHP configuration accordingly must be the beginning of the SAPI. In other words, that must happen in PHP's startup process. PHP requires that any actual request arrives before it has been built into its internal configuration. The kernel that is reflected in PHP is the Php_module_startup function. Php_module_startup is primarily responsible for initiating PHP, which is usually called at the beginning of SAPI. BTW, there is also a common function is php_request_startup, which is responsible for each request will be initialized at the moment of arrival, Php_module_startup and Php_request_startup is two of the identity of the action, But the analysis of them is not within the scope of this article. For example, when PHP is hooked up to a module under Apache, then Apache activates all of these module, including the PHP module. When the PHP module is activated, it is called to Php_module_startup. Php_module_startup function completed the vast number of work, once the php_module_startup call to the end means that ok,php has been started, can now accept the request and makeresponded. In the Php_module_startup function, the implementation associated with the parse INI file is:/* This is read in php.ini, set up the configuration parameters, load Zend Extens Ions and register PHP function extensions to be loaded later */if (Php_init_config (tsrmls_c) = = FAILURE) {return FAILURE; You can see that the Php_init_config function is actually called to complete the parse of the INI file. Parse works primarily for Lex&grammar analysis and extracts key and value key values from INI files and saves them. The format of the php.ini is simple, the left side of the equals sign is key, and the right is value. When a pair of kv is extracted, where does PHP store it? The answer is the Configuration_hash mentioned earlier. The static HashTable Configuration_hash;configuration_hash is declared in Php_ini.c, which is a HashTable type of data structure. As the name implies, is actually a hash table. aside, the version before php5.3 is not able to get configuration_hash because it is a static variable of the Php_ini.c file. Later php5.3 added the Php_ini_get_configuration_hash interface, which directly returns &configuration_hash, making PHP extensions easy to glimpse Configuration_ Hash full picture ... It's really a joy to run ... Note Four: First, Php_init_config does not do anything other than lexical syntax. That is, if we add a line of Hello=world to the INI file, as long as this is a well-formed configuration item, then the final configuration_hash will contain a key hello, the value of the world element, Configuration_ Hash to maximize the reflection of the INI file. Second, the INI file allows us to configure it in the form of an array. For example, write the following three lines in the INI file: drift.arr[]=1drift.arr[]=2drift.arr[]=3 then the resulting confIn the Iguration_hash table, there will be an element with a key of Drift.arr, whose value is an array of three numbers containing the three-by-one. This is a very rare configuration method. Third, PHP also allows us to build some INI files in addition to the default php.ini file (exactly Php-%s.ini). These INI files are placed in an additional directory. The directory is specified by the environment variable Php_ini_scan_dir, and when php_init_config resolves the php.ini, it scans the directory again and then finds all the. INI files in the directory for analysis. The KV key pairs generated in these additional INI files will also be added to the Configuration_hash. This is an occasionally useful feature, assuming we develop PHP's own extensions, but do not want to mix the configuration php.ini, you can write an additional ini, and through Php_ini_scan_dir tell PHP where to find it. Of course, its drawbacks are obvious, and it needs to be supported by setting additional environment variables. A better solution is for the developer to call Php_parse_user_ini_file or zend_parse_ini_file in the extension to parse the corresponding INI file. Four, in Configuration_hash, key is a string, so what is the type of the value? The answer is also a string (except for the very special array above). Specifically, for example, the following configuration: display_errors = onlog_errors = Offlog_errors_max_len = 1024 then the key value pair actually stored in the last Configuration_hash is: key: " Display_errors "val:" 1 "Key:" Log_errors "val:" "" Key: "Log_errors_max_len" val: "1024" note log_errors, whose stored value is not even "0", is a truly empty string. Also, Log_errors_max_len is not a number, but a string of 1024. Analysis to this point, basically parse INI file related content is clear. A simple summary: 1, the parsing ini occurs in the Php_module_startup Phase 2, the results are stored in Configuration_hash. 2, the configuration function to the module PHP's approximate structure can be seen as the lowest layer has a Zend engine, it is responsible for interacting with the OS, compiling PHP code, providing memory hosting, etc., on the top of the Zend engine, lined up a lot ofThe module. One of the most core of a core module, and others such as standard,pcre,date,session and so on ... These modules also have another name called PHP extensions. We can simply understand that each module will provide a set of functional interfaces for the developer to invoke, for example, built-in functions such as Explode,trim,array are provided by the standard module. Why do you need to talk about this, because in php.ini in addition to PHP itself, that is, for the core module configuration (such as safe_mode,display_errors,max_execution_time, etc.), There are also quite a few configurations for other different modules. For example, the date module, which provides functions such as the common date, time,strtotime, and so on. In php.ini, its related configuration is as follows: [Date];d ate.timezone = ' Asia/shanghai ';d ate.default_latitude = 31.7667;date.default_longitude = 35.2333;date.sunrise_zenith = 90.583333;date.sunset_zenith = 90.583333 In addition to these modules have a separate configuration, the Zend engine is also available, but the Zend engine can be very small, Only ERROR_REPORTING,ZEND.ENABLE_GC and Detect_unicode three items. As we mentioned in the previous section, Php_module_startup calls Php_init_config, which is intended to parse the INI file and generate Configuration_hash. So what's going to happen next in Php_module_startup? It is obvious that the configuration in Configuration_hash will be applied to different modules such as ZEND,CORE,STANDARD,SPL. Of course, this is not a one-off process, because PHP usually contains a lot of modules, PHP boot process These modules will be started in turn. Then, the process of configuring module A occurs during the boot process of module A. Students with extended development experience will directly point out that the start of module A is not in php_minit_function (a)? Yes, if module a needs to be configured, then in Php_minit_function, you can call Register_ini_entries () to complete. Register_ini_entries will be based on whenThe configuration item name required by the former module, go to Configuration_hash to find the configuration value set by the user, and update to the module's own global space. 2.1, module global space to understand how to configure the INI configuration from Configuration_hash to each module, it is necessary to understand the global space of the PHP module first. For different PHP modules, you can open up a piece of your own storage space, and this block of space for the module, is globally visible. Generally, it is used to store the INI configuration required for the module. That is, the configuration items in the Configuration_hash are eventually stored in the global space. In the execution of the module, only the direct access to the global space, you can get the user's settings for the module. Of course, it is also often used to record intermediate data during the execution of a module. We illustrate with the Bcmath module that Bcmath is a PHP module that provides an interface for mathematical computing, first we look at what INI configuration it has: Php_ini_begin () std_php_ini_entry ("Bcmath.scale", "0 ", Php_ini_all, Onupdatelonggezero, Bc_precision, Zend_bcmath_globals, Bcmath_globals) php_ini_end () Bcmath only one configuration item, We can use Bcmath.scale to configure the Bcmath module in php.ini. Next, look at the global space definition for the Bcmatch module. The following declaration is made in PHP_BCMATH.H: Zend_begin_module_globals (Bcmath) Bc_num _zero_; Bc_num _one_; Bc_num _two_; Long bc_precision; Zend_end_module_globals (BCMATH) macro expands, that is: typedef struct _ZEND_BCMATH_GLOBALS {bc_num _zero_; bc_num _one_; Bc_num _two_ ; Long Bc_precision;} Zend_bcmath_globals; in fact, the zend_bcmath_globals type is the global space type in the Bcmath module. Only the zend_bcmath_globals structure is declared here, and there is a specific instantiation definition in the BCMATH.C://Zend_bcmath_glo after expansionBals bcmath_globals; Zend_declare_module_globals (Bcmath) shows that the definition of variable bcmath_globals is accomplished with zend_declare_module_globals. Bcmath_globals is a real global space that contains four of fields. Its last field, Bc_precision, corresponds to Bcmath.scale in the INI configuration. We set the value of Bcmath.scale in PHP.ini, and then the value of Bcmath.scale is updated to bcmath_globals.bc_precision when the Bcmath module is started. The value in Configuration_hash is updated to the xxx_globals variable defined by each module, which is called the INI configuration action to the module. Once the module is started, these configurations are also in place. Therefore, in the subsequent execution phase, the PHP module does not need to revisit the Configuration_hash, the module only needs to access its own xxx_globals, you can get the user-defined configuration. Bcmath_globals, in addition to having a field INI configuration item, what other three fields do you mean? This is the second function of the module global space, which, in addition to the INI configuration, can also store some of the data in the process of module execution. Another example is the JSON module, which is a very common module in PHP: Zend_begin_module_globals (JSON) int error_code; Zend_end_module_globals (JSON) can see that the JSON module does not require an INI configuration, and that its global space has only one field error_code. Error_code records the last time an error occurred in the execution of Json_decode or Json_encode. The Json_last_error function returns this error_code to help the user locate the cause of the error. In order to easily access the module global space variables, PHP has introduced a number of macros. For example, we want to visit json_globals in the Error_code, of course, can write directly json_globals.error_code (not in multithreaded environment), but the more general way is to define the JSON_G macro: #define JSON_G (v) ( JSON_GLOBALS.V) We use Json_g (error_code) to access Json_globals.error_code. At the beginning of this article, and mentioned PG, BG, Json_g, Pcre_g,xxx_g and so on, these macros are also very common in PHP source code. Now we can easily understand them, PG macros can access global variables of the core module, BG accesses the global variables of the standard module, and PCRE_G accesses the global variables of the PCRE module. #define PG (v) (CORE_GLOBALS.V) #define BG (v) (BASIC_GLOBALS.V) 2.2, how do I determine what configuration is required for a module? What INI configuration The module requires is defined by itself in each module. For example, for a core module, a configuration item definition like the following: Php_ini_begin () ... STD_PHP_INI_ENTRY_EX ("Display_errors", "1", Php_ini_all, Onupdatedisplayerrors, Display_errors, Php_core_globals, Core_globals, Display_errors_mode) Std_php_ini_boolean ("Enable_dl", "1", Php_ini_system, Onupdatebool, ENABLE_DL, PHP _core_globals, Core_globals) Std_php_ini_boolean ("expose_php", "1", Php_ini_system, Onupdatebool, expose_php, Php_ Core_globals, Core_globals) Std_php_ini_boolean ("Safe_mode", "0", Php_ini_system, Onupdatebool, Safe_mode, php_core_ Globals, Core_globals) ... Php_ini_end () can find the above code in the Php-src\main\main.c file about 450+ line. There are more macros involved, there are Zend_ini_begin, Zend_ini_end, PHP_INI_ENTRY_EX, Std_php_ini_boolean, etc., this article does not repeat, interested readers can analyze their own. After macro expansion, the above code gets: static Const zend_ini_entry ini_entries[] = {.. {0, Php_ini_All, "display_errors", sizeof ("display_errors"), Onupdatedisplayerrors, (void *) Xtoffsetof (php_core_globals, display _errors), (void *) &core_globals, NULL, "1", sizeof ("1")-1, NULL, 0, 0, 0, Display_errors_mode}, {0, Php_ini_system, "Enable_dl", sizeof ("Enable_dl"), Onupdatebool, (void *) Xtoffsetof (php_core_globals, ENABLE_DL), (void *) &core_ Globals, NULL, "1", sizeof ("1")-1, NULL, 0, 0, 0, ZEND_INI_BOOLEAN_DISPLAYER_CB}, {0, Php_ini_system, "expose_php", size Of ("expose_php"), Onupdatebool, (void *) Xtoffsetof (php_core_globals, expose_php), (void *) &core_globals, NULL, "1" , sizeof ("1")-1, NULL, 0, 0, 0, ZEND_INI_BOOLEAN_DISPLAYER_CB}, {0, Php_ini_system, "Safe_mode", sizeof ("Safe_mode"), on Updatebool, (void *) Xtoffsetof (php_core_globals, Safe_mode), (void *) &core_globals, NULL, "0", sizeof ("0")-1, NULL, 0, 0, 0, ZEND_INI_BOOLEAN_DISPLAYER_CB}, ... {0, 0, NULL, 0, NULL, NULL, NULL, NULL, NULL, 0, NULL, 0, 0, 0, null}}; We see that the definition of a configuration item is essentially a definition of an array of type Zend_ini_entry. Zend_iThe field of the Ni_entry struct has the following meaning: struct _zend_ini_entry {int module_number;//ID of the module int modifiable;//range to be modified, e.g. Php.ini,ini_set Cha R *name; The name of the configuration item uint Name_length; ZEND_INI_MH ((*on_modify)); A callback function that calls void *MH_ARG1 when the configuration item is registered or modified; Typically the offset of the configuration item field in Xxx_g is void *mh_arg2; usually xxx_g void *mh_arg3; Usually reserved fields, rarely use char *value; The value of the configuration item uint Value_length; Char *orig_value; The original value of the configuration item uint Orig_value_length; int orig_modifiable; The original modifiable int modified of the configuration item; If any modifications have occurred, Orig_value will save the pre-modified value void (*displayer) (zend_ini_entry *ini_entry, int type);}; 2.3, the configuration action to the module--register_ini_entries is often able to see register_ini_entries in different extended php_minit_function. Register_ini_entries is mainly responsible for the completion of two things, first, the module's global space Xxx_g to fill, synchronous Configuration_hash in the value of Xxx_g. Second, it also generates eg (ini_directives). Register_ini_entries is also a macro, after unfolding is actually the Zend_register_ini_entries method. Specifically, the implementation of zend_register_ini_entries: Zend_api int zend_register_ini_entries (const zend_ini_entry *ini_entry, int module _number tsrmls_dc)/* {{*/{//Ini_entry is an array of zend_ini_entry types, and P is a pointer to each item in the groupNST zend_ini_entry *p = ini_entry; Zend_ini_entry *hashed_ini_entry; Zval Default_value; EG (ini_directives) is registered_zend_ini_directives HashTable *directives = registered_zend_ini_directives; Zend_bool config_directive_success = 0; Remember ini_entry last item fixed to {0, 0, NULL, ...} The while (p->name) {config_directive_success = 0;//Add P-pointed zend_ini_entry to eg (ini_directives) if (Zend_hash_add ( directives, P->name, P->name_length, (void*) p, sizeof (zend_ini_entry), (void *) &hashed_ini_entry) = = FAILURE) {zend_unregister_ini_entries (Module_number tsrmls_cc); return FAILURE;} hashed_ini_entry->module_number = Module_number; According to the name of the Configuration_hash query, the results are placed in Default_value//Note that the value of default_value is relatively primitive, usually numbers, strings, arrays, etc., depending on the wording of the php.ini in the IF ( (Zend_get_configuration_directive (P->name, P->name_length, &default_value)) = = SUCCESS) {//Call On_ Modify update to the module's global space Xxx_g if (!hashed_ini_entry->on_modify | | hashed_ini_entry->on_modify (hashed_ini_entry, Z_ Strval (Default_value), Z_strlen (Default_value), Hashed_ini_entry->mh_arg1, HASHED_INI_ENTRY->MH_ARG2, HASHED_INI_ENTRY->MH_ARG3 , zend_ini_stage_startup tsrmls_cc) = = SUCCESS) {hashed_ini_entry->value = Z_strval (default_value); hashed_ini_ Entry->value_length = Z_strlen (default_value); config_directive_success = 1; }}//If not found in Configuration_hash, the default value 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->mh_arg3, ZEND_INI_STAGE_STARTUP TSRMLS_CC); } p++; } return SUCCESS;} Simply put, the logic of the above code can be expressed as: 1, the module declaration of the INI configuration item is added to eg (ini_directives). Note that the value of the INI configuration item may subsequently be modified. 2, try to go to Configuration_hash to find the required INI for each module. If it can be found, the user is configured with this value in the 叜 INI file. If not found, OK, no relationship, because the module when declaring the INI, will bring the default value. 3, the INI value is synchronized to xx_g inside. After all, in the course of PHP execution, these xxx_globals are still working. The specific process is to invoke each INI configuration corresponding to the On_modify method is completed, on_modify by the module when declaring the INI is specified. Let's take a concrete look at the on_modify, itActually is a function pointer, to see two specific core module configuration declaration: Std_php_ini_boolean ("Log_errors", "0", Php_ini_all, Onupdatebool, Log_errors, Php_core _globals, Core_globals) std_php_ini_entry ("Log_errors_max_len", "1024x768", Php_ini_all, Onupdatelong, Log_errors_max_ Len, Php_core_globals, core_globals) for Log_errors, its on_modify is set to Onupdatebool, and for Log_errors_max_len, On_ Modify is set to Onupdatelong. Further assume that our configuration in php.ini is: log_errors = Onlog_errors_max_len = 1024 Specifically, the Onupdatebool function: Zend_api zend_ini_mh (Onupdatebool) {Zend_bool *p;//base represents the address of the core_globals char *base = (char *) mh_arg2;//P means the address of the Core_globals plus the offset of the log_errors field//The resulting LO g_errors field Address 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 && strcas ECMP ("true", new_value) = = 0) {*p = (zend_bool) 1;} else {//Configuration_hash the value stored is the string "1", not "on" So here the atoi is converted into a number 1 *p = (zend_bool) atoi (New_value); } return SUCCESS;} The most puzzling estimate is mh_arg1 and mh_arg2, in fact, compared with the zend_ini_entry definition described earlier, MH_ARG1,MH_ARG2 is very easy to fathom. MH_ARG1 represents the byte offset, and MH_ARG2 represents the address of the xxx_globals. Therefore, the result of (char *) MH_ARG2 + MH_ARG1 is the address of a field in Xxx_globals. In this case, the address of log_errors in Core_globals is calculated. Therefore, when Onupdatebool is finally executed to *p = (Zend_bool) atoi (New_value); Its function is equivalent to core_globals.log_errors = (Zend_bool) atoi ("1"); Analysis finished Onupdatebool, we again see Onupdatelong feel at a glance: Zend_api zend_ini_mh (Onupdatelong) {long *p; char *base = (char *) mh_arg2; Get Log_errors_max_len Address P = (long *) (base+ (size_t) mh_arg1); Convert "1024" to long and assign value to Core_globals.log_errors_max_len *p = Zend_atol (New_value, new_value_length); return SUCCESS;} Finally, it is important to note that in the Zend_register_ini_entries function, if there is a configuration in Configuration_hash, the value and value in Hashed_ini_entry after the call on_modify ends _length will be updated. That is, if the user is configured in php.ini, then eg (ini_directives) holds the actual configured value. If the user does not match, EG (ini_directives) holds the default value given when declaring Zend_ini_entry. The default_value variable in zend_register_ini_entries is poorly named, and it's quite easy to misunderstand. In fact, Default_value is notRepresents a default value, but rather a value that is actually configured by the user. 3, summed up to this point, three pieces of data Configuration_hash,eg (Ini_directives) and PG, BG, Pcre_g, Json_g, Xxx_g ... Have all been explained clearly. Sum up: 1,configuration_hash, store the configuration in the php.ini file, do not check, its value is a string. 2,eg (ini_directives), which holds zend_ini_entry defined in each module, is replaced with Configuration_hash if the user is configured in php.ini (Configuration_ exists) The value in the hash, the type is still a string. 3,xxx_g, the macro is used to access the module's global space, which can be used to hold the INI configuration and be updated by on_modify the specified function, whose data type is determined by the field declaration in Xxx_g.

http://www.bkjia.com/PHPjc/892830.html www.bkjia.com true http://www.bkjia.com/PHPjc/892830.html techarticle In -depth understanding of the INI configuration in PHP (1) This article does not describe in detail the purpose of an INI configuration item, which is covered in the manual. I just want to dig from a certain point of view ...

  • Related Article

    Contact Us

    The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

    If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

    A Free Trial That Lets You Build Big!

    Start building with 50+ products and up to 12 months usage for Elastic Compute Service

    • Sales Support

      1 on 1 presale consultation

    • After-Sales Support

      24/7 Technical Support 6 Free Tickets per Quarter Faster Response

    • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.