Backend Development 10 min read

Understanding PHP SAPI Internals: CGI Module Structure and Startup Process

This article provides an in‑depth English overview of PHP’s SAPI architecture, detailing the CGI SAPI module structure, the core _sapi_module_struct and sapi_globals definitions, and walking through the startup sequence including sapi_startup, sapi_globals_ctor, and FastCGI initialization with code examples.

php中文网 Courses
php中文网 Courses
php中文网 Courses
Understanding PHP SAPI Internals: CGI Module Structure and Startup Process

This article examines the internal implementation of PHP's Server API (SAPI), focusing on the CGI SAPI module used when PHP runs under a web server.

The CGI SAPI module is defined by the cgi_sapi_module structure, which populates a sapi_module_struct containing function pointers for startup, shutdown, request handling, I/O, and other operations.

<code>//* sapi_module_struct cgi_sapi_module
static sapi_module_struct cgi_sapi_module = {
  "cgi-fcgi",            /* name */
  "CGI/FastCGI",          /* pretty name */
  php_cgi_startup,        /* startup */
  php_module_shutdown_wrapper,  /* shutdown */
  sapi_cgi_activate,        /* activate */
  sapi_cgi_deactivate,      /* deactivate */
  sapi_cgi_ub_write,        /* unbuffered write */
  sapi_cgi_flush,          /* flush */
  NULL,              /* get uid */
  sapi_cgi_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 */
  NULL,              /* Get request time */
  NULL,              /* Child terminate */
  STANDARD_SAPI_MODULE_PROPERTIES
};
</code>

The core definition of the SAPI module resides in sapi.h as the _sapi_module_struct structure, which lists all callbacks and configuration fields required by a SAPI implementation.

<code>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)(void);
    int (*deactivate)(void);
    size_t (*ub_write)(const char *str, size_t str_length);
    void (*flush)(void *server_context);
    zend_stat_t *(*get_stat)(void);
    char *(*getenv)(const char *name, size_t name_len);
    void (*sapi_error)(int type, const char *error_msg, ...) ZEND_ATTRIBUTE_FORMAT(printf, 2, 3);
    int (*header_handler)(sapi_header_struct *sapi_header, sapi_header_op_enum op, sapi_headers_struct *sapi_headers);
    int (*send_headers)(sapi_headers_struct *sapi_headers);
    void (*send_header)(sapi_header_struct *sapi_header, void *server_context);
    size_t (*read_post)(char *buffer, size_t count_bytes);
    char *(*read_cookies)(void);
    void (*register_server_variables)(zval *track_vars_array);
    void (*log_message)(char *message, int syslog_type_int);
    double (*get_request_time)(void);
    void (*terminate_process)(void);
    /* ... other fields ... */
};
</code>

Another crucial data structure is sapi_globals_struct , accessed via the SG macro, which holds runtime state such as request information, headers, and configuration values.

<code>typedef struct _sapi_globals_struct {
    void *server_context;
    sapi_request_info request_info;
    sapi_headers_struct sapi_headers;
    int64_t read_post_bytes;
    unsigned char post_read;
    unsigned char headers_sent;
    zend_stat_t global_stat;
    char *default_mimetype;
    char *default_charset;
    HashTable *rfc1867_uploaded_files;
    zend_long post_max_size;
    int options;
    zend_bool sapi_started;
    double global_request_time;
    HashTable known_post_content_types;
    zval callback_func;
    zend_fcall_info_cache fci_cache;
} sapi_globals_struct;
</code>

The startup sequence begins with a call to sapi_startup(&amp;cgi_sapi_module) , which copies the module definition into a global sapi_module variable, allocates or constructs the sapi_globals structure (depending on whether ZTS is enabled), and registers default content types.

<code>void sapi_startup(sapi_module_struct *sf) {
    sf->ini_entries = NULL;
    sapi_module = *sf;
    #ifdef ZTS
        ts_allocate_fast_id(&sapi_globals_id, &sapi_globals_offset,
            sizeof(sapi_globals_struct), (ts_allocate_ctor) sapi_globals_ctor,
            (ts_allocate_dtor) sapi_globals_dtor);
    #else
        sapi_globals_ctor(&sapi_globals);
    #endif
    reentrancy_startup();
}
</code>

The sapi_globals_ctor function zero‑initialises the globals and creates a hash table for known POST content types before calling php_setup_sapi_content_types() , which registers default POST readers and input filters.

<code>static void sapi_globals_ctor(sapi_globals_struct *sapi_globals) {
    memset(sapi_globals, 0, sizeof(*sapi_globals));
    zend_hash_init(&sapi_globals->known_post_content_types, 8, NULL, _type_dtor, 1);
    php_setup_sapi_content_types();
}
</code>

After the SAPI is initialized, the code checks whether the process is running under FastCGI by invoking fcgi_is_fastcgi() , which may call fcgi_init() to set up FastCGI management variables, socket handling, and signal handling.

<code>int fcgi_is_fastcgi(void) {
    if (!is_initialized) {
        return fcgi_init();
    } else {
        return is_fastcgi;
    }
}
</code>

Overall, the article walks through the key structures and functions that enable PHP to operate as a CGI/FastCGI SAPI, providing concrete code excerpts to illustrate each step.

backendC++PHPCGIFastCGIInternalsSAPI
php中文网 Courses
Written by

php中文网 Courses

php中文网's platform for the latest courses and technical articles, helping PHP learners advance quickly.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.