Re: [PHP-DEV] Deprecate Undefined Constant Usage in php.ini Files (GH-20060)

On Sunday 19 October 2025 21:14:00 (+02:00), Tim Düsterhus wrote:

Hi

On 10/5/25 14:54, Hans Krentel wrote:
> The php.ini file parser (as used by `parse_ini_file()`) supports
> constant resolution, including core predefined constants. However, the
> current behavior with undefined constants is inconsistent with PHP 8's
> strict handling of undefined constants in regular PHP code.

How would PHP differentiate between “constants” and “unquoted strings”, the latter of which are explicitly supported (and encouraged) by the INI file format?

As it does today, no change. If you use a word that would expand to a constant name as it does today, you need to quote it.

This preparatory step - if required - can be done in advance and the configuration file remains forwards / backwards compatible so can be used across versions (e.g. configuration file templates).

Best,

-- hakre

Hi

On 10/19/25 21:47, Hans Krentel wrote:

As it does today, no change. If you use a word that would expand to a constant name as it does today, you need to quote it.

That was not what I was asking for.

You are proposing to warn for undefined constants. How do you plan to warn only for undefined constants, but not for unquoted strings?

Best regards
Tim Düsterhus

On Sunday 19 October 2025 22:09:52 (+02:00), Tim Düsterhus wrote:

Hi

On 10/19/25 21:47, Hans Krentel wrote:
> As it does today, no change. If you use a word that would expand to a constant name as it does today, you need to quote it.

That was not what I was asking for.

You are proposing to warn for undefined constants. How do you plan to warn only for undefined constants, but not for unquoted strings?

Best regards
Tim Düsterhus

Hi Tim,

Thanks for the clarification, and my apologies—my previous, shorter
answer missed the mark. Let me outline my understanding in greater
detail.

As noted in the implementation notes, I looked into
`zend_ini_get_constant()` and saw that the zend-ini parser doesn't
handle all unquoted strings, but only those matching `IS_CONSTANT_AST`,
which stems from:

  CONSTANT [a-zA-Z_][a-zA-Z0-9_]*

My proposal is to apply the same test (`Z_OPT_CONSTANT(tmp)`) *before*
probing for the constant's existence (currently done via `c =
zend_get_constant(Z_STR_P(name)) != 0`). This would address the current
ordering flaw in the parser as an incidental improvement.

More importantly, regarding your question, I've now looked more closely
at the `CONSTANT` regex and realize I was mistaken: I had assumed it
matched uppercase-only names, but it actually includes both upper- and
lowercase letters.

So, there would indeed be a change compared to my earlier answer: I now
propose using only uppercase names for constant resolution (and thus for
the warning you asked about). This would mean:

- Allowing unquoted strings with lowercase characters to pass through
  unchanged.

- Restricting constant name resolution to a pattern like:

    CONSTANT_NAME [A-Z_][A-Z0-9_]*

  ...possibly with a minimum length greater than one, as shown.

In my view, this improves clarity in configuration contexts--at this
level, case-folding to lowercase shouldn't be necessary. That said,
your perspective may differ, and perhaps this was exactly the point you
were raising.

This revised understanding also suggests a more granular approach to
differentiating cases, enabling richer behavior. But first, I'd
appreciate your feedback on this more detailed reply.

Best regards,

Hans

On 20/10/2025 10:16, Hans Krentel wrote:

So, there would indeed be a change compared to my earlier answer: I now
propose using only uppercase names for constant resolution (and thus for
the warning you asked about). This would mean:

- Allowing unquoted strings with lowercase characters to pass through
   unchanged.

- Restricting constant name resolution to a pattern like:

     CONSTANT_NAME [A-Z_][A-Z0-9_]*

   ...possibly with a minimum length greater than one, as shown.

I don't think this kind of pattern matching is the right way to go. It's perfectly normal in INI files to have all sorts of strings which aren't quoted; looking through the samples provided in the source, I spotted this:

user_agent=PHP

No regex is going to recognise that that should be interpreted as "PHP", not constant("PHP").

As I think I mentioned in an earlier message, the specific problem raised seems to be more to do with string-to-int conversion, rather than the INI parsing itself. Even if the invalid constant is surrounded by quotes, this is not a useful setting:

error_reporting = "X_ERROR"|E_WARNING|E_PARSE|E_NOTICE

Maybe the part of the parser that handles *operators* is what needs a behaviour change instead?

--
Rowan Tommins
[IMSoP]

Hi

Am 2025-10-20 20:17, schrieb Rowan Tommins [IMSoP]:

I don't think this kind of pattern matching is the right way to go. It's perfectly normal in INI files to have all sorts of strings which aren't quoted; looking through the samples provided in the source, I spotted this:

user_agent=PHP

No regex is going to recognise that that should be interpreted as "PHP", not constant("PHP").

I agree with that. Supporting bare strings is a key feature and randomly warning for *some* of them is going to be even more confusing than just some of them randomly getting replaced by a different value just because they happen to match a constant. In fact this made me realize that `parse_ini_*()` is unsafe, because it doesn't just support *internal* constants, but also constants defined in userland. I have thus just proposed a new warning to be added to the documentation: parse_ini_*(): Add warning that the functions are unsafe with untrusted inputs by TimWolla · Pull Request #4946 · php/doc-en · GitHub.

Given that the primary purpose of the constant support seems to be the E_* constants for `error_reporting`, it might be best to instead only support a small allow-list of safe constants in INI files.

Best regards
Tim Düsterhus

On 23.10.25 10:21, Tim Düsterhus wrote:

Hi

Am 2025-10-20 20:17, schrieb Rowan Tommins [IMSoP]:

I don't think this kind of pattern matching is the right way to go. It's perfectly normal in INI files to have all sorts of strings which aren't quoted; looking through the samples provided in the source, I spotted this:

user_agent=PHP

No regex is going to recognise that that should be interpreted as "PHP", not constant("PHP").

I agree with that. Supporting bare strings is a key feature and randomly warning for *some* of them is going to be even more confusing than just some of them randomly getting replaced by a different value just because they happen to match a constant. In fact this made me realize that `parse_ini_*()` is unsafe, because it doesn't just support *internal* constants, but also constants defined in userland. I have thus just proposed a new warning to be added to the documentation: parse_ini_*(): Add warning that the functions are unsafe with untrusted inputs by TimWolla · Pull Request #4946 · php/doc-en · GitHub.

Given that the primary purpose of the constant support seems to be the E_* constants for `error_reporting`, it might be best to instead only support a small allow-list of safe constants in INI files.

Another possible way would be to introduce a special syntax for constants - just like we already have for environment variables.

Best regards
Tim Düsterhus