1
0
mirror of https://github.com/php/php-src.git synced 2026-03-24 00:02:20 +01:00

Deprecate case-insensitive constants

RFC: https://wiki.php.net/rfc/case_insensitive_constant_deprecation
This commit is contained in:
Nikita Popov
2018-06-23 20:51:49 +02:00
parent a632ecd224
commit 3588d8af12
9 changed files with 263 additions and 21 deletions

2
NEWS
View File

@@ -7,6 +7,8 @@ PHP NEWS
arguments). (cmb)
. Fixed bug #76392 (Error relocating sapi/cli/php: unsupported relocation
type 37). (Peter Kokot)
. The declaration and use of case-insensitive constants has been deprecated.
(Nikita)
- Filter:
. Added the 'add_slashes' sanitization mode (FILTER_SANITIZE_ADD_SLASHES).

View File

@@ -258,6 +258,13 @@ FPM:
4. Deprecated Functionality
========================================
Core:
. The declaration of case-insensitive constants has been deprecate. Passing
true as the third argument to define() will now generate a deprecation
warning. The use of case-insensitive constants with a case that differs from
the declaration is also deprecated.
(RFC: https://wiki.php.net/rfc/case_insensitive_constant_deprecation)
GD:
. image2wbmp() has been deprecated.

View File

@@ -40,6 +40,11 @@ print ns1\ns2\coNSt6 . "\n";
print NS1\ns2\coNSt1 . "\n";
?>
--EXPECTF--
Deprecated: define(): Declaration of case-insensitive constants is deprecated in %s on line 6
Deprecated: define(): Declaration of case-insensitive constants is deprecated in %s on line 7
Deprecated: define(): Declaration of case-insensitive constants is deprecated in %s on line 8
value1
value1
value1
@@ -52,13 +57,23 @@ value3
value4
value4
value4
Deprecated: Case-insensitive constants are deprecated. The correct casing for this constant is "NS1\ns2\const4" in %s on line 25
value4
value5
value5
value5
Deprecated: Case-insensitive constants are deprecated. The correct casing for this constant is "ns1\ns2\const5" in %s on line 30
value5
Deprecated: Case-insensitive constants are deprecated. The correct casing for this constant is "ns1\NS2\coNSt6" in %s on line 32
value6
Deprecated: Case-insensitive constants are deprecated. The correct casing for this constant is "ns1\NS2\coNSt6" in %s on line 33
value6
Deprecated: Case-insensitive constants are deprecated. The correct casing for this constant is "ns1\NS2\coNSt6" in %s on line 34
value6
value6

View File

@@ -0,0 +1,127 @@
--TEST--
Case-insensitive constants are deprecated
--FILE--
<?php
namespace {
define('FOO', 42, true); // Deprecated
define('NS\FOO', 24, true); // Deprecated
var_dump(FOO); // Ok
var_dump(foo); // Deprecated
var_dump(NS\FOO); // Ok
var_dump(ns\FOO); // Ok
var_dump(ns\foo); // Deprecated
var_dump(defined('FOO')); // Ok
var_dump(defined('foo')); // Ok
var_dump(defined('NS\FOO')); // Ok
var_dump(defined('ns\FOO')); // Ok
var_dump(defined('ns\foo')); // Ok
var_dump(constant('FOO')); // Ok
var_dump(constant('foo')); // Deprecated
var_dump(constant('NS\FOO')); // Ok
var_dump(constant('ns\FOO')); // Ok
var_dump(constant('ns\foo')); // Deprecated
}
namespace NS {
var_dump(FOO); // Ok
var_dump(foo); // Deprecated
}
namespace ns {
var_dump(FOO); // Ok
var_dump(foo); // Deprecated
}
namespace Other {
var_dump(FOO); // Ok
var_dump(foo); // Deprecated
var_dump(defined('FOO')); // Ok
var_dump(defined('foo')); // Ok
var_dump(defined('NS\FOO')); // Ok
var_dump(defined('ns\FOO')); // Ok
var_dump(defined('ns\foo')); // Ok
var_dump(constant('FOO')); // Ok
var_dump(constant('foo')); // Deprecated
var_dump(constant('NS\FOO')); // Ok
var_dump(constant('ns\FOO')); // Ok
var_dump(constant('ns\foo')); // Deprecated
const C1 = FOO; // Ok
var_dump(C1);
const C2 = foo; // Deprecated
var_dump(C2);
const C3 = 1 + FOO; // Ok
var_dump(C3);
const C4 = 1 + foo; // Deprecated
var_dump(C4);
}
?>
--EXPECTF--
Deprecated: define(): Declaration of case-insensitive constants is deprecated in %s on line 4
Deprecated: define(): Declaration of case-insensitive constants is deprecated in %s on line 5
int(42)
Deprecated: Case-insensitive constants are deprecated. The correct casing for this constant is "FOO" in %s on line 8
int(42)
int(24)
int(24)
Deprecated: Case-insensitive constants are deprecated. The correct casing for this constant is "NS\FOO" in %s on line 12
int(24)
bool(true)
bool(true)
bool(true)
bool(true)
bool(true)
int(42)
Deprecated: Case-insensitive constants are deprecated. The correct casing for this constant is "FOO" in %s on line 21
int(42)
int(24)
int(24)
Deprecated: Case-insensitive constants are deprecated. The correct casing for this constant is "NS\FOO" in %s on line 24
int(24)
int(24)
Deprecated: Case-insensitive constants are deprecated. The correct casing for this constant is "NS\FOO" in %s on line 29
int(24)
int(24)
Deprecated: Case-insensitive constants are deprecated. The correct casing for this constant is "NS\FOO" in %s on line 34
int(24)
int(42)
Deprecated: Case-insensitive constants are deprecated. The correct casing for this constant is "FOO" in %s on line 39
int(42)
bool(true)
bool(true)
bool(true)
bool(true)
bool(true)
int(42)
Deprecated: Case-insensitive constants are deprecated. The correct casing for this constant is "FOO" in %s on line 48
int(42)
int(24)
int(24)
Deprecated: Case-insensitive constants are deprecated. The correct casing for this constant is "NS\FOO" in %s on line 51
int(24)
int(42)
Deprecated: Case-insensitive constants are deprecated. The correct casing for this constant is "FOO" in %s on line 55
int(42)
int(43)
Deprecated: Case-insensitive constants are deprecated. The correct casing for this constant is "FOO" in %s on line 59
int(43)

View File

@@ -854,7 +854,6 @@ ZEND_FUNCTION(define)
case_sensitive = 0;
}
/* class constant, check if there is name and make sure class is valid & exists */
if (zend_memnstr(ZSTR_VAL(name), "::", sizeof("::") - 1, ZSTR_VAL(name) + ZSTR_LEN(name))) {
zend_error(E_WARNING, "Class constants cannot be defined or redefined");
RETURN_FALSE;
@@ -905,7 +904,13 @@ repeat:
ZVAL_COPY(&c.value, val);
zval_ptr_dtor(&val_free);
register_constant:
if (non_cs) {
zend_error(E_DEPRECATED,
"define(): Declaration of case-insensitive constants is deprecated");
}
c.flags = case_sensitive; /* non persistent */
c.name = zend_string_copy(name);
c.module_number = PHP_USER_CONSTANT;
@@ -928,7 +933,7 @@ ZEND_FUNCTION(defined)
Z_PARAM_STR(name)
ZEND_PARSE_PARAMETERS_END();
if (zend_get_constant_ex(name, zend_get_executed_scope(), ZEND_FETCH_CLASS_SILENT)) {
if (zend_get_constant_ex(name, zend_get_executed_scope(), ZEND_FETCH_CLASS_SILENT | ZEND_GET_CONSTANT_NO_DEPRECATION_CHECK)) {
RETURN_TRUE;
} else {
RETURN_FALSE;

View File

@@ -250,7 +250,7 @@ ZEND_API int zend_verify_const_access(zend_class_constant *c, zend_class_entry *
}
/* }}} */
ZEND_API zval *zend_get_constant_str(const char *name, size_t name_len)
static inline zend_constant *zend_get_constant_str_impl(const char *name, size_t name_len)
{
zend_constant *c;
ALLOCA_FLAG(use_heap)
@@ -268,10 +268,16 @@ ZEND_API zval *zend_get_constant_str(const char *name, size_t name_len)
free_alloca(lcname, use_heap);
}
return c;
}
ZEND_API zval *zend_get_constant_str(const char *name, size_t name_len)
{
zend_constant *c = zend_get_constant_str_impl(name, name_len);
return c ? &c->value : NULL;
}
ZEND_API zval *zend_get_constant(zend_string *name)
static inline zend_constant *zend_get_constant_impl(zend_string *name)
{
zval *zv;
zend_constant *c;
@@ -291,9 +297,32 @@ ZEND_API zval *zend_get_constant(zend_string *name)
c = zend_get_special_constant(ZSTR_VAL(name), ZSTR_LEN(name));
}
free_alloca(lcname, use_heap);
return c ? &c->value : NULL;
return c;
} else {
return &((zend_constant*)Z_PTR_P(zv))->value;
return (zend_constant *) Z_PTR_P(zv);
}
}
ZEND_API zval *zend_get_constant(zend_string *name)
{
zend_constant *c = zend_get_constant_impl(name);
return c ? &c->value : NULL;
}
static zend_bool is_access_deprecated(const zend_constant *c, const char *access_name) {
const char *ns_sep = zend_memrchr(ZSTR_VAL(c->name), '\\', ZSTR_LEN(c->name));
if (ns_sep) {
/* Namespaces are always case-insensitive. Only compare shortname. */
size_t shortname_offset = ns_sep - ZSTR_VAL(c->name) + 1;
size_t shortname_len = ZSTR_LEN(c->name) - shortname_offset;
return memcmp(
access_name + shortname_offset,
ZSTR_VAL(c->name) + shortname_offset,
shortname_len
) != 0;
} else {
/* No namespace, compare whole name */
return memcmp(access_name, ZSTR_VAL(c->name), ZSTR_LEN(c->name)) != 0;
}
}
@@ -415,26 +444,45 @@ failure:
}
}
free_alloca(lcname, use_heap);
if (c) {
return &c->value;
if (!c) {
if (!(flags & IS_CONSTANT_UNQUALIFIED)) {
return NULL;
}
/* name requires runtime resolution, need to check non-namespaced name */
c = zend_get_constant_str_impl(constant_name, const_name_len);
name = constant_name;
}
/* name requires runtime resolution, need to check non-namespaced name */
if ((flags & IS_CONSTANT_UNQUALIFIED) != 0) {
return zend_get_constant_str(constant_name, const_name_len);
} else {
if (cname) {
c = zend_get_constant_impl(cname);
} else {
c = zend_get_constant_str_impl(name, name_len);
}
}
if (!c) {
return NULL;
}
if (cname) {
return zend_get_constant(cname);
} else {
return zend_get_constant_str(name, name_len);
if (!(flags & ZEND_GET_CONSTANT_NO_DEPRECATION_CHECK)) {
if (!(c->flags & (CONST_CS|CONST_CT_SUBST)) && is_access_deprecated(c, name)) {
zend_error(E_DEPRECATED,
"Case-insensitive constants are deprecated. "
"The correct casing for this constant is \"%s\"",
ZSTR_VAL(c->name));
}
}
return &c->value;
}
ZEND_API zend_constant* ZEND_FASTCALL zend_quick_get_constant(const zval *key, uint32_t flags)
ZEND_API zend_constant* ZEND_FASTCALL zend_quick_get_constant(
const zval *key, uint32_t flags, zend_bool *is_deprecated)
{
zval *zv;
const zval *orig_key = key;
zend_constant *c = NULL;
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
}
}
}
if (!c) {
return NULL;
}
if (is_deprecated) {
if (c->flags & (CONST_CS|CONST_CT_SUBST)) {
/* Constant is case-sensitive or true/false/null */
*is_deprecated = 0;
} else {
zend_bool ns_fallback = key >= orig_key + 2;
const zval *access_key = ns_fallback ? orig_key + 2 : orig_key - 1;
*is_deprecated = is_access_deprecated(c, Z_STRVAL_P(access_key));
}
}
return c;
}

View File

@@ -31,6 +31,9 @@
#define PHP_USER_CONSTANT INT_MAX /* a constant defined in user space */
/* Flag for zend_get_constant_ex(). Must not class with ZEND_FETCH_CLASS_* flags. */
#define ZEND_GET_CONSTANT_NO_DEPRECATION_CHECK 0x1000
typedef struct _zend_constant {
zval value;
zend_string *name;
@@ -79,7 +82,8 @@ ZEND_API int zend_register_constant(zend_constant *c);
#ifdef ZTS
void zend_copy_constants(HashTable *target, HashTable *sourc);
#endif
ZEND_API zend_constant* ZEND_FASTCALL zend_quick_get_constant(const zval *key, uint32_t flags);
ZEND_API zend_constant* ZEND_FASTCALL zend_quick_get_constant(
const zval *key, uint32_t flags, zend_bool *is_deprecated);
END_EXTERN_C()
#define ZEND_CONSTANT_DTOR free_zend_constant

View File

@@ -5045,11 +5045,12 @@ ZEND_VM_HANDLER(99, ZEND_FETCH_CONSTANT, UNUSED|CONST_FETCH, CONST, CACHE_SLOT)
{
USE_OPLINE
zend_constant *c;
zend_bool is_deprecated;
c = CACHED_PTR(opline->extended_value);
if (EXPECTED(c != NULL) && EXPECTED(!IS_SPECIAL_CACHE_VAL(c))) {
/* pass */
} else if (UNEXPECTED((c = zend_quick_get_constant(RT_CONSTANT(opline, opline->op2) + 1, opline->op1.num)) == NULL)) {
} else if (UNEXPECTED((c = zend_quick_get_constant(RT_CONSTANT(opline, opline->op2) + 1, opline->op1.num, &is_deprecated)) == NULL)) {
SAVE_OPLINE();
if ((opline->op1.num & IS_CONSTANT_UNQUALIFIED) != 0) {
@@ -5070,6 +5071,14 @@ ZEND_VM_HANDLER(99, ZEND_FETCH_CONSTANT, UNUSED|CONST_FETCH, CONST, CACHE_SLOT)
ZVAL_UNDEF(EX_VAR(opline->result.var));
HANDLE_EXCEPTION();
}
} else if (is_deprecated) {
SAVE_OPLINE();
zend_error(E_DEPRECATED,
"Case-insensitive constants are deprecated. "
"The correct casing for this constant is \"%s\"",
ZSTR_VAL(c->name));
ZVAL_COPY_OR_DUP(EX_VAR(opline->result.var), &c->value);
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
} else {
CACHE_PTR(opline->extended_value, c);
}
@@ -7611,7 +7620,7 @@ ZEND_VM_HANDLER(122, ZEND_DEFINED, CONST, ANY, CACHE_SLOT)
break;
}
}
if ((c = zend_quick_get_constant(RT_CONSTANT(opline, opline->op1), 0)) == NULL) {
if ((c = zend_quick_get_constant(RT_CONSTANT(opline, opline->op1), 0, NULL)) == NULL) {
CACHE_PTR(opline->extended_value, ENCODE_SPECIAL_CACHE_NUM(zend_hash_num_elements(EG(zend_constants))));
result = 0;
} else {

View File

@@ -3883,7 +3883,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DEFINED_SPEC_CONST_HANDLER(ZEN
break;
}
}
if ((c = zend_quick_get_constant(RT_CONSTANT(opline, opline->op1), 0)) == NULL) {
if ((c = zend_quick_get_constant(RT_CONSTANT(opline, opline->op1), 0, NULL)) == NULL) {
CACHE_PTR(opline->extended_value, ENCODE_SPECIAL_CACHE_NUM(zend_hash_num_elements(EG(zend_constants))));
result = 0;
} else {
@@ -31965,11 +31965,12 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_CONSTANT_SPEC_UNUSED_CON
{
USE_OPLINE
zend_constant *c;
zend_bool is_deprecated;
c = CACHED_PTR(opline->extended_value);
if (EXPECTED(c != NULL) && EXPECTED(!IS_SPECIAL_CACHE_VAL(c))) {
/* pass */
} else if (UNEXPECTED((c = zend_quick_get_constant(RT_CONSTANT(opline, opline->op2) + 1, opline->op1.num)) == NULL)) {
} else if (UNEXPECTED((c = zend_quick_get_constant(RT_CONSTANT(opline, opline->op2) + 1, opline->op1.num, &is_deprecated)) == NULL)) {
SAVE_OPLINE();
if ((opline->op1.num & IS_CONSTANT_UNQUALIFIED) != 0) {
@@ -31990,6 +31991,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_CONSTANT_SPEC_UNUSED_CON
ZVAL_UNDEF(EX_VAR(opline->result.var));
HANDLE_EXCEPTION();
}
} else if (is_deprecated) {
SAVE_OPLINE();
zend_error(E_DEPRECATED,
"Case-insensitive constants are deprecated. "
"The correct casing for this constant is \"%s\"",
ZSTR_VAL(c->name));
ZVAL_COPY_OR_DUP(EX_VAR(opline->result.var), &c->value);
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
} else {
CACHE_PTR(opline->extended_value, c);
}