Хозяйке на заметку

Я сейчас занимаюсь написанием расширения PHP, которое меняет UID/EUID (а также GID/EGID) процесса PHP-интерпретатора на UID/GID владельца DocumentRoot сайта. При этом по замыслу расширение должно отключаться, если SAPI не используется (например, запущена CLI-версия интерпретатора).

Для этой задачи оказалось важным знать точную последовательность инициализации и финализации.

Те, кто разрабатывал расширения для PHP, знают, что функции инициализации/финализации задаются структурой zend_module_entry, например:

[-]
View Code C
zend_module_entry chuid_module_entry = {
    STANDARD_MODULE_HEADER_EX,
    NULL,
    NULL,
    PHP_CHUID_EXTNAME,
    NULL,
    PHP_MINIT(chuid),     /* Module init*/
    PHP_MSHUTDOWN(chuid), /* Module shutdown */
    PHP_RINIT(chuid),     /* Request init */
    PHP_RSHUTDOWN(chuid), /* Request shutdown */
    PHP_MINFO(chuid),
    PHP_CHUID_EXTVER,
    PHP_MODULE_GLOBALS(chuid),
    PHP_GINIT(chuid),     /* Globals init */
    PHP_GSHUTDOWN(chuid), /* Globals shutdown */
    NULL,
    STANDARD_MODULE_PROPERTIES_EX
};

Инициализация происходит при этом в таком порядке:

  1. GINIT — инициализация глобальных переменных;
  2. MINIT — инициализация расширения;
  3. RINIT — инициализация перед обработкой запроса.

Разрушение, соответственно, происходит в обратном порядке: RSHUTDOWN, MSHUTDOWN, GSHUTDOWN. Всё просто.

Однако у программиста есть возможность установить свой обработчик для фазы SAPI Activate/SAPI Deactivate (обычно это делается во время MINIT):

[-]
View Code C
int (*php_cgi_sapi_activate)(TSRMLS_D) = NULL;
int (*php_cgi_sapi_deactivate)(TSRMLS_D) = NULL;

static int sapi_cgi_activate(TSRMLS_D)
{
    printf("SAPI activate\n");
    if (php_cgi_sapi_activate) {
        return php_cgi_sapi_activate(TSRMLS_C);
    }

    return SUCCESS;
}

static int sapi_cgi_deactivate(TSRMLS_D)
{
    printf("SAPI deactivate\n");
    if (php_cgi_sapi_deactivate) {
        return php_cgi_sapi_deactivate(TSRMLS_C);
    }

    return SUCCESS;
}

static PHP_MINIT_FUNCTION(chuid)
{
    REGISTER_INI_ENTRIES();

    php_cgi_sapi_activate   = sapi_module.activate;
    php_cgi_sapi_deactivate = sapi_module.deactivate;
    sapi_module.activate    = sapi_cgi_activate;
    sapi_module.deactivate  = sapi_cgi_deactivate;

    return SUCCESS;
}

printf() всё же лучше не использовать, но в качестве примера сойдёт :-)

И вот тут-то начинается самое интересное.

При запуске PHP (я использовал php-cgi) получается такая картина:

  1. GINIT;
  2. MINIT;
  3. SAPI deactivate — вот оно!

Получается, что SAPI Deactivate вызывается до SAPI Activate, что не вполне очевидно, особенно для новичка :-) Последовательность обработки запросов остаётся практически той же:

  1. SAPI activate;
  2. RINIT;
  3. RSHUTDOWN;
  4. SAPI deactivate.

При завершении процесса (именно процесса, а не запроса — ибо один процесс может обработать несколько запросов — это зависит от значения переменной окружения PHP_FCGI_MAX_REQUESTS) будут вызваны MSHUTDOWN и RSHUTDOWN — и никаких лишних SAPI (De)activate.

Добавить в закладки

Связанные записи

29
Авг
2009

Комментарии к статье «Последовательность инициализации и сброса в расширениях PHP»  »

К статье «Последовательность инициализации и сброса в расширениях PHP» комментариев пока нет. Не хотите ли стать первым?

Подписаться на RSS-ленту комментариев к статье «Последовательность инициализации и сброса в расширениях PHP» Trackback URL: http://blog.sjinks.org.ua/php/623-initialization-shutdown-sequence-in-php-extensions/trackback/

Оставить комментарий к записи «Последовательность инициализации и сброса в расширениях PHP»

Вы можете использовать данные тэги: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Оставляя комментарий, Вы выражаете своё согласие с Правилами комментирования.

Подписаться, не комментируя