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