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 #include "ext/standard/php_standard.h"
12
13 #include <nxt_main.h>
14 #include <nxt_router.h>
15 #include <nxt_unit.h>
16 #include <nxt_unit_request.h>
17
18
19 #if PHP_VERSION_ID >= 50400
20 #define NXT_HAVE_PHP_IGNORE_CWD 1
21 #endif
22
23 #if PHP_VERSION_ID >= 70100
24 #define NXT_HAVE_PHP_LOG_MESSAGE_WITH_SYSLOG_TYPE 1
25 #else
26 #define NXT_HAVE_PHP_INTERRUPTS 1
27 #endif
28
29 #if PHP_VERSION_ID >= 70000
30 #define NXT_PHP7 1
31 #endif
32 #if PHP_VERSION_ID >= 80000
33 #define NXT_PHP8 1
34 #endif
35
36 /* PHP 8 */
37 #ifndef TSRMLS_CC
38 #define TSRMLS_CC
39 #define TSRMLS_DC
40 #define TSRMLS_D void
41 #define TSRMLS_C
42 #endif
43
44
45 typedef struct {
46 nxt_str_t root;
47 nxt_str_t index;
48 nxt_str_t script_name;
49 nxt_str_t script_dirname;
50 nxt_str_t script_filename;
51 } nxt_php_target_t;
52
53
54 typedef struct {
55 char *cookie;
56 nxt_str_t *root;
57 nxt_str_t *index;
58 nxt_str_t path_info;
59 nxt_str_t script_name;
60 nxt_str_t script_filename;
61 nxt_str_t script_dirname;
62 nxt_unit_request_info_t *req;
63
64 uint8_t chdir; /* 1 bit */
65 } nxt_php_run_ctx_t;
66
67
68 #if NXT_PHP8
69 typedef int (*nxt_php_disable_t)(const char *p, size_t size);
70 #elif NXT_PHP7
71 typedef int (*nxt_php_disable_t)(char *p, size_t size);
72 #else
73 typedef int (*nxt_php_disable_t)(char *p, uint TSRMLS_DC);
74 #endif
75
76 #if PHP_VERSION_ID < 70200
77 typedef void (*zif_handler)(INTERNAL_FUNCTION_PARAMETERS);
78 #endif
79
80
81 static nxt_int_t nxt_php_setup(nxt_task_t *task, nxt_process_t *process,
82 nxt_common_app_conf_t *conf);
83 static nxt_int_t nxt_php_start(nxt_task_t *task, nxt_process_data_t *data);
84 static nxt_int_t nxt_php_set_target(nxt_task_t *task, nxt_php_target_t *target,
85 nxt_conf_value_t *conf);
86 static nxt_int_t nxt_php_set_ini_path(nxt_task_t *task, nxt_str_t *path,
87 char *workdir);
88 static void nxt_php_set_options(nxt_task_t *task, nxt_conf_value_t *options,
89 int type);
90 static nxt_int_t nxt_php_alter_option(nxt_str_t *name, nxt_str_t *value,
91 int type);
92 #ifdef NXT_PHP8
93 static void nxt_php_disable_functions(nxt_str_t *str);
94 #endif
95 static void nxt_php_disable(nxt_task_t *task, const char *type,
96 nxt_str_t *value, char **ptr, nxt_php_disable_t disable);
97
98 static nxt_int_t nxt_php_dirname(const nxt_str_t *file, nxt_str_t *dir);
99 static void nxt_php_str_trim_trail(nxt_str_t *str, u_char t);
100 static void nxt_php_str_trim_lead(nxt_str_t *str, u_char t);
101 nxt_inline u_char *nxt_realpath(const void *c);
102
103 static void nxt_php_request_handler(nxt_unit_request_info_t *req);
104 static void nxt_php_dynamic_request(nxt_php_run_ctx_t *ctx,
105 nxt_unit_request_t *r);
106 static void nxt_php_execute(nxt_php_run_ctx_t *ctx, nxt_unit_request_t *r);
107 nxt_inline void nxt_php_vcwd_chdir(nxt_unit_request_info_t *req, u_char *dir);
108
109 static int nxt_php_startup(sapi_module_struct *sapi_module);
110 static int nxt_php_send_headers(sapi_headers_struct *sapi_headers TSRMLS_DC);
111 static void *nxt_php_hash_str_find_ptr(const HashTable *ht,
112 const nxt_str_t *str);
113 static char *nxt_php_read_cookies(TSRMLS_D);
114 static void nxt_php_set_sptr(nxt_unit_request_info_t *req, const char *name,
115 nxt_unit_sptr_t *v, uint32_t len, zval *track_vars_array TSRMLS_DC);
116 nxt_inline void nxt_php_set_str(nxt_unit_request_info_t *req, const char *name,
117 nxt_str_t *s, zval *track_vars_array TSRMLS_DC);
118 static void nxt_php_set_cstr(nxt_unit_request_info_t *req, const char *name,
119 const char *str, uint32_t len, zval *track_vars_array TSRMLS_DC);
120 static void nxt_php_register_variables(zval *track_vars_array TSRMLS_DC);
121 #if NXT_PHP8
122 static void nxt_php_log_message(const char *message, int syslog_type_int);
123 #else
124 #ifdef NXT_HAVE_PHP_LOG_MESSAGE_WITH_SYSLOG_TYPE
125 static void nxt_php_log_message(char *message, int syslog_type_int);
126 #else
127 static void nxt_php_log_message(char *message TSRMLS_DC);
128 #endif
129 #endif
130
131 #ifdef NXT_PHP7
132 static size_t nxt_php_unbuffered_write(const char *str,
133 size_t str_length TSRMLS_DC);
134 static size_t nxt_php_read_post(char *buffer, size_t count_bytes TSRMLS_DC);
135 #else
136 static int nxt_php_unbuffered_write(const char *str, uint str_length TSRMLS_DC);
137 static int nxt_php_read_post(char *buffer, uint count_bytes TSRMLS_DC);
138 #endif
139
140
141 #ifdef NXT_PHP7
142 #if PHP_VERSION_ID < 70200
143 ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_fastcgi_finish_request, 0, 0,
144 _IS_BOOL, NULL, 0)
145 #else
146 ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_fastcgi_finish_request, 0, 0,
147 _IS_BOOL, 0)
148 #endif
149 #else /* PHP5 */
150 ZEND_BEGIN_ARG_INFO_EX(arginfo_fastcgi_finish_request, 0, 0, 0)
151 #endif
152 ZEND_END_ARG_INFO()
153
154 ZEND_FUNCTION(fastcgi_finish_request);
155
156 PHP_MINIT_FUNCTION(nxt_php_ext);
157 ZEND_NAMED_FUNCTION(nxt_php_chdir);
158
159
160 static const zend_function_entry nxt_php_ext_functions[] = {
161 ZEND_FE(fastcgi_finish_request, arginfo_fastcgi_finish_request)
162 ZEND_FE_END
163 };
164
165
166 zif_handler nxt_php_chdir_handler;
167 zend_auto_global *nxt_php_server_ag;
168
169
170 static zend_module_entry nxt_php_unit_module = {
171 STANDARD_MODULE_HEADER,
172 "unit",
173 nxt_php_ext_functions, /* function table */
174 PHP_MINIT(nxt_php_ext), /* initialization */
175 NULL, /* shutdown */
176 NULL, /* request initialization */
177 NULL, /* request shutdown */
178 NULL, /* information */
179 NXT_VERSION,
180 STANDARD_MODULE_PROPERTIES
181 };
182
183
PHP_MINIT_FUNCTION(nxt_php_ext)184 PHP_MINIT_FUNCTION(nxt_php_ext)
185 {
186 zend_function *func;
187
188 static const nxt_str_t chdir = nxt_string("chdir");
189
190 func = nxt_php_hash_str_find_ptr(CG(function_table), &chdir);
191 if (nxt_slow_path(func == NULL)) {
192 return FAILURE;
193 }
194
195 nxt_php_chdir_handler = func->internal_function.handler;
196 func->internal_function.handler = nxt_php_chdir;
197
198 return SUCCESS;
199 }
200
201
ZEND_NAMED_FUNCTION(nxt_php_chdir)202 ZEND_NAMED_FUNCTION(nxt_php_chdir)
203 {
204 nxt_php_run_ctx_t *ctx;
205
206 ctx = SG(server_context);
207
208 if (nxt_fast_path(ctx != NULL)) {
209 ctx->chdir = 1;
210 }
211
212 nxt_php_chdir_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU);
213 }
214
215
PHP_FUNCTION(fastcgi_finish_request)216 PHP_FUNCTION(fastcgi_finish_request)
217 {
218 zend_auto_global *ag;
219 nxt_php_run_ctx_t *ctx;
220
221 if (nxt_slow_path(zend_parse_parameters_none() == FAILURE)) {
222 #ifdef NXT_PHP8
223 RETURN_THROWS();
224 #else
225 return;
226 #endif
227 }
228
229 ctx = SG(server_context);
230
231 if (nxt_slow_path(ctx == NULL || ctx->req == NULL)) {
232 RETURN_FALSE;
233 }
234
235 #ifdef NXT_PHP7
236 php_output_end_all();
237 php_header();
238 #else
239 #ifdef PHP_OUTPUT_NEWAPI
240 php_output_end_all(TSRMLS_C);
241 #else
242 php_end_ob_buffers(1 TSRMLS_CC);
243 #endif
244
245 php_header(TSRMLS_C);
246 #endif
247
248 ag = nxt_php_server_ag;
249
250 if (ag->armed) {
251 #ifdef NXT_PHP7
252 ag->armed = ag->auto_global_callback(ag->name);
253 #else
254 ag->armed = ag->auto_global_callback(ag->name, ag->name_len TSRMLS_CC);
255 #endif
256 }
257
258 nxt_unit_request_done(ctx->req, NXT_UNIT_OK);
259 ctx->req = NULL;
260
261 PG(connection_status) = PHP_CONNECTION_ABORTED;
262 #ifdef NXT_PHP7
263 php_output_set_status(PHP_OUTPUT_DISABLED);
264 #else
265 #ifdef PHP_OUTPUT_NEWAPI
266 php_output_set_status(PHP_OUTPUT_DISABLED TSRMLS_CC);
267 #else
268 php_output_set_status(0 TSRMLS_CC);
269 #endif
270 #endif
271
272 RETURN_TRUE;
273 }
274
275
276 static sapi_module_struct nxt_php_sapi_module =
277 {
278 (char *) "cli-server",
279 (char *) "unit",
280
281 nxt_php_startup, /* startup */
282 php_module_shutdown_wrapper, /* shutdown */
283
284 NULL, /* activate */
285 NULL, /* deactivate */
286
287 nxt_php_unbuffered_write, /* unbuffered write */
288 NULL, /* flush */
289 NULL, /* get uid */
290 NULL, /* getenv */
291
292 php_error, /* error handler */
293
294 NULL, /* header handler */
295 nxt_php_send_headers, /* send headers handler */
296 NULL, /* send header handler */
297
298 nxt_php_read_post, /* read POST data */
299 nxt_php_read_cookies, /* read Cookies */
300
301 nxt_php_register_variables, /* register server variables */
302 nxt_php_log_message, /* log message */
303 NULL, /* get request time */
304 NULL, /* terminate process */
305
306 NULL, /* php_ini_path_override */
307 #ifdef NXT_HAVE_PHP_INTERRUPTS
308 NULL, /* block_interruptions */
309 NULL, /* unblock_interruptions */
310 #endif
311 NULL, /* default_post_reader */
312 NULL, /* treat_data */
313 NULL, /* executable_location */
314
315 0, /* php_ini_ignore */
316 #ifdef NXT_HAVE_PHP_IGNORE_CWD
317 1, /* php_ini_ignore_cwd */
318 #endif
319 NULL, /* get_fd */
320
321 NULL, /* force_http_10 */
322
323 NULL, /* get_target_uid */
324 NULL, /* get_target_gid */
325
326 NULL, /* input_filter */
327
328 NULL, /* ini_defaults */
329 0, /* phpinfo_as_text */
330
331 NULL, /* ini_entries */
332 NULL, /* additional_functions */
333 NULL /* input_filter_init */
334 };
335
336
337 static uint32_t compat[] = {
338 NXT_VERNUM, NXT_DEBUG,
339 };
340
341
342 NXT_EXPORT nxt_app_module_t nxt_app_module = {
343 sizeof(compat),
344 compat,
345 nxt_string("php"),
346 PHP_VERSION,
347 NULL,
348 0,
349 nxt_php_setup,
350 nxt_php_start,
351 };
352
353
354 static nxt_php_target_t *nxt_php_targets;
355 static nxt_int_t nxt_php_last_target = -1;
356
357 static nxt_unit_ctx_t *nxt_php_unit_ctx;
358 #if defined(ZTS) && PHP_VERSION_ID < 70400
359 static void ***tsrm_ls;
360 #endif
361
362
363 static nxt_int_t
nxt_php_setup(nxt_task_t * task,nxt_process_t * process,nxt_common_app_conf_t * conf)364 nxt_php_setup(nxt_task_t *task, nxt_process_t *process,
365 nxt_common_app_conf_t *conf)
366 {
367 nxt_str_t ini_path;
368 nxt_int_t ret;
369 nxt_conf_value_t *value;
370 nxt_php_app_conf_t *c;
371
372 static nxt_str_t file_str = nxt_string("file");
373 static nxt_str_t user_str = nxt_string("user");
374 static nxt_str_t admin_str = nxt_string("admin");
375
376 c = &conf->u.php;
377
378 #ifdef ZTS
379
380 #if PHP_VERSION_ID >= 70400
381 php_tsrm_startup();
382 #else
383 tsrm_startup(1, 1, 0, NULL);
384 tsrm_ls = ts_resource(0);
385 #endif
386
387 #endif
388
389 #if defined(NXT_PHP7) && defined(ZEND_SIGNALS)
390
391 #if (NXT_ZEND_SIGNAL_STARTUP)
392 zend_signal_startup();
393 #elif defined(ZTS)
394 #error PHP is built with thread safety and broken signals.
395 #endif
396
397 #endif
398
399 sapi_startup(&nxt_php_sapi_module);
400
401 if (c->options != NULL) {
402 value = nxt_conf_get_object_member(c->options, &file_str, NULL);
403
404 if (value != NULL) {
405 nxt_conf_get_string(value, &ini_path);
406
407 ret = nxt_php_set_ini_path(task, &ini_path,
408 conf->working_directory);
409
410 if (nxt_slow_path(ret != NXT_OK)) {
411 return NXT_ERROR;
412 }
413 }
414 }
415
416 if (nxt_slow_path(nxt_php_startup(&nxt_php_sapi_module) == FAILURE)) {
417 nxt_alert(task, "failed to initialize SAPI module and extension");
418 return NXT_ERROR;
419 }
420
421 if (c->options != NULL) {
422 value = nxt_conf_get_object_member(c->options, &admin_str, NULL);
423 nxt_php_set_options(task, value, ZEND_INI_SYSTEM);
424
425 value = nxt_conf_get_object_member(c->options, &user_str, NULL);
426 nxt_php_set_options(task, value, ZEND_INI_USER);
427 }
428
429 #ifdef NXT_PHP7
430 nxt_php_server_ag = zend_hash_str_find_ptr(CG(auto_globals), "_SERVER",
431 nxt_length("_SERVER"));
432 #else
433 zend_hash_quick_find(CG(auto_globals), "_SERVER", sizeof("_SERVER"),
434 zend_hash_func("_SERVER", sizeof("_SERVER")),
435 (void **) &nxt_php_server_ag);
436 #endif
437 if (nxt_slow_path(nxt_php_server_ag == NULL)) {
438 nxt_alert(task, "failed to find $_SERVER auto global");
439 return NXT_ERROR;
440 }
441
442 return NXT_OK;
443 }
444
445
446 static nxt_int_t
nxt_php_start(nxt_task_t * task,nxt_process_data_t * data)447 nxt_php_start(nxt_task_t *task, nxt_process_data_t *data)
448 {
449 uint32_t next;
450 nxt_int_t ret;
451 nxt_str_t name;
452 nxt_uint_t n;
453 nxt_unit_ctx_t *unit_ctx;
454 nxt_unit_init_t php_init;
455 nxt_conf_value_t *value;
456 nxt_php_app_conf_t *c;
457 nxt_common_app_conf_t *conf;
458
459 conf = data->app;
460 c = &conf->u.php;
461
462 n = (c->targets != NULL) ? nxt_conf_object_members_count(c->targets) : 1;
463
464 nxt_php_targets = nxt_zalloc(sizeof(nxt_php_target_t) * n);
465 if (nxt_slow_path(nxt_php_targets == NULL)) {
466 return NXT_ERROR;
467 }
468
469 if (c->targets != NULL) {
470 next = 0;
471
472 for (n = 0; /* void */; n++) {
473 value = nxt_conf_next_object_member(c->targets, &name, &next);
474 if (value == NULL) {
475 break;
476 }
477
478 ret = nxt_php_set_target(task, &nxt_php_targets[n], value);
479 if (nxt_slow_path(ret != NXT_OK)) {
480 return NXT_ERROR;
481 }
482 }
483
484 } else {
485 ret = nxt_php_set_target(task, &nxt_php_targets[0], conf->self);
486 if (nxt_slow_path(ret != NXT_OK)) {
487 return NXT_ERROR;
488 }
489 }
490
491 ret = nxt_unit_default_init(task, &php_init, conf);
492 if (nxt_slow_path(ret != NXT_OK)) {
493 nxt_alert(task, "nxt_unit_default_init() failed");
494 return ret;
495 }
496
497 php_init.callbacks.request_handler = nxt_php_request_handler;
498
499 unit_ctx = nxt_unit_init(&php_init);
500 if (nxt_slow_path(unit_ctx == NULL)) {
501 return NXT_ERROR;
502 }
503
504 nxt_php_unit_ctx = unit_ctx;
505
506 nxt_unit_run(nxt_php_unit_ctx);
507 nxt_unit_done(nxt_php_unit_ctx);
508
509 exit(0);
510
511 return NXT_OK;
512 }
513
514
515 static nxt_int_t
nxt_php_set_target(nxt_task_t * task,nxt_php_target_t * target,nxt_conf_value_t * conf)516 nxt_php_set_target(nxt_task_t *task, nxt_php_target_t *target,
517 nxt_conf_value_t *conf)
518 {
519 u_char *tmp, *p;
520 nxt_str_t str;
521 nxt_int_t ret;
522 nxt_conf_value_t *value;
523
524 static nxt_str_t root_str = nxt_string("root");
525 static nxt_str_t script_str = nxt_string("script");
526 static nxt_str_t index_str = nxt_string("index");
527
528 value = nxt_conf_get_object_member(conf, &root_str, NULL);
529
530 nxt_conf_get_string(value, &str);
531
532 tmp = nxt_malloc(str.length + 1);
533 if (nxt_slow_path(tmp == NULL)) {
534 return NXT_ERROR;
535 }
536
537 p = tmp;
538
539 p = nxt_cpymem(p, str.start, str.length);
540 *p = '\0';
541
542 p = nxt_realpath(tmp);
543 if (nxt_slow_path(p == NULL)) {
544 nxt_alert(task, "root realpath(%s) failed %E", tmp, nxt_errno);
545 return NXT_ERROR;
546 }
547
548 nxt_free(tmp);
549
550 target->root.length = nxt_strlen(p);
551 target->root.start = p;
552
553 nxt_php_str_trim_trail(&target->root, '/');
554
555 value = nxt_conf_get_object_member(conf, &script_str, NULL);
556
557 if (value != NULL) {
558 nxt_conf_get_string(value, &str);
559
560 nxt_php_str_trim_lead(&str, '/');
561
562 tmp = nxt_malloc(target->root.length + 1 + str.length + 1);
563 if (nxt_slow_path(tmp == NULL)) {
564 return NXT_ERROR;
565 }
566
567 p = tmp;
568
569 p = nxt_cpymem(p, target->root.start, target->root.length);
570 *p++ = '/';
571
572 p = nxt_cpymem(p, str.start, str.length);
573 *p = '\0';
574
575 p = nxt_realpath(tmp);
576 if (nxt_slow_path(p == NULL)) {
577 nxt_alert(task, "script realpath(%s) failed %E", tmp, nxt_errno);
578 return NXT_ERROR;
579 }
580
581 nxt_free(tmp);
582
583 target->script_filename.length = nxt_strlen(p);
584 target->script_filename.start = p;
585
586 if (!nxt_str_start(&target->script_filename,
587 target->root.start, target->root.length))
588 {
589 nxt_alert(task, "script is not under php root");
590 return NXT_ERROR;
591 }
592
593 ret = nxt_php_dirname(&target->script_filename,
594 &target->script_dirname);
595 if (nxt_slow_path(ret != NXT_OK)) {
596 return NXT_ERROR;
597 }
598
599 target->script_name.length = target->script_filename.length
600 - target->root.length;
601 target->script_name.start = target->script_filename.start
602 + target->root.length;
603
604 } else {
605 value = nxt_conf_get_object_member(conf, &index_str, NULL);
606
607 if (value != NULL) {
608 nxt_conf_get_string(value, &str);
609
610 tmp = nxt_malloc(str.length);
611 if (nxt_slow_path(tmp == NULL)) {
612 return NXT_ERROR;
613 }
614
615 nxt_memcpy(tmp, str.start, str.length);
616
617 target->index.length = str.length;
618 target->index.start = tmp;
619
620 } else {
621 nxt_str_set(&target->index, "index.php");
622 }
623 }
624
625 return NXT_OK;
626 }
627
628
629 static nxt_int_t
nxt_php_set_ini_path(nxt_task_t * task,nxt_str_t * ini_path,char * workdir)630 nxt_php_set_ini_path(nxt_task_t *task, nxt_str_t *ini_path, char *workdir)
631 {
632 size_t wdlen;
633 u_char *p, *start;
634
635 if (ini_path->start[0] == '/' || workdir == NULL) {
636 p = nxt_malloc(ini_path->length + 1);
637 if (nxt_slow_path(p == NULL)) {
638 return NXT_ERROR;
639 }
640
641 start = p;
642
643 } else {
644 wdlen = nxt_strlen(workdir);
645
646 p = nxt_malloc(wdlen + ini_path->length + 2);
647 if (nxt_slow_path(p == NULL)) {
648 return NXT_ERROR;
649 }
650
651 start = p;
652
653 p = nxt_cpymem(p, workdir, wdlen);
654
655 if (workdir[wdlen - 1] != '/') {
656 *p++ = '/';
657 }
658 }
659
660 p = nxt_cpymem(p, ini_path->start, ini_path->length);
661 *p = '\0';
662
663 nxt_php_sapi_module.php_ini_path_override = (char *) start;
664
665 return NXT_OK;
666 }
667
668
669 static void
nxt_php_set_options(nxt_task_t * task,nxt_conf_value_t * options,int type)670 nxt_php_set_options(nxt_task_t *task, nxt_conf_value_t *options, int type)
671 {
672 uint32_t next;
673 nxt_str_t name, value;
674 nxt_conf_value_t *value_obj;
675
676 if (options != NULL) {
677 next = 0;
678
679 for ( ;; ) {
680 value_obj = nxt_conf_next_object_member(options, &name, &next);
681 if (value_obj == NULL) {
682 break;
683 }
684
685 nxt_conf_get_string(value_obj, &value);
686
687 if (nxt_php_alter_option(&name, &value, type) != NXT_OK) {
688 nxt_log(task, NXT_LOG_ERR,
689 "setting PHP option \"%V: %V\" failed", &name, &value);
690 continue;
691 }
692
693 if (nxt_str_eq(&name, "disable_functions", 17)) {
694 #ifdef NXT_PHP8
695 nxt_php_disable_functions(&value);
696 #else
697 nxt_php_disable(task, "function", &value,
698 &PG(disable_functions),
699 zend_disable_function);
700 #endif
701 continue;
702 }
703
704 if (nxt_str_eq(&name, "disable_classes", 15)) {
705 nxt_php_disable(task, "class", &value,
706 &PG(disable_classes),
707 zend_disable_class);
708 continue;
709 }
710 }
711 }
712 }
713
714
715 #ifdef NXT_PHP7
716
717 static nxt_int_t
nxt_php_alter_option(nxt_str_t * name,nxt_str_t * value,int type)718 nxt_php_alter_option(nxt_str_t *name, nxt_str_t *value, int type)
719 {
720 zend_string *zs;
721 zend_ini_entry *ini_entry;
722
723 ini_entry = nxt_php_hash_str_find_ptr(EG(ini_directives), name);
724 if (nxt_slow_path(ini_entry == NULL)) {
725 return NXT_ERROR;
726 }
727
728 /* PHP exits on memory allocation errors. */
729 zs = zend_string_init((char *) value->start, value->length, 1);
730
731 if (ini_entry->on_modify
732 && ini_entry->on_modify(ini_entry, zs, ini_entry->mh_arg1,
733 ini_entry->mh_arg2, ini_entry->mh_arg3,
734 ZEND_INI_STAGE_ACTIVATE)
735 != SUCCESS)
736 {
737 zend_string_release(zs);
738 return NXT_ERROR;
739 }
740
741 ini_entry->value = zs;
742 ini_entry->modifiable = type;
743
744 return NXT_OK;
745 }
746
747 #else /* PHP 5. */
748
749 static nxt_int_t
nxt_php_alter_option(nxt_str_t * name,nxt_str_t * value,int type)750 nxt_php_alter_option(nxt_str_t *name, nxt_str_t *value, int type)
751 {
752 char *cstr;
753 zend_ini_entry *ini_entry;
754
755 ini_entry = nxt_php_hash_str_find_ptr(EG(ini_directives), name);
756 if (nxt_slow_path(ini_entry == NULL)) {
757 return NXT_ERROR;
758 }
759
760 cstr = nxt_malloc(value->length + 1);
761 if (nxt_slow_path(cstr == NULL)) {
762 return NXT_ERROR;
763 }
764
765 nxt_memcpy(cstr, value->start, value->length);
766 cstr[value->length] = '\0';
767
768 if (ini_entry->on_modify
769 && ini_entry->on_modify(ini_entry, cstr, value->length,
770 ini_entry->mh_arg1, ini_entry->mh_arg2,
771 ini_entry->mh_arg3, ZEND_INI_STAGE_ACTIVATE
772 TSRMLS_CC)
773 != SUCCESS)
774 {
775 nxt_free(cstr);
776 return NXT_ERROR;
777 }
778
779 ini_entry->value = cstr;
780 ini_entry->value_length = value->length;
781 ini_entry->modifiable = type;
782
783 return NXT_OK;
784 }
785
786 #endif
787
788
789 #ifdef NXT_PHP8
790
791 static void
nxt_php_disable_functions(nxt_str_t * str)792 nxt_php_disable_functions(nxt_str_t *str)
793 {
794 char *p;
795
796 p = nxt_malloc(str->length + 1);
797 if (nxt_slow_path(p == NULL)) {
798 return;
799 }
800
801 nxt_memcpy(p, str->start, str->length);
802 p[str->length] = '\0';
803
804 zend_disable_functions(p);
805
806 nxt_free(p);
807 }
808
809 #endif
810
811
812 static void
nxt_php_disable(nxt_task_t * task,const char * type,nxt_str_t * value,char ** ptr,nxt_php_disable_t disable)813 nxt_php_disable(nxt_task_t *task, const char *type, nxt_str_t *value,
814 char **ptr, nxt_php_disable_t disable)
815 {
816 char c, *p, *start;
817
818 p = nxt_malloc(value->length + 1);
819 if (nxt_slow_path(p == NULL)) {
820 return;
821 }
822
823 /*
824 * PHP frees this memory on module shutdown.
825 * See core_globals_dtor() for details.
826 */
827 *ptr = p;
828
829 nxt_memcpy(p, value->start, value->length);
830 p[value->length] = '\0';
831
832 start = p;
833
834 do {
835 c = *p;
836
837 if (c == ' ' || c == ',' || c == '\0') {
838
839 if (p != start) {
840 *p = '\0';
841
842 #ifdef NXT_PHP7
843 if (disable(start, p - start)
844 #else
845 if (disable(start, p - start TSRMLS_CC)
846 #endif
847 != SUCCESS)
848 {
849 nxt_log(task, NXT_LOG_ERR,
850 "PHP: failed to disable \"%s\": no such %s",
851 start, type);
852 }
853 }
854
855 start = p + 1;
856 }
857
858 p++;
859
860 } while (c != '\0');
861 }
862
863
864 static nxt_int_t
nxt_php_dirname(const nxt_str_t * file,nxt_str_t * dir)865 nxt_php_dirname(const nxt_str_t *file, nxt_str_t *dir)
866 {
867 size_t length;
868
869 if (file->length == 0 || file->start[0] != '/') {
870 nxt_unit_alert(NULL, "php_dirname: invalid file name "
871 "(not starts from '/')");
872 return NXT_ERROR;
873 }
874
875 length = file->length;
876
877 while (file->start[length - 1] != '/') {
878 length--;
879 }
880
881 dir->length = length;
882 dir->start = nxt_malloc(length + 1);
883 if (nxt_slow_path(dir->start == NULL)) {
884 return NXT_ERROR;
885 }
886
887 nxt_memcpy(dir->start, file->start, length);
888
889 dir->start[length] = '\0';
890
891 return NXT_OK;
892 }
893
894
895 static void
nxt_php_str_trim_trail(nxt_str_t * str,u_char t)896 nxt_php_str_trim_trail(nxt_str_t *str, u_char t)
897 {
898 while (str->length > 0 && str->start[str->length - 1] == t) {
899 str->length--;
900 }
901
902 str->start[str->length] = '\0';
903 }
904
905
906 static void
nxt_php_str_trim_lead(nxt_str_t * str,u_char t)907 nxt_php_str_trim_lead(nxt_str_t *str, u_char t)
908 {
909 while (str->length > 0 && str->start[0] == t) {
910 str->length--;
911 str->start++;
912 }
913 }
914
915
916 nxt_inline u_char *
nxt_realpath(const void * c)917 nxt_realpath(const void *c)
918 {
919 return (u_char *) realpath(c, NULL);
920 }
921
922
923 static void
nxt_php_request_handler(nxt_unit_request_info_t * req)924 nxt_php_request_handler(nxt_unit_request_info_t *req)
925 {
926 nxt_php_target_t *target;
927 nxt_php_run_ctx_t ctx;
928 nxt_unit_request_t *r;
929
930 r = req->request;
931 target = &nxt_php_targets[r->app_target];
932
933 nxt_memzero(&ctx, sizeof(ctx));
934
935 ctx.req = req;
936 ctx.root = &target->root;
937 ctx.index = &target->index;
938
939 if (target->script_filename.length == 0) {
940 nxt_php_dynamic_request(&ctx, r);
941 return;
942 }
943
944 ctx.script_filename = target->script_filename;
945 ctx.script_dirname = target->script_dirname;
946 ctx.script_name = target->script_name;
947
948 ctx.chdir = (r->app_target != nxt_php_last_target);
949
950 nxt_php_execute(&ctx, r);
951
952 nxt_php_last_target = ctx.chdir ? -1 : r->app_target;
953 }
954
955
956 static void
nxt_php_dynamic_request(nxt_php_run_ctx_t * ctx,nxt_unit_request_t * r)957 nxt_php_dynamic_request(nxt_php_run_ctx_t *ctx, nxt_unit_request_t *r)
958 {
959 u_char *p;
960 nxt_str_t path, script_name;
961 nxt_int_t ret;
962
963 path.length = r->path_length;
964 path.start = nxt_unit_sptr_get(&r->path);
965
966 nxt_str_null(&script_name);
967
968 ctx->path_info.start = (u_char *) strstr((char *) path.start, ".php/");
969 if (ctx->path_info.start != NULL) {
970 ctx->path_info.start += 4;
971 path.length = ctx->path_info.start - path.start;
972
973 ctx->path_info.length = r->path_length - path.length;
974
975 } else if (path.start[path.length - 1] == '/') {
976 script_name = *ctx->index;
977
978 } else {
979 if (nxt_slow_path(path.length < 4
980 || nxt_memcmp(path.start + (path.length - 4),
981 ".php", 4)))
982 {
983 nxt_unit_request_done(ctx->req, NXT_UNIT_ERROR);
984
985 return;
986 }
987 }
988
989 ctx->script_filename.length = ctx->root->length
990 + path.length
991 + script_name.length;
992
993 p = nxt_malloc(ctx->script_filename.length + 1);
994 if (nxt_slow_path(p == NULL)) {
995 nxt_unit_request_done(ctx->req, NXT_UNIT_ERROR);
996
997 return;
998 }
999
1000 ctx->script_filename.start = p;
1001
1002 ctx->script_name.length = path.length + script_name.length;
1003 ctx->script_name.start = p + ctx->root->length;
1004
1005 p = nxt_cpymem(p, ctx->root->start, ctx->root->length);
1006 p = nxt_cpymem(p, path.start, path.length);
1007
1008 if (script_name.length > 0) {
1009 p = nxt_cpymem(p, script_name.start, script_name.length);
1010 }
1011
1012 *p = '\0';
1013
1014 ctx->chdir = 1;
1015
1016 ret = nxt_php_dirname(&ctx->script_filename, &ctx->script_dirname);
1017 if (nxt_slow_path(ret != NXT_OK)) {
1018 nxt_unit_request_done(ctx->req, NXT_UNIT_ERROR);
1019 nxt_free(ctx->script_filename.start);
1020
1021 return;
1022 }
1023
1024 nxt_php_execute(ctx, r);
1025
1026 nxt_free(ctx->script_filename.start);
1027 nxt_free(ctx->script_dirname.start);
1028
1029 nxt_php_last_target = -1;
1030 }
1031
1032
1033 static void
nxt_php_execute(nxt_php_run_ctx_t * ctx,nxt_unit_request_t * r)1034 nxt_php_execute(nxt_php_run_ctx_t *ctx, nxt_unit_request_t *r)
1035 {
1036 #if (PHP_VERSION_ID < 50600)
1037 void *read_post;
1038 #endif
1039 nxt_unit_field_t *f;
1040 zend_file_handle file_handle;
1041
1042 nxt_unit_req_debug(ctx->req, "PHP execute script %s",
1043 ctx->script_filename.start);
1044
1045 SG(server_context) = ctx;
1046 SG(options) |= SAPI_OPTION_NO_CHDIR;
1047 SG(request_info).request_uri = nxt_unit_sptr_get(&r->target);
1048 SG(request_info).request_method = nxt_unit_sptr_get(&r->method);
1049
1050 SG(request_info).proto_num = 1001;
1051
1052 SG(request_info).query_string = r->query.offset
1053 ? nxt_unit_sptr_get(&r->query) : NULL;
1054 SG(request_info).content_length = r->content_length;
1055
1056 if (r->content_type_field != NXT_UNIT_NONE_FIELD) {
1057 f = r->fields + r->content_type_field;
1058
1059 SG(request_info).content_type = nxt_unit_sptr_get(&f->value);
1060 }
1061
1062 if (r->cookie_field != NXT_UNIT_NONE_FIELD) {
1063 f = r->fields + r->cookie_field;
1064
1065 ctx->cookie = nxt_unit_sptr_get(&f->value);
1066 }
1067
1068 if (r->authorization_field != NXT_UNIT_NONE_FIELD) {
1069 f = r->fields + r->authorization_field;
1070
1071 #ifdef NXT_PHP7
1072 php_handle_auth_data(nxt_unit_sptr_get(&f->value));
1073 #else
1074 php_handle_auth_data(nxt_unit_sptr_get(&f->value) TSRMLS_CC);
1075 #endif
1076
1077 } else {
1078 SG(request_info).auth_digest = NULL;
1079 SG(request_info).auth_user = NULL;
1080 SG(request_info).auth_password = NULL;
1081 }
1082
1083 SG(sapi_headers).http_response_code = 200;
1084
1085 SG(request_info).path_translated = NULL;
1086
1087 #ifdef NXT_PHP7
1088 if (nxt_slow_path(php_request_startup() == FAILURE)) {
1089 #else
1090 if (nxt_slow_path(php_request_startup(TSRMLS_C) == FAILURE)) {
1091 #endif
1092 nxt_unit_req_debug(ctx->req, "php_request_startup() failed");
1093
1094 nxt_unit_request_done(ctx->req, NXT_UNIT_ERROR);
1095 return;
1096 }
1097
1098 if (ctx->chdir) {
1099 ctx->chdir = 0;
1100 nxt_php_vcwd_chdir(ctx->req, ctx->script_dirname.start);
1101 }
1102
1103 nxt_memzero(&file_handle, sizeof(file_handle));
1104
1105 file_handle.type = ZEND_HANDLE_FILENAME;
1106 #if (PHP_VERSION_ID >= 80100)
1107 file_handle.filename = zend_string_init((char *) ctx->script_filename.start,
1108 ctx->script_filename.length, 0);
1109 file_handle.primary_script = 1;
1110 #else
1111 file_handle.filename = (char *) ctx->script_filename.start;
1112 #endif
1113
1114 php_execute_script(&file_handle TSRMLS_CC);
1115
1116 #if (PHP_VERSION_ID >= 80100)
1117 zend_destroy_file_handle(&file_handle);
1118 #endif
1119
1120 /* Prevention of consuming possible unread request body. */
1121 #if (PHP_VERSION_ID < 50600)
1122 read_post = sapi_module.read_post;
1123 sapi_module.read_post = NULL;
1124 #else
1125 SG(post_read) = 1;
1126 #endif
1127
1128 php_request_shutdown(NULL);
1129
1130 if (ctx->req != NULL) {
1131 nxt_unit_request_done(ctx->req, NXT_UNIT_OK);
1132 }
1133
1134 #if (PHP_VERSION_ID < 50600)
1135 sapi_module.read_post = read_post;
1136 #endif
1137 }
1138
1139
1140 nxt_inline void
1141 nxt_php_vcwd_chdir(nxt_unit_request_info_t *req, u_char *dir)
1142 {
1143 if (nxt_slow_path(VCWD_CHDIR((char *) dir) != 0)) {
1144 nxt_unit_req_alert(req, "VCWD_CHDIR(%s) failed (%d: %s)",
1145 dir, errno, strerror(errno));
1146 }
1147 }
1148
1149
1150 static int
1151 nxt_php_startup(sapi_module_struct *sapi_module)
1152 {
1153 return php_module_startup(sapi_module, &nxt_php_unit_module, 1);
1154 }
1155
1156
1157 #ifdef NXT_PHP7
1158 static size_t
1159 nxt_php_unbuffered_write(const char *str, size_t str_length TSRMLS_DC)
1160 #else
1161 static int
1162 nxt_php_unbuffered_write(const char *str, uint str_length TSRMLS_DC)
1163 #endif
1164 {
1165 int rc;
1166 nxt_php_run_ctx_t *ctx;
1167
1168 ctx = SG(server_context);
1169
1170 rc = nxt_unit_response_write(ctx->req, str, str_length);
1171 if (nxt_fast_path(rc == NXT_UNIT_OK)) {
1172 return str_length;
1173 }
1174
1175 php_handle_aborted_connection();
1176 return 0;
1177 }
1178
1179
1180 static int
1181 nxt_php_send_headers(sapi_headers_struct *sapi_headers TSRMLS_DC)
1182 {
1183 int rc, fields_count;
1184 char *colon, *value;
1185 uint16_t status;
1186 uint32_t resp_size;
1187 nxt_php_run_ctx_t *ctx;
1188 sapi_header_struct *h;
1189 zend_llist_position zpos;
1190 nxt_unit_request_info_t *req;
1191
1192 ctx = SG(server_context);
1193 req = ctx->req;
1194
1195 nxt_unit_req_debug(req, "nxt_php_send_headers");
1196
1197 if (SG(request_info).no_headers == 1) {
1198 rc = nxt_unit_response_init(req, 200, 0, 0);
1199 if (nxt_slow_path(rc != NXT_UNIT_OK)) {
1200 return SAPI_HEADER_SEND_FAILED;
1201 }
1202
1203 return SAPI_HEADER_SENT_SUCCESSFULLY;
1204 }
1205
1206 resp_size = 0;
1207 fields_count = zend_llist_count(&sapi_headers->headers);
1208
1209 for (h = zend_llist_get_first_ex(&sapi_headers->headers, &zpos);
1210 h;
1211 h = zend_llist_get_next_ex(&sapi_headers->headers, &zpos))
1212 {
1213 resp_size += h->header_len;
1214 }
1215
1216 status = SG(sapi_headers).http_response_code;
1217
1218 rc = nxt_unit_response_init(req, status, fields_count, resp_size);
1219 if (nxt_slow_path(rc != NXT_UNIT_OK)) {
1220 return SAPI_HEADER_SEND_FAILED;
1221 }
1222
1223 for (h = zend_llist_get_first_ex(&sapi_headers->headers, &zpos);
1224 h;
1225 h = zend_llist_get_next_ex(&sapi_headers->headers, &zpos))
1226 {
1227 colon = memchr(h->header, ':', h->header_len);
1228 if (nxt_slow_path(colon == NULL)) {
1229 nxt_unit_req_warn(req, "colon not found in header '%.*s'",
1230 (int) h->header_len, h->header);
1231 continue;
1232 }
1233
1234 value = colon + 1;
1235 while(isspace(*value)) {
1236 value++;
1237 }
1238
1239 nxt_unit_response_add_field(req, h->header, colon - h->header,
1240 value,
1241 h->header_len - (value - h->header));
1242 }
1243
1244 rc = nxt_unit_response_send(req);
1245 if (nxt_slow_path(rc != NXT_UNIT_OK)) {
1246 nxt_unit_req_debug(req, "failed to send response");
1247
1248 return SAPI_HEADER_SEND_FAILED;
1249 }
1250
1251 return SAPI_HEADER_SENT_SUCCESSFULLY;
1252 }
1253
1254
1255 #ifdef NXT_PHP7
1256 static size_t
1257 nxt_php_read_post(char *buffer, size_t count_bytes TSRMLS_DC)
1258 #else
1259 static int
1260 nxt_php_read_post(char *buffer, uint count_bytes TSRMLS_DC)
1261 #endif
1262 {
1263 nxt_php_run_ctx_t *ctx;
1264
1265 ctx = SG(server_context);
1266
1267 nxt_unit_req_debug(ctx->req, "nxt_php_read_post %d", (int) count_bytes);
1268
1269 return nxt_unit_request_read(ctx->req, buffer, count_bytes);
1270 }
1271
1272
1273 static char *
1274 nxt_php_read_cookies(TSRMLS_D)
1275 {
1276 nxt_php_run_ctx_t *ctx;
1277
1278 ctx = SG(server_context);
1279
1280 nxt_unit_req_debug(ctx->req, "nxt_php_read_cookies");
1281
1282 return ctx->cookie;
1283 }
1284
1285
1286 static void
1287 nxt_php_register_variables(zval *track_vars_array TSRMLS_DC)
1288 {
1289 const char *name;
1290 nxt_unit_field_t *f, *f_end;
1291 nxt_php_run_ctx_t *ctx;
1292 nxt_unit_request_t *r;
1293 nxt_unit_request_info_t *req;
1294
1295 ctx = SG(server_context);
1296
1297 req = ctx->req;
1298 r = req->request;
1299
1300 nxt_unit_req_debug(req, "nxt_php_register_variables");
1301
1302 php_register_variable_safe((char *) "SERVER_SOFTWARE",
1303 (char *) nxt_server.start,
1304 nxt_server.length, track_vars_array TSRMLS_CC);
1305
1306 nxt_php_set_sptr(req, "SERVER_PROTOCOL", &r->version, r->version_length,
1307 track_vars_array TSRMLS_CC);
1308
1309 /*
1310 * 'PHP_SELF'
1311 * The filename of the currently executing script, relative to the document
1312 * root. For instance, $_SERVER['PHP_SELF'] in a script at the address
1313 * http://example.com/foo/bar.php would be /foo/bar.php. The __FILE__
1314 * constant contains the full path and filename of the current (i.e.
1315 * included) file. If PHP is running as a command-line processor this
1316 * variable contains the script name since PHP 4.3.0. Previously it was not
1317 * available.
1318 */
1319
1320 if (ctx->path_info.length != 0) {
1321 nxt_php_set_sptr(req, "PHP_SELF", &r->path, r->path_length,
1322 track_vars_array TSRMLS_CC);
1323
1324 nxt_php_set_str(req, "PATH_INFO", &ctx->path_info,
1325 track_vars_array TSRMLS_CC);
1326
1327 } else {
1328 nxt_php_set_str(req, "PHP_SELF", &ctx->script_name,
1329 track_vars_array TSRMLS_CC);
1330 }
1331
1332 /*
1333 * 'SCRIPT_NAME'
1334 * Contains the current script's path. This is useful for pages which need
1335 * to point to themselves. The __FILE__ constant contains the full path and
1336 * filename of the current (i.e. included) file.
1337 */
1338
1339 nxt_php_set_str(req, "SCRIPT_NAME", &ctx->script_name,
1340 track_vars_array TSRMLS_CC);
1341
1342 /*
1343 * 'SCRIPT_FILENAME'
1344 * The absolute pathname of the currently executing script.
1345 */
1346
1347 nxt_php_set_str(req, "SCRIPT_FILENAME", &ctx->script_filename,
1348 track_vars_array TSRMLS_CC);
1349
1350 /*
1351 * 'DOCUMENT_ROOT'
1352 * The document root directory under which the current script is executing,
1353 * as defined in the server's configuration file.
1354 */
1355
1356 nxt_php_set_str(req, "DOCUMENT_ROOT", ctx->root,
1357 track_vars_array TSRMLS_CC);
1358
1359 nxt_php_set_sptr(req, "REQUEST_METHOD", &r->method, r->method_length,
1360 track_vars_array TSRMLS_CC);
1361 nxt_php_set_sptr(req, "REQUEST_URI", &r->target, r->target_length,
1362 track_vars_array TSRMLS_CC);
1363 nxt_php_set_sptr(req, "QUERY_STRING", &r->query, r->query_length,
1364 track_vars_array TSRMLS_CC);
1365
1366 nxt_php_set_sptr(req, "REMOTE_ADDR", &r->remote, r->remote_length,
1367 track_vars_array TSRMLS_CC);
1368 nxt_php_set_sptr(req, "SERVER_ADDR", &r->local, r->local_length,
1369 track_vars_array TSRMLS_CC);
1370
1371 nxt_php_set_sptr(req, "SERVER_NAME", &r->server_name, r->server_name_length,
1372 track_vars_array TSRMLS_CC);
1373 nxt_php_set_cstr(req, "SERVER_PORT", "80", 2, track_vars_array TSRMLS_CC);
1374
1375 if (r->tls) {
1376 nxt_php_set_cstr(req, "HTTPS", "on", 2, track_vars_array TSRMLS_CC);
1377 }
1378
1379 f_end = r->fields + r->fields_count;
1380 for (f = r->fields; f < f_end; f++) {
1381 name = nxt_unit_sptr_get(&f->name);
1382
1383 nxt_php_set_sptr(req, name, &f->value, f->value_length,
1384 track_vars_array TSRMLS_CC);
1385 }
1386
1387 if (r->content_length_field != NXT_UNIT_NONE_FIELD) {
1388 f = r->fields + r->content_length_field;
1389
1390 nxt_php_set_sptr(req, "CONTENT_LENGTH", &f->value, f->value_length,
1391 track_vars_array TSRMLS_CC);
1392 }
1393
1394 if (r->content_type_field != NXT_UNIT_NONE_FIELD) {
1395 f = r->fields + r->content_type_field;
1396
1397 nxt_php_set_sptr(req, "CONTENT_TYPE", &f->value, f->value_length,
1398 track_vars_array TSRMLS_CC);
1399 }
1400 }
1401
1402
1403 static void
1404 nxt_php_set_sptr(nxt_unit_request_info_t *req, const char *name,
1405 nxt_unit_sptr_t *v, uint32_t len, zval *track_vars_array TSRMLS_DC)
1406 {
1407 char *str;
1408
1409 str = nxt_unit_sptr_get(v);
1410
1411 nxt_unit_req_debug(req, "php: register %s='%.*s'", name, (int) len, str);
1412
1413 php_register_variable_safe((char *) name, str, len,
1414 track_vars_array TSRMLS_CC);
1415 }
1416
1417
1418 nxt_inline void
1419 nxt_php_set_str(nxt_unit_request_info_t *req, const char *name,
1420 nxt_str_t *s, zval *track_vars_array TSRMLS_DC)
1421 {
1422 nxt_php_set_cstr(req, name, (char *) s->start, s->length,
1423 track_vars_array TSRMLS_CC);
1424 }
1425
1426
1427 #ifdef NXT_PHP7
1428
1429 static void *
1430 nxt_php_hash_str_find_ptr(const HashTable *ht, const nxt_str_t *str)
1431 {
1432 return zend_hash_str_find_ptr(ht, (const char *) str->start, str->length);
1433 }
1434
1435 #else
1436
1437 static void *
1438 nxt_php_hash_str_find_ptr(const HashTable *ht, const nxt_str_t *str)
1439 {
1440 int ret;
1441 void *entry;
1442 char buf[256];
1443
1444 if (nxt_slow_path(str->length >= (sizeof(buf) - 1))) {
1445 return NULL;
1446 }
1447
1448 nxt_memcpy(buf, str->start, str->length);
1449 buf[str->length] = '\0';
1450
1451 ret = zend_hash_find(ht, buf, str->length + 1, &entry);
1452 if (nxt_fast_path(ret == SUCCESS)) {
1453 return entry;
1454 }
1455
1456 return NULL;
1457 }
1458
1459 #endif
1460
1461
1462 static void
1463 nxt_php_set_cstr(nxt_unit_request_info_t *req, const char *name,
1464 const char *cstr, uint32_t len, zval *track_vars_array TSRMLS_DC)
1465 {
1466 if (nxt_slow_path(cstr == NULL)) {
1467 return;
1468 }
1469
1470 nxt_unit_req_debug(req, "php: register %s='%.*s'", name, (int) len, cstr);
1471
1472 php_register_variable_safe((char *) name, (char *) cstr, len,
1473 track_vars_array TSRMLS_CC);
1474 }
1475
1476
1477 #if NXT_PHP8
1478 static void
1479 nxt_php_log_message(const char *message, int syslog_type_int)
1480 #else
1481 #ifdef NXT_HAVE_PHP_LOG_MESSAGE_WITH_SYSLOG_TYPE
1482 static void
1483 nxt_php_log_message(char *message, int syslog_type_int)
1484 #else
1485 static void
1486 nxt_php_log_message(char *message TSRMLS_DC)
1487 #endif
1488 #endif
1489 {
1490 nxt_php_run_ctx_t *ctx;
1491
1492 ctx = SG(server_context);
1493
1494 if (ctx != NULL) {
1495 nxt_unit_req_log(ctx->req, NXT_UNIT_LOG_NOTICE,
1496 "php message: %s", message);
1497
1498 } else {
1499 nxt_unit_log(nxt_php_unit_ctx, NXT_UNIT_LOG_NOTICE,
1500 "php message: %s", message);
1501 }
1502 }
1503