2 +----------------------------------------------------------------------+
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-present Facebook, Inc. (http://www.facebook.com) |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
16 #include "hphp/runtime/base/emulate-zend.h"
17 #include "hphp/runtime/base/ini-setting.h"
29 #include <folly/portability/Fcntl.h>
30 #include <folly/portability/Stdlib.h>
31 #include <folly/portability/Unistd.h>
35 int execute_program(int argc
, char **argv
);
37 static int get_tempfile_if_not_exists(int ini_fd
, char ini_path
[]) {
40 // MSVC doesn't require the characters to be the last
42 ini_fd
= open(mktemp(ini_path
), O_RDWR
| O_EXCL
);
44 ini_fd
= mkstemps(ini_path
, 4); // keep the .ini suffix
47 fprintf(stderr
, "Error: unable to open temporary file");
54 int emulate_zend(int argc
, char** argv
) {
55 std::vector
<std::string
> newargv
;
57 newargv
.push_back(argv
[0]);
61 bool need_file
= true;
63 char ini_path
[] = "/tmp/php-ini-XXXXXX.ini";
64 std::string ini_section
= "";
65 const char* program
= nullptr;
68 bool ignore_default_configs
= ::getenv("HHVM_NO_DEFAULT_CONFIGS") != nullptr;
70 if (strcmp(argv
[cnt
], "-a") == 0 ||
71 strcmp(argv
[cnt
], "--interactive") == 0) {
73 newargv
.push_back("-a");
77 if (strcmp(argv
[cnt
], "-z") == 0) {
78 std::string arg
= "-vDynamicExtensions.0=";
79 arg
.append(argv
[cnt
+1]);
80 newargv
.push_back(arg
.c_str());
84 if (strcmp(argv
[cnt
], "-l") == 0 || strcmp(argv
[cnt
], "--lint") == 0) {
89 if (strcmp(argv
[cnt
], "-r") == 0) {
90 if (cnt
+ 1 == argc
) {
91 // Hmm, no program fragment passed along. Let hhvm print its usage
93 newargv
.push_back(argv
[cnt
++]);
96 assert(cnt
+ 1 < argc
);
97 program
= argv
[cnt
+ 1];
102 if (strcmp(argv
[cnt
], "-i") == 0 || strcmp(argv
[cnt
], "--info") == 0) {
103 // Pretend they did "-r 'phpinfo();'"
104 program
= "phpinfo();";
106 cnt
= argc
; // no need to check the rest of options and arguments
109 if (strcmp(argv
[cnt
], "-w") == 0) {
114 if (strcmp(argv
[cnt
], "-v") == 0 || strcmp(argv
[cnt
], "--version") == 0) {
115 newargv
.push_back("--version");
116 cnt
= argc
; // no need to check the rest of options and arguments
120 if (strcmp(argv
[cnt
], "--modules") == 0) {
121 // zend has a -m flag but we're already using it for --mode
122 newargv
.push_back("--modules");
123 cnt
= argc
; // no need to check the rest of options and arguments
127 if (strcmp(argv
[cnt
], "-f") == 0 || strcmp(argv
[cnt
], "--file") == 0) {
129 newargv
.push_back(lint
? "-l" : "-f");
130 newargv
.push_back(argv
[cnt
++]);
134 if (strcmp(argv
[cnt
], "-n") == 0) {
135 ignore_default_configs
= true;
137 newargv
.push_back("--no-config");
140 if (strcmp(argv
[cnt
], "-c") == 0) {
141 if (cnt
+ 1 < argc
&& argv
[cnt
+ 1][0] != '-') {
142 newargv
.push_back("-c");
143 newargv
.push_back(argv
[cnt
+ 1]);
147 fprintf(stderr
, "Notice: No config file specified");
151 if (strcmp(argv
[cnt
], "-d") == 0 || strcmp(argv
[cnt
], "--define") == 0) {
152 ini_fd
= get_tempfile_if_not_exists(ini_fd
, ini_path
);
154 std::string line
= argv
[cnt
+1];
155 std::string section
= "php";
156 int pos_period
= line
.find_first_of('.');
157 int pos_equals
= line
.find_first_of('=');
159 if (pos_period
!= std::string::npos
&&
160 pos_equals
!= std::string::npos
&&
161 pos_period
< pos_equals
) {
162 section
= line
.substr(0, pos_period
);
165 if (section
!= ini_section
) {
166 ini_section
= section
;
167 write(ini_fd
, "[", 1);
168 write(ini_fd
, section
.c_str(), section
.length());
169 write(ini_fd
, "]\n", 2);
172 write(ini_fd
, line
.c_str(), line
.length());
173 write(ini_fd
, "\n", 1);
177 if (argv
[cnt
][0] != '-') {
179 newargv
.push_back("-w");
181 newargv
.push_back(lint
? "-l" : "-f");
183 newargv
.push_back(argv
[cnt
++]);
187 if (strcmp(argv
[cnt
], "--") == 0) {
190 cnt
++; // skip unknown options
194 char tmp
[] = "/tmp/php-wrap-XXXXXX";
195 int tmp_fd
= mkstemp(tmp
);
197 fprintf(stderr
, "Error: unable to open temporary file");
200 if (program
== nullptr) {
201 // If the program wasn't specified on the command-line, ala' -r,
202 // is no command-line parameter, read the PHP file from stdin.
204 while (std::getline(std::cin
, line
)) {
205 write(tmp_fd
, line
.c_str(), line
.length());
206 write(tmp_fd
, "\n", 1);
209 // -r omits the braces
210 write(tmp_fd
, "<?\n", 3);
211 write(tmp_fd
, program
, strlen(program
));
216 newargv
.push_back("-w");
218 newargv
.push_back(lint
? "-l" : "-f");
220 newargv
.push_back(tmp
);
221 newargv
.push_back("--temp-file");
225 newargv
.push_back("-c");
226 newargv
.push_back(ini_path
);
229 if (ignore_default_configs
) {
230 // Appending empty file to -c options to avoid loading defaults
231 ini_fd
= get_tempfile_if_not_exists(ini_fd
, ini_path
);
233 // Should only include this default if not explicitly ignored.
234 #ifdef PHP_DEFAULT_HDF
235 newargv
.push_back("-c");
236 newargv
.push_back(PHP_DEFAULT_HDF
);
239 // If the -c option is specified without a -n, php behavior is to
240 // load the default ini/hdf
241 auto cb
= [&newargv
] (const char *filename
) {
242 newargv
.push_back("-c");
243 newargv
.push_back(filename
);
245 add_default_config_files_globbed(DEFAULT_CONFIG_DIR
"/php*.ini", cb
);
246 add_default_config_files_globbed(DEFAULT_CONFIG_DIR
"/config*.hdf", cb
);
249 if (cnt
< argc
&& strcmp(argv
[cnt
], "--") == 0) cnt
++;
251 // There are arguments following the filename, so copy them.
252 newargv
.push_back("--");
253 for (int i
= cnt
; i
< argc
; i
++) {
254 newargv
.push_back(argv
[i
]);
258 char** newargv_array
= (char**)alloca(sizeof(char*) * (newargv
.size() + 1));
259 for (unsigned i
= 0; i
< newargv
.size(); i
++) {
260 // printf("%s\n", newargv[i].data());
261 newargv_array
[i
] = (char *)newargv
[i
].data();
263 // NULL-terminate the argument array.
264 newargv_array
[newargv
.size()] = nullptr;
266 auto ret
= execute_program(newargv
.size(), newargv_array
);