Write PHP extensions in C under Windows (GO)
C Write php extension under Windows (Encrypt and decrypt PHP source code)
First hackers with Hello World.
Download PHP source Package, ext directory is the extension directory, there are 2 important files are Ext_skel and ext_skel_win32.php.
Download Cygwin, with this can easily create a php extension under Windows.
Download ...
After downloading, use PHP ext_skel_win32.php--extname=hello to compile and build our extension development directory Hello, and then start writing the test program Hello World. Add function definitions and function registration statements 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 is our manually added {null, NULL, NULL}};
?
function definition:
Php_function (SayHello) {php_printf ("Hello C Extension");}
?
The
appears to be a macro form that must appear as php_function, because naming conflicts or other conflicts can occur if you write the C code directly. Then add the function declaration statement inside the php_hello.h:
Php_function (SayHello);
Write the test program and the result of the compilation appears:
.. /main/config.w32.h ': No such file or directory
looked it up on the Internet as if to download additional packages ... Oh, trouble!
Http://www.php.net/extra/bindlib_w32.zip
Http://www.php.net/extra/win32build.zip
Put the two packages together, I put them in the Win32/build directory, and then execute the PHP source package root directory under the Buildconf.bat (preferably run at the command line, otherwise the results will be flashed).
Then set the directory for Bison.exe (inside the package that you just downloaded) to an environment variable, and then run Configure.bat. This file is generated after the/main/config.w32.h is finished.
and then compile it again. The result of the Hello project is a big push error.
Shape:
. \.. \main\streams/php_stream_transport.h: Error c2143:syntax error:missing ') ' before ' * '
. \.. \main\streams/php_stream_transport.h: Error C2081: ' socklen_t ': name in formal parameter list illegal
said online is because the macro definition can not find this, it should be socklen_t this macro is not defined, but its specific macro definition should be what kind of, always can not write a bar, so open
\main\streams/php_stream_ Transport.h
Discovery should be a type alias, and an int, because there is socklen_t Addrlen; Addrlen is literally the value of the stored length.
so add
typedef int socklen_t to this file;
and save, and then compile the project just now, the error is a lot less, but there are 7, after the inspection found that the Chinese symbol was entered. Correct re-compiling ... There is also an error:
Link:fatal error Lnk1181:cannot Open input file "Php5ts.lib"
will then look for php5ts.lib this file and put it in the project directory or VC6 LIB file is also available under the default search directory. Find, find, find ...
TMD, with Windows Search for a long time have not found. Baidu is said to be inside the PHP binary code package. So first the next version of the binary code package (it should be usually written PHP must download the package bar)
Here first say environment Bar windows+vc6+php5.3.5 (binary code package and source package) +cygwin
Download complete, find, copy, compile, success!
But there is a very serious problem, DLL file did not come out,,, I cry! The Php_hello.exp and Php_hello.lib are created. How can it be static?? The
has actually been generated, but not in the directory under the Release_ts directory, but in the Ext Superior release_ts directory.
and then test. Haha, say is undefined function, is it possible to test the PHP version and my extension of the PHP version of the relationship? The
test is not a bit, as long as the INI in a set load Php_hello.dll reboot Apache will appear memory unreadable error.
always feel that the code is not a problem, it should be the previous configuration of the compilation when there is a problem.
After a few tests, found that the PHP binary package under the wrong I under the vc9 should be under the 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 Zend layer with the interface of the Zend itself and C to program, before Zend compile the source file to decrypt the file (of course, before the file is encrypted).
For ease of use. My idea is to build a DLL like Php_screw and generate an encrypted executable file that is executed manually by us, passing in the directory parameters and being able to encrypt all the files in that directory.
After looking for a bunch of information on the Internet, and then look at Php_screw code, there are some difficulties, so decided to write according to their own ideas. Of course, some places will draw on Php_screw code
The first is to write a function to decrypt the file. This function decrypts the contents of the file using our existing decryption algorithm.
This function should have a parameter to receive the current request file handle (seems to be zend_compile_file this thing, Baidu, confirm, a few articles said is a function pointer, I see the next source code is really a function pointer)
extern zend_api Zend_op_array * (*zend_compile_file) (zend_file_handle *file_handle, int type TSRMLS_DC);
?
So how do you get the file pointer for the current request file? It may be related to the function that the Zend_compile_file function pointer refers to. Found in the source code:
Zend_compile_file = Compile_file;
The definition of the function is zend_language_scanner.c, but to understand the function is a bit difficult, the online statement is:
-------------
The zend_compile_file is responsible for compiling the script file to be executed into the OP codes consisting of the ze basic instruction sequence.
PHP executes this code in the following 4 steps:
1. Scanning (lexing), convert the PHP code to a language fragment (Tokens)
2. Parsing, convert tokens to simple and meaningful expressions
3. Compilation, compile the expression into Opocdes
4. Execution, execute opcodes sequentially, one at a time, thus realizing the function of PHP script.
-------------
So we should be able to decrypt the file before this four step.
The idea is to rewrite a function mycompile to decrypt the file before it is compile, and then call the default Complie function. Once the mycompile is defined, the mycompile should be passed to the function pointer when the request is initialized Zend_compile_file
Php_minit_function (dencrypt) {old_comlie_file = zend_complie_file;//leave the default compile to wait for the call Zend_complie_file = Mycompile; return SUCCESS;} Zend_api Zend_op_array *mycompile (zend_file_handle *file_handle,int type TSRMLS_DC) { //TSRMLS_DC Here is a macro similar to,... (macro definition is temporarily not found) in short, with the multi-threaded environment of global variables of the thread safety, and then dig deep //Here is the decryption code ... Old_comlie_file (file_handle); ....}
?
But the problem is still not solved, because we still do not know how to get to the file pointer. I see the php_screw inside the decryption procedure is very long, the reference ... Got it:
fp = fopen (File_handle->filename, "R");
The original file_handle has the file name information (in fact, if found File_handle structure definition statement will know). But there's a php_screw inside:
Char Fname[32];memset (fname, 0, sizeof fname); if (zend_is_executing (Tsrmls_c)) { //tsrmls_c get global variable // Gets the name of the current calling function (the current calling function?). Where's the function? PHP functions? Think of course the function inside the Zend. Instead of the PHP layer function, because it's not compiled yet, and not executed yet) if (Get_active_function_name (Tsrmls_c)) { strncpy (fname, Get_active_function_ Name (Tsrmls_c), sizeof fname-2);} } if (Fname[0]) { if (strcasecmp (fname, "show_source") = = 0 //That is, if both functions are present, they are not compiled. Well, it looks right. | | | strcasecmp (fname, "highlight_file") = = 0) { return NULL; }}
?
So this paragraph is still necessary, or meet the above two functions can not be achieved, compile_file function inside should also have this step to. So the main point here is not to let it be decrypted, but to display the ciphertext directly.
And there's this:
fp = fopen (File_handle->filename, "R"); if (!FP) {//If open fails, call the default compile function directly return Org_compile_file (file_handle , type);} Fread (BUF, Pm9screw_len, 1, FP); The function of the 5 sentence is: If the found unencrypted file is not 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 return the result File_handle->type = ZEND_HANDLE_FP with the FP receive function inside the File_handle; Set the handle type to the file pointer type File_handle->opened_path = Expand_filepath (File_handle->filename, NULL tsrmls_cc);
?
The above sentence is a bit confused, guess whether to accept the path of the current file? Traced all the way to expand_filepath_ex. The last sentence of this function is return real_path; it should look like the path to the file you are compiling now. But why should there be two steps above? is to set the type and path of the two. If we do not do the decryption operation without these two steps, my guess is because fclose (FILE_HANDLE->HANDLE.FP) here changed the state of File_handle, so only need to reset it! (But one question is, is this to be decrypted before compilation, or before scanning?) I initially think that semantically is compilation before the decryption, but from the actual situation should be decrypted before scanning, this side can be verified later, it turns out that the latter is right, because Compile_file function has a pair of open_file_for_ The invocation of the scanning function, which means that the previous 123 steps are performed in the Compile_file function).
The entry point is there (there are 4 3 problems to be solved).
?
The next step is to write the function that decrypts the file.
The problem to consider is that the plaintext code after decrypting the file does not need to be written to the file, so how do you get these plaintext file pointers? Use temporary files to do it? However, if each request uses a different temporary file that generates a lot of temporary files (which is obviously not possible), there will be a resource waiting issue (obviously not possible) if you use only one temporary file for different requests to the same PHP file. Can you specify a file pointer directly in memory? Take a look at Php_screw's practice, call tmpfile () to produce temporary files, but will be automatically deleted when the program exits! In fact, I think the files in memory are also implemented in this way.
Directly down to the previous use of PHP to write the reversible encryption and decryption algorithm with C to achieve, but C has no ready-made MD5 and Base64 functions, it seems only to abandon the 2.
After writing it began to compile, encountered a number of errors are also changed over.
Then the link came up with an error:
Error lnk2001:unresolved external symbol _zend_compile_file
Search, it seems that the function is not compiled in the same way caused by the function can not find, join:
Begin_extern_c () Zend_api Zend_op_array * (*zend_compile_file) (zend_file_handle *file_handle, int type TSRMLS_DC); End_extern_c ()
?
Can.
Building the DLL file succeeds, but does not know how to generate an executable file for encryption, the simplest solution is to build another project. It seems to have to do this, because some of the VC compiler mechanism and parameter settings are not very familiar with (later to study the programmer's self-cultivation seems to have said this).
Then encountered the C pointer transfer problem (long time did not get, some of the basic forget, finally with a two-level pointer to solve the problem of the pointer as a parameter callback).
There was a problem with the _zend_compile_file symbol when I encountered the link (related to ZEND_API macro dllimport\dllexport)
And then encountered the problem of reading and writing files, in fact, it is true that I write the ciphertext to the file manually copied to another file to test, the results will be wrong, if you copy the file directly, or directly manipulate the original file is correct.
Finally encountered a memory unreadable error ...
Finally, the discovery is due to the problem of file read mode, binary reading is possible, if read and write in text, some special characters will be processed.
... The final Test function is yes, but if you really want to apply it to improve, such as when I encrypt the original directory directly generated encrypted files, better practice should be to the original PHP files packaged, easy to manage.
The next step was to get the ZF framework, and it was almost forgotten, and there was still a lot of stuff that didn't work.
?
?
===============================
Original address:
Http://blog.sina.com.cn/s/blog_4d06da1f0100pgmj.html