1 /*
2 +----------------------------------------------------------------------+
3 | Zend OPcache |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 1998-2016 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 | 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 +----------------------------------------------------------------------+
15 | Authors: Andi Gutmans <andi@zend.com> |
16 | Zeev Suraski <zeev@zend.com> |
17 | Stanislav Malyshev <stas@zend.com> |
18 | Dmitry Stogov <dmitry@zend.com> |
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 #if ZEND_EXTENSION_API_NO > PHP_5_5_X_API_NO
32 # include "zend_virtual_cwd.h"
33 #else
34 # include "TSRM/tsrm_virtual_cwd.h"
35 #endif
36 #include "ext/standard/info.h"
37 #include "ext/standard/php_filestat.h"
38
39 #define STRING_NOT_NULL(s) (NULL == (s)?"":s)
40 #define MIN_ACCEL_FILES 200
41 #define MAX_ACCEL_FILES 1000000
42 #define TOKENTOSTR(X) #X
43
44 static void (*orig_file_exists)(INTERNAL_FUNCTION_PARAMETERS) = NULL;
45 static void (*orig_is_file)(INTERNAL_FUNCTION_PARAMETERS) = NULL;
46 static void (*orig_is_readable)(INTERNAL_FUNCTION_PARAMETERS) = NULL;
47
48 ZEND_BEGIN_ARG_INFO(arginfo_opcache_none, 0)
49 ZEND_END_ARG_INFO()
50
51 ZEND_BEGIN_ARG_INFO_EX(arginfo_opcache_get_status, 0, 0, 0)
52 ZEND_ARG_INFO(0, fetch_scripts)
53 ZEND_END_ARG_INFO()
54
55 ZEND_BEGIN_ARG_INFO_EX(arginfo_opcache_compile_file, 0, 0, 1)
56 ZEND_ARG_INFO(0, file)
57 ZEND_END_ARG_INFO()
58
59 ZEND_BEGIN_ARG_INFO_EX(arginfo_opcache_invalidate, 0, 0, 1)
60 ZEND_ARG_INFO(0, script)
61 ZEND_ARG_INFO(0, force)
62 ZEND_END_ARG_INFO()
63
64 ZEND_BEGIN_ARG_INFO_EX(arginfo_opcache_is_script_cached, 0, 0, 1)
65 ZEND_ARG_INFO(0, script)
66 ZEND_END_ARG_INFO()
67
68 /* User functions */
69 static ZEND_FUNCTION(opcache_reset);
70 static ZEND_FUNCTION(opcache_invalidate);
71 static ZEND_FUNCTION(opcache_is_script_cached);
72
73 /* Private functions */
74 static ZEND_FUNCTION(opcache_get_status);
75 static ZEND_FUNCTION(opcache_compile_file);
76 static ZEND_FUNCTION(opcache_get_configuration);
77
78 static zend_function_entry accel_functions[] = {
79 /* User functions */
80 ZEND_FE(opcache_reset, arginfo_opcache_none)
81 ZEND_FE(opcache_invalidate, arginfo_opcache_invalidate)
82 ZEND_FE(opcache_compile_file, arginfo_opcache_compile_file)
83 ZEND_FE(opcache_is_script_cached, arginfo_opcache_is_script_cached)
84 /* Private functions */
85 ZEND_FE(opcache_get_configuration, arginfo_opcache_none)
86 ZEND_FE(opcache_get_status, arginfo_opcache_get_status)
87 { NULL, NULL, NULL, 0, 0 }
88 };
89
validate_api_restriction(TSRMLS_D)90 static int validate_api_restriction(TSRMLS_D)
91 {
92 if (ZCG(accel_directives).restrict_api && *ZCG(accel_directives).restrict_api) {
93 int len = strlen(ZCG(accel_directives).restrict_api);
94
95 if (!SG(request_info).path_translated ||
96 strlen(SG(request_info).path_translated) < len ||
97 memcmp(SG(request_info).path_translated, ZCG(accel_directives).restrict_api, len) != 0) {
98 zend_error(E_WARNING, ACCELERATOR_PRODUCT_NAME " API is restricted by \"restrict_api\" configuration directive");
99 return 0;
100 }
101 }
102 return 1;
103 }
104
ZEND_INI_MH(OnUpdateMemoryConsumption)105 static ZEND_INI_MH(OnUpdateMemoryConsumption)
106 {
107 long *p;
108 long memsize;
109 #ifndef ZTS
110 char *base = (char *) mh_arg2;
111 #else
112 char *base = (char *) ts_resource(*((int *) mh_arg2));
113 #endif
114
115 /* keep the compiler happy */
116 (void)entry; (void)new_value_length; (void)mh_arg2; (void)mh_arg3; (void)stage;
117
118 p = (long *) (base + (size_t)mh_arg1);
119 memsize = atoi(new_value);
120 /* sanity check we must use at least 8 MB */
121 if (memsize < 8) {
122 const char *new_new_value = "8";
123 zend_ini_entry *ini_entry;
124
125 memsize = 8;
126 zend_accel_error(ACCEL_LOG_WARNING, "opcache.memory_consumption is set below the required 8MB.\n");
127 zend_accel_error(ACCEL_LOG_WARNING, ACCELERATOR_PRODUCT_NAME " will use the minimal 8MB configuration.\n");
128
129 if (zend_hash_find(EG(ini_directives),
130 "opcache.memory_consumption",
131 sizeof("opcache.memory_consumption"),
132 (void *) &ini_entry) == FAILURE) {
133 return FAILURE;
134 }
135
136 ini_entry->value = strdup(new_new_value);
137 ini_entry->value_length = strlen(new_new_value);
138 }
139 *p = memsize * (1024 * 1024);
140 return SUCCESS;
141 }
142
ZEND_INI_MH(OnUpdateMaxAcceleratedFiles)143 static ZEND_INI_MH(OnUpdateMaxAcceleratedFiles)
144 {
145 long *p;
146 long size;
147 #ifndef ZTS
148 char *base = (char *) mh_arg2;
149 #else
150 char *base = (char *) ts_resource(*((int *) mh_arg2));
151 #endif
152
153 /* keep the compiler happy */
154 (void)entry; (void)new_value_length; (void)mh_arg2; (void)mh_arg3; (void)stage;
155
156 p = (long *) (base + (size_t)mh_arg1);
157 size = atoi(new_value);
158 /* sanity check we must use a value between MIN_ACCEL_FILES and MAX_ACCEL_FILES */
159
160 if (size < MIN_ACCEL_FILES || size > MAX_ACCEL_FILES) {
161 const char *new_new_value;
162 zend_ini_entry *ini_entry;
163
164 if (size < MIN_ACCEL_FILES) {
165 size = MIN_ACCEL_FILES;
166 new_new_value = TOKENTOSTR(MIN_ACCEL_FILES);
167 zend_accel_error(ACCEL_LOG_WARNING, "opcache.max_accelerated_files is set below the required minimum (%d).\n", MIN_ACCEL_FILES);
168 zend_accel_error(ACCEL_LOG_WARNING, ACCELERATOR_PRODUCT_NAME " will use the minimal configuration.\n");
169 }
170 if (size > MAX_ACCEL_FILES) {
171 size = MAX_ACCEL_FILES;
172 new_new_value = TOKENTOSTR(MAX_ACCEL_FILES);
173 zend_accel_error(ACCEL_LOG_WARNING, "opcache.max_accelerated_files is set above the limit (%d).\n", MAX_ACCEL_FILES);
174 zend_accel_error(ACCEL_LOG_WARNING, ACCELERATOR_PRODUCT_NAME " will use the maximal configuration.\n");
175 }
176 if (zend_hash_find(EG(ini_directives),
177 "opcache.max_accelerated_files",
178 sizeof("opcache.max_accelerated_files"),
179 (void *) &ini_entry) == FAILURE) {
180 return FAILURE;
181 }
182 ini_entry->value = strdup(new_new_value);
183 ini_entry->value_length = strlen(new_new_value);
184 }
185 *p = size;
186 return SUCCESS;
187 }
188
ZEND_INI_MH(OnUpdateMaxWastedPercentage)189 static ZEND_INI_MH(OnUpdateMaxWastedPercentage)
190 {
191 double *p;
192 long percentage;
193 #ifndef ZTS
194 char *base = (char *) mh_arg2;
195 #else
196 char *base = (char *) ts_resource(*((int *) mh_arg2));
197 #endif
198
199 /* keep the compiler happy */
200 (void)entry; (void)new_value_length; (void)mh_arg2; (void)mh_arg3; (void)stage;
201
202 p = (double *) (base + (size_t)mh_arg1);
203 percentage = atoi(new_value);
204
205 if (percentage <= 0 || percentage > 50) {
206 const char *new_new_value = "5";
207 zend_ini_entry *ini_entry;
208
209 percentage = 5;
210 zend_accel_error(ACCEL_LOG_WARNING, "opcache.max_wasted_percentage must be set between 1 and 50.\n");
211 zend_accel_error(ACCEL_LOG_WARNING, ACCELERATOR_PRODUCT_NAME " will use 5%.\n");
212 if (zend_hash_find(EG(ini_directives),
213 "opcache.max_wasted_percentage",
214 sizeof("opcache.max_wasted_percentage"),
215 (void *) &ini_entry) == FAILURE) {
216 return FAILURE;
217 }
218 ini_entry->value = strdup(new_new_value);
219 ini_entry->value_length = strlen(new_new_value);
220 }
221 *p = (double)percentage / 100.0;
222 return SUCCESS;
223 }
224
ZEND_INI_MH(OnEnable)225 static ZEND_INI_MH(OnEnable)
226 {
227 if (stage == ZEND_INI_STAGE_STARTUP ||
228 stage == ZEND_INI_STAGE_SHUTDOWN ||
229 stage == ZEND_INI_STAGE_DEACTIVATE) {
230 return OnUpdateBool(entry, new_value, new_value_length, mh_arg1, mh_arg2, mh_arg3, stage TSRMLS_CC);
231 } else {
232 /* It may be only temporary disabled */
233 zend_bool *p;
234 #ifndef ZTS
235 char *base = (char *) mh_arg2;
236 #else
237 char *base = (char *) ts_resource(*((int *) mh_arg2));
238 #endif
239
240 p = (zend_bool *) (base+(size_t) mh_arg1);
241 if ((new_value_length == 2 && strcasecmp("on", new_value) == 0) ||
242 (new_value_length == 3 && strcasecmp("yes", new_value) == 0) ||
243 (new_value_length == 4 && strcasecmp("true", new_value) == 0) ||
244 atoi(new_value) != 0) {
245 zend_error(E_WARNING, ACCELERATOR_PRODUCT_NAME " can't be temporary enabled (it may be only disabled till the end of request)");
246 return FAILURE;
247 } else {
248 *p = 0;
249 return SUCCESS;
250 }
251 }
252 }
253
254 ZEND_INI_BEGIN()
255 STD_PHP_INI_BOOLEAN("opcache.enable" , "1", PHP_INI_ALL, OnEnable, enabled , zend_accel_globals, accel_globals)
256 STD_PHP_INI_BOOLEAN("opcache.use_cwd" , "1", PHP_INI_SYSTEM, OnUpdateBool, accel_directives.use_cwd , zend_accel_globals, accel_globals)
257 STD_PHP_INI_BOOLEAN("opcache.validate_timestamps", "1", PHP_INI_ALL , OnUpdateBool, accel_directives.validate_timestamps, zend_accel_globals, accel_globals)
258 STD_PHP_INI_BOOLEAN("opcache.validate_permission", "0", PHP_INI_SYSTEM, OnUpdateBool, accel_directives.validate_permission, zend_accel_globals, accel_globals)
259 #ifndef ZEND_WIN32
260 STD_PHP_INI_BOOLEAN("opcache.validate_root" , "0", PHP_INI_SYSTEM, OnUpdateBool, accel_directives.validate_root , zend_accel_globals, accel_globals)
261 #endif
262 STD_PHP_INI_BOOLEAN("opcache.inherited_hack" , "1", PHP_INI_SYSTEM, OnUpdateBool, accel_directives.inherited_hack , zend_accel_globals, accel_globals)
263 STD_PHP_INI_BOOLEAN("opcache.dups_fix" , "0", PHP_INI_ALL , OnUpdateBool, accel_directives.ignore_dups , zend_accel_globals, accel_globals)
264 STD_PHP_INI_BOOLEAN("opcache.revalidate_path" , "0", PHP_INI_ALL , OnUpdateBool, accel_directives.revalidate_path , zend_accel_globals, accel_globals)
265
266 STD_PHP_INI_ENTRY("opcache.log_verbosity_level" , "1" , PHP_INI_SYSTEM, OnUpdateLong, accel_directives.log_verbosity_level, zend_accel_globals, accel_globals)
267 STD_PHP_INI_ENTRY("opcache.memory_consumption" , "64" , PHP_INI_SYSTEM, OnUpdateMemoryConsumption, accel_directives.memory_consumption, zend_accel_globals, accel_globals)
268 #if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
269 STD_PHP_INI_ENTRY("opcache.interned_strings_buffer", "4" , PHP_INI_SYSTEM, OnUpdateLong, accel_directives.interned_strings_buffer, zend_accel_globals, accel_globals)
270 #endif
271 STD_PHP_INI_ENTRY("opcache.max_accelerated_files" , "2000", PHP_INI_SYSTEM, OnUpdateMaxAcceleratedFiles, accel_directives.max_accelerated_files, zend_accel_globals, accel_globals)
272 STD_PHP_INI_ENTRY("opcache.max_wasted_percentage" , "5" , PHP_INI_SYSTEM, OnUpdateMaxWastedPercentage, accel_directives.max_wasted_percentage, zend_accel_globals, accel_globals)
273 STD_PHP_INI_ENTRY("opcache.consistency_checks" , "0" , PHP_INI_ALL , OnUpdateLong, accel_directives.consistency_checks, zend_accel_globals, accel_globals)
274 STD_PHP_INI_ENTRY("opcache.force_restart_timeout" , "180" , PHP_INI_SYSTEM, OnUpdateLong, accel_directives.force_restart_timeout, zend_accel_globals, accel_globals)
275 STD_PHP_INI_ENTRY("opcache.revalidate_freq" , "2" , PHP_INI_ALL , OnUpdateLong, accel_directives.revalidate_freq, zend_accel_globals, accel_globals)
276 STD_PHP_INI_ENTRY("opcache.file_update_protection", "2" , PHP_INI_ALL , OnUpdateLong, accel_directives.file_update_protection, zend_accel_globals, accel_globals)
277 STD_PHP_INI_ENTRY("opcache.preferred_memory_model", "" , PHP_INI_SYSTEM, OnUpdateStringUnempty, accel_directives.memory_model, zend_accel_globals, accel_globals)
278 STD_PHP_INI_ENTRY("opcache.blacklist_filename" , "" , PHP_INI_SYSTEM, OnUpdateString, accel_directives.user_blacklist_filename, zend_accel_globals, accel_globals)
279 STD_PHP_INI_ENTRY("opcache.max_file_size" , "0" , PHP_INI_SYSTEM, OnUpdateLong, accel_directives.max_file_size, zend_accel_globals, accel_globals)
280
281 STD_PHP_INI_ENTRY("opcache.protect_memory" , "0" , PHP_INI_SYSTEM, OnUpdateBool, accel_directives.protect_memory, zend_accel_globals, accel_globals)
282 STD_PHP_INI_ENTRY("opcache.save_comments" , "1" , PHP_INI_SYSTEM, OnUpdateBool, accel_directives.save_comments, zend_accel_globals, accel_globals)
283 STD_PHP_INI_ENTRY("opcache.load_comments" , "1" , PHP_INI_ALL, OnUpdateBool, accel_directives.load_comments, zend_accel_globals, accel_globals)
284 STD_PHP_INI_ENTRY("opcache.fast_shutdown" , "0" , PHP_INI_SYSTEM, OnUpdateBool, accel_directives.fast_shutdown, zend_accel_globals, accel_globals)
285
286 STD_PHP_INI_ENTRY("opcache.optimization_level" , DEFAULT_OPTIMIZATION_LEVEL , PHP_INI_SYSTEM, OnUpdateLong, accel_directives.optimization_level, zend_accel_globals, accel_globals)
287 STD_PHP_INI_BOOLEAN("opcache.enable_file_override" , "0" , PHP_INI_SYSTEM, OnUpdateBool, accel_directives.file_override_enabled, zend_accel_globals, accel_globals)
288 STD_PHP_INI_BOOLEAN("opcache.enable_cli" , "0" , PHP_INI_SYSTEM, OnUpdateBool, accel_directives.enable_cli, zend_accel_globals, accel_globals)
289 STD_PHP_INI_ENTRY("opcache.error_log" , "" , PHP_INI_SYSTEM, OnUpdateString, accel_directives.error_log, zend_accel_globals, accel_globals)
290 STD_PHP_INI_ENTRY("opcache.restrict_api" , "" , PHP_INI_SYSTEM, OnUpdateString, accel_directives.restrict_api, zend_accel_globals, accel_globals)
291
292 #ifdef ZEND_WIN32
293 STD_PHP_INI_ENTRY("opcache.mmap_base", NULL, PHP_INI_SYSTEM, OnUpdateString, accel_directives.mmap_base, zend_accel_globals, accel_globals)
294 #endif
ZEND_INI_END()295 ZEND_INI_END()
296
297 #if ZEND_EXTENSION_API_NO < PHP_5_3_X_API_NO
298
299 #undef EX
300 #define EX(element) execute_data->element
301 #define EX_T(offset) (*(temp_variable *)((char *) EX(Ts) + offset))
302
303 static int ZEND_DECLARE_INHERITED_CLASS_DELAYED_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
304 {
305 zend_class_entry **pce, **pce_orig;
306
307 if (zend_hash_find(EG(class_table), Z_STRVAL(EX(opline)->op2.u.constant), Z_STRLEN(EX(opline)->op2.u.constant) + 1, (void **)&pce) == FAILURE ||
308 (zend_hash_find(EG(class_table), Z_STRVAL(EX(opline)->op1.u.constant), Z_STRLEN(EX(opline)->op1.u.constant), (void**)&pce_orig) == SUCCESS &&
309 *pce != *pce_orig)) {
310 do_bind_inherited_class(EX(opline), EG(class_table), EX_T(EX(opline)->extended_value).class_entry, 0 TSRMLS_CC);
311 }
312 EX(opline)++;
313 return ZEND_USER_OPCODE_CONTINUE;
314 }
315 #endif
316
filename_is_in_cache(char * filename,int filename_len TSRMLS_DC)317 static int filename_is_in_cache(char *filename, int filename_len TSRMLS_DC)
318 {
319 char *key;
320 int key_length;
321 zend_file_handle handle = {0};
322 zend_persistent_script *persistent_script;
323
324 handle.filename = filename;
325 handle.type = ZEND_HANDLE_FILENAME;
326
327 if (IS_ABSOLUTE_PATH(filename, filename_len)) {
328 persistent_script = zend_accel_hash_find(&ZCSG(hash), filename, filename_len + 1);
329 if (persistent_script) {
330 return !persistent_script->corrupted &&
331 (!ZCG(accel_directives).validate_timestamps ||
332 validate_timestamp_and_record(persistent_script, &handle TSRMLS_CC) == SUCCESS);
333 }
334 }
335
336 if ((key = accel_make_persistent_key_ex(&handle, filename_len, &key_length TSRMLS_CC)) != NULL) {
337 persistent_script = zend_accel_hash_find(&ZCSG(hash), key, key_length + 1);
338 return persistent_script && !persistent_script->corrupted &&
339 (!ZCG(accel_directives).validate_timestamps ||
340 validate_timestamp_and_record(persistent_script, &handle TSRMLS_CC) == SUCCESS);
341 }
342
343 return 0;
344 }
345
accel_file_in_cache(INTERNAL_FUNCTION_PARAMETERS)346 static int accel_file_in_cache(INTERNAL_FUNCTION_PARAMETERS)
347 {
348 zval **zfilename;
349
350 if (ZEND_NUM_ARGS() != 1 ||
351 zend_get_parameters_array_ex(1, &zfilename) == FAILURE ||
352 Z_TYPE_PP(zfilename) != IS_STRING ||
353 Z_STRLEN_PP(zfilename) == 0) {
354 return 0;
355 }
356 return filename_is_in_cache(Z_STRVAL_PP(zfilename), Z_STRLEN_PP(zfilename) TSRMLS_CC);
357 }
358
accel_file_exists(INTERNAL_FUNCTION_PARAMETERS)359 static void accel_file_exists(INTERNAL_FUNCTION_PARAMETERS)
360 {
361 if (accel_file_in_cache(INTERNAL_FUNCTION_PARAM_PASSTHRU)) {
362 RETURN_TRUE;
363 } else {
364 orig_file_exists(INTERNAL_FUNCTION_PARAM_PASSTHRU);
365 }
366 }
367
accel_is_file(INTERNAL_FUNCTION_PARAMETERS)368 static void accel_is_file(INTERNAL_FUNCTION_PARAMETERS)
369 {
370 if (accel_file_in_cache(INTERNAL_FUNCTION_PARAM_PASSTHRU)) {
371 RETURN_TRUE;
372 } else {
373 orig_is_file(INTERNAL_FUNCTION_PARAM_PASSTHRU);
374 }
375 }
376
accel_is_readable(INTERNAL_FUNCTION_PARAMETERS)377 static void accel_is_readable(INTERNAL_FUNCTION_PARAMETERS)
378 {
379 if (accel_file_in_cache(INTERNAL_FUNCTION_PARAM_PASSTHRU)) {
380 RETURN_TRUE;
381 } else {
382 orig_is_readable(INTERNAL_FUNCTION_PARAM_PASSTHRU);
383 }
384 }
385
ZEND_MINIT_FUNCTION(zend_accelerator)386 static ZEND_MINIT_FUNCTION(zend_accelerator)
387 {
388 (void)type; /* keep the compiler happy */
389
390 REGISTER_INI_ENTRIES();
391 #if ZEND_EXTENSION_API_NO < PHP_5_3_X_API_NO
392 zend_set_user_opcode_handler(ZEND_DECLARE_INHERITED_CLASS_DELAYED, ZEND_DECLARE_INHERITED_CLASS_DELAYED_HANDLER);
393 #endif
394 return SUCCESS;
395 }
396
zend_accel_override_file_functions(TSRMLS_D)397 void zend_accel_override_file_functions(TSRMLS_D)
398 {
399 zend_function *old_function;
400 if (ZCG(enabled) && accel_startup_ok && ZCG(accel_directives).file_override_enabled) {
401 /* override file_exists */
402 if (zend_hash_find(CG(function_table), "file_exists", sizeof("file_exists"), (void **)&old_function) == SUCCESS) {
403 orig_file_exists = old_function->internal_function.handler;
404 old_function->internal_function.handler = accel_file_exists;
405 }
406 if (zend_hash_find(CG(function_table), "is_file", sizeof("is_file"), (void **)&old_function) == SUCCESS) {
407 orig_is_file = old_function->internal_function.handler;
408 old_function->internal_function.handler = accel_is_file;
409 }
410 if (zend_hash_find(CG(function_table), "is_readable", sizeof("is_readable"), (void **)&old_function) == SUCCESS) {
411 orig_is_readable = old_function->internal_function.handler;
412 old_function->internal_function.handler = accel_is_readable;
413 }
414 }
415 }
416
ZEND_MSHUTDOWN_FUNCTION(zend_accelerator)417 static ZEND_MSHUTDOWN_FUNCTION(zend_accelerator)
418 {
419 (void)type; /* keep the compiler happy */
420
421 UNREGISTER_INI_ENTRIES();
422 accel_shutdown(TSRMLS_C);
423 return SUCCESS;
424 }
425
zend_accel_info(ZEND_MODULE_INFO_FUNC_ARGS)426 void zend_accel_info(ZEND_MODULE_INFO_FUNC_ARGS)
427 {
428 php_info_print_table_start();
429
430 if (ZCG(enabled) && accel_startup_ok && (ZCG(counted) || ZCSG(accelerator_enabled))) {
431 php_info_print_table_row(2, "Opcode Caching", "Up and Running");
432 } else {
433 php_info_print_table_row(2, "Opcode Caching", "Disabled");
434 }
435 if (ZCG(enabled) && accel_startup_ok && ZCSG(accelerator_enabled) && ZCG(accel_directives).optimization_level) {
436 php_info_print_table_row(2, "Optimization", "Enabled");
437 } else {
438 php_info_print_table_row(2, "Optimization", "Disabled");
439 }
440 if (ZCG(enabled)) {
441 if (!accel_startup_ok || zps_api_failure_reason) {
442 php_info_print_table_row(2, "Startup Failed", zps_api_failure_reason);
443 } else {
444 char buf[32];
445 php_info_print_table_row(2, "Startup", "OK");
446 php_info_print_table_row(2, "Shared memory model", zend_accel_get_shared_model());
447 snprintf(buf, sizeof(buf), "%ld", ZCSG(hits));
448 php_info_print_table_row(2, "Cache hits", buf);
449 snprintf(buf, sizeof(buf), "%ld", ZSMMG(memory_exhausted)?ZCSG(misses):ZCSG(misses)-ZCSG(blacklist_misses));
450 php_info_print_table_row(2, "Cache misses", buf);
451 snprintf(buf, sizeof(buf), "%ld", ZCG(accel_directives).memory_consumption-zend_shared_alloc_get_free_memory()-ZSMMG(wasted_shared_memory));
452 php_info_print_table_row(2, "Used memory", buf);
453 snprintf(buf, sizeof(buf), "%ld", zend_shared_alloc_get_free_memory());
454 php_info_print_table_row(2, "Free memory", buf);
455 snprintf(buf, sizeof(buf), "%ld", ZSMMG(wasted_shared_memory));
456 php_info_print_table_row(2, "Wasted memory", buf);
457 #if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
458 if (ZCSG(interned_strings_start) && ZCSG(interned_strings_end) && ZCSG(interned_strings_top)) {
459 snprintf(buf, sizeof(buf), "%ld", ZCSG(interned_strings_top) - ZCSG(interned_strings_start));
460 php_info_print_table_row(2, "Interned Strings Used memory", buf);
461 snprintf(buf, sizeof(buf), "%ld", ZCSG(interned_strings_end) - ZCSG(interned_strings_top));
462 php_info_print_table_row(2, "Interned Strings Free memory", buf);
463 }
464 #endif
465 snprintf(buf, sizeof(buf), "%ld", ZCSG(hash).num_direct_entries);
466 php_info_print_table_row(2, "Cached scripts", buf);
467 snprintf(buf, sizeof(buf), "%ld", ZCSG(hash).num_entries);
468 php_info_print_table_row(2, "Cached keys", buf);
469 snprintf(buf, sizeof(buf), "%ld", ZCSG(hash).max_num_entries);
470 php_info_print_table_row(2, "Max keys", buf);
471 snprintf(buf, sizeof(buf), "%ld", ZCSG(oom_restarts));
472 php_info_print_table_row(2, "OOM restarts", buf);
473 snprintf(buf, sizeof(buf), "%ld", ZCSG(hash_restarts));
474 php_info_print_table_row(2, "Hash keys restarts", buf);
475 snprintf(buf, sizeof(buf), "%ld", ZCSG(manual_restarts));
476 php_info_print_table_row(2, "Manual restarts", buf);
477 }
478 }
479
480 php_info_print_table_end();
481 DISPLAY_INI_ENTRIES();
482 }
483
484 static zend_module_entry accel_module_entry = {
485 STANDARD_MODULE_HEADER,
486 ACCELERATOR_PRODUCT_NAME,
487 accel_functions,
488 ZEND_MINIT(zend_accelerator),
489 ZEND_MSHUTDOWN(zend_accelerator),
490 NULL,
491 NULL,
492 zend_accel_info,
493 ACCELERATOR_VERSION "FE",
494 STANDARD_MODULE_PROPERTIES
495 };
496
start_accel_module(void)497 int start_accel_module(void)
498 {
499 return zend_startup_module(&accel_module_entry);
500 }
501
502 /* {{{ proto array accelerator_get_scripts()
503 Get the scripts which are accelerated by ZendAccelerator */
accelerator_get_scripts(TSRMLS_D)504 static zval* accelerator_get_scripts(TSRMLS_D)
505 {
506 uint i;
507 zval *return_value,*persistent_script_report;
508 zend_accel_hash_entry *cache_entry;
509 struct tm *ta;
510 struct timeval exec_time;
511 struct timeval fetch_time;
512
513 if (!ZCG(enabled) || !accel_startup_ok || !ZCSG(accelerator_enabled) || accelerator_shm_read_lock(TSRMLS_C) != SUCCESS) {
514 return 0;
515 }
516
517 MAKE_STD_ZVAL(return_value);
518 array_init(return_value);
519 for (i = 0; i<ZCSG(hash).max_num_entries; i++) {
520 for (cache_entry = ZCSG(hash).hash_table[i]; cache_entry; cache_entry = cache_entry->next) {
521 zend_persistent_script *script;
522 char *str;
523 size_t len;
524
525 if (cache_entry->indirect) continue;
526
527 script = (zend_persistent_script *)cache_entry->data;
528
529 MAKE_STD_ZVAL(persistent_script_report);
530 array_init(persistent_script_report);
531 add_assoc_stringl(persistent_script_report, "full_path", script->full_path, script->full_path_len, 1);
532 add_assoc_long(persistent_script_report, "hits", script->dynamic_members.hits);
533 add_assoc_long(persistent_script_report, "memory_consumption", script->dynamic_members.memory_consumption);
534 ta = localtime(&script->dynamic_members.last_used);
535 str = asctime(ta);
536 len = strlen(str);
537 if (len > 0 && str[len - 1] == '\n') len--;
538 add_assoc_stringl(persistent_script_report, "last_used", str, len, 1);
539 add_assoc_long(persistent_script_report, "last_used_timestamp", script->dynamic_members.last_used);
540 if (ZCG(accel_directives).validate_timestamps) {
541 add_assoc_long(persistent_script_report, "timestamp", (long)script->timestamp);
542 }
543 timerclear(&exec_time);
544 timerclear(&fetch_time);
545
546 zend_hash_update(return_value->value.ht, cache_entry->key, cache_entry->key_length, &persistent_script_report, sizeof(zval *), NULL);
547 }
548 }
549 accelerator_shm_read_unlock(TSRMLS_C);
550
551 return return_value;
552 }
553
554 /* {{{ proto array accelerator_get_status([bool fetch_scripts])
555 Obtain statistics information regarding code acceleration */
ZEND_FUNCTION(opcache_get_status)556 static ZEND_FUNCTION(opcache_get_status)
557 {
558 long reqs;
559 zval *memory_usage,*statistics,*scripts;
560 zend_bool fetch_scripts = 1;
561
562 /* keep the compiler happy */
563 (void)ht; (void)return_value_ptr; (void)this_ptr; (void)return_value_used;
564
565 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &fetch_scripts) == FAILURE) {
566 return;
567 }
568
569 if (!validate_api_restriction(TSRMLS_C)) {
570 RETURN_FALSE;
571 }
572
573 if (!accel_startup_ok) {
574 RETURN_FALSE;
575 }
576
577 array_init(return_value);
578
579 /* Trivia */
580 add_assoc_bool(return_value, "opcache_enabled", ZCG(enabled) && (ZCG(counted) || ZCSG(accelerator_enabled)));
581 add_assoc_bool(return_value, "cache_full", ZSMMG(memory_exhausted));
582 add_assoc_bool(return_value, "restart_pending", ZCSG(restart_pending));
583 add_assoc_bool(return_value, "restart_in_progress", ZCSG(restart_in_progress));
584
585 /* Memory usage statistics */
586 MAKE_STD_ZVAL(memory_usage);
587 array_init(memory_usage);
588 add_assoc_long(memory_usage, "used_memory", ZCG(accel_directives).memory_consumption-zend_shared_alloc_get_free_memory()-ZSMMG(wasted_shared_memory));
589 add_assoc_long(memory_usage, "free_memory", zend_shared_alloc_get_free_memory());
590 add_assoc_long(memory_usage, "wasted_memory", ZSMMG(wasted_shared_memory));
591 add_assoc_double(memory_usage, "current_wasted_percentage", (((double) ZSMMG(wasted_shared_memory))/ZCG(accel_directives).memory_consumption)*100.0);
592 add_assoc_zval(return_value, "memory_usage", memory_usage);
593
594 #if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
595 if (ZCSG(interned_strings_start) && ZCSG(interned_strings_end) && ZCSG(interned_strings_top)) {
596 zval *interned_strings_usage;
597
598 MAKE_STD_ZVAL(interned_strings_usage);
599 array_init(interned_strings_usage);
600 add_assoc_long(interned_strings_usage, "buffer_size", ZCSG(interned_strings_end) - ZCSG(interned_strings_start));
601 add_assoc_long(interned_strings_usage, "used_memory", ZCSG(interned_strings_top) - ZCSG(interned_strings_start));
602 add_assoc_long(interned_strings_usage, "free_memory", ZCSG(interned_strings_end) - ZCSG(interned_strings_top));
603 add_assoc_long(interned_strings_usage, "number_of_strings", ZCSG(interned_strings).nNumOfElements);
604 add_assoc_zval(return_value, "interned_strings_usage", interned_strings_usage);
605 }
606 #endif
607
608 /* Accelerator statistics */
609 MAKE_STD_ZVAL(statistics);
610 array_init(statistics);
611 add_assoc_long(statistics, "num_cached_scripts", ZCSG(hash).num_direct_entries);
612 add_assoc_long(statistics, "num_cached_keys", ZCSG(hash).num_entries);
613 add_assoc_long(statistics, "max_cached_keys", ZCSG(hash).max_num_entries);
614 add_assoc_long(statistics, "hits", ZCSG(hits));
615 add_assoc_long(statistics, "start_time", ZCSG(start_time));
616 add_assoc_long(statistics, "last_restart_time", ZCSG(last_restart_time));
617 add_assoc_long(statistics, "oom_restarts", ZCSG(oom_restarts));
618 add_assoc_long(statistics, "hash_restarts", ZCSG(hash_restarts));
619 add_assoc_long(statistics, "manual_restarts", ZCSG(manual_restarts));
620 add_assoc_long(statistics, "misses", ZSMMG(memory_exhausted)?ZCSG(misses):ZCSG(misses)-ZCSG(blacklist_misses));
621 add_assoc_long(statistics, "blacklist_misses", ZCSG(blacklist_misses));
622 reqs = ZCSG(hits)+ZCSG(misses);
623 add_assoc_double(statistics, "blacklist_miss_ratio", reqs?(((double) ZCSG(blacklist_misses))/reqs)*100.0:0);
624 add_assoc_double(statistics, "opcache_hit_rate", reqs?(((double) ZCSG(hits))/reqs)*100.0:0);
625 add_assoc_zval(return_value, "opcache_statistics", statistics);
626
627 if (fetch_scripts) {
628 /* accelerated scripts */
629 scripts = accelerator_get_scripts(TSRMLS_C);
630 if (scripts) {
631 add_assoc_zval(return_value, "scripts", scripts);
632 }
633 }
634 }
635
add_blacklist_path(zend_blacklist_entry * p,zval * return_value TSRMLS_DC)636 static int add_blacklist_path(zend_blacklist_entry *p, zval *return_value TSRMLS_DC)
637 {
638 add_next_index_stringl(return_value, p->path, p->path_length, 1);
639 return 0;
640 }
641
642 /* {{{ proto array accelerator_get_configuration()
643 Obtain configuration information */
ZEND_FUNCTION(opcache_get_configuration)644 static ZEND_FUNCTION(opcache_get_configuration)
645 {
646 zval *directives,*version,*blacklist;
647
648 /* keep the compiler happy */
649 (void)ht; (void)return_value_ptr; (void)this_ptr; (void)return_value_used;
650
651 #if ZEND_EXTENSION_API_NO >= PHP_5_3_X_API_NO
652 if (zend_parse_parameters_none() == FAILURE) {
653 RETURN_FALSE;
654 }
655 #endif
656
657 if (!validate_api_restriction(TSRMLS_C)) {
658 RETURN_FALSE;
659 }
660
661 array_init(return_value);
662
663 /* directives */
664 MAKE_STD_ZVAL(directives);
665 array_init(directives);
666 add_assoc_bool(directives, "opcache.enable", ZCG(enabled));
667 add_assoc_bool(directives, "opcache.enable_cli", ZCG(accel_directives).enable_cli);
668 add_assoc_bool(directives, "opcache.use_cwd", ZCG(accel_directives).use_cwd);
669 add_assoc_bool(directives, "opcache.validate_timestamps", ZCG(accel_directives).validate_timestamps);
670 add_assoc_bool(directives, "opcache.validate_permission", ZCG(accel_directives).validate_permission);
671 #ifndef ZEND_WIN32
672 add_assoc_bool(directives, "opcache.validate_root", ZCG(accel_directives).validate_root);
673 #endif
674 add_assoc_bool(directives, "opcache.inherited_hack", ZCG(accel_directives).inherited_hack);
675 add_assoc_bool(directives, "opcache.dups_fix", ZCG(accel_directives).ignore_dups);
676 add_assoc_bool(directives, "opcache.revalidate_path", ZCG(accel_directives).revalidate_path);
677
678 add_assoc_long(directives, "opcache.log_verbosity_level", ZCG(accel_directives).log_verbosity_level);
679 add_assoc_long(directives, "opcache.memory_consumption", ZCG(accel_directives).memory_consumption);
680 #if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
681 add_assoc_long(directives, "opcache.interned_strings_buffer",ZCG(accel_directives).interned_strings_buffer);
682 #endif
683 add_assoc_long(directives, "opcache.max_accelerated_files", ZCG(accel_directives).max_accelerated_files);
684 add_assoc_double(directives, "opcache.max_wasted_percentage", ZCG(accel_directives).max_wasted_percentage);
685 add_assoc_long(directives, "opcache.consistency_checks", ZCG(accel_directives).consistency_checks);
686 add_assoc_long(directives, "opcache.force_restart_timeout", ZCG(accel_directives).force_restart_timeout);
687 add_assoc_long(directives, "opcache.revalidate_freq", ZCG(accel_directives).revalidate_freq);
688 add_assoc_string(directives, "opcache.preferred_memory_model", STRING_NOT_NULL(ZCG(accel_directives).memory_model), 1);
689 add_assoc_string(directives, "opcache.blacklist_filename", STRING_NOT_NULL(ZCG(accel_directives).user_blacklist_filename), 1);
690 add_assoc_long(directives, "opcache.max_file_size", ZCG(accel_directives).max_file_size);
691 add_assoc_string(directives, "opcache.error_log", STRING_NOT_NULL(ZCG(accel_directives).error_log), 1);
692
693 add_assoc_bool(directives, "opcache.protect_memory", ZCG(accel_directives).protect_memory);
694 add_assoc_bool(directives, "opcache.save_comments", ZCG(accel_directives).save_comments);
695 add_assoc_bool(directives, "opcache.load_comments", ZCG(accel_directives).load_comments);
696 add_assoc_bool(directives, "opcache.fast_shutdown", ZCG(accel_directives).fast_shutdown);
697 add_assoc_bool(directives, "opcache.enable_file_override", ZCG(accel_directives).file_override_enabled);
698 add_assoc_long(directives, "opcache.optimization_level", ZCG(accel_directives).optimization_level);
699
700 add_assoc_zval(return_value, "directives", directives);
701
702 /*version */
703 MAKE_STD_ZVAL(version);
704 array_init(version);
705 add_assoc_string(version, "version", ACCELERATOR_VERSION, 1);
706 add_assoc_string(version, "opcache_product_name", ACCELERATOR_PRODUCT_NAME, 1);
707 add_assoc_zval(return_value, "version", version);
708
709 /* blacklist */
710 MAKE_STD_ZVAL(blacklist);
711 array_init(blacklist);
712 zend_accel_blacklist_apply(&accel_blacklist, (apply_func_arg_t) add_blacklist_path, blacklist TSRMLS_CC);
713 add_assoc_zval(return_value, "blacklist", blacklist);
714 }
715
716 /* {{{ proto void accelerator_reset()
717 Request that the contents of the opcode cache to be reset */
ZEND_FUNCTION(opcache_reset)718 static ZEND_FUNCTION(opcache_reset)
719 {
720 /* keep the compiler happy */
721 (void)ht; (void)return_value_ptr; (void)this_ptr; (void)return_value_used;
722
723 #if ZEND_EXTENSION_API_NO >= PHP_5_3_X_API_NO
724 if (zend_parse_parameters_none() == FAILURE) {
725 RETURN_FALSE;
726 }
727 #endif
728
729 if (!validate_api_restriction(TSRMLS_C)) {
730 RETURN_FALSE;
731 }
732
733 if (!ZCG(enabled) || !accel_startup_ok || !ZCSG(accelerator_enabled)) {
734 RETURN_FALSE;
735 }
736
737 zend_accel_schedule_restart(ACCEL_RESTART_USER TSRMLS_CC);
738 RETURN_TRUE;
739 }
740
741 /* {{{ proto void opcache_invalidate(string $script [, bool $force = false])
742 Invalidates cached script (in necessary or forced) */
ZEND_FUNCTION(opcache_invalidate)743 static ZEND_FUNCTION(opcache_invalidate)
744 {
745 char *script_name;
746 int script_name_len;
747 zend_bool force = 0;
748
749 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|b", &script_name, &script_name_len, &force) == FAILURE) {
750 return;
751 }
752
753 if (!validate_api_restriction(TSRMLS_C)) {
754 RETURN_FALSE;
755 }
756
757 if (zend_accel_invalidate(script_name, script_name_len, force TSRMLS_CC) == SUCCESS) {
758 RETURN_TRUE;
759 } else {
760 RETURN_FALSE;
761 }
762 }
763
ZEND_FUNCTION(opcache_compile_file)764 static ZEND_FUNCTION(opcache_compile_file)
765 {
766 char *script_name;
767 int script_name_len;
768 zend_file_handle handle;
769 zend_op_array *op_array = NULL;
770 zend_execute_data *orig_execute_data = NULL;
771
772 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &script_name, &script_name_len) == FAILURE) {
773 return;
774 }
775
776 if (!ZCG(enabled) || !accel_startup_ok || !ZCSG(accelerator_enabled)) {
777 zend_error(E_NOTICE, ACCELERATOR_PRODUCT_NAME " seems to be disabled, can't compile file");
778 RETURN_FALSE;
779 }
780
781 handle.filename = script_name;
782 handle.free_filename = 0;
783 handle.opened_path = NULL;
784 handle.type = ZEND_HANDLE_FILENAME;
785
786 orig_execute_data = EG(current_execute_data);
787
788 zend_try {
789 op_array = persistent_compile_file(&handle, ZEND_INCLUDE TSRMLS_CC);
790 } zend_catch {
791 EG(current_execute_data) = orig_execute_data;
792 zend_error(E_WARNING, ACCELERATOR_PRODUCT_NAME " could not compile file %s", handle.filename);
793 } zend_end_try();
794
795 if(op_array != NULL) {
796 destroy_op_array(op_array TSRMLS_CC);
797 efree(op_array);
798 RETVAL_TRUE;
799 } else {
800 RETVAL_FALSE;
801 }
802 zend_destroy_file_handle(&handle TSRMLS_CC);
803 }
804
805 /* {{{ proto bool opcache_is_script_cached(string $script)
806 Return true if the script is cached in OPCache, false if it is not cached or if OPCache is not running. */
ZEND_FUNCTION(opcache_is_script_cached)807 static ZEND_FUNCTION(opcache_is_script_cached)
808 {
809 char *script_name;
810 int script_name_len;
811
812 if (!validate_api_restriction(TSRMLS_C)) {
813 RETURN_FALSE;
814 }
815
816 if (!ZCG(enabled) || !accel_startup_ok || !ZCSG(accelerator_enabled)) {
817 RETURN_FALSE;
818 }
819
820 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &script_name, &script_name_len) == FAILURE) {
821 return;
822 }
823
824 RETURN_BOOL(filename_is_in_cache(script_name, script_name_len TSRMLS_CC));
825 }
826