Linux C ++ for PHP extension reading: 1
Currently, the password of the Bastion host in the database is stored in the ciphertext encrypted by rc4. in the past, PHP had to call the background system command after reading the password, read the stdout of the background system command to obtain the decrypted plaintext password.
This call method encrypts or decrypts each time, so that the call time of a system command may be 10 ms, and will not cause too many problems. Currently, a requirement for verifying the complexity of passwords of all accounts requires that the passwords of all accounts meet the requirements when loading a page. if the account size is large, the problem arises, when the number of accounts is, the request response time reaches 5m19s. if you comment out the decrypted part, the response time is 2-3 s. To optimize this problem, we first try to use xmlrpc to call the c ++ extension of python to speed up the response. The effect is also good, and the response time is increased to about 20 s. After investigation, we found that the serialization and deserialization of pieces of data took 15 s out of 20 s during the xmlrpc call. In order to further improve the response speed, and the source code for encryption and decryption is the code implementation of c ++, I thought that using c ++ to implement a PHP extension may be better, so I started to implement the PHP extension of rc4.
Preparations for compiling PHP Extension 1 using C ++
First, obtain the source code of the php version of the Bastion host on the development machine and decompress it.
yangshuofei@IPS-dev3 ~/src $ tarxvfphp-5.5.25.tar.bz2
2. Compile the config file
The config. m4 file is the core file in the compilation Foundation. this file mainly uses autoconf to generate the configure configuration file, and then automatically generates the Makefile that everyone is familiar.
You can write the config. m4 file by yourself, or use the Shell script ext_skel to generate a template. here I use the latter.
Go to the ext folder of the source code and run the./ext_skel command as follows:
yangshuofei@IPS-dev3 ~/src $ cdphp-5.5.25/ext/yangshuofei@IPS-dev3 ~/src/php-5.5.25/ext $ ./ext_skel --extname=rc4Creatingdirectoryrc4Creatingbasicfiles: config.m4config.w32 .svnignorerc4.c php_rc4.h CREDITSEXPERIMENTALtests/001.phpt rc4.php [done]. To use yournew extension, youwillhaveto executethefollowingsteps: 1. $ cd ..2. $ viext/rc4/config.m43. $ ./buildconf4. $ ./configure --[with|enable]-rc45. $ make6. $ ./sapi/cli/php -f ext/rc4/rc4.php7. $ viext/rc4/rc4.c8. $ make Repeatsteps 3-6 untilyouaresatisfiedwithext/rc4/config.m4andstep 6 confirmsthatyourmoduleis compiledintoPHP. Then, startwritingcodeand repeatthelasttwostepsas oftenas necessary.
There is an additional directory named rc4 under the ext directory. When you enter this directory, you will find several files in the directory:
yangshuofei@IPS-dev3 ~/src/php-5.5.25/ext $ cdrc4yangshuofei@IPS-dev3 ~/src/php-5.5.25/ext/rc4 $ ls -ltotal 32-rw-r--r-- 1 yangshuofeiyangshuofei 3 Mar 14 17:27 CREDITS-rw-r--r-- 1 yangshuofeiyangshuofei 0 Mar 14 17:27 EXPERIMENTAL-rw-r--r-- 1 yangshuofeiyangshuofei 1954 Mar 14 17:27 config.m4-rw-r--r-- 1 yangshuofeiyangshuofei 275 Mar 14 17:27 config.w32-rw-r--r-- 1 yangshuofeiyangshuofei 2787 Mar 14 17:27 php_rc4.h-rw-r--r-- 1 yangshuofeiyangshuofei 5002 Mar 14 17:27 rc4.c-rw-r--r-- 1 yangshuofeiyangshuofei 493 Mar 14 17:27 rc4.phpdrwxr-xr-x 2 yangshuofeiyangshuofei 4096 Mar 14 17:27 tests
Then you can modify the config. m4 file as Prompted. Here are several important macro commands:
- Dnl is a comment;
- PHP_ARG_WITH or PHP_ARG_ENABLE specifies the working mode of the PHP Extension Module. The former means no third-party libraries are required, and the latter is the opposite;
- PHP_REQUIRE_CXX is used to specify that the extension uses C ++;
- PHP_ADD_INCLUDE specifies the header file directory used by the PHP extension module;
- PHP_CHECK_LIBRARY specifies the PHP extension module PHP_ADD_LIBRARY_WITH_PATH definition and library connection error information;
- PHP_ADD_LIBRARY (stdc ++, ", EXTERN_NAME_LIBADD) is used to link the standard C ++ library to the extension;
- PHP_SUBST (EXTERN_NAME_SHARED_LIBADD) is used to illustrate how this extension is compiled into a dynamic link library;
- PHP_NEW_EXTENSION is used to specify which source files should be compiled and separated by spaces;
The default Module Framework generated by ext_skel is for C. We need to use C ++ for PHP extension. in addition to the above two macros PHP_REQUIRE_CXX and PHP_ADD_LIBRARY, we also need to change rc4.c to rc4.cc.
It should be noted that similar Makefile syntax can also be used in config. m4. the snippets are as follows:
PHP_ARG_WITH(rc4, for rc4support,Makesurethatthecommentis aligned:[ --with-rc4 Include rc4support])... COMMON_PATH="../../common" PHP_REQUIRE_CXX() PHP_SUBST(RC4_SHARED_LIBADD) PHP_ADD_INCLUDE($COMMON_PATH/crypt) PHP_ADD_LIBRARY(stdc++, 1, RC4_SHARED_LIBADD) PHP_ADD_LIBRARY_WITH_PATH(SashCommon, $COMMON_PATH, RC4_SHARED_LIBADD) CCFILES="rc4.cc" PHP_NEW_EXTENSION(rc4, $CCFILES, $ext_shared)...
3. write an. h file
Modify the php_rc4.h header file.
Because the functions and classes in the TSRM. h file are written in pure C language, use extern as follows:
extern "C" {#ifdef ZTS#include "TSRM.h"#endif}
Add the php function declaration as follows:
PHP_FUNCTION(rc4_encrypt); /* For encrypt string. */PHP_FUNCTION(rc4_decrypt); /* For decrypt string. */
If the php_rc4.h header file or rc4.cc file uses some containers or functions in the C ++ language, you must include the header file of the corresponding c ++ library, otherwise, the corresponding C ++ function cannot be found.
4. Write A. cc file
Modify the rc4.cc file.
Since config. h. php. h, php_ini.h, and ext/standard/info. h contains functions and classes such as TSRM. h is the same, it is written in pure C language, so you also need to use extern to describe the following:
extern "C" {#ifdef HAVE_CONFIG_H#include "config.h"#endif #include "php.h"#include "php_ini.h"#include "ext/standard/info.h"}#include "php_rc4.h"
The # include "php_ext_name.h" statement does not need to be included in the extern "C". In addition, the macro command ZEND_GET_MODULE also needs to be specifically stated as follows:
#ifdef COMPILE_DL_RC4BEGIN_EXTERN_C()ZEND_GET_MODULE(rc4)END_EXTERN_C()#endif
In short, some C-written libraries or h are compatible. As there is a ready-made c ++ implementation, the relevant header file is introduced:
#include "Crypt.h"
Add related functions:
const zend_function_entryrc4_functions[] = { PHP_FE(rc4_encrypt, NULL) /* For encrypt string. */ PHP_FE(rc4_decrypt, NULL) /* For decrypt string. */ PHP_FE_END /* Must be the last line in rc4_functions[] */};
Add functions as follows:
PHP_FUNCTION(rc4_encrypt){ char *arg = NULL; int arg_len, len; const char *key = "key"; int key_len = sizeof("key") - 1; char *strg; const char *result = NULL; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s", &arg, &arg_len, &key, &key_len) == FAILURE) { return; } result = SASH::Crypt::encryptWithKey(arg, key).c_str(); len = spprintf(&strg, 0, "%s", result); RETURN_STRINGL(strg, len, 0);}
The macro PHP_FUNCTION () is used for the function definition. this macro can generate a function prototype suitable for the Zend Engine. The logic itself is divided into semantic parts to obtain the parameters and logic of the called function.
To obtain the parameters passed by the function, you can use the zend_parse_parameters () API function. The following is a prototype of the function:
zend_parse_parameters(int num_argsTSRMLS_CC, char *type_spec, …);
Most of the code of the zend_parse_parameters () function looks almost the same. ZEND_NUM_ARGS () provides Zend Engine with information about the number of parameters received. TSRMLS_CC is used to ensure thread security, and the function returns SUCCESS or FAILURE. Under normal circumstances, zend_parse_parameters () will return SUCCESS; if the number of parameters passed by a call script exceeds the number of parameters defined by the function, or the passed parameters cannot be converted to the appropriate data type, zend will automatically output an error message, and then the function will return the control to the calling script elegantly.
Possible types
The zval in the table is the real data type used to store all user space variables in PHP. Three "complex" data types: Resource, Array, and Object. when their data type letters are used in zend_parse_parameters, zend Engine checks its type, but they do not have the corresponding data type in the C language, so no conversion will be actually executed.
Since the default key is used for decryption, I used the variable parameter "s | s" in rc4_encrypt. it can be interpreted as follows: I need a string parameter first, then a pipeline character indicates that the following parameter list is optional (if an optional parameter is not passed during the function call, then zend_parse_parameters () will not change the parameter value that has been passed to it), the s below indicates that I need an optional string parameter. & Arg, & arg_len, & key, & key_len are passed in as references. Therefore, zend_parse_parameters () can be filled with parameter values. (Extensions also support variable parameters)
The return value from the C ++ function to PHP does not use the usual return statement. Zend transmits the return value address as a parameter to us. return_value is a standard zval structure created by Zend, it is equivalent to a local variable. when a user obtains the return value, it is equivalent to assigning a value to the return_value. we only need to fill it in. return_value_used indicates whether the user has used the return value, and 0 indicates that the return value is not used, after the function is completed, the refcount of return_value will be reduced to 0 and destroyed. Therefore, in this case, the return value is not processed; return_value_ptr is used to return the reference, which needs to be used together with zend_function_entry.arg_info, it is usually NULL.
A group of macros used to fill in return_value
After filling in the return_value, these macros execute the return statement. If you do not want to return, you can use the RETVAL_xxx version of the corresponding RETURN_xxx macro. Here we use RETURN_STRINGL (strg, len, 0); to return the encrypted string.
5. Generate. so
Use phpize to generate configure (because it is different from the php version on the development machine, we use the self-compiled phpize here ):
yangshuofei@IPS-dev3 ~/src/php-5.5.25/ext/rc4 $ /home/yangshuofei/php/bin/phpize Configuringfor:PHPApiVersion: 20121113ZendModuleApiNo: 20121212ZendExtensionApiNo: 220121212
Generate Makefile (because it is different from the php version on the development machine, the php-config compiled by yourself is used here ):
yangshuofei@IPS-dev3 ~/src/php-5.5.25/ext/rc4 $ ./configure --with-php-config=/home/yangshuofei/php/bin/php-config
After you use phpize to generate the configure execution file, you can use./configure-help to view help information and modify the config. m4 file to modify the help information of configure. Every time you modify the config. m4 file, you need to use the command phpize-clean to clear the temporary file to remove configure.
Generate. so, which will be placed in the modules folder:
yangshuofei@IPS-dev3 ~/src/php-5.5.25/ext/rc4 $ make...----------------------------------------------------------------------Librarieshavebeeninstalledin: /home/yangshuofei/src/php-5.5.25/ext/rc4/modules If youeverhappento wantto linkagainstinstalledlibrariesin a givendirectory, LIBDIR, youmusteitheruse libtool, andspecifythefullpathnameofthelibrary, or use the `-LLIBDIR'flag during linking and do at least one of the following: - add LIBDIR to the `LD_LIBRARY_PATH' environmentvariable duringexecution - addLIBDIRto the `LD_RUN_PATH' environment variable during linking - use the `-Wl,--rpath -Wl,LIBDIR' linkerflag - haveyoursystemadministratoraddLIBDIRto `/etc/ld.so.conf' See any operating system documentation about shared libraries formore information, such as the ld(1) and ld.so(8) manual pages.---------------------------------------------------------------------- Build complete.Don't forgetto run 'make test'.
6. use on the device
According to the configuration in php. ini:
extension_dir = /etc/php/apache2-php5.3/ext
Put the generated rc4.so file in the/etc/php/apache2-php5.3/ext folder of the device,
Add rc4.ini in the/etc/php/apache2-php5.3/ext-active folder as follows:
extension= rc4.so
Restart apache:
Develop>apache2ctlrestart
Next, you can call the rc4_encrypt and rc4_decrypt functions in so in the PHP file for encryption and decryption.
Performance Comparison before and after modification
Response time before expansion: 5m19s
Use the response time before expansion
Response time 2.73 s after expansion
Response time after extension
For more information
Join QQ group: 486207500
Directly ask: 010-68438880-8669