summaryrefslogtreecommitdiffhomepage
path: root/src/nxt_php_sapi.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nxt_php_sapi.c')
-rw-r--r--src/nxt_php_sapi.c446
1 files changed, 241 insertions, 205 deletions
diff --git a/src/nxt_php_sapi.c b/src/nxt_php_sapi.c
index f5053652..ccbdd475 100644
--- a/src/nxt_php_sapi.c
+++ b/src/nxt_php_sapi.c
@@ -29,8 +29,20 @@
#define NXT_PHP7 1
#endif
+
+typedef struct {
+ nxt_str_t root;
+ nxt_str_t index;
+ nxt_str_t script_name;
+ nxt_str_t script_dirname;
+ nxt_str_t script_filename;
+} nxt_php_target_t;
+
+
typedef struct {
char *cookie;
+ nxt_str_t *root;
+ nxt_str_t *index;
nxt_str_t path_info;
nxt_str_t script_name;
nxt_str_t script_filename;
@@ -53,26 +65,27 @@ typedef void (*zif_handler)(INTERNAL_FUNCTION_PARAMETERS);
static nxt_int_t nxt_php_init(nxt_task_t *task, nxt_common_app_conf_t *conf);
+static nxt_int_t nxt_php_set_target(nxt_task_t *task, nxt_php_target_t *target,
+ nxt_conf_value_t *conf);
+static void nxt_php_set_options(nxt_task_t *task, nxt_conf_value_t *options,
+ int type);
+static nxt_int_t nxt_php_alter_option(nxt_str_t *name, nxt_str_t *value,
+ int type);
+static void nxt_php_disable(nxt_task_t *task, const char *type,
+ nxt_str_t *value, char **ptr, nxt_php_disable_t disable);
+static nxt_int_t nxt_php_dirname(const nxt_str_t *file, nxt_str_t *dir);
static void nxt_php_str_trim_trail(nxt_str_t *str, u_char t);
static void nxt_php_str_trim_lead(nxt_str_t *str, u_char t);
-static nxt_int_t nxt_php_dirname(const nxt_str_t *file, nxt_str_t *dir);
nxt_inline u_char *nxt_realpath(const void *c);
-nxt_inline void nxt_php_vcwd_chdir(nxt_unit_request_info_t *req,
- const nxt_str_t *dirname);
-static void nxt_php_script_request_handler(nxt_unit_request_info_t *req);
-static void nxt_php_path_request_handler(nxt_unit_request_info_t *req);
-static nxt_int_t nxt_php_request_init(nxt_php_run_ctx_t *ctx,
+static void nxt_php_request_handler(nxt_unit_request_info_t *req);
+static void nxt_php_dynamic_request(nxt_php_run_ctx_t *ctx,
nxt_unit_request_t *r);
+static void nxt_php_execute(nxt_php_run_ctx_t *ctx, nxt_unit_request_t *r);
+nxt_inline void nxt_php_vcwd_chdir(nxt_unit_request_info_t *req, u_char *dir);
static int nxt_php_startup(sapi_module_struct *sapi_module);
-static void nxt_php_set_options(nxt_task_t *task, nxt_conf_value_t *options,
- int type);
-static nxt_int_t nxt_php_alter_option(nxt_str_t *name, nxt_str_t *value,
- int type);
-static void nxt_php_disable(nxt_task_t *task, const char *type,
- nxt_str_t *value, char **ptr, nxt_php_disable_t disable);
static int nxt_php_send_headers(sapi_headers_struct *sapi_headers TSRMLS_DC);
static void *nxt_php_hash_str_find_ptr(const HashTable *ht,
const nxt_str_t *str);
@@ -210,13 +223,6 @@ static sapi_module_struct nxt_php_sapi_module =
};
-static nxt_str_t nxt_php_root;
-static nxt_str_t nxt_php_script_name;
-static nxt_str_t nxt_php_script_dirname;
-static nxt_str_t nxt_php_script_filename;
-static nxt_str_t nxt_php_index = nxt_string("index.php");
-
-
static uint32_t compat[] = {
NXT_VERNUM, NXT_DEBUG,
};
@@ -232,6 +238,9 @@ NXT_EXPORT nxt_app_module_t nxt_app_module = {
};
+static nxt_php_target_t *nxt_php_targets;
+static nxt_int_t nxt_php_last_target = -1;
+
static nxt_task_t *nxt_php_task;
#if defined(ZTS) && PHP_VERSION_ID < 70400
static void ***tsrm_ls;
@@ -241,11 +250,11 @@ static void ***tsrm_ls;
static nxt_int_t
nxt_php_init(nxt_task_t *task, nxt_common_app_conf_t *conf)
{
- u_char *p, *tmp;
- nxt_str_t ini_path;
- nxt_str_t *root, *script_filename, *script_dirname, *script_name;
- nxt_str_t *index;
+ u_char *p;
+ uint32_t next;
+ nxt_str_t ini_path, name;
nxt_int_t ret;
+ nxt_uint_t n;
nxt_port_t *my_port, *main_port;
nxt_runtime_t *rt;
nxt_unit_ctx_t *unit_ctx;
@@ -261,105 +270,33 @@ nxt_php_init(nxt_task_t *task, nxt_common_app_conf_t *conf)
c = &conf->u.php;
- if (c->root == NULL) {
- nxt_alert(task, "php root is empty");
- return NXT_ERROR;
- }
-
- root = &nxt_php_root;
- script_filename = &nxt_php_script_filename;
- script_dirname = &nxt_php_script_dirname;
- script_name = &nxt_php_script_name;
- index = &nxt_php_index;
+ n = (c->targets != NULL) ? nxt_conf_object_members_count(c->targets) : 1;
- root->start = nxt_realpath(c->root);
- if (nxt_slow_path(root->start == NULL)) {
- nxt_alert(task, "root realpath(%s) failed %E", c->root, nxt_errno);
+ nxt_php_targets = nxt_zalloc(sizeof(nxt_php_target_t) * n);
+ if (nxt_slow_path(nxt_php_targets == NULL)) {
return NXT_ERROR;
}
- root->length = nxt_strlen(root->start);
-
- nxt_php_str_trim_trail(root, '/');
-
- if (c->script.length > 0) {
- nxt_php_str_trim_lead(&c->script, '/');
-
- tmp = nxt_malloc(root->length + 1 + c->script.length + 1);
- if (nxt_slow_path(tmp == NULL)) {
- return NXT_ERROR;
- }
-
- p = tmp;
-
- p = nxt_cpymem(p, root->start, root->length);
- *p++ = '/';
-
- p = nxt_cpymem(p, c->script.start, c->script.length);
- *p = '\0';
-
- script_filename->start = nxt_realpath(tmp);
- if (nxt_slow_path(script_filename->start == NULL)) {
- nxt_alert(task, "script realpath(%s) failed %E", tmp, nxt_errno);
- return NXT_ERROR;
- }
-
- nxt_free(tmp);
-
- script_filename->length = nxt_strlen(script_filename->start);
-
- if (!nxt_str_start(script_filename, root->start, root->length)) {
- nxt_alert(task, "script is not under php root");
- return NXT_ERROR;
- }
+ if (c->targets != NULL) {
+ next = 0;
- ret = nxt_php_dirname(script_filename, script_dirname);
- if (nxt_slow_path(ret != NXT_OK)) {
- return NXT_ERROR;
- }
+ for (n = 0; /* void */; n++) {
+ value = nxt_conf_next_object_member(c->targets, &name, &next);
+ if (value == NULL) {
+ break;
+ }
- script_name->length = c->script.length + 1;
- script_name->start = nxt_malloc(script_name->length);
- if (nxt_slow_path(script_name->start == NULL)) {
- return NXT_ERROR;
+ ret = nxt_php_set_target(task, &nxt_php_targets[n], value);
+ if (nxt_slow_path(ret != NXT_OK)) {
+ return NXT_ERROR;
+ }
}
- script_name->start[0] = '/';
- nxt_memcpy(script_name->start + 1, c->script.start, c->script.length);
-
- nxt_log_error(NXT_LOG_INFO, task->log,
- "(ABS_MODE) php script \"%V\" root: \"%V\"",
- script_name, root);
-
} else {
- nxt_log_error(NXT_LOG_INFO, task->log,
- "(non ABS_MODE) php root: \"%V\"", root);
- }
-
- if (c->index.length > 0) {
- index->length = c->index.length;
- index->start = nxt_malloc(index->length);
- if (nxt_slow_path(index->start == NULL)) {
- return NXT_ERROR;
- }
-
- nxt_memcpy(index->start, c->index.start, c->index.length);
- }
-
- nxt_memzero(&php_init, sizeof(nxt_unit_init_t));
-
- if (nxt_php_script_filename.start != NULL) {
- if (nxt_slow_path(chdir((char *) script_dirname->start) != 0)) {
- nxt_alert(task, "failed to chdir(%V) %E", script_dirname,
- nxt_errno);
-
+ ret = nxt_php_set_target(task, &nxt_php_targets[0], conf->self);
+ if (nxt_slow_path(ret != NXT_OK)) {
return NXT_ERROR;
}
-
- php_init.callbacks.request_handler = nxt_php_script_request_handler;
-
- } else {
- php_init.callbacks.request_handler = nxt_php_path_request_handler;
}
#ifdef ZTS
@@ -430,6 +367,10 @@ nxt_php_init(nxt_task_t *task, nxt_common_app_conf_t *conf)
return NXT_ERROR;
}
+ nxt_memzero(&php_init, sizeof(nxt_unit_init_t));
+
+ php_init.callbacks.request_handler = nxt_php_request_handler;
+
php_init.ready_port.id.pid = main_port->pid;
php_init.ready_port.id.id = main_port->id;
php_init.ready_port.out_fd = main_port->pair[1];
@@ -462,6 +403,125 @@ nxt_php_init(nxt_task_t *task, nxt_common_app_conf_t *conf)
}
+static nxt_int_t
+nxt_php_set_target(nxt_task_t *task, nxt_php_target_t *target,
+ nxt_conf_value_t *conf)
+{
+ u_char *tmp, *p;
+ nxt_str_t str;
+ nxt_int_t ret;
+ nxt_conf_value_t *value;
+
+ static nxt_str_t root_str = nxt_string("root");
+ static nxt_str_t script_str = nxt_string("script");
+ static nxt_str_t index_str = nxt_string("index");
+
+ value = nxt_conf_get_object_member(conf, &root_str, NULL);
+
+ if (value == NULL) {
+ nxt_alert(task, "no php root specified");
+ return NXT_ERROR;
+ }
+
+ nxt_conf_get_string(value, &str);
+
+ tmp = nxt_malloc(str.length + 1);
+ if (nxt_slow_path(tmp == NULL)) {
+ return NXT_ERROR;
+ }
+
+ p = tmp;
+
+ p = nxt_cpymem(p, str.start, str.length);
+ *p = '\0';
+
+ p = nxt_realpath(tmp);
+ if (nxt_slow_path(p == NULL)) {
+ nxt_alert(task, "root realpath(%s) failed %E", tmp, nxt_errno);
+ return NXT_ERROR;
+ }
+
+ nxt_free(tmp);
+
+ target->root.length = nxt_strlen(p);
+ target->root.start = p;
+
+ nxt_php_str_trim_trail(&target->root, '/');
+
+ value = nxt_conf_get_object_member(conf, &script_str, NULL);
+
+ if (value != NULL) {
+ nxt_conf_get_string(value, &str);
+
+ nxt_php_str_trim_lead(&str, '/');
+
+ tmp = nxt_malloc(target->root.length + 1 + str.length + 1);
+ if (nxt_slow_path(tmp == NULL)) {
+ return NXT_ERROR;
+ }
+
+ p = tmp;
+
+ p = nxt_cpymem(p, target->root.start, target->root.length);
+ *p++ = '/';
+
+ p = nxt_cpymem(p, str.start, str.length);
+ *p = '\0';
+
+ p = nxt_realpath(tmp);
+ if (nxt_slow_path(p == NULL)) {
+ nxt_alert(task, "script realpath(%s) failed %E", tmp, nxt_errno);
+ return NXT_ERROR;
+ }
+
+ nxt_free(tmp);
+
+ target->script_filename.length = nxt_strlen(p);
+ target->script_filename.start = p;
+
+ if (!nxt_str_start(&target->script_filename,
+ target->root.start, target->root.length))
+ {
+ nxt_alert(task, "script is not under php root");
+ return NXT_ERROR;
+ }
+
+ ret = nxt_php_dirname(&target->script_filename,
+ &target->script_dirname);
+ if (nxt_slow_path(ret != NXT_OK)) {
+ return NXT_ERROR;
+ }
+
+ target->script_name.length = target->script_filename.length
+ - target->root.length;
+ target->script_name.start = target->script_filename.start
+ + target->root.length;
+
+ } else {
+ value = nxt_conf_get_object_member(conf, &index_str, NULL);
+
+ if (value != NULL) {
+ nxt_conf_get_string(value, &str);
+
+ tmp = nxt_malloc(str.length);
+ if (nxt_slow_path(tmp == NULL)) {
+ return NXT_ERROR;
+ }
+
+ nxt_memcpy(tmp, str.start, str.length);
+
+ target->index.length = str.length;
+ target->index.start = tmp;
+
+ } else {
+ nxt_str_set(&target->index, "index.php");
+ }
+ }
+
+ return NXT_OK;
+}
+
+
static void
nxt_php_set_options(nxt_task_t *task, nxt_conf_value_t *options, int type)
{
@@ -686,56 +746,44 @@ nxt_realpath(const void *c)
static void
-nxt_php_script_request_handler(nxt_unit_request_info_t *req)
+nxt_php_request_handler(nxt_unit_request_info_t *req)
{
- zend_file_handle file_handle;
- nxt_php_run_ctx_t ctx;
+ nxt_php_target_t *target;
+ nxt_php_run_ctx_t ctx;
+ nxt_unit_request_t *r;
+
+ r = req->request;
+ target = &nxt_php_targets[r->app_target];
nxt_memzero(&ctx, sizeof(ctx));
ctx.req = req;
- ctx.script_filename = nxt_php_script_filename;
- ctx.script_dirname = nxt_php_script_dirname;
- ctx.script_name = nxt_php_script_name;
-
- nxt_memzero(&file_handle, sizeof(file_handle));
+ ctx.root = &target->root;
+ ctx.index = &target->index;
- file_handle.type = ZEND_HANDLE_FILENAME;
- file_handle.filename = (char *) ctx.script_filename.start;
-
- if (nxt_slow_path(nxt_php_request_init(&ctx, req->request) != NXT_OK)) {
- nxt_unit_request_done(req, NXT_UNIT_ERROR);
+ if (target->script_filename.length == 0) {
+ nxt_php_dynamic_request(&ctx, r);
return;
}
- php_execute_script(&file_handle TSRMLS_CC);
+ ctx.script_filename = target->script_filename;
+ ctx.script_dirname = target->script_dirname;
+ ctx.script_name = target->script_name;
- if (ctx.chdir) {
- nxt_php_vcwd_chdir(ctx.req, &nxt_php_script_dirname);
- }
+ ctx.chdir = (r->app_target != nxt_php_last_target);
- php_request_shutdown(NULL);
+ nxt_php_execute(&ctx, r);
- nxt_unit_request_done(req, NXT_UNIT_OK);
+ nxt_php_last_target = ctx.chdir ? -1 : r->app_target;
}
static void
-nxt_php_path_request_handler(nxt_unit_request_info_t *req)
+nxt_php_dynamic_request(nxt_php_run_ctx_t *ctx, nxt_unit_request_t *r)
{
- u_char *p;
- nxt_str_t path, script_name;
- nxt_int_t ret;
- zend_file_handle file_handle;
- nxt_php_run_ctx_t run_ctx, *ctx;
- nxt_unit_request_t *r;
-
- nxt_memzero(&run_ctx, sizeof(run_ctx));
-
- ctx = &run_ctx;
- ctx->req = req;
-
- r = req->request;
+ u_char *p;
+ nxt_str_t path, script_name;
+ nxt_int_t ret;
path.length = r->path_length;
path.start = nxt_unit_sptr_get(&r->path);
@@ -750,26 +798,26 @@ nxt_php_path_request_handler(nxt_unit_request_info_t *req)
ctx->path_info.length = r->path_length - path.length;
} else if (path.start[path.length - 1] == '/') {
- script_name = nxt_php_index;
+ script_name = *ctx->index;
} else {
if (nxt_slow_path(path.length < 4
|| nxt_memcmp(path.start + (path.length - 4),
".php", 4)))
{
- nxt_unit_request_done(req, NXT_UNIT_ERROR);
+ nxt_unit_request_done(ctx->req, NXT_UNIT_ERROR);
return;
}
}
- ctx->script_filename.length = nxt_php_root.length
+ ctx->script_filename.length = ctx->root->length
+ path.length
+ script_name.length;
p = nxt_malloc(ctx->script_filename.length + 1);
if (nxt_slow_path(p == NULL)) {
- nxt_unit_request_done(req, NXT_UNIT_ERROR);
+ nxt_unit_request_done(ctx->req, NXT_UNIT_ERROR);
return;
}
@@ -777,9 +825,9 @@ nxt_php_path_request_handler(nxt_unit_request_info_t *req)
ctx->script_filename.start = p;
ctx->script_name.length = path.length + script_name.length;
- ctx->script_name.start = p + nxt_php_root.length;
+ ctx->script_name.start = p + ctx->root->length;
- p = nxt_cpymem(p, nxt_php_root.start, nxt_php_root.length);
+ p = nxt_cpymem(p, ctx->root->start, ctx->root->length);
p = nxt_cpymem(p, path.start, path.length);
if (script_name.length > 0) {
@@ -788,50 +836,33 @@ nxt_php_path_request_handler(nxt_unit_request_info_t *req)
*p = '\0';
- nxt_memzero(&file_handle, sizeof(file_handle));
-
- file_handle.type = ZEND_HANDLE_FILENAME;
- file_handle.filename = (char *) ctx->script_filename.start;
+ ctx->chdir = 1;
ret = nxt_php_dirname(&ctx->script_filename, &ctx->script_dirname);
if (nxt_slow_path(ret != NXT_OK)) {
- nxt_unit_request_done(req, NXT_UNIT_ERROR);
+ nxt_unit_request_done(ctx->req, NXT_UNIT_ERROR);
nxt_free(ctx->script_filename.start);
return;
}
- if (nxt_slow_path(nxt_php_request_init(ctx, req->request) != NXT_OK)) {
- nxt_unit_request_done(req, NXT_UNIT_ERROR);
- goto cleanup;
- }
-
- nxt_php_vcwd_chdir(ctx->req, &ctx->script_dirname);
-
- php_execute_script(&file_handle TSRMLS_CC);
-
- php_request_shutdown(NULL);
-
- nxt_unit_request_done(req, NXT_UNIT_OK);
-
-cleanup:
+ nxt_php_execute(ctx, r);
nxt_free(ctx->script_filename.start);
nxt_free(ctx->script_dirname.start);
-}
-
-static int
-nxt_php_startup(sapi_module_struct *sapi_module)
-{
- return php_module_startup(sapi_module, &nxt_php_unit_module, 1);
+ nxt_php_last_target = -1;
}
-static nxt_int_t
-nxt_php_request_init(nxt_php_run_ctx_t *ctx, nxt_unit_request_t *r)
+static void
+nxt_php_execute(nxt_php_run_ctx_t *ctx, nxt_unit_request_t *r)
{
nxt_unit_field_t *f;
+ zend_file_handle file_handle;
+
+ nxt_unit_req_debug(ctx->req, "PHP execute script %s",
+ ctx->script_filename.start);
SG(server_context) = ctx;
SG(options) |= SAPI_OPTION_NO_CHDIR;
@@ -860,20 +891,6 @@ nxt_php_request_init(nxt_php_run_ctx_t *ctx, nxt_unit_request_t *r)
SG(request_info).path_translated = NULL;
- nxt_unit_req_debug(ctx->req, "handle.filename = '%s'",
- ctx->script_filename.start);
-
- if (nxt_php_script_filename.start != NULL) {
- nxt_unit_req_debug(ctx->req, "run script %.*s in absolute mode",
- (int) nxt_php_script_filename.length,
- (char *) nxt_php_script_filename.start);
-
- } else {
- nxt_unit_req_debug(ctx->req, "run script %.*s",
- (int) ctx->script_filename.length,
- (char *) ctx->script_filename.start);
- }
-
#ifdef NXT_PHP7
if (nxt_slow_path(php_request_startup() == FAILURE)) {
#else
@@ -881,23 +898,45 @@ nxt_php_request_init(nxt_php_run_ctx_t *ctx, nxt_unit_request_t *r)
#endif
nxt_unit_req_debug(ctx->req, "php_request_startup() failed");
- return NXT_ERROR;
+ nxt_unit_request_done(ctx->req, NXT_UNIT_ERROR);
+ return;
}
- return NXT_OK;
+ if (ctx->chdir) {
+ ctx->chdir = 0;
+ nxt_php_vcwd_chdir(ctx->req, ctx->script_dirname.start);
+ }
+
+ nxt_memzero(&file_handle, sizeof(file_handle));
+
+ file_handle.type = ZEND_HANDLE_FILENAME;
+ file_handle.filename = (char *) ctx->script_filename.start;
+
+ php_execute_script(&file_handle TSRMLS_CC);
+
+ php_request_shutdown(NULL);
+
+ nxt_unit_request_done(ctx->req, NXT_UNIT_OK);
}
nxt_inline void
-nxt_php_vcwd_chdir(nxt_unit_request_info_t *req, const nxt_str_t *dir)
+nxt_php_vcwd_chdir(nxt_unit_request_info_t *req, u_char *dir)
{
- if (nxt_slow_path(VCWD_CHDIR((char *) dir->start) != 0)) {
+ if (nxt_slow_path(VCWD_CHDIR((char *) dir) != 0)) {
nxt_unit_req_alert(req, "VCWD_CHDIR(%s) failed (%d: %s)",
- dir->start, errno, strerror(errno));
+ dir, errno, strerror(errno));
}
}
+static int
+nxt_php_startup(sapi_module_struct *sapi_module)
+{
+ return php_module_startup(sapi_module, &nxt_php_unit_module, 1);
+}
+
+
#ifdef NXT_PHP7
static size_t
nxt_php_unbuffered_write(const char *str, size_t str_length TSRMLS_DC)
@@ -1061,19 +1100,16 @@ nxt_php_register_variables(zval *track_vars_array TSRMLS_DC)
* available.
*/
- if (nxt_php_script_name.start != NULL) {
- /* ABS_MODE */
- nxt_php_set_str(req, "PHP_SELF", &nxt_php_script_name,
- track_vars_array TSRMLS_CC);
-
- } else {
+ if (ctx->path_info.length != 0) {
nxt_php_set_sptr(req, "PHP_SELF", &r->path, r->path_length,
track_vars_array TSRMLS_CC);
- }
- if (ctx->path_info.length != 0) {
nxt_php_set_str(req, "PATH_INFO", &ctx->path_info,
track_vars_array TSRMLS_CC);
+
+ } else {
+ nxt_php_set_str(req, "PHP_SELF", &ctx->script_name,
+ track_vars_array TSRMLS_CC);
}
/*
@@ -1100,7 +1136,7 @@ nxt_php_register_variables(zval *track_vars_array TSRMLS_DC)
* as defined in the server's configuration file.
*/
- nxt_php_set_str(req, "DOCUMENT_ROOT", &nxt_php_root,
+ nxt_php_set_str(req, "DOCUMENT_ROOT", ctx->root,
track_vars_array TSRMLS_CC);
nxt_php_set_sptr(req, "REQUEST_METHOD", &r->method, r->method_length,