1/* 2 * Copyright (C) Max Romanov 3 * Copyright (C) Valentin V. Bartenev 4 * Copyright (C) NGINX, Inc. 5 */ 6 7#include "php.h" 8#include "SAPI.h" 9#include "php_main.h" 10#include "php_variables.h" 11 12#include <nxt_main.h> 13#include <nxt_router.h> 14#include <nxt_unit.h> 15#include <nxt_unit_request.h> 16 17 18#if PHP_MAJOR_VERSION >= 7 19# define NXT_PHP7 1 20# if PHP_MINOR_VERSION >= 1 21# define NXT_HAVE_PHP_LOG_MESSAGE_WITH_SYSLOG_TYPE 1 22# else 23# define NXT_HAVE_PHP_INTERRUPTS 1 24# endif 25# define NXT_HAVE_PHP_IGNORE_CWD 1 26#else 27# define NXT_HAVE_PHP_INTERRUPTS 1 28# if PHP_MINOR_VERSION >= 4 29# define NXT_HAVE_PHP_IGNORE_CWD 1 30# endif 31#endif 32 33 34typedef struct nxt_php_run_ctx_s nxt_php_run_ctx_t; 35 36#ifdef NXT_PHP7 37typedef int (*nxt_php_disable_t)(char *p, size_t size); 38#else 39typedef int (*nxt_php_disable_t)(char *p, uint TSRMLS_DC); 40#endif 41 42 43static nxt_int_t nxt_php_init(nxt_task_t *task, nxt_common_app_conf_t *conf); 44 45static void nxt_php_str_trim_trail(nxt_str_t *str, u_char t); 46static void nxt_php_str_trim_lead(nxt_str_t *str, u_char t); 47nxt_inline u_char *nxt_realpath(const void *c); 48 49static void nxt_php_request_handler(nxt_unit_request_info_t *req); 50 51static int nxt_php_startup(sapi_module_struct *sapi_module); 52static void nxt_php_set_options(nxt_task_t *task, nxt_conf_value_t *options, 53 int type); 54static nxt_int_t nxt_php_alter_option(nxt_str_t *name, nxt_str_t *value, 55 int type); 56static void nxt_php_disable(nxt_task_t *task, const char *type, 57 nxt_str_t *value, char **ptr, nxt_php_disable_t disable); 58static int nxt_php_send_headers(sapi_headers_struct *sapi_headers TSRMLS_DC); 59static char *nxt_php_read_cookies(TSRMLS_D); 60static void nxt_php_set_sptr(nxt_unit_request_info_t *req, const char *name, 61 nxt_unit_sptr_t *v, uint32_t len, zval *track_vars_array TSRMLS_DC); 62nxt_inline void nxt_php_set_str(nxt_unit_request_info_t *req, const char *name, 63 nxt_str_t *s, zval *track_vars_array TSRMLS_DC); 64static void nxt_php_set_cstr(nxt_unit_request_info_t *req, const char *name, 65 const char *str, uint32_t len, zval *track_vars_array TSRMLS_DC); 66static void nxt_php_register_variables(zval *track_vars_array TSRMLS_DC); 67#ifdef NXT_HAVE_PHP_LOG_MESSAGE_WITH_SYSLOG_TYPE 68static void nxt_php_log_message(char *message, int syslog_type_int); 69#else 70static void nxt_php_log_message(char *message TSRMLS_DC); 71#endif 72 73#ifdef NXT_PHP7 74static size_t nxt_php_unbuffered_write(const char *str, 75 size_t str_length TSRMLS_DC); 76static size_t nxt_php_read_post(char *buffer, size_t count_bytes TSRMLS_DC); 77#else 78static int nxt_php_unbuffered_write(const char *str, uint str_length TSRMLS_DC); 79static int nxt_php_read_post(char *buffer, uint count_bytes TSRMLS_DC); 80#endif 81 82 83static sapi_module_struct nxt_php_sapi_module = 84{ 85 (char *) "cli-server", 86 (char *) "unit", 87 88 nxt_php_startup, /* startup */ 89 php_module_shutdown_wrapper, /* shutdown */ 90 91 NULL, /* activate */ 92 NULL, /* deactivate */ 93 94 nxt_php_unbuffered_write, /* unbuffered write */ 95 NULL, /* flush */ 96 NULL, /* get uid */ 97 NULL, /* getenv */ 98 99 php_error, /* error handler */ 100 101 NULL, /* header handler */ 102 nxt_php_send_headers, /* send headers handler */ 103 NULL, /* send header handler */ 104 105 nxt_php_read_post, /* read POST data */ 106 nxt_php_read_cookies, /* read Cookies */ 107 108 nxt_php_register_variables, /* register server variables */ 109 nxt_php_log_message, /* log message */ 110 NULL, /* get request time */ 111 NULL, /* terminate process */ 112 113 NULL, /* php_ini_path_override */ 114#ifdef NXT_HAVE_PHP_INTERRUPTS 115 NULL, /* block_interruptions */ 116 NULL, /* unblock_interruptions */ 117#endif 118 NULL, /* default_post_reader */ 119 NULL, /* treat_data */ 120 NULL, /* executable_location */ 121 122 0, /* php_ini_ignore */ 123#ifdef NXT_HAVE_PHP_IGNORE_CWD 124 1, /* php_ini_ignore_cwd */ 125#endif 126 NULL, /* get_fd */ 127 128 NULL, /* force_http_10 */ 129 130 NULL, /* get_target_uid */ 131 NULL, /* get_target_gid */ 132 133 NULL, /* input_filter */ 134 135 NULL, /* ini_defaults */ 136 0, /* phpinfo_as_text */ 137 138 NULL, /* ini_entries */ 139 NULL, /* additional_functions */ 140 NULL /* input_filter_init */ 141}; 142 143 144struct nxt_php_run_ctx_s { 145 char *cookie; 146 nxt_str_t path_info; 147 nxt_str_t script_name; 148 nxt_str_t script_filename; 149 nxt_unit_request_info_t *req; 150}; 151 152 153static nxt_str_t nxt_php_root; 154static nxt_str_t nxt_php_script_name; 155static nxt_str_t nxt_php_script_filename; 156static nxt_str_t nxt_php_index = nxt_string("index.php"); 157 158 159static uint32_t compat[] = { 160 NXT_VERNUM, NXT_DEBUG, 161}; 162 163 164NXT_EXPORT nxt_app_module_t nxt_app_module = { 165 sizeof(compat), 166 compat, 167 nxt_string("php"), 168 PHP_VERSION, 169 NULL, 170 nxt_php_init, 171}; 172 173 174static nxt_task_t *nxt_php_task; 175#ifdef ZTS 176static void ***tsrm_ls; 177#endif 178 179 180static nxt_int_t 181nxt_php_init(nxt_task_t *task, nxt_common_app_conf_t *conf) 182{
| 1/* 2 * Copyright (C) Max Romanov 3 * Copyright (C) Valentin V. Bartenev 4 * Copyright (C) NGINX, Inc. 5 */ 6 7#include "php.h" 8#include "SAPI.h" 9#include "php_main.h" 10#include "php_variables.h" 11 12#include <nxt_main.h> 13#include <nxt_router.h> 14#include <nxt_unit.h> 15#include <nxt_unit_request.h> 16 17 18#if PHP_MAJOR_VERSION >= 7 19# define NXT_PHP7 1 20# if PHP_MINOR_VERSION >= 1 21# define NXT_HAVE_PHP_LOG_MESSAGE_WITH_SYSLOG_TYPE 1 22# else 23# define NXT_HAVE_PHP_INTERRUPTS 1 24# endif 25# define NXT_HAVE_PHP_IGNORE_CWD 1 26#else 27# define NXT_HAVE_PHP_INTERRUPTS 1 28# if PHP_MINOR_VERSION >= 4 29# define NXT_HAVE_PHP_IGNORE_CWD 1 30# endif 31#endif 32 33 34typedef struct nxt_php_run_ctx_s nxt_php_run_ctx_t; 35 36#ifdef NXT_PHP7 37typedef int (*nxt_php_disable_t)(char *p, size_t size); 38#else 39typedef int (*nxt_php_disable_t)(char *p, uint TSRMLS_DC); 40#endif 41 42 43static nxt_int_t nxt_php_init(nxt_task_t *task, nxt_common_app_conf_t *conf); 44 45static void nxt_php_str_trim_trail(nxt_str_t *str, u_char t); 46static void nxt_php_str_trim_lead(nxt_str_t *str, u_char t); 47nxt_inline u_char *nxt_realpath(const void *c); 48 49static void nxt_php_request_handler(nxt_unit_request_info_t *req); 50 51static int nxt_php_startup(sapi_module_struct *sapi_module); 52static void nxt_php_set_options(nxt_task_t *task, nxt_conf_value_t *options, 53 int type); 54static nxt_int_t nxt_php_alter_option(nxt_str_t *name, nxt_str_t *value, 55 int type); 56static void nxt_php_disable(nxt_task_t *task, const char *type, 57 nxt_str_t *value, char **ptr, nxt_php_disable_t disable); 58static int nxt_php_send_headers(sapi_headers_struct *sapi_headers TSRMLS_DC); 59static char *nxt_php_read_cookies(TSRMLS_D); 60static void nxt_php_set_sptr(nxt_unit_request_info_t *req, const char *name, 61 nxt_unit_sptr_t *v, uint32_t len, zval *track_vars_array TSRMLS_DC); 62nxt_inline void nxt_php_set_str(nxt_unit_request_info_t *req, const char *name, 63 nxt_str_t *s, zval *track_vars_array TSRMLS_DC); 64static void nxt_php_set_cstr(nxt_unit_request_info_t *req, const char *name, 65 const char *str, uint32_t len, zval *track_vars_array TSRMLS_DC); 66static void nxt_php_register_variables(zval *track_vars_array TSRMLS_DC); 67#ifdef NXT_HAVE_PHP_LOG_MESSAGE_WITH_SYSLOG_TYPE 68static void nxt_php_log_message(char *message, int syslog_type_int); 69#else 70static void nxt_php_log_message(char *message TSRMLS_DC); 71#endif 72 73#ifdef NXT_PHP7 74static size_t nxt_php_unbuffered_write(const char *str, 75 size_t str_length TSRMLS_DC); 76static size_t nxt_php_read_post(char *buffer, size_t count_bytes TSRMLS_DC); 77#else 78static int nxt_php_unbuffered_write(const char *str, uint str_length TSRMLS_DC); 79static int nxt_php_read_post(char *buffer, uint count_bytes TSRMLS_DC); 80#endif 81 82 83static sapi_module_struct nxt_php_sapi_module = 84{ 85 (char *) "cli-server", 86 (char *) "unit", 87 88 nxt_php_startup, /* startup */ 89 php_module_shutdown_wrapper, /* shutdown */ 90 91 NULL, /* activate */ 92 NULL, /* deactivate */ 93 94 nxt_php_unbuffered_write, /* unbuffered write */ 95 NULL, /* flush */ 96 NULL, /* get uid */ 97 NULL, /* getenv */ 98 99 php_error, /* error handler */ 100 101 NULL, /* header handler */ 102 nxt_php_send_headers, /* send headers handler */ 103 NULL, /* send header handler */ 104 105 nxt_php_read_post, /* read POST data */ 106 nxt_php_read_cookies, /* read Cookies */ 107 108 nxt_php_register_variables, /* register server variables */ 109 nxt_php_log_message, /* log message */ 110 NULL, /* get request time */ 111 NULL, /* terminate process */ 112 113 NULL, /* php_ini_path_override */ 114#ifdef NXT_HAVE_PHP_INTERRUPTS 115 NULL, /* block_interruptions */ 116 NULL, /* unblock_interruptions */ 117#endif 118 NULL, /* default_post_reader */ 119 NULL, /* treat_data */ 120 NULL, /* executable_location */ 121 122 0, /* php_ini_ignore */ 123#ifdef NXT_HAVE_PHP_IGNORE_CWD 124 1, /* php_ini_ignore_cwd */ 125#endif 126 NULL, /* get_fd */ 127 128 NULL, /* force_http_10 */ 129 130 NULL, /* get_target_uid */ 131 NULL, /* get_target_gid */ 132 133 NULL, /* input_filter */ 134 135 NULL, /* ini_defaults */ 136 0, /* phpinfo_as_text */ 137 138 NULL, /* ini_entries */ 139 NULL, /* additional_functions */ 140 NULL /* input_filter_init */ 141}; 142 143 144struct nxt_php_run_ctx_s { 145 char *cookie; 146 nxt_str_t path_info; 147 nxt_str_t script_name; 148 nxt_str_t script_filename; 149 nxt_unit_request_info_t *req; 150}; 151 152 153static nxt_str_t nxt_php_root; 154static nxt_str_t nxt_php_script_name; 155static nxt_str_t nxt_php_script_filename; 156static nxt_str_t nxt_php_index = nxt_string("index.php"); 157 158 159static uint32_t compat[] = { 160 NXT_VERNUM, NXT_DEBUG, 161}; 162 163 164NXT_EXPORT nxt_app_module_t nxt_app_module = { 165 sizeof(compat), 166 compat, 167 nxt_string("php"), 168 PHP_VERSION, 169 NULL, 170 nxt_php_init, 171}; 172 173 174static nxt_task_t *nxt_php_task; 175#ifdef ZTS 176static void ***tsrm_ls; 177#endif 178 179 180static nxt_int_t 181nxt_php_init(nxt_task_t *task, nxt_common_app_conf_t *conf) 182{
|
242 243 script_filename->length = nxt_strlen(script_filename->start); 244 245 if (!nxt_str_start(script_filename, root->start, root->length)) { 246 nxt_alert(task, "script is not under php root"); 247 return NXT_ERROR; 248 } 249 250 script_name->length = c->script.length + 1; 251 script_name->start = nxt_malloc(script_name->length); 252 if (nxt_slow_path(script_name->start == NULL)) { 253 return NXT_ERROR; 254 } 255 256 script_name->start[0] = '/'; 257 nxt_memcpy(script_name->start + 1, c->script.start, c->script.length); 258 259 nxt_log_error(NXT_LOG_INFO, task->log, 260 "(ABS_MODE) php script \"%V\" root: \"%V\"", 261 script_name, root); 262 263 } else { 264 nxt_log_error(NXT_LOG_INFO, task->log, 265 "(non ABS_MODE) php root: \"%V\"", root); 266 } 267 268 if (c->index.length > 0) { 269 index->length = c->index.length; 270 index->start = nxt_malloc(index->length); 271 if (nxt_slow_path(index->start == NULL)) { 272 return NXT_ERROR; 273 } 274 275 nxt_memcpy(index->start, c->index.start, c->index.length); 276 } 277 278#ifdef ZTS 279 tsrm_startup(1, 1, 0, NULL); 280 tsrm_ls = ts_resource(0); 281#endif 282 283#if defined(NXT_PHP7) && defined(ZEND_SIGNALS) 284 285#if (NXT_ZEND_SIGNAL_STARTUP) 286 zend_signal_startup(); 287#elif defined(ZTS) 288#error PHP is built with thread safety and broken signals. 289#endif 290 291#endif 292 293 sapi_startup(&nxt_php_sapi_module); 294 295 if (c->options != NULL) { 296 value = nxt_conf_get_object_member(c->options, &file_str, NULL); 297 298 if (value != NULL) { 299 nxt_conf_get_string(value, &ini_path); 300 301 p = nxt_malloc(ini_path.length + 1); 302 if (nxt_slow_path(p == NULL)) { 303 return NXT_ERROR; 304 } 305 306 nxt_php_sapi_module.php_ini_path_override = (char *) p; 307 308 p = nxt_cpymem(p, ini_path.start, ini_path.length); 309 *p = '\0'; 310 } 311 } 312 313 nxt_php_startup(&nxt_php_sapi_module); 314 315 if (c->options != NULL) { 316 value = nxt_conf_get_object_member(c->options, &admin_str, NULL); 317 nxt_php_set_options(task, value, ZEND_INI_SYSTEM); 318 319 value = nxt_conf_get_object_member(c->options, &user_str, NULL); 320 nxt_php_set_options(task, value, ZEND_INI_USER); 321 } 322 323 nxt_memzero(&php_init, sizeof(nxt_unit_init_t)); 324 325 rt = task->thread->runtime; 326 327 main_port = rt->port_by_type[NXT_PROCESS_MAIN]; 328 if (nxt_slow_path(main_port == NULL)) { 329 return NXT_ERROR; 330 } 331 332 my_port = nxt_runtime_port_find(rt, nxt_pid, 0); 333 if (nxt_slow_path(my_port == NULL)) { 334 return NXT_ERROR; 335 } 336 337 php_init.callbacks.request_handler = nxt_php_request_handler; 338 php_init.ready_port.id.pid = main_port->pid; 339 php_init.ready_port.id.id = main_port->id; 340 php_init.ready_port.out_fd = main_port->pair[1]; 341 342 nxt_fd_blocking(task, main_port->pair[1]); 343 344 php_init.ready_stream = my_port->process->init->stream; 345 346 php_init.read_port.id.pid = my_port->pid; 347 php_init.read_port.id.id = my_port->id; 348 php_init.read_port.in_fd = my_port->pair[0]; 349 350 nxt_fd_blocking(task, my_port->pair[0]); 351 352 php_init.log_fd = 2; 353 354 unit_ctx = nxt_unit_init(&php_init); 355 if (nxt_slow_path(unit_ctx == NULL)) { 356 return NXT_ERROR; 357 } 358 359 nxt_unit_run(unit_ctx); 360 361 nxt_unit_done(unit_ctx); 362 363 exit(0); 364 365 return NXT_OK; 366} 367 368 369static void 370nxt_php_set_options(nxt_task_t *task, nxt_conf_value_t *options, int type) 371{ 372 uint32_t next; 373 nxt_str_t name, value; 374 nxt_conf_value_t *value_obj; 375 376 if (options != NULL) { 377 next = 0; 378 379 for ( ;; ) { 380 value_obj = nxt_conf_next_object_member(options, &name, &next); 381 if (value_obj == NULL) { 382 break; 383 } 384 385 nxt_conf_get_string(value_obj, &value); 386 387 if (nxt_php_alter_option(&name, &value, type) != NXT_OK) { 388 nxt_log(task, NXT_LOG_ERR, 389 "setting PHP option \"%V: %V\" failed", &name, &value); 390 continue; 391 } 392 393 if (nxt_str_eq(&name, "disable_functions", 17)) { 394 nxt_php_disable(task, "function", &value, 395 &PG(disable_functions), 396 zend_disable_function); 397 continue; 398 } 399 400 if (nxt_str_eq(&name, "disable_classes", 15)) { 401 nxt_php_disable(task, "class", &value, 402 &PG(disable_classes), 403 zend_disable_class); 404 continue; 405 } 406 } 407 } 408} 409 410 411#if (NXT_PHP7) 412 413static nxt_int_t 414nxt_php_alter_option(nxt_str_t *name, nxt_str_t *value, int type) 415{ 416 zend_string *zs; 417 zend_ini_entry *ini_entry; 418 419 ini_entry = zend_hash_str_find_ptr(EG(ini_directives), 420 (char *) name->start, name->length); 421 422 if (ini_entry == NULL) { 423 return NXT_ERROR; 424 } 425 426 /* PHP exits on memory allocation errors. */ 427 zs = zend_string_init((char *) value->start, value->length, 1); 428 429 if (ini_entry->on_modify 430 && ini_entry->on_modify(ini_entry, zs, ini_entry->mh_arg1, 431 ini_entry->mh_arg2, ini_entry->mh_arg3, 432 ZEND_INI_STAGE_ACTIVATE) 433 != SUCCESS) 434 { 435 zend_string_release(zs); 436 return NXT_ERROR; 437 } 438 439 ini_entry->value = zs; 440 ini_entry->modifiable = type; 441 442 return NXT_OK; 443} 444 445#else /* PHP 5. */ 446 447static nxt_int_t 448nxt_php_alter_option(nxt_str_t *name, nxt_str_t *value, int type) 449{ 450 char *cstr; 451 zend_ini_entry *ini_entry; 452 char buf[256]; 453 454 if (nxt_slow_path(name->length >= sizeof(buf))) { 455 return NXT_ERROR; 456 } 457 458 nxt_memcpy(buf, name->start, name->length); 459 buf[name->length] = '\0'; 460 461 if (zend_hash_find(EG(ini_directives), buf, name->length + 1, 462 (void **) &ini_entry) 463 == FAILURE) 464 { 465 return NXT_ERROR; 466 } 467 468 cstr = nxt_malloc(value->length + 1); 469 if (nxt_slow_path(cstr == NULL)) { 470 return NXT_ERROR; 471 } 472 473 nxt_memcpy(cstr, value->start, value->length); 474 cstr[value->length] = '\0'; 475 476 if (ini_entry->on_modify 477 && ini_entry->on_modify(ini_entry, cstr, value->length, 478 ini_entry->mh_arg1, ini_entry->mh_arg2, 479 ini_entry->mh_arg3, ZEND_INI_STAGE_ACTIVATE 480 TSRMLS_CC) 481 != SUCCESS) 482 { 483 nxt_free(cstr); 484 return NXT_ERROR; 485 } 486 487 ini_entry->value = cstr; 488 ini_entry->value_length = value->length; 489 ini_entry->modifiable = type; 490 491 return NXT_OK; 492} 493 494#endif 495 496 497static void 498nxt_php_disable(nxt_task_t *task, const char *type, nxt_str_t *value, 499 char **ptr, nxt_php_disable_t disable) 500{ 501 char c, *p, *start; 502 503 p = nxt_malloc(value->length + 1); 504 if (nxt_slow_path(p == NULL)) { 505 return; 506 } 507 508 /* 509 * PHP frees this memory on module shutdown. 510 * See core_globals_dtor() for details. 511 */ 512 *ptr = p; 513 514 nxt_memcpy(p, value->start, value->length); 515 p[value->length] = '\0'; 516 517 start = p; 518 519 do { 520 c = *p; 521 522 if (c == ' ' || c == ',' || c == '\0') { 523 524 if (p != start) { 525 *p = '\0'; 526 527#ifdef NXT_PHP7 528 if (disable(start, p - start) 529#else 530 if (disable(start, p - start TSRMLS_CC) 531#endif 532 != SUCCESS) 533 { 534 nxt_log(task, NXT_LOG_ERR, 535 "PHP: failed to disable \"%s\": no such %s", 536 start, type); 537 } 538 } 539 540 start = p + 1; 541 } 542 543 p++; 544 545 } while (c != '\0'); 546} 547 548 549static void 550nxt_php_str_trim_trail(nxt_str_t *str, u_char t) 551{ 552 while (str->length > 0 && str->start[str->length - 1] == t) { 553 str->length--; 554 } 555 556 str->start[str->length] = '\0'; 557} 558 559 560static void 561nxt_php_str_trim_lead(nxt_str_t *str, u_char t) 562{ 563 while (str->length > 0 && str->start[0] == t) { 564 str->length--; 565 str->start++; 566 } 567} 568 569 570nxt_inline u_char * 571nxt_realpath(const void *c) 572{ 573 return (u_char *) realpath(c, NULL); 574} 575 576 577static void 578nxt_php_request_handler(nxt_unit_request_info_t *req) 579{ 580 int rc; 581 u_char *p; 582 nxt_str_t path, script_name; 583 nxt_unit_field_t *f; 584 zend_file_handle file_handle; 585 nxt_php_run_ctx_t run_ctx, *ctx; 586 nxt_unit_request_t *r; 587 588 nxt_memzero(&run_ctx, sizeof(run_ctx)); 589 590 ctx = &run_ctx; 591 ctx->req = req; 592 593 r = req->request; 594 595 path.length = r->path_length; 596 path.start = nxt_unit_sptr_get(&r->path); 597 598 if (nxt_php_script_filename.start == NULL) { 599 ctx->path_info.start = (u_char *) strstr((char *) path.start, ".php/"); 600 if (ctx->path_info.start != NULL) { 601 ctx->path_info.start += 4; 602 path.length = ctx->path_info.start - path.start; 603 604 ctx->path_info.length = r->path_length - path.length; 605 } 606 607 if (path.start[path.length - 1] == '/') { 608 script_name = nxt_php_index; 609 610 } else { 611 script_name.length = 0; 612 script_name.start = NULL; 613 } 614 615 ctx->script_filename.length = nxt_php_root.length + path.length 616 + script_name.length; 617 p = nxt_malloc(ctx->script_filename.length + 1); 618 if (nxt_slow_path(p == NULL)) { 619 nxt_unit_request_done(req, NXT_UNIT_ERROR); 620 621 return; 622 } 623 624 ctx->script_filename.start = p; 625 626 ctx->script_name.length = path.length + script_name.length; 627 ctx->script_name.start = p + nxt_php_root.length; 628 629 p = nxt_cpymem(p, nxt_php_root.start, nxt_php_root.length); 630 p = nxt_cpymem(p, path.start, path.length); 631 632 if (script_name.length > 0) { 633 p = nxt_cpymem(p, script_name.start, script_name.length); 634 } 635 636 *p = '\0'; 637 638 } else { 639 ctx->script_filename = nxt_php_script_filename; 640 ctx->script_name = nxt_php_script_name; 641 } 642 643 SG(server_context) = ctx; 644 SG(request_info).request_uri = nxt_unit_sptr_get(&r->target); 645 SG(request_info).request_method = nxt_unit_sptr_get(&r->method); 646 647 SG(request_info).proto_num = 1001; 648 649 SG(request_info).query_string = r->query.offset 650 ? nxt_unit_sptr_get(&r->query) : NULL; 651 SG(request_info).content_length = r->content_length; 652 653 if (r->content_type_field != NXT_UNIT_NONE_FIELD) { 654 f = r->fields + r->content_type_field; 655 656 SG(request_info).content_type = nxt_unit_sptr_get(&f->value); 657 } 658 659 if (r->cookie_field != NXT_UNIT_NONE_FIELD) { 660 f = r->fields + r->cookie_field; 661 662 ctx->cookie = nxt_unit_sptr_get(&f->value); 663 } 664 665 SG(sapi_headers).http_response_code = 200; 666 667 SG(request_info).path_translated = NULL; 668 669 file_handle.type = ZEND_HANDLE_FILENAME; 670 file_handle.filename = (char *) ctx->script_filename.start; 671 file_handle.free_filename = 0; 672 file_handle.opened_path = NULL; 673 674 nxt_unit_req_debug(req, "handle.filename = '%s'", 675 ctx->script_filename.start); 676 677 if (nxt_php_script_filename.start != NULL) { 678 nxt_unit_req_debug(req, "run script %.*s in absolute mode", 679 (int) nxt_php_script_filename.length, 680 (char *) nxt_php_script_filename.start); 681 682 } else { 683 nxt_unit_req_debug(req, "run script %.*s", 684 (int) ctx->script_filename.length, 685 (char *) ctx->script_filename.start); 686 } 687 688#if (NXT_PHP7) 689 if (nxt_slow_path(php_request_startup() == FAILURE)) { 690#else 691 if (nxt_slow_path(php_request_startup(TSRMLS_C) == FAILURE)) { 692#endif 693 nxt_unit_req_debug(req, "php_request_startup() failed"); 694 rc = NXT_UNIT_ERROR; 695 696 goto fail; 697 } 698 699 rc = NXT_UNIT_OK; 700 701 php_execute_script(&file_handle TSRMLS_CC); 702 php_request_shutdown(NULL); 703 704fail: 705 706 nxt_unit_request_done(req, rc); 707 708 if (ctx->script_filename.start != nxt_php_script_filename.start) { 709 nxt_free(ctx->script_filename.start); 710 } 711} 712 713 714static int 715nxt_php_startup(sapi_module_struct *sapi_module) 716{ 717 return php_module_startup(sapi_module, NULL, 0); 718} 719 720 721#ifdef NXT_PHP7 722static size_t 723nxt_php_unbuffered_write(const char *str, size_t str_length TSRMLS_DC) 724#else 725static int 726nxt_php_unbuffered_write(const char *str, uint str_length TSRMLS_DC) 727#endif 728{ 729 int rc; 730 nxt_php_run_ctx_t *ctx; 731 732 ctx = SG(server_context); 733 734 rc = nxt_unit_response_write(ctx->req, str, str_length); 735 if (nxt_fast_path(rc == NXT_UNIT_OK)) { 736 return str_length; 737 } 738 739 php_handle_aborted_connection(); 740 return 0; 741} 742 743 744static int 745nxt_php_send_headers(sapi_headers_struct *sapi_headers TSRMLS_DC) 746{ 747 int rc, fields_count; 748 char *colon, *value; 749 uint16_t status; 750 uint32_t resp_size; 751 nxt_php_run_ctx_t *ctx; 752 sapi_header_struct *h; 753 zend_llist_position zpos; 754 nxt_unit_request_info_t *req; 755 756 ctx = SG(server_context); 757 req = ctx->req; 758 759 nxt_unit_req_debug(req, "nxt_php_send_headers"); 760 761 if (SG(request_info).no_headers == 1) { 762 rc = nxt_unit_response_init(req, 200, 0, 0); 763 if (nxt_slow_path(rc != NXT_UNIT_OK)) { 764 return SAPI_HEADER_SEND_FAILED; 765 } 766 767 return SAPI_HEADER_SENT_SUCCESSFULLY; 768 } 769 770 resp_size = 0; 771 fields_count = zend_llist_count(&sapi_headers->headers); 772 773 for (h = zend_llist_get_first_ex(&sapi_headers->headers, &zpos); 774 h; 775 h = zend_llist_get_next_ex(&sapi_headers->headers, &zpos)) 776 { 777 resp_size += h->header_len; 778 } 779 780 status = SG(sapi_headers).http_response_code; 781 782 rc = nxt_unit_response_init(req, status, fields_count, resp_size); 783 if (nxt_slow_path(rc != NXT_UNIT_OK)) { 784 return SAPI_HEADER_SEND_FAILED; 785 } 786 787 for (h = zend_llist_get_first_ex(&sapi_headers->headers, &zpos); 788 h; 789 h = zend_llist_get_next_ex(&sapi_headers->headers, &zpos)) 790 { 791 colon = memchr(h->header, ':', h->header_len); 792 if (nxt_slow_path(colon == NULL)) { 793 nxt_unit_req_warn(req, "colon not found in header '%.*s'", 794 (int) h->header_len, h->header); 795 continue; 796 } 797 798 value = colon + 1; 799 while(isspace(*value)) { 800 value++; 801 } 802 803 nxt_unit_response_add_field(req, h->header, colon - h->header, 804 value, 805 h->header_len - (value - h->header)); 806 } 807 808 rc = nxt_unit_response_send(req); 809 if (nxt_slow_path(rc != NXT_UNIT_OK)) { 810 nxt_unit_req_debug(req, "failed to send response"); 811 812 return SAPI_HEADER_SEND_FAILED; 813 } 814 815 return SAPI_HEADER_SENT_SUCCESSFULLY; 816} 817 818 819#ifdef NXT_PHP7 820static size_t 821nxt_php_read_post(char *buffer, size_t count_bytes TSRMLS_DC) 822#else 823static int 824nxt_php_read_post(char *buffer, uint count_bytes TSRMLS_DC) 825#endif 826{ 827 nxt_php_run_ctx_t *ctx; 828 829 ctx = SG(server_context); 830 831 nxt_unit_req_debug(ctx->req, "nxt_php_read_post %d", (int) count_bytes); 832 833 return nxt_unit_request_read(ctx->req, buffer, count_bytes); 834} 835 836 837static char * 838nxt_php_read_cookies(TSRMLS_D) 839{ 840 nxt_php_run_ctx_t *ctx; 841 842 ctx = SG(server_context); 843 844 nxt_unit_req_debug(ctx->req, "nxt_php_read_cookies"); 845 846 return ctx->cookie; 847} 848 849 850static void 851nxt_php_register_variables(zval *track_vars_array TSRMLS_DC) 852{ 853 const char *name; 854 nxt_unit_field_t *f, *f_end; 855 nxt_php_run_ctx_t *ctx; 856 nxt_unit_request_t *r; 857 nxt_unit_request_info_t *req; 858 859 ctx = SG(server_context); 860 861 req = ctx->req; 862 r = req->request; 863 864 nxt_unit_req_debug(req, "nxt_php_register_variables"); 865 866 php_register_variable_safe((char *) "SERVER_SOFTWARE", 867 (char *) nxt_server.start, 868 nxt_server.length, track_vars_array TSRMLS_CC); 869 870 nxt_php_set_sptr(req, "SERVER_PROTOCOL", &r->version, r->version_length, 871 track_vars_array TSRMLS_CC); 872 873 /* 874 * 'PHP_SELF' 875 * The filename of the currently executing script, relative to the document 876 * root. For instance, $_SERVER['PHP_SELF'] in a script at the address 877 * http://example.com/foo/bar.php would be /foo/bar.php. The __FILE__ 878 * constant contains the full path and filename of the current (i.e. 879 * included) file. If PHP is running as a command-line processor this 880 * variable contains the script name since PHP 4.3.0. Previously it was not 881 * available. 882 */ 883 884 if (nxt_php_script_name.start != NULL) { 885 /* ABS_MODE */ 886 nxt_php_set_str(req, "PHP_SELF", &nxt_php_script_name, 887 track_vars_array TSRMLS_CC); 888 889 } else { 890 nxt_php_set_sptr(req, "PHP_SELF", &r->path, r->path_length, 891 track_vars_array TSRMLS_CC); 892 } 893 894 if (ctx->path_info.length != 0) { 895 nxt_php_set_str(req, "PATH_INFO", &ctx->path_info, 896 track_vars_array TSRMLS_CC); 897 } 898 899 /* 900 * 'SCRIPT_NAME' 901 * Contains the current script's path. This is useful for pages which need 902 * to point to themselves. The __FILE__ constant contains the full path and 903 * filename of the current (i.e. included) file. 904 */ 905 906 nxt_php_set_str(req, "SCRIPT_NAME", &ctx->script_name, 907 track_vars_array TSRMLS_CC); 908 909 /* 910 * 'SCRIPT_FILENAME' 911 * The absolute pathname of the currently executing script. 912 */ 913 914 nxt_php_set_str(req, "SCRIPT_FILENAME", &ctx->script_filename, 915 track_vars_array TSRMLS_CC); 916 917 /* 918 * 'DOCUMENT_ROOT' 919 * The document root directory under which the current script is executing, 920 * as defined in the server's configuration file. 921 */ 922 923 nxt_php_set_str(req, "DOCUMENT_ROOT", &nxt_php_root, 924 track_vars_array TSRMLS_CC); 925 926 nxt_php_set_sptr(req, "REQUEST_METHOD", &r->method, r->method_length, 927 track_vars_array TSRMLS_CC); 928 nxt_php_set_sptr(req, "REQUEST_URI", &r->target, r->target_length, 929 track_vars_array TSRMLS_CC); 930 nxt_php_set_sptr(req, "QUERY_STRING", &r->query, r->query_length, 931 track_vars_array TSRMLS_CC); 932 933 nxt_php_set_sptr(req, "REMOTE_ADDR", &r->remote, r->remote_length, 934 track_vars_array TSRMLS_CC); 935 nxt_php_set_sptr(req, "SERVER_ADDR", &r->local, r->local_length, 936 track_vars_array TSRMLS_CC); 937 938 nxt_php_set_sptr(req, "SERVER_NAME", &r->server_name, r->server_name_length, 939 track_vars_array TSRMLS_CC); 940 nxt_php_set_cstr(req, "SERVER_PORT", "80", 2, track_vars_array TSRMLS_CC); 941 942 if (r->tls) { 943 nxt_php_set_cstr(req, "HTTPS", "on", 2, track_vars_array TSRMLS_CC); 944 } 945 946 f_end = r->fields + r->fields_count; 947 for (f = r->fields; f < f_end; f++) { 948 name = nxt_unit_sptr_get(&f->name); 949 950 nxt_php_set_sptr(req, name, &f->value, f->value_length, 951 track_vars_array TSRMLS_CC); 952 } 953 954 if (r->content_length_field != NXT_UNIT_NONE_FIELD) { 955 f = r->fields + r->content_length_field; 956 957 nxt_php_set_sptr(req, "CONTENT_LENGTH", &f->value, f->value_length, 958 track_vars_array TSRMLS_CC); 959 } 960 961 if (r->content_type_field != NXT_UNIT_NONE_FIELD) { 962 f = r->fields + r->content_type_field; 963 964 nxt_php_set_sptr(req, "CONTENT_TYPE", &f->value, f->value_length, 965 track_vars_array TSRMLS_CC); 966 } 967} 968 969 970static void 971nxt_php_set_sptr(nxt_unit_request_info_t *req, const char *name, 972 nxt_unit_sptr_t *v, uint32_t len, zval *track_vars_array TSRMLS_DC) 973{ 974 char *str; 975 976 str = nxt_unit_sptr_get(v); 977 978 nxt_unit_req_debug(req, "php: register %s='%.*s'", name, (int) len, str); 979 980 php_register_variable_safe((char *) name, str, len, 981 track_vars_array TSRMLS_CC); 982} 983 984 985nxt_inline void 986nxt_php_set_str(nxt_unit_request_info_t *req, const char *name, 987 nxt_str_t *s, zval *track_vars_array TSRMLS_DC) 988{ 989 nxt_php_set_cstr(req, name, (char *) s->start, s->length, 990 track_vars_array TSRMLS_CC); 991} 992 993 994static void 995nxt_php_set_cstr(nxt_unit_request_info_t *req, const char *name, 996 const char *cstr, uint32_t len, zval *track_vars_array TSRMLS_DC) 997{ 998 if (nxt_slow_path(cstr == NULL)) { 999 return; 1000 } 1001 1002 nxt_unit_req_debug(req, "php: register %s='%.*s'", name, (int) len, cstr); 1003 1004 php_register_variable_safe((char *) name, (char *) cstr, len, 1005 track_vars_array TSRMLS_CC); 1006} 1007 1008 1009#ifdef NXT_HAVE_PHP_LOG_MESSAGE_WITH_SYSLOG_TYPE 1010static void 1011nxt_php_log_message(char *message, int syslog_type_int) 1012#else 1013static void 1014nxt_php_log_message(char *message TSRMLS_DC) 1015#endif 1016{ 1017 nxt_log(nxt_php_task, NXT_LOG_NOTICE, "php message: %s", message); 1018}
| 244 245 script_filename->length = nxt_strlen(script_filename->start); 246 247 if (!nxt_str_start(script_filename, root->start, root->length)) { 248 nxt_alert(task, "script is not under php root"); 249 return NXT_ERROR; 250 } 251 252 script_name->length = c->script.length + 1; 253 script_name->start = nxt_malloc(script_name->length); 254 if (nxt_slow_path(script_name->start == NULL)) { 255 return NXT_ERROR; 256 } 257 258 script_name->start[0] = '/'; 259 nxt_memcpy(script_name->start + 1, c->script.start, c->script.length); 260 261 nxt_log_error(NXT_LOG_INFO, task->log, 262 "(ABS_MODE) php script \"%V\" root: \"%V\"", 263 script_name, root); 264 265 } else { 266 nxt_log_error(NXT_LOG_INFO, task->log, 267 "(non ABS_MODE) php root: \"%V\"", root); 268 } 269 270 if (c->index.length > 0) { 271 index->length = c->index.length; 272 index->start = nxt_malloc(index->length); 273 if (nxt_slow_path(index->start == NULL)) { 274 return NXT_ERROR; 275 } 276 277 nxt_memcpy(index->start, c->index.start, c->index.length); 278 } 279 280#ifdef ZTS 281 tsrm_startup(1, 1, 0, NULL); 282 tsrm_ls = ts_resource(0); 283#endif 284 285#if defined(NXT_PHP7) && defined(ZEND_SIGNALS) 286 287#if (NXT_ZEND_SIGNAL_STARTUP) 288 zend_signal_startup(); 289#elif defined(ZTS) 290#error PHP is built with thread safety and broken signals. 291#endif 292 293#endif 294 295 sapi_startup(&nxt_php_sapi_module); 296 297 if (c->options != NULL) { 298 value = nxt_conf_get_object_member(c->options, &file_str, NULL); 299 300 if (value != NULL) { 301 nxt_conf_get_string(value, &ini_path); 302 303 p = nxt_malloc(ini_path.length + 1); 304 if (nxt_slow_path(p == NULL)) { 305 return NXT_ERROR; 306 } 307 308 nxt_php_sapi_module.php_ini_path_override = (char *) p; 309 310 p = nxt_cpymem(p, ini_path.start, ini_path.length); 311 *p = '\0'; 312 } 313 } 314 315 nxt_php_startup(&nxt_php_sapi_module); 316 317 if (c->options != NULL) { 318 value = nxt_conf_get_object_member(c->options, &admin_str, NULL); 319 nxt_php_set_options(task, value, ZEND_INI_SYSTEM); 320 321 value = nxt_conf_get_object_member(c->options, &user_str, NULL); 322 nxt_php_set_options(task, value, ZEND_INI_USER); 323 } 324 325 nxt_memzero(&php_init, sizeof(nxt_unit_init_t)); 326 327 rt = task->thread->runtime; 328 329 main_port = rt->port_by_type[NXT_PROCESS_MAIN]; 330 if (nxt_slow_path(main_port == NULL)) { 331 return NXT_ERROR; 332 } 333 334 my_port = nxt_runtime_port_find(rt, nxt_pid, 0); 335 if (nxt_slow_path(my_port == NULL)) { 336 return NXT_ERROR; 337 } 338 339 php_init.callbacks.request_handler = nxt_php_request_handler; 340 php_init.ready_port.id.pid = main_port->pid; 341 php_init.ready_port.id.id = main_port->id; 342 php_init.ready_port.out_fd = main_port->pair[1]; 343 344 nxt_fd_blocking(task, main_port->pair[1]); 345 346 php_init.ready_stream = my_port->process->init->stream; 347 348 php_init.read_port.id.pid = my_port->pid; 349 php_init.read_port.id.id = my_port->id; 350 php_init.read_port.in_fd = my_port->pair[0]; 351 352 nxt_fd_blocking(task, my_port->pair[0]); 353 354 php_init.log_fd = 2; 355 356 unit_ctx = nxt_unit_init(&php_init); 357 if (nxt_slow_path(unit_ctx == NULL)) { 358 return NXT_ERROR; 359 } 360 361 nxt_unit_run(unit_ctx); 362 363 nxt_unit_done(unit_ctx); 364 365 exit(0); 366 367 return NXT_OK; 368} 369 370 371static void 372nxt_php_set_options(nxt_task_t *task, nxt_conf_value_t *options, int type) 373{ 374 uint32_t next; 375 nxt_str_t name, value; 376 nxt_conf_value_t *value_obj; 377 378 if (options != NULL) { 379 next = 0; 380 381 for ( ;; ) { 382 value_obj = nxt_conf_next_object_member(options, &name, &next); 383 if (value_obj == NULL) { 384 break; 385 } 386 387 nxt_conf_get_string(value_obj, &value); 388 389 if (nxt_php_alter_option(&name, &value, type) != NXT_OK) { 390 nxt_log(task, NXT_LOG_ERR, 391 "setting PHP option \"%V: %V\" failed", &name, &value); 392 continue; 393 } 394 395 if (nxt_str_eq(&name, "disable_functions", 17)) { 396 nxt_php_disable(task, "function", &value, 397 &PG(disable_functions), 398 zend_disable_function); 399 continue; 400 } 401 402 if (nxt_str_eq(&name, "disable_classes", 15)) { 403 nxt_php_disable(task, "class", &value, 404 &PG(disable_classes), 405 zend_disable_class); 406 continue; 407 } 408 } 409 } 410} 411 412 413#if (NXT_PHP7) 414 415static nxt_int_t 416nxt_php_alter_option(nxt_str_t *name, nxt_str_t *value, int type) 417{ 418 zend_string *zs; 419 zend_ini_entry *ini_entry; 420 421 ini_entry = zend_hash_str_find_ptr(EG(ini_directives), 422 (char *) name->start, name->length); 423 424 if (ini_entry == NULL) { 425 return NXT_ERROR; 426 } 427 428 /* PHP exits on memory allocation errors. */ 429 zs = zend_string_init((char *) value->start, value->length, 1); 430 431 if (ini_entry->on_modify 432 && ini_entry->on_modify(ini_entry, zs, ini_entry->mh_arg1, 433 ini_entry->mh_arg2, ini_entry->mh_arg3, 434 ZEND_INI_STAGE_ACTIVATE) 435 != SUCCESS) 436 { 437 zend_string_release(zs); 438 return NXT_ERROR; 439 } 440 441 ini_entry->value = zs; 442 ini_entry->modifiable = type; 443 444 return NXT_OK; 445} 446 447#else /* PHP 5. */ 448 449static nxt_int_t 450nxt_php_alter_option(nxt_str_t *name, nxt_str_t *value, int type) 451{ 452 char *cstr; 453 zend_ini_entry *ini_entry; 454 char buf[256]; 455 456 if (nxt_slow_path(name->length >= sizeof(buf))) { 457 return NXT_ERROR; 458 } 459 460 nxt_memcpy(buf, name->start, name->length); 461 buf[name->length] = '\0'; 462 463 if (zend_hash_find(EG(ini_directives), buf, name->length + 1, 464 (void **) &ini_entry) 465 == FAILURE) 466 { 467 return NXT_ERROR; 468 } 469 470 cstr = nxt_malloc(value->length + 1); 471 if (nxt_slow_path(cstr == NULL)) { 472 return NXT_ERROR; 473 } 474 475 nxt_memcpy(cstr, value->start, value->length); 476 cstr[value->length] = '\0'; 477 478 if (ini_entry->on_modify 479 && ini_entry->on_modify(ini_entry, cstr, value->length, 480 ini_entry->mh_arg1, ini_entry->mh_arg2, 481 ini_entry->mh_arg3, ZEND_INI_STAGE_ACTIVATE 482 TSRMLS_CC) 483 != SUCCESS) 484 { 485 nxt_free(cstr); 486 return NXT_ERROR; 487 } 488 489 ini_entry->value = cstr; 490 ini_entry->value_length = value->length; 491 ini_entry->modifiable = type; 492 493 return NXT_OK; 494} 495 496#endif 497 498 499static void 500nxt_php_disable(nxt_task_t *task, const char *type, nxt_str_t *value, 501 char **ptr, nxt_php_disable_t disable) 502{ 503 char c, *p, *start; 504 505 p = nxt_malloc(value->length + 1); 506 if (nxt_slow_path(p == NULL)) { 507 return; 508 } 509 510 /* 511 * PHP frees this memory on module shutdown. 512 * See core_globals_dtor() for details. 513 */ 514 *ptr = p; 515 516 nxt_memcpy(p, value->start, value->length); 517 p[value->length] = '\0'; 518 519 start = p; 520 521 do { 522 c = *p; 523 524 if (c == ' ' || c == ',' || c == '\0') { 525 526 if (p != start) { 527 *p = '\0'; 528 529#ifdef NXT_PHP7 530 if (disable(start, p - start) 531#else 532 if (disable(start, p - start TSRMLS_CC) 533#endif 534 != SUCCESS) 535 { 536 nxt_log(task, NXT_LOG_ERR, 537 "PHP: failed to disable \"%s\": no such %s", 538 start, type); 539 } 540 } 541 542 start = p + 1; 543 } 544 545 p++; 546 547 } while (c != '\0'); 548} 549 550 551static void 552nxt_php_str_trim_trail(nxt_str_t *str, u_char t) 553{ 554 while (str->length > 0 && str->start[str->length - 1] == t) { 555 str->length--; 556 } 557 558 str->start[str->length] = '\0'; 559} 560 561 562static void 563nxt_php_str_trim_lead(nxt_str_t *str, u_char t) 564{ 565 while (str->length > 0 && str->start[0] == t) { 566 str->length--; 567 str->start++; 568 } 569} 570 571 572nxt_inline u_char * 573nxt_realpath(const void *c) 574{ 575 return (u_char *) realpath(c, NULL); 576} 577 578 579static void 580nxt_php_request_handler(nxt_unit_request_info_t *req) 581{ 582 int rc; 583 u_char *p; 584 nxt_str_t path, script_name; 585 nxt_unit_field_t *f; 586 zend_file_handle file_handle; 587 nxt_php_run_ctx_t run_ctx, *ctx; 588 nxt_unit_request_t *r; 589 590 nxt_memzero(&run_ctx, sizeof(run_ctx)); 591 592 ctx = &run_ctx; 593 ctx->req = req; 594 595 r = req->request; 596 597 path.length = r->path_length; 598 path.start = nxt_unit_sptr_get(&r->path); 599 600 if (nxt_php_script_filename.start == NULL) { 601 ctx->path_info.start = (u_char *) strstr((char *) path.start, ".php/"); 602 if (ctx->path_info.start != NULL) { 603 ctx->path_info.start += 4; 604 path.length = ctx->path_info.start - path.start; 605 606 ctx->path_info.length = r->path_length - path.length; 607 } 608 609 if (path.start[path.length - 1] == '/') { 610 script_name = nxt_php_index; 611 612 } else { 613 script_name.length = 0; 614 script_name.start = NULL; 615 } 616 617 ctx->script_filename.length = nxt_php_root.length + path.length 618 + script_name.length; 619 p = nxt_malloc(ctx->script_filename.length + 1); 620 if (nxt_slow_path(p == NULL)) { 621 nxt_unit_request_done(req, NXT_UNIT_ERROR); 622 623 return; 624 } 625 626 ctx->script_filename.start = p; 627 628 ctx->script_name.length = path.length + script_name.length; 629 ctx->script_name.start = p + nxt_php_root.length; 630 631 p = nxt_cpymem(p, nxt_php_root.start, nxt_php_root.length); 632 p = nxt_cpymem(p, path.start, path.length); 633 634 if (script_name.length > 0) { 635 p = nxt_cpymem(p, script_name.start, script_name.length); 636 } 637 638 *p = '\0'; 639 640 } else { 641 ctx->script_filename = nxt_php_script_filename; 642 ctx->script_name = nxt_php_script_name; 643 } 644 645 SG(server_context) = ctx; 646 SG(request_info).request_uri = nxt_unit_sptr_get(&r->target); 647 SG(request_info).request_method = nxt_unit_sptr_get(&r->method); 648 649 SG(request_info).proto_num = 1001; 650 651 SG(request_info).query_string = r->query.offset 652 ? nxt_unit_sptr_get(&r->query) : NULL; 653 SG(request_info).content_length = r->content_length; 654 655 if (r->content_type_field != NXT_UNIT_NONE_FIELD) { 656 f = r->fields + r->content_type_field; 657 658 SG(request_info).content_type = nxt_unit_sptr_get(&f->value); 659 } 660 661 if (r->cookie_field != NXT_UNIT_NONE_FIELD) { 662 f = r->fields + r->cookie_field; 663 664 ctx->cookie = nxt_unit_sptr_get(&f->value); 665 } 666 667 SG(sapi_headers).http_response_code = 200; 668 669 SG(request_info).path_translated = NULL; 670 671 file_handle.type = ZEND_HANDLE_FILENAME; 672 file_handle.filename = (char *) ctx->script_filename.start; 673 file_handle.free_filename = 0; 674 file_handle.opened_path = NULL; 675 676 nxt_unit_req_debug(req, "handle.filename = '%s'", 677 ctx->script_filename.start); 678 679 if (nxt_php_script_filename.start != NULL) { 680 nxt_unit_req_debug(req, "run script %.*s in absolute mode", 681 (int) nxt_php_script_filename.length, 682 (char *) nxt_php_script_filename.start); 683 684 } else { 685 nxt_unit_req_debug(req, "run script %.*s", 686 (int) ctx->script_filename.length, 687 (char *) ctx->script_filename.start); 688 } 689 690#if (NXT_PHP7) 691 if (nxt_slow_path(php_request_startup() == FAILURE)) { 692#else 693 if (nxt_slow_path(php_request_startup(TSRMLS_C) == FAILURE)) { 694#endif 695 nxt_unit_req_debug(req, "php_request_startup() failed"); 696 rc = NXT_UNIT_ERROR; 697 698 goto fail; 699 } 700 701 rc = NXT_UNIT_OK; 702 703 php_execute_script(&file_handle TSRMLS_CC); 704 php_request_shutdown(NULL); 705 706fail: 707 708 nxt_unit_request_done(req, rc); 709 710 if (ctx->script_filename.start != nxt_php_script_filename.start) { 711 nxt_free(ctx->script_filename.start); 712 } 713} 714 715 716static int 717nxt_php_startup(sapi_module_struct *sapi_module) 718{ 719 return php_module_startup(sapi_module, NULL, 0); 720} 721 722 723#ifdef NXT_PHP7 724static size_t 725nxt_php_unbuffered_write(const char *str, size_t str_length TSRMLS_DC) 726#else 727static int 728nxt_php_unbuffered_write(const char *str, uint str_length TSRMLS_DC) 729#endif 730{ 731 int rc; 732 nxt_php_run_ctx_t *ctx; 733 734 ctx = SG(server_context); 735 736 rc = nxt_unit_response_write(ctx->req, str, str_length); 737 if (nxt_fast_path(rc == NXT_UNIT_OK)) { 738 return str_length; 739 } 740 741 php_handle_aborted_connection(); 742 return 0; 743} 744 745 746static int 747nxt_php_send_headers(sapi_headers_struct *sapi_headers TSRMLS_DC) 748{ 749 int rc, fields_count; 750 char *colon, *value; 751 uint16_t status; 752 uint32_t resp_size; 753 nxt_php_run_ctx_t *ctx; 754 sapi_header_struct *h; 755 zend_llist_position zpos; 756 nxt_unit_request_info_t *req; 757 758 ctx = SG(server_context); 759 req = ctx->req; 760 761 nxt_unit_req_debug(req, "nxt_php_send_headers"); 762 763 if (SG(request_info).no_headers == 1) { 764 rc = nxt_unit_response_init(req, 200, 0, 0); 765 if (nxt_slow_path(rc != NXT_UNIT_OK)) { 766 return SAPI_HEADER_SEND_FAILED; 767 } 768 769 return SAPI_HEADER_SENT_SUCCESSFULLY; 770 } 771 772 resp_size = 0; 773 fields_count = zend_llist_count(&sapi_headers->headers); 774 775 for (h = zend_llist_get_first_ex(&sapi_headers->headers, &zpos); 776 h; 777 h = zend_llist_get_next_ex(&sapi_headers->headers, &zpos)) 778 { 779 resp_size += h->header_len; 780 } 781 782 status = SG(sapi_headers).http_response_code; 783 784 rc = nxt_unit_response_init(req, status, fields_count, resp_size); 785 if (nxt_slow_path(rc != NXT_UNIT_OK)) { 786 return SAPI_HEADER_SEND_FAILED; 787 } 788 789 for (h = zend_llist_get_first_ex(&sapi_headers->headers, &zpos); 790 h; 791 h = zend_llist_get_next_ex(&sapi_headers->headers, &zpos)) 792 { 793 colon = memchr(h->header, ':', h->header_len); 794 if (nxt_slow_path(colon == NULL)) { 795 nxt_unit_req_warn(req, "colon not found in header '%.*s'", 796 (int) h->header_len, h->header); 797 continue; 798 } 799 800 value = colon + 1; 801 while(isspace(*value)) { 802 value++; 803 } 804 805 nxt_unit_response_add_field(req, h->header, colon - h->header, 806 value, 807 h->header_len - (value - h->header)); 808 } 809 810 rc = nxt_unit_response_send(req); 811 if (nxt_slow_path(rc != NXT_UNIT_OK)) { 812 nxt_unit_req_debug(req, "failed to send response"); 813 814 return SAPI_HEADER_SEND_FAILED; 815 } 816 817 return SAPI_HEADER_SENT_SUCCESSFULLY; 818} 819 820 821#ifdef NXT_PHP7 822static size_t 823nxt_php_read_post(char *buffer, size_t count_bytes TSRMLS_DC) 824#else 825static int 826nxt_php_read_post(char *buffer, uint count_bytes TSRMLS_DC) 827#endif 828{ 829 nxt_php_run_ctx_t *ctx; 830 831 ctx = SG(server_context); 832 833 nxt_unit_req_debug(ctx->req, "nxt_php_read_post %d", (int) count_bytes); 834 835 return nxt_unit_request_read(ctx->req, buffer, count_bytes); 836} 837 838 839static char * 840nxt_php_read_cookies(TSRMLS_D) 841{ 842 nxt_php_run_ctx_t *ctx; 843 844 ctx = SG(server_context); 845 846 nxt_unit_req_debug(ctx->req, "nxt_php_read_cookies"); 847 848 return ctx->cookie; 849} 850 851 852static void 853nxt_php_register_variables(zval *track_vars_array TSRMLS_DC) 854{ 855 const char *name; 856 nxt_unit_field_t *f, *f_end; 857 nxt_php_run_ctx_t *ctx; 858 nxt_unit_request_t *r; 859 nxt_unit_request_info_t *req; 860 861 ctx = SG(server_context); 862 863 req = ctx->req; 864 r = req->request; 865 866 nxt_unit_req_debug(req, "nxt_php_register_variables"); 867 868 php_register_variable_safe((char *) "SERVER_SOFTWARE", 869 (char *) nxt_server.start, 870 nxt_server.length, track_vars_array TSRMLS_CC); 871 872 nxt_php_set_sptr(req, "SERVER_PROTOCOL", &r->version, r->version_length, 873 track_vars_array TSRMLS_CC); 874 875 /* 876 * 'PHP_SELF' 877 * The filename of the currently executing script, relative to the document 878 * root. For instance, $_SERVER['PHP_SELF'] in a script at the address 879 * http://example.com/foo/bar.php would be /foo/bar.php. The __FILE__ 880 * constant contains the full path and filename of the current (i.e. 881 * included) file. If PHP is running as a command-line processor this 882 * variable contains the script name since PHP 4.3.0. Previously it was not 883 * available. 884 */ 885 886 if (nxt_php_script_name.start != NULL) { 887 /* ABS_MODE */ 888 nxt_php_set_str(req, "PHP_SELF", &nxt_php_script_name, 889 track_vars_array TSRMLS_CC); 890 891 } else { 892 nxt_php_set_sptr(req, "PHP_SELF", &r->path, r->path_length, 893 track_vars_array TSRMLS_CC); 894 } 895 896 if (ctx->path_info.length != 0) { 897 nxt_php_set_str(req, "PATH_INFO", &ctx->path_info, 898 track_vars_array TSRMLS_CC); 899 } 900 901 /* 902 * 'SCRIPT_NAME' 903 * Contains the current script's path. This is useful for pages which need 904 * to point to themselves. The __FILE__ constant contains the full path and 905 * filename of the current (i.e. included) file. 906 */ 907 908 nxt_php_set_str(req, "SCRIPT_NAME", &ctx->script_name, 909 track_vars_array TSRMLS_CC); 910 911 /* 912 * 'SCRIPT_FILENAME' 913 * The absolute pathname of the currently executing script. 914 */ 915 916 nxt_php_set_str(req, "SCRIPT_FILENAME", &ctx->script_filename, 917 track_vars_array TSRMLS_CC); 918 919 /* 920 * 'DOCUMENT_ROOT' 921 * The document root directory under which the current script is executing, 922 * as defined in the server's configuration file. 923 */ 924 925 nxt_php_set_str(req, "DOCUMENT_ROOT", &nxt_php_root, 926 track_vars_array TSRMLS_CC); 927 928 nxt_php_set_sptr(req, "REQUEST_METHOD", &r->method, r->method_length, 929 track_vars_array TSRMLS_CC); 930 nxt_php_set_sptr(req, "REQUEST_URI", &r->target, r->target_length, 931 track_vars_array TSRMLS_CC); 932 nxt_php_set_sptr(req, "QUERY_STRING", &r->query, r->query_length, 933 track_vars_array TSRMLS_CC); 934 935 nxt_php_set_sptr(req, "REMOTE_ADDR", &r->remote, r->remote_length, 936 track_vars_array TSRMLS_CC); 937 nxt_php_set_sptr(req, "SERVER_ADDR", &r->local, r->local_length, 938 track_vars_array TSRMLS_CC); 939 940 nxt_php_set_sptr(req, "SERVER_NAME", &r->server_name, r->server_name_length, 941 track_vars_array TSRMLS_CC); 942 nxt_php_set_cstr(req, "SERVER_PORT", "80", 2, track_vars_array TSRMLS_CC); 943 944 if (r->tls) { 945 nxt_php_set_cstr(req, "HTTPS", "on", 2, track_vars_array TSRMLS_CC); 946 } 947 948 f_end = r->fields + r->fields_count; 949 for (f = r->fields; f < f_end; f++) { 950 name = nxt_unit_sptr_get(&f->name); 951 952 nxt_php_set_sptr(req, name, &f->value, f->value_length, 953 track_vars_array TSRMLS_CC); 954 } 955 956 if (r->content_length_field != NXT_UNIT_NONE_FIELD) { 957 f = r->fields + r->content_length_field; 958 959 nxt_php_set_sptr(req, "CONTENT_LENGTH", &f->value, f->value_length, 960 track_vars_array TSRMLS_CC); 961 } 962 963 if (r->content_type_field != NXT_UNIT_NONE_FIELD) { 964 f = r->fields + r->content_type_field; 965 966 nxt_php_set_sptr(req, "CONTENT_TYPE", &f->value, f->value_length, 967 track_vars_array TSRMLS_CC); 968 } 969} 970 971 972static void 973nxt_php_set_sptr(nxt_unit_request_info_t *req, const char *name, 974 nxt_unit_sptr_t *v, uint32_t len, zval *track_vars_array TSRMLS_DC) 975{ 976 char *str; 977 978 str = nxt_unit_sptr_get(v); 979 980 nxt_unit_req_debug(req, "php: register %s='%.*s'", name, (int) len, str); 981 982 php_register_variable_safe((char *) name, str, len, 983 track_vars_array TSRMLS_CC); 984} 985 986 987nxt_inline void 988nxt_php_set_str(nxt_unit_request_info_t *req, const char *name, 989 nxt_str_t *s, zval *track_vars_array TSRMLS_DC) 990{ 991 nxt_php_set_cstr(req, name, (char *) s->start, s->length, 992 track_vars_array TSRMLS_CC); 993} 994 995 996static void 997nxt_php_set_cstr(nxt_unit_request_info_t *req, const char *name, 998 const char *cstr, uint32_t len, zval *track_vars_array TSRMLS_DC) 999{ 1000 if (nxt_slow_path(cstr == NULL)) { 1001 return; 1002 } 1003 1004 nxt_unit_req_debug(req, "php: register %s='%.*s'", name, (int) len, cstr); 1005 1006 php_register_variable_safe((char *) name, (char *) cstr, len, 1007 track_vars_array TSRMLS_CC); 1008} 1009 1010 1011#ifdef NXT_HAVE_PHP_LOG_MESSAGE_WITH_SYSLOG_TYPE 1012static void 1013nxt_php_log_message(char *message, int syslog_type_int) 1014#else 1015static void 1016nxt_php_log_message(char *message TSRMLS_DC) 1017#endif 1018{ 1019 nxt_log(nxt_php_task, NXT_LOG_NOTICE, "php message: %s", message); 1020}
|