PageRenderTime 54ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/ext/opcache/zend_accelerator_module.c

http://github.com/php/php-src
C | 864 lines | 707 code | 110 blank | 47 comment | 150 complexity | 70f3072408a9e136b7c21eef3bf4370d MD5 | raw file
Possible License(s): BSD-2-Clause, BSD-3-Clause, MPL-2.0-no-copyleft-exception, LGPL-2.1
  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. | 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@php.net> |
  16. | Zeev Suraski <zeev@php.net> |
  17. | Stanislav Malyshev <stas@zend.com> |
  18. | Dmitry Stogov <dmitry@php.net> |
  19. +----------------------------------------------------------------------+
  20. */
  21. #include <time.h>
  22. #include "php.h"
  23. #include "ZendAccelerator.h"
  24. #include "zend_API.h"
  25. #include "zend_shared_alloc.h"
  26. #include "zend_accelerator_blacklist.h"
  27. #include "php_ini.h"
  28. #include "SAPI.h"
  29. #include "zend_virtual_cwd.h"
  30. #include "ext/standard/info.h"
  31. #include "ext/standard/php_filestat.h"
  32. #include "opcache_arginfo.h"
  33. #if HAVE_JIT
  34. #include "jit/zend_jit.h"
  35. #endif
  36. #define STRING_NOT_NULL(s) (NULL == (s)?"":s)
  37. #define MIN_ACCEL_FILES 200
  38. #define MAX_ACCEL_FILES 1000000
  39. #define TOKENTOSTR(X) #X
  40. static zif_handler orig_file_exists = NULL;
  41. static zif_handler orig_is_file = NULL;
  42. static zif_handler orig_is_readable = NULL;
  43. static int validate_api_restriction(void)
  44. {
  45. if (ZCG(accel_directives).restrict_api && *ZCG(accel_directives).restrict_api) {
  46. size_t len = strlen(ZCG(accel_directives).restrict_api);
  47. if (!SG(request_info).path_translated ||
  48. strlen(SG(request_info).path_translated) < len ||
  49. memcmp(SG(request_info).path_translated, ZCG(accel_directives).restrict_api, len) != 0) {
  50. zend_error(E_WARNING, ACCELERATOR_PRODUCT_NAME " API is restricted by \"restrict_api\" configuration directive");
  51. return 0;
  52. }
  53. }
  54. return 1;
  55. }
  56. static ZEND_INI_MH(OnUpdateMemoryConsumption)
  57. {
  58. zend_long *p = (zend_long *) ZEND_INI_GET_ADDR();
  59. zend_long memsize = atoi(ZSTR_VAL(new_value));
  60. /* sanity check we must use at least 8 MB */
  61. if (memsize < 8) {
  62. const char *new_new_value = "8";
  63. zend_ini_entry *ini_entry;
  64. memsize = 8;
  65. zend_accel_error(ACCEL_LOG_WARNING, "opcache.memory_consumption is set below the required 8MB.\n");
  66. zend_accel_error(ACCEL_LOG_WARNING, ACCELERATOR_PRODUCT_NAME " will use the minimal 8MB configuration.\n");
  67. if ((ini_entry = zend_hash_str_find_ptr(EG(ini_directives),
  68. "opcache.memory_consumption",
  69. sizeof("opcache.memory_consumption")-1)) == NULL) {
  70. return FAILURE;
  71. }
  72. ini_entry->value = zend_string_init_interned(new_new_value, 1, 1);
  73. }
  74. if (UNEXPECTED(memsize > ZEND_ULONG_MAX / (1024 * 1024))) {
  75. *p = ZEND_ULONG_MAX;
  76. } else {
  77. *p = memsize * (1024 * 1024);
  78. }
  79. return SUCCESS;
  80. }
  81. static ZEND_INI_MH(OnUpdateMaxAcceleratedFiles)
  82. {
  83. zend_long *p = (zend_long *) ZEND_INI_GET_ADDR();
  84. zend_long size = atoi(ZSTR_VAL(new_value));
  85. /* sanity check we must use a value between MIN_ACCEL_FILES and MAX_ACCEL_FILES */
  86. if (size < MIN_ACCEL_FILES || size > MAX_ACCEL_FILES) {
  87. const char *new_new_value;
  88. zend_ini_entry *ini_entry;
  89. if (size < MIN_ACCEL_FILES) {
  90. size = MIN_ACCEL_FILES;
  91. new_new_value = TOKENTOSTR(MIN_ACCEL_FILES);
  92. zend_accel_error(ACCEL_LOG_WARNING, "opcache.max_accelerated_files is set below the required minimum (%d).\n", MIN_ACCEL_FILES);
  93. zend_accel_error(ACCEL_LOG_WARNING, ACCELERATOR_PRODUCT_NAME " will use the minimal configuration.\n");
  94. }
  95. if (size > MAX_ACCEL_FILES) {
  96. size = MAX_ACCEL_FILES;
  97. new_new_value = TOKENTOSTR(MAX_ACCEL_FILES);
  98. zend_accel_error(ACCEL_LOG_WARNING, "opcache.max_accelerated_files is set above the limit (%d).\n", MAX_ACCEL_FILES);
  99. zend_accel_error(ACCEL_LOG_WARNING, ACCELERATOR_PRODUCT_NAME " will use the maximal configuration.\n");
  100. }
  101. if ((ini_entry = zend_hash_str_find_ptr(EG(ini_directives),
  102. "opcache.max_accelerated_files",
  103. sizeof("opcache.max_accelerated_files")-1)) == NULL) {
  104. return FAILURE;
  105. }
  106. ini_entry->value = zend_string_init_interned(new_new_value, strlen(new_new_value), 1);
  107. }
  108. *p = size;
  109. return SUCCESS;
  110. }
  111. static ZEND_INI_MH(OnUpdateMaxWastedPercentage)
  112. {
  113. double *p = (double *) ZEND_INI_GET_ADDR();
  114. zend_long percentage = atoi(ZSTR_VAL(new_value));
  115. if (percentage <= 0 || percentage > 50) {
  116. const char *new_new_value = "5";
  117. zend_ini_entry *ini_entry;
  118. percentage = 5;
  119. zend_accel_error(ACCEL_LOG_WARNING, "opcache.max_wasted_percentage must be set between 1 and 50.\n");
  120. zend_accel_error(ACCEL_LOG_WARNING, ACCELERATOR_PRODUCT_NAME " will use 5%%.\n");
  121. if ((ini_entry = zend_hash_str_find_ptr(EG(ini_directives),
  122. "opcache.max_wasted_percentage",
  123. sizeof("opcache.max_wasted_percentage")-1)) == NULL) {
  124. return FAILURE;
  125. }
  126. ini_entry->value = zend_string_init_interned(new_new_value, strlen(new_new_value), 1);
  127. }
  128. *p = (double)percentage / 100.0;
  129. return SUCCESS;
  130. }
  131. static ZEND_INI_MH(OnEnable)
  132. {
  133. if (stage == ZEND_INI_STAGE_STARTUP ||
  134. stage == ZEND_INI_STAGE_SHUTDOWN ||
  135. stage == ZEND_INI_STAGE_DEACTIVATE) {
  136. return OnUpdateBool(entry, new_value, mh_arg1, mh_arg2, mh_arg3, stage);
  137. } else {
  138. /* It may be only temporary disabled */
  139. zend_bool *p = (zend_bool *) ZEND_INI_GET_ADDR();
  140. if ((ZSTR_LEN(new_value) == 2 && strcasecmp("on", ZSTR_VAL(new_value)) == 0) ||
  141. (ZSTR_LEN(new_value) == 3 && strcasecmp("yes", ZSTR_VAL(new_value)) == 0) ||
  142. (ZSTR_LEN(new_value) == 4 && strcasecmp("true", ZSTR_VAL(new_value)) == 0) ||
  143. atoi(ZSTR_VAL(new_value)) != 0) {
  144. zend_error(E_WARNING, ACCELERATOR_PRODUCT_NAME " can't be temporary enabled (it may be only disabled till the end of request)");
  145. return FAILURE;
  146. } else {
  147. *p = 0;
  148. ZCG(accelerator_enabled) = 0;
  149. return SUCCESS;
  150. }
  151. }
  152. }
  153. static ZEND_INI_MH(OnUpdateFileCache)
  154. {
  155. if (new_value) {
  156. if (!ZSTR_LEN(new_value)) {
  157. new_value = NULL;
  158. } else {
  159. zend_stat_t buf;
  160. if (!IS_ABSOLUTE_PATH(ZSTR_VAL(new_value), ZSTR_LEN(new_value)) ||
  161. zend_stat(ZSTR_VAL(new_value), &buf) != 0 ||
  162. !S_ISDIR(buf.st_mode) ||
  163. #ifndef ZEND_WIN32
  164. access(ZSTR_VAL(new_value), R_OK | W_OK | X_OK) != 0) {
  165. #else
  166. _access(ZSTR_VAL(new_value), 06) != 0) {
  167. #endif
  168. zend_accel_error(ACCEL_LOG_WARNING, "opcache.file_cache must be a full path of accessible directory.\n");
  169. new_value = NULL;
  170. }
  171. }
  172. }
  173. OnUpdateString(entry, new_value, mh_arg1, mh_arg2, mh_arg3, stage);
  174. return SUCCESS;
  175. }
  176. ZEND_INI_BEGIN()
  177. STD_PHP_INI_BOOLEAN("opcache.enable" , "1", PHP_INI_ALL, OnEnable, enabled , zend_accel_globals, accel_globals)
  178. STD_PHP_INI_BOOLEAN("opcache.use_cwd" , "1", PHP_INI_SYSTEM, OnUpdateBool, accel_directives.use_cwd , zend_accel_globals, accel_globals)
  179. STD_PHP_INI_BOOLEAN("opcache.validate_timestamps", "1", PHP_INI_ALL , OnUpdateBool, accel_directives.validate_timestamps, zend_accel_globals, accel_globals)
  180. STD_PHP_INI_BOOLEAN("opcache.validate_permission", "0", PHP_INI_SYSTEM, OnUpdateBool, accel_directives.validate_permission, zend_accel_globals, accel_globals)
  181. #ifndef ZEND_WIN32
  182. STD_PHP_INI_BOOLEAN("opcache.validate_root" , "0", PHP_INI_SYSTEM, OnUpdateBool, accel_directives.validate_root , zend_accel_globals, accel_globals)
  183. #endif
  184. STD_PHP_INI_BOOLEAN("opcache.dups_fix" , "0", PHP_INI_ALL , OnUpdateBool, accel_directives.ignore_dups , zend_accel_globals, accel_globals)
  185. STD_PHP_INI_BOOLEAN("opcache.revalidate_path" , "0", PHP_INI_ALL , OnUpdateBool, accel_directives.revalidate_path , zend_accel_globals, accel_globals)
  186. STD_PHP_INI_ENTRY("opcache.log_verbosity_level" , "1" , PHP_INI_SYSTEM, OnUpdateLong, accel_directives.log_verbosity_level, zend_accel_globals, accel_globals)
  187. STD_PHP_INI_ENTRY("opcache.memory_consumption" , "128" , PHP_INI_SYSTEM, OnUpdateMemoryConsumption, accel_directives.memory_consumption, zend_accel_globals, accel_globals)
  188. STD_PHP_INI_ENTRY("opcache.interned_strings_buffer", "8" , PHP_INI_SYSTEM, OnUpdateLong, accel_directives.interned_strings_buffer, zend_accel_globals, accel_globals)
  189. STD_PHP_INI_ENTRY("opcache.max_accelerated_files" , "10000", PHP_INI_SYSTEM, OnUpdateMaxAcceleratedFiles, accel_directives.max_accelerated_files, zend_accel_globals, accel_globals)
  190. STD_PHP_INI_ENTRY("opcache.max_wasted_percentage" , "5" , PHP_INI_SYSTEM, OnUpdateMaxWastedPercentage, accel_directives.max_wasted_percentage, zend_accel_globals, accel_globals)
  191. STD_PHP_INI_ENTRY("opcache.consistency_checks" , "0" , PHP_INI_ALL , OnUpdateLong, accel_directives.consistency_checks, zend_accel_globals, accel_globals)
  192. STD_PHP_INI_ENTRY("opcache.force_restart_timeout" , "180" , PHP_INI_SYSTEM, OnUpdateLong, accel_directives.force_restart_timeout, zend_accel_globals, accel_globals)
  193. STD_PHP_INI_ENTRY("opcache.revalidate_freq" , "2" , PHP_INI_ALL , OnUpdateLong, accel_directives.revalidate_freq, zend_accel_globals, accel_globals)
  194. STD_PHP_INI_ENTRY("opcache.file_update_protection", "2" , PHP_INI_ALL , OnUpdateLong, accel_directives.file_update_protection, zend_accel_globals, accel_globals)
  195. STD_PHP_INI_ENTRY("opcache.preferred_memory_model", "" , PHP_INI_SYSTEM, OnUpdateStringUnempty, accel_directives.memory_model, zend_accel_globals, accel_globals)
  196. STD_PHP_INI_ENTRY("opcache.blacklist_filename" , "" , PHP_INI_SYSTEM, OnUpdateString, accel_directives.user_blacklist_filename, zend_accel_globals, accel_globals)
  197. STD_PHP_INI_ENTRY("opcache.max_file_size" , "0" , PHP_INI_SYSTEM, OnUpdateLong, accel_directives.max_file_size, zend_accel_globals, accel_globals)
  198. STD_PHP_INI_ENTRY("opcache.protect_memory" , "0" , PHP_INI_SYSTEM, OnUpdateBool, accel_directives.protect_memory, zend_accel_globals, accel_globals)
  199. STD_PHP_INI_ENTRY("opcache.save_comments" , "1" , PHP_INI_SYSTEM, OnUpdateBool, accel_directives.save_comments, zend_accel_globals, accel_globals)
  200. STD_PHP_INI_ENTRY("opcache.optimization_level" , DEFAULT_OPTIMIZATION_LEVEL , PHP_INI_SYSTEM, OnUpdateLong, accel_directives.optimization_level, zend_accel_globals, accel_globals)
  201. STD_PHP_INI_ENTRY("opcache.opt_debug_level" , "0" , PHP_INI_SYSTEM, OnUpdateLong, accel_directives.opt_debug_level, zend_accel_globals, accel_globals)
  202. STD_PHP_INI_BOOLEAN("opcache.enable_file_override" , "0" , PHP_INI_SYSTEM, OnUpdateBool, accel_directives.file_override_enabled, zend_accel_globals, accel_globals)
  203. STD_PHP_INI_BOOLEAN("opcache.enable_cli" , "0" , PHP_INI_SYSTEM, OnUpdateBool, accel_directives.enable_cli, zend_accel_globals, accel_globals)
  204. STD_PHP_INI_ENTRY("opcache.error_log" , "" , PHP_INI_SYSTEM, OnUpdateString, accel_directives.error_log, zend_accel_globals, accel_globals)
  205. STD_PHP_INI_ENTRY("opcache.restrict_api" , "" , PHP_INI_SYSTEM, OnUpdateString, accel_directives.restrict_api, zend_accel_globals, accel_globals)
  206. #ifndef ZEND_WIN32
  207. STD_PHP_INI_ENTRY("opcache.lockfile_path" , "/tmp" , PHP_INI_SYSTEM, OnUpdateString, accel_directives.lockfile_path, zend_accel_globals, accel_globals)
  208. #else
  209. STD_PHP_INI_ENTRY("opcache.mmap_base", NULL, PHP_INI_SYSTEM, OnUpdateString, accel_directives.mmap_base, zend_accel_globals, accel_globals)
  210. #endif
  211. STD_PHP_INI_ENTRY("opcache.file_cache" , NULL , PHP_INI_SYSTEM, OnUpdateFileCache, accel_directives.file_cache, zend_accel_globals, accel_globals)
  212. STD_PHP_INI_ENTRY("opcache.file_cache_only" , "0" , PHP_INI_SYSTEM, OnUpdateBool, accel_directives.file_cache_only, zend_accel_globals, accel_globals)
  213. STD_PHP_INI_ENTRY("opcache.file_cache_consistency_checks" , "1" , PHP_INI_SYSTEM, OnUpdateBool, accel_directives.file_cache_consistency_checks, zend_accel_globals, accel_globals)
  214. #if ENABLE_FILE_CACHE_FALLBACK
  215. STD_PHP_INI_ENTRY("opcache.file_cache_fallback" , "1" , PHP_INI_SYSTEM, OnUpdateBool, accel_directives.file_cache_fallback, zend_accel_globals, accel_globals)
  216. #endif
  217. #ifdef HAVE_HUGE_CODE_PAGES
  218. STD_PHP_INI_BOOLEAN("opcache.huge_code_pages" , "0" , PHP_INI_SYSTEM, OnUpdateBool, accel_directives.huge_code_pages, zend_accel_globals, accel_globals)
  219. #endif
  220. STD_PHP_INI_ENTRY("opcache.preload" , "" , PHP_INI_SYSTEM, OnUpdateStringUnempty, accel_directives.preload, zend_accel_globals, accel_globals)
  221. #ifndef ZEND_WIN32
  222. STD_PHP_INI_ENTRY("opcache.preload_user" , "" , PHP_INI_SYSTEM, OnUpdateStringUnempty, accel_directives.preload_user, zend_accel_globals, accel_globals)
  223. #endif
  224. #if ZEND_WIN32
  225. STD_PHP_INI_ENTRY("opcache.cache_id" , "" , PHP_INI_SYSTEM, OnUpdateString, accel_directives.cache_id, zend_accel_globals, accel_globals)
  226. #endif
  227. #ifdef HAVE_JIT
  228. STD_PHP_INI_ENTRY("opcache.jit" , ZEND_JIT_DEFAULT, PHP_INI_SYSTEM, OnUpdateLong, accel_directives.jit, zend_accel_globals, accel_globals)
  229. STD_PHP_INI_ENTRY("opcache.jit_buffer_size" , "0" , PHP_INI_SYSTEM, OnUpdateLong, accel_directives.jit_buffer_size, zend_accel_globals, accel_globals)
  230. STD_PHP_INI_ENTRY("opcache.jit_debug" , "0" , PHP_INI_SYSTEM, OnUpdateLong, accel_directives.jit_debug, zend_accel_globals, accel_globals)
  231. STD_PHP_INI_ENTRY("opcache.jit_bisect_limit" , "0" , PHP_INI_SYSTEM, OnUpdateLong, accel_directives.jit_bisect_limit, zend_accel_globals, accel_globals)
  232. #endif
  233. ZEND_INI_END()
  234. static int filename_is_in_cache(zend_string *filename)
  235. {
  236. char *key;
  237. int key_length;
  238. key = accel_make_persistent_key(ZSTR_VAL(filename), ZSTR_LEN(filename), &key_length);
  239. if (key != NULL) {
  240. zend_persistent_script *persistent_script = zend_accel_hash_str_find(&ZCSG(hash), key, key_length);
  241. if (persistent_script && !persistent_script->corrupted) {
  242. if (ZCG(accel_directives).validate_timestamps) {
  243. zend_file_handle handle;
  244. zend_stream_init_filename(&handle, ZSTR_VAL(filename));
  245. return validate_timestamp_and_record_ex(persistent_script, &handle) == SUCCESS;
  246. }
  247. return 1;
  248. }
  249. }
  250. return 0;
  251. }
  252. static int accel_file_in_cache(INTERNAL_FUNCTION_PARAMETERS)
  253. {
  254. zval zfilename;
  255. if (ZEND_NUM_ARGS() != 1 ||
  256. zend_get_parameters_array_ex(1, &zfilename) == FAILURE ||
  257. Z_TYPE(zfilename) != IS_STRING ||
  258. Z_STRLEN(zfilename) == 0) {
  259. return 0;
  260. }
  261. return filename_is_in_cache(Z_STR(zfilename));
  262. }
  263. static ZEND_NAMED_FUNCTION(accel_file_exists)
  264. {
  265. if (accel_file_in_cache(INTERNAL_FUNCTION_PARAM_PASSTHRU)) {
  266. RETURN_TRUE;
  267. } else {
  268. orig_file_exists(INTERNAL_FUNCTION_PARAM_PASSTHRU);
  269. }
  270. }
  271. static ZEND_NAMED_FUNCTION(accel_is_file)
  272. {
  273. if (accel_file_in_cache(INTERNAL_FUNCTION_PARAM_PASSTHRU)) {
  274. RETURN_TRUE;
  275. } else {
  276. orig_is_file(INTERNAL_FUNCTION_PARAM_PASSTHRU);
  277. }
  278. }
  279. static ZEND_NAMED_FUNCTION(accel_is_readable)
  280. {
  281. if (accel_file_in_cache(INTERNAL_FUNCTION_PARAM_PASSTHRU)) {
  282. RETURN_TRUE;
  283. } else {
  284. orig_is_readable(INTERNAL_FUNCTION_PARAM_PASSTHRU);
  285. }
  286. }
  287. static ZEND_MINIT_FUNCTION(zend_accelerator)
  288. {
  289. (void)type; /* keep the compiler happy */
  290. REGISTER_INI_ENTRIES();
  291. return SUCCESS;
  292. }
  293. void zend_accel_override_file_functions(void)
  294. {
  295. zend_function *old_function;
  296. if (ZCG(enabled) && accel_startup_ok && ZCG(accel_directives).file_override_enabled) {
  297. if (file_cache_only) {
  298. zend_accel_error(ACCEL_LOG_WARNING, "file_override_enabled has no effect when file_cache_only is set");
  299. return;
  300. }
  301. /* override file_exists */
  302. if ((old_function = zend_hash_str_find_ptr(CG(function_table), "file_exists", sizeof("file_exists")-1)) != NULL) {
  303. orig_file_exists = old_function->internal_function.handler;
  304. old_function->internal_function.handler = accel_file_exists;
  305. }
  306. if ((old_function = zend_hash_str_find_ptr(CG(function_table), "is_file", sizeof("is_file")-1)) != NULL) {
  307. orig_is_file = old_function->internal_function.handler;
  308. old_function->internal_function.handler = accel_is_file;
  309. }
  310. if ((old_function = zend_hash_str_find_ptr(CG(function_table), "is_readable", sizeof("is_readable")-1)) != NULL) {
  311. orig_is_readable = old_function->internal_function.handler;
  312. old_function->internal_function.handler = accel_is_readable;
  313. }
  314. }
  315. }
  316. static ZEND_MSHUTDOWN_FUNCTION(zend_accelerator)
  317. {
  318. (void)type; /* keep the compiler happy */
  319. UNREGISTER_INI_ENTRIES();
  320. accel_shutdown();
  321. return SUCCESS;
  322. }
  323. void zend_accel_info(ZEND_MODULE_INFO_FUNC_ARGS)
  324. {
  325. php_info_print_table_start();
  326. if (ZCG(accelerator_enabled) || file_cache_only) {
  327. php_info_print_table_row(2, "Opcode Caching", "Up and Running");
  328. } else {
  329. php_info_print_table_row(2, "Opcode Caching", "Disabled");
  330. }
  331. if (ZCG(enabled) && accel_startup_ok && ZCG(accel_directives).optimization_level) {
  332. php_info_print_table_row(2, "Optimization", "Enabled");
  333. } else {
  334. php_info_print_table_row(2, "Optimization", "Disabled");
  335. }
  336. if (!file_cache_only) {
  337. php_info_print_table_row(2, "SHM Cache", "Enabled");
  338. } else {
  339. php_info_print_table_row(2, "SHM Cache", "Disabled");
  340. }
  341. if (ZCG(accel_directives).file_cache) {
  342. php_info_print_table_row(2, "File Cache", "Enabled");
  343. } else {
  344. php_info_print_table_row(2, "File Cache", "Disabled");
  345. }
  346. #if HAVE_JIT
  347. if (ZCG(jit_enabled)) {
  348. php_info_print_table_row(2, "JIT", "Enabled");
  349. } else {
  350. php_info_print_table_row(2, "JIT", "Disabled");
  351. }
  352. #else
  353. php_info_print_table_row(2, "JIT", "Not Available");
  354. #endif
  355. if (file_cache_only) {
  356. if (!accel_startup_ok || zps_api_failure_reason) {
  357. php_info_print_table_row(2, "Startup Failed", zps_api_failure_reason);
  358. } else {
  359. php_info_print_table_row(2, "Startup", "OK");
  360. }
  361. } else
  362. if (ZCG(enabled)) {
  363. if (!accel_startup_ok || zps_api_failure_reason) {
  364. php_info_print_table_row(2, "Startup Failed", zps_api_failure_reason);
  365. } else {
  366. char buf[32];
  367. php_info_print_table_row(2, "Startup", "OK");
  368. php_info_print_table_row(2, "Shared memory model", zend_accel_get_shared_model());
  369. snprintf(buf, sizeof(buf), ZEND_ULONG_FMT, ZCSG(hits));
  370. php_info_print_table_row(2, "Cache hits", buf);
  371. snprintf(buf, sizeof(buf), ZEND_ULONG_FMT, ZSMMG(memory_exhausted)?ZCSG(misses):ZCSG(misses)-ZCSG(blacklist_misses));
  372. php_info_print_table_row(2, "Cache misses", buf);
  373. snprintf(buf, sizeof(buf), ZEND_LONG_FMT, ZCG(accel_directives).memory_consumption-zend_shared_alloc_get_free_memory()-ZSMMG(wasted_shared_memory));
  374. php_info_print_table_row(2, "Used memory", buf);
  375. snprintf(buf, sizeof(buf), "%zu", zend_shared_alloc_get_free_memory());
  376. php_info_print_table_row(2, "Free memory", buf);
  377. snprintf(buf, sizeof(buf), "%zu", ZSMMG(wasted_shared_memory));
  378. php_info_print_table_row(2, "Wasted memory", buf);
  379. if (ZCSG(interned_strings).start && ZCSG(interned_strings).end) {
  380. snprintf(buf, sizeof(buf), "%zu", (size_t)((char*)ZCSG(interned_strings).top - (char*)ZCSG(interned_strings).start));
  381. php_info_print_table_row(2, "Interned Strings Used memory", buf);
  382. snprintf(buf, sizeof(buf), "%zu", (size_t)((char*)ZCSG(interned_strings).end - (char*)ZCSG(interned_strings).top));
  383. php_info_print_table_row(2, "Interned Strings Free memory", buf);
  384. }
  385. snprintf(buf, sizeof(buf), "%" PRIu32, ZCSG(hash).num_direct_entries);
  386. php_info_print_table_row(2, "Cached scripts", buf);
  387. snprintf(buf, sizeof(buf), "%" PRIu32, ZCSG(hash).num_entries);
  388. php_info_print_table_row(2, "Cached keys", buf);
  389. snprintf(buf, sizeof(buf), "%" PRIu32, ZCSG(hash).max_num_entries);
  390. php_info_print_table_row(2, "Max keys", buf);
  391. snprintf(buf, sizeof(buf), ZEND_ULONG_FMT, ZCSG(oom_restarts));
  392. php_info_print_table_row(2, "OOM restarts", buf);
  393. snprintf(buf, sizeof(buf), ZEND_ULONG_FMT, ZCSG(hash_restarts));
  394. php_info_print_table_row(2, "Hash keys restarts", buf);
  395. snprintf(buf, sizeof(buf), ZEND_ULONG_FMT, ZCSG(manual_restarts));
  396. php_info_print_table_row(2, "Manual restarts", buf);
  397. }
  398. }
  399. php_info_print_table_end();
  400. DISPLAY_INI_ENTRIES();
  401. }
  402. static zend_module_entry accel_module_entry = {
  403. STANDARD_MODULE_HEADER,
  404. ACCELERATOR_PRODUCT_NAME,
  405. ext_functions,
  406. ZEND_MINIT(zend_accelerator),
  407. ZEND_MSHUTDOWN(zend_accelerator),
  408. accel_activate,
  409. NULL,
  410. zend_accel_info,
  411. PHP_VERSION,
  412. NO_MODULE_GLOBALS,
  413. accel_post_deactivate,
  414. STANDARD_MODULE_PROPERTIES_EX
  415. };
  416. int start_accel_module(void)
  417. {
  418. return zend_startup_module(&accel_module_entry);
  419. }
  420. /* {{{ proto array accelerator_get_scripts()
  421. Get the scripts which are accelerated by ZendAccelerator */
  422. static int accelerator_get_scripts(zval *return_value)
  423. {
  424. uint32_t i;
  425. zval persistent_script_report;
  426. zend_accel_hash_entry *cache_entry;
  427. struct tm *ta;
  428. struct timeval exec_time;
  429. struct timeval fetch_time;
  430. if (!ZCG(accelerator_enabled) || accelerator_shm_read_lock() != SUCCESS) {
  431. return 0;
  432. }
  433. array_init(return_value);
  434. for (i = 0; i<ZCSG(hash).max_num_entries; i++) {
  435. for (cache_entry = ZCSG(hash).hash_table[i]; cache_entry; cache_entry = cache_entry->next) {
  436. zend_persistent_script *script;
  437. char *str;
  438. size_t len;
  439. if (cache_entry->indirect) continue;
  440. script = (zend_persistent_script *)cache_entry->data;
  441. array_init(&persistent_script_report);
  442. add_assoc_str(&persistent_script_report, "full_path", zend_string_dup(script->script.filename, 0));
  443. add_assoc_long(&persistent_script_report, "hits", (zend_long)script->dynamic_members.hits);
  444. add_assoc_long(&persistent_script_report, "memory_consumption", script->dynamic_members.memory_consumption);
  445. ta = localtime(&script->dynamic_members.last_used);
  446. str = asctime(ta);
  447. len = strlen(str);
  448. if (len > 0 && str[len - 1] == '\n') len--;
  449. add_assoc_stringl(&persistent_script_report, "last_used", str, len);
  450. add_assoc_long(&persistent_script_report, "last_used_timestamp", script->dynamic_members.last_used);
  451. if (ZCG(accel_directives).validate_timestamps) {
  452. add_assoc_long(&persistent_script_report, "timestamp", (zend_long)script->timestamp);
  453. }
  454. timerclear(&exec_time);
  455. timerclear(&fetch_time);
  456. zend_hash_str_update(Z_ARRVAL_P(return_value), cache_entry->key, cache_entry->key_length, &persistent_script_report);
  457. }
  458. }
  459. accelerator_shm_read_unlock();
  460. return 1;
  461. }
  462. /* {{{ proto array accelerator_get_status([bool fetch_scripts])
  463. Obtain statistics information regarding code acceleration */
  464. ZEND_FUNCTION(opcache_get_status)
  465. {
  466. zend_long reqs;
  467. zval memory_usage, statistics, scripts;
  468. zend_bool fetch_scripts = 1;
  469. if (zend_parse_parameters(ZEND_NUM_ARGS(), "|b", &fetch_scripts) == FAILURE) {
  470. RETURN_THROWS();
  471. }
  472. if (!validate_api_restriction()) {
  473. RETURN_FALSE;
  474. }
  475. if (!accel_startup_ok) {
  476. RETURN_FALSE;
  477. }
  478. array_init(return_value);
  479. /* Trivia */
  480. add_assoc_bool(return_value, "opcache_enabled", ZCG(accelerator_enabled));
  481. if (ZCG(accel_directives).file_cache) {
  482. add_assoc_string(return_value, "file_cache", ZCG(accel_directives).file_cache);
  483. }
  484. if (file_cache_only) {
  485. add_assoc_bool(return_value, "file_cache_only", 1);
  486. return;
  487. }
  488. add_assoc_bool(return_value, "cache_full", ZSMMG(memory_exhausted));
  489. add_assoc_bool(return_value, "restart_pending", ZCSG(restart_pending));
  490. add_assoc_bool(return_value, "restart_in_progress", ZCSG(restart_in_progress));
  491. /* Memory usage statistics */
  492. array_init(&memory_usage);
  493. add_assoc_long(&memory_usage, "used_memory", ZCG(accel_directives).memory_consumption-zend_shared_alloc_get_free_memory()-ZSMMG(wasted_shared_memory));
  494. add_assoc_long(&memory_usage, "free_memory", zend_shared_alloc_get_free_memory());
  495. add_assoc_long(&memory_usage, "wasted_memory", ZSMMG(wasted_shared_memory));
  496. add_assoc_double(&memory_usage, "current_wasted_percentage", (((double) ZSMMG(wasted_shared_memory))/ZCG(accel_directives).memory_consumption)*100.0);
  497. add_assoc_zval(return_value, "memory_usage", &memory_usage);
  498. if (ZCSG(interned_strings).start && ZCSG(interned_strings).end) {
  499. zval interned_strings_usage;
  500. array_init(&interned_strings_usage);
  501. add_assoc_long(&interned_strings_usage, "buffer_size", (char*)ZCSG(interned_strings).end - (char*)ZCSG(interned_strings).start);
  502. add_assoc_long(&interned_strings_usage, "used_memory", (char*)ZCSG(interned_strings).top - (char*)ZCSG(interned_strings).start);
  503. add_assoc_long(&interned_strings_usage, "free_memory", (char*)ZCSG(interned_strings).end - (char*)ZCSG(interned_strings).top);
  504. add_assoc_long(&interned_strings_usage, "number_of_strings", ZCSG(interned_strings).nNumOfElements);
  505. add_assoc_zval(return_value, "interned_strings_usage", &interned_strings_usage);
  506. }
  507. /* Accelerator statistics */
  508. array_init(&statistics);
  509. add_assoc_long(&statistics, "num_cached_scripts", ZCSG(hash).num_direct_entries);
  510. add_assoc_long(&statistics, "num_cached_keys", ZCSG(hash).num_entries);
  511. add_assoc_long(&statistics, "max_cached_keys", ZCSG(hash).max_num_entries);
  512. add_assoc_long(&statistics, "hits", (zend_long)ZCSG(hits));
  513. add_assoc_long(&statistics, "start_time", ZCSG(start_time));
  514. add_assoc_long(&statistics, "last_restart_time", ZCSG(last_restart_time));
  515. add_assoc_long(&statistics, "oom_restarts", ZCSG(oom_restarts));
  516. add_assoc_long(&statistics, "hash_restarts", ZCSG(hash_restarts));
  517. add_assoc_long(&statistics, "manual_restarts", ZCSG(manual_restarts));
  518. add_assoc_long(&statistics, "misses", ZSMMG(memory_exhausted)?ZCSG(misses):ZCSG(misses)-ZCSG(blacklist_misses));
  519. add_assoc_long(&statistics, "blacklist_misses", ZCSG(blacklist_misses));
  520. reqs = ZCSG(hits)+ZCSG(misses);
  521. add_assoc_double(&statistics, "blacklist_miss_ratio", reqs?(((double) ZCSG(blacklist_misses))/reqs)*100.0:0);
  522. add_assoc_double(&statistics, "opcache_hit_rate", reqs?(((double) ZCSG(hits))/reqs)*100.0:0);
  523. add_assoc_zval(return_value, "opcache_statistics", &statistics);
  524. if (ZCSG(preload_script)) {
  525. array_init(&statistics);
  526. add_assoc_long(&statistics, "memory_consumption", ZCSG(preload_script)->dynamic_members.memory_consumption);
  527. if (zend_hash_num_elements(&ZCSG(preload_script)->script.function_table)) {
  528. zend_op_array *op_array;
  529. array_init(&scripts);
  530. ZEND_HASH_FOREACH_PTR(&ZCSG(preload_script)->script.function_table, op_array) {
  531. add_next_index_str(&scripts, op_array->function_name);
  532. } ZEND_HASH_FOREACH_END();
  533. add_assoc_zval(&statistics, "functions", &scripts);
  534. }
  535. if (zend_hash_num_elements(&ZCSG(preload_script)->script.class_table)) {
  536. zend_class_entry *ce;
  537. zend_string *key;
  538. array_init(&scripts);
  539. ZEND_HASH_FOREACH_STR_KEY_PTR(&ZCSG(preload_script)->script.class_table, key, ce) {
  540. if (ce->refcount > 1 && !zend_string_equals_ci(key, ce->name)) {
  541. add_next_index_str(&scripts, key);
  542. } else {
  543. add_next_index_str(&scripts, ce->name);
  544. }
  545. } ZEND_HASH_FOREACH_END();
  546. add_assoc_zval(&statistics, "classes", &scripts);
  547. }
  548. if (ZCSG(saved_scripts)) {
  549. zend_persistent_script **p = ZCSG(saved_scripts);
  550. array_init(&scripts);
  551. while (*p) {
  552. add_next_index_str(&scripts, (*p)->script.filename);
  553. p++;
  554. }
  555. add_assoc_zval(&statistics, "scripts", &scripts);
  556. }
  557. add_assoc_zval(return_value, "preload_statistics", &statistics);
  558. }
  559. if (fetch_scripts) {
  560. /* accelerated scripts */
  561. if (accelerator_get_scripts(&scripts)) {
  562. add_assoc_zval(return_value, "scripts", &scripts);
  563. }
  564. }
  565. #if HAVE_JIT
  566. zend_jit_status(return_value);
  567. #endif
  568. }
  569. static int add_blacklist_path(zend_blacklist_entry *p, zval *return_value)
  570. {
  571. add_next_index_stringl(return_value, p->path, p->path_length);
  572. return 0;
  573. }
  574. /* {{{ proto array accelerator_get_configuration()
  575. Obtain configuration information */
  576. ZEND_FUNCTION(opcache_get_configuration)
  577. {
  578. zval directives, version, blacklist;
  579. if (zend_parse_parameters_none() == FAILURE) {
  580. RETURN_THROWS();
  581. }
  582. if (!validate_api_restriction()) {
  583. RETURN_FALSE;
  584. }
  585. array_init(return_value);
  586. /* directives */
  587. array_init(&directives);
  588. add_assoc_bool(&directives, "opcache.enable", ZCG(enabled));
  589. add_assoc_bool(&directives, "opcache.enable_cli", ZCG(accel_directives).enable_cli);
  590. add_assoc_bool(&directives, "opcache.use_cwd", ZCG(accel_directives).use_cwd);
  591. add_assoc_bool(&directives, "opcache.validate_timestamps", ZCG(accel_directives).validate_timestamps);
  592. add_assoc_bool(&directives, "opcache.validate_permission", ZCG(accel_directives).validate_permission);
  593. #ifndef ZEND_WIN32
  594. add_assoc_bool(&directives, "opcache.validate_root", ZCG(accel_directives).validate_root);
  595. #endif
  596. add_assoc_bool(&directives, "opcache.dups_fix", ZCG(accel_directives).ignore_dups);
  597. add_assoc_bool(&directives, "opcache.revalidate_path", ZCG(accel_directives).revalidate_path);
  598. add_assoc_long(&directives, "opcache.log_verbosity_level", ZCG(accel_directives).log_verbosity_level);
  599. add_assoc_long(&directives, "opcache.memory_consumption", ZCG(accel_directives).memory_consumption);
  600. add_assoc_long(&directives, "opcache.interned_strings_buffer",ZCG(accel_directives).interned_strings_buffer);
  601. add_assoc_long(&directives, "opcache.max_accelerated_files", ZCG(accel_directives).max_accelerated_files);
  602. add_assoc_double(&directives, "opcache.max_wasted_percentage", ZCG(accel_directives).max_wasted_percentage);
  603. add_assoc_long(&directives, "opcache.consistency_checks", ZCG(accel_directives).consistency_checks);
  604. add_assoc_long(&directives, "opcache.force_restart_timeout", ZCG(accel_directives).force_restart_timeout);
  605. add_assoc_long(&directives, "opcache.revalidate_freq", ZCG(accel_directives).revalidate_freq);
  606. add_assoc_string(&directives, "opcache.preferred_memory_model", STRING_NOT_NULL(ZCG(accel_directives).memory_model));
  607. add_assoc_string(&directives, "opcache.blacklist_filename", STRING_NOT_NULL(ZCG(accel_directives).user_blacklist_filename));
  608. add_assoc_long(&directives, "opcache.max_file_size", ZCG(accel_directives).max_file_size);
  609. add_assoc_string(&directives, "opcache.error_log", STRING_NOT_NULL(ZCG(accel_directives).error_log));
  610. add_assoc_bool(&directives, "opcache.protect_memory", ZCG(accel_directives).protect_memory);
  611. add_assoc_bool(&directives, "opcache.save_comments", ZCG(accel_directives).save_comments);
  612. add_assoc_bool(&directives, "opcache.enable_file_override", ZCG(accel_directives).file_override_enabled);
  613. add_assoc_long(&directives, "opcache.optimization_level", ZCG(accel_directives).optimization_level);
  614. #ifndef ZEND_WIN32
  615. add_assoc_string(&directives, "opcache.lockfile_path", STRING_NOT_NULL(ZCG(accel_directives).lockfile_path));
  616. #else
  617. add_assoc_string(&directives, "opcache.mmap_base", STRING_NOT_NULL(ZCG(accel_directives).mmap_base));
  618. #endif
  619. add_assoc_string(&directives, "opcache.file_cache", ZCG(accel_directives).file_cache ? ZCG(accel_directives).file_cache : "");
  620. add_assoc_bool(&directives, "opcache.file_cache_only", ZCG(accel_directives).file_cache_only);
  621. add_assoc_bool(&directives, "opcache.file_cache_consistency_checks", ZCG(accel_directives).file_cache_consistency_checks);
  622. #if ENABLE_FILE_CACHE_FALLBACK
  623. add_assoc_bool(&directives, "opcache.file_cache_fallback", ZCG(accel_directives).file_cache_fallback);
  624. #endif
  625. add_assoc_long(&directives, "opcache.file_update_protection", ZCG(accel_directives).file_update_protection);
  626. add_assoc_long(&directives, "opcache.opt_debug_level", ZCG(accel_directives).opt_debug_level);
  627. add_assoc_string(&directives, "opcache.restrict_api", STRING_NOT_NULL(ZCG(accel_directives).restrict_api));
  628. #ifdef HAVE_HUGE_CODE_PAGES
  629. add_assoc_bool(&directives, "opcache.huge_code_pages", ZCG(accel_directives).huge_code_pages);
  630. #endif
  631. add_assoc_string(&directives, "opcache.preload", STRING_NOT_NULL(ZCG(accel_directives).preload));
  632. #ifndef ZEND_WIN32
  633. add_assoc_string(&directives, "opcache.preload_user", STRING_NOT_NULL(ZCG(accel_directives).preload_user));
  634. #endif
  635. #if ZEND_WIN32
  636. add_assoc_string(&directives, "opcache.cache_id", STRING_NOT_NULL(ZCG(accel_directives).cache_id));
  637. #endif
  638. #ifdef HAVE_JIT
  639. add_assoc_long(&directives, "opcache.jit", ZCG(accel_directives).jit);
  640. add_assoc_long(&directives, "opcache.jit_buffer_size", ZCG(accel_directives).jit_buffer_size);
  641. add_assoc_long(&directives, "opcache.jit_debug", ZCG(accel_directives).jit_debug);
  642. add_assoc_long(&directives, "opcache.jit_bisect_limit", ZCG(accel_directives).jit_bisect_limit);
  643. #endif
  644. add_assoc_zval(return_value, "directives", &directives);
  645. /*version */
  646. array_init(&version);
  647. add_assoc_string(&version, "version", PHP_VERSION);
  648. add_assoc_string(&version, "opcache_product_name", ACCELERATOR_PRODUCT_NAME);
  649. add_assoc_zval(return_value, "version", &version);
  650. /* blacklist */
  651. array_init(&blacklist);
  652. zend_accel_blacklist_apply(&accel_blacklist, add_blacklist_path, &blacklist);
  653. add_assoc_zval(return_value, "blacklist", &blacklist);
  654. }
  655. /* {{{ proto void accelerator_reset()
  656. Request that the contents of the opcode cache to be reset */
  657. ZEND_FUNCTION(opcache_reset)
  658. {
  659. if (zend_parse_parameters_none() == FAILURE) {
  660. RETURN_THROWS();
  661. }
  662. if (!validate_api_restriction()) {
  663. RETURN_FALSE;
  664. }
  665. if ((!ZCG(enabled) || !accel_startup_ok || !ZCSG(accelerator_enabled))
  666. #if ENABLE_FILE_CACHE_FALLBACK
  667. && !fallback_process
  668. #endif
  669. ) {
  670. RETURN_FALSE;
  671. }
  672. /* exclusive lock */
  673. zend_shared_alloc_lock();
  674. zend_accel_schedule_restart(ACCEL_RESTART_USER);
  675. zend_shared_alloc_unlock();
  676. RETURN_TRUE;
  677. }
  678. /* {{{ proto void opcache_invalidate(string $script [, bool $force = false])
  679. Invalidates cached script (in necessary or forced) */
  680. ZEND_FUNCTION(opcache_invalidate)
  681. {
  682. char *script_name;
  683. size_t script_name_len;
  684. zend_bool force = 0;
  685. if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|b", &script_name, &script_name_len, &force) == FAILURE) {
  686. RETURN_THROWS();
  687. }
  688. if (!validate_api_restriction()) {
  689. RETURN_FALSE;
  690. }
  691. if (zend_accel_invalidate(script_name, script_name_len, force) == SUCCESS) {
  692. RETURN_TRUE;
  693. } else {
  694. RETURN_FALSE;
  695. }
  696. }
  697. ZEND_FUNCTION(opcache_compile_file)
  698. {
  699. char *script_name;
  700. size_t script_name_len;
  701. zend_file_handle handle;
  702. zend_op_array *op_array = NULL;
  703. zend_execute_data *orig_execute_data = NULL;
  704. uint32_t orig_compiler_options;
  705. if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &script_name, &script_name_len) == FAILURE) {
  706. RETURN_THROWS();
  707. }
  708. if (!accel_startup_ok) {
  709. zend_error(E_NOTICE, ACCELERATOR_PRODUCT_NAME " has not been properly started, can't compile file");
  710. RETURN_FALSE;
  711. }
  712. zend_stream_init_filename(&handle, script_name);
  713. orig_execute_data = EG(current_execute_data);
  714. orig_compiler_options = CG(compiler_options);
  715. CG(compiler_options) |= ZEND_COMPILE_WITHOUT_EXECUTION;
  716. if (CG(compiler_options) & ZEND_COMPILE_PRELOAD) {
  717. /* During preloading, a failure in opcache_compile_file() should result in an overall
  718. * preloading failure. Otherwise we may include partially compiled files in the preload
  719. * state. */
  720. op_array = persistent_compile_file(&handle, ZEND_INCLUDE);
  721. } else {
  722. zend_try {
  723. op_array = persistent_compile_file(&handle, ZEND_INCLUDE);
  724. } zend_catch {
  725. EG(current_execute_data) = orig_execute_data;
  726. zend_error(E_WARNING, ACCELERATOR_PRODUCT_NAME " could not compile file %s", handle.filename);
  727. } zend_end_try();
  728. }
  729. CG(compiler_options) = orig_compiler_options;
  730. if(op_array != NULL) {
  731. destroy_op_array(op_array);
  732. efree(op_array);
  733. RETVAL_TRUE;
  734. } else {
  735. RETVAL_FALSE;
  736. }
  737. zend_destroy_file_handle(&handle);
  738. }
  739. /* {{{ proto bool opcache_is_script_cached(string $script)
  740. Return true if the script is cached in OPCache, false if it is not cached or if OPCache is not running. */
  741. ZEND_FUNCTION(opcache_is_script_cached)
  742. {
  743. zend_string *script_name;
  744. if (!validate_api_restriction()) {
  745. RETURN_FALSE;
  746. }
  747. if (!ZCG(accelerator_enabled)) {
  748. RETURN_FALSE;
  749. }
  750. if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &script_name) == FAILURE) {
  751. RETURN_THROWS();
  752. }
  753. RETURN_BOOL(filename_is_in_cache(script_name));
  754. }