Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

Detailed explanation of PHP extension Development

2025-04-01 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/03 Report--

This article is to share with you the details of PHP extension development. The editor thinks it is very practical, so share it with you as a reference and follow the editor to have a look.

PHP is an interpreted language, and for users, our careful control of memory means easier prototyping and fewer crashes! When we go deep into the kernel, all the security lines have been crossed, and ultimately we have to rely on truly responsible software engineers to ensure the stable operation of the system.

1. Thread safety macro definition

The definition in the TSRM/TSRM.h file is as follows

# define TSRMLS_FETCH () void * tsrm_ls = (void * *) ts_resource_ex (0, NULL)

# define TSRMLS_FETCH_FROM_CTX (ctx) void * tsrm_ls = (void * *) ctx

# define TSRMLS_SET_CTX (ctx) ctx = (void * *) tsrm_ls

# define TSRMG (id, type, element) (type) (* (void * *) tsrm_ls)) [TSRM_UNSHUFFLE_RSRC_ID (id)])-> element)

# define TSRMLS_D void * tsrm_ls

# define TSRMLS_DC, TSRMLS_D

# define TSRMLS_C tsrm_ls

# define TSRMLS_CC, TSRMLS_C

There is a passage in ext/xsl/php_xsl.h.

/ * In every utility function you add that needs to use variables.

In php_xsl_globals, call TSRM_FETCH (); after declaring other.

Variables used by that function, or better yet, pass in TSRMLS_CC

After the last function argument and declare your utility function

With TSRMLS_DC after the last declared argument. Always refer to

The globals in your function as XSL_G (variable). You are.

Encouraged to rename these macros something shorter, see

Examples in any other php module directory.

, /

1. Add TSRMLS_D (if the method has no parameters to use this) or TSRMLS_DC (with more than one parameter) when defining the method

two。 Use TSRMLS_C (if the method has no parameters) or TSRMLS_CC (with more than one parameter) when the method is called

It should be understood this way.

The first suffix letter D represents a definition, or D=Define, the first suffix letter C indicates a call, that is, C=Call, and does the second suffix letter C represent a comma? C=Comma (comma)

TSRMLS_D is defined, so it is void * tsrm_ls

TSRMLS_DC is defined with a comma, so it is void * tsrm_ls

TSRMLS_C is called, that is, tsrm_ls

TSRMLS_CC is called with a comma, that is, tsrm_ls

So one is a formal parameter and the other is an actual parameter.

It can be used like this.

Int php_myext_action (int action_id, char * message TSRMLS_DC)

Php_myext_action (42, "The meaning of life" TSRMLS_CC)

It is generally recommended to use tsrm_ls pointer definition to ensure thread safety.

The TSRMLS_FETCH call takes a certain amount of processing time. This is not obvious in a single iteration, but as you increase the number of threads and the number of points you call TSRMLS_FETCH (), your extension will show this bottleneck. Therefore, please use it carefully. Note: for compatibility with the C++ compiler, make sure that TSRMLS_FETCH () and all variable definitions are placed at the top of the given block scope (before any other statements). Because the TSRMLS_FETCH () macro itself has many different parsing methods, it is best to use it as the last line of the variable definition

2. The life cycle of PHP

The two most common operating modes of PHP are WEB mode and CLI mode. No matter which mode, PHP works on the same principle, running as a SAPI.

1. When we type the command php on the terminal, it uses CLI.

It is like a web server to support php to complete the request, and then re-transfer control to the terminal after the request is completed.

2. When using Apache as the host, PHP will support the completion of a request when it arrives

Run when PHP_MINIT_FUNCTION initializes module

PHP_MSHUTDOWN_FUNCTION runs when module is uninstalled

PHP_RINIT_FUNCTION runs when an REQUEST request initializes

PHP_RSHUTDOWN_FUNCTION runs when an REQUEST request ends

PHP_MINFO_FUNCTION this is the information that sets the module in phpinfo.

When PHP_GINIT_FUNCTION initializes global variables

When PHP_GSHUTDOWN_FUNCTION releases global variables

Like PHP_GINIT_FUNCTION.

PHP_GINIT_FUNCTION (test) {/ * initialize global variable * /} / corresponding C code void zm_globals_ctor_test (zend_test_globals * test_globals TSRMLS_DC) {/ * initialize global variable * /} / / when thread exits, you can use PHP_GSHUTDOWN_FUNCTION to register the destructor when you need to release previously applied resources. PHP_GSHUTDOWN_FUNCTION (test) {/ * clear global variable * / / corresponding C code void zm_globals_dtor_test (zend_test_globals * test_globals TSRMLS_DC) {/ * clear global variable * /}

Here is a piece of code that you can test.

Int minit_time;PHP_MINIT_FUNCTION (test) {minit_time = time (NULL); return SUCCESS;} PHP_MSHUTDOWN_FUNCTION (test) {FILE * fp=fopen ("mshutdown.txt", "a +"); fprintf (fp, "% ld\ n", time (NULL)); fclose (fp); return SUCCESS;} int rinit_time;PHP_RINIT_FUNCTION (test) {rinit_time = time (NULL); return SUCCESS } PHP_RSHUTDOWN_FUNCTION (test) {FILE * fp=fopen ("rshutdown.txt", "a +"); fprintf (fp, "% ld\ n", time (NULL)); fclose (fp); return SUCCESS;} PHP_MINFO_FUNCTION (test) {php_info_print_table_start (); php_info_print_table_header (, "module info", "enabled"); php_info_print_table_end () / * Remove comments if you have entries in php.ini DISPLAY_INI_ENTRIES (); * /} PHP_FUNCTION (test) {php_printf ("% d", time_of_minit); php_printf ("% d", time_of_rinit); return;}

3. Segment error debugging

C programs under Linux often cause segment fault (segment errors) due to memory access errors and other reasons. At this time, if the system core dump function is turned on, then a memory image will be dumped to the hard disk, and then the core file can be analyzed with gdb to restore the stack when a segment error occurs in the system. This is very helpful for us to find the program bug.

Use ulimit-a to view the size limit of the system's core file; use ulimit-c [kbytes] to set the size of the core file that the system is allowed to generate.

Ulimit-c 0 does not generate core files

Ulimit-c 100 sets the maximum core file to 100k

Ulimit-c unlimited does not limit core file size

Steps:

1. When a segment error occurs, we check that ulimit-a (core file size (blocks,-c) 0) does not have a file.

2. Setting: ulimit-c unlimited does not limit the size of core files

3. Run the program and automatically record it in core (php-f WorkWithArray.php) when a segment error occurs.

4. Ls-al core.* is under that file (- rw- 1 leconte leconte 139264 01-06 22:3 1 core.2065)

5. Use gdb to run the program and record the segment error. (gdb. / test core.2065)

6. Will mention which line is wrong.

The default core file size for many systems is 0. We can specify the core file size by adding the ulimit-c command in the shell startup script / etc/bashrc or ~ / .bashrc to ensure that the core file can be generated.

In addition, you can also set the file name template of the core file in / proc/sys/kernel/core_pattern, see core's official man manual for details.

4. Common variable operation macros

CG-> Complier Global compile-time information, including function tables, etc. (zend_globals_macros.h:32)

EG-> Executor Global execution time Information (zend_globals_macros.h:43)

PG-> PHP Core Global mainly stores information in php.ini

SG-> SAPI Global SAPI information

1. SG is in the main/SAPI.h file for SAPI information.

Typedef struct _ sapi_globals_struct {void * server_context; sapi_request_info request_info; sapi_headers_struct sapi_headers; int read_post_bytes; unsigned char headers_sent; struct stat global_stat; char * default_mimetype; char * default_charset; HashTable * rfc1867_uploaded_files; long post_max_size; int options; zend_bool sapi_started; double global_request_time; HashTable known_post_content_types; zval * callback_func Zend_fcall_info_cache fci_cache; zend_bool callback_run;} sapi_globals_struct

Take a look at the definition of SG

BEGIN_EXTERN_C ()

# ifdef ZTS

# define SG (v) TSRMG (sapi_globals_id, sapi_globals_struct *, v)

SAPI_API extern int sapi_globals_id

# else

# define SG (v) (sapi_globals.v)

Extern SAPI_API sapi_globals_struct sapi_globals

# endif

SAPI_API void sapi_startup (sapi_module_struct * sf)

SAPI_API void sapi_shutdown (void)

SAPI_API void sapi_activate (TSRMLS_D)

SAPI_API void sapi_deactivate (TSRMLS_D)

SAPI_API void sapi_initialize_empty_request (TSRMLS_D)

END_EXTERN_C ()

The members are all here at sapi_globals_struct.

Then we can call like this.

SG (default_mimetype)

SG (request_info). Request_uri

You can feel this piece of code.

Static int sapi_cgi_send_headers (sapi_headers_struct * sapi_headers TSRMLS_DC) {char buf [SAPI _ CGI_MAX_HEADER_LENGTH]; sapi_header_struct * h; zend_llist_position pos; long rfc2616_headers = 0; if (SG (request_info). No_headers = = 1) {return SAPI_HEADER_SENT_SUCCESSFULLY;} if (SG (sapi_headers). Http_response_code! = 200) {int len Len = sprintf (buf, "Status:% d\ r\ n", SG (sapi_headers). Http_response_code); PHPWRITE_H (buf, len);} if (SG (sapi_headers). Send_default_content_type) {char * hd; hd = sapi_get_default_content_type (TSRMLS_C); PHPWRITE_H ("Content-type:", sizeof ("Content-type:")-1) PHPWRITE_H (hd, strlen (hd)); PHPWRITE_H ("\ r\ n", 2); efree (hd);} h = zend_llist_get_first_ex (& sapi_headers- > headers, & pos); while (h) {PHPWRITE_H (h-> header, h-> header_len); PHPWRITE_H ("\ r\ n", 2); h = zend_llist_get_next_ex (& sapi_headers- > headers, & pos) } PHPWRITE_H ("\ r\ n", 2); return SAPI_HEADER_SENT_SUCCESSFULLY;}

2 、 EG Executor Globals

EG acquires the data in the struct _ zend_execution_globals structure

Struct _ zend_execution_globals {... HashTable symbol_table; / * global scope, if not inside the function, global = activity * / HashTable * active_symbol_table; / * activity scope, current scope * /...}

In general, EG (symbol_table) is used to get the symbol table in the global scope, and EG (active_symbol_table) is used to get the symbol table in the current scope

For example, to define $foo = 'bar'

Zval * fooval

MAKE_STD_ZVAL (fooval)

ZVAL_STRING (fooval, "bar", 1)

ZEND_SET_SYMBOL (EG (active_symbol_table), "foo", fooval)

Or look for $foo from the symbol table

Zval * * fooval

If (zend_hash_find (& EG (symbol_table), foo, sizeof ("foo"), (void * *) & fooval) = = SUCCESS) {

RETURN_STRINGL (Z_STRVAL_PP (fooval), Z_STRLEN_PP (fooval))

} else {

RETURN_FALSE

}

In the above code, EG (active_symbol_table) = & EG (symbol_table)

3. CG () is used to access the core global variables. (zend/zend_globals_macros.h)

4. PG () PHP global variable. We know that php.ini maps one or more PHP global structures. (main/php_globals.h)

5. FG () file global variable. The data flow of most file Icano or related global variables is crammed into the standard extended exit structure. (ext/standard/file.h)

5. Get the type and value of the variable

# define Z_TYPE (zval) (zval). Type

# define Z_TYPE_P (zval_p) Z_TYPE (* zval_p)

# define Z_TYPE_PP (zval_pp) Z_TYPE (* * zval_pp)

Such as getting the type of a variable

Void describe_zval (zval * foo) {if (Z_TYPE_P (foo) = = IS_NULL) {php_printf ("the data type of this variable is: NULL");} else {php_printf ("the data type of this variable is not NULL, the number corresponding to this data type is:% d", Z_TYPE_P (foo));}}

There are several types.

# define IS_NULL 0

# define IS_LONG 1

# define IS_DOUBLE 2

# define IS_BOOL 3

# define IS_ARRAY 4

# define IS_OBJECT 5

# define IS_STRING 6

# define IS_RESOURCE 7

# define IS_CONSTANT 8

# define IS_CONSTANT_ARRAY 9

# define IS_CALLABLE 10

The php_printf () function is a layer of encapsulation of the kernel printf () function, and we can use it as we do with the printf () function. Macros ending in a P are mostly * zval variables. In addition, there are two macros for getting variable types, Z_TYPE and Z_TYPE_PP, whose argument is zval and the latter is * * zval

For example, the implementation of the gettype function

/ / start defining the function gettypePHP_FUNCTION (gettype) {/ / arg in the php language indirectly points to the parameters passed when the gettype function is called. Is a zval** structure / / so we will use a macro with the _ _ PP suffix on it. The main operation of zval * * arg; / / this if is to make arg point to the parameter ~ if (zend_parse_parameters (ZEND_NUM_ARGS () TSRMLS_CC, "Z", & arg) = = FAILURE) {return;} / / call the Z_TYPE_PP macro to get the type of arg pointing to zval. / / then there is a switch structure, and the RETVAL_ string macro represents the string type value switch (Z_TYPE_PP (arg)) {case IS_NULL: RETVAL_STRING ("NULL", 1) returned by the gettype function; break; case IS_BOOL: RETVAL_STRING ("boolean", 1); break; case IS_LONG: RETVAL_STRING ("integer", 1); break Case IS_DOUBLE: RETVAL_STRING ("double", 1); break; case IS_STRING: RETVAL_STRING ("string", 1); break; case IS_ARRAY: RETVAL_STRING ("array", 1); break; case IS_OBJECT: RETVAL_STRING ("object", 1); break; case IS_RESOURCE: {char * type_name Type_name = zend_rsrc_list_get_rsrc_type (Z_LVAL_PP (arg) TSRMLS_CC); if (type_name) {RETVAL_STRING ("resource", 1); break;} default: RETVAL_STRING ("unknown type", 1);}}

Get the value of the variable, there are so many macros to get

Long

Boolean

Double

String value

String length

Z_LVAL () Z_BVAL () Z_DVAL () Z_STRVAL () Z_STRLEN () Z_LVAL_P () Z_BVAL_P () Z_DVAL_P () Z_STRVAL_P () Z_STRLEN_P () Z_LVAL_PP () Z_BVAL_PP () Z_DVAL_PP () Z_STRVAL_PP () Z_STRLEN_PP ()

HashTable

Object

Object properties

Object class entry

Resource value

Z_ARRVAL () Z_OBJ () Z_OBJPROP () Z_OBJCE () Z_RESVAL () Z_ARRVAL_P () Z_OBJ_P () Z_OBJPROP_P () Z_OBJCE_P () Z_RESVAL_P () Z_ARRVAL_PP () Z_OBJ_PP () Z_OBJPROP_PP () Z_OBJCE_PP () Z_RESVAL_PP ()

The realization of rot13 function

PHP_FUNCTION (rot13) {zval * * arg; char * ch, cap; int i; if (ZEND_NUM_ARGS ()! = 1 | | zend_get_parameters_ex (1, & arg) = = FAILURE) {WRONG_PARAM_COUNT;} * return_value = * * arg; zval_copy_ctor (return_value); convert_to_string (return_value); for (iTun0, ch=return_value- > value.str.val; ivalue.str.len) ITunes, ch++) {cap = * ch & 32; * ch & = ~ cap; * ch = (* ch > ='A') & & (* ch

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.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report