Skip to content

Commit 3588d8a

Browse files
committed
1 parent a632ecd commit 3588d8a

9 files changed

+263
-21
lines changed

NEWS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ PHP NEWS
77
arguments). (cmb)
88
. Fixed bug #76392 (Error relocating sapi/cli/php: unsupported relocation
99
type 37). (Peter Kokot)
10+
. The declaration and use of case-insensitive constants has been deprecated.
11+
(Nikita)
1012

1113
- Filter:
1214
. Added the 'add_slashes' sanitization mode (FILTER_SANITIZE_ADD_SLASHES).

UPGRADING

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,13 @@ FPM:
258258
4. Deprecated Functionality
259259
========================================
260260

261+
Core:
262+
. The declaration of case-insensitive constants has been deprecate. Passing
263+
true as the third argument to define() will now generate a deprecation
264+
warning. The use of case-insensitive constants with a case that differs from
265+
the declaration is also deprecated.
266+
(RFC: https://wiki.php.net/rfc/case_insensitive_constant_deprecation)
267+
261268
GD:
262269
. image2wbmp() has been deprecated.
263270

Zend/tests/bug46304.phpt

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,11 @@ print ns1\ns2\coNSt6 . "\n";
4040
print NS1\ns2\coNSt1 . "\n";
4141
?>
4242
--EXPECTF--
43+
Deprecated: define(): Declaration of case-insensitive constants is deprecated in %s on line 6
44+
45+
Deprecated: define(): Declaration of case-insensitive constants is deprecated in %s on line 7
46+
47+
Deprecated: define(): Declaration of case-insensitive constants is deprecated in %s on line 8
4348
value1
4449
value1
4550
value1
@@ -52,13 +57,23 @@ value3
5257
value4
5358
value4
5459
value4
60+
61+
Deprecated: Case-insensitive constants are deprecated. The correct casing for this constant is "NS1\ns2\const4" in %s on line 25
5562
value4
5663
value5
5764
value5
5865
value5
66+
67+
Deprecated: Case-insensitive constants are deprecated. The correct casing for this constant is "ns1\ns2\const5" in %s on line 30
5968
value5
69+
70+
Deprecated: Case-insensitive constants are deprecated. The correct casing for this constant is "ns1\NS2\coNSt6" in %s on line 32
6071
value6
72+
73+
Deprecated: Case-insensitive constants are deprecated. The correct casing for this constant is "ns1\NS2\coNSt6" in %s on line 33
6174
value6
75+
76+
Deprecated: Case-insensitive constants are deprecated. The correct casing for this constant is "ns1\NS2\coNSt6" in %s on line 34
6277
value6
6378
value6
6479

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
--TEST--
2+
Case-insensitive constants are deprecated
3+
--FILE--
4+
<?php
5+
6+
namespace {
7+
define('FOO', 42, true); // Deprecated
8+
define('NS\FOO', 24, true); // Deprecated
9+
10+
var_dump(FOO); // Ok
11+
var_dump(foo); // Deprecated
12+
13+
var_dump(NS\FOO); // Ok
14+
var_dump(ns\FOO); // Ok
15+
var_dump(ns\foo); // Deprecated
16+
17+
var_dump(defined('FOO')); // Ok
18+
var_dump(defined('foo')); // Ok
19+
var_dump(defined('NS\FOO')); // Ok
20+
var_dump(defined('ns\FOO')); // Ok
21+
var_dump(defined('ns\foo')); // Ok
22+
23+
var_dump(constant('FOO')); // Ok
24+
var_dump(constant('foo')); // Deprecated
25+
var_dump(constant('NS\FOO')); // Ok
26+
var_dump(constant('ns\FOO')); // Ok
27+
var_dump(constant('ns\foo')); // Deprecated
28+
}
29+
30+
namespace NS {
31+
var_dump(FOO); // Ok
32+
var_dump(foo); // Deprecated
33+
}
34+
35+
namespace ns {
36+
var_dump(FOO); // Ok
37+
var_dump(foo); // Deprecated
38+
}
39+
40+
namespace Other {
41+
var_dump(FOO); // Ok
42+
var_dump(foo); // Deprecated
43+
44+
var_dump(defined('FOO')); // Ok
45+
var_dump(defined('foo')); // Ok
46+
var_dump(defined('NS\FOO')); // Ok
47+
var_dump(defined('ns\FOO')); // Ok
48+
var_dump(defined('ns\foo')); // Ok
49+
50+
var_dump(constant('FOO')); // Ok
51+
var_dump(constant('foo')); // Deprecated
52+
var_dump(constant('NS\FOO')); // Ok
53+
var_dump(constant('ns\FOO')); // Ok
54+
var_dump(constant('ns\foo')); // Deprecated
55+
56+
const C1 = FOO; // Ok
57+
var_dump(C1);
58+
const C2 = foo; // Deprecated
59+
var_dump(C2);
60+
const C3 = 1 + FOO; // Ok
61+
var_dump(C3);
62+
const C4 = 1 + foo; // Deprecated
63+
var_dump(C4);
64+
}
65+
66+
?>
67+
--EXPECTF--
68+
Deprecated: define(): Declaration of case-insensitive constants is deprecated in %s on line 4
69+
70+
Deprecated: define(): Declaration of case-insensitive constants is deprecated in %s on line 5
71+
int(42)
72+
73+
Deprecated: Case-insensitive constants are deprecated. The correct casing for this constant is "FOO" in %s on line 8
74+
int(42)
75+
int(24)
76+
int(24)
77+
78+
Deprecated: Case-insensitive constants are deprecated. The correct casing for this constant is "NS\FOO" in %s on line 12
79+
int(24)
80+
bool(true)
81+
bool(true)
82+
bool(true)
83+
bool(true)
84+
bool(true)
85+
int(42)
86+
87+
Deprecated: Case-insensitive constants are deprecated. The correct casing for this constant is "FOO" in %s on line 21
88+
int(42)
89+
int(24)
90+
int(24)
91+
92+
Deprecated: Case-insensitive constants are deprecated. The correct casing for this constant is "NS\FOO" in %s on line 24
93+
int(24)
94+
int(24)
95+
96+
Deprecated: Case-insensitive constants are deprecated. The correct casing for this constant is "NS\FOO" in %s on line 29
97+
int(24)
98+
int(24)
99+
100+
Deprecated: Case-insensitive constants are deprecated. The correct casing for this constant is "NS\FOO" in %s on line 34
101+
int(24)
102+
int(42)
103+
104+
Deprecated: Case-insensitive constants are deprecated. The correct casing for this constant is "FOO" in %s on line 39
105+
int(42)
106+
bool(true)
107+
bool(true)
108+
bool(true)
109+
bool(true)
110+
bool(true)
111+
int(42)
112+
113+
Deprecated: Case-insensitive constants are deprecated. The correct casing for this constant is "FOO" in %s on line 48
114+
int(42)
115+
int(24)
116+
int(24)
117+
118+
Deprecated: Case-insensitive constants are deprecated. The correct casing for this constant is "NS\FOO" in %s on line 51
119+
int(24)
120+
int(42)
121+
122+
Deprecated: Case-insensitive constants are deprecated. The correct casing for this constant is "FOO" in %s on line 55
123+
int(42)
124+
int(43)
125+
126+
Deprecated: Case-insensitive constants are deprecated. The correct casing for this constant is "FOO" in %s on line 59
127+
int(43)

Zend/zend_builtin_functions.c

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -854,7 +854,6 @@ ZEND_FUNCTION(define)
854854
case_sensitive = 0;
855855
}
856856

857-
/* class constant, check if there is name and make sure class is valid & exists */
858857
if (zend_memnstr(ZSTR_VAL(name), "::", sizeof("::") - 1, ZSTR_VAL(name) + ZSTR_LEN(name))) {
859858
zend_error(E_WARNING, "Class constants cannot be defined or redefined");
860859
RETURN_FALSE;
@@ -905,7 +904,13 @@ ZEND_FUNCTION(define)
905904

906905
ZVAL_COPY(&c.value, val);
907906
zval_ptr_dtor(&val_free);
907+
908908
register_constant:
909+
if (non_cs) {
910+
zend_error(E_DEPRECATED,
911+
"define(): Declaration of case-insensitive constants is deprecated");
912+
}
913+
909914
c.flags = case_sensitive; /* non persistent */
910915
c.name = zend_string_copy(name);
911916
c.module_number = PHP_USER_CONSTANT;
@@ -928,7 +933,7 @@ ZEND_FUNCTION(defined)
928933
Z_PARAM_STR(name)
929934
ZEND_PARSE_PARAMETERS_END();
930935

931-
if (zend_get_constant_ex(name, zend_get_executed_scope(), ZEND_FETCH_CLASS_SILENT)) {
936+
if (zend_get_constant_ex(name, zend_get_executed_scope(), ZEND_FETCH_CLASS_SILENT | ZEND_GET_CONSTANT_NO_DEPRECATION_CHECK)) {
932937
RETURN_TRUE;
933938
} else {
934939
RETURN_FALSE;

Zend/zend_constants.c

Lines changed: 78 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -250,7 +250,7 @@ ZEND_API int zend_verify_const_access(zend_class_constant *c, zend_class_entry *
250250
}
251251
/* }}} */
252252

253-
ZEND_API zval *zend_get_constant_str(const char *name, size_t name_len)
253+
static inline zend_constant *zend_get_constant_str_impl(const char *name, size_t name_len)
254254
{
255255
zend_constant *c;
256256
ALLOCA_FLAG(use_heap)
@@ -268,10 +268,16 @@ ZEND_API zval *zend_get_constant_str(const char *name, size_t name_len)
268268
free_alloca(lcname, use_heap);
269269
}
270270

271+
return c;
272+
}
273+
274+
ZEND_API zval *zend_get_constant_str(const char *name, size_t name_len)
275+
{
276+
zend_constant *c = zend_get_constant_str_impl(name, name_len);
271277
return c ? &c->value : NULL;
272278
}
273279

274-
ZEND_API zval *zend_get_constant(zend_string *name)
280+
static inline zend_constant *zend_get_constant_impl(zend_string *name)
275281
{
276282
zval *zv;
277283
zend_constant *c;
@@ -291,9 +297,32 @@ ZEND_API zval *zend_get_constant(zend_string *name)
291297
c = zend_get_special_constant(ZSTR_VAL(name), ZSTR_LEN(name));
292298
}
293299
free_alloca(lcname, use_heap);
294-
return c ? &c->value : NULL;
300+
return c;
301+
} else {
302+
return (zend_constant *) Z_PTR_P(zv);
303+
}
304+
}
305+
306+
ZEND_API zval *zend_get_constant(zend_string *name)
307+
{
308+
zend_constant *c = zend_get_constant_impl(name);
309+
return c ? &c->value : NULL;
310+
}
311+
312+
static zend_bool is_access_deprecated(const zend_constant *c, const char *access_name) {
313+
const char *ns_sep = zend_memrchr(ZSTR_VAL(c->name), '\\', ZSTR_LEN(c->name));
314+
if (ns_sep) {
315+
/* Namespaces are always case-insensitive. Only compare shortname. */
316+
size_t shortname_offset = ns_sep - ZSTR_VAL(c->name) + 1;
317+
size_t shortname_len = ZSTR_LEN(c->name) - shortname_offset;
318+
return memcmp(
319+
access_name + shortname_offset,
320+
ZSTR_VAL(c->name) + shortname_offset,
321+
shortname_len
322+
) != 0;
295323
} else {
296-
return &((zend_constant*)Z_PTR_P(zv))->value;
324+
/* No namespace, compare whole name */
325+
return memcmp(access_name, ZSTR_VAL(c->name), ZSTR_LEN(c->name)) != 0;
297326
}
298327
}
299328

@@ -415,26 +444,45 @@ ZEND_API zval *zend_get_constant_ex(zend_string *cname, zend_class_entry *scope,
415444
}
416445
}
417446
free_alloca(lcname, use_heap);
418-
if (c) {
419-
return &c->value;
447+
448+
if (!c) {
449+
if (!(flags & IS_CONSTANT_UNQUALIFIED)) {
450+
return NULL;
451+
}
452+
453+
/* name requires runtime resolution, need to check non-namespaced name */
454+
c = zend_get_constant_str_impl(constant_name, const_name_len);
455+
name = constant_name;
420456
}
421-
/* name requires runtime resolution, need to check non-namespaced name */
422-
if ((flags & IS_CONSTANT_UNQUALIFIED) != 0) {
423-
return zend_get_constant_str(constant_name, const_name_len);
457+
} else {
458+
if (cname) {
459+
c = zend_get_constant_impl(cname);
460+
} else {
461+
c = zend_get_constant_str_impl(name, name_len);
424462
}
463+
}
464+
465+
if (!c) {
425466
return NULL;
426467
}
427468

428-
if (cname) {
429-
return zend_get_constant(cname);
430-
} else {
431-
return zend_get_constant_str(name, name_len);
469+
if (!(flags & ZEND_GET_CONSTANT_NO_DEPRECATION_CHECK)) {
470+
if (!(c->flags & (CONST_CS|CONST_CT_SUBST)) && is_access_deprecated(c, name)) {
471+
zend_error(E_DEPRECATED,
472+
"Case-insensitive constants are deprecated. "
473+
"The correct casing for this constant is \"%s\"",
474+
ZSTR_VAL(c->name));
475+
}
432476
}
477+
478+
return &c->value;
433479
}
434480

435-
ZEND_API zend_constant* ZEND_FASTCALL zend_quick_get_constant(const zval *key, uint32_t flags)
481+
ZEND_API zend_constant* ZEND_FASTCALL zend_quick_get_constant(
482+
const zval *key, uint32_t flags, zend_bool *is_deprecated)
436483
{
437484
zval *zv;
485+
const zval *orig_key = key;
438486
zend_constant *c = NULL;
439487

440488
zv = zend_hash_find_ex(EG(zend_constants), Z_STR_P(key), 1);
@@ -461,6 +509,22 @@ ZEND_API zend_constant* ZEND_FASTCALL zend_quick_get_constant(const zval *key, u
461509
}
462510
}
463511
}
512+
513+
if (!c) {
514+
return NULL;
515+
}
516+
517+
if (is_deprecated) {
518+
if (c->flags & (CONST_CS|CONST_CT_SUBST)) {
519+
/* Constant is case-sensitive or true/false/null */
520+
*is_deprecated = 0;
521+
} else {
522+
zend_bool ns_fallback = key >= orig_key + 2;
523+
const zval *access_key = ns_fallback ? orig_key + 2 : orig_key - 1;
524+
*is_deprecated = is_access_deprecated(c, Z_STRVAL_P(access_key));
525+
}
526+
}
527+
464528
return c;
465529
}
466530

Zend/zend_constants.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@
3131

3232
#define PHP_USER_CONSTANT INT_MAX /* a constant defined in user space */
3333

34+
/* Flag for zend_get_constant_ex(). Must not class with ZEND_FETCH_CLASS_* flags. */
35+
#define ZEND_GET_CONSTANT_NO_DEPRECATION_CHECK 0x1000
36+
3437
typedef struct _zend_constant {
3538
zval value;
3639
zend_string *name;
@@ -79,7 +82,8 @@ ZEND_API int zend_register_constant(zend_constant *c);
7982
#ifdef ZTS
8083
void zend_copy_constants(HashTable *target, HashTable *sourc);
8184
#endif
82-
ZEND_API zend_constant* ZEND_FASTCALL zend_quick_get_constant(const zval *key, uint32_t flags);
85+
ZEND_API zend_constant* ZEND_FASTCALL zend_quick_get_constant(
86+
const zval *key, uint32_t flags, zend_bool *is_deprecated);
8387
END_EXTERN_C()
8488

8589
#define ZEND_CONSTANT_DTOR free_zend_constant

0 commit comments

Comments
 (0)