Home > Article > Backend Development > How to extend PHP and how to extend php at the bottom of linux?_PHP tutorial
Although most PHP engineers don’t need to know how PHP’s C code core works, some may know that there is a dl() function. Or have used some third-party libraries, which are the focus of this article. 1.
I hope this article can be helpful to engineers who want to take PHP to wider boundaries.
First look at the running process of a php request:
Browser user--->web server (apache, nginx)--->Zend engine reads php code files from the file system--->Zend interpreter working
--->Execute the interpreted code-->Function interface registered by Zend engine-->Built-in modules or required external module extensions-->Back-end resources such as database memcache
Among them
The function interface registered by Zend engine is the various php functions that php engineers often come into contact with.
External module extensions are various so files (linux) or dll files (windwos) compiled by PHP.
Execute the interpreted code and the content of the browser is returned from here.
Built-in modules are modules that will be started every time PHP is started.
From the flow chart above, we can know that PHP can be expanded from 3 points. 1 External module expansion 2 Zend engine 3 Built-in modules, I will discuss them one by one below.
External module extension.
If you have used dl() you have come into contact with these external extension modules. The external extension module file is placed on your hard disk. It is loaded into memory when the php script is running, and is only loaded when needed. .
When this script is finished running, it will be released from the memory. Generally speaking, it runs slowly but does not occupy resources. You do not need to recompile PHP.
Built-in modules
Although it is also a module outside the Zend engine, it is somewhat different from the external module extension. It is already in PHP. It will make the size of your compiled PHP larger. If there are changes, PHP must be recompiled. Built-in modules will make
PHP memory will become larger, but it will also be called faster. In our tests, some modules will have a speed increase of more than 30% when running in built-in mode.
Zend Engine
First of all, I definitely do not recommend that you modify the Zend engine. Some PHP language features can only be implemented in the Zend engine. For example, if you want to modify the name of the array keyword, you can do it here.
In the php source code you downloaded, everything starting with zend is the code related to the zend engine.
Generally, the PHP source code directory structure is similar to the following:
Main source code of main php,
ext php extension
sapi api interaction layer code with different servers
zend zend engine part
TSRM thread safety related module code
The following uses a simple module as an example to illustrate how PHP can be extended:
First of all, PHP code has its own set of standards, which you need to abide by, otherwise your module may not be able to release variables or have other problems. These standards include macro definitions, variable declarations, etc. You can go to the official website for detailed instructions.
/* Extended standard header */
#include "php.h"
/* Declare the function exported by this so */
ZEND_FUNCTION(helloworld_module);
/* Function interface registered by Zend engine */
zend_function_entry helloworldmod_interfaces[] =
{
ZEND_FE(helloworld_module, NULL)
{NULL, NULL, NULL}
};
/* This is the declaration entity of this module, and its value has an actual effect on module compilation */
zend_module_entry helloworldmod_module_entry =
{
STANDARD_MODULE_HEADER,
"Hello world",
Helloworldmod_interfaces,
NULL,
NULL,
NULL,
NULL,
NULL,
NO_VERSION_YET,
STANDARD_MODULE_PROPERTIES
};
/* Declare a registration to the zend engine, which can indicate that helloworldmod_module_entry belongs to the dynamic library helloworldmod.so*/
#if COMPILE_DL_helloworld_module
ZEND_GET_MODULE(helloworldmod)
#endif
/* This is the real code of our new function */
ZEND_FUNCTION(helloworld_module)
{
Return "Hello,world";
}
We can modify it to our necessary compilation configuration information based on other extended config.m4 files. This module here is almost an empty config.m4 file,
Then use phpize to generate the configure file and then execute ./configure && make && make install to compile a copy of our dynamic library
test.php
echo helloworld_module();
?>
Output:
"Hello,world"
After completing the PHP extension, we have gone deep into the internals of PHP's C code, but in some cases, this is not enough. We need to go deep into the process of calling C library in C language. A very powerful tool under Linux is the LD_PRELOAD environment variable
LD_PRELOAD environment variable is a filter for the compiler to find the location of functions or global variables referenced in the program. For example, calling a method connect to start a network connection in the C code of PHP is actually through dynamic link
Look for the function connect of the Linux C library. These link files are generally placed under lib. This also provides an entry point for us to affect the code execution of PHP. Because the php program will check LD_PRELOAD
before dynamically loading the function connect under lib
Does the provided dynamic library have this connect function? We can interfere with the behavior of PHP here.
The following is a simple example of filtering network access to illustrate how to implement:
First, there is a code to prepare the so file as the value of the LD_PRELOAD environment variable.
lp_demo.c
#include
#include
#include
#include
#include
#include
//Define our own connect function
int connect(int sockfd, const struct sockaddr *serv_addr, socklen_t
addrlen){
static int (*connect_linuxc)(int, const struct sockaddr*, socklen_t)=NULL;
unsigned char *ip_char;
//Use lsym's RTLD_NEXT option to bypass the connect method of the LD_PRELOAD environment variable to find the function of the c library
if (!connect_linuxc) connect_linuxc=dlsym(RTLD_NEXT,"connect");
ip_char=serv_addr->sa_data;
ip_char+=2;
//192.168.2.3 Found
If ((*ip_char==192)&&(*(ip_char+1)==168)&&(*(ip_char+2)==2)&&(*(ip_char+3)==3)) {
//Simply return a permission error code
return EACCES;
}
//Call the real connect method
Return connect_linuxc(sockfd,serv_addr,addrlen);
}
Compile into so file
$ gcc -o lp_demo.so -shared lp_demo.c -ldl
Test file test.php
file_get_contents("http://192.168.2.3/");
?>
How to use
LD_PRELOAD=lp_demo.so php test.php
In this way, it will be impossible for him to access our internal URL such as 192.168.2.3. Acts as a good sandbox.
In addition, we can also use functions such as fwrite fopen to transfer PHP's read and write operations on the file system to back-end resources such as mencache and nosql.
Finally, even if we have gone deep into the inside of the c library, it does not mean that we have reached the bottom. Under the c library, there are a bunch of functions starting with sys_. They are the real functions in the kernel space. This will not be discussed further.