Advanced PHP Programming- P13

50 326 0
Advanced PHP Programming- P13

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

Thông tin tài liệu

578 Chapter 22 Extending PHP: Part II if((fd = open(filename, O_RDWR)) < -1) { return NULL; } if(!file_length) { if(fstat(fd, &sb) == -1) { close(fd); return NULL; } file_length = sb.st_size; } if((mpos = mmap(NULL, file_length, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0)) == (void *) -1) { return NULL; } data = emalloc(sizeof(struct mmap_stream_data)); data->base_pos = mpos; data->current_pos = mpos; data->len = file_length; close(fd); stream = php_stream_alloc(&mmap_ops, data, NULL, “ mode ” ); if(opened_path) { *opened_path = estrdup(filename); } return stream; } Now you only need to register this function with the engine.To do so, you add a regis- tration hook to the MINIT function, as follows: PHP_MINIT_FUNCTION(mmap_session) { php_register_url_stream_wrapper( “ mmap ” , &mmap_wrapper TSRMLS_CC); } Here the first argument, “ mmap ” , instructs the streams subsystem to dispatch to the wrap- per any URLs with the protocol mmap .You also need to register a de-registration func- tion for the wrapper in MSHUTDOWN : PHP_MSHUTDOWN_FUNCTION(mmap_session) { php_unregister_url_stream_wrapper( “ mmap ” TSRMLS_CC); } This section provides only a brief treatment of the streams API. Another of its cool fea- tures is the ability to write stacked stream filters.These stream filters allow you to trans- parently modify data read from or written to a stream. PHP 5 features a number of stock stream filters, including the following: Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark. 579 Further Reading n Content compression n HTTP 1.1 chunked encoding/decoding n Streaming cryptographic ciphers via mcrypt n Whitespace folding The streams API’s ability to allow you to transparently affect all the internal I/O func- tions in PHP is extremely powerful. It is only beginning to be fully explored, but I expect some very ingenious uses of its capabilities over the coming years. Further Reading The official PHP documentation of how to author classes and streams is pretty sparse. As the saying goes,“Use the force, read the source.”That having been said, there are some resources out there. For OOP extension code, the following are some good resources: n The Zend Engine2 Reflection API, in the PHP source tree under Zend/ reflection_api.c , is a good reference for writing classes in C. n The streams API is documented in the online PHP manual at http://www.php.net/manual/en/streams.php . In addition,Wez Furlong, the streams API architect, has an excellent talk on the subject, which is available at http://talks.php.net/index.php/Streams . Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark. Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark. 23 Writing SAPIs and Extending the Zend Engine T HE FLIP SIDE TO WRITING PHP EXTENSIONS in C is writing applications in C that run PHP.There are a number of reasons you might want to do this: n To allow PHP to efficiently operate on a new Web server platform. n To harness the ease of use of a scripting language inside an application. PHP pro- vides powerful templating capabilities that can be validly embedded in many appli- cations. An example of this is the PHP filter SAPI, which provides a PHP interface for writing sendmail mail filters in PHP. n For easy extensibility.You can allow end users to customize parts of an application with code written in PHP. Understanding how PHP embeds into applications is also important because it helps you get the most out of the existing SAPI implementations. Do you like mod_php but feel like it’s missing a feature? Understanding how SAPIs work can help you solve your problems. Do you like PHP but wish the Zend Engine had some additional features? Understanding how to modify its behavior can help you solve your problems. SAPIs SAPIs provide the glue for interfacing PHP into an application.They define the ways in which data is passed between an application and PHP. The following sections provide an in-depth look at a moderately simple SAPI, the PHP CGI SAPI, and the embed SAPI, for embedding PHP into an application with minimal custom needs. Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark. 582 Chapter 23 Writing SAPIs and Extending the Zend Engine The CGI SAPI The CGI SAPI provides a good introduction to how SAPIs are implemented. It is sim- ple, in that it does not have to link against complicated external entities as mod_php does. Despite this relative simplicity, it supports reading in complex environment information, including POST , GET , and cookie data.This import of environmental information is one of the major duties of any SAPI implementation, so it is important to understand it. The defining structure in a SAPI is sapi_module_struct , which defines all the ways that the SAPI can bridge PHP and the environment so that it can set environment and query variables. sapi_module_struct is a collection of details and function pointers that tell the SAPI how to hand data to and from PHP. It is defined as follows: struct _sapi_module_struct { char *name; char *pretty_name; int (*startup)(struct _sapi_module_struct *sapi_module); int (*shutdown)(struct _sapi_module_struct *sapi_module); int (*activate)(TSRMLS_D); int (*deactivate)(TSRMLS_D); int (*ub_write)(const char *str, unsigned int str_length TSRMLS_DC); void (*flush)(void *server_context); struct stat *(*get_stat)(TSRMLS_D); char *(*getenv)(char *name, size_t name_len TSRMLS_DC); void (*sapi_error)(int type, const char *error_msg, .); int (*header_handler)(sapi_header_struct *sapi_header, sapi_headers_struct *sapi_headers TSRMLS_DC); int (*send_headers)(sapi_headers_struct *sapi_headers TSRMLS_DC); void (*send_header)(sapi_header_struct *sapi_header, void *server_context TSRMLS_DC); int (*read_post)(char *buffer, uint count_bytes TSRMLS_DC); char *(*read_cookies)(TSRMLS_D); void (*register_server_variables)(zval *track_vars_array TSRMLS_DC); void (*log_message)(char *message); char *php_ini_path_override; void (*block_interruptions)(void); void (*unblock_interruptions)(void); void (*default_post_reader)(TSRMLS_D); void (*treat_data)(int arg, char *str, zval *destArray TSRMLS_DC); char *executable_location; int php_ini_ignore; int (*get_fd)(int *fd TSRMLS_DC); int (*force_http_10)(TSRMLS_D); int (*get_target_uid)(uid_t * TSRMLS_DC); int (*get_target_gid)(gid_t * TSRMLS_DC); unsigned int (*input_filter)(int arg, char *var, char **val, unsigned int val_len TSRMLS_DC); Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark. 583 SAPIs void (*ini_defaults)(HashTable *configuration_hash); int phpinfo_as_text; }; Here is the module structure for the CGI SAPI: static sapi_module_struct cgi_sapi_module = { “ cgi ” , /* name */ “ CGI ” , /* pretty name */ php_cgi_startup, /* startup */ php_module_shutdown_wrapper, /* shutdown */ NULL, /* activate */ sapi_cgi_deactivate, /* deactivate */ sapi_cgibin_ub_write, /* unbuffered write */ sapi_cgibin_flush, /* flush */ NULL, /* get uid */ sapi_cgibin_getenv, /* getenv */ php_error, /* error handler */ NULL, /* header handler */ sapi_cgi_send_headers, /* send headers handler */ NULL, /* send header handler *= sapi_cgi_read_post, /* read POST data */ sapi_cgi_read_cookies, /* read Cookies */ sapi_cgi_register_variables, /* register server variables */ sapi_cgi_log_message, /* Log message */ STANDARD_SAPI_MODULE_PROPERTIES }; Notice that the last 14 fields of the struct have been replaced with the macro STANDARD_ SAPI_PROPERTIES .This common technique used by SAPI authors takes advantage of the C language semantic of defining omitted struct elements in a declaration as NULL . The first two fields in the struct are the name of the SAPI.These are what is returned when you call phpinfo() or php_sapi_name() from a script. The third field is the function pointer sapi_module_struct.startup .When an application implementing a PHP SAPI is started, this function is called. An important task for this function is to bootstrap the rest of the loading by calling php_module_startup() on its module details. In the CGI module, only the bootstrap- ping procedure is performed, as shown here: static int php_cgi_startup(sapi_module_struct *sapi_module) { if (php_module_startup(sapi_module, NULL, 0) == FAILURE) { return FAILURE; } return SUCCESS; } Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark. 584 Chapter 23 Writing SAPIs and Extending the Zend Engine The fourth element, sapi_module_struct.shutdown , is the corresponding function called when the SAPI is shut down (usually when the application is terminating).The CGI SAPI (like most of the SAPIs that ship with PHP) calls php_module_shutdown_wrapper as its shutdown function.This simply calls php_mod- ule_shutdown , as shown here: int php_module_shutdown_wrapper(sapi_module_struct *sapi_globals) { TSRMLS_FETCH(); php_module_shutdown(TSRMLS_C); return SUCCESS; } As described in Chapter 20, “PHP and Zend Engine Internals,” on every request, the SAPI performs startup and shutdown calls to clean up its running environment and to reset any resources it may require.These are the fifth and sixth sapi_module_struct elements.The CGI SAPI does not define sapi_module_struct.activate , meaning that it registers no generic request-startup code, but it does register sapi_module_struct.deactivate .In deactivate , the CGI SAPI flushes its output file streams to guarantee that the end user gets all the data before the SAPI closes its end of the socket.The following are the deactivation code and the flush helper function: static void sapi_cgibin_flush(void *server_context) { if (fflush(stdout)==EOF) { php_handle_aborted_connection(); } } static int sapi_cgi_deactivate(TSRMLS_D) {cdx sapi_cgibin_flush(SG(server_context)); return SUCCESS; } Note that stdout is explicitly flushed; this is because the CGI SAPI is hard-coded to send output to stdout . A SAPI that implements more complex activate and deactivate functions is the Apache module mod_php . Its activate function registers memory cleanup functions in case Apache terminates the script prematurely (for instance, if the client clicks the Stop button in the browser or the script exceeds Apache’s timeout setting). The seventh element, sapi_module_struct.ub_write , provides a callback for how PHP should write data to the user when output buffering is not on.This is the function that will actually send the data when you use print or echo on something in a PHP script. As mentioned earlier, the CGI SAPI writes directly to stdout . Here is its imple- mentation, which writes data in 16KB chunks: Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark. 585 SAPIs static inline size_t sapi_cgibin_single_write(const char *str, uint str_length TSRMLS_DC) { size_t ret; ret = fwrite(str, 1, MIN(str_length, 16384), stdout); return ret; } static int sapi_cgibin_ub_write(const char *str, uint str_length TSRMLS_DC) { const char *ptr = str; uint remaining = str_length; size_t ret; while (remaining > 0) { ret = sapi_cgibin_single_write(ptr, remaining TSRMLS_CC); if (!ret) { php_handle_aborted_connection(); return str_length - remaining; } ptr += ret; remaining -= ret; } return str_length; } This method writes each individual character separately, which is inefficient but very cross-platform portable. On systems that support POSIX input/output, you could as eas- ily consolidate this function into the following: static int sapi_cgibin_ub_write(const char *str, uint str_length TSRMLS_DC) { size_t ret; ret = write(fileno(stdout), str, str_length); return (ret >= 0)?ret:0; } The eighth element is sapi_module_struct.flush , which gives PHP a way to flush its stream buffers (for example, when you call flush() within a PHP script).This uses the function sapi_cgibin_flush , which you saw called earlier from within the deactivate function. The ninth element is sapi_module_struct.get_stat .This provides a callback to override the default stat() of the file performed to ensure that the script can be run in safe mode.The CGI SAPI does not implement this hook. The tenth element is sapi_module_struct.getenv . getenv provides an interface to look up environment variables by name. Because the CGI SAPI runs akin to a regular Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark. 586 Chapter 23 Writing SAPIs and Extending the Zend Engine user shell script, its sapi_cgibin_getenv() function is just a simple gateway to the C function getenv() , as shown here: static char *sapi_cgibin_getenv(char *name, size_t name_len TSRMLS_DC) { return getenv(name); } In more complex applications, such as mod_php , the SAPI should implement sapi_ module_struct.getenv on top of the application’s internal environment facilities. The eleventh element is the callback sapi_module_struct.sapi_error .This sets the function to be called whenever a userspace error or an internal call to zend_error() occurs. Most SAPIs set this to php_error , which is the built-in PHP error handler. The twelfth element is sapi_module_struct.header_handler .This function is called anytime you call header() inside code or when PHP sets its own internal head- ers.The CGI SAPI does not set its own header_handler , which means that it falls back on the default SAPI behavior, which is to append it to an internal list that PHP man- ages.This callback is mainly used in Web server SAPIs such as mod_php , where the Web server wants to maintain the headers itself instead of having PHP do so. The thirteenth element is sapi_module_struct.send_headers .This is called when it is time to send all the headers that have been set in PHP (that is, immediately before the first content is sent).This callback can choose to send all the headers itself, in which case it returns SAPI_HEADER_SENT_SUCCESSFULLY , or it can delegate the task of sending indi- vidual headers to the fourteenth sapi_module_struct element, send_header , in which case it should return SAPI_HEADER_DO_SEND .The CGI SAPI chooses the first methodol- ogy and writes all its headers in a send_headers function, defined as follows: 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); Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark. 587 SAPIs 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; } PHPWRITE_H is a macro wrapper that handles output buffering, which might potentially be on. The fifteenth element is sapi_module_struct.read_post , which specifies how POST data should be read.The function is passed a buffer and a buffer size, and it is expected to fill out the buffer and return the length of the data within. Here is the CGI SAPI’s implementation, which simply reads up to the specified buffer size of data from stdin (file descriptor 0): static int sapi_cgi_read_post(char *buffer, uint count_bytes TSRMLS_DC) { uint read_bytes=0, tmp_read_bytes; count_bytes = MIN(count_bytes, (uint)SG(request_info).content_length-SG(read_post_bytes)); while (read_bytes < count_bytes) { tmp_read_bytes = read(0, buffer+read_bytes, count_bytes-read_bytes); if (tmp_read_bytes<=0) { break; } read_bytes += tmp_read_bytes; } return read_bytes; } Note that no parsing is done here: read_post only provides the facility to read in raw post data. If you want to modify the way PHP parses POST data, you can do so in sapi_module_struct.default_post_reader , which is covered later in this chapter, in the section “SAPI Input Filters.” The sixteenth element is sapi_module_struct.read_cookies .This performs the same function as read_post , except on cookie data. In the CGI specification, cookie data is passed in as an environment variable, so the CGI SAPI cookie reader just uses the Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark. [...]... else { $counter ; } ?> you get the following output: /Users/george /Advanced_ PHP/ examples/chapter-23/call_coverage/test .php: 2 /Users/george /Advanced_ PHP/ examples/chapter-23/call_coverage/test .php: 3 /Users/george /Advanced_ PHP/ examples/chapter-23/call_coverage/test .php: 4 /Users/george /Advanced_ PHP/ examples/chapter-23/call_coverage/test .php: 10 Homework While the other chapters in this book have “Further... main(int argc, char **argv) { char *code; PHP_ EMBED_START_BLOCK(argc,argv); while((code = readline(“> “)) != NULL) { zend_eval_string(code, NULL, argv[0] TSRMLS_CC); } PHP_ EMBED_END_BLOCK(); return 0; } You then compile this, as shown here: > gcc -pipe -g -O2 -I/usr/local/include /php -I/usr/local/include /php/ Zend \ -I/usr/local/include /php/ TSRM -I/usr/local/include /php/ main -c psh.c > gcc -pipe -g -O2 -L/usr/local/lib... { php_ info_print_table_start(); php_ info_print_table_row( 2, “strip_tags() Filter Support”, “enabled” ); php_ info_print_table_end(); 595 596 Chapter 23 Writing SAPIs and Extending the Zend Engine } zend_module_entry raw_filter_module_entry = { STANDARD_MODULE_HEADER, “raw_filter”, NULL, PHP_ MINIT(raw_filter), PHP_ MSHUTDOWN(raw_filter), NULL, PHP_ RSHUTDOWN(raw_filter), PHP_ MINFO(raw_filter), “0.1”, STANDARD_MODULE_PROPERTIES... you.The embed SAPI exposes PHP as a shared library that you can link against and run code To build the embed library, you need to compile PHP with the following configuration line: enable-embed This creates libphp5.so The embed SAPI exposes two macros to the user: PHP_ EMBED_START_BLOCK(int argc, char **argv) PHP_ EMBED_END_BLOCK() Inside the block defined by those macros is a running PHP environment where... 199 updating files, 191-193 packaging, 199 Apache, 204-205 binaries, 203-204 pack(), 200-201 PHP, 205-206 pushing code, 201-203 application programming interfaces See APIs application servers, database scaling, 390-391 applications APD (Advanced PHP Debugger) profiler, 435-440 PHP lifecycle PHP core, 493, 496 PHP extension API, 493, 497-498 SAPI (Server Abstraction API layer), 492-496 Zend extension... (php_ request_startup(TSRMLS_C)==FAILURE) { php_ module_shutdown(TSRMLS_C); return FAILURE; } retval = php_ fopen_primary_script(&file_handle TSRMLS_CC); if (retval == FAILURE && file_handle.handle.fp == NULL) { SG(sapi_headers).http_response_code = 404; PUTS(“No input file specified.\n”); php_ request_shutdown((void *) 0); php_ module_shutdown(TSRMLS_C); return FAILURE; } php_ execute_script(&file_handle TSRMLS_CC);... *track_vars_array TSRMLS_DC) { php_ import_environment_variables(track_vars_array TSRMLS_CC); php_ register_variable( PHP_ SELF”, (SG(request_info).request_uri ? SG(request_info).request_uri:””), track_vars_array TSRMLS_CC); } This calls php_ import_environment_variables(), which loops through all the shell environment variables and creates entries for them in $_SERVER.Then it sets $_SERVER[ PHP_ SELF’] to be the... callback for the SAPI 6 Open and execute the script with php_ fopen_primary_script(&file_handle TSRMLS_CC) and php_ execute_script(&file_handle TSRMLS_CC).Technically, it is not necessary to open the script, but doing so allows an easy way to check whether the script actually exists.When php_ execute_script() returns, the script has completed 7 Call php_ request_shutdown((void *) 0) to complete the request.This... args); PHP_ MINIT_FUNCTION(warn_as_except) { EEG(old_error_cb) = zend_error_cb; zend_error_cb = exception_error_cb; return SUCCESS; } PHP_ MSHUTDOWN_FUNCTION(warn_as_except) { return SUCCESS; } PHP_ MINFO_FUNCTION(warn_as_except) { } function_entry no_functions[] = { {NULL, NULL, NULL} }; zend_module_entry warn_as_except_module_entry = { STANDARD_MODULE_HEADER, “warn_as_except”, no_functions, PHP_ MINIT(warn_as_except),... the new autoglobal arrays you are creating Here is the code for this: #ifdef HAVE_CONFIG_H # include “config.h” #endif #include #include #include #include #include php. h” php_ globals.h” php_ variables.h” “ext/standard/info.h” “ext/standard /php_ string.h” ZEND_BEGIN_MODULE_GLOBALS(raw_filter) zval *post_array; zval *get_array; zval *cookie_array; ZEND_END_MODULE_GLOBALS(raw_filter) #ifdef ZTS #define . that ship with PHP) calls php_ module_shutdown_wrapper as its shutdown function.This simply calls php_ mod- ule_shutdown , as shown here: int php_ module_shutdown_wrapper(sapi_module_struct. -pipe -g -O2 -I/usr/local/include /php -I/usr/local/include /php/ Zend -I/usr/local/include /php/ TSRM -I/usr/local/include /php/ main -c psh.c > gcc -pipe

Ngày đăng: 20/10/2013, 11:15

Từ khóa liên quan

Tài liệu cùng người dùng

Tài liệu liên quan