xref: /unit/src/nxt_php_sapi.c (revision 673:9fa79c719a17)
1 
2 /*
3  * Copyright (C) Max Romanov
4  * Copyright (C) Valentin V. Bartenev
5  * Copyright (C) NGINX, Inc.
6  */
7 
8 #include "php.h"
9 #include "SAPI.h"
10 #include "php_main.h"
11 #include "php_variables.h"
12 
13 #include <nxt_main.h>
14 #include <nxt_router.h>
15 
16 
17 static nxt_int_t nxt_php_init(nxt_task_t *task, nxt_common_app_conf_t *conf);
18 
19 static nxt_int_t nxt_php_run(nxt_task_t *task,
20                       nxt_app_rmsg_t *rmsg, nxt_app_wmsg_t *wmsg);
21 
22 #if PHP_MAJOR_VERSION >= 7
23 #   define NXT_PHP7 1
24 #   if PHP_MINOR_VERSION >= 1
25 #       define NXT_HAVE_PHP_LOG_MESSAGE_WITH_SYSLOG_TYPE 1
26 #   else
27 #       define NXT_HAVE_PHP_INTERRUPTS 1
28 #   endif
29 #   define NXT_HAVE_PHP_IGNORE_CWD 1
30 #else
31 #   define NXT_HAVE_PHP_INTERRUPTS 1
32 #   if PHP_MINOR_VERSION >= 4
33 #       define NXT_HAVE_PHP_IGNORE_CWD 1
34 #   endif
35 #endif
36 
37 static int nxt_php_startup(sapi_module_struct *sapi_module);
38 static int nxt_php_send_headers(sapi_headers_struct *sapi_headers);
39 static char *nxt_php_read_cookies(void);
40 static void nxt_php_register_variables(zval *track_vars_array);
41 #ifdef NXT_HAVE_PHP_LOG_MESSAGE_WITH_SYSLOG_TYPE
42 static void nxt_php_log_message(char *message, int syslog_type_int);
43 #else
44 static void nxt_php_log_message(char *message);
45 #endif
46 
47 #ifdef NXT_PHP7
48 static size_t nxt_php_unbuffered_write(const char *str,
49     size_t str_length TSRMLS_DC);
50 static size_t nxt_php_read_post(char *buffer, size_t count_bytes TSRMLS_DC);
51 #else
52 static int nxt_php_unbuffered_write(const char *str, uint str_length TSRMLS_DC);
53 static int nxt_php_read_post(char *buffer, uint count_bytes TSRMLS_DC);
54 #endif
55 
56 static void nxt_php_flush(void *server_context);
57 
58 
59 static sapi_module_struct  nxt_php_sapi_module =
60 {
61     (char *) "cli-server",
62     (char *) "unit",
63 
64     nxt_php_startup,             /* startup */
65     php_module_shutdown_wrapper, /* shutdown */
66 
67     NULL,                        /* activate */
68     NULL,                        /* deactivate */
69 
70     nxt_php_unbuffered_write,    /* unbuffered write */
71     nxt_php_flush,               /* flush */
72     NULL,                        /* get uid */
73     NULL,                        /* getenv */
74 
75     php_error,                   /* error handler */
76 
77     NULL,                        /* header handler */
78     nxt_php_send_headers,        /* send headers handler */
79     NULL,                        /* send header handler */
80 
81     nxt_php_read_post,           /* read POST data */
82     nxt_php_read_cookies,        /* read Cookies */
83 
84     nxt_php_register_variables,  /* register server variables */
85     nxt_php_log_message,         /* log message */
86     NULL,                        /* get request time */
87     NULL,                        /* terminate process */
88 
89     NULL,                        /* php_ini_path_override */
90 #ifdef NXT_HAVE_PHP_INTERRUPTS
91     NULL,                        /* block_interruptions */
92     NULL,                        /* unblock_interruptions */
93 #endif
94     NULL,                        /* default_post_reader */
95     NULL,                        /* treat_data */
96     NULL,                        /* executable_location */
97 
98     0,                           /* php_ini_ignore */
99 #ifdef NXT_HAVE_PHP_IGNORE_CWD
100     0,                           /* php_ini_ignore_cwd */
101 #endif
102     NULL,                        /* get_fd */
103 
104     NULL,                        /* force_http_10 */
105 
106     NULL,                        /* get_target_uid */
107     NULL,                        /* get_target_gid */
108 
109     NULL,                        /* input_filter */
110 
111     NULL,                        /* ini_defaults */
112     0,                           /* phpinfo_as_text */
113 
114     NULL,                        /* ini_entries */
115     NULL,                        /* additional_functions */
116     NULL                         /* input_filter_init */
117 };
118 
119 typedef struct {
120     nxt_task_t           *task;
121     nxt_app_rmsg_t       *rmsg;
122     nxt_app_request_t    r;
123     nxt_str_t            script;
124     nxt_app_wmsg_t       *wmsg;
125 
126     size_t               body_preread_size;
127 } nxt_php_run_ctx_t;
128 
129 nxt_inline nxt_int_t nxt_php_write(nxt_php_run_ctx_t *ctx,
130                       const u_char *data, size_t len,
131                       nxt_bool_t flush, nxt_bool_t last);
132 
133 
134 static nxt_str_t nxt_php_path;
135 static nxt_str_t nxt_php_root;
136 static nxt_str_t nxt_php_script;
137 static nxt_str_t nxt_php_index = nxt_string("index.php");
138 
139 
140 static void
141 nxt_php_str_trim_trail(nxt_str_t *str, u_char t)
142 {
143     while (str->length > 0 && str->start[str->length - 1] == t) {
144         str->length--;
145     }
146 
147     str->start[str->length] = '\0';
148 }
149 
150 
151 static void
152 nxt_php_str_trim_lead(nxt_str_t *str, u_char t)
153 {
154     while (str->length > 0 && str->start[0] == t) {
155         str->length--;
156         str->start++;
157     }
158 }
159 
160 static uint32_t  compat[] = {
161     NXT_VERNUM, NXT_DEBUG,
162 };
163 
164 
165 NXT_EXPORT nxt_application_module_t  nxt_app_module = {
166     sizeof(compat),
167     compat,
168     nxt_string("php"),
169     PHP_VERSION,
170     nxt_php_init,
171     nxt_php_run,
172     NULL,
173 };
174 
175 
176 nxt_inline u_char *
177 nxt_realpath(const void *c)
178 {
179     return (u_char *) realpath(c, NULL);
180 }
181 
182 
183 static nxt_int_t
184 nxt_php_init(nxt_task_t *task, nxt_common_app_conf_t *conf)
185 {
186     u_char              *p;
187     nxt_str_t           rpath;
188     nxt_str_t           *root, *path, *script, *index;
189     nxt_php_app_conf_t  *c;
190 
191     c = &conf->u.php;
192 
193     if (c->root == NULL) {
194         nxt_alert(task, "php root is empty");
195         return NXT_ERROR;
196     }
197 
198     root = &nxt_php_root;
199     path = &nxt_php_path;
200     script = &nxt_php_script;
201     index = &nxt_php_index;
202 
203     root->start = nxt_realpath(c->root);
204     if (nxt_slow_path(root->start == NULL)) {
205         nxt_alert(task, "root realpath(%s) failed %E", c->root, nxt_errno);
206         return NXT_ERROR;
207     }
208 
209     root->length = nxt_strlen(root->start);
210 
211     nxt_php_str_trim_trail(root, '/');
212 
213     if (c->script.length > 0) {
214         nxt_php_str_trim_lead(&c->script, '/');
215 
216         path->length = root->length + 1 + c->script.length;
217         path->start = nxt_malloc(path->length + 1);
218         if (nxt_slow_path(path->start == NULL)) {
219             return NXT_ERROR;
220         }
221 
222         p = nxt_cpymem(path->start, root->start, root->length);
223         *p++ = '/';
224 
225         p = nxt_cpymem(p, c->script.start, c->script.length);
226         *p = '\0';
227 
228         rpath.start = nxt_realpath(path->start);
229         if (nxt_slow_path(rpath.start == NULL)) {
230             nxt_alert(task, "script realpath(%V) failed %E", path, nxt_errno);
231             return NXT_ERROR;
232         }
233 
234         rpath.length = nxt_strlen(rpath.start);
235 
236         if (!nxt_str_start(&rpath, root->start, root->length)) {
237             nxt_alert(task, "script is not under php root");
238             return NXT_ERROR;
239         }
240 
241         nxt_free(path->start);
242 
243         *path = rpath;
244 
245         script->length = c->script.length + 1;
246         script->start = nxt_malloc(script->length);
247         if (nxt_slow_path(script->start == NULL)) {
248             return NXT_ERROR;
249         }
250 
251         script->start[0] = '/';
252         nxt_memcpy(script->start + 1, c->script.start, c->script.length);
253 
254         nxt_log_error(NXT_LOG_INFO, task->log,
255                       "(ABS_MODE) php script \"%V\" root: \"%V\"",
256                       script, root);
257 
258     } else {
259         nxt_log_error(NXT_LOG_INFO, task->log,
260                       "(non ABS_MODE) php root: \"%V\"", root);
261     }
262 
263     if (c->index.length > 0) {
264         index->length = c->index.length;
265         index->start = nxt_malloc(index->length);
266         if (nxt_slow_path(index->start == NULL)) {
267             return NXT_ERROR;
268         }
269 
270         nxt_memcpy(index->start, c->index.start, c->index.length);
271     }
272 
273     sapi_startup(&nxt_php_sapi_module);
274     nxt_php_startup(&nxt_php_sapi_module);
275 
276     return NXT_OK;
277 }
278 
279 
280 static nxt_int_t
281 nxt_php_read_request(nxt_task_t *task, nxt_app_rmsg_t *rmsg,
282     nxt_php_run_ctx_t *ctx)
283 {
284     u_char                    *p;
285     size_t                    s;
286     nxt_int_t                 rc;
287     nxt_str_t                 script_name;
288     nxt_app_request_header_t  *h;
289 
290     h = &ctx->r.header;
291 
292 #define RC(S)                                                                 \
293     do {                                                                      \
294         rc = (S);                                                             \
295         if (nxt_slow_path(rc != NXT_OK)) {                                    \
296             goto fail;                                                        \
297         }                                                                     \
298     } while(0)
299 
300 #define NXT_READ(dst)                                                         \
301     RC(nxt_app_msg_read_str(task, rmsg, (dst)))
302 
303     NXT_READ(&h->method);
304     NXT_READ(&h->target);
305     NXT_READ(&h->path);
306 
307     RC(nxt_app_msg_read_size(task, rmsg, &s));
308     if (s > 0) {
309         s--;
310         h->query.start = h->target.start + s;
311         h->query.length = h->target.length - s;
312 
313         if (h->path.start == NULL) {
314             h->path.start = h->target.start;
315             h->path.length = s - 1;
316         }
317     }
318 
319     if (h->path.start == NULL) {
320         h->path = h->target;
321     }
322 
323     if (nxt_php_path.start == NULL) {
324         if (h->path.start[h->path.length - 1] == '/') {
325             script_name = nxt_php_index;
326 
327         } else {
328             script_name.length = 0;
329             script_name.start = NULL;
330         }
331 
332         ctx->script.length = nxt_php_root.length + h->path.length
333                              + script_name.length;
334         p = ctx->script.start = nxt_malloc(ctx->script.length + 1);
335         if (nxt_slow_path(p == NULL)) {
336             return NXT_ERROR;
337         }
338 
339         p = nxt_cpymem(p, nxt_php_root.start, nxt_php_root.length);
340         p = nxt_cpymem(p, h->path.start, h->path.length);
341 
342         if (script_name.length > 0) {
343             p = nxt_cpymem(p, script_name.start, script_name.length);
344         }
345 
346         *p = '\0';
347 
348     } else {
349         ctx->script = nxt_php_path;
350     }
351 
352     NXT_READ(&h->version);
353 
354     NXT_READ(&ctx->r.remote);
355     NXT_READ(&ctx->r.local);
356 
357     NXT_READ(&h->host);
358     NXT_READ(&h->cookie);
359     NXT_READ(&h->content_type);
360     NXT_READ(&h->content_length);
361 
362     RC(nxt_app_msg_read_size(task, rmsg, &s));
363     h->parsed_content_length = s;
364 
365     RC(nxt_app_msg_read_size(task, ctx->rmsg, &ctx->body_preread_size));
366 
367 #undef NXT_READ
368 #undef RC
369 
370     /* Further headers read moved to nxt_php_register_variables. */
371     return NXT_OK;
372 
373 fail:
374 
375     return rc;
376 }
377 
378 
379 static nxt_int_t
380 nxt_php_run(nxt_task_t *task,
381     nxt_app_rmsg_t *rmsg, nxt_app_wmsg_t *wmsg)
382 {
383     nxt_int_t                 rc;
384     zend_file_handle          file_handle;
385     nxt_php_run_ctx_t         run_ctx;
386     nxt_app_request_header_t  *h;
387 
388     nxt_memzero(&run_ctx, sizeof(run_ctx));
389 
390     run_ctx.task = task;
391     run_ctx.rmsg = rmsg;
392     run_ctx.wmsg = wmsg;
393 
394     h = &run_ctx.r.header;
395 
396     rc = nxt_php_read_request(task, rmsg, &run_ctx);
397 
398     if (nxt_slow_path(rc != NXT_OK)) {
399         goto fail;
400     }
401 
402     SG(server_context) = &run_ctx;
403     SG(request_info).request_uri = (char *) h->target.start;
404     SG(request_info).request_method = (char *) h->method.start;
405 
406     SG(request_info).proto_num = 1001;
407 
408     SG(request_info).query_string = (char *) h->query.start;
409     SG(request_info).content_length = h->parsed_content_length;
410 
411     if (h->content_type.start != NULL) {
412         SG(request_info).content_type = (char *) h->content_type.start;
413     }
414 
415     SG(sapi_headers).http_response_code = 200;
416 
417     SG(request_info).path_translated = NULL;
418 
419     file_handle.type = ZEND_HANDLE_FILENAME;
420     file_handle.filename = (char *) run_ctx.script.start;
421     file_handle.free_filename = 0;
422     file_handle.opened_path = NULL;
423 
424     nxt_debug(task, "handle.filename = '%s'", run_ctx.script.start);
425 
426     if (nxt_php_path.start != NULL) {
427         nxt_debug(task, "run script %V in absolute mode", &nxt_php_path);
428 
429     } else {
430         nxt_debug(task, "run script %V", &run_ctx.script);
431     }
432 
433     if (nxt_slow_path(php_request_startup() == FAILURE)) {
434         nxt_debug(task, "php_request_startup() failed");
435         rc = NXT_ERROR;
436         goto fail;
437     }
438 
439     php_execute_script(&file_handle TSRMLS_CC);
440     php_request_shutdown(NULL);
441 
442     nxt_app_msg_flush(task, wmsg, 1);
443 
444     rc = NXT_OK;
445 
446 fail:
447 
448     if (run_ctx.script.start != nxt_php_path.start) {
449         nxt_free(run_ctx.script.start);
450     }
451 
452     return rc;
453 }
454 
455 
456 nxt_inline nxt_int_t
457 nxt_php_write(nxt_php_run_ctx_t *ctx, const u_char *data, size_t len,
458     nxt_bool_t flush, nxt_bool_t last)
459 {
460     nxt_int_t  rc;
461 
462     if (len > 0) {
463         rc = nxt_app_msg_write_raw(ctx->task, ctx->wmsg, data, len);
464 
465     } else {
466         rc = NXT_OK;
467     }
468 
469     if (flush || last) {
470         rc = nxt_app_msg_flush(ctx->task, ctx->wmsg, last);
471     }
472 
473     return rc;
474 }
475 
476 
477 static int
478 nxt_php_startup(sapi_module_struct *sapi_module)
479 {
480    return php_module_startup(sapi_module, NULL, 0);
481 }
482 
483 
484 #ifdef NXT_PHP7
485 static size_t
486 nxt_php_unbuffered_write(const char *str, size_t str_length TSRMLS_DC)
487 #else
488 static int
489 nxt_php_unbuffered_write(const char *str, uint str_length TSRMLS_DC)
490 #endif
491 {
492     nxt_int_t          rc;
493     nxt_php_run_ctx_t  *ctx;
494 
495     ctx = SG(server_context);
496 
497     rc = nxt_php_write(ctx, (u_char *) str, str_length, 1, 0);
498 
499     if (nxt_fast_path(rc == NXT_OK)) {
500         return str_length;
501     }
502 
503     // TODO handle NXT_AGAIN
504     php_handle_aborted_connection();
505     return 0;
506 }
507 
508 
509 static void
510 nxt_php_flush(void *server_context)
511 {
512     nxt_php_run_ctx_t  *ctx;
513 
514     ctx = server_context;
515 
516     (void) nxt_app_msg_flush(ctx->task, ctx->wmsg, 0);
517 }
518 
519 
520 static int
521 nxt_php_send_headers(sapi_headers_struct *sapi_headers TSRMLS_DC)
522 {
523     size_t               len;
524     u_char               *status, buf[64];
525     nxt_int_t            rc;
526     nxt_php_run_ctx_t    *ctx;
527     sapi_header_struct   *h;
528     zend_llist_position  zpos;
529 
530     static const u_char default_repsonse[]
531         = "Status: 200\r\n"
532           "\r\n";
533 
534     static const u_char status_200[] = "Status: 200";
535     static const u_char cr_lf[] = "\r\n";
536 
537     ctx = SG(server_context);
538 
539 #define RC(S)                                                                 \
540     do {                                                                      \
541         rc = (S);                                                             \
542         if (nxt_slow_path(rc != NXT_OK)) {                                    \
543             goto fail;                                                        \
544         }                                                                     \
545     } while(0)
546 
547     if (SG(request_info).no_headers == 1) {
548         RC(nxt_php_write(ctx, default_repsonse, sizeof(default_repsonse) - 1,
549                       1, 0));
550         return SAPI_HEADER_SENT_SUCCESSFULLY;
551     }
552 
553     if (SG(sapi_headers).http_status_line) {
554         status = (u_char *) SG(sapi_headers).http_status_line;
555         len = nxt_strlen(status);
556 
557         if (len < 12) {
558             goto fail;
559         }
560 
561         RC(nxt_php_write(ctx, status_200, sizeof(status_200) - 4, 0, 0));
562         RC(nxt_php_write(ctx, status + 9, 3, 0, 0));
563 
564     } else if (SG(sapi_headers).http_response_code) {
565         status = nxt_sprintf(buf, buf + sizeof(buf), "%03d",
566                         SG(sapi_headers).http_response_code);
567         len = status - buf;
568 
569         RC(nxt_php_write(ctx, status_200, sizeof(status_200) - 4, 0, 0));
570         RC(nxt_php_write(ctx, buf, len, 0, 0));
571 
572     } else {
573         RC(nxt_php_write(ctx, status_200, sizeof(status_200) - 1, 0, 0));
574     }
575 
576     RC(nxt_php_write(ctx, cr_lf, sizeof(cr_lf) - 1, 0, 0));
577 
578     h = zend_llist_get_first_ex(&sapi_headers->headers, &zpos);
579 
580     while (h) {
581         RC(nxt_php_write(ctx, (u_char *) h->header, h->header_len, 0, 0));
582         RC(nxt_php_write(ctx, cr_lf, sizeof(cr_lf) - 1, 0, 0));
583 
584         h = zend_llist_get_next_ex(&sapi_headers->headers, &zpos);
585     }
586 
587     RC(nxt_php_write(ctx, cr_lf, sizeof(cr_lf) - 1, 1, 0));
588 
589 #undef RC
590 
591     return SAPI_HEADER_SENT_SUCCESSFULLY;
592 
593 fail:
594 
595     // TODO handle NXT_AGAIN
596     return SAPI_HEADER_SEND_FAILED;
597 }
598 
599 
600 #ifdef NXT_PHP7
601 static size_t
602 nxt_php_read_post(char *buffer, size_t count_bytes TSRMLS_DC)
603 #else
604 static int
605 nxt_php_read_post(char *buffer, uint count_bytes TSRMLS_DC)
606 #endif
607 {
608     size_t                    size, rest;
609     nxt_php_run_ctx_t         *ctx;
610     nxt_app_request_header_t  *h;
611 
612     ctx = SG(server_context);
613     h = &ctx->r.header;
614 
615     rest = (size_t) h->parsed_content_length - SG(read_post_bytes);
616 
617     nxt_debug(ctx->task, "nxt_php_read_post %O", rest);
618 
619     if (rest == 0) {
620         return 0;
621     }
622 
623     rest = nxt_min(ctx->body_preread_size, (size_t) count_bytes);
624     size = nxt_app_msg_read_raw(ctx->task, ctx->rmsg, buffer, rest);
625 
626     ctx->body_preread_size -= size;
627 
628     return size;
629 }
630 
631 
632 static char *
633 nxt_php_read_cookies(TSRMLS_D)
634 {
635     nxt_php_run_ctx_t  *ctx;
636 
637     ctx = SG(server_context);
638 
639     nxt_debug(ctx->task, "nxt_php_read_cookies");
640 
641     return (char *) ctx->r.header.cookie.start;
642 }
643 
644 
645 static void
646 nxt_php_register_variables(zval *track_vars_array TSRMLS_DC)
647 {
648     u_char                    *colon;
649     nxt_str_t                 n, v;
650     nxt_int_t                 rc;
651     nxt_str_t                 host, server_name, server_port;
652     nxt_task_t                *task;
653     nxt_php_run_ctx_t         *ctx;
654     nxt_app_request_header_t  *h;
655 
656     static nxt_str_t def_host = nxt_string("localhost");
657     static nxt_str_t def_port = nxt_string("80");
658 
659     ctx = SG(server_context);
660 
661     h = &ctx->r.header;
662     task = ctx->task;
663 
664     nxt_debug(task, "php register variables");
665 
666 #define NXT_PHP_SET(n, v)                                                     \
667     nxt_debug(task, "php: register %s='%V'", n, &v);                          \
668     php_register_variable_safe((char *) (n), (char *) (v).start,              \
669                                (v).length, track_vars_array TSRMLS_CC)        \
670 
671     NXT_PHP_SET("SERVER_SOFTWARE", nxt_server);
672 
673     NXT_PHP_SET("SERVER_PROTOCOL", h->version);
674 
675 /*
676  * 'SCRIPT_NAME'
677  * Contains the current script's path. This is useful for pages which need to
678  * point to themselves. The __FILE__ constant contains the full path and
679  * filename of the current (i.e. included) file.
680  */
681 
682 /*
683  * 'SCRIPT_FILENAME'
684  * The absolute pathname of the currently executing script.
685  */
686 
687 /*
688  * 'DOCUMENT_ROOT'
689  * The document root directory under which the current script is executing,
690  * as defined in the server's configuration file.
691  */
692 
693     if (nxt_php_script.start != NULL) {
694     // ABS_MODE
695 /*
696  * 'PHP_SELF'
697  * The filename of the currently executing script, relative to the document
698  * root. For instance, $_SERVER['PHP_SELF'] in a script at the address
699  * http://example.com/foo/bar.php would be /foo/bar.php. The __FILE__ constant
700  * contains the full path and filename of the current (i.e. included) file.
701  * If PHP is running as a command-line processor this variable contains the
702  * script name since PHP 4.3.0. Previously it was not available.
703  */
704         NXT_PHP_SET("PHP_SELF", nxt_php_script);
705         NXT_PHP_SET("SCRIPT_NAME", nxt_php_script);
706 
707     } else {
708         NXT_PHP_SET("PHP_SELF", h->path);
709         NXT_PHP_SET("SCRIPT_NAME", h->path);
710     }
711 
712     NXT_PHP_SET("SCRIPT_FILENAME", ctx->script);
713     NXT_PHP_SET("DOCUMENT_ROOT", nxt_php_root);
714 
715     NXT_PHP_SET("REQUEST_METHOD", h->method);
716     NXT_PHP_SET("REQUEST_URI", h->target);
717 
718     if (h->query.start != NULL) {
719         NXT_PHP_SET("QUERY_STRING", h->query);
720     }
721 
722     if (h->content_type.start != NULL) {
723         NXT_PHP_SET("CONTENT_TYPE", h->content_type);
724     }
725 
726     if (h->content_length.start != NULL) {
727         NXT_PHP_SET("CONTENT_LENGTH", h->content_length);
728     }
729 
730     host = h->host;
731     if (host.length == 0) {
732         host = def_host;
733     }
734 
735     server_name = host;
736     colon = nxt_memchr(host.start, ':', host.length);
737 
738     if (colon != NULL) {
739         server_name.length = colon - host.start;
740 
741         server_port.start = colon + 1;
742         server_port.length = host.length - server_name.length - 1;
743 
744     } else {
745         server_port = def_port;
746     }
747 
748     NXT_PHP_SET("SERVER_NAME", server_name);
749     NXT_PHP_SET("SERVER_PORT", server_port);
750 
751     NXT_PHP_SET("REMOTE_ADDR", ctx->r.remote);
752     NXT_PHP_SET("SERVER_ADDR", ctx->r.local);
753 
754     while (nxt_app_msg_read_str(task, ctx->rmsg, &n) == NXT_OK) {
755         if (nxt_slow_path(n.length == 0)) {
756             break;
757         }
758 
759         rc = nxt_app_msg_read_str(task, ctx->rmsg, &v);
760         if (nxt_slow_path(rc != NXT_OK)) {
761             break;
762         }
763 
764         NXT_PHP_SET(n.start, v);
765     }
766 
767 #undef NXT_PHP_SET
768 }
769 
770 
771 #ifdef NXT_HAVE_PHP_LOG_MESSAGE_WITH_SYSLOG_TYPE
772 static void
773 nxt_php_log_message(char *message, int syslog_type_int)
774 #else
775 static void
776 nxt_php_log_message(char *message)
777 #endif
778 {
779     nxt_thread_log_error(NXT_LOG_NOTICE, "php message: %s", message);
780 }
781