PHP Kernel Explorer: Starting with the SAPI interface

Source: Internet
Author: User

Sapi:server application Programming Interface Server-side application programming port. Students who have studied PHP architecture should know the importance of this stuff, and it provides an interface that allows PHP to interact with other applications. This article does not detail each PHP SAPI, but only for the simplest CGI SAPI, to illustrate the mechanism of SAPI.

Let's take a look at the PHP architecture diagram first:

SAPI refers to the specific application of PHP programming interface, like a PC, no matter what operating system installed, as long as the interface specifications of the PC can be run properly on the PC, PHP script to execute in a number of ways, through the Web server, or directly under the command line, can also be embedded in other programs.

In general, we use a Web server such as Apache or Nginx to test PHP scripts or execute them under the command line via the PHP interpreter program. When the script finishes executing, the Web server answers, the browser displays the response information, or the content is displayed on the command line standard output.

We seldom care where the PHP interpreter is. While executing scripts through the Web server and the command-line program looks very different, the workflow is actually the same. Command-line arguments are passed to the PHP interpreter to execute the script, which is equivalent to requesting a PHP page via a URL. The result of the response is returned when the script executes, except that the command line response is displayed on the terminal.

The start of the script execution begins with the SAPI interface implementation. Just different SAPI interface implementations will accomplish their specific work, such as Apache's mod_php SAPI implementations need to initialize some information obtained from Apache, the output content is to return the content to Apache, other SAPI implementations are similar.

SAPI provides an interface to the external communication, for PHP5.2, the default provides many kinds of SAPI, common to Apache mod_php5,cgi, to IIS ISAPI, and the Shell CLI, this article from the CGI SAPI, introduced SAPI mechanism. Although CGI is simple, 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 to see PHP-SRC/SAPI/CGI/CGI_MAIN.C:

*/static sapi_module_struct cgi_sapi_module = {#if php_fastcgi "cgi-fcgi",/* name */"CGI/FASTC                          GI ",/* Pretty name */#else" CGI ",/* Name */" CGI ", /* Pretty name */#endif php_cgi_startup,/* startup */Php_module_shutdown_wrapper,/* shutdo WN */NULL,/* activate */sapi_cgi_deactivate,/* Deactivate */Sapi_cgib                           In_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 */SA    Pi_cgi_read_cookies,      /* Read Cookies */sapi_cgi_register_variables,/* Register Server Variables */sapi_cgi_log_message, /* LOG message */NULL,/* Get Request time */standard_sapi_module_properties};

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

1. Php_cgi_startup, when an application to invoke PHP, this function will be called, for CGI, it simply calls 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 is part of the Activate field to be defined, as we can see from the structure above that, for CGI, it does not provide a handle to the initialization handle. For mod_php, that's different, he wants to register the resource destructor, request space, initialize environment variables, and so on in the Apache pool.

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

static int Sapi_cgi_deactivate (tsrmls_d) {/    * Flush only if SAPI was started. The reasons is:        1. SAPI Deactivate is called from the Places:module init and request shutdown        2. When the first call occurs and the request are 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 for writing 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) {#ifdef 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 logic of writing is stripped out, simply to achieve the compatibility of fastcgi write way.

6. Sapi_cgibin_flush, this is a function handle that is provided to Zend to flush the cache, and for CGI, it simply invokes the fflush provided by the 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, not provided by CGI.

8. Sapi_cgibin_getenv, provides an interface for Zend to find environment variables according to name, and for MOD_PHP5, when we call getenv in the script, we call the handle indirectly. And for CGI, because his operating mechanism is similar to the CLI, the direct call to the parent is the shell, so it simply invokes the system-provided genenv:

Static Char *sapi_cgibin_getenv (char *name, size_t Name_len tsrmls_dc) {#if php_fastcgi/    * When PHP was started by Mod_f astcgi, no regular environment is       provided to PHP.  It is always sent to PHP at the start of       a request.  So, we have the 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, here, say a few digression, last see php maillist mentioned make PHP error handling mechanism completely OO, that is, rewrite this function handle, so that whenever there is an error occurred, throw an exception. CGI simply invokes the error-handling function provided by PHP.

10. This function is called when we call the header () function of PHP and is not available for CGI.

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

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_len             GTH, "%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 post data, and if you do CGI programming, we know that 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, this is the same as the above function, just 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, it 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 Environmen T to is a part of the server     * Variables     *    /Php_import_environment_variables (Track_vars_array tsrmls_cc); c5/>/* Build the special-case php_self variable for the CGI version */    php_register_variable ("Php_self", (SG (request_ info). Request_uri? SG (Request_info). Request_uri: ""), Track_vars_array tsrmls_cc);}

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

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 understood how a SAPI is implemented, after analyzing the CGI, we can also imagine mod_php, embed and other SAPI implementation mechanism.

PHP Kernel Explorer: Starting with the SAPI interface

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.