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