Talk about your understanding of Zend Sapis (Zend SAPI internals) _php Example

Source: Internet
Author: User
Tags error handling sapi zend

Sapi:server abstraction API, students who have studied PHP architecture should know the importance of this dongdong, which provides an interface that allows PHP to interact with other applications. This article does not describe each PHP SAPI in detail, but only for the simplest CGI SAPI to illustrate the SAPI mechanism.

First, let's look at the architecture diagram of PHP:

Figure 1 PHP Architecture

SAPI provides an interface to communicate with the outside, for PHP5.2, the default provides many kinds of sapi, common to the Apache mod_php5,cgi, to the IIS ISAPI, as well as the shell of the CLI, this article from the CGI SAPI to introduce the SAPI mechanism. Although CGI is simple, but don't worry, it contains most of the content enough to give you a deep understanding of how SAPI works.

To define a SAPI, first define a sapi_module_struct and view the PHP-SRC/SAPI/CGI/CGI_MAIN.C:

 */static sapi_module_struct Cgi_sapi_module = {#if php_fastcgi "cgi-fcgi",/* NA Me/* "cgi/fastcgi",/* Pretty name * * * * #else "CGI",/* Name/"CGI",/* Pretty name */#endif Php_c Gi_startup,/* Startup/Php_module_shutdown_wrapper,/* Shutdown/NULL, * activate * * Sapi_cgi_deactiva TE,/* 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 Variab Les/sapi_cgi_log_message,/* Log message */NULL,/* GET request time */standard_sapi_module_properties} 
;

This structure contains a number of constants, such as name, which will be used when we call Php_info (). Some initialization, closure functions, and some function pointers, used to tell Zend how to get, and output data.

1. Php_cgi_startup, when an application calls PHP, this function is invoked, and for CGI it simply invokes the PHP initialization function:

 static int Php_cgi_startup (sapi_module_struct *sapi_module)
{
 if (Php_module_startup (sapi_module, NULL, 0) = = Failure) {return
  failure;
 }
 return SUCCESS;
}

2. Php_module_shutdown_wrapper, a simple wrapper for the PHP shutdown function. Simply call the Php_module_shutdown;

3. PHP handles some initialization, resource-allocation transactions at each request. This part is the Activate field to define, from the above structure we can see, for CGI, it does not provide initialization processing handle. For mod_php, that's different, he's going to register the resource destructor in the Apache pool, request space, initialize environment variables, and so on.

4. Sapi_cgi_deactivate, this is the corresponding to the Activate function, as the name suggests, it will provide a handler, to deal with the finishing work, for CGI, he is simply refreshing the buffer, To ensure that the user gets all the output data before the Zend is closed:

 The static int sapi_cgi_deactivate (Tsrmls_d)
{/* flush only when SAPI is
 started. The reasons are:
  1. SAPI Deactivate is called from two places:module init and request shutdown
  2. When the the, the the "occurs" and "the" request is not set up, flush fails on
   FastCGI.
 */
 if (SG (sapi_started)) {
  Sapi_cgibin_flush (SG (server_context));
 }
 return SUCCESS;
}

5. Sapi_cgibin_ub_write, this hanlder tells Zend how to output data, for mod_php, this function provides an interface to response data, and for CGI, it simply writes to STDOUT:

 static inline size_t sapi_cgibin_single_write (const char *STR, UINT str_length-TSRMLS_DC) {#ifd
EF Php_write_stdout long ret;
#else size_t ret;
  #endif #if php_fastcgi if (fcgi_is_fastcgi ()) {Fcgi_request *request = (fcgi_request*) SG (Server_context);
  LONG ret = fcgi_write (request, Fcgi_stdout, str, str_length);
  if (ret <= 0) {return 0;
 return ret;
 #endif #ifdef php_write_stdout ret = WRITE (Stdout_fileno, str, str_length);
 if (Ret <= 0) return 0;
return ret;
 #else ret = fwrite (str, 1, MIN (Str_length, 16384), stdout);
return ret;
 #endif} 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; }

The real writing logic is stripped out, in order to achieve a simple and compatible fastcgi writing method.

6. Sapi_cgibin_flush, this is a function handle provided to the Zend flush cache, and for CGI, it is simply the fflush provided by the invocation system;

7.NULL, which is used to allow Zend to validate a state to execute a script file, to determine whether the file has execute permissions, and so on, which is not provided by CGI.

8. SAPI_CGIBIN_GETENV provides an interface for Zend to find environment variables based on name, and for MOD_PHP5, this handle is invoked indirectly when we call getenv in a script. And for CGI, because his operating mechanism is similar to the CLI, the direct invocation of the parent is the shell, so it simply invokes the system-supplied genenv:

Static Char *sapi_cgibin_getenv (char *name, size_t name_len tsrmls_dc)
{
#if php_fastcgi/* When the
 PHP is start Ed by mod_fastcgi, no regular environment are
  provided to PHP. It is always sent to PHP at the start of
  a request. So we have to does our own lookup to get Env
  VARs. This could probably is faster somehow. */
 if (fcgi_is_fastcgi ()) {
  Fcgi_request *request = (fcgi_request*) SG (server_context);
  return fcgi_getenv (Request, name, Name_len);
 }
#endif
 /* If CGI, or fastcgi and not found in fcgi env
  Check the regular environment
 /return getenv (name) ;
}

9. Php_error, error handling function, to here, say a few digression, last seen PHP maillist mentioned makes the error-handling mechanism of PHP completely oo, that is, rewrite the function handle, so that whenever there is an error occurs, all throw an exception. CGI simply invokes the error-handling function provided by PHP.

10. This function is invoked when we invoke the header () function of PHP, which is not provided for CGI.

Sapi_cgi_send_headers, this function will be invoked when the header is actually sent, in general, when any output is to be sent:

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;
 if (SG (request_info). No_headers = = 1) {return sapi_header_sent_successfully; } if (Cgi_nph | |
  SG (sapi_headers). Http_response_code!=) {int len;
       if (rfc2616_headers && SG (sapi_headers). http_status_line) {len = snprintf (buf, Sapi_cgi_max_header_length,
   "%s\r\n", SG (sapi_headers). Http_status_line);
   if (Len > sapi_cgi_max_header_length) {len = sapi_cgi_max_header_length;
  } else {len = sprintf (buf, Status:%d\r\n), SG (sapi_headers). Http_response_code);
 } phpwrite_h (buf, Len);
 } h = (sapi_header_struct*) zend_llist_get_first_ex (&sapi_headers->headers, &pos);
   while (h) {/* Prevent CRLFCRLF/if (H->header_len) {phpwrite_h (H->header, H->header_len);
  Phpwrite_h ("\ r \ n", 2); } h = (sapi_header_struct*) zend_llist_get_next_ex (&sApi_headers->headers, &pos);
 } phpwrite_h ("\ r \ n", 2);
 return sapi_header_sent_successfully; }

NULL, this is used to send each header separately, CGI does not provide

Sapi_cgi_read_post, this handle indicates how to get the post data, and if you do CGI programming, we know that the CGI reads post data from stdin,

static int Sapi_cgi_read_post (char *buffer, uint count_bytes tsrmls_dc)
{uint read_bytes=0
 , tmp_read_bytes;
#if php_fastcgi
 char *pos = buffer;
#endif
 count_bytes = MIN (Count_bytes, (UINT) SG (request_info). CONTENT_LENGTH-SG (Read_post_bytes));
 while (Read_bytes < count_bytes) {
#if php_fastcgi
  if (fcgi_is_fastcgi ()) {
   Fcgi_request *request = ( fcgi_request*) SG (server_context);
   Tmp_read_bytes = Fcgi_read (Request, POS, count_bytes-read_bytes);
   POS + + tmp_read_bytes;
  } else {
   tmp_read_bytes = read (0, buffer + read_bytes, count_bytes-read_bytes);
  }
#else
  tmp_read_bytes = Read (0, buffer + read_bytes, count_bytes-read_bytes);
#endif
  if (tmp_read_bytes <= 0) {break
   ;
  }
  Read_bytes + + tmp_read_bytes;
 }
 return read_bytes;
}

Sapi_cgi_read_cookies, like the above function, is simply to get the cookie value:

Static char *sapi_cgi_read_cookies (tsrmls_d)
{return
 sapi_cgibin_getenv ((char *) "Http_cookie", sizeof (" Http_cookie ")-1 tsrmls_cc);


Sapi_cgi_register_variables, this function gives an interface to add a variable to the $_server variable and, for CGI, registers a php_self so that we can access $_server[' php_ in the script SELF '] to get

The Request_uri of this time:

static void Sapi_cgi_register_variables (Zval *track_vars_array tsrmls_dc)
{/
 * in CGI mode, we consider the EnviR Onment to is a part of the server
  * variables * *
 php_import_environment_variables (Track_vars_array tsrmls_ CC);
 /* Build the Special-case php_self variable for the CGI version * *
 php_register_variable ("Php_self", SG (Request_inf o). Request_uri? SG (Request_info). Request_uri: ""), Track_vars_array tsrmls_cc);
}

Sapi_cgi_log_message, used to output error messages, for CGI, is simply output to stderr:

static void Sapi_cgi_log_message (char *message)
{
#if php_fastcgi
 if (fcgi_is_fastcgi () && fcgi_ Logging) {
  fcgi_request *request;
  Tsrmls_fetch ();
  Request = (fcgi_request*) SG (server_context);
  if (request) {
   int len = strlen (message);
   Char *buf = malloc (len+2);
   memcpy (buf, message, Len);
   memcpy (buf + len, "\ n", sizeof ("\ n"));
   Fcgi_write (Request, Fcgi_stderr, buf, len+1);
   Free (BUF);
  } else {
   fprintf (stderr, "%s\n", message);
  }
  /* Ignore return code
 /Else
#endif/* php_fastcgi * *
 fprintf (stderr, "%s\n", message);

After analysis, we have learned how a SAPI is implemented, after analyzing CGI, we can also imagine mod_php, embed and other SAPI implementation mechanism. :)

How, this article is not very detailed description, I hope you like.

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.