Skip to content

Commit 7e92f63

Browse files
committed
Integrate Shanes patch that allows specifying the cwd and environment
for the child process created by proc_open().
1 parent c40eff3 commit 7e92f63

File tree

2 files changed

+168
-12
lines changed

2 files changed

+168
-12
lines changed

ext/standard/proc_open.c

Lines changed: 156 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,136 @@
5656

5757
static int le_proc_open;
5858

59+
/* {{{ _php_array_to_envp */
60+
static php_process_env_t _php_array_to_envp(zval *environment, int is_persistent TSRMLS_DC)
61+
{
62+
zval **element;
63+
php_process_env_t env;
64+
char *string_key, *data;
65+
#ifndef PHP_WIN32
66+
char **ep;
67+
#endif
68+
char *p;
69+
uint string_length, cnt, l, sizeenv=0, el_len;
70+
ulong num_key;
71+
HashTable *target_hash;
72+
HashPosition pos;
73+
74+
memset(&env, 0, sizeof(env));
75+
76+
if (!environment) {
77+
return env;
78+
}
79+
80+
cnt = zend_hash_num_elements(Z_ARRVAL_P(environment));
81+
82+
if (cnt < 1) {
83+
return env;
84+
}
85+
86+
target_hash = HASH_OF(environment);
87+
if (!target_hash) {
88+
return env;
89+
}
90+
91+
/* first, we have to get the size of all the elements in the hash */
92+
for (zend_hash_internal_pointer_reset_ex(target_hash, &pos);
93+
zend_hash_get_current_data_ex(target_hash, (void **) &element, &pos) == SUCCESS;
94+
zend_hash_move_forward_ex(target_hash, &pos)) {
95+
96+
convert_to_string_ex(element);
97+
el_len = Z_STRLEN_PP(element);
98+
if (el_len == 0) {
99+
continue;
100+
}
101+
102+
sizeenv += el_len+1;
103+
104+
switch (zend_hash_get_current_key_ex(target_hash, &string_key, &string_length, &num_key, 0, &pos)) {
105+
case HASH_KEY_IS_STRING:
106+
if (string_length == 0) {
107+
continue;
108+
}
109+
sizeenv += string_length+1;
110+
break;
111+
}
112+
}
113+
114+
#ifndef PHP_WIN32
115+
ep = env.envarray = (char **) pecalloc(cnt + 1, sizeof(char *), is_persistent);
116+
#endif
117+
p = env.envp = (char *) pecalloc(sizeenv + 4, 1, is_persistent);
118+
119+
for (zend_hash_internal_pointer_reset_ex(target_hash, &pos);
120+
zend_hash_get_current_data_ex(target_hash, (void **) &element, &pos) == SUCCESS;
121+
zend_hash_move_forward_ex(target_hash, &pos)) {
122+
123+
convert_to_string_ex(element);
124+
el_len = Z_STRLEN_PP(element);
125+
126+
if (el_len == 0) {
127+
continue;
128+
}
129+
130+
data = Z_STRVAL_PP(element);
131+
switch (zend_hash_get_current_key_ex(target_hash, &string_key, &string_length, &num_key, 0, &pos)) {
132+
case HASH_KEY_IS_STRING:
133+
if (string_length == 0) {
134+
continue;
135+
}
136+
l = string_length + el_len + 1;
137+
memcpy(p, string_key, string_length);
138+
strcat(p, "=");
139+
strcat(p, data);
140+
141+
if (PG(magic_quotes_gpc)) {
142+
php_stripslashes(p, &l TSRMLS_CC);
143+
}
144+
#ifndef PHP_WIN32
145+
*ep = p;
146+
++ep;
147+
#endif
148+
p += l;
149+
break;
150+
case HASH_KEY_IS_LONG:
151+
memcpy(p,data,el_len);
152+
if (PG(magic_quotes_gpc)) {
153+
php_stripslashes(p, &el_len TSRMLS_CC);
154+
}
155+
#ifndef PHP_WIN32
156+
*ep = p;
157+
++ep;
158+
#endif
159+
p += el_len + 1;
160+
break;
161+
case HASH_KEY_NON_EXISTANT:
162+
break;
163+
}
164+
}
165+
166+
assert(p - env.envp <= sizeenv);
167+
168+
zend_hash_internal_pointer_reset_ex(target_hash, &pos);
169+
170+
return env;
171+
}
172+
/* }}} */
173+
174+
/* {{{ _php_free_envp */
175+
static void _php_free_envp(php_process_env_t env, int is_persistent)
176+
{
177+
#ifndef PHP_WIN32
178+
if (env.envarray) {
179+
pefree(env.envarray, is_persistent);
180+
}
181+
#endif
182+
if (env.envp) {
183+
pefree(env.envp, is_persistent);
184+
}
185+
}
186+
/* }}} */
187+
188+
59189
static void proc_open_rsrc_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC)
60190
{
61191
struct php_process_handle *proc = (struct php_process_handle*)rsrc->ptr;
@@ -98,7 +228,7 @@ static void proc_open_rsrc_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC)
98228
#else
99229
FG(pclose_ret) = -1;
100230
#endif
101-
231+
_php_free_envp(proc->env, proc->is_persistent);
102232
pefree(proc->command, proc->is_persistent);
103233
pefree(proc, proc->is_persistent);
104234

@@ -166,8 +296,6 @@ static int php_make_safe_mode_command(char *cmd, char **safecmd, int is_persiste
166296
}
167297
/* }}} */
168298

169-
170-
171299
PHP_MINIT_FUNCTION(proc_open)
172300
{
173301
le_proc_open = zend_register_list_destructors_ex(proc_open_rsrc_dtor, NULL, "process", module_number);
@@ -321,15 +449,17 @@ struct php_proc_open_descriptor_item {
321449
};
322450
/* }}} */
323451

324-
/* {{{ proto resource proc_open(string command, array descriptorspec, array &pipes)
452+
/* {{{ proto resource proc_open(string command, array descriptorspec, array &pipes [, string cwd [, array env]])
325453
Run a process with more control over it's file descriptors */
326454
PHP_FUNCTION(proc_open)
327455
{
328456

329-
char *command;
330-
long command_len;
457+
char *command, *cwd=NULL;
458+
long command_len, cwd_len;
331459
zval *descriptorspec;
332460
zval *pipes;
461+
zval *environment = NULL;
462+
php_process_env_t env;
333463
int ndesc = 0;
334464
int i;
335465
zval **descitem = NULL;
@@ -346,8 +476,8 @@ PHP_FUNCTION(proc_open)
346476
struct php_process_handle *proc;
347477
int is_persistent = 0; /* TODO: ensure that persistent procs will work */
348478

349-
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "saz/", &command,
350-
&command_len, &descriptorspec, &pipes) == FAILURE) {
479+
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "saz/|sa!", &command,
480+
&command_len, &descriptorspec, &pipes, &cwd, &cwd_len, &environment) == FAILURE) {
351481
RETURN_FALSE;
352482
}
353483

@@ -357,6 +487,12 @@ PHP_FUNCTION(proc_open)
357487

358488
command_len = strlen(command);
359489

490+
if (environment) {
491+
env = _php_array_to_envp(environment, is_persistent TSRMLS_CC);
492+
} else {
493+
memset(&env, 0, sizeof(env));
494+
}
495+
360496
memset(descriptors, 0, sizeof(descriptors));
361497

362498
#ifdef PHP_WIN32
@@ -538,7 +674,7 @@ PHP_FUNCTION(proc_open)
538674

539675
command_with_cmd = emalloc(command_len + sizeof(COMSPEC_9X) + 1 + sizeof(" /c "));
540676
sprintf(command_with_cmd, "%s /c %s", GetVersion() < 0x80000000 ? COMSPEC_NT : COMSPEC_9X, command);
541-
newprocok = CreateProcess(NULL, command_with_cmd, &security, &security, TRUE, NORMAL_PRIORITY_CLASS, NULL, NULL, &si, &pi);
677+
newprocok = CreateProcess(NULL, command_with_cmd, &security, &security, TRUE, NORMAL_PRIORITY_CLASS, env.envp, cwd, &si, &pi);
542678
efree(command_with_cmd);
543679

544680
if (FALSE == newprocok) {
@@ -551,7 +687,6 @@ PHP_FUNCTION(proc_open)
551687

552688
#elif HAVE_FORK
553689
/* the unix way */
554-
555690
child = fork();
556691

557692
if (child == 0) {
@@ -571,8 +706,15 @@ PHP_FUNCTION(proc_open)
571706
if (descriptors[i].childend != descriptors[i].index)
572707
close(descriptors[i].childend);
573708
}
574-
575-
execl("/bin/sh", "sh", "-c", command, NULL);
709+
if (cwd) {
710+
chdir(cwd);
711+
}
712+
713+
if (env.envarray) {
714+
execle("/bin/sh", "sh", "-c", command, NULL, env.envarray);
715+
} else {
716+
execl("/bin/sh", "sh", "-c", command, NULL);
717+
}
576718
_exit(127);
577719

578720
} else if (child < 0) {
@@ -599,6 +741,7 @@ PHP_FUNCTION(proc_open)
599741
proc->command = command;
600742
proc->npipes = ndesc;
601743
proc->child = child;
744+
proc->env = env;
602745

603746
array_init(pipes);
604747

@@ -657,6 +800,7 @@ PHP_FUNCTION(proc_open)
657800
return;
658801

659802
exit_fail:
803+
_php_free_envp(env, is_persistent);
660804
pefree(command, is_persistent);
661805
RETURN_FALSE;
662806

ext/standard/proc_open.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,23 @@ typedef pid_t php_process_id_t;
2727

2828
#define PHP_PROC_OPEN_MAX_DESCRIPTORS 16
2929

30+
/* Environment block under win32 is a NUL terminated sequence of NUL terminated
31+
* name=value strings.
32+
* Under unix, it is an argv style array.
33+
* */
34+
typedef struct _php_process_env {
35+
char *envp;
36+
#ifndef PHP_WIN32
37+
char **envarray;
38+
#endif
39+
} php_process_env_t;
40+
3041
struct php_process_handle {
3142
php_process_id_t child;
3243
int npipes;
3344
long pipes[PHP_PROC_OPEN_MAX_DESCRIPTORS];
3445
char *command;
3546
int is_persistent;
47+
php_process_env_t env;
3648
};
3749

0 commit comments

Comments
 (0)