Coverage Report

Created: 2025-06-13 06:43

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