10Sigor@sysoev.ru 20Sigor@sysoev.ru /* 386Smax.romanov@nginx.com * Copyright (C) Max Romanov 40Sigor@sysoev.ru * Copyright (C) Valentin V. Bartenev 50Sigor@sysoev.ru * Copyright (C) NGINX, Inc. 60Sigor@sysoev.ru */ 70Sigor@sysoev.ru 80Sigor@sysoev.ru #include "php.h" 90Sigor@sysoev.ru #include "SAPI.h" 100Sigor@sysoev.ru #include "php_main.h" 110Sigor@sysoev.ru #include "php_variables.h" 120Sigor@sysoev.ru 130Sigor@sysoev.ru #include <nxt_main.h> 140Sigor@sysoev.ru #include <nxt_application.h> 150Sigor@sysoev.ru 160Sigor@sysoev.ru 17142Smax.romanov@nginx.com static nxt_int_t nxt_php_init(nxt_task_t *task, nxt_common_app_conf_t *conf); 180Sigor@sysoev.ru 1986Smax.romanov@nginx.com static nxt_int_t nxt_php_run(nxt_task_t *task, 2086Smax.romanov@nginx.com nxt_app_rmsg_t *rmsg, nxt_app_wmsg_t *wmsg); 210Sigor@sysoev.ru 2286Smax.romanov@nginx.com #if PHP_MAJOR_VERSION >= 7 2386Smax.romanov@nginx.com # define NXT_PHP7 1 2486Smax.romanov@nginx.com # if PHP_MINOR_VERSION >= 1 2586Smax.romanov@nginx.com # define NXT_HAVE_PHP_LOG_MESSAGE_WITH_SYSLOG_TYPE 1 2686Smax.romanov@nginx.com # else 2786Smax.romanov@nginx.com # define NXT_HAVE_PHP_INTERRUPTS 1 2886Smax.romanov@nginx.com # endif 2986Smax.romanov@nginx.com # define NXT_HAVE_PHP_IGNORE_CWD 1 3086Smax.romanov@nginx.com #else 3186Smax.romanov@nginx.com # define NXT_HAVE_PHP_INTERRUPTS 1 3286Smax.romanov@nginx.com # if PHP_MINOR_VERSION >= 4 3386Smax.romanov@nginx.com # define NXT_HAVE_PHP_IGNORE_CWD 1 3486Smax.romanov@nginx.com # endif 3586Smax.romanov@nginx.com #endif 360Sigor@sysoev.ru 370Sigor@sysoev.ru static int nxt_php_startup(sapi_module_struct *sapi_module); 380Sigor@sysoev.ru static int nxt_php_send_headers(sapi_headers_struct *sapi_headers); 390Sigor@sysoev.ru static char *nxt_php_read_cookies(void); 400Sigor@sysoev.ru static void nxt_php_register_variables(zval *track_vars_array); 4186Smax.romanov@nginx.com static void nxt_php_log_message(char *message 4286Smax.romanov@nginx.com #ifdef NXT_HAVE_PHP_LOG_MESSAGE_WITH_SYSLOG_TYPE 4386Smax.romanov@nginx.com , int syslog_type_int 4486Smax.romanov@nginx.com #endif 4586Smax.romanov@nginx.com ); 460Sigor@sysoev.ru 470Sigor@sysoev.ru #ifdef NXT_PHP7 480Sigor@sysoev.ru static size_t nxt_php_unbuffered_write(const char *str, 490Sigor@sysoev.ru size_t str_length TSRMLS_DC); 500Sigor@sysoev.ru static size_t nxt_php_read_post(char *buffer, size_t count_bytes TSRMLS_DC); 510Sigor@sysoev.ru #else 520Sigor@sysoev.ru static int nxt_php_unbuffered_write(const char *str, uint str_length TSRMLS_DC); 530Sigor@sysoev.ru static int nxt_php_read_post(char *buffer, uint count_bytes TSRMLS_DC); 540Sigor@sysoev.ru #endif 550Sigor@sysoev.ru 56114Smax.romanov@nginx.com static void nxt_php_flush(void *server_context); 57114Smax.romanov@nginx.com 580Sigor@sysoev.ru 590Sigor@sysoev.ru static sapi_module_struct nxt_php_sapi_module = 600Sigor@sysoev.ru { 610Sigor@sysoev.ru (char *) "cli-server", 629Sigor@sysoev.ru (char *) "nginext", 630Sigor@sysoev.ru 640Sigor@sysoev.ru nxt_php_startup, /* startup */ 650Sigor@sysoev.ru php_module_shutdown_wrapper, /* shutdown */ 660Sigor@sysoev.ru 670Sigor@sysoev.ru NULL, /* activate */ 680Sigor@sysoev.ru NULL, /* deactivate */ 690Sigor@sysoev.ru 700Sigor@sysoev.ru nxt_php_unbuffered_write, /* unbuffered write */ 71114Smax.romanov@nginx.com nxt_php_flush, /* flush */ 720Sigor@sysoev.ru NULL, /* get uid */ 730Sigor@sysoev.ru NULL, /* getenv */ 740Sigor@sysoev.ru 750Sigor@sysoev.ru php_error, /* error handler */ 760Sigor@sysoev.ru 770Sigor@sysoev.ru NULL, /* header handler */ 780Sigor@sysoev.ru nxt_php_send_headers, /* send headers handler */ 790Sigor@sysoev.ru NULL, /* send header handler */ 800Sigor@sysoev.ru 810Sigor@sysoev.ru nxt_php_read_post, /* read POST data */ 820Sigor@sysoev.ru nxt_php_read_cookies, /* read Cookies */ 830Sigor@sysoev.ru 840Sigor@sysoev.ru nxt_php_register_variables, /* register server variables */ 850Sigor@sysoev.ru nxt_php_log_message, /* log message */ 8686Smax.romanov@nginx.com NULL, /* get request time */ 8786Smax.romanov@nginx.com NULL, /* terminate process */ 880Sigor@sysoev.ru 8986Smax.romanov@nginx.com NULL, /* php_ini_path_override */ 9086Smax.romanov@nginx.com #ifdef NXT_HAVE_PHP_INTERRUPTS 9186Smax.romanov@nginx.com NULL, /* block_interruptions */ 9286Smax.romanov@nginx.com NULL, /* unblock_interruptions */ 9386Smax.romanov@nginx.com #endif 9486Smax.romanov@nginx.com NULL, /* default_post_reader */ 9586Smax.romanov@nginx.com NULL, /* treat_data */ 9686Smax.romanov@nginx.com NULL, /* executable_location */ 9786Smax.romanov@nginx.com 9886Smax.romanov@nginx.com 0, /* php_ini_ignore */ 9986Smax.romanov@nginx.com #ifdef NXT_HAVE_PHP_IGNORE_CWD 10086Smax.romanov@nginx.com 0, /* php_ini_ignore_cwd */ 10186Smax.romanov@nginx.com #endif 10286Smax.romanov@nginx.com NULL, /* get_fd */ 10386Smax.romanov@nginx.com 10486Smax.romanov@nginx.com NULL, /* force_http_10 */ 10586Smax.romanov@nginx.com 10686Smax.romanov@nginx.com NULL, /* get_target_uid */ 10786Smax.romanov@nginx.com NULL, /* get_target_gid */ 10886Smax.romanov@nginx.com 10986Smax.romanov@nginx.com NULL, /* input_filter */ 11086Smax.romanov@nginx.com 11186Smax.romanov@nginx.com NULL, /* ini_defaults */ 11286Smax.romanov@nginx.com 0, /* phpinfo_as_text */ 11386Smax.romanov@nginx.com 11486Smax.romanov@nginx.com NULL, /* ini_entries */ 11586Smax.romanov@nginx.com NULL, /* additional_functions */ 11686Smax.romanov@nginx.com NULL /* input_filter_init */ 1170Sigor@sysoev.ru }; 1180Sigor@sysoev.ru 11986Smax.romanov@nginx.com typedef struct { 12086Smax.romanov@nginx.com nxt_task_t *task; 12186Smax.romanov@nginx.com nxt_app_rmsg_t *rmsg; 12286Smax.romanov@nginx.com nxt_app_request_t r; 12386Smax.romanov@nginx.com nxt_str_t script; 12486Smax.romanov@nginx.com nxt_app_wmsg_t *wmsg; 12586Smax.romanov@nginx.com nxt_mp_t *mem_pool; 126206Smax.romanov@nginx.com 127206Smax.romanov@nginx.com size_t body_preread_size; 12886Smax.romanov@nginx.com } nxt_php_run_ctx_t; 12986Smax.romanov@nginx.com 13086Smax.romanov@nginx.com nxt_inline nxt_int_t nxt_php_write(nxt_php_run_ctx_t *ctx, 13186Smax.romanov@nginx.com const u_char *data, size_t len, 13286Smax.romanov@nginx.com nxt_bool_t flush, nxt_bool_t last); 13386Smax.romanov@nginx.com 1340Sigor@sysoev.ru 1350Sigor@sysoev.ru static nxt_str_t nxt_php_path; 1360Sigor@sysoev.ru static nxt_str_t nxt_php_root; 1370Sigor@sysoev.ru static nxt_str_t nxt_php_script; 138142Smax.romanov@nginx.com static nxt_str_t nxt_php_index = nxt_string("index.php"); 139142Smax.romanov@nginx.com 140142Smax.romanov@nginx.com static void 141142Smax.romanov@nginx.com nxt_php_strdup(nxt_str_t *dst, nxt_str_t *src) 142142Smax.romanov@nginx.com { 143142Smax.romanov@nginx.com dst->start = malloc(src->length + 1); 144142Smax.romanov@nginx.com nxt_memcpy(dst->start, src->start, src->length); 145142Smax.romanov@nginx.com dst->start[src->length] = '\0'; 146142Smax.romanov@nginx.com 147142Smax.romanov@nginx.com dst->length = src->length; 148142Smax.romanov@nginx.com } 149142Smax.romanov@nginx.com 150142Smax.romanov@nginx.com static void 151142Smax.romanov@nginx.com nxt_php_str_trim_trail(nxt_str_t *str, u_char t) 152142Smax.romanov@nginx.com { 153142Smax.romanov@nginx.com while (str->length > 0 && str->start[str->length - 1] == t) { 154142Smax.romanov@nginx.com str->length--; 155142Smax.romanov@nginx.com } 156142Smax.romanov@nginx.com 157142Smax.romanov@nginx.com str->start[str->length] = '\0'; 158142Smax.romanov@nginx.com } 159142Smax.romanov@nginx.com 160142Smax.romanov@nginx.com 161142Smax.romanov@nginx.com static void 162142Smax.romanov@nginx.com nxt_php_str_trim_lead(nxt_str_t *str, u_char t) 163142Smax.romanov@nginx.com { 164142Smax.romanov@nginx.com while (str->length > 0 && str->start[0] == t) { 165142Smax.romanov@nginx.com str->length--; 166142Smax.romanov@nginx.com str->start++; 167142Smax.romanov@nginx.com } 168142Smax.romanov@nginx.com } 1690Sigor@sysoev.ru 1700Sigor@sysoev.ru 171*216Sigor@sysoev.ru NXT_EXPORT nxt_application_module_t nxt_app_module = { 172*216Sigor@sysoev.ru nxt_string("php"), 173*216Sigor@sysoev.ru nxt_string(PHP_VERSION), 17486Smax.romanov@nginx.com nxt_php_init, 175*216Sigor@sysoev.ru nxt_php_run, 17686Smax.romanov@nginx.com }; 1770Sigor@sysoev.ru 1780Sigor@sysoev.ru 17986Smax.romanov@nginx.com static nxt_int_t 180142Smax.romanov@nginx.com nxt_php_init(nxt_task_t *task, nxt_common_app_conf_t *conf) 1810Sigor@sysoev.ru { 182142Smax.romanov@nginx.com nxt_str_t *root, *path, *script, *index; 183142Smax.romanov@nginx.com nxt_php_app_conf_t *c; 184142Smax.romanov@nginx.com 185142Smax.romanov@nginx.com c = &conf->u.php; 186142Smax.romanov@nginx.com 187142Smax.romanov@nginx.com if (c->root.length == 0) { 188142Smax.romanov@nginx.com nxt_log_emerg(task->log, "php root is empty"); 189142Smax.romanov@nginx.com return NXT_ERROR; 190142Smax.romanov@nginx.com } 191142Smax.romanov@nginx.com 192142Smax.romanov@nginx.com root = &nxt_php_root; 193142Smax.romanov@nginx.com path = &nxt_php_path; 194142Smax.romanov@nginx.com script = &nxt_php_script; 195142Smax.romanov@nginx.com index = &nxt_php_index; 196142Smax.romanov@nginx.com 197142Smax.romanov@nginx.com nxt_php_strdup(root, &c->root); 198142Smax.romanov@nginx.com 199142Smax.romanov@nginx.com nxt_php_str_trim_trail(root, '/'); 200142Smax.romanov@nginx.com 201142Smax.romanov@nginx.com if (c->script.length > 0) { 202142Smax.romanov@nginx.com nxt_php_str_trim_lead(&c->script, '/'); 203142Smax.romanov@nginx.com 204142Smax.romanov@nginx.com path->length = root->length + c->script.length + 1; 205142Smax.romanov@nginx.com path->start = malloc(path->length + 1); 206142Smax.romanov@nginx.com 207142Smax.romanov@nginx.com nxt_memcpy(path->start, root->start, root->length); 208142Smax.romanov@nginx.com path->start[root->length] = '/'; 209142Smax.romanov@nginx.com 210142Smax.romanov@nginx.com nxt_memcpy(path->start + root->length + 1, 211142Smax.romanov@nginx.com c->script.start, c->script.length); 212142Smax.romanov@nginx.com 213142Smax.romanov@nginx.com path->start[path->length] = '\0'; 214142Smax.romanov@nginx.com 215142Smax.romanov@nginx.com 216142Smax.romanov@nginx.com script->length = c->script.length + 1; 217142Smax.romanov@nginx.com script->start = malloc(script->length + 1); 218142Smax.romanov@nginx.com script->start[0] = '/'; 219142Smax.romanov@nginx.com nxt_memcpy(script->start + 1, c->script.start, c->script.length); 220142Smax.romanov@nginx.com script->start[script->length] = '\0'; 221142Smax.romanov@nginx.com 222142Smax.romanov@nginx.com nxt_log_error(NXT_LOG_INFO, task->log, 223142Smax.romanov@nginx.com "(ABS_MODE) php script \"%V\" root: \"%V\"", 224142Smax.romanov@nginx.com script, root); 225142Smax.romanov@nginx.com } else { 226142Smax.romanov@nginx.com nxt_log_error(NXT_LOG_INFO, task->log, 227142Smax.romanov@nginx.com "(non ABS_MODE) php root: \"%V\"", root); 228142Smax.romanov@nginx.com } 229142Smax.romanov@nginx.com 230142Smax.romanov@nginx.com if (c->index.length > 0) { 231142Smax.romanov@nginx.com nxt_php_strdup(index, &c->index); 232142Smax.romanov@nginx.com } 233142Smax.romanov@nginx.com 234142Smax.romanov@nginx.com sapi_startup(&nxt_php_sapi_module); 235142Smax.romanov@nginx.com nxt_php_startup(&nxt_php_sapi_module); 236142Smax.romanov@nginx.com 2370Sigor@sysoev.ru return NXT_OK; 2380Sigor@sysoev.ru } 2390Sigor@sysoev.ru 2400Sigor@sysoev.ru 24186Smax.romanov@nginx.com static nxt_int_t 24286Smax.romanov@nginx.com nxt_php_read_request(nxt_task_t *task, nxt_app_rmsg_t *rmsg, 24386Smax.romanov@nginx.com nxt_php_run_ctx_t *ctx) 2440Sigor@sysoev.ru { 24586Smax.romanov@nginx.com u_char *p; 24686Smax.romanov@nginx.com size_t s; 247114Smax.romanov@nginx.com nxt_int_t rc; 24894Smax.romanov@nginx.com nxt_str_t script_name; 24986Smax.romanov@nginx.com nxt_app_request_header_t *h; 2500Sigor@sysoev.ru 25186Smax.romanov@nginx.com h = &ctx->r.header; 2520Sigor@sysoev.ru 253114Smax.romanov@nginx.com #define RC(S) \ 254114Smax.romanov@nginx.com do { \ 255114Smax.romanov@nginx.com rc = (S); \ 256114Smax.romanov@nginx.com if (nxt_slow_path(rc != NXT_OK)) { \ 257114Smax.romanov@nginx.com goto fail; \ 258114Smax.romanov@nginx.com } \ 259114Smax.romanov@nginx.com } while(0) 2600Sigor@sysoev.ru 261114Smax.romanov@nginx.com #define NXT_READ(dst) \ 262114Smax.romanov@nginx.com RC(nxt_app_msg_read_str(task, rmsg, (dst))) 263114Smax.romanov@nginx.com 264114Smax.romanov@nginx.com NXT_READ(&h->method); 265114Smax.romanov@nginx.com NXT_READ(&h->target); 266114Smax.romanov@nginx.com NXT_READ(&h->path); 267114Smax.romanov@nginx.com 268114Smax.romanov@nginx.com RC(nxt_app_msg_read_size(task, rmsg, &s)); 26986Smax.romanov@nginx.com if (s > 0) { 27086Smax.romanov@nginx.com s--; 271112Smax.romanov@nginx.com h->query.start = h->target.start + s; 272112Smax.romanov@nginx.com h->query.length = h->target.length - s; 2730Sigor@sysoev.ru 274112Smax.romanov@nginx.com if (h->path.start == NULL) { 275112Smax.romanov@nginx.com h->path.start = h->target.start; 276112Smax.romanov@nginx.com h->path.length = s - 1; 27786Smax.romanov@nginx.com } 2780Sigor@sysoev.ru } 2790Sigor@sysoev.ru 280112Smax.romanov@nginx.com if (h->path.start == NULL) { 281112Smax.romanov@nginx.com h->path = h->target; 282112Smax.romanov@nginx.com } 283112Smax.romanov@nginx.com 28486Smax.romanov@nginx.com if (nxt_php_path.start == NULL) { 285112Smax.romanov@nginx.com if (h->path.start[h->path.length - 1] == '/') { 286142Smax.romanov@nginx.com script_name = nxt_php_index; 28794Smax.romanov@nginx.com } else { 28894Smax.romanov@nginx.com script_name.length = 0; 28994Smax.romanov@nginx.com } 29094Smax.romanov@nginx.com 291112Smax.romanov@nginx.com ctx->script.length = nxt_php_root.length + h->path.length + 29294Smax.romanov@nginx.com script_name.length; 29386Smax.romanov@nginx.com ctx->script.start = nxt_mp_nget(ctx->mem_pool, 29486Smax.romanov@nginx.com ctx->script.length + 1); 29586Smax.romanov@nginx.com 29686Smax.romanov@nginx.com p = ctx->script.start; 29786Smax.romanov@nginx.com 29886Smax.romanov@nginx.com nxt_memcpy(p, nxt_php_root.start, nxt_php_root.length); 29986Smax.romanov@nginx.com p += nxt_php_root.length; 30094Smax.romanov@nginx.com 301112Smax.romanov@nginx.com nxt_memcpy(p, h->path.start, h->path.length); 302112Smax.romanov@nginx.com p += h->path.length; 30394Smax.romanov@nginx.com 30494Smax.romanov@nginx.com if (script_name.length > 0) { 30594Smax.romanov@nginx.com nxt_memcpy(p, script_name.start, script_name.length); 30694Smax.romanov@nginx.com p += script_name.length; 30794Smax.romanov@nginx.com } 30894Smax.romanov@nginx.com 30994Smax.romanov@nginx.com p[0] = '\0'; 31086Smax.romanov@nginx.com } else { 31186Smax.romanov@nginx.com ctx->script = nxt_php_path; 31286Smax.romanov@nginx.com } 31386Smax.romanov@nginx.com 314114Smax.romanov@nginx.com NXT_READ(&h->version); 315114Smax.romanov@nginx.com 316114Smax.romanov@nginx.com NXT_READ(&ctx->r.remote); 31786Smax.romanov@nginx.com 318114Smax.romanov@nginx.com NXT_READ(&h->host); 319114Smax.romanov@nginx.com NXT_READ(&h->cookie); 320114Smax.romanov@nginx.com NXT_READ(&h->content_type); 321114Smax.romanov@nginx.com NXT_READ(&h->content_length); 32286Smax.romanov@nginx.com 323114Smax.romanov@nginx.com RC(nxt_app_msg_read_size(task, rmsg, &s)); 32486Smax.romanov@nginx.com h->parsed_content_length = s; 32586Smax.romanov@nginx.com 326114Smax.romanov@nginx.com #undef NXT_READ 327114Smax.romanov@nginx.com #undef RC 32894Smax.romanov@nginx.com 32986Smax.romanov@nginx.com /* Further headers read moved to nxt_php_register_variables. */ 3300Sigor@sysoev.ru return NXT_OK; 331114Smax.romanov@nginx.com 332114Smax.romanov@nginx.com fail: 333114Smax.romanov@nginx.com 334114Smax.romanov@nginx.com return rc; 3350Sigor@sysoev.ru } 3360Sigor@sysoev.ru 3370Sigor@sysoev.ru 33886Smax.romanov@nginx.com static nxt_int_t 33986Smax.romanov@nginx.com nxt_php_run(nxt_task_t *task, 34086Smax.romanov@nginx.com nxt_app_rmsg_t *rmsg, nxt_app_wmsg_t *wmsg) 3410Sigor@sysoev.ru { 342114Smax.romanov@nginx.com nxt_int_t rc; 34386Smax.romanov@nginx.com zend_file_handle file_handle; 34486Smax.romanov@nginx.com nxt_php_run_ctx_t run_ctx; 34586Smax.romanov@nginx.com nxt_app_request_header_t *h; 3460Sigor@sysoev.ru 34786Smax.romanov@nginx.com if (nxt_php_root.length == 0) { 3480Sigor@sysoev.ru return NXT_ERROR; 3490Sigor@sysoev.ru } 3500Sigor@sysoev.ru 35186Smax.romanov@nginx.com nxt_memzero(&run_ctx, sizeof(run_ctx)); 35286Smax.romanov@nginx.com 35386Smax.romanov@nginx.com run_ctx.task = task; 35486Smax.romanov@nginx.com run_ctx.rmsg = rmsg; 35586Smax.romanov@nginx.com run_ctx.wmsg = wmsg; 35686Smax.romanov@nginx.com 35786Smax.romanov@nginx.com run_ctx.mem_pool = nxt_mp_create(1024, 128, 256, 32); 3580Sigor@sysoev.ru 35986Smax.romanov@nginx.com h = &run_ctx.r.header; 36086Smax.romanov@nginx.com 361114Smax.romanov@nginx.com rc = nxt_php_read_request(task, rmsg, &run_ctx); 362114Smax.romanov@nginx.com 363114Smax.romanov@nginx.com if (nxt_slow_path(rc != NXT_OK)) { 364114Smax.romanov@nginx.com goto fail; 365114Smax.romanov@nginx.com } 36686Smax.romanov@nginx.com 36786Smax.romanov@nginx.com SG(server_context) = &run_ctx; 368112Smax.romanov@nginx.com SG(request_info).request_uri = (char *) h->target.start; 36986Smax.romanov@nginx.com SG(request_info).request_method = (char *) h->method.start; 3700Sigor@sysoev.ru 3710Sigor@sysoev.ru SG(request_info).proto_num = 1001; 3720Sigor@sysoev.ru 37386Smax.romanov@nginx.com SG(request_info).query_string = (char *) h->query.start; 37486Smax.romanov@nginx.com SG(request_info).content_length = h->parsed_content_length; 3750Sigor@sysoev.ru 37686Smax.romanov@nginx.com if (h->content_type.start != NULL) { 37786Smax.romanov@nginx.com SG(request_info).content_type = (char *) h->content_type.start; 3780Sigor@sysoev.ru } 3790Sigor@sysoev.ru 3800Sigor@sysoev.ru SG(sapi_headers).http_response_code = 200; 3810Sigor@sysoev.ru 3820Sigor@sysoev.ru SG(request_info).path_translated = NULL; 3830Sigor@sysoev.ru 3840Sigor@sysoev.ru file_handle.type = ZEND_HANDLE_FILENAME; 38586Smax.romanov@nginx.com file_handle.filename = (char *) run_ctx.script.start; 3860Sigor@sysoev.ru file_handle.free_filename = 0; 3870Sigor@sysoev.ru file_handle.opened_path = NULL; 3880Sigor@sysoev.ru 389142Smax.romanov@nginx.com nxt_debug(task, "handle.filename = '%s'", run_ctx.script.start); 390142Smax.romanov@nginx.com 39186Smax.romanov@nginx.com if (nxt_php_path.start != NULL) { 39286Smax.romanov@nginx.com nxt_debug(task, "run script %V in absolute mode", &nxt_php_path); 39386Smax.romanov@nginx.com } else { 39486Smax.romanov@nginx.com nxt_debug(task, "run script %V", &run_ctx.script); 39586Smax.romanov@nginx.com } 3960Sigor@sysoev.ru 3970Sigor@sysoev.ru if (nxt_slow_path(php_request_startup() == FAILURE)) { 398142Smax.romanov@nginx.com nxt_debug(task, "php_request_startup() failed"); 39986Smax.romanov@nginx.com goto fail; 4000Sigor@sysoev.ru } 4010Sigor@sysoev.ru 4020Sigor@sysoev.ru php_execute_script(&file_handle TSRMLS_CC); 4030Sigor@sysoev.ru php_request_shutdown(NULL); 4040Sigor@sysoev.ru 40586Smax.romanov@nginx.com nxt_app_msg_flush(task, wmsg, 1); 40686Smax.romanov@nginx.com 40786Smax.romanov@nginx.com nxt_mp_destroy(run_ctx.mem_pool); 40886Smax.romanov@nginx.com 4090Sigor@sysoev.ru return NXT_OK; 41086Smax.romanov@nginx.com 41186Smax.romanov@nginx.com fail: 41286Smax.romanov@nginx.com 41386Smax.romanov@nginx.com nxt_mp_destroy(run_ctx.mem_pool); 41486Smax.romanov@nginx.com 41586Smax.romanov@nginx.com return NXT_ERROR; 41686Smax.romanov@nginx.com } 41786Smax.romanov@nginx.com 41886Smax.romanov@nginx.com 41986Smax.romanov@nginx.com nxt_inline nxt_int_t 42086Smax.romanov@nginx.com nxt_php_write(nxt_php_run_ctx_t *ctx, const u_char *data, size_t len, 42186Smax.romanov@nginx.com nxt_bool_t flush, nxt_bool_t last) 42286Smax.romanov@nginx.com { 42386Smax.romanov@nginx.com nxt_int_t rc; 42486Smax.romanov@nginx.com 425114Smax.romanov@nginx.com if (len > 0) { 426114Smax.romanov@nginx.com rc = nxt_app_msg_write_raw(ctx->task, ctx->wmsg, data, len); 427114Smax.romanov@nginx.com } else { 428114Smax.romanov@nginx.com rc = NXT_OK; 429114Smax.romanov@nginx.com } 43086Smax.romanov@nginx.com 43186Smax.romanov@nginx.com if (flush || last) { 43286Smax.romanov@nginx.com rc = nxt_app_msg_flush(ctx->task, ctx->wmsg, last); 43386Smax.romanov@nginx.com } 43486Smax.romanov@nginx.com 43586Smax.romanov@nginx.com return rc; 4360Sigor@sysoev.ru } 4370Sigor@sysoev.ru 4380Sigor@sysoev.ru 4390Sigor@sysoev.ru static int 4400Sigor@sysoev.ru nxt_php_startup(sapi_module_struct *sapi_module) 4410Sigor@sysoev.ru { 4420Sigor@sysoev.ru return php_module_startup(sapi_module, NULL, 0); 4430Sigor@sysoev.ru } 4440Sigor@sysoev.ru 4450Sigor@sysoev.ru 4460Sigor@sysoev.ru #ifdef NXT_PHP7 4470Sigor@sysoev.ru static size_t 4480Sigor@sysoev.ru nxt_php_unbuffered_write(const char *str, size_t str_length TSRMLS_DC) 4490Sigor@sysoev.ru #else 4500Sigor@sysoev.ru static int 4510Sigor@sysoev.ru nxt_php_unbuffered_write(const char *str, uint str_length TSRMLS_DC) 4520Sigor@sysoev.ru #endif 4530Sigor@sysoev.ru { 454114Smax.romanov@nginx.com nxt_int_t rc; 45586Smax.romanov@nginx.com nxt_php_run_ctx_t *ctx; 4560Sigor@sysoev.ru 45786Smax.romanov@nginx.com ctx = SG(server_context); 4580Sigor@sysoev.ru 459114Smax.romanov@nginx.com rc = nxt_php_write(ctx, (u_char *) str, str_length, 1, 0); 460114Smax.romanov@nginx.com 461114Smax.romanov@nginx.com if (nxt_fast_path(rc == NXT_OK)) { 462114Smax.romanov@nginx.com return str_length; 463114Smax.romanov@nginx.com } 4640Sigor@sysoev.ru 465114Smax.romanov@nginx.com // TODO handle NXT_AGAIN 466114Smax.romanov@nginx.com php_handle_aborted_connection(); 467114Smax.romanov@nginx.com return 0; 468114Smax.romanov@nginx.com } 469114Smax.romanov@nginx.com 470114Smax.romanov@nginx.com 471114Smax.romanov@nginx.com static void 472114Smax.romanov@nginx.com nxt_php_flush(void *server_context) 473114Smax.romanov@nginx.com { 474114Smax.romanov@nginx.com nxt_php_run_ctx_t *ctx; 475114Smax.romanov@nginx.com 476114Smax.romanov@nginx.com ctx = server_context; 477114Smax.romanov@nginx.com 478114Smax.romanov@nginx.com (void) nxt_app_msg_flush(ctx->task, ctx->wmsg, 0); 4790Sigor@sysoev.ru } 4800Sigor@sysoev.ru 4810Sigor@sysoev.ru 4820Sigor@sysoev.ru static int 4830Sigor@sysoev.ru nxt_php_send_headers(sapi_headers_struct *sapi_headers TSRMLS_DC) 4840Sigor@sysoev.ru { 4850Sigor@sysoev.ru size_t len; 486114Smax.romanov@nginx.com u_char *status, buf[64]; 487114Smax.romanov@nginx.com nxt_int_t rc; 488114Smax.romanov@nginx.com nxt_php_run_ctx_t *ctx; 4890Sigor@sysoev.ru sapi_header_struct *h; 4900Sigor@sysoev.ru zend_llist_position zpos; 4910Sigor@sysoev.ru 4920Sigor@sysoev.ru static const u_char default_repsonse[] 4930Sigor@sysoev.ru = "HTTP/1.1 200 OK\r\n" 4949Sigor@sysoev.ru "Server: nginext/0.1\r\n" 4950Sigor@sysoev.ru "Content-Type: text/html; charset=UTF-8\r\n" 4960Sigor@sysoev.ru "Connection: close\r\n" 4970Sigor@sysoev.ru "\r\n"; 4980Sigor@sysoev.ru 4990Sigor@sysoev.ru static const u_char default_headers[] 5009Sigor@sysoev.ru = "Server: nginext/0.1\r\n" 5010Sigor@sysoev.ru "Connection: close\r\n"; 5020Sigor@sysoev.ru 50386Smax.romanov@nginx.com static const u_char http_11[] = "HTTP/1.1 "; 50486Smax.romanov@nginx.com static const u_char cr_lf[] = "\r\n"; 50586Smax.romanov@nginx.com static const u_char _200_ok[] = "200 OK"; 50686Smax.romanov@nginx.com 50786Smax.romanov@nginx.com ctx = SG(server_context); 5080Sigor@sysoev.ru 509114Smax.romanov@nginx.com #define RC(S) \ 510114Smax.romanov@nginx.com do { \ 511114Smax.romanov@nginx.com rc = (S); \ 512114Smax.romanov@nginx.com if (nxt_slow_path(rc != NXT_OK)) { \ 513114Smax.romanov@nginx.com goto fail; \ 514114Smax.romanov@nginx.com } \ 515114Smax.romanov@nginx.com } while(0) 516114Smax.romanov@nginx.com 5170Sigor@sysoev.ru if (SG(request_info).no_headers == 1) { 518114Smax.romanov@nginx.com RC(nxt_php_write(ctx, default_repsonse, sizeof(default_repsonse) - 1, 519114Smax.romanov@nginx.com 1, 0)); 5200Sigor@sysoev.ru return SAPI_HEADER_SENT_SUCCESSFULLY; 5210Sigor@sysoev.ru } 5220Sigor@sysoev.ru 5230Sigor@sysoev.ru if (SG(sapi_headers).http_status_line) { 524114Smax.romanov@nginx.com status = (u_char *) SG(sapi_headers).http_status_line; 5250Sigor@sysoev.ru len = nxt_strlen(status); 5260Sigor@sysoev.ru 527114Smax.romanov@nginx.com RC(nxt_php_write(ctx, status, len, 0, 0)); 5280Sigor@sysoev.ru 5290Sigor@sysoev.ru } else if (SG(sapi_headers).http_response_code) { 53086Smax.romanov@nginx.com status = nxt_sprintf(buf, buf + sizeof(buf), "%03d", 5310Sigor@sysoev.ru SG(sapi_headers).http_response_code); 53286Smax.romanov@nginx.com len = status - buf; 53386Smax.romanov@nginx.com 534114Smax.romanov@nginx.com RC(nxt_php_write(ctx, http_11, sizeof(http_11) - 1, 0, 0)); 535114Smax.romanov@nginx.com RC(nxt_php_write(ctx, buf, len, 0, 0)); 5360Sigor@sysoev.ru 5370Sigor@sysoev.ru } else { 538114Smax.romanov@nginx.com RC(nxt_php_write(ctx, http_11, sizeof(http_11) - 1, 0, 0)); 539114Smax.romanov@nginx.com RC(nxt_php_write(ctx, _200_ok, sizeof(_200_ok) - 1, 0, 0)); 5400Sigor@sysoev.ru } 5410Sigor@sysoev.ru 542114Smax.romanov@nginx.com RC(nxt_php_write(ctx, cr_lf, sizeof(cr_lf) - 1, 0, 0)); 543114Smax.romanov@nginx.com RC(nxt_php_write(ctx, default_headers, sizeof(default_headers) - 1, 0, 0)); 5440Sigor@sysoev.ru 5450Sigor@sysoev.ru h = zend_llist_get_first_ex(&sapi_headers->headers, &zpos); 5460Sigor@sysoev.ru 5470Sigor@sysoev.ru while (h) { 548114Smax.romanov@nginx.com RC(nxt_php_write(ctx, (u_char *) h->header, h->header_len, 0, 0)); 549114Smax.romanov@nginx.com RC(nxt_php_write(ctx, cr_lf, sizeof(cr_lf) - 1, 0, 0)); 5500Sigor@sysoev.ru 5510Sigor@sysoev.ru h = zend_llist_get_next_ex(&sapi_headers->headers, &zpos); 5520Sigor@sysoev.ru } 5530Sigor@sysoev.ru 554114Smax.romanov@nginx.com RC(nxt_php_write(ctx, cr_lf, sizeof(cr_lf) - 1, 1, 0)); 555114Smax.romanov@nginx.com 556114Smax.romanov@nginx.com #undef RC 5570Sigor@sysoev.ru 5580Sigor@sysoev.ru return SAPI_HEADER_SENT_SUCCESSFULLY; 559114Smax.romanov@nginx.com 560114Smax.romanov@nginx.com fail: 561114Smax.romanov@nginx.com 562114Smax.romanov@nginx.com // TODO handle NXT_AGAIN 563114Smax.romanov@nginx.com return SAPI_HEADER_SEND_FAILED; 5640Sigor@sysoev.ru } 5650Sigor@sysoev.ru 5660Sigor@sysoev.ru 5670Sigor@sysoev.ru #ifdef NXT_PHP7 5680Sigor@sysoev.ru static size_t 5690Sigor@sysoev.ru nxt_php_read_post(char *buffer, size_t count_bytes TSRMLS_DC) 5700Sigor@sysoev.ru #else 5710Sigor@sysoev.ru static int 5720Sigor@sysoev.ru nxt_php_read_post(char *buffer, uint count_bytes TSRMLS_DC) 5730Sigor@sysoev.ru #endif 5740Sigor@sysoev.ru { 575206Smax.romanov@nginx.com size_t size, rest; 57686Smax.romanov@nginx.com nxt_php_run_ctx_t *ctx; 57786Smax.romanov@nginx.com nxt_app_request_header_t *h; 5780Sigor@sysoev.ru 57986Smax.romanov@nginx.com ctx = SG(server_context); 58086Smax.romanov@nginx.com h = &ctx->r.header; 5810Sigor@sysoev.ru 582206Smax.romanov@nginx.com rest = (size_t) h->parsed_content_length - SG(read_post_bytes); 58386Smax.romanov@nginx.com 58486Smax.romanov@nginx.com nxt_debug(ctx->task, "nxt_php_read_post %O", rest); 5850Sigor@sysoev.ru 5860Sigor@sysoev.ru if (rest == 0) { 5870Sigor@sysoev.ru return 0; 5880Sigor@sysoev.ru } 5890Sigor@sysoev.ru 590206Smax.romanov@nginx.com rest = nxt_min(ctx->body_preread_size, (size_t) count_bytes); 591206Smax.romanov@nginx.com size = nxt_app_msg_read_raw(ctx->task, ctx->rmsg, buffer, rest); 5920Sigor@sysoev.ru 593206Smax.romanov@nginx.com ctx->body_preread_size -= size; 5940Sigor@sysoev.ru 59586Smax.romanov@nginx.com return size; 5960Sigor@sysoev.ru } 5970Sigor@sysoev.ru 5980Sigor@sysoev.ru 5990Sigor@sysoev.ru static char * 6000Sigor@sysoev.ru nxt_php_read_cookies(TSRMLS_D) 6010Sigor@sysoev.ru { 60286Smax.romanov@nginx.com nxt_php_run_ctx_t *ctx; 6030Sigor@sysoev.ru 60486Smax.romanov@nginx.com ctx = SG(server_context); 6050Sigor@sysoev.ru 60694Smax.romanov@nginx.com nxt_debug(ctx->task, "nxt_php_read_cookies"); 60794Smax.romanov@nginx.com 60886Smax.romanov@nginx.com return (char *) ctx->r.header.cookie.start; 6090Sigor@sysoev.ru } 6100Sigor@sysoev.ru 6110Sigor@sysoev.ru 6120Sigor@sysoev.ru static void 6130Sigor@sysoev.ru nxt_php_register_variables(zval *track_vars_array TSRMLS_DC) 6140Sigor@sysoev.ru { 615114Smax.romanov@nginx.com u_char *colon; 61686Smax.romanov@nginx.com nxt_str_t n, v; 61786Smax.romanov@nginx.com nxt_int_t rc; 618114Smax.romanov@nginx.com nxt_str_t host, server_name, server_port; 61986Smax.romanov@nginx.com nxt_task_t *task; 62086Smax.romanov@nginx.com nxt_php_run_ctx_t *ctx; 62186Smax.romanov@nginx.com nxt_app_request_header_t *h; 6220Sigor@sysoev.ru 623114Smax.romanov@nginx.com static nxt_str_t def_host = nxt_string("localhost"); 624114Smax.romanov@nginx.com static nxt_str_t def_port = nxt_string("80"); 625114Smax.romanov@nginx.com 62686Smax.romanov@nginx.com ctx = SG(server_context); 6270Sigor@sysoev.ru 62886Smax.romanov@nginx.com h = &ctx->r.header; 62986Smax.romanov@nginx.com task = ctx->task; 6300Sigor@sysoev.ru 63186Smax.romanov@nginx.com nxt_debug(task, "php register variables"); 6320Sigor@sysoev.ru 633114Smax.romanov@nginx.com #define NXT_PHP_SET(n, v) \ 634142Smax.romanov@nginx.com nxt_debug(task, "php: register %s='%V'", n, &v); \ 635114Smax.romanov@nginx.com php_register_variable_safe((char *) (n), (char *) (v).start, \ 636114Smax.romanov@nginx.com (v).length, track_vars_array TSRMLS_CC) \ 637114Smax.romanov@nginx.com 638114Smax.romanov@nginx.com NXT_PHP_SET("SERVER_PROTOCOL", h->version); 63986Smax.romanov@nginx.com 64086Smax.romanov@nginx.com /* 64186Smax.romanov@nginx.com * 'SCRIPT_NAME' 64286Smax.romanov@nginx.com * Contains the current script's path. This is useful for pages which need to 64386Smax.romanov@nginx.com * point to themselves. The __FILE__ constant contains the full path and 64486Smax.romanov@nginx.com * filename of the current (i.e. included) file. 64586Smax.romanov@nginx.com */ 64686Smax.romanov@nginx.com 64786Smax.romanov@nginx.com /* 64886Smax.romanov@nginx.com * 'SCRIPT_FILENAME' 64986Smax.romanov@nginx.com * The absolute pathname of the currently executing script. 65086Smax.romanov@nginx.com */ 65186Smax.romanov@nginx.com 65286Smax.romanov@nginx.com /* 65386Smax.romanov@nginx.com * 'DOCUMENT_ROOT' 65486Smax.romanov@nginx.com * The document root directory under which the current script is executing, 65586Smax.romanov@nginx.com * as defined in the server's configuration file. 65686Smax.romanov@nginx.com */ 6570Sigor@sysoev.ru 65886Smax.romanov@nginx.com if (nxt_php_script.start != NULL) { 65986Smax.romanov@nginx.com // ABS_MODE 66086Smax.romanov@nginx.com /* 66186Smax.romanov@nginx.com * 'PHP_SELF' 66286Smax.romanov@nginx.com * The filename of the currently executing script, relative to the document 66386Smax.romanov@nginx.com * root. For instance, $_SERVER['PHP_SELF'] in a script at the address 66486Smax.romanov@nginx.com * http://example.com/foo/bar.php would be /foo/bar.php. The __FILE__ constant 66586Smax.romanov@nginx.com * contains the full path and filename of the current (i.e. included) file. 66686Smax.romanov@nginx.com * If PHP is running as a command-line processor this variable contains the 66786Smax.romanov@nginx.com * script name since PHP 4.3.0. Previously it was not available. 66886Smax.romanov@nginx.com */ 669114Smax.romanov@nginx.com NXT_PHP_SET("PHP_SELF", nxt_php_script); 670114Smax.romanov@nginx.com NXT_PHP_SET("SCRIPT_NAME", nxt_php_script); 67186Smax.romanov@nginx.com } else { 672114Smax.romanov@nginx.com NXT_PHP_SET("PHP_SELF", h->path); 673114Smax.romanov@nginx.com NXT_PHP_SET("SCRIPT_NAME", h->path); 67486Smax.romanov@nginx.com } 6750Sigor@sysoev.ru 676114Smax.romanov@nginx.com NXT_PHP_SET("SCRIPT_FILENAME", ctx->script); 677114Smax.romanov@nginx.com NXT_PHP_SET("DOCUMENT_ROOT", nxt_php_root); 6780Sigor@sysoev.ru 679114Smax.romanov@nginx.com NXT_PHP_SET("REQUEST_METHOD", h->method); 680114Smax.romanov@nginx.com NXT_PHP_SET("REQUEST_URI", h->target); 6810Sigor@sysoev.ru 68286Smax.romanov@nginx.com if (h->query.start != NULL) { 683114Smax.romanov@nginx.com NXT_PHP_SET("QUERY_STRING", h->query); 6840Sigor@sysoev.ru } 6850Sigor@sysoev.ru 68686Smax.romanov@nginx.com if (h->content_type.start != NULL) { 687114Smax.romanov@nginx.com NXT_PHP_SET("CONTENT_TYPE", h->content_type); 6880Sigor@sysoev.ru } 6890Sigor@sysoev.ru 69086Smax.romanov@nginx.com if (h->content_length.start != NULL) { 691114Smax.romanov@nginx.com NXT_PHP_SET("CONTENT_LENGTH", h->content_length); 692114Smax.romanov@nginx.com } 693114Smax.romanov@nginx.com 694114Smax.romanov@nginx.com host = h->host; 695114Smax.romanov@nginx.com if (host.length == 0) { 696114Smax.romanov@nginx.com host = def_host; 69786Smax.romanov@nginx.com } 6980Sigor@sysoev.ru 699114Smax.romanov@nginx.com server_name = host; 700114Smax.romanov@nginx.com colon = nxt_memchr(host.start, ':', host.length); 701114Smax.romanov@nginx.com 702114Smax.romanov@nginx.com if (colon != NULL) { 703114Smax.romanov@nginx.com server_name.length = colon - host.start; 704114Smax.romanov@nginx.com 705114Smax.romanov@nginx.com server_port.start = colon + 1; 706114Smax.romanov@nginx.com server_port.length = host.length - server_name.length - 1; 707114Smax.romanov@nginx.com } else { 708114Smax.romanov@nginx.com server_port = def_port; 709114Smax.romanov@nginx.com } 710114Smax.romanov@nginx.com 711114Smax.romanov@nginx.com NXT_PHP_SET("SERVER_NAME", server_name); 712114Smax.romanov@nginx.com NXT_PHP_SET("SERVER_PORT", server_port); 713114Smax.romanov@nginx.com 714114Smax.romanov@nginx.com NXT_PHP_SET("REMOTE_ADDR", ctx->r.remote); 715114Smax.romanov@nginx.com 71694Smax.romanov@nginx.com while (nxt_app_msg_read_str(task, ctx->rmsg, &n) == NXT_OK) { 71786Smax.romanov@nginx.com if (nxt_slow_path(n.length == 0)) { 71886Smax.romanov@nginx.com break; 7190Sigor@sysoev.ru } 7200Sigor@sysoev.ru 72194Smax.romanov@nginx.com rc = nxt_app_msg_read_str(task, ctx->rmsg, &v); 72294Smax.romanov@nginx.com if (nxt_slow_path(rc != NXT_OK)) { 72394Smax.romanov@nginx.com break; 72494Smax.romanov@nginx.com } 72594Smax.romanov@nginx.com 726114Smax.romanov@nginx.com NXT_PHP_SET(n.start, v); 7270Sigor@sysoev.ru } 728114Smax.romanov@nginx.com 729206Smax.romanov@nginx.com nxt_app_msg_read_size(task, ctx->rmsg, &ctx->body_preread_size); 730206Smax.romanov@nginx.com 731114Smax.romanov@nginx.com #undef NXT_PHP_SET 7320Sigor@sysoev.ru } 7330Sigor@sysoev.ru 7340Sigor@sysoev.ru 7350Sigor@sysoev.ru static void 73686Smax.romanov@nginx.com nxt_php_log_message(char *message 73786Smax.romanov@nginx.com #ifdef NXT_HAVE_PHP_LOG_MESSAGE_WITH_SYSLOG_TYPE 73886Smax.romanov@nginx.com , int syslog_type_int 73986Smax.romanov@nginx.com #endif 74086Smax.romanov@nginx.com ) 7410Sigor@sysoev.ru { 7420Sigor@sysoev.ru return; 7430Sigor@sysoev.ru } 744