1 /*
2 +----------------------------------------------------------------------+
3 | Zend OPcache |
4 +----------------------------------------------------------------------+
5 | Copyright (c) The PHP Group |
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 | https://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 +----------------------------------------------------------------------+
15 | Authors: Andi Gutmans <andi@php.net> |
16 | Zeev Suraski <zeev@php.net> |
17 | Stanislav Malyshev <stas@zend.com> |
18 | Dmitry Stogov <dmitry@php.net> |
19 +----------------------------------------------------------------------+
20 */
21
22 #include <time.h>
23
24 #include "php.h"
25 #include "ZendAccelerator.h"
26 #include "zend_API.h"
27 #include "zend_shared_alloc.h"
28 #include "zend_accelerator_blacklist.h"
29 #include "php_ini.h"
30 #include "SAPI.h"
31 #include "zend_virtual_cwd.h"
32 #include "ext/standard/info.h"
33 #include "ext/standard/php_filestat.h"
34 #include "opcache_arginfo.h"
35
36 #if HAVE_JIT
37 #include "jit/zend_jit.h"
38 #endif
39
40 #define STRING_NOT_NULL(s) (NULL == (s)?"":s)
41 #define MIN_ACCEL_FILES 200
42 #define MAX_ACCEL_FILES 1000000
43 #define MAX_INTERNED_STRINGS_BUFFER_SIZE ((zend_long)((UINT32_MAX-PLATFORM_ALIGNMENT-sizeof(zend_accel_shared_globals))/(1024*1024)))
44 #define TOKENTOSTR(X) #X
45
46 static zif_handler orig_file_exists = NULL;
47 static zif_handler orig_is_file = NULL;
48 static zif_handler orig_is_readable = NULL;
49
validate_api_restriction(void)50 static int validate_api_restriction(void)
51 {
52 if (ZCG(accel_directives).restrict_api && *ZCG(accel_directives).restrict_api) {
53 size_t len = strlen(ZCG(accel_directives).restrict_api);
54
55 if (!SG(request_info).path_translated ||
56 strlen(SG(request_info).path_translated) < len ||
57 memcmp(SG(request_info).path_translated, ZCG(accel_directives).restrict_api, len) != 0) {
58 zend_error(E_WARNING, ACCELERATOR_PRODUCT_NAME " API is restricted by \"restrict_api\" configuration directive");
59 return 0;
60 }
61 }
62 return 1;
63 }
64
ZEND_INI_MH(OnUpdateMemoryConsumption)65 static ZEND_INI_MH(OnUpdateMemoryConsumption)
66 {
67 zend_long *p = (zend_long *) ZEND_INI_GET_ADDR();
68 zend_long memsize = atoi(ZSTR_VAL(new_value));
69 /* sanity check we must use at least 8 MB */
70 if (memsize < 8) {
71 zend_accel_error(ACCEL_LOG_WARNING, "opcache.memory_consumption is set below the required 8MB.\n");
72 return FAILURE;
73 }
74 if (UNEXPECTED(memsize > ZEND_LONG_MAX / (1024 * 1024))) {
75 *p = ZEND_LONG_MAX & ~(1024 * 1024 - 1);
76 } else {
77 *p = memsize * (1024 * 1024);
78 }
79 return SUCCESS;
80 }
81
ZEND_INI_MH(OnUpdateInternedStringsBuffer)82 static ZEND_INI_MH(OnUpdateInternedStringsBuffer)
83 {
84 zend_long *p = (zend_long *) ZEND_INI_GET_ADDR();
85 zend_long size = zend_ini_parse_quantity_warn(new_value, entry->name);
86
87 if (size < 0) {
88 zend_accel_error(ACCEL_LOG_WARNING, "opcache.interned_strings_buffer must be greater than or equal to 0, " ZEND_LONG_FMT " given.\n", size);
89 return FAILURE;
90 }
91 if (size > MAX_INTERNED_STRINGS_BUFFER_SIZE) {
92 zend_accel_error(ACCEL_LOG_WARNING, "opcache.interned_strings_buffer must be less than or equal to " ZEND_LONG_FMT ", " ZEND_LONG_FMT " given.\n", MAX_INTERNED_STRINGS_BUFFER_SIZE, size);
93 return FAILURE;
94 }
95
96 *p = size;
97
98 return SUCCESS;
99 }
100
ZEND_INI_MH(OnUpdateMaxAcceleratedFiles)101 static ZEND_INI_MH(OnUpdateMaxAcceleratedFiles)
102 {
103 zend_long *p = (zend_long *) ZEND_INI_GET_ADDR();
104 zend_long size = atoi(ZSTR_VAL(new_value));
105 /* sanity check we must use a value between MIN_ACCEL_FILES and MAX_ACCEL_FILES */
106 if (size < MIN_ACCEL_FILES) {
107 zend_accel_error(ACCEL_LOG_WARNING, "opcache.max_accelerated_files is set below the required minimum (%d).\n", MIN_ACCEL_FILES);
108 return FAILURE;
109 }
110 if (size > MAX_ACCEL_FILES) {
111 zend_accel_error(ACCEL_LOG_WARNING, "opcache.max_accelerated_files is set above the limit (%d).\n", MAX_ACCEL_FILES);
112 return FAILURE;
113 }
114 *p = size;
115 return SUCCESS;
116 }
117
ZEND_INI_MH(OnUpdateMaxWastedPercentage)118 static ZEND_INI_MH(OnUpdateMaxWastedPercentage)
119 {
120 double *p = (double *) ZEND_INI_GET_ADDR();
121 zend_long percentage = atoi(ZSTR_VAL(new_value));
122
123 if (percentage <= 0 || percentage > 50) {
124 zend_accel_error(ACCEL_LOG_WARNING, "opcache.max_wasted_percentage must be set between 1 and 50.\n");
125 return FAILURE;
126 }
127 *p = (double)percentage / 100.0;
128 return SUCCESS;
129 }
130
ZEND_INI_MH(OnUpdateConsistencyChecks)131 static ZEND_INI_MH(OnUpdateConsistencyChecks)
132 {
133 zend_long *p = (zend_long *) ZEND_INI_GET_ADDR();
134 zend_long consistency_checks = atoi(ZSTR_VAL(new_value));
135
136 if (consistency_checks != 0) {
137 zend_accel_error(ACCEL_LOG_WARNING, "opcache.consistency_checks is reset back to 0 because it does not work properly (see GH-8065, GH-10624).\n");
138 return FAILURE;
139 }
140 *p = 0;
141 return SUCCESS;
142 }
143
ZEND_INI_MH(OnEnable)144 static ZEND_INI_MH(OnEnable)
145 {
146 if (stage == ZEND_INI_STAGE_STARTUP ||
147 stage == ZEND_INI_STAGE_SHUTDOWN ||
148 stage == ZEND_INI_STAGE_DEACTIVATE) {
149 return OnUpdateBool(entry, new_value, mh_arg1, mh_arg2, mh_arg3, stage);
150 } else {
151 /* It may be only temporary disabled */
152 bool *p = (bool *) ZEND_INI_GET_ADDR();
153 if (zend_ini_parse_bool(new_value)) {
154 zend_error(E_WARNING, ACCELERATOR_PRODUCT_NAME " can't be temporary enabled (it may be only disabled till the end of request)");
155 return FAILURE;
156 } else {
157 *p = 0;
158 ZCG(accelerator_enabled) = 0;
159 return SUCCESS;
160 }
161 }
162 }
163
ZEND_INI_MH(OnUpdateFileCache)164 static ZEND_INI_MH(OnUpdateFileCache)
165 {
166 if (new_value) {
167 if (!ZSTR_LEN(new_value)) {
168 new_value = NULL;
169 } else {
170 zend_stat_t buf = {0};
171
172 if (!IS_ABSOLUTE_PATH(ZSTR_VAL(new_value), ZSTR_LEN(new_value)) ||
173 zend_stat(ZSTR_VAL(new_value), &buf) != 0 ||
174 !S_ISDIR(buf.st_mode) ||
175 #ifndef ZEND_WIN32
176 access(ZSTR_VAL(new_value), R_OK | W_OK | X_OK) != 0) {
177 #else
178 _access(ZSTR_VAL(new_value), 06) != 0) {
179 #endif
180 zend_accel_error(ACCEL_LOG_WARNING, "opcache.file_cache must be a full path of accessible directory.\n");
181 new_value = NULL;
182 }
183 }
184 }
185 OnUpdateString(entry, new_value, mh_arg1, mh_arg2, mh_arg3, stage);
186 return SUCCESS;
187 }
188
189 #ifdef HAVE_JIT
190 static ZEND_INI_MH(OnUpdateJit)
191 {
192 if (zend_jit_config(new_value, stage) == SUCCESS) {
193 return OnUpdateString(entry, new_value, mh_arg1, mh_arg2, mh_arg3, stage);
194 }
195 return FAILURE;
196 }
197
198 static ZEND_INI_MH(OnUpdateJitDebug)
199 {
200 zend_long *p = (zend_long *) ZEND_INI_GET_ADDR();
201 zend_long val = zend_ini_parse_quantity_warn(new_value, entry->name);
202
203 if (zend_jit_debug_config(*p, val, stage) == SUCCESS) {
204 *p = val;
205 return SUCCESS;
206 }
207 return FAILURE;
208 }
209
210 static ZEND_INI_MH(OnUpdateCounter)
211 {
212 zend_long val = zend_ini_parse_quantity_warn(new_value, entry->name);
213 if (val >= 0 && val < 256) {
214 zend_long *p = (zend_long *) ZEND_INI_GET_ADDR();
215 *p = val;
216 return SUCCESS;
217 }
218 zend_error(E_WARNING, "Invalid \"%s\" setting; using default value instead. Should be between 0 and 255", ZSTR_VAL(entry->name));
219 return FAILURE;
220 }
221
222 static ZEND_INI_MH(OnUpdateUnrollC)
223 {
224 zend_long val = zend_ini_parse_quantity_warn(new_value, entry->name);
225 if (val > 0 && val < ZEND_JIT_TRACE_MAX_CALL_DEPTH) {
226 zend_long *p = (zend_long *) ZEND_INI_GET_ADDR();
227 *p = val;
228 return SUCCESS;
229 }
230 zend_error(E_WARNING, "Invalid \"%s\" setting. Should be between 1 and %d", ZSTR_VAL(entry->name),
231 ZEND_JIT_TRACE_MAX_CALL_DEPTH);
232 return FAILURE;
233 }
234
235 static ZEND_INI_MH(OnUpdateUnrollR)
236 {
237 zend_long val = zend_ini_parse_quantity_warn(new_value, entry->name);
238 if (val >= 0 && val < ZEND_JIT_TRACE_MAX_RET_DEPTH) {
239 zend_long *p = (zend_long *) ZEND_INI_GET_ADDR();
240 *p = val;
241 return SUCCESS;
242 }
243 zend_error(E_WARNING, "Invalid \"%s\" setting. Should be between 0 and %d", ZSTR_VAL(entry->name),
244 ZEND_JIT_TRACE_MAX_RET_DEPTH);
245 return FAILURE;
246 }
247
248 static ZEND_INI_MH(OnUpdateUnrollL)
249 {
250 zend_long val = zend_ini_parse_quantity_warn(new_value, entry->name);
251 if (val > 0 && val < ZEND_JIT_TRACE_MAX_LOOPS_UNROLL) {
252 zend_long *p = (zend_long *) ZEND_INI_GET_ADDR();
253 *p = val;
254 return SUCCESS;
255 }
256 zend_error(E_WARNING, "Invalid \"%s\" setting. Should be between 1 and %d", ZSTR_VAL(entry->name),
257 ZEND_JIT_TRACE_MAX_LOOPS_UNROLL);
258 return FAILURE;
259 }
260 #endif
261
262 ZEND_INI_BEGIN()
263 STD_PHP_INI_BOOLEAN("opcache.enable" , "1", PHP_INI_ALL, OnEnable, enabled , zend_accel_globals, accel_globals)
264 STD_PHP_INI_BOOLEAN("opcache.use_cwd" , "1", PHP_INI_SYSTEM, OnUpdateBool, accel_directives.use_cwd , zend_accel_globals, accel_globals)
265 STD_PHP_INI_BOOLEAN("opcache.validate_timestamps", "1", PHP_INI_ALL , OnUpdateBool, accel_directives.validate_timestamps, zend_accel_globals, accel_globals)
266 STD_PHP_INI_BOOLEAN("opcache.validate_permission", "0", PHP_INI_SYSTEM, OnUpdateBool, accel_directives.validate_permission, zend_accel_globals, accel_globals)
267 #ifndef ZEND_WIN32
268 STD_PHP_INI_BOOLEAN("opcache.validate_root" , "0", PHP_INI_SYSTEM, OnUpdateBool, accel_directives.validate_root , zend_accel_globals, accel_globals)
269 #endif
270 STD_PHP_INI_BOOLEAN("opcache.dups_fix" , "0", PHP_INI_ALL , OnUpdateBool, accel_directives.ignore_dups , zend_accel_globals, accel_globals)
271 STD_PHP_INI_BOOLEAN("opcache.revalidate_path" , "0", PHP_INI_ALL , OnUpdateBool, accel_directives.revalidate_path , zend_accel_globals, accel_globals)
272
273 STD_PHP_INI_ENTRY("opcache.log_verbosity_level" , "1" , PHP_INI_SYSTEM, OnUpdateLong, accel_directives.log_verbosity_level, zend_accel_globals, accel_globals)
274 STD_PHP_INI_ENTRY("opcache.memory_consumption" , "128" , PHP_INI_SYSTEM, OnUpdateMemoryConsumption, accel_directives.memory_consumption, zend_accel_globals, accel_globals)
275 STD_PHP_INI_ENTRY("opcache.interned_strings_buffer", "8" , PHP_INI_SYSTEM, OnUpdateInternedStringsBuffer, accel_directives.interned_strings_buffer, zend_accel_globals, accel_globals)
276 STD_PHP_INI_ENTRY("opcache.max_accelerated_files" , "10000", PHP_INI_SYSTEM, OnUpdateMaxAcceleratedFiles, accel_directives.max_accelerated_files, zend_accel_globals, accel_globals)
277 STD_PHP_INI_ENTRY("opcache.max_wasted_percentage" , "5" , PHP_INI_SYSTEM, OnUpdateMaxWastedPercentage, accel_directives.max_wasted_percentage, zend_accel_globals, accel_globals)
278 STD_PHP_INI_ENTRY("opcache.consistency_checks" , "0" , PHP_INI_ALL , OnUpdateConsistencyChecks, accel_directives.consistency_checks, zend_accel_globals, accel_globals)
279 STD_PHP_INI_ENTRY("opcache.force_restart_timeout" , "180" , PHP_INI_SYSTEM, OnUpdateLong, accel_directives.force_restart_timeout, zend_accel_globals, accel_globals)
280 STD_PHP_INI_ENTRY("opcache.revalidate_freq" , "2" , PHP_INI_ALL , OnUpdateLong, accel_directives.revalidate_freq, zend_accel_globals, accel_globals)
281 STD_PHP_INI_ENTRY("opcache.file_update_protection", "2" , PHP_INI_ALL , OnUpdateLong, accel_directives.file_update_protection, zend_accel_globals, accel_globals)
282 STD_PHP_INI_ENTRY("opcache.preferred_memory_model", "" , PHP_INI_SYSTEM, OnUpdateStringUnempty, accel_directives.memory_model, zend_accel_globals, accel_globals)
283 STD_PHP_INI_ENTRY("opcache.blacklist_filename" , "" , PHP_INI_SYSTEM, OnUpdateString, accel_directives.user_blacklist_filename, zend_accel_globals, accel_globals)
284 STD_PHP_INI_ENTRY("opcache.max_file_size" , "0" , PHP_INI_SYSTEM, OnUpdateLong, accel_directives.max_file_size, zend_accel_globals, accel_globals)
285
286 STD_PHP_INI_BOOLEAN("opcache.protect_memory" , "0" , PHP_INI_SYSTEM, OnUpdateBool, accel_directives.protect_memory, zend_accel_globals, accel_globals)
287 STD_PHP_INI_BOOLEAN("opcache.save_comments" , "1" , PHP_INI_SYSTEM, OnUpdateBool, accel_directives.save_comments, zend_accel_globals, accel_globals)
288 STD_PHP_INI_BOOLEAN("opcache.record_warnings" , "0" , PHP_INI_SYSTEM, OnUpdateBool, accel_directives.record_warnings, zend_accel_globals, accel_globals)
289
290 STD_PHP_INI_ENTRY("opcache.optimization_level" , DEFAULT_OPTIMIZATION_LEVEL , PHP_INI_SYSTEM, OnUpdateLong, accel_directives.optimization_level, zend_accel_globals, accel_globals)
291 STD_PHP_INI_ENTRY("opcache.opt_debug_level" , "0" , PHP_INI_SYSTEM, OnUpdateLong, accel_directives.opt_debug_level, zend_accel_globals, accel_globals)
292 STD_PHP_INI_BOOLEAN("opcache.enable_file_override" , "0" , PHP_INI_SYSTEM, OnUpdateBool, accel_directives.file_override_enabled, zend_accel_globals, accel_globals)
293 STD_PHP_INI_BOOLEAN("opcache.enable_cli" , "0" , PHP_INI_SYSTEM, OnUpdateBool, accel_directives.enable_cli, zend_accel_globals, accel_globals)
294 STD_PHP_INI_ENTRY("opcache.error_log" , "" , PHP_INI_SYSTEM, OnUpdateString, accel_directives.error_log, zend_accel_globals, accel_globals)
295 STD_PHP_INI_ENTRY("opcache.restrict_api" , "" , PHP_INI_SYSTEM, OnUpdateString, accel_directives.restrict_api, zend_accel_globals, accel_globals)
296
297 #ifndef ZEND_WIN32
298 STD_PHP_INI_ENTRY("opcache.lockfile_path" , "/tmp" , PHP_INI_SYSTEM, OnUpdateString, accel_directives.lockfile_path, zend_accel_globals, accel_globals)
299 #else
300 STD_PHP_INI_ENTRY("opcache.mmap_base", NULL, PHP_INI_SYSTEM, OnUpdateString, accel_directives.mmap_base, zend_accel_globals, accel_globals)
301 #endif
302
303 STD_PHP_INI_ENTRY("opcache.file_cache" , NULL , PHP_INI_SYSTEM, OnUpdateFileCache, accel_directives.file_cache, zend_accel_globals, accel_globals)
304 STD_PHP_INI_BOOLEAN("opcache.file_cache_only" , "0" , PHP_INI_SYSTEM, OnUpdateBool, accel_directives.file_cache_only, zend_accel_globals, accel_globals)
305 STD_PHP_INI_BOOLEAN("opcache.file_cache_consistency_checks" , "1" , PHP_INI_SYSTEM, OnUpdateBool, accel_directives.file_cache_consistency_checks, zend_accel_globals, accel_globals)
306 #if ENABLE_FILE_CACHE_FALLBACK
307 STD_PHP_INI_BOOLEAN("opcache.file_cache_fallback" , "1" , PHP_INI_SYSTEM, OnUpdateBool, accel_directives.file_cache_fallback, zend_accel_globals, accel_globals)
308 #endif
309 #ifdef HAVE_HUGE_CODE_PAGES
310 STD_PHP_INI_BOOLEAN("opcache.huge_code_pages" , "0" , PHP_INI_SYSTEM, OnUpdateBool, accel_directives.huge_code_pages, zend_accel_globals, accel_globals)
311 #endif
312 STD_PHP_INI_ENTRY("opcache.preload" , "" , PHP_INI_SYSTEM, OnUpdateStringUnempty, accel_directives.preload, zend_accel_globals, accel_globals)
313 #ifndef ZEND_WIN32
314 STD_PHP_INI_ENTRY("opcache.preload_user" , "" , PHP_INI_SYSTEM, OnUpdateStringUnempty, accel_directives.preload_user, zend_accel_globals, accel_globals)
315 #endif
316 #if ZEND_WIN32
317 STD_PHP_INI_ENTRY("opcache.cache_id" , "" , PHP_INI_SYSTEM, OnUpdateString, accel_directives.cache_id, zend_accel_globals, accel_globals)
318 #endif
319 #ifdef HAVE_JIT
320 STD_PHP_INI_ENTRY("opcache.jit" , "tracing", PHP_INI_ALL, OnUpdateJit, options, zend_jit_globals, jit_globals)
321 STD_PHP_INI_ENTRY("opcache.jit_buffer_size" , ZEND_JIT_DEFAULT_BUFFER_SIZE, PHP_INI_SYSTEM, OnUpdateLong, buffer_size, zend_jit_globals, jit_globals)
322 STD_PHP_INI_ENTRY("opcache.jit_debug" , "0", PHP_INI_ALL, OnUpdateJitDebug, debug, zend_jit_globals, jit_globals)
323 STD_PHP_INI_ENTRY("opcache.jit_bisect_limit" , "0", PHP_INI_ALL, OnUpdateLong, bisect_limit, zend_jit_globals, jit_globals)
324 STD_PHP_INI_ENTRY("opcache.jit_prof_threshold" , "0.005", PHP_INI_ALL, OnUpdateReal, prof_threshold, zend_jit_globals, jit_globals)
325 STD_PHP_INI_ENTRY("opcache.jit_max_root_traces" , "1024", PHP_INI_SYSTEM, OnUpdateLong, max_root_traces, zend_jit_globals, jit_globals)
326 STD_PHP_INI_ENTRY("opcache.jit_max_side_traces" , "128", PHP_INI_SYSTEM, OnUpdateLong, max_side_traces, zend_jit_globals, jit_globals)
327 STD_PHP_INI_ENTRY("opcache.jit_max_exit_counters" , "8192", PHP_INI_SYSTEM, OnUpdateLong, max_exit_counters, zend_jit_globals, jit_globals)
328 STD_PHP_INI_ENTRY("opcache.jit_hot_loop" , "64", PHP_INI_SYSTEM, OnUpdateCounter, hot_loop, zend_jit_globals, jit_globals)
329 STD_PHP_INI_ENTRY("opcache.jit_hot_func" , "127", PHP_INI_SYSTEM, OnUpdateCounter, hot_func, zend_jit_globals, jit_globals)
330 STD_PHP_INI_ENTRY("opcache.jit_hot_return" , "8", PHP_INI_SYSTEM, OnUpdateCounter, hot_return, zend_jit_globals, jit_globals)
331 STD_PHP_INI_ENTRY("opcache.jit_hot_side_exit" , "8", PHP_INI_ALL, OnUpdateCounter, hot_side_exit, zend_jit_globals, jit_globals)
332 STD_PHP_INI_ENTRY("opcache.jit_blacklist_root_trace" , "16", PHP_INI_ALL, OnUpdateCounter, blacklist_root_trace, zend_jit_globals, jit_globals)
333 STD_PHP_INI_ENTRY("opcache.jit_blacklist_side_trace" , "8", PHP_INI_ALL, OnUpdateCounter, blacklist_side_trace, zend_jit_globals, jit_globals)
334 STD_PHP_INI_ENTRY("opcache.jit_max_loop_unrolls" , "8", PHP_INI_ALL, OnUpdateUnrollL, max_loop_unrolls, zend_jit_globals, jit_globals)
335 STD_PHP_INI_ENTRY("opcache.jit_max_recursive_calls" , "2", PHP_INI_ALL, OnUpdateUnrollC, max_recursive_calls, zend_jit_globals, jit_globals)
336 STD_PHP_INI_ENTRY("opcache.jit_max_recursive_returns" , "2", PHP_INI_ALL, OnUpdateUnrollR, max_recursive_returns, zend_jit_globals, jit_globals)
337 STD_PHP_INI_ENTRY("opcache.jit_max_polymorphic_calls" , "2", PHP_INI_ALL, OnUpdateLong, max_polymorphic_calls, zend_jit_globals, jit_globals)
338 #endif
339 ZEND_INI_END()
340
341 static int filename_is_in_cache(zend_string *filename)
342 {
343 zend_string *key;
344
345 key = accel_make_persistent_key(filename);
346 if (key != NULL) {
347 zend_persistent_script *persistent_script = zend_accel_hash_find(&ZCSG(hash), key);
348 if (persistent_script && !persistent_script->corrupted) {
349 if (ZCG(accel_directives).validate_timestamps) {
350 zend_file_handle handle;
351 int ret;
352
353 zend_stream_init_filename_ex(&handle, filename);
354 ret = validate_timestamp_and_record_ex(persistent_script, &handle) == SUCCESS
355 ? 1 : 0;
356 zend_destroy_file_handle(&handle);
357 return ret;
358 }
359
360 return 1;
361 }
362 }
363
364 return 0;
365 }
366
367 static int accel_file_in_cache(INTERNAL_FUNCTION_PARAMETERS)
368 {
369 if (ZEND_NUM_ARGS() == 1) {
370 zval *zv = ZEND_CALL_ARG(execute_data , 1);
371
372 if (Z_TYPE_P(zv) == IS_STRING && Z_STRLEN_P(zv) != 0) {
373 return filename_is_in_cache(Z_STR_P(zv));
374 }
375 }
376 return 0;
377 }
378
379 static ZEND_NAMED_FUNCTION(accel_file_exists)
380 {
381 if (accel_file_in_cache(INTERNAL_FUNCTION_PARAM_PASSTHRU)) {
382 RETURN_TRUE;
383 } else {
384 orig_file_exists(INTERNAL_FUNCTION_PARAM_PASSTHRU);
385 }
386 }
387
388 static ZEND_NAMED_FUNCTION(accel_is_file)
389 {
390 if (accel_file_in_cache(INTERNAL_FUNCTION_PARAM_PASSTHRU)) {
391 RETURN_TRUE;
392 } else {
393 orig_is_file(INTERNAL_FUNCTION_PARAM_PASSTHRU);
394 }
395 }
396
397 static ZEND_NAMED_FUNCTION(accel_is_readable)
398 {
399 if (accel_file_in_cache(INTERNAL_FUNCTION_PARAM_PASSTHRU)) {
400 RETURN_TRUE;
401 } else {
402 orig_is_readable(INTERNAL_FUNCTION_PARAM_PASSTHRU);
403 }
404 }
405
406 static ZEND_MINIT_FUNCTION(zend_accelerator)
407 {
408 (void)type; /* keep the compiler happy */
409
410 REGISTER_INI_ENTRIES();
411
412 return SUCCESS;
413 }
414
415 void zend_accel_override_file_functions(void)
416 {
417 zend_function *old_function;
418 if (ZCG(enabled) && accel_startup_ok && ZCG(accel_directives).file_override_enabled) {
419 if (file_cache_only) {
420 zend_accel_error(ACCEL_LOG_WARNING, "file_override_enabled has no effect when file_cache_only is set");
421 return;
422 }
423 /* override file_exists */
424 if ((old_function = zend_hash_str_find_ptr(CG(function_table), "file_exists", sizeof("file_exists")-1)) != NULL) {
425 orig_file_exists = old_function->internal_function.handler;
426 old_function->internal_function.handler = accel_file_exists;
427 }
428 if ((old_function = zend_hash_str_find_ptr(CG(function_table), "is_file", sizeof("is_file")-1)) != NULL) {
429 orig_is_file = old_function->internal_function.handler;
430 old_function->internal_function.handler = accel_is_file;
431 }
432 if ((old_function = zend_hash_str_find_ptr(CG(function_table), "is_readable", sizeof("is_readable")-1)) != NULL) {
433 orig_is_readable = old_function->internal_function.handler;
434 old_function->internal_function.handler = accel_is_readable;
435 }
436 }
437 }
438
439 static ZEND_MSHUTDOWN_FUNCTION(zend_accelerator)
440 {
441 (void)type; /* keep the compiler happy */
442
443 UNREGISTER_INI_ENTRIES();
444 accel_shutdown();
445 return SUCCESS;
446 }
447
448 void zend_accel_info(ZEND_MODULE_INFO_FUNC_ARGS)
449 {
450 php_info_print_table_start();
451
452 if (ZCG(accelerator_enabled) || file_cache_only) {
453 php_info_print_table_row(2, "Opcode Caching", "Up and Running");
454 } else {
455 php_info_print_table_row(2, "Opcode Caching", "Disabled");
456 }
457 if (ZCG(enabled) && accel_startup_ok && ZCG(accel_directives).optimization_level) {
458 php_info_print_table_row(2, "Optimization", "Enabled");
459 } else {
460 php_info_print_table_row(2, "Optimization", "Disabled");
461 }
462 if (!file_cache_only) {
463 php_info_print_table_row(2, "SHM Cache", "Enabled");
464 } else {
465 php_info_print_table_row(2, "SHM Cache", "Disabled");
466 }
467 if (ZCG(accel_directives).file_cache) {
468 php_info_print_table_row(2, "File Cache", "Enabled");
469 } else {
470 php_info_print_table_row(2, "File Cache", "Disabled");
471 }
472 #if HAVE_JIT
473 if (JIT_G(enabled)) {
474 if (JIT_G(on)) {
475 php_info_print_table_row(2, "JIT", "On");
476 } else {
477 php_info_print_table_row(2, "JIT", "Off");
478 }
479 } else {
480 php_info_print_table_row(2, "JIT", "Disabled");
481 }
482 #else
483 php_info_print_table_row(2, "JIT", "Not Available");
484 #endif
485 if (file_cache_only) {
486 if (!accel_startup_ok || zps_api_failure_reason) {
487 php_info_print_table_row(2, "Startup Failed", zps_api_failure_reason);
488 } else {
489 php_info_print_table_row(2, "Startup", "OK");
490 }
491 } else
492 if (ZCG(enabled)) {
493 if (!accel_startup_ok || zps_api_failure_reason) {
494 php_info_print_table_row(2, "Startup Failed", zps_api_failure_reason);
495 } else {
496 char buf[32];
497 php_info_print_table_row(2, "Startup", "OK");
498 php_info_print_table_row(2, "Shared memory model", zend_accel_get_shared_model());
499 snprintf(buf, sizeof(buf), ZEND_ULONG_FMT, ZCSG(hits));
500 php_info_print_table_row(2, "Cache hits", buf);
501 snprintf(buf, sizeof(buf), ZEND_ULONG_FMT, ZSMMG(memory_exhausted)?ZCSG(misses):ZCSG(misses)-ZCSG(blacklist_misses));
502 php_info_print_table_row(2, "Cache misses", buf);
503 snprintf(buf, sizeof(buf), ZEND_LONG_FMT, ZCG(accel_directives).memory_consumption-zend_shared_alloc_get_free_memory()-ZSMMG(wasted_shared_memory));
504 php_info_print_table_row(2, "Used memory", buf);
505 snprintf(buf, sizeof(buf), "%zu", zend_shared_alloc_get_free_memory());
506 php_info_print_table_row(2, "Free memory", buf);
507 snprintf(buf, sizeof(buf), "%zu", ZSMMG(wasted_shared_memory));
508 php_info_print_table_row(2, "Wasted memory", buf);
509 if (ZCSG(interned_strings).start && ZCSG(interned_strings).end) {
510 snprintf(buf, sizeof(buf), "%zu", (size_t)((char*)ZCSG(interned_strings).top - (char*)(accel_shared_globals + 1)));
511 php_info_print_table_row(2, "Interned Strings Used memory", buf);
512 snprintf(buf, sizeof(buf), "%zu", (size_t)((char*)ZCSG(interned_strings).end - (char*)ZCSG(interned_strings).top));
513 php_info_print_table_row(2, "Interned Strings Free memory", buf);
514 }
515 snprintf(buf, sizeof(buf), "%" PRIu32, ZCSG(hash).num_direct_entries);
516 php_info_print_table_row(2, "Cached scripts", buf);
517 snprintf(buf, sizeof(buf), "%" PRIu32, ZCSG(hash).num_entries);
518 php_info_print_table_row(2, "Cached keys", buf);
519 snprintf(buf, sizeof(buf), "%" PRIu32, ZCSG(hash).max_num_entries);
520 php_info_print_table_row(2, "Max keys", buf);
521 snprintf(buf, sizeof(buf), ZEND_ULONG_FMT, ZCSG(oom_restarts));
522 php_info_print_table_row(2, "OOM restarts", buf);
523 snprintf(buf, sizeof(buf), ZEND_ULONG_FMT, ZCSG(hash_restarts));
524 php_info_print_table_row(2, "Hash keys restarts", buf);
525 snprintf(buf, sizeof(buf), ZEND_ULONG_FMT, ZCSG(manual_restarts));
526 php_info_print_table_row(2, "Manual restarts", buf);
527 }
528 }
529
530 php_info_print_table_end();
531 DISPLAY_INI_ENTRIES();
532 }
533
534 static zend_module_entry accel_module_entry = {
535 STANDARD_MODULE_HEADER,
536 ACCELERATOR_PRODUCT_NAME,
537 ext_functions,
538 ZEND_MINIT(zend_accelerator),
539 ZEND_MSHUTDOWN(zend_accelerator),
540 accel_activate,
541 NULL,
542 zend_accel_info,
543 PHP_VERSION,
544 NO_MODULE_GLOBALS,
545 accel_post_deactivate,
546 STANDARD_MODULE_PROPERTIES_EX
547 };
548
549 int start_accel_module(void)
550 {
551 return zend_startup_module(&accel_module_entry);
552 }
553
554 /* {{{ Get the scripts which are accelerated by ZendAccelerator */
555 static int accelerator_get_scripts(zval *return_value)
556 {
557 uint32_t i;
558 zval persistent_script_report;
559 zend_accel_hash_entry *cache_entry;
560 struct tm *ta;
561 struct timeval exec_time;
562 struct timeval fetch_time;
563
564 if (!ZCG(accelerator_enabled) || accelerator_shm_read_lock() != SUCCESS) {
565 return 0;
566 }
567
568 array_init(return_value);
569 for (i = 0; i<ZCSG(hash).max_num_entries; i++) {
570 for (cache_entry = ZCSG(hash).hash_table[i]; cache_entry; cache_entry = cache_entry->next) {
571 zend_persistent_script *script;
572 char *str;
573 size_t len;
574
575 if (cache_entry->indirect) continue;
576
577 script = (zend_persistent_script *)cache_entry->data;
578
579 array_init(&persistent_script_report);
580 add_assoc_str(&persistent_script_report, "full_path", zend_string_dup(script->script.filename, 0));
581 add_assoc_long(&persistent_script_report, "hits", script->dynamic_members.hits);
582 add_assoc_long(&persistent_script_report, "memory_consumption", script->dynamic_members.memory_consumption);
583 ta = localtime(&script->dynamic_members.last_used);
584 str = asctime(ta);
585 len = strlen(str);
586 if (len > 0 && str[len - 1] == '\n') len--;
587 add_assoc_stringl(&persistent_script_report, "last_used", str, len);
588 add_assoc_long(&persistent_script_report, "last_used_timestamp", script->dynamic_members.last_used);
589 if (ZCG(accel_directives).validate_timestamps) {
590 add_assoc_long(&persistent_script_report, "timestamp", (zend_long)script->timestamp);
591 }
592 timerclear(&exec_time);
593 timerclear(&fetch_time);
594
595 zend_hash_update(Z_ARRVAL_P(return_value), cache_entry->key, &persistent_script_report);
596 }
597 }
598 accelerator_shm_read_unlock();
599
600 return 1;
601 }
602
603 /* {{{ Obtain statistics information regarding code acceleration */
604 ZEND_FUNCTION(opcache_get_status)
605 {
606 zend_long reqs;
607 zval memory_usage, statistics, scripts;
608 bool fetch_scripts = 1;
609
610 if (zend_parse_parameters(ZEND_NUM_ARGS(), "|b", &fetch_scripts) == FAILURE) {
611 RETURN_THROWS();
612 }
613
614 if (!validate_api_restriction()) {
615 RETURN_FALSE;
616 }
617
618 if (!accel_startup_ok) {
619 RETURN_FALSE;
620 }
621
622 array_init(return_value);
623
624 /* Trivia */
625 add_assoc_bool(return_value, "opcache_enabled", ZCG(accelerator_enabled));
626
627 if (ZCG(accel_directives).file_cache) {
628 add_assoc_string(return_value, "file_cache", ZCG(accel_directives).file_cache);
629 }
630 if (file_cache_only) {
631 add_assoc_bool(return_value, "file_cache_only", 1);
632 return;
633 }
634
635 add_assoc_bool(return_value, "cache_full", ZSMMG(memory_exhausted));
636 add_assoc_bool(return_value, "restart_pending", ZCSG(restart_pending));
637 add_assoc_bool(return_value, "restart_in_progress", ZCSG(restart_in_progress));
638
639 /* Memory usage statistics */
640 array_init(&memory_usage);
641 add_assoc_long(&memory_usage, "used_memory", ZCG(accel_directives).memory_consumption-zend_shared_alloc_get_free_memory()-ZSMMG(wasted_shared_memory));
642 add_assoc_long(&memory_usage, "free_memory", zend_shared_alloc_get_free_memory());
643 add_assoc_long(&memory_usage, "wasted_memory", ZSMMG(wasted_shared_memory));
644 add_assoc_double(&memory_usage, "current_wasted_percentage", (((double) ZSMMG(wasted_shared_memory))/ZCG(accel_directives).memory_consumption)*100.0);
645 add_assoc_zval(return_value, "memory_usage", &memory_usage);
646
647 if (ZCSG(interned_strings).start && ZCSG(interned_strings).end) {
648 zval interned_strings_usage;
649
650 array_init(&interned_strings_usage);
651 add_assoc_long(&interned_strings_usage, "buffer_size", (char*)ZCSG(interned_strings).end - (char*)(accel_shared_globals + 1));
652 add_assoc_long(&interned_strings_usage, "used_memory", (char*)ZCSG(interned_strings).top - (char*)(accel_shared_globals + 1));
653 add_assoc_long(&interned_strings_usage, "free_memory", (char*)ZCSG(interned_strings).end - (char*)ZCSG(interned_strings).top);
654 add_assoc_long(&interned_strings_usage, "number_of_strings", ZCSG(interned_strings).nNumOfElements);
655 add_assoc_zval(return_value, "interned_strings_usage", &interned_strings_usage);
656 }
657
658 /* Accelerator statistics */
659 array_init(&statistics);
660 add_assoc_long(&statistics, "num_cached_scripts", ZCSG(hash).num_direct_entries);
661 add_assoc_long(&statistics, "num_cached_keys", ZCSG(hash).num_entries);
662 add_assoc_long(&statistics, "max_cached_keys", ZCSG(hash).max_num_entries);
663 add_assoc_long(&statistics, "hits", (zend_long)ZCSG(hits));
664 add_assoc_long(&statistics, "start_time", ZCSG(start_time));
665 add_assoc_long(&statistics, "last_restart_time", ZCSG(last_restart_time));
666 add_assoc_long(&statistics, "oom_restarts", ZCSG(oom_restarts));
667 add_assoc_long(&statistics, "hash_restarts", ZCSG(hash_restarts));
668 add_assoc_long(&statistics, "manual_restarts", ZCSG(manual_restarts));
669 add_assoc_long(&statistics, "misses", ZSMMG(memory_exhausted)?ZCSG(misses):ZCSG(misses)-ZCSG(blacklist_misses));
670 add_assoc_long(&statistics, "blacklist_misses", ZCSG(blacklist_misses));
671 reqs = ZCSG(hits)+ZCSG(misses);
672 add_assoc_double(&statistics, "blacklist_miss_ratio", reqs?(((double) ZCSG(blacklist_misses))/reqs)*100.0:0);
673 add_assoc_double(&statistics, "opcache_hit_rate", reqs?(((double) ZCSG(hits))/reqs)*100.0:0);
674 add_assoc_zval(return_value, "opcache_statistics", &statistics);
675
676 if (ZCSG(preload_script)) {
677 array_init(&statistics);
678
679 add_assoc_long(&statistics, "memory_consumption", ZCSG(preload_script)->dynamic_members.memory_consumption);
680
681 if (zend_hash_num_elements(&ZCSG(preload_script)->script.function_table)) {
682 zend_op_array *op_array;
683
684 array_init(&scripts);
685 ZEND_HASH_MAP_FOREACH_PTR(&ZCSG(preload_script)->script.function_table, op_array) {
686 add_next_index_str(&scripts, op_array->function_name);
687 } ZEND_HASH_FOREACH_END();
688 add_assoc_zval(&statistics, "functions", &scripts);
689 }
690
691 if (zend_hash_num_elements(&ZCSG(preload_script)->script.class_table)) {
692 zend_class_entry *ce;
693 zend_string *key;
694
695 array_init(&scripts);
696 ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&ZCSG(preload_script)->script.class_table, key, ce) {
697 if (ce->refcount > 1 && !zend_string_equals_ci(key, ce->name)) {
698 add_next_index_str(&scripts, key);
699 } else {
700 add_next_index_str(&scripts, ce->name);
701 }
702 } ZEND_HASH_FOREACH_END();
703 add_assoc_zval(&statistics, "classes", &scripts);
704 }
705
706 if (ZCSG(saved_scripts)) {
707 zend_persistent_script **p = ZCSG(saved_scripts);
708
709 array_init(&scripts);
710 while (*p) {
711 add_next_index_str(&scripts, (*p)->script.filename);
712 p++;
713 }
714 add_assoc_zval(&statistics, "scripts", &scripts);
715 }
716 add_assoc_zval(return_value, "preload_statistics", &statistics);
717 }
718
719 if (fetch_scripts) {
720 /* accelerated scripts */
721 if (accelerator_get_scripts(&scripts)) {
722 add_assoc_zval(return_value, "scripts", &scripts);
723 }
724 }
725 #if HAVE_JIT
726 zend_jit_status(return_value);
727 #endif
728 }
729
730 static int add_blacklist_path(zend_blacklist_entry *p, zval *return_value)
731 {
732 add_next_index_stringl(return_value, p->path, p->path_length);
733 return 0;
734 }
735
736 /* {{{ Obtain configuration information */
737 ZEND_FUNCTION(opcache_get_configuration)
738 {
739 zval directives, version, blacklist;
740
741 if (zend_parse_parameters_none() == FAILURE) {
742 RETURN_THROWS();
743 }
744
745 if (!validate_api_restriction()) {
746 RETURN_FALSE;
747 }
748
749 array_init(return_value);
750
751 /* directives */
752 array_init(&directives);
753 add_assoc_bool(&directives, "opcache.enable", ZCG(enabled));
754 add_assoc_bool(&directives, "opcache.enable_cli", ZCG(accel_directives).enable_cli);
755 add_assoc_bool(&directives, "opcache.use_cwd", ZCG(accel_directives).use_cwd);
756 add_assoc_bool(&directives, "opcache.validate_timestamps", ZCG(accel_directives).validate_timestamps);
757 add_assoc_bool(&directives, "opcache.validate_permission", ZCG(accel_directives).validate_permission);
758 #ifndef ZEND_WIN32
759 add_assoc_bool(&directives, "opcache.validate_root", ZCG(accel_directives).validate_root);
760 #endif
761 add_assoc_bool(&directives, "opcache.dups_fix", ZCG(accel_directives).ignore_dups);
762 add_assoc_bool(&directives, "opcache.revalidate_path", ZCG(accel_directives).revalidate_path);
763
764 add_assoc_long(&directives, "opcache.log_verbosity_level", ZCG(accel_directives).log_verbosity_level);
765 add_assoc_long(&directives, "opcache.memory_consumption", ZCG(accel_directives).memory_consumption);
766 add_assoc_long(&directives, "opcache.interned_strings_buffer",ZCG(accel_directives).interned_strings_buffer);
767 add_assoc_long(&directives, "opcache.max_accelerated_files", ZCG(accel_directives).max_accelerated_files);
768 add_assoc_double(&directives, "opcache.max_wasted_percentage", ZCG(accel_directives).max_wasted_percentage);
769 add_assoc_long(&directives, "opcache.consistency_checks", ZCG(accel_directives).consistency_checks);
770 add_assoc_long(&directives, "opcache.force_restart_timeout", ZCG(accel_directives).force_restart_timeout);
771 add_assoc_long(&directives, "opcache.revalidate_freq", ZCG(accel_directives).revalidate_freq);
772 add_assoc_string(&directives, "opcache.preferred_memory_model", STRING_NOT_NULL(ZCG(accel_directives).memory_model));
773 add_assoc_string(&directives, "opcache.blacklist_filename", STRING_NOT_NULL(ZCG(accel_directives).user_blacklist_filename));
774 add_assoc_long(&directives, "opcache.max_file_size", ZCG(accel_directives).max_file_size);
775 add_assoc_string(&directives, "opcache.error_log", STRING_NOT_NULL(ZCG(accel_directives).error_log));
776
777 add_assoc_bool(&directives, "opcache.protect_memory", ZCG(accel_directives).protect_memory);
778 add_assoc_bool(&directives, "opcache.save_comments", ZCG(accel_directives).save_comments);
779 add_assoc_bool(&directives, "opcache.record_warnings", ZCG(accel_directives).record_warnings);
780 add_assoc_bool(&directives, "opcache.enable_file_override", ZCG(accel_directives).file_override_enabled);
781 add_assoc_long(&directives, "opcache.optimization_level", ZCG(accel_directives).optimization_level);
782
783 #ifndef ZEND_WIN32
784 add_assoc_string(&directives, "opcache.lockfile_path", STRING_NOT_NULL(ZCG(accel_directives).lockfile_path));
785 #else
786 add_assoc_string(&directives, "opcache.mmap_base", STRING_NOT_NULL(ZCG(accel_directives).mmap_base));
787 #endif
788
789 add_assoc_string(&directives, "opcache.file_cache", ZCG(accel_directives).file_cache ? ZCG(accel_directives).file_cache : "");
790 add_assoc_bool(&directives, "opcache.file_cache_only", ZCG(accel_directives).file_cache_only);
791 add_assoc_bool(&directives, "opcache.file_cache_consistency_checks", ZCG(accel_directives).file_cache_consistency_checks);
792 #if ENABLE_FILE_CACHE_FALLBACK
793 add_assoc_bool(&directives, "opcache.file_cache_fallback", ZCG(accel_directives).file_cache_fallback);
794 #endif
795
796 add_assoc_long(&directives, "opcache.file_update_protection", ZCG(accel_directives).file_update_protection);
797 add_assoc_long(&directives, "opcache.opt_debug_level", ZCG(accel_directives).opt_debug_level);
798 add_assoc_string(&directives, "opcache.restrict_api", STRING_NOT_NULL(ZCG(accel_directives).restrict_api));
799 #ifdef HAVE_HUGE_CODE_PAGES
800 add_assoc_bool(&directives, "opcache.huge_code_pages", ZCG(accel_directives).huge_code_pages);
801 #endif
802 add_assoc_string(&directives, "opcache.preload", STRING_NOT_NULL(ZCG(accel_directives).preload));
803 #ifndef ZEND_WIN32
804 add_assoc_string(&directives, "opcache.preload_user", STRING_NOT_NULL(ZCG(accel_directives).preload_user));
805 #endif
806 #if ZEND_WIN32
807 add_assoc_string(&directives, "opcache.cache_id", STRING_NOT_NULL(ZCG(accel_directives).cache_id));
808 #endif
809 #ifdef HAVE_JIT
810 add_assoc_string(&directives, "opcache.jit", JIT_G(options));
811 add_assoc_long(&directives, "opcache.jit_buffer_size", JIT_G(buffer_size));
812 add_assoc_long(&directives, "opcache.jit_debug", JIT_G(debug));
813 add_assoc_long(&directives, "opcache.jit_bisect_limit", JIT_G(bisect_limit));
814 add_assoc_long(&directives, "opcache.jit_blacklist_root_trace", JIT_G(blacklist_root_trace));
815 add_assoc_long(&directives, "opcache.jit_blacklist_side_trace", JIT_G(blacklist_side_trace));
816 add_assoc_long(&directives, "opcache.jit_hot_func", JIT_G(hot_func));
817 add_assoc_long(&directives, "opcache.jit_hot_loop", JIT_G(hot_loop));
818 add_assoc_long(&directives, "opcache.jit_hot_return", JIT_G(hot_return));
819 add_assoc_long(&directives, "opcache.jit_hot_side_exit", JIT_G(hot_side_exit));
820 add_assoc_long(&directives, "opcache.jit_max_exit_counters", JIT_G(max_exit_counters));
821 add_assoc_long(&directives, "opcache.jit_max_loop_unrolls", JIT_G(max_loop_unrolls));
822 add_assoc_long(&directives, "opcache.jit_max_polymorphic_calls", JIT_G(max_polymorphic_calls));
823 add_assoc_long(&directives, "opcache.jit_max_recursive_calls", JIT_G(max_recursive_calls));
824 add_assoc_long(&directives, "opcache.jit_max_recursive_returns", JIT_G(max_recursive_returns));
825 add_assoc_long(&directives, "opcache.jit_max_root_traces", JIT_G(max_root_traces));
826 add_assoc_long(&directives, "opcache.jit_max_side_traces", JIT_G(max_side_traces));
827 add_assoc_long(&directives, "opcache.jit_prof_threshold", JIT_G(prof_threshold));
828 #endif
829
830 add_assoc_zval(return_value, "directives", &directives);
831
832 /*version */
833 array_init(&version);
834 add_assoc_string(&version, "version", PHP_VERSION);
835 add_assoc_string(&version, "opcache_product_name", ACCELERATOR_PRODUCT_NAME);
836 add_assoc_zval(return_value, "version", &version);
837
838 /* blacklist */
839 array_init(&blacklist);
840 zend_accel_blacklist_apply(&accel_blacklist, add_blacklist_path, &blacklist);
841 add_assoc_zval(return_value, "blacklist", &blacklist);
842 }
843
844 /* {{{ Request that the contents of the opcode cache to be reset */
845 ZEND_FUNCTION(opcache_reset)
846 {
847 if (zend_parse_parameters_none() == FAILURE) {
848 RETURN_THROWS();
849 }
850
851 if (!validate_api_restriction()) {
852 RETURN_FALSE;
853 }
854
855 if ((!ZCG(enabled) || !accel_startup_ok || !ZCSG(accelerator_enabled))
856 #if ENABLE_FILE_CACHE_FALLBACK
857 && !fallback_process
858 #endif
859 ) {
860 RETURN_FALSE;
861 }
862
863 /* exclusive lock */
864 zend_shared_alloc_lock();
865 zend_accel_schedule_restart(ACCEL_RESTART_USER);
866 zend_shared_alloc_unlock();
867 RETURN_TRUE;
868 }
869
870 /* {{{ Invalidates cached script (in necessary or forced) */
871 ZEND_FUNCTION(opcache_invalidate)
872 {
873 zend_string *script_name;
874 bool force = 0;
875
876 if (zend_parse_parameters(ZEND_NUM_ARGS(), "S|b", &script_name, &force) == FAILURE) {
877 RETURN_THROWS();
878 }
879
880 if (!validate_api_restriction()) {
881 RETURN_FALSE;
882 }
883
884 if (zend_accel_invalidate(script_name, force) == SUCCESS) {
885 RETURN_TRUE;
886 } else {
887 RETURN_FALSE;
888 }
889 }
890
891 ZEND_FUNCTION(opcache_compile_file)
892 {
893 zend_string *script_name;
894 zend_file_handle handle;
895 zend_op_array *op_array = NULL;
896 zend_execute_data *orig_execute_data = NULL;
897 uint32_t orig_compiler_options;
898
899 if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &script_name) == FAILURE) {
900 RETURN_THROWS();
901 }
902
903 if (!accel_startup_ok) {
904 zend_error(E_NOTICE, ACCELERATOR_PRODUCT_NAME " has not been properly started, can't compile file");
905 RETURN_FALSE;
906 }
907
908 zend_stream_init_filename_ex(&handle, script_name);
909
910 orig_execute_data = EG(current_execute_data);
911 orig_compiler_options = CG(compiler_options);
912 CG(compiler_options) |= ZEND_COMPILE_WITHOUT_EXECUTION;
913
914 if (CG(compiler_options) & ZEND_COMPILE_PRELOAD) {
915 /* During preloading, a failure in opcache_compile_file() should result in an overall
916 * preloading failure. Otherwise we may include partially compiled files in the preload
917 * state. */
918 op_array = persistent_compile_file(&handle, ZEND_INCLUDE);
919 } else {
920 zend_try {
921 op_array = persistent_compile_file(&handle, ZEND_INCLUDE);
922 } zend_catch {
923 EG(current_execute_data) = orig_execute_data;
924 zend_error(E_WARNING, ACCELERATOR_PRODUCT_NAME " could not compile file %s", ZSTR_VAL(handle.filename));
925 } zend_end_try();
926 }
927
928 CG(compiler_options) = orig_compiler_options;
929
930 if(op_array != NULL) {
931 destroy_op_array(op_array);
932 efree(op_array);
933 RETVAL_TRUE;
934 } else {
935 RETVAL_FALSE;
936 }
937 zend_destroy_file_handle(&handle);
938 }
939
940 /* {{{ Return true if the script is cached in OPCache, false if it is not cached or if OPCache is not running. */
941 ZEND_FUNCTION(opcache_is_script_cached)
942 {
943 zend_string *script_name;
944
945 ZEND_PARSE_PARAMETERS_START(1, 1)
946 Z_PARAM_STR(script_name)
947 ZEND_PARSE_PARAMETERS_END();
948
949 if (!validate_api_restriction()) {
950 RETURN_FALSE;
951 }
952
953 if (!ZCG(accelerator_enabled)) {
954 RETURN_FALSE;
955 }
956
957 RETURN_BOOL(filename_is_in_cache(script_name));
958 }
959