Add sub-controls for Hack array compat runtime checks
[hiphop-php.git] / hphp / runtime / base / emulate-zend.cpp
bloba24d3aca76efbc47e4d226f714070a90172098b3
1 /*
2 +----------------------------------------------------------------------+
3 | HipHop for PHP |
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"
19 #include <assert.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
24 #include <vector>
25 #include <string>
26 #include <iostream>
27 #include <sstream>
29 #include <folly/portability/Fcntl.h>
30 #include <folly/portability/Stdlib.h>
31 #include <folly/portability/Unistd.h>
33 namespace HPHP {
35 int execute_program(int argc, char **argv);
37 static int get_tempfile_if_not_exists(int ini_fd, char ini_path[]) {
38 if (ini_fd == -1) {
39 #ifdef _MSC_VER
40 // MSVC doesn't require the characters to be the last
41 // 6 in the string.
42 ini_fd = open(mktemp(ini_path), O_RDWR | O_EXCL);
43 #else
44 ini_fd = mkstemps(ini_path, 4); // keep the .ini suffix
45 #endif
46 if (ini_fd == -1) {
47 fprintf(stderr, "Error: unable to open temporary file");
48 exit(EXIT_FAILURE);
51 return ini_fd;
54 int emulate_zend(int argc, char** argv) {
55 std::vector<std::string> newargv;
57 newargv.push_back(argv[0]);
59 bool lint = false;
60 bool show = false;
61 bool need_file = true;
62 int ini_fd = -1;
63 char ini_path[] = "/tmp/php-ini-XXXXXX.ini";
64 std::string ini_section = "";
65 const char* program = nullptr;
67 int cnt = 1;
68 bool ignore_default_configs = ::getenv("HHVM_NO_DEFAULT_CONFIGS") != nullptr;
69 while (cnt < argc) {
70 if (strcmp(argv[cnt], "-a") == 0 ||
71 strcmp(argv[cnt], "--interactive") == 0) {
72 need_file = false;
73 newargv.push_back("-a");
74 cnt++;
75 continue;
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());
81 cnt += 2;
82 continue;
84 if (strcmp(argv[cnt], "-l") == 0 || strcmp(argv[cnt], "--lint") == 0) {
85 cnt++;
86 lint = true;
87 continue;
89 if (strcmp(argv[cnt], "-r") == 0) {
90 if (cnt + 1 == argc) {
91 // Hmm, no program fragment passed along. Let hhvm print its usage
92 // message?
93 newargv.push_back(argv[cnt++]);
94 continue;
96 assert(cnt + 1 < argc);
97 program = argv[cnt + 1];
98 need_file = true;
99 cnt += 2;
100 continue;
102 if (strcmp(argv[cnt], "-i") == 0 || strcmp(argv[cnt], "--info") == 0) {
103 // Pretend they did "-r 'phpinfo();'"
104 program = "phpinfo();";
105 need_file = true;
106 cnt = argc; // no need to check the rest of options and arguments
107 break;
109 if (strcmp(argv[cnt], "-w") == 0) {
110 cnt++;
111 show = true;
112 continue;
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
117 need_file = false;
118 break;
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
124 need_file = false;
125 break;
127 if (strcmp(argv[cnt], "-f") == 0 || strcmp(argv[cnt], "--file") == 0) {
128 cnt++;
129 newargv.push_back(lint ? "-l" : "-f");
130 newargv.push_back(argv[cnt++]);
131 need_file = false;
132 break;
134 if (strcmp(argv[cnt], "-n") == 0) {
135 ignore_default_configs = true;
136 cnt++;
137 newargv.push_back("--no-config");
138 continue;
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]);
144 cnt = cnt + 2;
145 continue;
146 } else {
147 fprintf(stderr, "Notice: No config file specified");
148 exit(EXIT_FAILURE);
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);
174 cnt += 2;
175 continue;
177 if (argv[cnt][0] != '-') {
178 if (show) {
179 newargv.push_back("-w");
180 } else {
181 newargv.push_back(lint ? "-l" : "-f");
183 newargv.push_back(argv[cnt++]);
184 need_file = false;
185 break;
187 if (strcmp(argv[cnt], "--") == 0) {
188 break;
190 cnt++; // skip unknown options
193 if (need_file) {
194 char tmp[] = "/tmp/php-wrap-XXXXXX";
195 int tmp_fd = mkstemp(tmp);
196 if (tmp_fd == -1) {
197 fprintf(stderr, "Error: unable to open temporary file");
198 exit(EXIT_FAILURE);
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.
203 std::string line;
204 while (std::getline(std::cin, line)) {
205 write(tmp_fd, line.c_str(), line.length());
206 write(tmp_fd, "\n", 1);
208 } else {
209 // -r omits the braces
210 write(tmp_fd, "<?\n", 3);
211 write(tmp_fd, program, strlen(program));
213 close(tmp_fd);
215 if (show) {
216 newargv.push_back("-w");
217 } else {
218 newargv.push_back(lint ? "-l" : "-f");
220 newargv.push_back(tmp);
221 newargv.push_back("--temp-file");
224 if (ini_fd != -1) {
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);
232 } else {
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);
237 #endif
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++;
250 if (cnt < argc) {
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);
268 if (ini_fd != -1) {
269 unlink(ini_path);
272 return ret;