php_ini.c 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978
  1. /*
  2. +----------------------------------------------------------------------+
  3. | PHP Version 7 |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 1997-2018 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. | Author: Zeev Suraski <zeev@php.net> |
  16. +----------------------------------------------------------------------+
  17. */
  18. #include "php.h"
  19. #include "ext/standard/info.h"
  20. #include "zend_ini.h"
  21. #include "zend_ini_scanner.h"
  22. #include "php_ini.h"
  23. #include "ext/standard/dl.h"
  24. #include "zend_extensions.h"
  25. #include "zend_highlight.h"
  26. #include "SAPI.h"
  27. #include "php_main.h"
  28. #include "php_scandir.h"
  29. #ifdef PHP_WIN32
  30. #include "win32/php_registry.h"
  31. #endif
  32. #if HAVE_SCANDIR && HAVE_ALPHASORT && HAVE_DIRENT_H
  33. #include <dirent.h>
  34. #endif
  35. #ifdef PHP_WIN32
  36. #define TRANSLATE_SLASHES_LOWER(path) \
  37. { \
  38. char *tmp = path; \
  39. while (*tmp) { \
  40. if (*tmp == '\\') *tmp = '/'; \
  41. else *tmp = tolower(*tmp); \
  42. tmp++; \
  43. } \
  44. }
  45. #else
  46. #define TRANSLATE_SLASHES_LOWER(path)
  47. #endif
  48. typedef struct _php_extension_lists {
  49. zend_llist engine;
  50. zend_llist functions;
  51. } php_extension_lists;
  52. /* True globals */
  53. static int is_special_section = 0;
  54. static HashTable *active_ini_hash;
  55. static HashTable configuration_hash;
  56. static int has_per_dir_config = 0;
  57. static int has_per_host_config = 0;
  58. PHPAPI char *php_ini_opened_path=NULL;
  59. static php_extension_lists extension_lists;
  60. PHPAPI char *php_ini_scanned_path=NULL;
  61. PHPAPI char *php_ini_scanned_files=NULL;
  62. /* {{{ php_ini_displayer_cb
  63. */
  64. static void php_ini_displayer_cb(zend_ini_entry *ini_entry, int type)
  65. {
  66. if (ini_entry->displayer) {
  67. ini_entry->displayer(ini_entry, type);
  68. } else {
  69. char *display_string;
  70. size_t display_string_length;
  71. int esc_html=0;
  72. if (type == ZEND_INI_DISPLAY_ORIG && ini_entry->modified) {
  73. if (ini_entry->orig_value && ZSTR_VAL(ini_entry->orig_value)[0]) {
  74. display_string = ZSTR_VAL(ini_entry->orig_value);
  75. display_string_length = ZSTR_LEN(ini_entry->orig_value);
  76. esc_html = !sapi_module.phpinfo_as_text;
  77. } else {
  78. if (!sapi_module.phpinfo_as_text) {
  79. display_string = "<i>no value</i>";
  80. display_string_length = sizeof("<i>no value</i>") - 1;
  81. } else {
  82. display_string = "no value";
  83. display_string_length = sizeof("no value") - 1;
  84. }
  85. }
  86. } else if (ini_entry->value && ZSTR_VAL(ini_entry->value)[0]) {
  87. display_string = ZSTR_VAL(ini_entry->value);
  88. display_string_length = ZSTR_LEN(ini_entry->value);
  89. esc_html = !sapi_module.phpinfo_as_text;
  90. } else {
  91. if (!sapi_module.phpinfo_as_text) {
  92. display_string = "<i>no value</i>";
  93. display_string_length = sizeof("<i>no value</i>") - 1;
  94. } else {
  95. display_string = "no value";
  96. display_string_length = sizeof("no value") - 1;
  97. }
  98. }
  99. if (esc_html) {
  100. php_html_puts(display_string, display_string_length);
  101. } else {
  102. PHPWRITE(display_string, display_string_length);
  103. }
  104. }
  105. }
  106. /* }}} */
  107. /* {{{ php_ini_displayer
  108. */
  109. static int php_ini_displayer(zval *el, void *arg)
  110. {
  111. zend_ini_entry *ini_entry = (zend_ini_entry*)Z_PTR_P(el);
  112. int module_number = *(int *)arg;
  113. if (ini_entry->module_number != module_number) {
  114. return 0;
  115. }
  116. if (!sapi_module.phpinfo_as_text) {
  117. PUTS("<tr>");
  118. PUTS("<td class=\"e\">");
  119. PHPWRITE(ZSTR_VAL(ini_entry->name), ZSTR_LEN(ini_entry->name));
  120. PUTS("</td><td class=\"v\">");
  121. php_ini_displayer_cb(ini_entry, ZEND_INI_DISPLAY_ACTIVE);
  122. PUTS("</td><td class=\"v\">");
  123. php_ini_displayer_cb(ini_entry, ZEND_INI_DISPLAY_ORIG);
  124. PUTS("</td></tr>\n");
  125. } else {
  126. PHPWRITE(ZSTR_VAL(ini_entry->name), ZSTR_LEN(ini_entry->name));
  127. PUTS(" => ");
  128. php_ini_displayer_cb(ini_entry, ZEND_INI_DISPLAY_ACTIVE);
  129. PUTS(" => ");
  130. php_ini_displayer_cb(ini_entry, ZEND_INI_DISPLAY_ORIG);
  131. PUTS("\n");
  132. }
  133. return 0;
  134. }
  135. /* }}} */
  136. /* {{{ php_ini_available
  137. */
  138. static int php_ini_available(zval *el, void *arg)
  139. {
  140. zend_ini_entry *ini_entry = (zend_ini_entry *)Z_PTR_P(el);
  141. int *module_number_available = (int *)arg;
  142. if (ini_entry->module_number == *(int *)module_number_available) {
  143. *(int *)module_number_available = -1;
  144. return ZEND_HASH_APPLY_STOP;
  145. } else {
  146. return ZEND_HASH_APPLY_KEEP;
  147. }
  148. }
  149. /* }}} */
  150. /* {{{ display_ini_entries
  151. */
  152. PHPAPI void display_ini_entries(zend_module_entry *module)
  153. {
  154. int module_number, module_number_available;
  155. if (module) {
  156. module_number = module->module_number;
  157. } else {
  158. module_number = 0;
  159. }
  160. module_number_available = module_number;
  161. zend_hash_apply_with_argument(EG(ini_directives), php_ini_available, &module_number_available);
  162. if (module_number_available == -1) {
  163. php_info_print_table_start();
  164. php_info_print_table_header(3, "Directive", "Local Value", "Master Value");
  165. zend_hash_apply_with_argument(EG(ini_directives), php_ini_displayer, (void *)&module_number);
  166. php_info_print_table_end();
  167. }
  168. }
  169. /* }}} */
  170. /* php.ini support */
  171. #define PHP_EXTENSION_TOKEN "extension"
  172. #define ZEND_EXTENSION_TOKEN "zend_extension"
  173. /* {{{ config_zval_dtor
  174. */
  175. PHPAPI void config_zval_dtor(zval *zvalue)
  176. {
  177. if (Z_TYPE_P(zvalue) == IS_ARRAY) {
  178. zend_hash_destroy(Z_ARRVAL_P(zvalue));
  179. free(Z_ARR_P(zvalue));
  180. } else if (Z_TYPE_P(zvalue) == IS_STRING) {
  181. zend_string_release_ex(Z_STR_P(zvalue), 1);
  182. }
  183. }
  184. /* Reset / free active_ini_sectin global */
  185. #define RESET_ACTIVE_INI_HASH() do { \
  186. active_ini_hash = NULL; \
  187. is_special_section = 0; \
  188. } while (0)
  189. /* }}} */
  190. /* {{{ php_ini_parser_cb
  191. */
  192. static void php_ini_parser_cb(zval *arg1, zval *arg2, zval *arg3, int callback_type, HashTable *target_hash)
  193. {
  194. zval *entry;
  195. HashTable *active_hash;
  196. char *extension_name;
  197. if (active_ini_hash) {
  198. active_hash = active_ini_hash;
  199. } else {
  200. active_hash = target_hash;
  201. }
  202. switch (callback_type) {
  203. case ZEND_INI_PARSER_ENTRY: {
  204. if (!arg2) {
  205. /* bare string - nothing to do */
  206. break;
  207. }
  208. /* PHP and Zend extensions are not added into configuration hash! */
  209. if (!is_special_section && !strcasecmp(Z_STRVAL_P(arg1), PHP_EXTENSION_TOKEN)) { /* load PHP extension */
  210. extension_name = estrndup(Z_STRVAL_P(arg2), Z_STRLEN_P(arg2));
  211. zend_llist_add_element(&extension_lists.functions, &extension_name);
  212. } else if (!is_special_section && !strcasecmp(Z_STRVAL_P(arg1), ZEND_EXTENSION_TOKEN)) { /* load Zend extension */
  213. extension_name = estrndup(Z_STRVAL_P(arg2), Z_STRLEN_P(arg2));
  214. zend_llist_add_element(&extension_lists.engine, &extension_name);
  215. /* All other entries are added into either configuration_hash or active ini section array */
  216. } else {
  217. /* Store in active hash */
  218. entry = zend_hash_update(active_hash, Z_STR_P(arg1), arg2);
  219. Z_STR_P(entry) = zend_string_dup(Z_STR_P(entry), 1);
  220. }
  221. }
  222. break;
  223. case ZEND_INI_PARSER_POP_ENTRY: {
  224. zval option_arr;
  225. zval *find_arr;
  226. if (!arg2) {
  227. /* bare string - nothing to do */
  228. break;
  229. }
  230. /* fprintf(stdout, "ZEND_INI_PARSER_POP_ENTRY: %s[%s] = %s\n",Z_STRVAL_P(arg1), Z_STRVAL_P(arg3), Z_STRVAL_P(arg2)); */
  231. /* If option not found in hash or is not an array -> create array, otherwise add to existing array */
  232. if ((find_arr = zend_hash_find(active_hash, Z_STR_P(arg1))) == NULL || Z_TYPE_P(find_arr) != IS_ARRAY) {
  233. ZVAL_NEW_PERSISTENT_ARR(&option_arr);
  234. zend_hash_init(Z_ARRVAL(option_arr), 8, NULL, config_zval_dtor, 1);
  235. find_arr = zend_hash_update(active_hash, Z_STR_P(arg1), &option_arr);
  236. }
  237. /* arg3 is possible option offset name */
  238. if (arg3 && Z_STRLEN_P(arg3) > 0) {
  239. entry = zend_symtable_update(Z_ARRVAL_P(find_arr), Z_STR_P(arg3), arg2);
  240. } else {
  241. entry = zend_hash_next_index_insert(Z_ARRVAL_P(find_arr), arg2);
  242. }
  243. Z_STR_P(entry) = zend_string_dup(Z_STR_P(entry), 1);
  244. }
  245. break;
  246. case ZEND_INI_PARSER_SECTION: { /* Create an array of entries of each section */
  247. /* fprintf(stdout, "ZEND_INI_PARSER_SECTION: %s\n",Z_STRVAL_P(arg1)); */
  248. char *key = NULL;
  249. size_t key_len;
  250. /* PATH sections */
  251. if (!zend_binary_strncasecmp(Z_STRVAL_P(arg1), Z_STRLEN_P(arg1), "PATH", sizeof("PATH") - 1, sizeof("PATH") - 1)) {
  252. key = Z_STRVAL_P(arg1);
  253. key = key + sizeof("PATH") - 1;
  254. key_len = Z_STRLEN_P(arg1) - sizeof("PATH") + 1;
  255. is_special_section = 1;
  256. has_per_dir_config = 1;
  257. /* make the path lowercase on Windows, for case insensitivity. Does nothing for other platforms */
  258. TRANSLATE_SLASHES_LOWER(key);
  259. /* HOST sections */
  260. } else if (!zend_binary_strncasecmp(Z_STRVAL_P(arg1), Z_STRLEN_P(arg1), "HOST", sizeof("HOST") - 1, sizeof("HOST") - 1)) {
  261. key = Z_STRVAL_P(arg1);
  262. key = key + sizeof("HOST") - 1;
  263. key_len = Z_STRLEN_P(arg1) - sizeof("HOST") + 1;
  264. is_special_section = 1;
  265. has_per_host_config = 1;
  266. zend_str_tolower(key, key_len); /* host names are case-insensitive. */
  267. } else {
  268. is_special_section = 0;
  269. }
  270. if (key && key_len > 0) {
  271. /* Strip any trailing slashes */
  272. while (key_len > 0 && (key[key_len - 1] == '/' || key[key_len - 1] == '\\')) {
  273. key_len--;
  274. key[key_len] = 0;
  275. }
  276. /* Strip any leading whitespace and '=' */
  277. while (*key && (
  278. *key == '=' ||
  279. *key == ' ' ||
  280. *key == '\t'
  281. )) {
  282. key++;
  283. key_len--;
  284. }
  285. /* Search for existing entry and if it does not exist create one */
  286. if ((entry = zend_hash_str_find(target_hash, key, key_len)) == NULL) {
  287. zval section_arr;
  288. ZVAL_NEW_PERSISTENT_ARR(&section_arr);
  289. zend_hash_init(Z_ARRVAL(section_arr), 8, NULL, (dtor_func_t) config_zval_dtor, 1);
  290. entry = zend_hash_str_update(target_hash, key, key_len, &section_arr);
  291. }
  292. if (Z_TYPE_P(entry) == IS_ARRAY) {
  293. active_ini_hash = Z_ARRVAL_P(entry);
  294. }
  295. }
  296. }
  297. break;
  298. }
  299. }
  300. /* }}} */
  301. /* {{{ php_load_php_extension_cb
  302. */
  303. static void php_load_php_extension_cb(void *arg)
  304. {
  305. #ifdef HAVE_LIBDL
  306. php_load_extension(*((char **) arg), MODULE_PERSISTENT, 0);
  307. #endif
  308. }
  309. /* }}} */
  310. /* {{{ php_load_zend_extension_cb
  311. */
  312. #ifdef HAVE_LIBDL
  313. static void php_load_zend_extension_cb(void *arg)
  314. {
  315. char *filename = *((char **) arg);
  316. const size_t length = strlen(filename);
  317. #ifndef PHP_WIN32
  318. (void) length;
  319. #endif
  320. if (IS_ABSOLUTE_PATH(filename, length)) {
  321. zend_load_extension(filename);
  322. } else {
  323. DL_HANDLE handle;
  324. char *libpath;
  325. char *extension_dir = INI_STR("extension_dir");
  326. int slash_suffix = 0;
  327. char *err1, *err2;
  328. if (extension_dir && extension_dir[0]) {
  329. slash_suffix = IS_SLASH(extension_dir[strlen(extension_dir)-1]);
  330. }
  331. /* Try as filename first */
  332. if (slash_suffix) {
  333. spprintf(&libpath, 0, "%s%s", extension_dir, filename); /* SAFE */
  334. } else {
  335. spprintf(&libpath, 0, "%s%c%s", extension_dir, DEFAULT_SLASH, filename); /* SAFE */
  336. }
  337. handle = (DL_HANDLE)php_load_shlib(libpath, &err1);
  338. if (!handle) {
  339. /* If file does not exist, consider as extension name and build file name */
  340. char *orig_libpath = libpath;
  341. if (slash_suffix) {
  342. spprintf(&libpath, 0, "%s" PHP_SHLIB_EXT_PREFIX "%s." PHP_SHLIB_SUFFIX, extension_dir, filename); /* SAFE */
  343. } else {
  344. spprintf(&libpath, 0, "%s%c" PHP_SHLIB_EXT_PREFIX "%s." PHP_SHLIB_SUFFIX, extension_dir, DEFAULT_SLASH, filename); /* SAFE */
  345. }
  346. handle = (DL_HANDLE)php_load_shlib(libpath, &err2);
  347. if (!handle) {
  348. php_error(E_CORE_WARNING, "Failed loading Zend extension '%s' (tried: %s (%s), %s (%s))",
  349. filename, orig_libpath, err1, libpath, err2);
  350. efree(orig_libpath);
  351. efree(err1);
  352. efree(libpath);
  353. efree(err2);
  354. return;
  355. }
  356. efree(orig_libpath);
  357. efree(err1);
  358. }
  359. zend_load_extension_handle(handle, libpath);
  360. efree(libpath);
  361. }
  362. }
  363. #else
  364. static void php_load_zend_extension_cb(void *arg) { }
  365. #endif
  366. /* }}} */
  367. /* {{{ php_init_config
  368. */
  369. int php_init_config(void)
  370. {
  371. char *php_ini_file_name = NULL;
  372. char *php_ini_search_path = NULL;
  373. int php_ini_scanned_path_len;
  374. char *open_basedir;
  375. int free_ini_search_path = 0;
  376. zend_file_handle fh;
  377. zend_string *opened_path = NULL;
  378. zend_hash_init(&configuration_hash, 8, NULL, config_zval_dtor, 1);
  379. if (sapi_module.ini_defaults) {
  380. sapi_module.ini_defaults(&configuration_hash);
  381. }
  382. zend_llist_init(&extension_lists.engine, sizeof(char *), (llist_dtor_func_t) free_estring, 1);
  383. zend_llist_init(&extension_lists.functions, sizeof(char *), (llist_dtor_func_t) free_estring, 1);
  384. open_basedir = PG(open_basedir);
  385. if (sapi_module.php_ini_path_override) {
  386. php_ini_file_name = sapi_module.php_ini_path_override;
  387. php_ini_search_path = sapi_module.php_ini_path_override;
  388. free_ini_search_path = 0;
  389. } else if (!sapi_module.php_ini_ignore) {
  390. int search_path_size;
  391. char *default_location;
  392. char *env_location;
  393. static const char paths_separator[] = { ZEND_PATHS_SEPARATOR, 0 };
  394. #ifdef PHP_WIN32
  395. char *reg_location;
  396. char phprc_path[MAXPATHLEN];
  397. #endif
  398. env_location = getenv("PHPRC");
  399. #ifdef PHP_WIN32
  400. if (!env_location) {
  401. char dummybuf;
  402. int size;
  403. SetLastError(0);
  404. /*If the given buffer is not large enough to hold the data, the return value is
  405. the buffer size, in characters, required to hold the string and its terminating
  406. null character. We use this return value to alloc the final buffer. */
  407. size = GetEnvironmentVariableA("PHPRC", &dummybuf, 0);
  408. if (GetLastError() == ERROR_ENVVAR_NOT_FOUND) {
  409. /* The environment variable doesn't exist. */
  410. env_location = "";
  411. } else {
  412. if (size == 0) {
  413. env_location = "";
  414. } else {
  415. size = GetEnvironmentVariableA("PHPRC", phprc_path, size);
  416. if (size == 0) {
  417. env_location = "";
  418. } else {
  419. env_location = phprc_path;
  420. }
  421. }
  422. }
  423. }
  424. #else
  425. if (!env_location) {
  426. env_location = "";
  427. }
  428. #endif
  429. /*
  430. * Prepare search path
  431. */
  432. search_path_size = MAXPATHLEN * 4 + (int)strlen(env_location) + 3 + 1;
  433. php_ini_search_path = (char *) emalloc(search_path_size);
  434. free_ini_search_path = 1;
  435. php_ini_search_path[0] = 0;
  436. /* Add environment location */
  437. if (env_location[0]) {
  438. if (*php_ini_search_path) {
  439. strlcat(php_ini_search_path, paths_separator, search_path_size);
  440. }
  441. strlcat(php_ini_search_path, env_location, search_path_size);
  442. php_ini_file_name = env_location;
  443. }
  444. #ifdef PHP_WIN32
  445. /* Add registry location */
  446. reg_location = GetIniPathFromRegistry();
  447. if (reg_location != NULL) {
  448. if (*php_ini_search_path) {
  449. strlcat(php_ini_search_path, paths_separator, search_path_size);
  450. }
  451. strlcat(php_ini_search_path, reg_location, search_path_size);
  452. efree(reg_location);
  453. }
  454. #endif
  455. /* Add cwd (not with CLI) */
  456. if (!sapi_module.php_ini_ignore_cwd) {
  457. if (*php_ini_search_path) {
  458. strlcat(php_ini_search_path, paths_separator, search_path_size);
  459. }
  460. strlcat(php_ini_search_path, ".", search_path_size);
  461. }
  462. if (PG(php_binary)) {
  463. char *separator_location, *binary_location;
  464. binary_location = estrdup(PG(php_binary));
  465. separator_location = strrchr(binary_location, DEFAULT_SLASH);
  466. if (separator_location && separator_location != binary_location) {
  467. *(separator_location) = 0;
  468. }
  469. if (*php_ini_search_path) {
  470. strlcat(php_ini_search_path, paths_separator, search_path_size);
  471. }
  472. strlcat(php_ini_search_path, binary_location, search_path_size);
  473. efree(binary_location);
  474. }
  475. /* Add default location */
  476. #ifdef PHP_WIN32
  477. default_location = (char *) emalloc(MAXPATHLEN + 1);
  478. if (0 < GetWindowsDirectory(default_location, MAXPATHLEN)) {
  479. if (*php_ini_search_path) {
  480. strlcat(php_ini_search_path, paths_separator, search_path_size);
  481. }
  482. strlcat(php_ini_search_path, default_location, search_path_size);
  483. }
  484. /* For people running under terminal services, GetWindowsDirectory will
  485. * return their personal Windows directory, so lets add the system
  486. * windows directory too */
  487. if (0 < GetSystemWindowsDirectory(default_location, MAXPATHLEN)) {
  488. if (*php_ini_search_path) {
  489. strlcat(php_ini_search_path, paths_separator, search_path_size);
  490. }
  491. strlcat(php_ini_search_path, default_location, search_path_size);
  492. }
  493. efree(default_location);
  494. #else
  495. default_location = PHP_CONFIG_FILE_PATH;
  496. if (*php_ini_search_path) {
  497. strlcat(php_ini_search_path, paths_separator, search_path_size);
  498. }
  499. strlcat(php_ini_search_path, default_location, search_path_size);
  500. #endif
  501. }
  502. PG(open_basedir) = NULL;
  503. /*
  504. * Find and open actual ini file
  505. */
  506. memset(&fh, 0, sizeof(fh));
  507. /* If SAPI does not want to ignore all ini files OR an overriding file/path is given.
  508. * This allows disabling scanning for ini files in the PHP_CONFIG_FILE_SCAN_DIR but still
  509. * load an optional ini file. */
  510. if (!sapi_module.php_ini_ignore || sapi_module.php_ini_path_override) {
  511. /* Check if php_ini_file_name is a file and can be opened */
  512. if (php_ini_file_name && php_ini_file_name[0]) {
  513. zend_stat_t statbuf;
  514. if (!VCWD_STAT(php_ini_file_name, &statbuf)) {
  515. if (!((statbuf.st_mode & S_IFMT) == S_IFDIR)) {
  516. fh.handle.fp = VCWD_FOPEN(php_ini_file_name, "r");
  517. if (fh.handle.fp) {
  518. fh.filename = expand_filepath(php_ini_file_name, NULL);
  519. }
  520. }
  521. }
  522. }
  523. /* Otherwise search for php-%sapi-module-name%.ini file in search path */
  524. if (!fh.handle.fp) {
  525. const char *fmt = "php-%s.ini";
  526. char *ini_fname;
  527. spprintf(&ini_fname, 0, fmt, sapi_module.name);
  528. fh.handle.fp = php_fopen_with_path(ini_fname, "r", php_ini_search_path, &opened_path);
  529. efree(ini_fname);
  530. if (fh.handle.fp) {
  531. fh.filename = ZSTR_VAL(opened_path);
  532. }
  533. }
  534. /* If still no ini file found, search for php.ini file in search path */
  535. if (!fh.handle.fp) {
  536. fh.handle.fp = php_fopen_with_path("php.ini", "r", php_ini_search_path, &opened_path);
  537. if (fh.handle.fp) {
  538. fh.filename = ZSTR_VAL(opened_path);
  539. }
  540. }
  541. }
  542. if (free_ini_search_path) {
  543. efree(php_ini_search_path);
  544. }
  545. PG(open_basedir) = open_basedir;
  546. if (fh.handle.fp) {
  547. fh.type = ZEND_HANDLE_FP;
  548. RESET_ACTIVE_INI_HASH();
  549. zend_parse_ini_file(&fh, 1, ZEND_INI_SCANNER_NORMAL, (zend_ini_parser_cb_t) php_ini_parser_cb, &configuration_hash);
  550. {
  551. zval tmp;
  552. ZVAL_NEW_STR(&tmp, zend_string_init(fh.filename, strlen(fh.filename), 1));
  553. zend_hash_str_update(&configuration_hash, "cfg_file_path", sizeof("cfg_file_path")-1, &tmp);
  554. if (opened_path) {
  555. zend_string_release_ex(opened_path, 0);
  556. } else {
  557. efree((char *)fh.filename);
  558. }
  559. php_ini_opened_path = zend_strndup(Z_STRVAL(tmp), Z_STRLEN(tmp));
  560. }
  561. }
  562. /* Check for PHP_INI_SCAN_DIR environment variable to override/set config file scan directory */
  563. php_ini_scanned_path = getenv("PHP_INI_SCAN_DIR");
  564. if (!php_ini_scanned_path) {
  565. /* Or fall back using possible --with-config-file-scan-dir setting (defaults to empty string!) */
  566. php_ini_scanned_path = PHP_CONFIG_FILE_SCAN_DIR;
  567. }
  568. php_ini_scanned_path_len = (int)strlen(php_ini_scanned_path);
  569. /* Scan and parse any .ini files found in scan path if path not empty. */
  570. if (!sapi_module.php_ini_ignore && php_ini_scanned_path_len) {
  571. struct dirent **namelist;
  572. int ndir, i;
  573. zend_stat_t sb;
  574. char ini_file[MAXPATHLEN];
  575. char *p;
  576. zend_file_handle fh2;
  577. zend_llist scanned_ini_list;
  578. zend_llist_element *element;
  579. int l, total_l = 0;
  580. char *bufpath, *debpath, *endpath;
  581. int lenpath;
  582. zend_llist_init(&scanned_ini_list, sizeof(char *), (llist_dtor_func_t) free_estring, 1);
  583. memset(&fh2, 0, sizeof(fh2));
  584. bufpath = estrdup(php_ini_scanned_path);
  585. for (debpath = bufpath ; debpath ; debpath=endpath) {
  586. endpath = strchr(debpath, DEFAULT_DIR_SEPARATOR);
  587. if (endpath) {
  588. *(endpath++) = 0;
  589. }
  590. if (!debpath[0]) {
  591. /* empty string means default builtin value
  592. to allow "/foo/php.d:" or ":/foo/php.d" */
  593. debpath = PHP_CONFIG_FILE_SCAN_DIR;
  594. }
  595. lenpath = (int)strlen(debpath);
  596. if (lenpath > 0 && (ndir = php_scandir(debpath, &namelist, 0, php_alphasort)) > 0) {
  597. for (i = 0; i < ndir; i++) {
  598. /* check for any file with .ini extension */
  599. if (!(p = strrchr(namelist[i]->d_name, '.')) || (p && strcmp(p, ".ini"))) {
  600. free(namelist[i]);
  601. continue;
  602. }
  603. /* Reset active ini section */
  604. RESET_ACTIVE_INI_HASH();
  605. if (IS_SLASH(debpath[lenpath - 1])) {
  606. snprintf(ini_file, MAXPATHLEN, "%s%s", debpath, namelist[i]->d_name);
  607. } else {
  608. snprintf(ini_file, MAXPATHLEN, "%s%c%s", debpath, DEFAULT_SLASH, namelist[i]->d_name);
  609. }
  610. if (VCWD_STAT(ini_file, &sb) == 0) {
  611. if (S_ISREG(sb.st_mode)) {
  612. if ((fh2.handle.fp = VCWD_FOPEN(ini_file, "r"))) {
  613. fh2.filename = ini_file;
  614. fh2.type = ZEND_HANDLE_FP;
  615. if (zend_parse_ini_file(&fh2, 1, ZEND_INI_SCANNER_NORMAL, (zend_ini_parser_cb_t) php_ini_parser_cb, &configuration_hash) == SUCCESS) {
  616. /* Here, add it to the list of ini files read */
  617. l = (int)strlen(ini_file);
  618. total_l += l + 2;
  619. p = estrndup(ini_file, l);
  620. zend_llist_add_element(&scanned_ini_list, &p);
  621. }
  622. }
  623. }
  624. }
  625. free(namelist[i]);
  626. }
  627. free(namelist);
  628. }
  629. }
  630. efree(bufpath);
  631. if (total_l) {
  632. int php_ini_scanned_files_len = (php_ini_scanned_files) ? (int)strlen(php_ini_scanned_files) + 1 : 0;
  633. php_ini_scanned_files = (char *) realloc(php_ini_scanned_files, php_ini_scanned_files_len + total_l + 1);
  634. if (!php_ini_scanned_files_len) {
  635. *php_ini_scanned_files = '\0';
  636. }
  637. total_l += php_ini_scanned_files_len;
  638. for (element = scanned_ini_list.head; element; element = element->next) {
  639. if (php_ini_scanned_files_len) {
  640. strlcat(php_ini_scanned_files, ",\n", total_l);
  641. }
  642. strlcat(php_ini_scanned_files, *(char **)element->data, total_l);
  643. strlcat(php_ini_scanned_files, element->next ? ",\n" : "\n", total_l);
  644. }
  645. }
  646. zend_llist_destroy(&scanned_ini_list);
  647. } else {
  648. /* Make sure an empty php_ini_scanned_path ends up as NULL */
  649. php_ini_scanned_path = NULL;
  650. }
  651. if (sapi_module.ini_entries) {
  652. /* Reset active ini section */
  653. RESET_ACTIVE_INI_HASH();
  654. zend_parse_ini_string(sapi_module.ini_entries, 1, ZEND_INI_SCANNER_NORMAL, (zend_ini_parser_cb_t) php_ini_parser_cb, &configuration_hash);
  655. }
  656. return SUCCESS;
  657. }
  658. /* }}} */
  659. /* {{{ php_shutdown_config
  660. */
  661. int php_shutdown_config(void)
  662. {
  663. zend_hash_destroy(&configuration_hash);
  664. if (php_ini_opened_path) {
  665. free(php_ini_opened_path);
  666. php_ini_opened_path = NULL;
  667. }
  668. if (php_ini_scanned_files) {
  669. free(php_ini_scanned_files);
  670. php_ini_scanned_files = NULL;
  671. }
  672. return SUCCESS;
  673. }
  674. /* }}} */
  675. /* {{{ php_ini_register_extensions
  676. */
  677. void php_ini_register_extensions(void)
  678. {
  679. zend_llist_apply(&extension_lists.engine, php_load_zend_extension_cb);
  680. zend_llist_apply(&extension_lists.functions, php_load_php_extension_cb);
  681. zend_llist_destroy(&extension_lists.engine);
  682. zend_llist_destroy(&extension_lists.functions);
  683. }
  684. /* }}} */
  685. /* {{{ php_parse_user_ini_file
  686. */
  687. PHPAPI int php_parse_user_ini_file(const char *dirname, char *ini_filename, HashTable *target_hash)
  688. {
  689. zend_stat_t sb;
  690. char ini_file[MAXPATHLEN];
  691. zend_file_handle fh;
  692. snprintf(ini_file, MAXPATHLEN, "%s%c%s", dirname, DEFAULT_SLASH, ini_filename);
  693. if (VCWD_STAT(ini_file, &sb) == 0) {
  694. if (S_ISREG(sb.st_mode)) {
  695. memset(&fh, 0, sizeof(fh));
  696. if ((fh.handle.fp = VCWD_FOPEN(ini_file, "r"))) {
  697. fh.filename = ini_file;
  698. fh.type = ZEND_HANDLE_FP;
  699. /* Reset active ini section */
  700. RESET_ACTIVE_INI_HASH();
  701. if (zend_parse_ini_file(&fh, 1, ZEND_INI_SCANNER_NORMAL, (zend_ini_parser_cb_t) php_ini_parser_cb, target_hash) == SUCCESS) {
  702. /* FIXME: Add parsed file to the list of user files read? */
  703. return SUCCESS;
  704. }
  705. return FAILURE;
  706. }
  707. }
  708. }
  709. return FAILURE;
  710. }
  711. /* }}} */
  712. /* {{{ php_ini_activate_config
  713. */
  714. PHPAPI void php_ini_activate_config(HashTable *source_hash, int modify_type, int stage)
  715. {
  716. zend_string *str;
  717. zval *data;
  718. /* Walk through config hash and alter matching ini entries using the values found in the hash */
  719. ZEND_HASH_FOREACH_STR_KEY_VAL(source_hash, str, data) {
  720. zend_alter_ini_entry_ex(str, Z_STR_P(data), modify_type, stage, 0);
  721. } ZEND_HASH_FOREACH_END();
  722. }
  723. /* }}} */
  724. /* {{{ php_ini_has_per_dir_config
  725. */
  726. PHPAPI int php_ini_has_per_dir_config(void)
  727. {
  728. return has_per_dir_config;
  729. }
  730. /* }}} */
  731. /* {{{ php_ini_activate_per_dir_config
  732. */
  733. PHPAPI void php_ini_activate_per_dir_config(char *path, size_t path_len)
  734. {
  735. zval *tmp2;
  736. char *ptr;
  737. #ifdef PHP_WIN32
  738. char path_bak[MAXPATHLEN];
  739. #endif
  740. #ifdef PHP_WIN32
  741. /* MAX_PATH is \0-terminated, path_len == MAXPATHLEN would overrun path_bak */
  742. if (path_len >= MAXPATHLEN) {
  743. #else
  744. if (path_len > MAXPATHLEN) {
  745. #endif
  746. return;
  747. }
  748. #ifdef PHP_WIN32
  749. memcpy(path_bak, path, path_len);
  750. path_bak[path_len] = 0;
  751. TRANSLATE_SLASHES_LOWER(path_bak);
  752. path = path_bak;
  753. #endif
  754. /* Walk through each directory in path and apply any found per-dir-system-configuration from configuration_hash */
  755. if (has_per_dir_config && path && path_len) {
  756. ptr = path + 1;
  757. while ((ptr = strchr(ptr, '/')) != NULL) {
  758. *ptr = 0;
  759. /* Search for source array matching the path from configuration_hash */
  760. if ((tmp2 = zend_hash_str_find(&configuration_hash, path, strlen(path))) != NULL) {
  761. php_ini_activate_config(Z_ARRVAL_P(tmp2), PHP_INI_SYSTEM, PHP_INI_STAGE_ACTIVATE);
  762. }
  763. *ptr = '/';
  764. ptr++;
  765. }
  766. }
  767. }
  768. /* }}} */
  769. /* {{{ php_ini_has_per_host_config
  770. */
  771. PHPAPI int php_ini_has_per_host_config(void)
  772. {
  773. return has_per_host_config;
  774. }
  775. /* }}} */
  776. /* {{{ php_ini_activate_per_host_config
  777. */
  778. PHPAPI void php_ini_activate_per_host_config(const char *host, size_t host_len)
  779. {
  780. zval *tmp;
  781. if (has_per_host_config && host && host_len) {
  782. /* Search for source array matching the host from configuration_hash */
  783. if ((tmp = zend_hash_str_find(&configuration_hash, host, host_len)) != NULL) {
  784. php_ini_activate_config(Z_ARRVAL_P(tmp), PHP_INI_SYSTEM, PHP_INI_STAGE_ACTIVATE);
  785. }
  786. }
  787. }
  788. /* }}} */
  789. /* {{{ cfg_get_entry
  790. */
  791. PHPAPI zval *cfg_get_entry_ex(zend_string *name)
  792. {
  793. return zend_hash_find(&configuration_hash, name);
  794. }
  795. /* }}} */
  796. /* {{{ cfg_get_entry
  797. */
  798. PHPAPI zval *cfg_get_entry(const char *name, size_t name_length)
  799. {
  800. return zend_hash_str_find(&configuration_hash, name, name_length);
  801. }
  802. /* }}} */
  803. /* {{{ cfg_get_long
  804. */
  805. PHPAPI int cfg_get_long(const char *varname, zend_long *result)
  806. {
  807. zval *tmp;
  808. if ((tmp = zend_hash_str_find(&configuration_hash, varname, strlen(varname))) == NULL) {
  809. *result = 0;
  810. return FAILURE;
  811. }
  812. *result = zval_get_long(tmp);
  813. return SUCCESS;
  814. }
  815. /* }}} */
  816. /* {{{ cfg_get_double
  817. */
  818. PHPAPI int cfg_get_double(const char *varname, double *result)
  819. {
  820. zval *tmp;
  821. if ((tmp = zend_hash_str_find(&configuration_hash, varname, strlen(varname))) == NULL) {
  822. *result = (double) 0;
  823. return FAILURE;
  824. }
  825. *result = zval_get_double(tmp);
  826. return SUCCESS;
  827. }
  828. /* }}} */
  829. /* {{{ cfg_get_string
  830. */
  831. PHPAPI int cfg_get_string(const char *varname, char **result)
  832. {
  833. zval *tmp;
  834. if ((tmp = zend_hash_str_find(&configuration_hash, varname, strlen(varname))) == NULL) {
  835. *result = NULL;
  836. return FAILURE;
  837. }
  838. *result = Z_STRVAL_P(tmp);
  839. return SUCCESS;
  840. }
  841. /* }}} */
  842. PHPAPI HashTable* php_ini_get_configuration_hash(void) /* {{{ */
  843. {
  844. return &configuration_hash;
  845. } /* }}} */
  846. /*
  847. * Local variables:
  848. * tab-width: 4
  849. * c-basic-offset: 4
  850. * indent-tabs-mode: t
  851. * End:
  852. * vim600: sw=4 ts=4 fdm=marker
  853. * vim<600: sw=4 ts=4
  854. */