Write php extensions in c on windows (encrypt and decrypt php source code)

Source: Internet
Author: User
First try it with hello world.
Download the PHP source package.The ext directory is the extension directory.There are 2 important files in it: ext_skel and ext_skel_win32.php.

Download cygwin. With this you can easily create php extensions under windows.

downloading. . .
After downloading, use php ext_skel_win32.php --extname = hello to compile and generate our extension development directory hello
Then start writing the test program hello world
Add the function definition and function registration statement in the hello.c file:
Function registration statement: const zend_function_entry hello_functions [] = {
 PHP_FE (confirm_hello_compiled, NULL)
    PHP_FE (sayHello, NULL) // This sentence was manually added by us
Function definition: PHP_FUNCTION (sayHello) {
 php_printf ("Hello C extension");
It seems to say that it must be in the form of a macro that appears in PHP_FUNCTION, because if you write the c code directly, there may be naming conflicts or other conflicts.
Then add a function declaration in php_hello.h: PHP_FUNCTION (sayHello);
Write the test program, and the compilation results appear ../ main / config.w32.h ': No such file or directory
Checked it online, it seemed to be downloading additional packages. . . Trouble
Putting these two packages together, I put them in the win32 / build directory
Then execute buildconf.bat in the root directory of the php source package (preferably run on the command line, otherwise the results will be flashed)
Then set the directory where bison.exe (in the newly downloaded package) is set to the environment variable, and then run configure.bat. After that, the file /main/config.w32.h is generated.
Then compile again just now hello project results in a big push error.
Form: .. \ .. \ main \ streams / php_stream_transport.h (85): error C2143: syntax error: missing ')' before '*'
.. \ .. \ main \ streams / php_stream_transport.h (85): error C2081: 'socklen_t': name in formal parameter list illegal
The Internet says that this is the case because no macro definition can be found. It should be that the socks_t macro is not defined, but what is the specific macro definition? You ca n’t just write one. So open \ main \ streams / php_stream_transport.h and find that it should be a type alias and an int, because there is sockslen_t addrlen; addrlen should be the value of the storage length literally.
So add typedef int socklen_t in this file; save
In compiling the project just now, there are a lot of errors, but there are still seven. After inspection, it was found that Chinese symbols were entered. Correct and recompile. . . One more error:
LINK: fatal error LNK1181: cannot open input file "php5ts.lib"
So it will look for the file php5ts.lib and put it in the project directory or the default search directory of the VC6 lib file. Look for it. Look for it. . .
tmd, searched for windows for a long time but couldn't find it. Baidu is in the php binary code package. So first download the same version of the binary code package (should be the package you must download to write PHP usually)
Let's talk about the environment first windows + vc6 + php5.3.5 (binary code package and source package) + cygwin
After downloading, find, copy, compile, success!
But there was a very serious problem, the dll file did not come out, and I cried
Created are php_hello.exp and php_hello.lib. How could it be static? ?
In fact, it has been generated, but not in the Release_TS directory under this directory, but in the Release_TS directory above the ext.
Then test. Haha, it is an undefined function. Is it possible that the tested php version is different from the php version I extended?
The test is not the case, as long as the php_hello.dll is loaded in the ini setting to restart apache, a memory unreadable error occurs.
I always feel that there is no problem with the code, it should still be a problem when compiling the previous configuration.
After repeated tests, I found that the php binary package was wrong. I downloaded vc9 and should download vc6.


The next step is to start writing encryption and decryption. The encryption and decryption algorithm itself is not the focus here. The focus is how to use zend's own interface in combination with c to program at the zend layer, and decrypt the file before zend compiles the source file (of course, the file must be encrypted before). For convenience. My idea is to generate an encrypted executable file while generating the dll like php_screw. This encrypted executable file is manually executed by us. Passing in the directory parameters can encrypt all the files in the directory.
After looking up a lot of information on the Internet, look at the code of php_screw, there is still a bit laborious, so I decided to write according to my own ideas. Of course, some places will borrow the code of php_screw
The first is to write a function that decrypts the file. This function uses our ready-made decryption algorithm to decrypt the file contents.
This function should have a parameter to receive the handle of the currently requested file (seemingly zend_compile_file, Baidu, confirm it, several articles say that it is a function pointer, I looked at the source code is indeed a function pointer) extern ZEND_API zend_op_array * (* zend_compile_file) (zend_file_handle * file_handle, int type TSRMLS_DC);
So how to get the file pointer of the currently requested file? Perhaps it has something to do with the function pointed to by the zend_compile_file function pointer. Found in the source code zend_compile_file = compile_file; the function is defined in zend_language_scanner.c, but it is a bit difficult to understand the function, the online saying is:
zend_compile_file is responsible for compiling the script file to be executed into op codes composed of the basic instruction sequence of ZE.
PHP executes this code through four steps:
1. Scanning (Lexing), convert PHP code to language tokens
2. Parsing, transform tokens into simple and meaningful expressions
3. Compilation, compile the expression into Opocdes
4. Execution, sequentially execute Opcodes, one at a time, so as to achieve the function of PHP scripts.
So we should decrypt the file before these four steps.
The idea is to override a function a to determine that the file is decrypted before it is compile, and then call the default complie function. After defining function a, function a should be passed to the function pointer zend_compile_file when the request is initialized
 old_comlie_file = zend_complie_file; // Leave the default compile so that it can be called later
 zend_complie_file = function a;
 return SUCCESS;
ZEND_API zend_op_array * a (zend_file_handle * file_handle, int type TSRMLS_DC) Relational
 Decrypt the code. . .
 old_comlie_file (file_handle);
But the problem is still not solved, because we still don't know how to get the file pointer. I think the decryption steps in php_screw are quite long, please refer to it. . . Found fp = fopen (file_handle-> filename, "r"); the original file_handle contains the file name information (in fact, if you find the structure definition statement of file_handle, you will know).
But there is still this paragraph in php_screw
char fname [32];

 memset (fname, 0, sizeof fname);
 if (zend_is_executing (TSRMLS_C)) {// TSRMLS_C get global variables
  if (get_active_function_name (TSRMLS_C)) {// Get the name of the currently called function (currently called function? Where is the function? PHP function? Think of it as a function in zend. It is not a function in the PHP layer, because it has not been compiled yet, Not implemented yet)
   strncpy (fname, get_active_function_name (TSRMLS_C), sizeof fname-2);
 if (fname [0]) {
  if (strcasecmp (fname, "show_source") == 0 // If the current two functions are not decrypted or compiled. Well, it looks correct.
    || strcasecmp (fname, "highlight_file") == 0) {
   return NULL;
 } So this paragraph is still necessary, otherwise the above two functions will not be implemented, and there should be this step in the compile_file function. So the main thing here is not to let it be decrypted, but to display the ciphertext directly.
There is such a paragraph
 fp = fopen (file_handle-> filename, "r");
 if (! fp) {// If the opening fails, directly call the default compile function
  return org_compile_file (file_handle, type);

 fread (buf, PM9SCREW_LEN, 1, fp); // The effect of the following 5 sentences is: if the file is not encrypted when found, it will not be decrypted.
 if (memcmp (buf, PM9SCREW, PM9SCREW_LEN)! = 0) {
  fclose (fp);
  return org_compile_file (file_handle, type);

if (file_handle-> type == ZEND_HANDLE_FP) fclose (file_handle-> handle.fp); // Determine the file handle type and apply the corresponding close function.
 if (file_handle-> type == ZEND_HANDLE_FD) close (file_handle-> handle.fd);
 file_handle-> handle.fp = pm9screw_ext_fopen (fp); // Call the function that decrypts the file, and use the fp receive function in file_handle to return the result
 file_handle-> type = ZEND_HANDLE_FP; // Set the handle type to the file pointer type
 file_handle-> opened_path = expand_filepath (file_handle-> filename, NULL TSRMLS_CC); // I do n’t understand a bit here, I guess is it acceptable to accept the current file path? Along the way, I found the function expand_filepath_ex. The last sentence of this function is return real_path; it looks like it should return the path of the current file to be compiled. But why are there the two steps above? There are two parts, setting type and path. If we do n’t do the decryption, we do n’t need these two steps. My guess is that fclose (file_handle-> handle.fp) changed the state of file_handle here, so we need to reset it!
// (But there is a question whether this is decrypted before Compilation or Scanni
Decrypt before ng? I initially think that it is semantically decrypted before Compilation, but from a practical point of view, it should be decrypted before Scanning. This can be verified later. It turns out that the latter is correct, because the compile_file function has the open_file_for_scanning function. Call, that is to say, in the compile_file function, the aforementioned step 123 is performed)
The entry point is there (three-quarters of the problem needs to be resolved).
Let's start writing functions to decrypt files
The issues that need to be considered are: the plaintext code after decrypting the file does not need to be written to the file, so how to get the file pointer of these plaintext? Do it with temporary files? But if each request uses a different temporary file, it will generate a lot of temporary files (obviously not feasible). If different requests for the same php file only use a temporary file, the problem of resource waiting will also occur (obviously not feasible) ). Can you specify a file pointer directly in memory? First look at the method of php_screw, call tmpfile () to generate a temporary file, but it will be automatically deleted when the program exits! In fact, I think the files in memory are also implemented this way.
Go straight down and implement the reversible encryption and decryption algorithm written in php with c, but c has not become the md5 and base64 functions. It seems that these two can only be discarded.
After writing, it started compiling, and some errors were also corrected.
Then I got an error when linking: error LNK2001: unresolved external symbol _zend_compile_file
After a search, it seems that the function cannot be found because the function compilation method is different.
ZEND_API zend_op_array * (* zend_compile_file) (zend_file_handle * file_handle, int type TSRMLS_DC);
The dll file was generated successfully, but I don't know how to generate the executable file for encryption. Of course, the simplest solution is to build another project. It seems that I have to do this first, because some of the compilation mechanism and parameter settings of VC are not very familiar (I will study this in the self-cultivation of programmers later)
Later, I encountered the problem of pointer transfer in c (I haven't done it for a long time, some basic ones have been forgotten, and the second-level pointer was used to solve the problem of pointer return as a parameter)
I encountered the problem that the _zend_compile_file symbol could not be found when linking (related to zend_api macro dllimport \ dllexport)
Then I encountered the problem of reading and writing the file. Actually, I just copied the cipher text of the file into another file and tested it. The result will be wrong. If you copy the file directly or directly manipulate the original file, then correct.
Finally, I encountered an error that the memory could not be read. . .
Finally, it was found that the problem was due to the way the file was read, and it could be read in binary. If you read and write in text, some special characters would be processed.
... Finally, the test function is okay, but if you really want to apply it, you need to improve it. For example, when I encrypt, I directly generate the encrypted file in the original directory. A better way is to copy the original php file. Pack it up for easy management.
Then I started working on the zf framework, and I almost forgot about it, and there were still many things that were not used at the beginning.



Original address:






Related references:

Writing PHP C extensions under Windows:



Extending your PHP with C / C ++:




Do-it-yourself extension PHP with C (1)



Do-it-yourself extension PHP with C (2)-functions



Do-it-yourself extension PHP with C (3)-Important ZEND API functions




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.