mirror of
https://github.com/bdnugget/php-src.git
synced 2026-11-10 18:50:50 +00:00
Compare commits
134
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a66aeecc2c | ||
|
|
3424432ec9 | ||
|
|
f733ee1954 | ||
|
|
5070a0f689 | ||
|
|
b4814d7456 | ||
|
|
08b44a47ca | ||
|
|
966ee42d34 | ||
|
|
946e00afd6 | ||
|
|
605d9f55ad | ||
|
|
5e21867c55 | ||
|
|
9ce200f6cb | ||
|
|
b5599a37d7 | ||
|
|
a33d0c3aae | ||
|
|
e8a89c49db | ||
|
|
f3415758d1 | ||
|
|
05d168013a | ||
|
|
1bdd8f7ae4 | ||
|
|
5d31ee302d | ||
|
|
f33105dcb6 | ||
|
|
cfae999f1b | ||
|
|
68f5289e9e | ||
|
|
872f302b8d | ||
|
|
fbd8e20ed5 | ||
|
|
dd7d829896 | ||
|
|
f2364f316d | ||
|
|
7290dc4dcf | ||
|
|
ebf461a025 | ||
|
|
39077deea5 | ||
|
|
c31f9f7ee4 | ||
|
|
48e2e5324e | ||
|
|
0aad77418d | ||
|
|
c321896a37 | ||
|
|
38ad37ad43 | ||
|
|
880bf62224 | ||
|
|
f9fbba41b6 | ||
|
|
3edf5c969a | ||
|
|
41e9a8ebdc | ||
|
|
7a049cd6a4 | ||
|
|
973138f39d | ||
|
|
bc0f78a2da | ||
|
|
94a151a018 | ||
|
|
95a13ca989 | ||
|
|
52ed45745e | ||
|
|
25103c37aa | ||
|
|
35e0506a2e | ||
|
|
f40838eaaa | ||
|
|
8ae02c8a95 | ||
|
|
9450893dc6 | ||
|
|
34ef804b04 | ||
|
|
f674a3343c | ||
|
|
44a311dbbe | ||
|
|
90081c5391 | ||
|
|
66a74f2f4a | ||
|
|
d1b1c04398 | ||
|
|
b7689db7ab | ||
|
|
afc69e46b8 | ||
|
|
5c963731e2 | ||
|
|
dd335359e9 | ||
|
|
5e57f37247 | ||
|
|
6b631f073d | ||
|
|
121790eaff | ||
|
|
764b7bf108 | ||
|
|
9f96b2bdc8 | ||
|
|
821eaaf0b4 | ||
|
|
1b5c62facd | ||
|
|
af7445b9ac | ||
|
|
65f14b0d6c | ||
|
|
abe23bd9a3 | ||
|
|
6e90c75507 | ||
|
|
151fce1129 | ||
|
|
bf2bb39eac | ||
|
|
46d6daea7a | ||
|
|
4d1c1e4554 | ||
|
|
ced4c0bfe6 | ||
|
|
e65932060a | ||
|
|
ec589a27da | ||
|
|
65d7ade684 | ||
|
|
2498385dd9 | ||
|
|
8967e66559 | ||
|
|
8768621149 | ||
|
|
b132da7f9d | ||
|
|
aab23282fc | ||
|
|
e470f9b389 | ||
|
|
434c2b1bdb | ||
|
|
128fca4037 | ||
|
|
2d3d72412a | ||
|
|
cae0bcbab5 | ||
|
|
b2fba0ef62 | ||
|
|
b23c865d15 | ||
|
|
82f9e004da | ||
|
|
2e854791af | ||
|
|
446ad04524 | ||
|
|
abecaab09f | ||
|
|
da0ca53f39 | ||
|
|
56fde2a381 | ||
|
|
13f898b56a | ||
|
|
46a2c6a8d7 | ||
|
|
9cec093b7f | ||
|
|
420184ad52 | ||
|
|
45b638afe0 | ||
|
|
57430e6f1e | ||
|
|
0db6f5267c | ||
|
|
269936e680 | ||
|
|
23bbff2b05 | ||
|
|
ab4c5976d7 | ||
|
|
c1d766171b | ||
|
|
ed19cb6518 | ||
|
|
34aefa36f4 | ||
|
|
959d3c9636 | ||
|
|
7d9ddd61ec | ||
|
|
70dfbe0068 | ||
|
|
288332077f | ||
|
|
b043759cb4 | ||
|
|
27e250880b | ||
|
|
d6731d69bd | ||
|
|
74959b47cd | ||
|
|
2877642037 | ||
|
|
32c6c29d79 | ||
|
|
b67c232189 | ||
|
|
3c68f43251 | ||
|
|
51f57e7b81 | ||
|
|
ab84623108 | ||
|
|
bc166844e3 | ||
|
|
1860ef22eb | ||
|
|
c56701690a | ||
|
|
205d209de9 | ||
|
|
1a66d64717 | ||
|
|
315f3f8dc9 | ||
|
|
f6bd3dfdbc | ||
|
|
118ff03335 | ||
|
|
e586a35fc7 | ||
|
|
078cdd8f76 | ||
|
|
9eea9aae10 | ||
|
|
f1f78ac875 |
No files matched your search
@@ -340,7 +340,8 @@ define ____print_ht
|
||||
end
|
||||
printf "[%d] ", $i
|
||||
if $p->key
|
||||
printf "%s => ", $p->key->val
|
||||
____print_str $p->key->val $p->key->len
|
||||
printf " => "
|
||||
else
|
||||
printf "%d => ", $p->h
|
||||
end
|
||||
|
||||
@@ -1,6 +1,78 @@
|
||||
PHP NEWS
|
||||
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||
17 Dec 2020, PHP 8.0.1RC1
|
||||
04 Feb 2021, PHP 8.0.2
|
||||
|
||||
- Core:
|
||||
. Fixed bug #80523 (bogus parse error on >4GB source code). (Nikita)
|
||||
. Fixed bug #80384 (filter buffers entire read until file closed). (Adam
|
||||
Seitz, cmb)
|
||||
. Fixed bug #80596 (Invalid union type TypeError in anonymous classes).
|
||||
(Daniil Gentili)
|
||||
. Fixed bug #80617 (GCC throws warning about type narrowing in
|
||||
ZEND_TYPE_INIT_CODE). (Nikita)
|
||||
|
||||
- BCMath:
|
||||
. Fixed bug #80545 (bcadd('a', 'a') doesn't throw an exception).
|
||||
(Jens de Nies)
|
||||
|
||||
- Curl:
|
||||
. Fixed bug #80595 (Resetting POSTFIELDS to empty array breaks request). (cmb)
|
||||
|
||||
- Date:
|
||||
. Fixed bug #80376 (last day of the month causes runway cpu usage). (Derick)
|
||||
|
||||
- DOM:
|
||||
. Fixed bug #80537 (Wrong parameter type in DOMElement::removeAttributeNode
|
||||
stub). (Nikita)
|
||||
|
||||
- Filter:
|
||||
. Fixed bug #80584 (0x and 0X are considered valid hex numbers by
|
||||
filter_var()). (girgias)
|
||||
|
||||
- GMP:
|
||||
. Fixed bug #80560 (Strings containing only a base prefix return 0 object).
|
||||
(girgias)
|
||||
|
||||
- Intl:
|
||||
. Fixed bug #80644 (Missing resource causes subsequent get() calls to fail).
|
||||
(Nikita)
|
||||
|
||||
- MySQLi:
|
||||
. Fixed bug #67983 (mysqlnd with MYSQLI_OPT_INT_AND_FLOAT_NATIVE fails to
|
||||
interpret bit columns). (Nikita)
|
||||
. Fixed bug #64638 (Fetching resultsets from stored procedure with cursor
|
||||
fails). (Nikita)
|
||||
. Fixed bug #72862 (segfault using prepared statements on stored procedures
|
||||
that use a cursor). (Nikita)
|
||||
. Fixed bug #77935 (Crash in mysqlnd_fetch_stmt_row_cursor when calling an SP
|
||||
with a cursor). (Nikita)
|
||||
|
||||
- ODBC:
|
||||
. Fixed bug #80592 (all floats are the same in ODBC parameters). (cmb)
|
||||
|
||||
- Opcache:
|
||||
. Fixed bug #80422 (php_opcache.dll crashes when using Apache 2.4 with JIT).
|
||||
(Dmitry)
|
||||
|
||||
- PDO_Firebird:
|
||||
. Fixed bug #80521 (Parameters with underscores no longer recognized). (cmb,
|
||||
Simonov Denis)
|
||||
|
||||
- Phar:
|
||||
. Fixed bug #76929 (zip-based phar does not respect phar.require_hash).
|
||||
(david at bamsoftware, cmb)
|
||||
. Fixed bug #77565 (Incorrect locator detection in ZIP-based phars). (cmb)
|
||||
. Fixed bug #69279 (Compressed ZIP Phar extractTo() creates garbage files).
|
||||
(cmb)
|
||||
|
||||
- Phpdbg:
|
||||
. Reverted fix for bug #76813 (Access violation near NULL on source operand).
|
||||
(cmb)
|
||||
|
||||
- SOAP:
|
||||
. Fixed bug #80672 (Null Dereference in SoapClient). (CVE-2021-21702) (cmb, Stas)
|
||||
|
||||
07 Jan 2021, PHP 8.0.1
|
||||
|
||||
- Core:
|
||||
. Fixed bug #80345 (PHPIZE configuration has outdated PHP_RELEASE_VERSION).
|
||||
@@ -26,6 +98,9 @@ PHP NEWS
|
||||
- Intl:
|
||||
. Fixed bug #80425 (MessageFormatAdapter::getArgTypeList redefined). (Nikita)
|
||||
|
||||
- OCI8
|
||||
. Create Windows DLLs for Oracle Client 19c. (cmb)
|
||||
|
||||
- Opcache:
|
||||
. Fixed bug #80404 (Incorrect range inference result when division results
|
||||
in float). (Nikita)
|
||||
@@ -81,6 +156,8 @@ PHP NEWS
|
||||
. Fixed #62004 (SplFileObject: fgets after seek returns wrong line). (cmb)
|
||||
|
||||
- Standard:
|
||||
. Fixed bug #77423 (FILTER_VALIDATE_URL accepts URLs with invalid userinfo).
|
||||
(CVE-2020-7071) (cmb)
|
||||
. Fixed bug #80366 (Return Value of zend_fstat() not Checked). (sagpant, cmb)
|
||||
|
||||
- Tidy:
|
||||
@@ -469,4 +546,3 @@ PHP NEWS
|
||||
. Fixed bug #71417 (fread() does not report zlib.inflate errors). (cmb)
|
||||
. Fixed bug #78792 (zlib.output_compression disabled by Content-Type: image/).
|
||||
(cmb)
|
||||
|
||||
@@ -888,8 +888,8 @@ PHP 8.0 UPGRADE NOTES
|
||||
and this function is no longer needed to protect against XXE attacks.
|
||||
|
||||
- PGSQL / PDO PGSQL:
|
||||
. The constant PG_VERSION_STR has now the same value as PG_VERSION, and thus
|
||||
is deprecated.
|
||||
. The constant PGSQL_LIBPQ_VERSION_STR has now the same value as
|
||||
PGSQL_LIBPQ_VERSION, and thus is deprecated.
|
||||
. Function aliases in the pgsql extension have been deprecated.
|
||||
|
||||
- Zip:
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
--TEST--
|
||||
Union with anonymous class type
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$a = new class {
|
||||
public function testParam(self|string $a)
|
||||
{
|
||||
}
|
||||
public function test(): self|string
|
||||
{
|
||||
return new \stdClass;
|
||||
}
|
||||
};
|
||||
|
||||
try {
|
||||
$a->testParam(null);
|
||||
} catch (\Throwable $e) {
|
||||
echo $e->getMessage()."\n";
|
||||
}
|
||||
|
||||
try {
|
||||
$a->test();
|
||||
} catch (\Throwable $e) {
|
||||
echo $e->getMessage()."\n";
|
||||
}
|
||||
?>
|
||||
--EXPECTF--
|
||||
class@anonymous(): Argument #1 ($a) must be of type class@anonymous|string, null given, called in %s on line %d
|
||||
class@anonymous::test(): Return value must be of type class@anonymous|string, stdClass returned
|
||||
@@ -0,0 +1,17 @@
|
||||
--TEST--
|
||||
Infinite recursion in unlinked_instanceof()
|
||||
--FILE--
|
||||
<?php
|
||||
interface I {}
|
||||
spl_autoload_register(function() {
|
||||
class X {
|
||||
function test(): I {}
|
||||
}
|
||||
class Y extends X {
|
||||
function test(): C {}
|
||||
}
|
||||
});
|
||||
class C extends Z implements C {}
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Declaration of Y::test(): C must be compatible with X::test(): I in %s on line %d
|
||||
+1
-1
@@ -20,7 +20,7 @@
|
||||
#ifndef ZEND_H
|
||||
#define ZEND_H
|
||||
|
||||
#define ZEND_VERSION "4.0.1RC1"
|
||||
#define ZEND_VERSION "4.0.2"
|
||||
|
||||
#define ZEND_ENGINE_3
|
||||
|
||||
|
||||
+33
-3
@@ -2455,10 +2455,40 @@ ZEND_API zend_result zend_register_functions(zend_class_entry *scope, const zend
|
||||
for (i = 0; i < num_args; i++) {
|
||||
if (ZEND_TYPE_HAS_CLASS(new_arg_info[i].type)) {
|
||||
ZEND_ASSERT(ZEND_TYPE_HAS_NAME(new_arg_info[i].type)
|
||||
&& "Only simple classes are currently supported");
|
||||
&& "Should be stored as simple name");
|
||||
const char *class_name = ZEND_TYPE_LITERAL_NAME(new_arg_info[i].type);
|
||||
ZEND_TYPE_SET_PTR(new_arg_info[i].type,
|
||||
zend_string_init_interned(class_name, strlen(class_name), 1));
|
||||
|
||||
size_t num_types = 1;
|
||||
const char *p = class_name;
|
||||
while ((p = strchr(p, '|'))) {
|
||||
num_types++;
|
||||
p++;
|
||||
}
|
||||
|
||||
if (num_types == 1) {
|
||||
/* Simple class type */
|
||||
ZEND_TYPE_SET_PTR(new_arg_info[i].type,
|
||||
zend_string_init_interned(class_name, strlen(class_name), 1));
|
||||
} else {
|
||||
/* Union type */
|
||||
zend_type_list *list = malloc(ZEND_TYPE_LIST_SIZE(num_types));
|
||||
list->num_types = num_types;
|
||||
ZEND_TYPE_SET_LIST(new_arg_info[i].type, list);
|
||||
|
||||
const char *start = class_name;
|
||||
uint32_t j = 0;
|
||||
while (true) {
|
||||
const char *end = strchr(start, '|');
|
||||
zend_string *str =
|
||||
zend_string_init(start, end ? end - start : strlen(start), 1);
|
||||
list->types[j] = (zend_type) ZEND_TYPE_INIT_CLASS(str, 0, 0);
|
||||
if (!end) {
|
||||
break;
|
||||
}
|
||||
start = end + 1;
|
||||
j++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+13
-3
@@ -1167,7 +1167,15 @@ static zend_string *resolve_class_name(zend_string *name, zend_class_entry *scop
|
||||
name = scope->parent->name;
|
||||
}
|
||||
}
|
||||
return name;
|
||||
|
||||
/* The resolved name for anonymous classes contains null bytes. Cut off everything after the
|
||||
* null byte here, to avoid larger parts of the type being omitted by printing code later. */
|
||||
size_t len = strlen(ZSTR_VAL(name));
|
||||
if (len != ZSTR_LEN(name)) {
|
||||
ZEND_ASSERT(scope && "This should only happen with resolved types");
|
||||
return zend_string_init(ZSTR_VAL(name), len, 0);
|
||||
}
|
||||
return zend_string_copy(name);
|
||||
}
|
||||
|
||||
zend_string *zend_type_to_string_resolved(zend_type type, zend_class_entry *scope) {
|
||||
@@ -1179,11 +1187,13 @@ zend_string *zend_type_to_string_resolved(zend_type type, zend_class_entry *scop
|
||||
if (ZEND_TYPE_HAS_CE(*list_type)) {
|
||||
str = add_type_string(str, ZEND_TYPE_CE(*list_type)->name);
|
||||
} else {
|
||||
str = add_type_string(str, resolve_class_name(ZEND_TYPE_NAME(*list_type), scope));
|
||||
zend_string *resolved = resolve_class_name(ZEND_TYPE_NAME(*list_type), scope);
|
||||
str = add_type_string(str, resolved);
|
||||
zend_string_release(resolved);
|
||||
}
|
||||
} ZEND_TYPE_LIST_FOREACH_END();
|
||||
} else if (ZEND_TYPE_HAS_NAME(type)) {
|
||||
str = zend_string_copy(resolve_class_name(ZEND_TYPE_NAME(type), scope));
|
||||
str = resolve_class_name(ZEND_TYPE_NAME(type), scope);
|
||||
} else if (ZEND_TYPE_HAS_CE(type)) {
|
||||
str = zend_string_copy(ZEND_TYPE_CE(type)->name);
|
||||
}
|
||||
|
||||
+35
-16
@@ -763,6 +763,17 @@ static zend_bool zend_verify_weak_scalar_type_hint(uint32_t type_mask, zval *arg
|
||||
}
|
||||
|
||||
#if ZEND_DEBUG
|
||||
static bool can_convert_to_string(zval *zv) {
|
||||
/* We don't call cast_object here, because this check must be side-effect free. As this
|
||||
* is only used for a sanity check of arginfo/zpp consistency, it's okay if we accept
|
||||
* more than actually allowed here. */
|
||||
if (Z_TYPE_P(zv) == IS_OBJECT) {
|
||||
return Z_OBJ_HT_P(zv)->cast_object != zend_std_cast_object_tostring
|
||||
|| Z_OBJCE_P(zv)->__tostring;
|
||||
}
|
||||
return Z_TYPE_P(zv) <= IS_STRING;
|
||||
}
|
||||
|
||||
/* Used to sanity-check internal arginfo types without performing any actual type conversions. */
|
||||
static zend_bool zend_verify_weak_scalar_type_hint_no_sideeffect(uint32_t type_mask, zval *arg)
|
||||
{
|
||||
@@ -776,10 +787,7 @@ static zend_bool zend_verify_weak_scalar_type_hint_no_sideeffect(uint32_t type_m
|
||||
if ((type_mask & MAY_BE_DOUBLE) && zend_parse_arg_double_weak(arg, &dval)) {
|
||||
return 1;
|
||||
}
|
||||
/* We don't call cast_object here, because this check must be side-effect free. As this
|
||||
* is only used for a sanity check of arginfo/zpp consistency, it's okay if we accept
|
||||
* more than actually allowed here. */
|
||||
if ((type_mask & MAY_BE_STRING) && (Z_TYPE_P(arg) < IS_STRING || Z_TYPE_P(arg) == IS_OBJECT)) {
|
||||
if ((type_mask & MAY_BE_STRING) && can_convert_to_string(arg)) {
|
||||
return 1;
|
||||
}
|
||||
if ((type_mask & MAY_BE_BOOL) == MAY_BE_BOOL && zend_parse_arg_bool_weak(arg, &bval)) {
|
||||
@@ -943,6 +951,13 @@ ZEND_API zend_bool zend_value_instanceof_static(zval *zv) {
|
||||
return instanceof_function(Z_OBJCE_P(zv), called_scope);
|
||||
}
|
||||
|
||||
/* The cache_slot may only be NULL in debug builds, where arginfo verification of
|
||||
* internal functions is enabled. Avoid unnecessary checks in release builds. */
|
||||
#if ZEND_DEBUG
|
||||
# define HAVE_CACHE_SLOT (cache_slot != NULL)
|
||||
#else
|
||||
# define HAVE_CACHE_SLOT 1
|
||||
#endif
|
||||
|
||||
static zend_always_inline zend_bool zend_check_type_slow(
|
||||
zend_type type, zval *arg, zend_reference *ref, void **cache_slot, zend_class_entry *scope,
|
||||
@@ -954,31 +969,39 @@ static zend_always_inline zend_bool zend_check_type_slow(
|
||||
if (ZEND_TYPE_HAS_LIST(type)) {
|
||||
zend_type *list_type;
|
||||
ZEND_TYPE_LIST_FOREACH(ZEND_TYPE_LIST(type), list_type) {
|
||||
if (*cache_slot) {
|
||||
if (HAVE_CACHE_SLOT && *cache_slot) {
|
||||
ce = *cache_slot;
|
||||
} else {
|
||||
ce = zend_fetch_class(ZEND_TYPE_NAME(*list_type),
|
||||
(ZEND_FETCH_CLASS_AUTO | ZEND_FETCH_CLASS_NO_AUTOLOAD));
|
||||
if (!ce) {
|
||||
cache_slot++;
|
||||
if (HAVE_CACHE_SLOT) {
|
||||
cache_slot++;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
*cache_slot = ce;
|
||||
if (HAVE_CACHE_SLOT) {
|
||||
*cache_slot = ce;
|
||||
}
|
||||
}
|
||||
if (instanceof_function(Z_OBJCE_P(arg), ce)) {
|
||||
return 1;
|
||||
}
|
||||
cache_slot++;
|
||||
if (HAVE_CACHE_SLOT) {
|
||||
cache_slot++;
|
||||
}
|
||||
} ZEND_TYPE_LIST_FOREACH_END();
|
||||
} else {
|
||||
if (EXPECTED(*cache_slot)) {
|
||||
if (EXPECTED(HAVE_CACHE_SLOT && *cache_slot)) {
|
||||
ce = (zend_class_entry *) *cache_slot;
|
||||
} else {
|
||||
ce = zend_fetch_class(ZEND_TYPE_NAME(type), (ZEND_FETCH_CLASS_AUTO | ZEND_FETCH_CLASS_NO_AUTOLOAD));
|
||||
if (UNEXPECTED(!ce)) {
|
||||
goto builtin_types;
|
||||
}
|
||||
*cache_slot = (void *) ce;
|
||||
if (HAVE_CACHE_SLOT) {
|
||||
*cache_slot = (void *) ce;
|
||||
}
|
||||
}
|
||||
if (instanceof_function(Z_OBJCE_P(arg), ce)) {
|
||||
return 1;
|
||||
@@ -1071,8 +1094,6 @@ static zend_never_inline ZEND_ATTRIBUTE_UNUSED bool zend_verify_internal_arg_typ
|
||||
|
||||
for (i = 0; i < num_args; ++i) {
|
||||
zend_arg_info *cur_arg_info;
|
||||
void *dummy_cache_slot = NULL;
|
||||
|
||||
if (EXPECTED(i < fbc->common.num_args)) {
|
||||
cur_arg_info = &fbc->common.arg_info[i];
|
||||
} else if (UNEXPECTED(fbc->common.fn_flags & ZEND_ACC_VARIADIC)) {
|
||||
@@ -1082,7 +1103,7 @@ static zend_never_inline ZEND_ATTRIBUTE_UNUSED bool zend_verify_internal_arg_typ
|
||||
}
|
||||
|
||||
if (ZEND_TYPE_IS_SET(cur_arg_info->type)
|
||||
&& UNEXPECTED(!zend_check_type(cur_arg_info->type, arg, &dummy_cache_slot, fbc->common.scope, 0, /* is_internal */ 1))) {
|
||||
&& UNEXPECTED(!zend_check_type(cur_arg_info->type, arg, /* cache_slot */ NULL, fbc->common.scope, 0, /* is_internal */ 1))) {
|
||||
return 0;
|
||||
}
|
||||
arg++;
|
||||
@@ -1207,8 +1228,6 @@ static ZEND_COLD void zend_verify_void_return_error(const zend_function *zf, con
|
||||
static bool zend_verify_internal_return_type(zend_function *zf, zval *ret)
|
||||
{
|
||||
zend_internal_arg_info *ret_info = zf->internal_function.arg_info - 1;
|
||||
void *dummy_cache_slot = NULL;
|
||||
|
||||
if (ZEND_TYPE_FULL_MASK(ret_info->type) & MAY_BE_VOID) {
|
||||
if (UNEXPECTED(Z_TYPE_P(ret) != IS_NULL)) {
|
||||
zend_verify_void_return_error(zf, zend_zval_type_name(ret), "");
|
||||
@@ -1217,7 +1236,7 @@ static bool zend_verify_internal_return_type(zend_function *zf, zval *ret)
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (UNEXPECTED(!zend_check_type(ret_info->type, ret, &dummy_cache_slot, NULL, 1, /* is_internal */ 1))) {
|
||||
if (UNEXPECTED(!zend_check_type(ret_info->type, ret, /* cache_slot */ NULL, NULL, 1, /* is_internal */ 1))) {
|
||||
zend_verify_internal_return_error(zf, ret);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -311,7 +311,8 @@ static zend_bool unlinked_instanceof(zend_class_entry *ce1, zend_class_entry *ce
|
||||
zend_class_entry *ce = zend_lookup_class_ex(
|
||||
ce1->interface_names[i].name, ce1->interface_names[i].lc_name,
|
||||
ZEND_FETCH_CLASS_ALLOW_UNLINKED | ZEND_FETCH_CLASS_NO_AUTOLOAD);
|
||||
if (ce && unlinked_instanceof(ce, ce2)) {
|
||||
/* Avoid recursing if class implements ifself. */
|
||||
if (ce && ce != ce1 && unlinked_instanceof(ce, ce2)) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -177,7 +177,7 @@ static void yy_pop_state(void)
|
||||
zend_stack_del_top(&SCNG(state_stack));
|
||||
}
|
||||
|
||||
static void yy_scan_buffer(char *str, unsigned int len)
|
||||
static void yy_scan_buffer(char *str, size_t len)
|
||||
{
|
||||
YYCURSOR = (YYCTYPE*)str;
|
||||
YYLIMIT = YYCURSOR + len;
|
||||
@@ -571,7 +571,7 @@ ZEND_API zend_result open_file_for_scanning(zend_file_handle *file_handle)
|
||||
}
|
||||
}
|
||||
SCNG(yy_start) = (unsigned char *)buf;
|
||||
yy_scan_buffer(buf, (unsigned int)size);
|
||||
yy_scan_buffer(buf, size);
|
||||
} else {
|
||||
zend_error_noreturn(E_COMPILE_ERROR, "zend_stream_mmap() failed");
|
||||
}
|
||||
@@ -772,7 +772,7 @@ ZEND_API void zend_prepare_string_for_scanning(zval *str, const char *filename)
|
||||
}
|
||||
}
|
||||
|
||||
yy_scan_buffer(buf, (unsigned int)size);
|
||||
yy_scan_buffer(buf, size);
|
||||
|
||||
new_compiled_filename = zend_string_init(filename, strlen(filename), 0);
|
||||
zend_set_compiled_filename(new_compiled_filename);
|
||||
|
||||
@@ -195,6 +195,19 @@ static zend_always_inline zend_string *zend_string_dup(zend_string *s, bool pers
|
||||
}
|
||||
}
|
||||
|
||||
static zend_always_inline zend_string *zend_string_separate(zend_string *s, bool persistent)
|
||||
{
|
||||
if (ZSTR_IS_INTERNED(s) || GC_REFCOUNT(s) > 1) {
|
||||
if (!ZSTR_IS_INTERNED(s)) {
|
||||
GC_DELREF(s);
|
||||
}
|
||||
return zend_string_init(ZSTR_VAL(s), ZSTR_LEN(s), persistent);
|
||||
}
|
||||
|
||||
zend_string_forget_hash_val(s);
|
||||
return s;
|
||||
}
|
||||
|
||||
static zend_always_inline zend_string *zend_string_realloc(zend_string *s, size_t len, bool persistent)
|
||||
{
|
||||
zend_string *ret;
|
||||
|
||||
+1
-1
@@ -150,7 +150,7 @@ typedef struct {
|
||||
/* Type mask excluding the flags above. */
|
||||
#define _ZEND_TYPE_MAY_BE_MASK ((1u << 20) - 1)
|
||||
/* Must have same value as MAY_BE_NULL */
|
||||
#define _ZEND_TYPE_NULLABLE_BIT 0x2
|
||||
#define _ZEND_TYPE_NULLABLE_BIT 0x2u
|
||||
|
||||
#define ZEND_TYPE_IS_SET(t) \
|
||||
(((t).type_mask & _ZEND_TYPE_MASK) != 0)
|
||||
|
||||
+595
-72
@@ -111,7 +111,7 @@ class SimpleType {
|
||||
$this->isBuiltin = $isBuiltin;
|
||||
}
|
||||
|
||||
public static function fromNode(Node $node) {
|
||||
public static function fromNode(Node $node): SimpleType {
|
||||
if ($node instanceof Node\Name) {
|
||||
if ($node->toLowerString() === 'static') {
|
||||
// PHP internally considers "static" a builtin type.
|
||||
@@ -127,11 +127,48 @@ class SimpleType {
|
||||
throw new Exception("Unexpected node type");
|
||||
}
|
||||
|
||||
public function isNull() {
|
||||
public static function fromPhpDoc(string $type): SimpleType
|
||||
{
|
||||
switch (strtolower($type)) {
|
||||
case "void":
|
||||
case "null":
|
||||
case "false":
|
||||
case "bool":
|
||||
case "int":
|
||||
case "float":
|
||||
case "string":
|
||||
case "array":
|
||||
case "iterable":
|
||||
case "object":
|
||||
case "resource":
|
||||
case "mixed":
|
||||
case "self":
|
||||
case "static":
|
||||
return new SimpleType(strtolower($type), true);
|
||||
}
|
||||
|
||||
if (strpos($type, "[]") !== false) {
|
||||
return new SimpleType("array", true);
|
||||
}
|
||||
|
||||
return new SimpleType($type, false);
|
||||
}
|
||||
|
||||
public static function null(): SimpleType
|
||||
{
|
||||
return new SimpleType("null", true);
|
||||
}
|
||||
|
||||
public static function void(): SimpleType
|
||||
{
|
||||
return new SimpleType("void", true);
|
||||
}
|
||||
|
||||
public function isNull(): bool {
|
||||
return $this->isBuiltin && $this->name === 'null';
|
||||
}
|
||||
|
||||
public function toTypeCode() {
|
||||
public function toTypeCode(): string {
|
||||
assert($this->isBuiltin);
|
||||
switch (strtolower($this->name)) {
|
||||
case "bool":
|
||||
@@ -209,19 +246,30 @@ class Type {
|
||||
$this->types = $types;
|
||||
}
|
||||
|
||||
public static function fromNode(Node $node) {
|
||||
public static function fromNode(Node $node): Type {
|
||||
if ($node instanceof Node\UnionType) {
|
||||
return new Type(array_map(['SimpleType', 'fromNode'], $node->types));
|
||||
}
|
||||
if ($node instanceof Node\NullableType) {
|
||||
return new Type([
|
||||
SimpleType::fromNode($node->type),
|
||||
new SimpleType('null', true),
|
||||
SimpleType::null(),
|
||||
]);
|
||||
}
|
||||
return new Type([SimpleType::fromNode($node)]);
|
||||
}
|
||||
|
||||
public static function fromPhpDoc(string $phpDocType) {
|
||||
$types = explode("|", $phpDocType);
|
||||
|
||||
$simpleTypes = [];
|
||||
foreach ($types as $type) {
|
||||
$simpleTypes[] = SimpleType::fromPhpDoc($type);
|
||||
}
|
||||
|
||||
return new Type($simpleTypes);
|
||||
}
|
||||
|
||||
public function isNullable(): bool {
|
||||
foreach ($this->types as $type) {
|
||||
if ($type->isNull()) {
|
||||
@@ -245,20 +293,17 @@ class Type {
|
||||
return null;
|
||||
}
|
||||
|
||||
public function tryToRepresentableType(): ?RepresentableType {
|
||||
$classType = null;
|
||||
public function toArginfoType(): ?ArginfoType {
|
||||
$classTypes = [];
|
||||
$builtinTypes = [];
|
||||
foreach ($this->types as $type) {
|
||||
if ($type->isBuiltin) {
|
||||
$builtinTypes[] = $type;
|
||||
} else if ($classType === null) {
|
||||
$classType = $type;
|
||||
} else {
|
||||
// We can only represent a single class type.
|
||||
return null;
|
||||
$classTypes[] = $type;
|
||||
}
|
||||
}
|
||||
return new RepresentableType($classType, $builtinTypes);
|
||||
return new ArginfoType($classTypes, $builtinTypes);
|
||||
}
|
||||
|
||||
public static function equals(?Type $a, ?Type $b): bool {
|
||||
@@ -278,20 +323,45 @@ class Type {
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function __toString() {
|
||||
if ($this->types === null) {
|
||||
return 'mixed';
|
||||
}
|
||||
|
||||
return implode('|', array_map(
|
||||
function ($type) { return $type->name; },
|
||||
$this->types)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class RepresentableType {
|
||||
/** @var ?SimpleType $classType */
|
||||
public $classType;
|
||||
/** @var SimpleType[] $builtinTypes */
|
||||
public $builtinTypes;
|
||||
class ArginfoType {
|
||||
/** @var ClassType[] $classTypes */
|
||||
public $classTypes;
|
||||
|
||||
public function __construct(?SimpleType $classType, array $builtinTypes) {
|
||||
$this->classType = $classType;
|
||||
/** @var SimpleType[] $builtinTypes */
|
||||
private $builtinTypes;
|
||||
|
||||
public function __construct(array $classTypes, array $builtinTypes) {
|
||||
$this->classTypes = $classTypes;
|
||||
$this->builtinTypes = $builtinTypes;
|
||||
}
|
||||
|
||||
public function hasClassType(): bool {
|
||||
return !empty($this->classTypes);
|
||||
}
|
||||
|
||||
public function toClassTypeString(): string {
|
||||
return implode('|', array_map(function(SimpleType $type) {
|
||||
return $type->toEscapedName();
|
||||
}, $this->classTypes));
|
||||
}
|
||||
|
||||
public function toTypeMask(): string {
|
||||
if (empty($this->builtinTypes)) {
|
||||
return '0';
|
||||
}
|
||||
return implode('|', array_map(function(SimpleType $type) {
|
||||
return $type->toTypeMask();
|
||||
}, $this->builtinTypes));
|
||||
@@ -311,14 +381,17 @@ class ArgInfo {
|
||||
public $isVariadic;
|
||||
/** @var Type|null */
|
||||
public $type;
|
||||
/** @var Type|null */
|
||||
public $phpDocType;
|
||||
/** @var string|null */
|
||||
public $defaultValue;
|
||||
|
||||
public function __construct(string $name, int $sendBy, bool $isVariadic, ?Type $type, ?string $defaultValue) {
|
||||
public function __construct(string $name, int $sendBy, bool $isVariadic, ?Type $type, ?Type $phpDocType, ?string $defaultValue) {
|
||||
$this->name = $name;
|
||||
$this->sendBy = $sendBy;
|
||||
$this->isVariadic = $isVariadic;
|
||||
$this->type = $type;
|
||||
$this->phpDocType = $phpDocType;
|
||||
$this->defaultValue = $defaultValue;
|
||||
}
|
||||
|
||||
@@ -342,22 +415,52 @@ class ArgInfo {
|
||||
throw new Exception("Invalid sendBy value");
|
||||
}
|
||||
|
||||
public function hasDefaultValue(): bool {
|
||||
public function getMethodSynopsisType(): Type {
|
||||
if ($this->type) {
|
||||
return $this->type;
|
||||
}
|
||||
|
||||
if ($this->phpDocType) {
|
||||
return $this->phpDocType;
|
||||
}
|
||||
|
||||
throw new Exception("A parameter must have a type");
|
||||
}
|
||||
|
||||
public function hasProperDefaultValue(): bool {
|
||||
return $this->defaultValue !== null && $this->defaultValue !== "UNKNOWN";
|
||||
}
|
||||
|
||||
public function getDefaultValueString(): string {
|
||||
if ($this->hasDefaultValue()) {
|
||||
public function getDefaultValueAsArginfoString(): string {
|
||||
if ($this->hasProperDefaultValue()) {
|
||||
return '"' . addslashes($this->defaultValue) . '"';
|
||||
}
|
||||
|
||||
return "NULL";
|
||||
}
|
||||
|
||||
public function getDefaultValueAsMethodSynopsisString(): ?string {
|
||||
if ($this->defaultValue === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
switch ($this->defaultValue) {
|
||||
case 'UNKNOWN':
|
||||
return null;
|
||||
case 'false':
|
||||
case 'true':
|
||||
case 'null':
|
||||
return "&{$this->defaultValue};";
|
||||
}
|
||||
|
||||
return $this->defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
interface FunctionOrMethodName {
|
||||
public function getDeclaration(): string;
|
||||
public function getArgInfoName(): string;
|
||||
public function getMethodSynopsisFilename(): string;
|
||||
public function __toString(): string;
|
||||
public function isMethod(): bool;
|
||||
public function isConstructor(): bool;
|
||||
@@ -399,6 +502,10 @@ class FunctionName implements FunctionOrMethodName {
|
||||
return "arginfo_$underscoreName";
|
||||
}
|
||||
|
||||
public function getMethodSynopsisFilename(): string {
|
||||
return implode('_', $this->name->parts);
|
||||
}
|
||||
|
||||
public function __toString(): string {
|
||||
return $this->name->toString();
|
||||
}
|
||||
@@ -439,6 +546,10 @@ class MethodName implements FunctionOrMethodName {
|
||||
return "arginfo_class_{$this->getDeclarationClassName()}_{$this->methodName}";
|
||||
}
|
||||
|
||||
public function getMethodSynopsisFilename(): string {
|
||||
return $this->getDeclarationClassName() . "_{$this->methodName}";
|
||||
}
|
||||
|
||||
public function __toString(): string {
|
||||
return "$this->className::$this->methodName";
|
||||
}
|
||||
@@ -461,16 +572,23 @@ class ReturnInfo {
|
||||
public $byRef;
|
||||
/** @var Type|null */
|
||||
public $type;
|
||||
/** @var Type|null */
|
||||
public $phpDocType;
|
||||
|
||||
public function __construct(bool $byRef, ?Type $type) {
|
||||
public function __construct(bool $byRef, ?Type $type, ?Type $phpDocType) {
|
||||
$this->byRef = $byRef;
|
||||
$this->type = $type;
|
||||
$this->phpDocType = $phpDocType;
|
||||
}
|
||||
|
||||
public function equals(ReturnInfo $other): bool {
|
||||
return $this->byRef === $other->byRef
|
||||
&& Type::equals($this->type, $other->type);
|
||||
}
|
||||
|
||||
public function getMethodSynopsisType(): ?Type {
|
||||
return $this->type ?? $this->phpDocType;
|
||||
}
|
||||
}
|
||||
|
||||
class FuncInfo {
|
||||
@@ -538,6 +656,47 @@ class FuncInfo {
|
||||
return !($this->flags & Class_::MODIFIER_STATIC) && $this->isMethod() && !$this->name->isConstructor();
|
||||
}
|
||||
|
||||
/** @return string[] */
|
||||
public function getModifierNames(): array
|
||||
{
|
||||
if (!$this->isMethod()) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$result = [];
|
||||
|
||||
if ($this->flags & Class_::MODIFIER_FINAL) {
|
||||
$result[] = "final";
|
||||
} elseif ($this->flags & Class_::MODIFIER_ABSTRACT && $this->classFlags & ~Class_::MODIFIER_ABSTRACT) {
|
||||
$result[] = "abstract";
|
||||
}
|
||||
|
||||
if ($this->flags & Class_::MODIFIER_PROTECTED) {
|
||||
$result[] = "protected";
|
||||
} elseif ($this->flags & Class_::MODIFIER_PRIVATE) {
|
||||
$result[] = "private";
|
||||
} else {
|
||||
$result[] = "public";
|
||||
}
|
||||
|
||||
if ($this->flags & Class_::MODIFIER_STATIC) {
|
||||
$result[] = "static";
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function hasParamWithUnknownDefaultValue(): bool
|
||||
{
|
||||
foreach ($this->args as $arg) {
|
||||
if ($arg->defaultValue && !$arg->hasProperDefaultValue()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function equalsApartFromName(FuncInfo $other): bool {
|
||||
if (count($this->args) !== count($other->args)) {
|
||||
return false;
|
||||
@@ -583,13 +742,13 @@ class FuncInfo {
|
||||
return sprintf(
|
||||
"\tZEND_MALIAS(%s, %s, %s, %s, %s)\n",
|
||||
$this->alias->getDeclarationClassName(), $this->name->methodName,
|
||||
$this->alias->methodName, $this->getArgInfoName(), $this->getFlagsAsString()
|
||||
$this->alias->methodName, $this->getArgInfoName(), $this->getFlagsAsArginfoString()
|
||||
);
|
||||
} else if ($this->alias instanceof FunctionName) {
|
||||
return sprintf(
|
||||
"\tZEND_ME_MAPPING(%s, %s, %s, %s)\n",
|
||||
$this->name->methodName, $this->alias->getNonNamespacedName(),
|
||||
$this->getArgInfoName(), $this->getFlagsAsString()
|
||||
$this->getArgInfoName(), $this->getFlagsAsArginfoString()
|
||||
);
|
||||
} else {
|
||||
throw new Error("Cannot happen");
|
||||
@@ -600,14 +759,14 @@ class FuncInfo {
|
||||
return sprintf(
|
||||
"\tZEND_ABSTRACT_ME_WITH_FLAGS(%s, %s, %s, %s)\n",
|
||||
$declarationClassName, $this->name->methodName, $this->getArgInfoName(),
|
||||
$this->getFlagsAsString()
|
||||
$this->getFlagsAsArginfoString()
|
||||
);
|
||||
}
|
||||
|
||||
return sprintf(
|
||||
"\tZEND_ME(%s, %s, %s, %s)\n",
|
||||
$declarationClassName, $this->name->methodName, $this->getArgInfoName(),
|
||||
$this->getFlagsAsString()
|
||||
$this->getFlagsAsArginfoString()
|
||||
);
|
||||
}
|
||||
} else if ($this->name instanceof FunctionName) {
|
||||
@@ -645,7 +804,7 @@ class FuncInfo {
|
||||
}
|
||||
}
|
||||
|
||||
private function getFlagsAsString(): string
|
||||
private function getFlagsAsArginfoString(): string
|
||||
{
|
||||
$flags = "ZEND_ACC_PUBLIC";
|
||||
if ($this->flags & Class_::MODIFIER_PROTECTED) {
|
||||
@@ -673,6 +832,114 @@ class FuncInfo {
|
||||
return $flags;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param FuncInfo[] $funcMap
|
||||
* @param FuncInfo[] $aliasMap
|
||||
* @throws Exception
|
||||
*/
|
||||
public function getMethodSynopsisDocument(array $funcMap, array $aliasMap): ?string {
|
||||
|
||||
$doc = new DOMDocument();
|
||||
$doc->formatOutput = true;
|
||||
$methodSynopsis = $this->getMethodSynopsisElement($funcMap, $aliasMap, $doc);
|
||||
if (!$methodSynopsis) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$doc->appendChild($methodSynopsis);
|
||||
|
||||
return $doc->saveXML();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param FuncInfo[] $funcMap
|
||||
* @param FuncInfo[] $aliasMap
|
||||
* @throws Exception
|
||||
*/
|
||||
public function getMethodSynopsisElement(array $funcMap, array $aliasMap, DOMDocument $doc): ?DOMElement {
|
||||
if ($this->hasParamWithUnknownDefaultValue()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if ($this->name->isConstructor()) {
|
||||
$synopsisType = "constructorsynopsis";
|
||||
} elseif ($this->name->isDestructor()) {
|
||||
$synopsisType = "destructorsynopsis";
|
||||
} else {
|
||||
$synopsisType = "methodsynopsis";
|
||||
}
|
||||
|
||||
$methodSynopsis = $doc->createElement($synopsisType);
|
||||
|
||||
$aliasedFunc = $this->aliasType === "alias" && isset($funcMap[$this->alias->__toString()]) ? $funcMap[$this->alias->__toString()] : null;
|
||||
$aliasFunc = $aliasMap[$this->name->__toString()] ?? null;
|
||||
|
||||
if (($this->aliasType === "alias" && $aliasedFunc !== null && $aliasedFunc->isMethod() !== $this->isMethod()) ||
|
||||
($aliasFunc !== null && $aliasFunc->isMethod() !== $this->isMethod())
|
||||
) {
|
||||
$role = $doc->createAttribute("role");
|
||||
$role->value = $this->isMethod() ? "oop" : "procedural";
|
||||
$methodSynopsis->appendChild($role);
|
||||
}
|
||||
|
||||
$methodSynopsis->appendChild(new DOMText("\n "));
|
||||
|
||||
foreach ($this->getModifierNames() as $modifierString) {
|
||||
$modifierElement = $doc->createElement('modifier', $modifierString);
|
||||
$methodSynopsis->appendChild($modifierElement);
|
||||
$methodSynopsis->appendChild(new DOMText(" "));
|
||||
}
|
||||
|
||||
$returnType = $this->return->getMethodSynopsisType();
|
||||
if ($returnType) {
|
||||
$this->appendMethodSynopsisTypeToElement($doc, $methodSynopsis, $returnType);
|
||||
}
|
||||
|
||||
$methodname = $doc->createElement('methodname', $this->name->__toString());
|
||||
$methodSynopsis->appendChild($methodname);
|
||||
|
||||
if (empty($this->args)) {
|
||||
$methodSynopsis->appendChild(new DOMText("\n "));
|
||||
$void = $doc->createElement('void');
|
||||
$methodSynopsis->appendChild($void);
|
||||
} else {
|
||||
foreach ($this->args as $arg) {
|
||||
$methodSynopsis->appendChild(new DOMText("\n "));
|
||||
$methodparam = $doc->createElement('methodparam');
|
||||
if ($arg->defaultValue !== null) {
|
||||
$methodparam->setAttribute("choice", "opt");
|
||||
}
|
||||
if ($arg->isVariadic) {
|
||||
$methodparam->setAttribute("rep", "repeat");
|
||||
}
|
||||
|
||||
$methodSynopsis->appendChild($methodparam);
|
||||
$this->appendMethodSynopsisTypeToElement($doc, $methodparam, $arg->getMethodSynopsisType());
|
||||
|
||||
$parameter = $doc->createElement('parameter', $arg->name);
|
||||
if ($arg->sendBy !== ArgInfo::SEND_BY_VAL) {
|
||||
$parameter->setAttribute("role", "reference");
|
||||
}
|
||||
|
||||
$methodparam->appendChild($parameter);
|
||||
$defaultValue = $arg->getDefaultValueAsMethodSynopsisString();
|
||||
if ($defaultValue !== null) {
|
||||
$initializer = $doc->createElement('initializer');
|
||||
if (preg_match('/^[a-zA-Z_][a-zA-Z_0-9]*$/', $defaultValue)) {
|
||||
$constant = $doc->createElement('constant', $defaultValue);
|
||||
$initializer->appendChild($constant);
|
||||
} else {
|
||||
$initializer->nodeValue = $defaultValue;
|
||||
}
|
||||
$methodparam->appendChild($initializer);
|
||||
}
|
||||
}
|
||||
}
|
||||
$methodSynopsis->appendChild(new DOMText("\n "));
|
||||
|
||||
return $methodSynopsis;
|
||||
}
|
||||
|
||||
public function discardInfoForOldPhpVersions(): void {
|
||||
$this->return->type = null;
|
||||
foreach ($this->args as $arg) {
|
||||
@@ -680,6 +947,22 @@ class FuncInfo {
|
||||
$arg->defaultValue = null;
|
||||
}
|
||||
}
|
||||
|
||||
private function appendMethodSynopsisTypeToElement(DOMDocument $doc, DOMElement $elementToAppend, Type $type) {
|
||||
if (count($type->types) > 1) {
|
||||
$typeElement = $doc->createElement('type');
|
||||
$typeElement->setAttribute("class", "union");
|
||||
|
||||
foreach ($type->types as $type) {
|
||||
$unionTypeElement = $doc->createElement('type', $type->name);
|
||||
$typeElement->appendChild($unionTypeElement);
|
||||
}
|
||||
} else {
|
||||
$typeElement = $doc->createElement('type', $type->types[0]->name);
|
||||
}
|
||||
|
||||
$elementToAppend->appendChild($typeElement);
|
||||
}
|
||||
}
|
||||
|
||||
class ClassInfo {
|
||||
@@ -736,8 +1019,26 @@ class DocCommentTag {
|
||||
return $this->value;
|
||||
}
|
||||
|
||||
public function getVariableName(): string {
|
||||
public function getType(): string {
|
||||
$value = $this->getValue();
|
||||
|
||||
$matches = [];
|
||||
|
||||
if ($this->name === "param") {
|
||||
preg_match('/^\s*([\w\|\\\\\[\]]+)\s*\$\w+.*$/', $value, $matches);
|
||||
} elseif ($this->name === "return") {
|
||||
preg_match('/^\s*([\w\|\\\\\[\]]+)\s*$/', $value, $matches);
|
||||
}
|
||||
|
||||
if (isset($matches[1]) === false) {
|
||||
throw new Exception("@$this->name doesn't contain a type or has an invalid format \"$value\"");
|
||||
}
|
||||
|
||||
return $matches[1];
|
||||
}
|
||||
|
||||
public function getVariableName(): string {
|
||||
$value = $this->value;
|
||||
if ($value === null || strlen($value) === 0) {
|
||||
throw new Exception("@$this->name doesn't have any value");
|
||||
}
|
||||
@@ -745,13 +1046,13 @@ class DocCommentTag {
|
||||
$matches = [];
|
||||
|
||||
if ($this->name === "param") {
|
||||
preg_match('/^\s*[\w\|\\\\]+\s*\$(\w+).*$/', $value, $matches);
|
||||
preg_match('/^\s*[\w\|\\\\\[\]]+\s*\$(\w+).*$/', $value, $matches);
|
||||
} elseif ($this->name === "prefer-ref") {
|
||||
preg_match('/^\s*\$(\w+).*$/', $value, $matches);
|
||||
}
|
||||
|
||||
if (isset($matches[1]) === false) {
|
||||
throw new Exception("@$this->name doesn't contain variable name or has an invalid format \"$value\"");
|
||||
throw new Exception("@$this->name doesn't contain a variable name or has an invalid format \"$value\"");
|
||||
}
|
||||
|
||||
return $matches[1];
|
||||
@@ -786,7 +1087,7 @@ function parseFunctionLike(
|
||||
$alias = null;
|
||||
$isDeprecated = false;
|
||||
$verify = true;
|
||||
$haveDocReturnType = false;
|
||||
$docReturnType = null;
|
||||
$docParamTypes = [];
|
||||
|
||||
if ($comment) {
|
||||
@@ -811,9 +1112,9 @@ function parseFunctionLike(
|
||||
} else if ($tag->name === 'no-verify') {
|
||||
$verify = false;
|
||||
} else if ($tag->name === 'return') {
|
||||
$haveDocReturnType = true;
|
||||
$docReturnType = $tag->getType();
|
||||
} else if ($tag->name === 'param') {
|
||||
$docParamTypes[$tag->getVariableName()] = true;
|
||||
$docParamTypes[$tag->getVariableName()] = $tag->getType();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -867,6 +1168,7 @@ function parseFunctionLike(
|
||||
$sendBy,
|
||||
$param->variadic,
|
||||
$type,
|
||||
isset($docParamTypes[$varName]) ? Type::fromPhpDoc($docParamTypes[$varName]) : null,
|
||||
$param->default ? $prettyPrinter->prettyPrintExpr($param->default) : null
|
||||
);
|
||||
if (!$param->default && !$param->variadic) {
|
||||
@@ -879,13 +1181,14 @@ function parseFunctionLike(
|
||||
}
|
||||
|
||||
$returnType = $func->getReturnType();
|
||||
if ($returnType === null && !$haveDocReturnType && !$name->isConstructor() && !$name->isDestructor()) {
|
||||
if ($returnType === null && $docReturnType === null && !$name->isConstructor() && !$name->isDestructor()) {
|
||||
throw new Exception("Missing return type for function $name()");
|
||||
}
|
||||
|
||||
$return = new ReturnInfo(
|
||||
$func->returnsByRef(),
|
||||
$returnType ? Type::fromNode($returnType) : null
|
||||
$returnType ? Type::fromNode($returnType) : null,
|
||||
$docReturnType ? Type::fromPhpDoc($docReturnType) : null
|
||||
);
|
||||
|
||||
return new FuncInfo(
|
||||
@@ -1070,24 +1373,23 @@ function funcInfoToCode(FuncInfo $funcInfo): string {
|
||||
$simpleReturnType->toEscapedName(), $returnType->isNullable()
|
||||
);
|
||||
}
|
||||
} else if (null !== $representableType = $returnType->tryToRepresentableType()) {
|
||||
if ($representableType->classType !== null) {
|
||||
} else {
|
||||
$arginfoType = $returnType->toArginfoType();
|
||||
if ($arginfoType->hasClassType()) {
|
||||
$code .= sprintf(
|
||||
"ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(%s, %d, %d, %s, %s)\n",
|
||||
$funcInfo->getArgInfoName(), $funcInfo->return->byRef,
|
||||
$funcInfo->numRequiredArgs,
|
||||
$representableType->classType->toEscapedName(), $representableType->toTypeMask()
|
||||
$arginfoType->toClassTypeString(), $arginfoType->toTypeMask()
|
||||
);
|
||||
} else {
|
||||
$code .= sprintf(
|
||||
"ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(%s, %d, %d, %s)\n",
|
||||
$funcInfo->getArgInfoName(), $funcInfo->return->byRef,
|
||||
$funcInfo->numRequiredArgs,
|
||||
$representableType->toTypeMask()
|
||||
$arginfoType->toTypeMask()
|
||||
);
|
||||
}
|
||||
} else {
|
||||
throw new Exception('Unimplemented');
|
||||
}
|
||||
} else {
|
||||
$code .= sprintf(
|
||||
@@ -1098,7 +1400,7 @@ function funcInfoToCode(FuncInfo $funcInfo): string {
|
||||
|
||||
foreach ($funcInfo->args as $argInfo) {
|
||||
$argKind = $argInfo->isVariadic ? "ARG_VARIADIC" : "ARG";
|
||||
$argDefaultKind = $argInfo->hasDefaultValue() ? "_WITH_DEFAULT_VALUE" : "";
|
||||
$argDefaultKind = $argInfo->hasProperDefaultValue() ? "_WITH_DEFAULT_VALUE" : "";
|
||||
$argType = $argInfo->type;
|
||||
if ($argType !== null) {
|
||||
if (null !== $simpleArgType = $argType->tryToSimpleType()) {
|
||||
@@ -1107,41 +1409,39 @@ function funcInfoToCode(FuncInfo $funcInfo): string {
|
||||
"\tZEND_%s_TYPE_INFO%s(%s, %s, %s, %d%s)\n",
|
||||
$argKind, $argDefaultKind, $argInfo->getSendByString(), $argInfo->name,
|
||||
$simpleArgType->toTypeCode(), $argType->isNullable(),
|
||||
$argInfo->hasDefaultValue() ? ", " . $argInfo->getDefaultValueString() : ""
|
||||
$argInfo->hasProperDefaultValue() ? ", " . $argInfo->getDefaultValueAsArginfoString() : ""
|
||||
);
|
||||
} else {
|
||||
$code .= sprintf(
|
||||
"\tZEND_%s_OBJ_INFO%s(%s, %s, %s, %d%s)\n",
|
||||
$argKind,$argDefaultKind, $argInfo->getSendByString(), $argInfo->name,
|
||||
$simpleArgType->toEscapedName(), $argType->isNullable(),
|
||||
$argInfo->hasDefaultValue() ? ", " . $argInfo->getDefaultValueString() : ""
|
||||
$argInfo->hasProperDefaultValue() ? ", " . $argInfo->getDefaultValueAsArginfoString() : ""
|
||||
);
|
||||
}
|
||||
} else if (null !== $representableType = $argType->tryToRepresentableType()) {
|
||||
if ($representableType->classType !== null) {
|
||||
} else {
|
||||
$arginfoType = $argType->toArginfoType();
|
||||
if ($arginfoType->hasClassType()) {
|
||||
$code .= sprintf(
|
||||
"\tZEND_%s_OBJ_TYPE_MASK(%s, %s, %s, %s, %s)\n",
|
||||
$argKind, $argInfo->getSendByString(), $argInfo->name,
|
||||
$representableType->classType->toEscapedName(),
|
||||
$representableType->toTypeMask(),
|
||||
$argInfo->getDefaultValueString()
|
||||
$arginfoType->toClassTypeString(), $arginfoType->toTypeMask(),
|
||||
$argInfo->getDefaultValueAsArginfoString()
|
||||
);
|
||||
} else {
|
||||
$code .= sprintf(
|
||||
"\tZEND_%s_TYPE_MASK(%s, %s, %s, %s)\n",
|
||||
$argKind, $argInfo->getSendByString(), $argInfo->name,
|
||||
$representableType->toTypeMask(),
|
||||
$argInfo->getDefaultValueString()
|
||||
$arginfoType->toTypeMask(),
|
||||
$argInfo->getDefaultValueAsArginfoString()
|
||||
);
|
||||
}
|
||||
} else {
|
||||
throw new Exception('Unimplemented');
|
||||
}
|
||||
} else {
|
||||
$code .= sprintf(
|
||||
"\tZEND_%s_INFO%s(%s, %s%s)\n",
|
||||
$argKind, $argDefaultKind, $argInfo->getSendByString(), $argInfo->name,
|
||||
$argInfo->hasDefaultValue() ? ", " . $argInfo->getDefaultValueString() : ""
|
||||
$argInfo->hasProperDefaultValue() ? ", " . $argInfo->getDefaultValueAsArginfoString() : ""
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1253,6 +1553,194 @@ function generateFunctionEntries(?Name $className, array $funcInfos): string {
|
||||
return $code;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param FuncInfo[] $funcMap
|
||||
* @param FuncInfo[] $aliasMap
|
||||
* @return array<string, string>
|
||||
*/
|
||||
function generateMethodSynopses(array $funcMap, array $aliasMap): array {
|
||||
$result = [];
|
||||
|
||||
foreach ($funcMap as $funcInfo) {
|
||||
$methodSynopsis = $funcInfo->getMethodSynopsisDocument($funcMap, $aliasMap);
|
||||
if ($methodSynopsis !== null) {
|
||||
$result[$funcInfo->name->getMethodSynopsisFilename() . ".xml"] = $methodSynopsis;
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param FuncInfo[] $funcMap
|
||||
* @param FuncInfo[] $aliasMap
|
||||
* @return array<string, string>
|
||||
*/
|
||||
function replaceMethodSynopses(string $targetDirectory, array $funcMap, array $aliasMap): array {
|
||||
$methodSynopses = [];
|
||||
|
||||
$it = new RecursiveIteratorIterator(
|
||||
new RecursiveDirectoryIterator($targetDirectory),
|
||||
RecursiveIteratorIterator::LEAVES_ONLY
|
||||
);
|
||||
|
||||
foreach ($it as $file) {
|
||||
$pathName = $file->getPathName();
|
||||
if (!preg_match('/\.xml$/i', $pathName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$xml = file_get_contents($pathName);
|
||||
if ($xml === false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (stripos($xml, "<methodsynopsis") === false && stripos($xml, "<constructorsynopsis") === false && stripos($xml, "<destructorsynopsis") === false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$replacedXml = preg_replace("/&([A-Za-z0-9._{}%-]+?;)/", "REPLACED-ENTITY-$1", $xml);
|
||||
|
||||
$doc = new DOMDocument();
|
||||
$doc->formatOutput = false;
|
||||
$doc->preserveWhiteSpace = true;
|
||||
$doc->validateOnParse = true;
|
||||
$success = $doc->loadXML($replacedXml);
|
||||
if (!$success) {
|
||||
echo "Failed opening $pathName\n";
|
||||
continue;
|
||||
}
|
||||
|
||||
$docComparator = new DOMDocument();
|
||||
$docComparator->preserveWhiteSpace = false;
|
||||
$docComparator->formatOutput = true;
|
||||
|
||||
$methodSynopsisElements = [];
|
||||
foreach ($doc->getElementsByTagName("constructorsynopsis") as $element) {
|
||||
$methodSynopsisElements[] = $element;
|
||||
}
|
||||
foreach ($doc->getElementsByTagName("destructorsynopsis") as $element) {
|
||||
$methodSynopsisElements[] = $element;
|
||||
}
|
||||
foreach ($doc->getElementsByTagName("methodsynopsis") as $element) {
|
||||
$methodSynopsisElements[] = $element;
|
||||
}
|
||||
|
||||
foreach ($methodSynopsisElements as $methodSynopsis) {
|
||||
if (!$methodSynopsis instanceof DOMElement) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$list = $methodSynopsis->getElementsByTagName("methodname");
|
||||
$item = $list->item(0);
|
||||
if (!$item instanceof DOMElement) {
|
||||
continue;
|
||||
}
|
||||
$funcName = $item->textContent;
|
||||
if (!isset($funcMap[$funcName])) {
|
||||
continue;
|
||||
}
|
||||
$funcInfo = $funcMap[$funcName];
|
||||
|
||||
$newMethodSynopsis = $funcInfo->getMethodSynopsisElement($funcMap, $aliasMap, $doc);
|
||||
if ($newMethodSynopsis === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Retrieve current signature
|
||||
|
||||
$params = [];
|
||||
$list = $methodSynopsis->getElementsByTagName("methodparam");
|
||||
foreach ($list as $i => $item) {
|
||||
if (!$item instanceof DOMElement) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$paramList = $item->getElementsByTagName("parameter");
|
||||
if ($paramList->count() !== 1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$paramName = $paramList->item(0)->textContent;
|
||||
$paramTypes = [];
|
||||
|
||||
$paramList = $item->getElementsByTagName("type");
|
||||
foreach ($paramList as $type) {
|
||||
if (!$type instanceof DOMElement) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$paramTypes[] = $type->textContent;
|
||||
}
|
||||
|
||||
$params[$paramName] = ["index" => $i, "type" => $paramTypes];
|
||||
}
|
||||
|
||||
// Check if there is any change - short circuit if there is not any.
|
||||
|
||||
$xml1 = $doc->saveXML($methodSynopsis);
|
||||
$xml1 = preg_replace("/&([A-Za-z0-9._{}%-]+?;)/", "REPLACED-ENTITY-$1", $xml1);
|
||||
$docComparator->loadXML($xml1);
|
||||
$xml1 = $docComparator->saveXML();
|
||||
|
||||
$methodSynopsis->parentNode->replaceChild($newMethodSynopsis, $methodSynopsis);
|
||||
|
||||
$xml2 = $doc->saveXML($newMethodSynopsis);
|
||||
$xml2 = preg_replace("/&([A-Za-z0-9._{}%-]+?;)/", "REPLACED-ENTITY-$1", $xml2);
|
||||
$docComparator->loadXML($xml2);
|
||||
$xml2 = $docComparator->saveXML();
|
||||
|
||||
if ($xml1 === $xml2) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Update parameter references
|
||||
|
||||
$paramList = $doc->getElementsByTagName("parameter");
|
||||
/** @var DOMElement $paramElement */
|
||||
foreach ($paramList as $paramElement) {
|
||||
if ($paramElement->parentNode && $paramElement->parentNode->nodeName === "methodparam") {
|
||||
continue;
|
||||
}
|
||||
|
||||
$name = $paramElement->textContent;
|
||||
if (!isset($params[$name])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$index = $params[$name]["index"];
|
||||
if (!isset($funcInfo->args[$index])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$paramElement->textContent = $funcInfo->args[$index]->name;
|
||||
}
|
||||
|
||||
// Return the updated XML
|
||||
|
||||
$replacedXml = $doc->saveXML();
|
||||
|
||||
$replacedXml = preg_replace(
|
||||
[
|
||||
"/REPLACED-ENTITY-([A-Za-z0-9._{}%-]+?;)/",
|
||||
"/<refentry\s+xmlns=\"([a-z0-9.:\/]+)\"\s+xml:id=\"([a-z0-9._-]+)\"\s*>/i",
|
||||
"/<refentry\s+xmlns=\"([a-z0-9.:\/]+)\"\s+xmlns:xlink=\"([a-z0-9.:\/]+)\"\s+xml:id=\"([a-z0-9._-]+)\"\s*>/i",
|
||||
],
|
||||
[
|
||||
"&$1",
|
||||
"<refentry xml:id=\"$2\" xmlns=\"$1\">",
|
||||
"<refentry xml:id=\"$3\" xmlns=\"$1\" xmlns:xlink=\"$2\">",
|
||||
],
|
||||
$replacedXml
|
||||
);
|
||||
|
||||
$methodSynopses[$pathName] = $replacedXml;
|
||||
}
|
||||
}
|
||||
|
||||
return $methodSynopses;
|
||||
}
|
||||
|
||||
function installPhpParser(string $version, string $phpParserDir) {
|
||||
$lockFile = __DIR__ . "/PHP-Parser-install-lock";
|
||||
$lockFd = fopen($lockFile, 'w+');
|
||||
@@ -1318,16 +1806,22 @@ function initPhpParser() {
|
||||
}
|
||||
|
||||
$optind = null;
|
||||
$options = getopt("fh", ["force-regeneration", "parameter-stats", "help", "verify"], $optind);
|
||||
$options = getopt("fh", ["force-regeneration", "parameter-stats", "help", "verify", "generate-methodsynopses", "replace-methodsynopses"], $optind);
|
||||
|
||||
$context = new Context;
|
||||
$printParameterStats = isset($options["parameter-stats"]);
|
||||
$verify = isset($options["verify"]);
|
||||
$generateMethodSynopses = isset($options["generate-methodsynopses"]);
|
||||
$replaceMethodSynopses = isset($options["replace-methodsynopses"]);
|
||||
$context->forceRegeneration = isset($options["f"]) || isset($options["force-regeneration"]);
|
||||
$context->forceParse = $context->forceRegeneration || $printParameterStats || $verify;
|
||||
$context->forceParse = $context->forceRegeneration || $printParameterStats || $verify || $generateMethodSynopses || $replaceMethodSynopses;
|
||||
$targetMethodSynopses = $argv[$optind + 1] ?? null;
|
||||
if ($replaceMethodSynopses && $targetMethodSynopses === null) {
|
||||
die("A target directory must be provided.\n");
|
||||
}
|
||||
|
||||
if (isset($options["h"]) || isset($options["help"])) {
|
||||
die("\nusage: gen-stub.php [ -f | --force-regeneration ] [ --parameter-stats ] [ --verify ] [ -h | --help ] [ name.stub.php | directory ]\n\n");
|
||||
die("\nusage: gen-stub.php [ -f | --force-regeneration ] [ --generate-methodsynopses ] [ --replace-methodsynopses ] [ --parameter-stats ] [ --verify ] [ -h | --help ] [ name.stub.php | directory ] [ directory ]\n\n");
|
||||
}
|
||||
|
||||
$fileInfos = [];
|
||||
@@ -1363,23 +1857,26 @@ if ($printParameterStats) {
|
||||
echo json_encode($parameterStats, JSON_PRETTY_PRINT), "\n";
|
||||
}
|
||||
|
||||
if ($verify) {
|
||||
$errors = [];
|
||||
$funcMap = [];
|
||||
$aliases = [];
|
||||
/** @var FuncInfo[] $funcMap */
|
||||
$funcMap = [];
|
||||
/** @var FuncInfo[] $aliasMap */
|
||||
$aliasMap = [];
|
||||
|
||||
foreach ($fileInfos as $fileInfo) {
|
||||
foreach ($fileInfo->getAllFuncInfos() as $funcInfo) {
|
||||
/** @var FuncInfo $funcInfo */
|
||||
$funcMap[$funcInfo->name->__toString()] = $funcInfo;
|
||||
foreach ($fileInfos as $fileInfo) {
|
||||
foreach ($fileInfo->getAllFuncInfos() as $funcInfo) {
|
||||
/** @var FuncInfo $funcInfo */
|
||||
$funcMap[$funcInfo->name->__toString()] = $funcInfo;
|
||||
|
||||
if ($funcInfo->aliasType === "alias") {
|
||||
$aliases[] = $funcInfo;
|
||||
}
|
||||
if ($funcInfo->aliasType === "alias") {
|
||||
$aliasMap[$funcInfo->alias->__toString()] = $funcInfo;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($aliases as $aliasFunc) {
|
||||
if ($verify) {
|
||||
$errors = [];
|
||||
|
||||
foreach ($aliasMap as $aliasFunc) {
|
||||
if (!isset($funcMap[$aliasFunc->alias->__toString()])) {
|
||||
$errors[] = "Aliased function {$aliasFunc->alias}() cannot be found";
|
||||
continue;
|
||||
@@ -1412,7 +1909,6 @@ if ($verify) {
|
||||
}
|
||||
|
||||
if ($aliasedArg === null) {
|
||||
assert($aliasArg !== null);
|
||||
$errors[] = "{$aliasedFunc->name}(): Argument \$$aliasArg->name of alias function {$aliasFunc->name}() is missing";
|
||||
return null;
|
||||
}
|
||||
@@ -1447,3 +1943,30 @@ if ($verify) {
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
if ($generateMethodSynopses) {
|
||||
$methodSynopsesDirectory = getcwd() . "/methodsynopses";
|
||||
|
||||
$methodSynopses = generateMethodSynopses($funcMap, $aliasMap);
|
||||
if (!empty($methodSynopses)) {
|
||||
if (!file_exists($methodSynopsesDirectory)) {
|
||||
mkdir($methodSynopsesDirectory);
|
||||
}
|
||||
|
||||
foreach ($methodSynopses as $filename => $content) {
|
||||
if (file_put_contents("$methodSynopsesDirectory/$filename", $content)) {
|
||||
echo "Saved $filename\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($replaceMethodSynopses) {
|
||||
$methodSynopses = replaceMethodSynopses($targetMethodSynopses, $funcMap, $aliasMap);
|
||||
|
||||
foreach ($methodSynopses as $filename => $content) {
|
||||
if (file_put_contents($filename, $content)) {
|
||||
echo "Saved $filename\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -17,7 +17,7 @@ dnl Basic autoconf initialization, generation of config.nice.
|
||||
dnl ----------------------------------------------------------------------------
|
||||
|
||||
AC_PREREQ([2.68])
|
||||
AC_INIT([PHP],[8.0.1RC1],[https://bugs.php.net],[php],[https://www.php.net])
|
||||
AC_INIT([PHP],[8.0.2],[https://bugs.php.net],[php],[https://www.php.net])
|
||||
AC_CONFIG_SRCDIR([main/php_version.h])
|
||||
AC_CONFIG_AUX_DIR([build])
|
||||
AC_PRESERVE_HELP_ORDER
|
||||
|
||||
+144
-53
@@ -129,20 +129,23 @@ PHP_MINFO_FUNCTION(bcmath)
|
||||
|
||||
/* {{{ php_str2num
|
||||
Convert to bc_num detecting scale */
|
||||
static void php_str2num(bc_num *num, char *str)
|
||||
static zend_result php_str2num(bc_num *num, char *str)
|
||||
{
|
||||
char *p;
|
||||
|
||||
if (!(p = strchr(str, '.'))) {
|
||||
if (!bc_str2num(num, str, 0)) {
|
||||
php_error_docref(NULL, E_WARNING, "bcmath function argument is not well-formed");
|
||||
return FAILURE;
|
||||
}
|
||||
return;
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
if (!bc_str2num(num, str, strlen(p+1))) {
|
||||
php_error_docref(NULL, E_WARNING, "bcmath function argument is not well-formed");
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
@@ -174,15 +177,26 @@ PHP_FUNCTION(bcadd)
|
||||
bc_init_num(&first);
|
||||
bc_init_num(&second);
|
||||
bc_init_num(&result);
|
||||
php_str2num(&first, ZSTR_VAL(left));
|
||||
php_str2num(&second, ZSTR_VAL(right));
|
||||
|
||||
if (php_str2num(&first, ZSTR_VAL(left)) == FAILURE) {
|
||||
zend_argument_value_error(1, "is not well-formed");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (php_str2num(&second, ZSTR_VAL(right)) == FAILURE) {
|
||||
zend_argument_value_error(2, "is not well-formed");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
bc_add (first, second, &result, scale);
|
||||
|
||||
RETVAL_STR(bc_num2str_ex(result, scale));
|
||||
bc_free_num(&first);
|
||||
bc_free_num(&second);
|
||||
bc_free_num(&result);
|
||||
return;
|
||||
|
||||
cleanup: {
|
||||
bc_free_num(&first);
|
||||
bc_free_num(&second);
|
||||
bc_free_num(&result);
|
||||
};
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
@@ -214,15 +228,26 @@ PHP_FUNCTION(bcsub)
|
||||
bc_init_num(&first);
|
||||
bc_init_num(&second);
|
||||
bc_init_num(&result);
|
||||
php_str2num(&first, ZSTR_VAL(left));
|
||||
php_str2num(&second, ZSTR_VAL(right));
|
||||
|
||||
if (php_str2num(&first, ZSTR_VAL(left)) == FAILURE) {
|
||||
zend_argument_value_error(1, "is not well-formed");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (php_str2num(&second, ZSTR_VAL(right)) == FAILURE) {
|
||||
zend_argument_value_error(2, "is not well-formed");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
bc_sub (first, second, &result, scale);
|
||||
|
||||
RETVAL_STR(bc_num2str_ex(result, scale));
|
||||
bc_free_num(&first);
|
||||
bc_free_num(&second);
|
||||
bc_free_num(&result);
|
||||
return;
|
||||
|
||||
cleanup: {
|
||||
bc_free_num(&first);
|
||||
bc_free_num(&second);
|
||||
bc_free_num(&result);
|
||||
};
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
@@ -254,15 +279,26 @@ PHP_FUNCTION(bcmul)
|
||||
bc_init_num(&first);
|
||||
bc_init_num(&second);
|
||||
bc_init_num(&result);
|
||||
php_str2num(&first, ZSTR_VAL(left));
|
||||
php_str2num(&second, ZSTR_VAL(right));
|
||||
|
||||
if (php_str2num(&first, ZSTR_VAL(left)) == FAILURE) {
|
||||
zend_argument_value_error(1, "is not well-formed");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (php_str2num(&second, ZSTR_VAL(right)) == FAILURE) {
|
||||
zend_argument_value_error(2, "is not well-formed");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
bc_multiply (first, second, &result, scale);
|
||||
|
||||
RETVAL_STR(bc_num2str_ex(result, scale));
|
||||
bc_free_num(&first);
|
||||
bc_free_num(&second);
|
||||
bc_free_num(&result);
|
||||
return;
|
||||
|
||||
cleanup: {
|
||||
bc_free_num(&first);
|
||||
bc_free_num(&second);
|
||||
bc_free_num(&result);
|
||||
};
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
@@ -294,8 +330,16 @@ PHP_FUNCTION(bcdiv)
|
||||
bc_init_num(&first);
|
||||
bc_init_num(&second);
|
||||
bc_init_num(&result);
|
||||
php_str2num(&first, ZSTR_VAL(left));
|
||||
php_str2num(&second, ZSTR_VAL(right));
|
||||
|
||||
if (php_str2num(&first, ZSTR_VAL(left)) == FAILURE) {
|
||||
zend_argument_value_error(1, "is not well-formed");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (php_str2num(&second, ZSTR_VAL(right)) == FAILURE) {
|
||||
zend_argument_value_error(2, "is not well-formed");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
switch (bc_divide(first, second, &result, scale)) {
|
||||
case 0: /* OK */
|
||||
@@ -306,10 +350,11 @@ PHP_FUNCTION(bcdiv)
|
||||
break;
|
||||
}
|
||||
|
||||
bc_free_num(&first);
|
||||
bc_free_num(&second);
|
||||
bc_free_num(&result);
|
||||
return;
|
||||
cleanup: {
|
||||
bc_free_num(&first);
|
||||
bc_free_num(&second);
|
||||
bc_free_num(&result);
|
||||
};
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
@@ -341,8 +386,16 @@ PHP_FUNCTION(bcmod)
|
||||
bc_init_num(&first);
|
||||
bc_init_num(&second);
|
||||
bc_init_num(&result);
|
||||
php_str2num(&first, ZSTR_VAL(left));
|
||||
php_str2num(&second, ZSTR_VAL(right));
|
||||
|
||||
if (php_str2num(&first, ZSTR_VAL(left)) == FAILURE) {
|
||||
zend_argument_value_error(1, "is not well-formed");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (php_str2num(&second, ZSTR_VAL(right)) == FAILURE) {
|
||||
zend_argument_value_error(2, "is not well-formed");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
switch (bc_modulo(first, second, &result, scale)) {
|
||||
case 0:
|
||||
@@ -353,9 +406,11 @@ PHP_FUNCTION(bcmod)
|
||||
break;
|
||||
}
|
||||
|
||||
bc_free_num(&first);
|
||||
bc_free_num(&second);
|
||||
bc_free_num(&result);
|
||||
cleanup: {
|
||||
bc_free_num(&first);
|
||||
bc_free_num(&second);
|
||||
bc_free_num(&result);
|
||||
};
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
@@ -389,18 +444,32 @@ PHP_FUNCTION(bcpowmod)
|
||||
bc_init_num(&second);
|
||||
bc_init_num(&mod);
|
||||
bc_init_num(&result);
|
||||
php_str2num(&first, ZSTR_VAL(left));
|
||||
php_str2num(&second, ZSTR_VAL(right));
|
||||
php_str2num(&mod, ZSTR_VAL(modulus));
|
||||
|
||||
if (php_str2num(&first, ZSTR_VAL(left)) == FAILURE) {
|
||||
zend_argument_value_error(1, "is not well-formed");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (php_str2num(&second, ZSTR_VAL(right)) == FAILURE) {
|
||||
zend_argument_value_error(2, "is not well-formed");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (php_str2num(&mod, ZSTR_VAL(modulus)) == FAILURE) {
|
||||
zend_argument_value_error(3, "is not well-formed");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (bc_raisemod(first, second, mod, &result, scale) == SUCCESS) {
|
||||
RETVAL_STR(bc_num2str_ex(result, scale));
|
||||
}
|
||||
|
||||
bc_free_num(&first);
|
||||
bc_free_num(&second);
|
||||
bc_free_num(&mod);
|
||||
bc_free_num(&result);
|
||||
cleanup: {
|
||||
bc_free_num(&first);
|
||||
bc_free_num(&second);
|
||||
bc_free_num(&mod);
|
||||
bc_free_num(&result);
|
||||
};
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
@@ -432,14 +501,26 @@ PHP_FUNCTION(bcpow)
|
||||
bc_init_num(&first);
|
||||
bc_init_num(&second);
|
||||
bc_init_num(&result);
|
||||
php_str2num(&first, ZSTR_VAL(left));
|
||||
php_str2num(&second, ZSTR_VAL(right));
|
||||
|
||||
if (php_str2num(&first, ZSTR_VAL(left)) == FAILURE) {
|
||||
zend_argument_value_error(1, "is not well-formed");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (php_str2num(&second, ZSTR_VAL(right)) == FAILURE) {
|
||||
zend_argument_value_error(2, "is not well-formed");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
bc_raise (first, second, &result, scale);
|
||||
|
||||
RETVAL_STR(bc_num2str_ex(result, scale));
|
||||
bc_free_num(&first);
|
||||
bc_free_num(&second);
|
||||
bc_free_num(&result);
|
||||
|
||||
cleanup: {
|
||||
bc_free_num(&first);
|
||||
bc_free_num(&second);
|
||||
bc_free_num(&result);
|
||||
};
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
@@ -468,7 +549,11 @@ PHP_FUNCTION(bcsqrt)
|
||||
}
|
||||
|
||||
bc_init_num(&result);
|
||||
php_str2num(&result, ZSTR_VAL(left));
|
||||
|
||||
if (php_str2num(&result, ZSTR_VAL(left)) == FAILURE) {
|
||||
zend_argument_value_error(1, "is not well-formed");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (bc_sqrt (&result, scale) != 0) {
|
||||
RETVAL_STR(bc_num2str_ex(result, scale));
|
||||
@@ -476,8 +561,9 @@ PHP_FUNCTION(bcsqrt)
|
||||
zend_argument_value_error(1, "must be greater than or equal to 0");
|
||||
}
|
||||
|
||||
bc_free_num(&result);
|
||||
return;
|
||||
cleanup: {
|
||||
bc_free_num(&result);
|
||||
};
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
@@ -510,16 +596,21 @@ PHP_FUNCTION(bccomp)
|
||||
bc_init_num(&second);
|
||||
|
||||
if (!bc_str2num(&first, ZSTR_VAL(left), scale)) {
|
||||
php_error_docref(NULL, E_WARNING, "bcmath function argument is not well-formed");
|
||||
zend_argument_value_error(1, "is not well-formed");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (!bc_str2num(&second, ZSTR_VAL(right), scale)) {
|
||||
php_error_docref(NULL, E_WARNING, "bcmath function argument is not well-formed");
|
||||
zend_argument_value_error(2, "is not well-formed");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
RETVAL_LONG(bc_compare(first, second));
|
||||
|
||||
bc_free_num(&first);
|
||||
bc_free_num(&second);
|
||||
return;
|
||||
cleanup: {
|
||||
bc_free_num(&first);
|
||||
bc_free_num(&second);
|
||||
};
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
--TEST--
|
||||
Bug #80545 (bcadd('a', 'a') and bcadd('1', 'a') doesn't throw an exception)
|
||||
--SKIPIF--
|
||||
<?php
|
||||
if (!extension_loaded('bcmath')) die('skip bcmath extension not available');
|
||||
?>
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
try {
|
||||
bcadd('a', 'a');
|
||||
} catch (\ValueError $e) {
|
||||
echo $e->getMessage() . PHP_EOL;
|
||||
}
|
||||
|
||||
try {
|
||||
bcadd('1', 'a');
|
||||
} catch (\ValueError $e) {
|
||||
echo $e->getMessage();
|
||||
}
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
bcadd(): Argument #1 ($num1) is not well-formed
|
||||
bcadd(): Argument #2 ($num2) is not well-formed
|
||||
@@ -14,12 +14,39 @@ echo bcadd("", "2", 2),"\n";
|
||||
echo bcadd("+0", "2"), "\n";
|
||||
echo bcadd("-0", "2"), "\n";
|
||||
|
||||
echo bcadd(" 0", "2");
|
||||
echo bcadd("1e1", "2");
|
||||
echo bcadd("1,1", "2");
|
||||
echo bcadd("Hello", "2");
|
||||
echo bcadd("1 1", "2");
|
||||
echo "\n", "\n";
|
||||
echo "\n";
|
||||
|
||||
try {
|
||||
echo bcadd(" 0", "2");
|
||||
} catch (\ValueError $e) {
|
||||
echo $e->getMessage() . PHP_EOL;
|
||||
}
|
||||
|
||||
try {
|
||||
echo bcadd("1e1", "2");
|
||||
} catch (\ValueError $e) {
|
||||
echo $e->getMessage() . PHP_EOL;
|
||||
}
|
||||
|
||||
try {
|
||||
echo bcadd("1,1", "2");
|
||||
} catch (\ValueError $e) {
|
||||
echo $e->getMessage() . PHP_EOL;
|
||||
}
|
||||
|
||||
try {
|
||||
echo bcadd("Hello", "2");
|
||||
} catch (\ValueError $e) {
|
||||
echo $e->getMessage() . PHP_EOL;
|
||||
}
|
||||
|
||||
try {
|
||||
echo bcadd("1 1", "2");
|
||||
} catch (\ValueError $e) {
|
||||
echo $e->getMessage() . PHP_EOL;
|
||||
}
|
||||
|
||||
echo "\n";
|
||||
|
||||
echo bccomp("1", "2"),"\n";
|
||||
echo bccomp("1.1", "2", 2),"\n";
|
||||
@@ -27,11 +54,38 @@ echo bccomp("", "2"),"\n";
|
||||
echo bccomp("+0", "2"), "\n";
|
||||
echo bccomp("-0", "2"), "\n";
|
||||
|
||||
echo bccomp(" 0", "2");
|
||||
echo bccomp("1e1", "2");
|
||||
echo bccomp("1,1", "2");
|
||||
echo bccomp("Hello", "2");
|
||||
echo bccomp("1 1", "2");
|
||||
echo "\n";
|
||||
|
||||
try {
|
||||
echo bccomp(" 0", "2");
|
||||
} catch (\ValueError $e) {
|
||||
echo $e->getMessage() . PHP_EOL;
|
||||
}
|
||||
|
||||
try {
|
||||
echo bccomp("1e1", "2");
|
||||
} catch (\ValueError $e) {
|
||||
echo $e->getMessage() . PHP_EOL;
|
||||
}
|
||||
|
||||
try {
|
||||
echo bccomp("1,1", "2");
|
||||
} catch (\ValueError $e) {
|
||||
echo $e->getMessage() . PHP_EOL;
|
||||
}
|
||||
|
||||
try {
|
||||
echo bccomp("Hello", "2");
|
||||
} catch (\ValueError $e) {
|
||||
echo $e->getMessage() . PHP_EOL;
|
||||
}
|
||||
|
||||
try {
|
||||
echo bccomp("1 1", "2");
|
||||
} catch (\ValueError $e) {
|
||||
echo $e->getMessage() . PHP_EOL;
|
||||
}
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
3
|
||||
@@ -40,16 +94,11 @@ echo bccomp("1 1", "2");
|
||||
2
|
||||
2
|
||||
|
||||
Warning: bcadd(): bcmath function argument is not well-formed in %s on line %d
|
||||
2
|
||||
Warning: bcadd(): bcmath function argument is not well-formed in %s on line %d
|
||||
2
|
||||
Warning: bcadd(): bcmath function argument is not well-formed in %s on line %d
|
||||
2
|
||||
Warning: bcadd(): bcmath function argument is not well-formed in %s on line %d
|
||||
2
|
||||
Warning: bcadd(): bcmath function argument is not well-formed in %s on line %d
|
||||
2
|
||||
bcadd(): Argument #1 ($num1) is not well-formed
|
||||
bcadd(): Argument #1 ($num1) is not well-formed
|
||||
bcadd(): Argument #1 ($num1) is not well-formed
|
||||
bcadd(): Argument #1 ($num1) is not well-formed
|
||||
bcadd(): Argument #1 ($num1) is not well-formed
|
||||
|
||||
-1
|
||||
-1
|
||||
@@ -57,13 +106,8 @@ Warning: bcadd(): bcmath function argument is not well-formed in %s on line %d
|
||||
-1
|
||||
-1
|
||||
|
||||
Warning: bccomp(): bcmath function argument is not well-formed in %s on line %d
|
||||
-1
|
||||
Warning: bccomp(): bcmath function argument is not well-formed in %s on line %d
|
||||
-1
|
||||
Warning: bccomp(): bcmath function argument is not well-formed in %s on line %d
|
||||
-1
|
||||
Warning: bccomp(): bcmath function argument is not well-formed in %s on line %d
|
||||
-1
|
||||
Warning: bccomp(): bcmath function argument is not well-formed in %s on line %d
|
||||
-1
|
||||
bccomp(): Argument #1 ($num1) is not well-formed
|
||||
bccomp(): Argument #1 ($num1) is not well-formed
|
||||
bccomp(): Argument #1 ($num1) is not well-formed
|
||||
bccomp(): Argument #1 ($num1) is not well-formed
|
||||
bccomp(): Argument #1 ($num1) is not well-formed
|
||||
@@ -2722,7 +2722,14 @@ static int _php_curl_setopt(php_curl *ch, zend_long option, zval *zvalue, bool i
|
||||
|
||||
case CURLOPT_POSTFIELDS:
|
||||
if (Z_TYPE_P(zvalue) == IS_ARRAY) {
|
||||
return build_mime_structure_from_hash(ch, zvalue);
|
||||
if (zend_hash_num_elements(HASH_OF(zvalue)) == 0) {
|
||||
/* no need to build the mime structure for empty hashtables;
|
||||
also works around https://github.com/curl/curl/issues/6455 */
|
||||
curl_easy_setopt(ch->cp, CURLOPT_POSTFIELDS, "");
|
||||
error = curl_easy_setopt(ch->cp, CURLOPT_POSTFIELDSIZE, 0);
|
||||
} else {
|
||||
return build_mime_structure_from_hash(ch, zvalue);
|
||||
}
|
||||
} else {
|
||||
zend_string *tmp_str;
|
||||
zend_string *str = zval_get_tmp_string(zvalue, &tmp_str);
|
||||
|
||||
@@ -25,5 +25,6 @@ string(%d) "POST /get.inc?test=post HTTP/1.1
|
||||
Host: localhost:%d
|
||||
Accept: */*
|
||||
Content-Length: 0
|
||||
Content-Type: application/x-www-form-urlencoded
|
||||
|
||||
"
|
||||
@@ -0,0 +1,30 @@
|
||||
--TEST--
|
||||
Bug #80595 (Resetting POSTFIELDS to empty array breaks request)
|
||||
--SKIPIF--
|
||||
<?php include 'skipif.inc'; ?>
|
||||
--FILE--
|
||||
<?php
|
||||
include 'server.inc';
|
||||
$host = curl_cli_server_start();
|
||||
$ch = curl_init();
|
||||
curl_setopt_array($ch, [
|
||||
CURLOPT_RETURNTRANSFER => true,
|
||||
CURLOPT_POST => true,
|
||||
CURLOPT_URL => "{$host}/get.inc?test=post",
|
||||
]);
|
||||
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, ['foo' => 'bar']);
|
||||
var_dump(curl_exec($ch));
|
||||
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, []);
|
||||
var_dump(curl_exec($ch));
|
||||
?>
|
||||
--EXPECT--
|
||||
string(43) "array(1) {
|
||||
["foo"]=>
|
||||
string(3) "bar"
|
||||
}
|
||||
"
|
||||
string(13) "array(0) {
|
||||
}
|
||||
"
|
||||
+23303
-20532
File diff suppressed because it is too large.
Load diff
+395
-432
File diff suppressed because it is too large.
Load diff
+10
-10
@@ -57,7 +57,7 @@ function date_sub(DateTime $object, DateInterval $interval): DateTime {}
|
||||
|
||||
function date_timezone_get(DateTimeInterface $object): DateTimeZone|false {}
|
||||
|
||||
function date_timezone_set(DateTimeInterface $object, DateTimeZone $timezone): DateTime {}
|
||||
function date_timezone_set(DateTime $object, DateTimeZone $timezone): DateTime {}
|
||||
|
||||
function date_offset_get(DateTimeInterface $object): int {}
|
||||
|
||||
@@ -105,12 +105,12 @@ function date_default_timezone_get(): string {}
|
||||
function date_sunrise(
|
||||
int $timestamp, int $returnFormat = SUNFUNCS_RET_STRING,
|
||||
?float $latitude = null, ?float $longitude = null, ?float $zenith = null,
|
||||
float $utcOffset = 0): string|int|float|false {}
|
||||
?float $utcOffset = null): string|int|float|false {}
|
||||
|
||||
function date_sunset(
|
||||
int $timestamp, int $returnFormat = SUNFUNCS_RET_STRING,
|
||||
?float $latitude = null, ?float $longitude = null, ?float $zenith = null,
|
||||
float $utcOffset = 0): string|int|float|false {}
|
||||
?float $utcOffset = null): string|int|float|false {}
|
||||
|
||||
function date_sun_info(int $timestamp, float $latitude, float $longitude): array {}
|
||||
|
||||
@@ -125,7 +125,7 @@ interface DateTimeInterface
|
||||
/** @return DateTimeZone|false */
|
||||
public function getTimezone();
|
||||
|
||||
/** @return int|false */
|
||||
/** @return int */
|
||||
public function getOffset();
|
||||
|
||||
/** @return int|false */
|
||||
@@ -202,7 +202,7 @@ class DateTime implements DateTimeInterface
|
||||
public function setTimezone(DateTimeZone $timezone) {}
|
||||
|
||||
/**
|
||||
* @return int|false
|
||||
* @return int
|
||||
* @alias date_offset_get
|
||||
*/
|
||||
public function getOffset() {}
|
||||
@@ -238,7 +238,7 @@ class DateTime implements DateTimeInterface
|
||||
public function getTimestamp() {}
|
||||
|
||||
/**
|
||||
* @return DateInterval|false
|
||||
* @return DateInterval
|
||||
* @alias date_diff
|
||||
*/
|
||||
public function diff(DateTimeInterface $targetObject, bool $absolute = false) {}
|
||||
@@ -251,7 +251,7 @@ class DateTimeImmutable implements DateTimeInterface
|
||||
/** @return void */
|
||||
public function __wakeup() {}
|
||||
|
||||
/** @return DateTimeZone */
|
||||
/** @return DateTimeImmutable */
|
||||
public static function __set_state(array $array) {}
|
||||
|
||||
/**
|
||||
@@ -279,7 +279,7 @@ class DateTimeImmutable implements DateTimeInterface
|
||||
public function getTimezone() {}
|
||||
|
||||
/**
|
||||
* @return int|false
|
||||
* @return int
|
||||
* @alias date_offset_get
|
||||
*/
|
||||
public function getOffset() {}
|
||||
@@ -291,7 +291,7 @@ class DateTimeImmutable implements DateTimeInterface
|
||||
public function getTimestamp() {}
|
||||
|
||||
/**
|
||||
* @return DateInterval|false
|
||||
* @return DateInterval
|
||||
* @alias date_diff
|
||||
*/
|
||||
public function diff(DateTimeInterface $targetObject, bool $absolute = false) {}
|
||||
@@ -361,7 +361,7 @@ class DateTimeZone
|
||||
public static function listAbbreviations() {}
|
||||
|
||||
/**
|
||||
* @return array|false
|
||||
* @return array
|
||||
* @alias timezone_identifiers_list
|
||||
*/
|
||||
public static function listIdentifiers(int $timezoneGroup = DateTimeZone::ALL, ?string $countryCode = null) {}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* This is a generated file, edit the .stub.php file instead.
|
||||
* Stub hash: 07d0e6179d838847d4a5d454f8b56438f8df19c0 */
|
||||
* Stub hash: 880a93d8a3461635447318317869fa7d3d7762dd */
|
||||
|
||||
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_strtotime, 0, 1, MAY_BE_LONG|MAY_BE_FALSE)
|
||||
ZEND_ARG_TYPE_INFO(0, datetime, IS_STRING, 0)
|
||||
@@ -110,7 +110,7 @@ ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_date_timezone_get, 0, 1, Dat
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_date_timezone_set, 0, 2, DateTime, 0)
|
||||
ZEND_ARG_OBJ_INFO(0, object, DateTimeInterface, 0)
|
||||
ZEND_ARG_OBJ_INFO(0, object, DateTime, 0)
|
||||
ZEND_ARG_OBJ_INFO(0, timezone, DateTimeZone, 0)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
@@ -214,7 +214,7 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_date_sunrise, 0, 1, MAY_BE_STRIN
|
||||
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, latitude, IS_DOUBLE, 1, "null")
|
||||
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, longitude, IS_DOUBLE, 1, "null")
|
||||
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, zenith, IS_DOUBLE, 1, "null")
|
||||
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, utcOffset, IS_DOUBLE, 0, "0")
|
||||
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, utcOffset, IS_DOUBLE, 1, "null")
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
#define arginfo_date_sunset arginfo_date_sunrise
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
--TEST--
|
||||
Bug #76770 'U' modifier in 'datetime::createFromFormat' adds seconds to other specifiers
|
||||
--FILE--
|
||||
<?php
|
||||
var_dump(datetime::createFromFormat('U H', '3600 01')->getTimestamp());
|
||||
?>
|
||||
--EXPECT--
|
||||
int(3600)
|
||||
@@ -129,7 +129,7 @@ class DOMNodeList implements IteratorAggregate, Countable
|
||||
|
||||
public function getIterator(): Iterator {}
|
||||
|
||||
/** @return ?DOMNode */
|
||||
/** @return DOMNode|null */
|
||||
public function item(int $index) {}
|
||||
}
|
||||
|
||||
@@ -205,7 +205,7 @@ class DOMElement implements DOMParentNode, DOMChildNode
|
||||
public function removeAttributeNS(?string $namespace, string $localName) {}
|
||||
|
||||
/** @return DOMAttr|false */
|
||||
public function removeAttributeNode(string $qualifiedName) {}
|
||||
public function removeAttributeNode(DOMAttr $attr) {}
|
||||
|
||||
/** @return DOMAttr|bool */
|
||||
public function setAttribute(string $qualifiedName, string $value) {}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* This is a generated file, edit the .stub.php file instead.
|
||||
* Stub hash: 128108b08807ce0b125fc7b963bf3c5b77e6987a */
|
||||
* Stub hash: 7cba1a7a34cc4789871faf44fc4794a48db26e61 */
|
||||
|
||||
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_dom_import_simplexml, 0, 1, DOMElement, 1)
|
||||
ZEND_ARG_TYPE_INFO(0, node, IS_OBJECT, 0)
|
||||
@@ -197,7 +197,9 @@ ZEND_END_ARG_INFO()
|
||||
|
||||
#define arginfo_class_DOMElement_removeAttributeNS arginfo_class_DOMElement_getAttributeNS
|
||||
|
||||
#define arginfo_class_DOMElement_removeAttributeNode arginfo_class_DOMElement_getAttribute
|
||||
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_DOMElement_removeAttributeNode, 0, 0, 1)
|
||||
ZEND_ARG_OBJ_INFO(0, attr, DOMAttr, 0)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_DOMElement_setAttribute, 0, 0, 2)
|
||||
ZEND_ARG_TYPE_INFO(0, qualifiedName, IS_STRING, 0)
|
||||
@@ -210,11 +212,9 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_DOMElement_setAttributeNS, 0, 0, 3)
|
||||
ZEND_ARG_TYPE_INFO(0, value, IS_STRING, 0)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_DOMElement_setAttributeNode, 0, 0, 1)
|
||||
ZEND_ARG_OBJ_INFO(0, attr, DOMAttr, 0)
|
||||
ZEND_END_ARG_INFO()
|
||||
#define arginfo_class_DOMElement_setAttributeNode arginfo_class_DOMElement_removeAttributeNode
|
||||
|
||||
#define arginfo_class_DOMElement_setAttributeNodeNS arginfo_class_DOMElement_setAttributeNode
|
||||
#define arginfo_class_DOMElement_setAttributeNodeNS arginfo_class_DOMElement_removeAttributeNode
|
||||
|
||||
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_DOMElement_setIdAttribute, 0, 0, 2)
|
||||
ZEND_ARG_TYPE_INFO(0, qualifiedName, IS_STRING, 0)
|
||||
|
||||
+9
-9
@@ -3865,7 +3865,7 @@ ZEND_METHOD(FFI, cast) /* {{{ */
|
||||
RETURN_OBJ(&cdata->std);
|
||||
} else {
|
||||
zend_wrong_parameter_class_error(2, "FFI\\CData", zv);
|
||||
return;
|
||||
RETURN_THROWS();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4006,7 +4006,7 @@ ZEND_METHOD(FFI, typeof) /* {{{ */
|
||||
}
|
||||
} else {
|
||||
zend_wrong_parameter_class_error(1, "FFI\\CData", zv);
|
||||
return;
|
||||
RETURN_THROWS();
|
||||
}
|
||||
|
||||
ctype = (zend_ffi_ctype*)zend_ffi_ctype_new(zend_ffi_ctype_ce);
|
||||
@@ -4110,7 +4110,7 @@ ZEND_METHOD(FFI, addr) /* {{{ */
|
||||
ZVAL_DEREF(zv);
|
||||
if (Z_TYPE_P(zv) != IS_OBJECT || Z_OBJCE_P(zv) != zend_ffi_cdata_ce) {
|
||||
zend_wrong_parameter_class_error(1, "FFI\\CData", zv);
|
||||
return;
|
||||
RETURN_THROWS();
|
||||
}
|
||||
|
||||
cdata = (zend_ffi_cdata*)Z_OBJ_P(zv);
|
||||
@@ -4165,7 +4165,7 @@ ZEND_METHOD(FFI, sizeof) /* {{{ */
|
||||
type = ZEND_FFI_TYPE(ctype->type);
|
||||
} else {
|
||||
zend_wrong_parameter_class_error(1, "FFI\\CData or FFI\\CType", zv);
|
||||
return;
|
||||
RETURN_THROWS();
|
||||
}
|
||||
|
||||
RETURN_LONG(type->size);
|
||||
@@ -4191,7 +4191,7 @@ ZEND_METHOD(FFI, alignof) /* {{{ */
|
||||
type = ZEND_FFI_TYPE(ctype->type);
|
||||
} else {
|
||||
zend_wrong_parameter_class_error(1, "FFI\\CData or FFI\\CType", zv);
|
||||
return;
|
||||
RETURN_THROWS();
|
||||
}
|
||||
|
||||
RETURN_LONG(type->align);
|
||||
@@ -4246,7 +4246,7 @@ ZEND_METHOD(FFI, memcpy) /* {{{ */
|
||||
}
|
||||
} else {
|
||||
zend_wrong_parameter_class_error(2, "FFI\\CData or string", zv2);
|
||||
return;
|
||||
RETURN_THROWS();
|
||||
}
|
||||
|
||||
memcpy(ptr1, ptr2, size);
|
||||
@@ -4290,7 +4290,7 @@ ZEND_METHOD(FFI, memcmp) /* {{{ */
|
||||
}
|
||||
} else {
|
||||
zend_wrong_parameter_class_error(1, "FFI\\CData or string", zv1);
|
||||
return;
|
||||
RETURN_THROWS();
|
||||
}
|
||||
|
||||
ZVAL_DEREF(zv2);
|
||||
@@ -4314,7 +4314,7 @@ ZEND_METHOD(FFI, memcmp) /* {{{ */
|
||||
}
|
||||
} else {
|
||||
zend_wrong_parameter_class_error(2, "FFI\\CData or string", zv2);
|
||||
return;
|
||||
RETURN_THROWS();
|
||||
}
|
||||
|
||||
ret = memcmp(ptr1, ptr2, size);
|
||||
@@ -4416,7 +4416,7 @@ ZEND_METHOD(FFI, isNull) /* {{{ */
|
||||
ZVAL_DEREF(zv);
|
||||
if (Z_TYPE_P(zv) != IS_OBJECT || Z_OBJCE_P(zv) != zend_ffi_cdata_ce) {
|
||||
zend_wrong_parameter_class_error(1, "FFI\\CData", zv);
|
||||
return;
|
||||
RETURN_THROWS();
|
||||
}
|
||||
|
||||
cdata = (zend_ffi_cdata*)Z_OBJ_P(zv);
|
||||
|
||||
@@ -10,7 +10,7 @@ final class FFI
|
||||
|
||||
public static function load(string $filename): ?FFI {}
|
||||
|
||||
public static function scope(string $name): ?FFI {}
|
||||
public static function scope(string $name): FFI {}
|
||||
|
||||
public static function new(FFI\CType|string $type, bool $owned = true, bool $persistent = false): ?FFI\CData {}
|
||||
|
||||
@@ -18,7 +18,7 @@ final class FFI
|
||||
public static function free(FFI\CData $ptr): void {}
|
||||
|
||||
/**
|
||||
* @param FFI\CData|string|int|null $ptr
|
||||
* @param FFI\CData|int|float|bool|null $ptr
|
||||
* @prefer-ref $ptr
|
||||
*/
|
||||
public static function cast(FFI\CType|string $type, $ptr): ?FFI\CData {}
|
||||
@@ -26,18 +26,18 @@ final class FFI
|
||||
public static function type(string $type): ?FFI\CType {}
|
||||
|
||||
/** @prefer-ref $ptr */
|
||||
public static function typeof(FFI\CData $ptr): ?FFI\CType {}
|
||||
public static function typeof(FFI\CData $ptr): FFI\CType {}
|
||||
|
||||
public static function arrayType(FFI\CType $type, array $dimensions): ?FFI\CType {}
|
||||
public static function arrayType(FFI\CType $type, array $dimensions): FFI\CType {}
|
||||
|
||||
/** @prefer-ref $ptr */
|
||||
public static function addr(FFI\CData $ptr): FFI\CData {}
|
||||
|
||||
/** @prefer-ref $ptr */
|
||||
public static function sizeof(object $ptr): ?int {}
|
||||
public static function sizeof(FFI\CData|FFI\CType $ptr): int {}
|
||||
|
||||
/** @prefer-ref $ptr */
|
||||
public static function alignof(object $ptr): ?int {}
|
||||
public static function alignof(FFI\CData|FFI\CType $ptr): int {}
|
||||
|
||||
/**
|
||||
* @param FFI\CData|string $from
|
||||
@@ -52,13 +52,13 @@ final class FFI
|
||||
* @prefer-ref $ptr2
|
||||
* @param string|FFI\CData $ptr2
|
||||
*/
|
||||
public static function memcmp($ptr1, $ptr2, int $size): ?int {}
|
||||
public static function memcmp($ptr1, $ptr2, int $size): int {}
|
||||
|
||||
/** @prefer-ref $ptr */
|
||||
public static function memset(FFI\CData $ptr, int $value, int $size): void {}
|
||||
|
||||
/** @prefer-ref $ptr */
|
||||
public static function string(FFI\CData $ptr, ?int $size = null): ?string {}
|
||||
public static function string(FFI\CData $ptr, ?int $size = null): string {}
|
||||
|
||||
/** @prefer-ref $ptr */
|
||||
public static function isNull(FFI\CData $ptr): bool {}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* This is a generated file, edit the .stub.php file instead.
|
||||
* Stub hash: abd3bc186ae3f71f2b7eb1d47f3b6bab84fb2bda */
|
||||
* Stub hash: 5aeec68fea7a94cd643464acfb10bf4cfcc863da */
|
||||
|
||||
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_FFI_cdef, 0, 0, FFI, 0)
|
||||
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, code, IS_STRING, 0, "\"\"")
|
||||
@@ -10,7 +10,7 @@ ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_FFI_load, 0, 1, FFI, 1)
|
||||
ZEND_ARG_TYPE_INFO(0, filename, IS_STRING, 0)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_FFI_scope, 0, 1, FFI, 1)
|
||||
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_FFI_scope, 0, 1, FFI, 0)
|
||||
ZEND_ARG_TYPE_INFO(0, name, IS_STRING, 0)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
@@ -33,11 +33,11 @@ ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_FFI_type, 0, 1, FFI\\CType,
|
||||
ZEND_ARG_TYPE_INFO(0, type, IS_STRING, 0)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_FFI_typeof, 0, 1, FFI\\CType, 1)
|
||||
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_FFI_typeof, 0, 1, FFI\\CType, 0)
|
||||
ZEND_ARG_OBJ_INFO(ZEND_SEND_PREFER_REF, ptr, FFI\\CData, 0)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_FFI_arrayType, 0, 2, FFI\\CType, 1)
|
||||
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_FFI_arrayType, 0, 2, FFI\\CType, 0)
|
||||
ZEND_ARG_OBJ_INFO(0, type, FFI\\CType, 0)
|
||||
ZEND_ARG_TYPE_INFO(0, dimensions, IS_ARRAY, 0)
|
||||
ZEND_END_ARG_INFO()
|
||||
@@ -46,8 +46,8 @@ ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_FFI_addr, 0, 1, FFI\\CData,
|
||||
ZEND_ARG_OBJ_INFO(ZEND_SEND_PREFER_REF, ptr, FFI\\CData, 0)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_FFI_sizeof, 0, 1, IS_LONG, 1)
|
||||
ZEND_ARG_TYPE_INFO(ZEND_SEND_PREFER_REF, ptr, IS_OBJECT, 0)
|
||||
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_FFI_sizeof, 0, 1, IS_LONG, 0)
|
||||
ZEND_ARG_OBJ_TYPE_MASK(ZEND_SEND_PREFER_REF, ptr, FFI\\CData|FFI\\CType, 0, NULL)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
#define arginfo_class_FFI_alignof arginfo_class_FFI_sizeof
|
||||
@@ -58,7 +58,7 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_FFI_memcpy, 0, 3, IS_VOID,
|
||||
ZEND_ARG_TYPE_INFO(0, size, IS_LONG, 0)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_FFI_memcmp, 0, 3, IS_LONG, 1)
|
||||
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_FFI_memcmp, 0, 3, IS_LONG, 0)
|
||||
ZEND_ARG_INFO(ZEND_SEND_PREFER_REF, ptr1)
|
||||
ZEND_ARG_INFO(ZEND_SEND_PREFER_REF, ptr2)
|
||||
ZEND_ARG_TYPE_INFO(0, size, IS_LONG, 0)
|
||||
@@ -70,7 +70,7 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_FFI_memset, 0, 3, IS_VOID,
|
||||
ZEND_ARG_TYPE_INFO(0, size, IS_LONG, 0)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_FFI_string, 0, 1, IS_STRING, 1)
|
||||
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_FFI_string, 0, 1, IS_STRING, 0)
|
||||
ZEND_ARG_OBJ_INFO(ZEND_SEND_PREFER_REF, ptr, FFI\\CData, 0)
|
||||
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, size, IS_LONG, 1, "null")
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
@@ -233,6 +233,9 @@ void php_filter_int(PHP_INPUT_FILTER_PARAM_DECL) /* {{{ */
|
||||
p++; len--;
|
||||
if (allow_hex && (*p == 'x' || *p == 'X')) {
|
||||
p++; len--;
|
||||
if (len == 0) {
|
||||
RETURN_VALIDATION_FAILED
|
||||
}
|
||||
if (php_filter_parse_hex(p, len, &ctx_value) < 0) {
|
||||
error = 1;
|
||||
}
|
||||
@@ -553,6 +556,22 @@ void php_filter_validate_domain(PHP_INPUT_FILTER_PARAM_DECL) /* {{{ */
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
static int is_userinfo_valid(zend_string *str)
|
||||
{
|
||||
const char *valid = "-._~!$&'()*+,;=:";
|
||||
const char *p = ZSTR_VAL(str);
|
||||
while (p - ZSTR_VAL(str) < ZSTR_LEN(str)) {
|
||||
if (isalpha(*p) || isdigit(*p) || strchr(valid, *p)) {
|
||||
p++;
|
||||
} else if (*p == '%' && p - ZSTR_VAL(str) <= ZSTR_LEN(str) - 3 && isdigit(*(p+1)) && isxdigit(*(p+2))) {
|
||||
p += 3;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
void php_filter_validate_url(PHP_INPUT_FILTER_PARAM_DECL) /* {{{ */
|
||||
{
|
||||
php_url *url;
|
||||
@@ -608,6 +627,13 @@ bad_url:
|
||||
php_url_free(url);
|
||||
RETURN_VALIDATION_FAILED
|
||||
}
|
||||
|
||||
if (url->user != NULL && !is_userinfo_valid(url->user)) {
|
||||
php_url_free(url);
|
||||
RETURN_VALIDATION_FAILED
|
||||
|
||||
}
|
||||
|
||||
php_url_free(url);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
--TEST--
|
||||
Bug #77423 (parse_url() will deliver a wrong host to user)
|
||||
--FILE--
|
||||
<?php
|
||||
$urls = array(
|
||||
"http://php.net\@aliyun.com/aaa.do",
|
||||
"https://example.com\uFF03@bing.com",
|
||||
);
|
||||
foreach ($urls as $url) {
|
||||
var_dump(filter_var($url, FILTER_VALIDATE_URL));
|
||||
}
|
||||
?>
|
||||
--EXPECT--
|
||||
bool(false)
|
||||
bool(false)
|
||||
@@ -0,0 +1,18 @@
|
||||
--TEST--
|
||||
Bug #80584: "0x" and "0X" are considered valid hex numbers by filter_var()
|
||||
--SKIPIF--
|
||||
<?php
|
||||
if (!extension_loaded('filter')) die('skip filter extension not available');
|
||||
?>
|
||||
--FILE--
|
||||
<?php
|
||||
var_dump(filter_var('0x', FILTER_VALIDATE_INT, FILTER_FLAG_ALLOW_HEX));
|
||||
var_dump(filter_var('0X', FILTER_VALIDATE_INT, FILTER_FLAG_ALLOW_HEX));
|
||||
var_dump(filter_var('', FILTER_VALIDATE_INT, FILTER_FLAG_ALLOW_HEX));
|
||||
var_dump(filter_var('0', FILTER_VALIDATE_INT, FILTER_FLAG_ALLOW_HEX));
|
||||
?>
|
||||
--EXPECT--
|
||||
bool(false)
|
||||
bool(false)
|
||||
bool(false)
|
||||
int(0)
|
||||
+10
-5
@@ -174,7 +174,7 @@ if (IS_GMP(zval)) { \
|
||||
gmp_create(return_value, &gmpnumber)
|
||||
|
||||
static void gmp_strval(zval *result, mpz_t gmpnum, int base);
|
||||
static int convert_to_gmp(mpz_t gmpnumber, zval *val, zend_long base, uint32_t arg_pos);
|
||||
static zend_result convert_to_gmp(mpz_t gmpnumber, zval *val, zend_long base, uint32_t arg_pos);
|
||||
static void gmp_cmp(zval *return_value, zval *a_arg, zval *b_arg);
|
||||
|
||||
/*
|
||||
@@ -429,9 +429,14 @@ static int gmp_compare(zval *op1, zval *op2) /* {{{ */
|
||||
zval result;
|
||||
|
||||
gmp_cmp(&result, op1, op2);
|
||||
if (Z_TYPE(result) == IS_FALSE) {
|
||||
|
||||
/* An error/exception occurs if one of the operands is not a numeric string
|
||||
* or an object which is different from GMP */
|
||||
if (EG(exception)) {
|
||||
return 1;
|
||||
}
|
||||
/* result can only be a zend_long if gmp_cmp hasn't thrown an Error */
|
||||
ZEND_ASSERT(Z_TYPE(result) == IS_LONG);
|
||||
return Z_LVAL(result);
|
||||
}
|
||||
/* }}} */
|
||||
@@ -585,7 +590,7 @@ ZEND_MODULE_INFO_D(gmp)
|
||||
|
||||
/* {{{ convert_to_gmp
|
||||
* Convert zval to be gmp number */
|
||||
static int convert_to_gmp(mpz_t gmpnumber, zval *val, zend_long base, uint32_t arg_pos)
|
||||
static zend_result convert_to_gmp(mpz_t gmpnumber, zval *val, zend_long base, uint32_t arg_pos)
|
||||
{
|
||||
switch (Z_TYPE_P(val)) {
|
||||
case IS_LONG:
|
||||
@@ -596,7 +601,7 @@ static int convert_to_gmp(mpz_t gmpnumber, zval *val, zend_long base, uint32_t a
|
||||
zend_bool skip_lead = 0;
|
||||
int ret;
|
||||
|
||||
if (Z_STRLEN_P(val) > 2 && numstr[0] == '0') {
|
||||
if (Z_STRLEN_P(val) >= 2 && numstr[0] == '0') {
|
||||
if ((base == 0 || base == 16) && (numstr[1] == 'x' || numstr[1] == 'X')) {
|
||||
base = 16;
|
||||
skip_lead = 1;
|
||||
@@ -614,7 +619,7 @@ static int convert_to_gmp(mpz_t gmpnumber, zval *val, zend_long base, uint32_t a
|
||||
"Cannot convert variable to GMP, it is not an integer string");
|
||||
return FAILURE;
|
||||
}
|
||||
zend_argument_type_error(arg_pos, "is not an integer string");
|
||||
zend_argument_value_error(arg_pos, "is not an integer string");
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ Check for number base recognition
|
||||
$test[] = gmp_init("0x4d2", 16);
|
||||
try {
|
||||
$test[] = gmp_init("4d2");
|
||||
} catch (\TypeError $e) {
|
||||
} catch (\ValueError $e) {
|
||||
echo $e->getMessage() . \PHP_EOL;
|
||||
}
|
||||
$test[] = gmp_init("4d2", 16);
|
||||
|
||||
@@ -7,7 +7,7 @@ Bug #66872: Crash when passing string to gmp_testbit
|
||||
|
||||
try {
|
||||
var_dump(gmp_testbit("abc", 1));
|
||||
} catch (\TypeError $e) {
|
||||
} catch (\ValueError $e) {
|
||||
echo $e->getMessage() . \PHP_EOL;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,222 @@
|
||||
--TEST--
|
||||
Bug #80560: Strings containing only a base prefix return 0 object
|
||||
--SKIPIF--
|
||||
<?php if (!extension_loaded("gmp")) print "skip"; ?>
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$functions1 = [
|
||||
'gmp_init',
|
||||
'gmp_export',
|
||||
'gmp_intval',
|
||||
'gmp_strval',
|
||||
'gmp_neg',
|
||||
'gmp_abs',
|
||||
'gmp_fact',
|
||||
'gmp_sqrt',
|
||||
'gmp_sqrtrem',
|
||||
'gmp_perfect_square',
|
||||
'gmp_perfect_power',
|
||||
'gmp_prob_prime',
|
||||
'gmp_sign',
|
||||
'gmp_random_seed',
|
||||
'gmp_popcount',
|
||||
'gmp_com',
|
||||
'gmp_nextprime',
|
||||
];
|
||||
$functions1_need_int_2 = [
|
||||
'gmp_testbit',
|
||||
'gmp_scan0',
|
||||
'gmp_scan1',
|
||||
'gmp_binomial',
|
||||
'gmp_root',
|
||||
'gmp_rootrem',
|
||||
'gmp_pow',
|
||||
];
|
||||
$functions2 = [
|
||||
'gmp_add',
|
||||
'gmp_sub',
|
||||
'gmp_mul',
|
||||
'gmp_div',
|
||||
'gmp_div_q',
|
||||
'gmp_div_r',
|
||||
'gmp_div_qr',
|
||||
'gmp_divexact',
|
||||
'gmp_mod',
|
||||
'gmp_gcd',
|
||||
'gmp_gcdext',
|
||||
'gmp_lcm',
|
||||
'gmp_invert',
|
||||
'gmp_jacobi',
|
||||
'gmp_legendre',
|
||||
'gmp_kronecker',
|
||||
'gmp_cmp',
|
||||
'gmp_random_range',
|
||||
'gmp_and',
|
||||
'gmp_or',
|
||||
'gmp_xor',
|
||||
'gmp_hamdist',
|
||||
];
|
||||
$functions3 = [
|
||||
'gmp_powm',
|
||||
];
|
||||
|
||||
echo 'Explicit base with gmp_init:', \PHP_EOL;
|
||||
echo 'Hexadecimal', \PHP_EOL;
|
||||
try {
|
||||
var_dump(gmp_init('0X', 16));
|
||||
} catch (\ValueError $e) {
|
||||
echo $e->getMessage(), \PHP_EOL;
|
||||
}
|
||||
try {
|
||||
var_dump(gmp_init('0x', 16));
|
||||
} catch (\ValueError $e) {
|
||||
echo $e->getMessage(), \PHP_EOL;
|
||||
}
|
||||
|
||||
echo 'Binary', \PHP_EOL;
|
||||
try {
|
||||
var_dump(gmp_init('0B', 2));
|
||||
} catch (\ValueError $e) {
|
||||
echo $e->getMessage(), \PHP_EOL;
|
||||
}
|
||||
try {
|
||||
var_dump(gmp_init('0b', 2));
|
||||
} catch (\ValueError $e) {
|
||||
echo $e->getMessage(), \PHP_EOL;
|
||||
}
|
||||
|
||||
echo 'Fuzzing gmp functions:', \PHP_EOL;
|
||||
foreach ($functions1 as $function) {
|
||||
try {
|
||||
$function('0B');
|
||||
echo $function, ' failed with 0B', \PHP_EOL;
|
||||
} catch (\ValueError) { }
|
||||
try {
|
||||
$function('0b');
|
||||
echo $function, ' failed with 0b', \PHP_EOL;
|
||||
} catch (\ValueError) { }
|
||||
try {
|
||||
$function('0X');
|
||||
echo $function, ' failed with 0X', \PHP_EOL;
|
||||
} catch (\ValueError) { }
|
||||
try {
|
||||
$function('0x');
|
||||
echo $function, ' failed with 0x', \PHP_EOL;
|
||||
} catch (\ValueError) { }
|
||||
}
|
||||
foreach ($functions1_need_int_2 as $function) {
|
||||
try {
|
||||
$function('0B', 1);
|
||||
echo $function, ' failed with 0B', \PHP_EOL;
|
||||
} catch (\ValueError) { }
|
||||
try {
|
||||
$function('0b', 1);
|
||||
echo $function, ' failed with 0b', \PHP_EOL;
|
||||
} catch (\ValueError) { }
|
||||
try {
|
||||
$function('0X', 1);
|
||||
echo $function, ' failed with 0X', \PHP_EOL;
|
||||
} catch (\ValueError) { }
|
||||
try {
|
||||
$function('0x', 1);
|
||||
echo $function, ' failed with 0x', \PHP_EOL;
|
||||
} catch (\ValueError) { }
|
||||
}
|
||||
foreach ($functions2 as $function) {
|
||||
try {
|
||||
$function('0B', 1);
|
||||
echo $function, ' arg 1 failed with 0B', \PHP_EOL;
|
||||
} catch (\ValueError) { }
|
||||
try {
|
||||
$function('0b', 1);
|
||||
echo $function, ' arg 1 failed with 0b', \PHP_EOL;
|
||||
} catch (\ValueError) { }
|
||||
try {
|
||||
$function('0X', 1);
|
||||
echo $function, ' arg 1 failed with 0X', \PHP_EOL;
|
||||
} catch (\ValueError) { }
|
||||
try {
|
||||
$function('0x', 1);
|
||||
echo $function, ' arg 1 failed with 0x', \PHP_EOL;
|
||||
} catch (\ValueError) { }
|
||||
try {
|
||||
$function(1, '0B');
|
||||
echo $function, ' arg 2 failed with 0B', \PHP_EOL;
|
||||
} catch (\ValueError) { }
|
||||
try {
|
||||
$function(1, '0b');
|
||||
echo $function, ' arg 2 failed with 0b', \PHP_EOL;
|
||||
} catch (\ValueError) { }
|
||||
try {
|
||||
$function(1, '0X');
|
||||
echo $function, ' arg 2 failed with 0X', \PHP_EOL;
|
||||
} catch (\ValueError) { }
|
||||
try {
|
||||
$function(1, '0x');
|
||||
echo $function, ' arg 2 failed with 0x', \PHP_EOL;
|
||||
} catch (\ValueError) { }
|
||||
}
|
||||
foreach ($functions3 as $function) {
|
||||
try {
|
||||
$function('0B', 1, 1);
|
||||
echo $function, ' arg 1 failed with 0B', \PHP_EOL;
|
||||
} catch (\ValueError) { }
|
||||
try {
|
||||
$function('0b', 1, 1);
|
||||
echo $function, ' arg 1 failed with 0b', \PHP_EOL;
|
||||
} catch (\ValueError) { }
|
||||
try {
|
||||
$function('0X', 1, 1);
|
||||
echo $function, ' arg 1 failed with 0X', \PHP_EOL;
|
||||
} catch (\ValueError) { }
|
||||
try {
|
||||
$function('0x', 1, 1);
|
||||
echo $function, ' arg 1 failed with 0x', \PHP_EOL;
|
||||
} catch (\ValueError) { }
|
||||
try {
|
||||
$function(1, '0B', 1);
|
||||
echo $function, ' arg 2 failed with 0B', \PHP_EOL;
|
||||
} catch (\ValueError) { }
|
||||
try {
|
||||
$function(1, '0b', 1);
|
||||
echo $function, ' arg 2 failed with 0b', \PHP_EOL;
|
||||
} catch (\ValueError) { }
|
||||
try {
|
||||
$function(1, '0X', 1);
|
||||
echo $function, ' arg 2 failed with 0X', \PHP_EOL;
|
||||
} catch (\ValueError) { }
|
||||
try {
|
||||
$function(1, '0x', 1);
|
||||
echo $function, ' arg 2 failed with 0x', \PHP_EOL;
|
||||
} catch (\ValueError) { }
|
||||
try {
|
||||
$function(1, 1, '0B');
|
||||
echo $function, ' arg 3 failed with 0B', \PHP_EOL;
|
||||
} catch (\ValueError) { }
|
||||
try {
|
||||
$function(1, 1, '0b');
|
||||
echo $function, ' arg 3 failed with 0b', \PHP_EOL;
|
||||
} catch (\ValueError) { }
|
||||
try {
|
||||
$function(1, 1, '0X');
|
||||
echo $function, ' arg 3 failed with 0X', \PHP_EOL;
|
||||
} catch (\ValueError) { }
|
||||
try {
|
||||
$function(1, 1, '0x');
|
||||
echo $function, ' arg 3 failed with 0x', \PHP_EOL;
|
||||
} catch (\ValueError) { }
|
||||
}
|
||||
|
||||
echo "Done\n";
|
||||
?>
|
||||
--EXPECT--
|
||||
Explicit base with gmp_init:
|
||||
Hexadecimal
|
||||
gmp_init(): Argument #1 ($num) is not an integer string
|
||||
gmp_init(): Argument #1 ($num) is not an integer string
|
||||
Binary
|
||||
gmp_init(): Argument #1 ($num) is not an integer string
|
||||
gmp_init(): Argument #1 ($num) is not an integer string
|
||||
Fuzzing gmp functions:
|
||||
Done
|
||||
@@ -0,0 +1,23 @@
|
||||
--TEST--
|
||||
Invalid comparison with a GMP object
|
||||
--SKIPIF--
|
||||
<?php if (!extension_loaded("gmp")) print "skip"; ?>
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
try {
|
||||
var_dump("hapfegfbu" > gmp_init(0));
|
||||
} catch (\Error $e) {
|
||||
echo $e::class, ': ', $e->getMessage(), \PHP_EOL;
|
||||
}
|
||||
|
||||
try {
|
||||
var_dump((new DateTime()) > gmp_init(0));
|
||||
} catch (\Error $e) {
|
||||
echo $e::class, ': ', $e->getMessage(), \PHP_EOL;
|
||||
}
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
ValueError: main(): Argument #2 is not an integer string
|
||||
TypeError: main(): Argument #2 must be of type GMP|string|int, DateTime given
|
||||
@@ -7,7 +7,7 @@ gmp_abs() basic tests
|
||||
|
||||
try {
|
||||
var_dump(gmp_strval(gmp_abs("")));
|
||||
} catch (\TypeError $e) {
|
||||
} catch (\ValueError $e) {
|
||||
echo $e->getMessage() . \PHP_EOL;
|
||||
}
|
||||
var_dump(gmp_strval(gmp_abs("0")));
|
||||
@@ -24,13 +24,13 @@ var_dump(gmp_strval(gmp_abs("0000")));
|
||||
try {
|
||||
// Base 8
|
||||
var_dump(gmp_strval(gmp_abs("09876543")));
|
||||
} catch (\TypeError $e) {
|
||||
} catch (\ValueError $e) {
|
||||
echo $e->getMessage() . \PHP_EOL;
|
||||
}
|
||||
try {
|
||||
// Base 8
|
||||
var_dump(gmp_strval(gmp_abs("-099987654")));
|
||||
} catch (\TypeError $e) {
|
||||
} catch (\ValueError $e) {
|
||||
echo $e->getMessage() . \PHP_EOL;
|
||||
}
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ var_dump(gmp_strval(gmp_and(4545, -20)));
|
||||
|
||||
try {
|
||||
var_dump(gmp_strval(gmp_and("test", "no test")));
|
||||
} catch (\TypeError $e) {
|
||||
} catch (\ValueError $e) {
|
||||
echo $e->getMessage() . \PHP_EOL;
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ var_dump(gmp_strval(gmp_com(0)));
|
||||
var_dump(gmp_strval(gmp_com("0")));
|
||||
try {
|
||||
var_dump(gmp_strval(gmp_com("test")));
|
||||
} catch (\TypeError $e) {
|
||||
} catch (\ValueError $e) {
|
||||
echo $e->getMessage() . \PHP_EOL;
|
||||
}
|
||||
var_dump(gmp_strval(gmp_com("2394876545678")));
|
||||
|
||||
@@ -8,7 +8,7 @@ gmp_fact() basic tests
|
||||
var_dump(gmp_strval(gmp_fact(0)));
|
||||
try {
|
||||
var_dump(gmp_strval(gmp_fact("")));
|
||||
} catch (\TypeError $e) {
|
||||
} catch (\ValueError $e) {
|
||||
echo $e->getMessage() . \PHP_EOL;
|
||||
}
|
||||
var_dump(gmp_strval(gmp_fact("0")));
|
||||
|
||||
@@ -15,17 +15,17 @@ try {
|
||||
|
||||
try {
|
||||
var_dump(gmp_init("",36));
|
||||
} catch (\TypeError $e) {
|
||||
} catch (\ValueError $e) {
|
||||
echo $e->getMessage() . \PHP_EOL;
|
||||
}
|
||||
try {
|
||||
var_dump(gmp_init("foo",3));
|
||||
} catch (\TypeError $e) {
|
||||
} catch (\ValueError $e) {
|
||||
echo $e->getMessage() . \PHP_EOL;
|
||||
}
|
||||
try {
|
||||
var_dump(gmp_strval(gmp_init("993247326237679187178",3)));
|
||||
} catch (\TypeError $e) {
|
||||
} catch (\ValueError $e) {
|
||||
echo $e->getMessage() . \PHP_EOL;
|
||||
}
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ var_dump(gmp_intval($g));
|
||||
|
||||
try {
|
||||
var_dump(gmp_intval(""));
|
||||
} catch (TypeError $e) {
|
||||
} catch (ValueError $e) {
|
||||
echo $e->getMessage(), "\n";
|
||||
}
|
||||
try {
|
||||
@@ -31,7 +31,7 @@ try {
|
||||
}
|
||||
try {
|
||||
var_dump(gmp_intval("1.0001"));
|
||||
} catch (TypeError $e) {
|
||||
} catch (ValueError $e) {
|
||||
echo $e->getMessage(), "\n";
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ gmp_mod tests()
|
||||
|
||||
try {
|
||||
var_dump(gmp_mod("",""));
|
||||
} catch (\TypeError $e) {
|
||||
} catch (\ValueError $e) {
|
||||
echo $e->getMessage() . \PHP_EOL;
|
||||
}
|
||||
var_dump(gmp_mod(0,1));
|
||||
|
||||
@@ -12,7 +12,7 @@ var_dump(gmp_intval(gmp_neg("-1")));
|
||||
|
||||
try {
|
||||
var_dump(gmp_intval(gmp_neg("")));
|
||||
} catch (\TypeError $e) {
|
||||
} catch (\ValueError $e) {
|
||||
echo $e->getMessage() . \PHP_EOL;
|
||||
}
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ try {
|
||||
try {
|
||||
$n = gmp_nextprime("");
|
||||
var_dump(gmp_strval($n));
|
||||
} catch (\TypeError $e) {
|
||||
} catch (\ValueError $e) {
|
||||
echo $e->getMessage() . \PHP_EOL;
|
||||
}
|
||||
try {
|
||||
|
||||
@@ -13,7 +13,7 @@ var_dump(gmp_strval(gmp_or(4545, -20)));
|
||||
|
||||
try {
|
||||
var_dump(gmp_strval(gmp_or("test", "no test")));
|
||||
} catch (\TypeError $e) {
|
||||
} catch (\ValueError $e) {
|
||||
echo $e->getMessage() . \PHP_EOL;
|
||||
}
|
||||
|
||||
|
||||
@@ -108,7 +108,7 @@ var_dump(gmp_strval(gmp_random_range(-10000, 0)));
|
||||
// standard non conversion error
|
||||
try {
|
||||
var_dump(gmp_random_seed('not a number'));
|
||||
} catch (\TypeError $e) {
|
||||
} catch (\ValueError $e) {
|
||||
echo $e->getMessage() . \PHP_EOL;
|
||||
}
|
||||
|
||||
|
||||
@@ -13,13 +13,13 @@ var_dump(gmp_sign("-34535345345"));
|
||||
|
||||
try {
|
||||
var_dump(gmp_sign("+34534573457345"));
|
||||
} catch (\TypeError $e) {
|
||||
} catch (\ValueError $e) {
|
||||
echo $e->getMessage() . \PHP_EOL;
|
||||
}
|
||||
try {
|
||||
$n = gmp_init("098909878976786545");
|
||||
var_dump(gmp_sign($n));
|
||||
} catch (\TypeError $e) {
|
||||
} catch (\ValueError $e) {
|
||||
echo $e->getMessage() . \PHP_EOL;
|
||||
}
|
||||
try {
|
||||
|
||||
@@ -7,7 +7,7 @@ gmp_strval() tests
|
||||
|
||||
try {
|
||||
var_dump(gmp_strval(""));
|
||||
} catch (\TypeError $e) {
|
||||
} catch (\ValueError $e) {
|
||||
echo $e->getMessage() . \PHP_EOL;
|
||||
}
|
||||
try {
|
||||
|
||||
@@ -7,7 +7,7 @@ gmp_sub() tests
|
||||
|
||||
try {
|
||||
var_dump(gmp_sub("", ""));
|
||||
} catch (\TypeError $e) {
|
||||
} catch (\ValueError $e) {
|
||||
echo $e->getMessage() . \PHP_EOL;
|
||||
}
|
||||
try {
|
||||
|
||||
@@ -13,7 +13,7 @@ var_dump(gmp_strval(gmp_xor(4545, -20)));
|
||||
|
||||
try {
|
||||
var_dump(gmp_strval(gmp_xor("test", "no test")));
|
||||
} catch (\TypeError $e) {
|
||||
} catch (\ValueError $e) {
|
||||
echo $e->getMessage() . \PHP_EOL;
|
||||
}
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ function imap_close($imap, int $flags = 0): bool {}
|
||||
function imap_num_msg($imap): int|false {}
|
||||
|
||||
/** @param resource $imap */
|
||||
function imap_num_recent($imap): int|false {}
|
||||
function imap_num_recent($imap): int {}
|
||||
|
||||
/** @param resource $imap */
|
||||
function imap_headers($imap): array|false {}
|
||||
@@ -179,7 +179,7 @@ function imap_sort($imap, int $criteria, bool $reverse, int $flags = 0, ?string
|
||||
function imap_uid($imap, int $message_num): int|false {}
|
||||
|
||||
/** @param resource $imap */
|
||||
function imap_msgno($imap, int $message_uid): int|false {}
|
||||
function imap_msgno($imap, int $message_uid): int {}
|
||||
|
||||
/** @param resource $imap */
|
||||
function imap_list($imap, string $reference, string $pattern): array|false {}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* This is a generated file, edit the .stub.php file instead.
|
||||
* Stub hash: 326cb0410034aecc702e9397cd88ef91adaa254c */
|
||||
* Stub hash: d6d158112a802d867646b8f85402b8762599180b */
|
||||
|
||||
ZEND_BEGIN_ARG_INFO_EX(arginfo_imap_open, 0, 0, 3)
|
||||
ZEND_ARG_TYPE_INFO(0, mailbox, IS_STRING, 0)
|
||||
@@ -26,7 +26,9 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_imap_num_msg, 0, 1, MAY_BE_LONG|
|
||||
ZEND_ARG_INFO(0, imap)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
#define arginfo_imap_num_recent arginfo_imap_num_msg
|
||||
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_imap_num_recent, 0, 1, IS_LONG, 0)
|
||||
ZEND_ARG_INFO(0, imap)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_imap_headers, 0, 1, MAY_BE_ARRAY|MAY_BE_FALSE)
|
||||
ZEND_ARG_INFO(0, imap)
|
||||
@@ -218,7 +220,7 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_imap_uid, 0, 2, MAY_BE_LONG|MAY_
|
||||
ZEND_ARG_TYPE_INFO(0, message_num, IS_LONG, 0)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_imap_msgno, 0, 2, MAY_BE_LONG|MAY_BE_FALSE)
|
||||
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_imap_msgno, 0, 2, IS_LONG, 0)
|
||||
ZEND_ARG_INFO(0, imap)
|
||||
ZEND_ARG_TYPE_INFO(0, message_uid, IS_LONG, 0)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
@@ -8,7 +8,7 @@ class IntlCalendar
|
||||
|
||||
/**
|
||||
* @param IntlTimeZone|DateTimeZone|string|null $timezone
|
||||
* @return IntlCalendar|IntlGregorianCalendar|null
|
||||
* @return IntlCalendar|null
|
||||
* @alias intlcal_create_instance
|
||||
*/
|
||||
public static function createInstance($timezone = null, ?string $locale = null) {}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* This is a generated file, edit the .stub.php file instead.
|
||||
* Stub hash: ee755d4a500e2d1ba4d589c233b7d09a06b5cce8 */
|
||||
* Stub hash: 18a92d3af801f11e5c3b90e5d272fd98b3515c40 */
|
||||
|
||||
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_IntlCalendar___construct, 0, 0, 0)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
@@ -48,7 +48,7 @@ class IntlDateFormatter
|
||||
public function getTimeZoneId() {}
|
||||
|
||||
/**
|
||||
* @return IntlCalendar|null|false
|
||||
* @return IntlCalendar|false|null
|
||||
* @alias datefmt_get_calendar_object
|
||||
*/
|
||||
public function getCalendarObject() {}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* This is a generated file, edit the .stub.php file instead.
|
||||
* Stub hash: 437726f2d61a93d530e7e3b6df0741ae68c64697 */
|
||||
* Stub hash: 62742b5f463272f43970e98900a89d513c4fb839 */
|
||||
|
||||
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_IntlDateFormatter___construct, 0, 0, 3)
|
||||
ZEND_ARG_TYPE_INFO(0, locale, IS_STRING, 1)
|
||||
|
||||
@@ -171,8 +171,9 @@ static void resourcebundle_array_fetch(zend_object *object, zval *offset, zval *
|
||||
char *pbuf;
|
||||
ResourceBundle_object *rb;
|
||||
|
||||
intl_error_reset( NULL );
|
||||
rb = php_intl_resourcebundle_fetch_object(object);
|
||||
intl_error_reset(NULL);
|
||||
intl_error_reset(INTL_DATA_ERROR_P(rb));
|
||||
|
||||
if(Z_TYPE_P(offset) == IS_LONG) {
|
||||
is_numeric = 1;
|
||||
|
||||
@@ -28,6 +28,10 @@ function ut_main() {
|
||||
$t = ut_resourcebundle_get( $r, 'nonexisting' );
|
||||
$str_res .= debug( $t );
|
||||
|
||||
// Make sure accessing existing after non-existing works.
|
||||
$t = ut_resourcebundle_get( $r, 'teststring' );
|
||||
$str_res .= debug( $t );
|
||||
|
||||
return $str_res;
|
||||
}
|
||||
include_once( 'ut_common.inc' );
|
||||
@@ -55,3 +59,5 @@ testtable: 3
|
||||
testarray: string 3
|
||||
NULL
|
||||
2: Cannot load resource element 'nonexisting': U_MISSING_RESOURCE_ERROR
|
||||
Hello World!
|
||||
0: U_ZERO_ERROR
|
||||
@@ -35,19 +35,19 @@ function ldap_sasl_bind($ldap, ?string $dn = null, ?string $password = null, ?st
|
||||
|
||||
/**
|
||||
* @param resource|array $ldap
|
||||
* @return resource|false
|
||||
* @return resource|array|false
|
||||
*/
|
||||
function ldap_read($ldap, array|string $base, array|string $filter, array $attributes = [], int $attributes_only = 0, int $sizelimit = -1, int $timelimit = -1, int $deref = LDAP_DEREF_NEVER, ?array $controls = null) {}
|
||||
|
||||
/**
|
||||
* @param resource|array $ldap
|
||||
* @return resource|false
|
||||
* @return resource|array|false
|
||||
*/
|
||||
function ldap_list($ldap, array|string $base, array|string $filter, array $attributes = [], int $attributes_only = 0, int $sizelimit = -1, int $timelimit = -1, int $deref = LDAP_DEREF_NEVER, ?array $controls = null) {}
|
||||
|
||||
/**
|
||||
* @param resource|array $ldap
|
||||
* @return resource|false
|
||||
* @return resource|array|false
|
||||
*/
|
||||
function ldap_search($ldap, array|string $base, array|string $filter, array $attributes = [], int $attributes_only = 0, int $sizelimit = -1, int $timelimit = -1, int $deref = LDAP_DEREF_NEVER, ?array $controls = null) {}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* This is a generated file, edit the .stub.php file instead.
|
||||
* Stub hash: 836e18943977613fc0abf7443ad4d5afdbe65a0a */
|
||||
* Stub hash: 9d6315aeee2e3a1be51c05b65a960ed433bbe4ec */
|
||||
|
||||
#if defined(HAVE_ORALDAP)
|
||||
ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_connect, 0, 0, 0)
|
||||
|
||||
+29
-29
@@ -36,7 +36,7 @@ class mysqli
|
||||
public function change_user(string $username, string $password, ?string $database) {}
|
||||
|
||||
/**
|
||||
* @return string|null
|
||||
* @return string
|
||||
* @alias mysqli_character_set_name
|
||||
*/
|
||||
public function character_set_name() {}
|
||||
@@ -51,7 +51,7 @@ class mysqli
|
||||
* @return bool
|
||||
* @alias mysqli_commit
|
||||
*/
|
||||
public function commit(int $flags = -1, ?string $name = null) {}
|
||||
public function commit(int $flags = 0, ?string $name = null) {}
|
||||
|
||||
/**
|
||||
* @return mysqli|null|false
|
||||
@@ -101,7 +101,7 @@ class mysqli
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @return string|null
|
||||
* @return string
|
||||
* @alias mysqli_get_server_info
|
||||
*/
|
||||
public function get_server_info() {}
|
||||
@@ -152,7 +152,7 @@ class mysqli
|
||||
* @return int|false
|
||||
* @alias mysqli_poll
|
||||
*/
|
||||
public static function poll(?array &$read, ?array &$write, array &$error, int $seconds, int $microseconds = 0) {}
|
||||
public static function poll(?array &$read, ?array &$error, array &$reject, int $seconds, int $microseconds = 0) {}
|
||||
#endif
|
||||
|
||||
/**
|
||||
@@ -342,7 +342,7 @@ class mysqli_result implements IteratorAggregate
|
||||
|
||||
#if defined(MYSQLI_USE_MYSQLND)
|
||||
/**
|
||||
* @return array|false
|
||||
* @return array
|
||||
* @alias mysqli_fetch_all
|
||||
*/
|
||||
public function fetch_all(int $mode = MYSQLI_NUM) {}
|
||||
@@ -355,19 +355,19 @@ class mysqli_result implements IteratorAggregate
|
||||
public function fetch_array(int $mode = MYSQLI_BOTH) {}
|
||||
|
||||
/**
|
||||
* @return array|null
|
||||
* @return array|null|false
|
||||
* @alias mysqli_fetch_assoc
|
||||
*/
|
||||
public function fetch_assoc() {}
|
||||
|
||||
/**
|
||||
* @return object|null
|
||||
* @return object|null|false
|
||||
* @alias mysqli_fetch_object
|
||||
*/
|
||||
public function fetch_object(string $class = "stdClass", array $constructor_args = []) {}
|
||||
|
||||
/**
|
||||
* @return array|null
|
||||
* @return array|null|false
|
||||
* @alias mysqli_fetch_row
|
||||
*/
|
||||
public function fetch_row() {}
|
||||
@@ -392,7 +392,7 @@ class mysqli_stmt
|
||||
public function __construct(mysqli $mysql, ?string $query = null) {}
|
||||
|
||||
/**
|
||||
* @return int|false
|
||||
* @return int
|
||||
* @alias mysqli_stmt_attr_get
|
||||
*/
|
||||
public function attr_get(int $attribute) {}
|
||||
@@ -529,11 +529,11 @@ function mysqli_begin_transaction(mysqli $mysql, int $flags = 0, ?string $name =
|
||||
|
||||
function mysqli_change_user(mysqli $mysql, string $username, string $password, ?string $database): bool {}
|
||||
|
||||
function mysqli_character_set_name(mysqli $mysql): ?string {}
|
||||
function mysqli_character_set_name(mysqli $mysql): string {}
|
||||
|
||||
function mysqli_close(mysqli $mysql): bool {}
|
||||
|
||||
function mysqli_commit(mysqli $mysql, int $flags = -1, ?string $name = null): bool {}
|
||||
function mysqli_commit(mysqli $mysql, int $flags = 0, ?string $name = null): bool {}
|
||||
|
||||
function mysqli_connect(
|
||||
?string $hostname = null,
|
||||
@@ -556,7 +556,7 @@ function mysqli_debug(string $options): bool {}
|
||||
|
||||
function mysqli_errno(mysqli $mysql): int {}
|
||||
|
||||
function mysqli_error(mysqli $mysql): ?string {}
|
||||
function mysqli_error(mysqli $mysql): string {}
|
||||
|
||||
function mysqli_error_list(mysqli $mysql): array {}
|
||||
|
||||
@@ -574,16 +574,16 @@ function mysqli_fetch_field_direct(mysqli_result $result, int $index): object|fa
|
||||
function mysqli_fetch_lengths(mysqli_result $result): array|false {}
|
||||
|
||||
#if defined(MYSQLI_USE_MYSQLND)
|
||||
function mysqli_fetch_all(mysqli_result $result, int $mode = MYSQLI_NUM): array|false {}
|
||||
function mysqli_fetch_all(mysqli_result $result, int $mode = MYSQLI_NUM): array {}
|
||||
#endif
|
||||
|
||||
function mysqli_fetch_array(mysqli_result $result, int $mode = MYSQLI_BOTH): array|null|false {}
|
||||
|
||||
function mysqli_fetch_assoc(mysqli_result $result): ?array {}
|
||||
function mysqli_fetch_assoc(mysqli_result $result): array|null|false {}
|
||||
|
||||
function mysqli_fetch_object(mysqli_result $result, string $class = "stdClass", array $constructor_args = []): ?object {}
|
||||
function mysqli_fetch_object(mysqli_result $result, string $class = "stdClass", array $constructor_args = []): object|null|false {}
|
||||
|
||||
function mysqli_fetch_row(mysqli_result $result): ?array {}
|
||||
function mysqli_fetch_row(mysqli_result $result): array|null|false {}
|
||||
|
||||
function mysqli_field_count(mysqli $mysql): int {}
|
||||
|
||||
@@ -638,10 +638,16 @@ function mysqli_num_rows(mysqli_result $result): int|string {}
|
||||
/** @param string|int $value */
|
||||
function mysqli_options(mysqli $mysql, int $option, $value): bool {}
|
||||
|
||||
/**
|
||||
* @param string|int $value
|
||||
* @alias mysqli_options
|
||||
*/
|
||||
function mysqli_set_opt(mysqli $mysql, int $option, $value): bool {}
|
||||
|
||||
function mysqli_ping(mysqli $mysql): bool {}
|
||||
|
||||
#if defined(MYSQLI_USE_MYSQLND)
|
||||
function mysqli_poll(?array &$read, ?array &$write, array &$error, int $seconds, int $microseconds = 0): int|false {}
|
||||
function mysqli_poll(?array &$read, ?array &$error, array &$reject, int $seconds, int $microseconds = 0): int|false {}
|
||||
#endif
|
||||
|
||||
function mysqli_prepare(mysqli $mysql, string $query): mysqli_stmt|false {}
|
||||
@@ -663,6 +669,9 @@ function mysqli_real_connect(
|
||||
|
||||
function mysqli_real_escape_string(mysqli $mysql, string $string): string {}
|
||||
|
||||
/** @alias mysqli_real_escape_string */
|
||||
function mysqli_escape_string(mysqli $mysql, string $string): string {}
|
||||
|
||||
function mysqli_real_query(mysqli $mysql, string $query): bool {}
|
||||
|
||||
#if defined(MYSQLI_USE_MYSQLND)
|
||||
@@ -695,7 +704,7 @@ function mysqli_stmt_data_seek(mysqli_stmt $statement, int $offset): void {}
|
||||
|
||||
function mysqli_stmt_errno(mysqli_stmt $statement): int {}
|
||||
|
||||
function mysqli_stmt_error(mysqli_stmt $statement): ?string {}
|
||||
function mysqli_stmt_error(mysqli_stmt $statement): string {}
|
||||
|
||||
function mysqli_stmt_error_list(mysqli_stmt $statement): array {}
|
||||
|
||||
@@ -735,9 +744,9 @@ function mysqli_stmt_send_long_data(mysqli_stmt $statement, int $param_num, stri
|
||||
|
||||
function mysqli_stmt_store_result(mysqli_stmt $statement): bool {}
|
||||
|
||||
function mysqli_stmt_sqlstate(mysqli_stmt $statement): ?string {}
|
||||
function mysqli_stmt_sqlstate(mysqli_stmt $statement): string {}
|
||||
|
||||
function mysqli_sqlstate(mysqli $mysql): ?string {}
|
||||
function mysqli_sqlstate(mysqli $mysql): string {}
|
||||
|
||||
function mysqli_ssl_set(
|
||||
mysqli $mysql,
|
||||
@@ -761,12 +770,3 @@ function mysqli_use_result(mysqli $mysql): mysqli_result|false {}
|
||||
function mysqli_warning_count(mysqli $mysql): int {}
|
||||
|
||||
function mysqli_refresh(mysqli $mysql, int $flags): bool {}
|
||||
|
||||
/** @alias mysqli_real_escape_string */
|
||||
function mysqli_escape_string(mysqli $mysql, string $string): string {}
|
||||
|
||||
/**
|
||||
* @param string|int $value
|
||||
* @alias mysqli_options
|
||||
*/
|
||||
function mysqli_set_opt(mysqli $mysql, int $option, $value): bool {}
|
||||
+6
-29
@@ -614,17 +614,13 @@ PHP_FUNCTION(mysqli_character_set_name)
|
||||
{
|
||||
MY_MYSQL *mysql;
|
||||
zval *mysql_link;
|
||||
const char *cs_name;
|
||||
|
||||
if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) {
|
||||
RETURN_THROWS();
|
||||
}
|
||||
|
||||
MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
|
||||
cs_name = mysql_character_set_name(mysql->mysql);
|
||||
if (cs_name) {
|
||||
RETURN_STRING(cs_name);
|
||||
}
|
||||
RETURN_STRING(mysql_character_set_name(mysql->mysql));
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
@@ -801,16 +797,12 @@ PHP_FUNCTION(mysqli_error)
|
||||
{
|
||||
MY_MYSQL *mysql;
|
||||
zval *mysql_link;
|
||||
const char *err;
|
||||
|
||||
if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) {
|
||||
RETURN_THROWS();
|
||||
}
|
||||
MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
|
||||
err = mysql_error(mysql->mysql);
|
||||
if (err) {
|
||||
RETURN_STRING(err);
|
||||
}
|
||||
RETURN_STRING(mysql_error(mysql->mysql));
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
@@ -1337,10 +1329,7 @@ PHP_FUNCTION(mysqli_get_client_info)
|
||||
}
|
||||
}
|
||||
|
||||
const char * info = mysql_get_client_info();
|
||||
if (info) {
|
||||
RETURN_STRING(info);
|
||||
}
|
||||
RETURN_STRING(mysql_get_client_info());
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
@@ -2151,16 +2140,12 @@ PHP_FUNCTION(mysqli_sqlstate)
|
||||
{
|
||||
MY_MYSQL *mysql;
|
||||
zval *mysql_link;
|
||||
const char *state;
|
||||
|
||||
if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) {
|
||||
RETURN_THROWS();
|
||||
}
|
||||
MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
|
||||
state = mysql_sqlstate(mysql->mysql);
|
||||
if (state) {
|
||||
RETURN_STRING(state);
|
||||
}
|
||||
RETURN_STRING(mysql_sqlstate(mysql->mysql));
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
@@ -2360,17 +2345,13 @@ PHP_FUNCTION(mysqli_stmt_error)
|
||||
{
|
||||
MY_STMT *stmt;
|
||||
zval *mysql_stmt;
|
||||
const char * err;
|
||||
|
||||
if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_stmt, mysqli_stmt_class_entry) == FAILURE) {
|
||||
RETURN_THROWS();
|
||||
}
|
||||
MYSQLI_FETCH_RESOURCE_STMT(stmt, mysql_stmt, MYSQLI_STATUS_INITIALIZED);
|
||||
|
||||
err = mysql_stmt_error(stmt->stmt);
|
||||
if (err) {
|
||||
RETURN_STRING(err);
|
||||
}
|
||||
RETURN_STRING(mysql_stmt_error(stmt->stmt));
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
@@ -2501,17 +2482,13 @@ PHP_FUNCTION(mysqli_stmt_sqlstate)
|
||||
{
|
||||
MY_STMT *stmt;
|
||||
zval *mysql_stmt;
|
||||
const char * state;
|
||||
|
||||
if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_stmt, mysqli_stmt_class_entry) == FAILURE) {
|
||||
RETURN_THROWS();
|
||||
}
|
||||
MYSQLI_FETCH_RESOURCE_STMT(stmt, mysql_stmt, MYSQLI_STATUS_VALID);
|
||||
|
||||
state = mysql_stmt_sqlstate(stmt->stmt);
|
||||
if (state) {
|
||||
RETURN_STRING(state);
|
||||
}
|
||||
RETURN_STRING(mysql_stmt_sqlstate(stmt->stmt));
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
|
||||
+23
-30
@@ -1,5 +1,5 @@
|
||||
/* This is a generated file, edit the .stub.php file instead.
|
||||
* Stub hash: 480939b71e1dacbdbb4634dbabf375943e399b6f */
|
||||
* Stub hash: 5a8b778eaa9efcca7d3ad8bfdbaa31d9d07b25e8 */
|
||||
|
||||
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_mysqli_affected_rows, 0, 1, MAY_BE_LONG|MAY_BE_STRING)
|
||||
ZEND_ARG_OBJ_INFO(0, mysql, mysqli, 0)
|
||||
@@ -23,7 +23,7 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_mysqli_change_user, 0, 4, _IS_BO
|
||||
ZEND_ARG_TYPE_INFO(0, database, IS_STRING, 1)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_mysqli_character_set_name, 0, 1, IS_STRING, 1)
|
||||
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_mysqli_character_set_name, 0, 1, IS_STRING, 0)
|
||||
ZEND_ARG_OBJ_INFO(0, mysql, mysqli, 0)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
@@ -31,11 +31,7 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_mysqli_close, 0, 1, _IS_BOOL, 0)
|
||||
ZEND_ARG_OBJ_INFO(0, mysql, mysqli, 0)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_mysqli_commit, 0, 1, _IS_BOOL, 0)
|
||||
ZEND_ARG_OBJ_INFO(0, mysql, mysqli, 0)
|
||||
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, flags, IS_LONG, 0, "-1")
|
||||
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, name, IS_STRING, 1, "null")
|
||||
ZEND_END_ARG_INFO()
|
||||
#define arginfo_mysqli_commit arginfo_mysqli_begin_transaction
|
||||
|
||||
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_mysqli_connect, 0, 0, mysqli, MAY_BE_NULL|MAY_BE_FALSE)
|
||||
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, hostname, IS_STRING, 1, "null")
|
||||
@@ -97,7 +93,7 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_mysqli_fetch_lengths, 0, 1, MAY_
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
#if defined(MYSQLI_USE_MYSQLND)
|
||||
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_mysqli_fetch_all, 0, 1, MAY_BE_ARRAY|MAY_BE_FALSE)
|
||||
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_mysqli_fetch_all, 0, 1, IS_ARRAY, 0)
|
||||
ZEND_ARG_OBJ_INFO(0, result, mysqli_result, 0)
|
||||
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, mode, IS_LONG, 0, "MYSQLI_NUM")
|
||||
ZEND_END_ARG_INFO()
|
||||
@@ -108,11 +104,11 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_mysqli_fetch_array, 0, 1, MAY_BE
|
||||
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, mode, IS_LONG, 0, "MYSQLI_BOTH")
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_mysqli_fetch_assoc, 0, 1, IS_ARRAY, 1)
|
||||
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_mysqli_fetch_assoc, 0, 1, MAY_BE_ARRAY|MAY_BE_NULL|MAY_BE_FALSE)
|
||||
ZEND_ARG_OBJ_INFO(0, result, mysqli_result, 0)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_mysqli_fetch_object, 0, 1, IS_OBJECT, 1)
|
||||
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_mysqli_fetch_object, 0, 1, MAY_BE_OBJECT|MAY_BE_NULL|MAY_BE_FALSE)
|
||||
ZEND_ARG_OBJ_INFO(0, result, mysqli_result, 0)
|
||||
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, class, IS_STRING, 0, "\"stdClass\"")
|
||||
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, constructor_args, IS_ARRAY, 0, "[]")
|
||||
@@ -159,13 +155,11 @@ ZEND_END_ARG_INFO()
|
||||
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_mysqli_get_links_stats, 0, 0, IS_ARRAY, 0)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_mysqli_get_host_info, 0, 1, IS_STRING, 0)
|
||||
ZEND_ARG_OBJ_INFO(0, mysql, mysqli, 0)
|
||||
ZEND_END_ARG_INFO()
|
||||
#define arginfo_mysqli_get_host_info arginfo_mysqli_character_set_name
|
||||
|
||||
#define arginfo_mysqli_get_proto_info arginfo_mysqli_errno
|
||||
|
||||
#define arginfo_mysqli_get_server_info arginfo_mysqli_get_host_info
|
||||
#define arginfo_mysqli_get_server_info arginfo_mysqli_character_set_name
|
||||
|
||||
#define arginfo_mysqli_get_server_version arginfo_mysqli_errno
|
||||
|
||||
@@ -176,7 +170,9 @@ ZEND_END_ARG_INFO()
|
||||
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_mysqli_init, 0, 0, mysqli, MAY_BE_FALSE)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
#define arginfo_mysqli_info arginfo_mysqli_character_set_name
|
||||
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_mysqli_info, 0, 1, IS_STRING, 1)
|
||||
ZEND_ARG_OBJ_INFO(0, mysql, mysqli, 0)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
#define arginfo_mysqli_insert_id arginfo_mysqli_affected_rows
|
||||
|
||||
@@ -206,13 +202,15 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_mysqli_options, 0, 3, _IS_BOOL,
|
||||
ZEND_ARG_INFO(0, value)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
#define arginfo_mysqli_set_opt arginfo_mysqli_options
|
||||
|
||||
#define arginfo_mysqli_ping arginfo_mysqli_close
|
||||
|
||||
#if defined(MYSQLI_USE_MYSQLND)
|
||||
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_mysqli_poll, 0, 4, MAY_BE_LONG|MAY_BE_FALSE)
|
||||
ZEND_ARG_TYPE_INFO(1, read, IS_ARRAY, 1)
|
||||
ZEND_ARG_TYPE_INFO(1, write, IS_ARRAY, 1)
|
||||
ZEND_ARG_TYPE_INFO(1, error, IS_ARRAY, 0)
|
||||
ZEND_ARG_TYPE_INFO(1, error, IS_ARRAY, 1)
|
||||
ZEND_ARG_TYPE_INFO(1, reject, IS_ARRAY, 0)
|
||||
ZEND_ARG_TYPE_INFO(0, seconds, IS_LONG, 0)
|
||||
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, microseconds, IS_LONG, 0, "0")
|
||||
ZEND_END_ARG_INFO()
|
||||
@@ -249,6 +247,8 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_mysqli_real_escape_string, 0, 2,
|
||||
ZEND_ARG_TYPE_INFO(0, string, IS_STRING, 0)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
#define arginfo_mysqli_escape_string arginfo_mysqli_real_escape_string
|
||||
|
||||
#define arginfo_mysqli_real_query arginfo_mysqli_multi_query
|
||||
|
||||
#if defined(MYSQLI_USE_MYSQLND)
|
||||
@@ -313,7 +313,7 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_mysqli_stmt_errno, 0, 1, IS_LONG
|
||||
ZEND_ARG_OBJ_INFO(0, statement, mysqli_stmt, 0)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_mysqli_stmt_error, 0, 1, IS_STRING, 1)
|
||||
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_mysqli_stmt_error, 0, 1, IS_STRING, 0)
|
||||
ZEND_ARG_OBJ_INFO(0, statement, mysqli_stmt, 0)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
@@ -418,10 +418,6 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_mysqli_refresh, 0, 2, _IS_BOOL,
|
||||
ZEND_ARG_TYPE_INFO(0, flags, IS_LONG, 0)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
#define arginfo_mysqli_escape_string arginfo_mysqli_real_escape_string
|
||||
|
||||
#define arginfo_mysqli_set_opt arginfo_mysqli_options
|
||||
|
||||
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_mysqli___construct, 0, 0, 0)
|
||||
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, hostname, IS_STRING, 1, "null")
|
||||
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, username, IS_STRING, 1, "null")
|
||||
@@ -451,10 +447,7 @@ ZEND_END_ARG_INFO()
|
||||
|
||||
#define arginfo_class_mysqli_close arginfo_class_mysqli_character_set_name
|
||||
|
||||
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_mysqli_commit, 0, 0, 0)
|
||||
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, flags, IS_LONG, 0, "-1")
|
||||
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, name, IS_STRING, 1, "null")
|
||||
ZEND_END_ARG_INFO()
|
||||
#define arginfo_class_mysqli_commit arginfo_class_mysqli_begin_transaction
|
||||
|
||||
#define arginfo_class_mysqli_connect arginfo_class_mysqli___construct
|
||||
|
||||
@@ -496,8 +489,8 @@ ZEND_END_ARG_INFO()
|
||||
#if defined(MYSQLI_USE_MYSQLND)
|
||||
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_mysqli_poll, 0, 0, 4)
|
||||
ZEND_ARG_TYPE_INFO(1, read, IS_ARRAY, 1)
|
||||
ZEND_ARG_TYPE_INFO(1, write, IS_ARRAY, 1)
|
||||
ZEND_ARG_TYPE_INFO(1, error, IS_ARRAY, 0)
|
||||
ZEND_ARG_TYPE_INFO(1, error, IS_ARRAY, 1)
|
||||
ZEND_ARG_TYPE_INFO(1, reject, IS_ARRAY, 0)
|
||||
ZEND_ARG_TYPE_INFO(0, seconds, IS_LONG, 0)
|
||||
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, microseconds, IS_LONG, 0, "0")
|
||||
ZEND_END_ARG_INFO()
|
||||
@@ -878,6 +871,7 @@ static const zend_function_entry ext_functions[] = {
|
||||
ZEND_FE(mysqli_num_fields, arginfo_mysqli_num_fields)
|
||||
ZEND_FE(mysqli_num_rows, arginfo_mysqli_num_rows)
|
||||
ZEND_FE(mysqli_options, arginfo_mysqli_options)
|
||||
ZEND_FALIAS(mysqli_set_opt, mysqli_options, arginfo_mysqli_set_opt)
|
||||
ZEND_FE(mysqli_ping, arginfo_mysqli_ping)
|
||||
#if defined(MYSQLI_USE_MYSQLND)
|
||||
ZEND_FE(mysqli_poll, arginfo_mysqli_poll)
|
||||
@@ -887,6 +881,7 @@ static const zend_function_entry ext_functions[] = {
|
||||
ZEND_FE(mysqli_query, arginfo_mysqli_query)
|
||||
ZEND_FE(mysqli_real_connect, arginfo_mysqli_real_connect)
|
||||
ZEND_FE(mysqli_real_escape_string, arginfo_mysqli_real_escape_string)
|
||||
ZEND_FALIAS(mysqli_escape_string, mysqli_real_escape_string, arginfo_mysqli_escape_string)
|
||||
ZEND_FE(mysqli_real_query, arginfo_mysqli_real_query)
|
||||
#if defined(MYSQLI_USE_MYSQLND)
|
||||
ZEND_FE(mysqli_reap_async_query, arginfo_mysqli_reap_async_query)
|
||||
@@ -938,8 +933,6 @@ static const zend_function_entry ext_functions[] = {
|
||||
ZEND_FE(mysqli_use_result, arginfo_mysqli_use_result)
|
||||
ZEND_FE(mysqli_warning_count, arginfo_mysqli_warning_count)
|
||||
ZEND_FE(mysqli_refresh, arginfo_mysqli_refresh)
|
||||
ZEND_FALIAS(mysqli_escape_string, mysqli_real_escape_string, arginfo_mysqli_escape_string)
|
||||
ZEND_FALIAS(mysqli_set_opt, mysqli_options, arginfo_mysqli_set_opt)
|
||||
ZEND_FE_END
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
--TEST--
|
||||
Bug #67983: mysqlnd with MYSQLI_OPT_INT_AND_FLOAT_NATIVE fails to interpret bit columns
|
||||
--SKIPIF--
|
||||
<?php
|
||||
require_once('skipif.inc');
|
||||
require_once('skipifconnectfailure.inc');
|
||||
if (!$IS_MYSQLND) {
|
||||
die("skip mysqlnd only test");
|
||||
}
|
||||
?>
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
require_once("connect.inc");
|
||||
|
||||
$connection = my_mysqli_connect($host, $user, $passwd, $db, $port, $socket);
|
||||
|
||||
mysqli_options($connection, MYSQLI_OPT_INT_AND_FLOAT_NATIVE, true);
|
||||
|
||||
mysqli_set_charset($connection, 'utf8');
|
||||
mysqli_query($connection, 'DROP TABLE IF EXISTS test');
|
||||
mysqli_query($connection, 'CREATE TABLE test (id BIT(8))');
|
||||
mysqli_query($connection, 'INSERT INTO test VALUES (0), (1), (42)');
|
||||
|
||||
$res = mysqli_query($connection, 'SELECT * FROM test');
|
||||
|
||||
while ($result = mysqli_fetch_assoc($res)) {
|
||||
var_dump($result['id']);
|
||||
}
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
int(0)
|
||||
int(1)
|
||||
int(42)
|
||||
@@ -0,0 +1,38 @@
|
||||
--TEST--
|
||||
Bug #77935: Crash in mysqlnd_fetch_stmt_row_cursor when calling an SP with a cursor
|
||||
--SKIPIF--
|
||||
<?php
|
||||
require_once('skipif.inc');
|
||||
require_once('skipifconnectfailure.inc');
|
||||
?>
|
||||
--FILE--
|
||||
<?php
|
||||
require_once(__DIR__ . '/connect.inc');
|
||||
|
||||
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
|
||||
$db = my_mysqli_connect($host, $user, $passwd, $db, $port, $socket);
|
||||
$db->query('DROP PROCEDURE IF EXISTS testSp');
|
||||
$db->query(<<<'SQL'
|
||||
CREATE
|
||||
PROCEDURE `testSp`()
|
||||
BEGIN
|
||||
DECLARE `cur` CURSOR FOR SELECT 1;
|
||||
OPEN `cur`;
|
||||
CLOSE `cur`;
|
||||
SELECT 1;
|
||||
END;
|
||||
SQL);
|
||||
|
||||
$stmt = $db->prepare("CALL testSp()");
|
||||
$stmt->execute();
|
||||
$result = $stmt->get_result();
|
||||
while ($row = $result->fetch_assoc()) {
|
||||
var_dump($row);
|
||||
}
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
array(1) {
|
||||
[1]=>
|
||||
int(1)
|
||||
}
|
||||
@@ -109,7 +109,7 @@ if (!function_exists('mysqli_stmt_get_result'))
|
||||
|
||||
mysqli_stmt_close($stmt);
|
||||
|
||||
// get_result cannot be used in PS cursor mode
|
||||
// get_result can be used in PS cursor mode
|
||||
if (!$stmt = mysqli_stmt_init($link))
|
||||
printf("[030] [%d] %s\n", mysqli_errno($link), mysqli_error($link));
|
||||
|
||||
@@ -122,24 +122,11 @@ if (!function_exists('mysqli_stmt_get_result'))
|
||||
if (!mysqli_stmt_execute($stmt))
|
||||
printf("[033] [%d] %s\n", mysqli_stmt_errno($stmt), mysqli_stmt_error($stmt));
|
||||
|
||||
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
|
||||
try {
|
||||
$res = mysqli_stmt_get_result($stmt);
|
||||
// we expect no segfault if we try to fetch a row because get_result should throw an error or return false
|
||||
mysqli_fetch_assoc($res);
|
||||
} catch (\mysqli_sql_exception $e) {
|
||||
echo $e->getMessage() . "\n";
|
||||
$result = mysqli_stmt_get_result($stmt);
|
||||
while ($row = mysqli_fetch_assoc($result)) {
|
||||
var_dump($row);
|
||||
}
|
||||
|
||||
try {
|
||||
$res = $stmt->get_result();
|
||||
// we expect no segfault if we try to fetch a row because get_result should throw an error or return false
|
||||
$res->fetch_assoc();
|
||||
} catch (\mysqli_sql_exception $e) {
|
||||
echo $e->getMessage() . "\n";
|
||||
}
|
||||
mysqli_report(MYSQLI_REPORT_OFF);
|
||||
|
||||
if (!$stmt = mysqli_stmt_init($link))
|
||||
printf("[034] [%d] %s\n", mysqli_errno($link), mysqli_error($link));
|
||||
|
||||
@@ -196,8 +183,18 @@ if (!function_exists('mysqli_stmt_get_result'))
|
||||
mysqli_stmt object is not fully initialized
|
||||
mysqli_stmt object is not fully initialized
|
||||
mysqli_stmt object is not fully initialized
|
||||
mysqli_stmt_get_result() cannot be used with cursors
|
||||
get_result() cannot be used with cursors
|
||||
array(2) {
|
||||
["id"]=>
|
||||
int(1)
|
||||
["label"]=>
|
||||
string(1) "a"
|
||||
}
|
||||
array(2) {
|
||||
["id"]=>
|
||||
int(2)
|
||||
["label"]=>
|
||||
string(1) "b"
|
||||
}
|
||||
[040] [2014] [Commands out of sync; you can't run this command now]
|
||||
[041] [0] []
|
||||
array(2) {
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
--TEST--
|
||||
PS using cursor and returning multiple result sets
|
||||
--SKIPIF--
|
||||
<?php
|
||||
require_once('skipif.inc');
|
||||
require_once('skipifconnectfailure.inc');
|
||||
?>
|
||||
--FILE--
|
||||
<?php
|
||||
require_once(__DIR__ . '/connect.inc');
|
||||
|
||||
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
|
||||
$db = my_mysqli_connect($host, $user, $passwd, $db, $port, $socket);
|
||||
$db->query('DROP PROCEDURE IF EXISTS testPs');
|
||||
$db->query(<<<'SQL'
|
||||
CREATE PROCEDURE testPs() BEGIN
|
||||
DECLARE testCursor CURSOR FOR SELECT 'stuff';
|
||||
OPEN testCursor;
|
||||
CLOSE testCursor;
|
||||
SELECT 1 as a, 2 as b;
|
||||
SELECT 3 as a, 4 as b;
|
||||
END
|
||||
SQL
|
||||
);
|
||||
|
||||
echo "use_result:\n";
|
||||
$stmt = $db->prepare("call testPs()");
|
||||
$stmt->execute();
|
||||
$stmt->bind_result($v1, $v2);
|
||||
while ($stmt->fetch()) {
|
||||
var_dump($v1, $v2);
|
||||
}
|
||||
|
||||
$stmt->next_result();
|
||||
$stmt->bind_result($v1, $v2);
|
||||
while ($stmt->fetch()) {
|
||||
var_dump($v1, $v2);
|
||||
}
|
||||
$stmt->next_result();
|
||||
|
||||
echo "\nstore_result:\n";
|
||||
$stmt = $db->prepare("call testPs()");
|
||||
$stmt->execute();
|
||||
$stmt->store_result();
|
||||
$stmt->bind_result($v1, $v2);
|
||||
while ($stmt->fetch()) {
|
||||
var_dump($v1, $v2);
|
||||
}
|
||||
|
||||
$stmt->next_result();
|
||||
$stmt->store_result();
|
||||
$stmt->bind_result($v1, $v2);
|
||||
while ($stmt->fetch()) {
|
||||
var_dump($v1, $v2);
|
||||
}
|
||||
$stmt->next_result();
|
||||
|
||||
echo "\nget_result:\n";
|
||||
$stmt = $db->prepare("call testPs()");
|
||||
$stmt->execute();
|
||||
$result = $stmt->get_result();
|
||||
while ($row = $result->fetch_assoc()) {
|
||||
var_dump($row);
|
||||
}
|
||||
|
||||
$stmt->next_result();
|
||||
$result = $stmt->get_result();
|
||||
while ($row = $result->fetch_assoc()) {
|
||||
var_dump($row);
|
||||
}
|
||||
$stmt->next_result();
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
use_result:
|
||||
int(1)
|
||||
int(2)
|
||||
int(3)
|
||||
int(4)
|
||||
|
||||
store_result:
|
||||
int(1)
|
||||
int(2)
|
||||
int(3)
|
||||
int(4)
|
||||
|
||||
get_result:
|
||||
array(2) {
|
||||
["a"]=>
|
||||
int(1)
|
||||
["b"]=>
|
||||
int(2)
|
||||
}
|
||||
array(2) {
|
||||
["a"]=>
|
||||
int(3)
|
||||
["b"]=>
|
||||
int(4)
|
||||
}
|
||||
+71
-58
@@ -37,6 +37,36 @@ enum_func_status mysqlnd_stmt_execute_batch_generate_request(MYSQLND_STMT * cons
|
||||
|
||||
static void mysqlnd_stmt_separate_result_bind(MYSQLND_STMT * const stmt);
|
||||
|
||||
static enum_func_status mysqlnd_stmt_send_cursor_fetch_command(
|
||||
const MYSQLND_STMT_DATA *stmt, unsigned max_rows)
|
||||
{
|
||||
MYSQLND_CONN_DATA *conn = stmt->conn;
|
||||
zend_uchar buf[MYSQLND_STMT_ID_LENGTH /* statement id */ + 4 /* number of rows to fetch */];
|
||||
const MYSQLND_CSTRING payload = {(const char*) buf, sizeof(buf)};
|
||||
|
||||
int4store(buf, stmt->stmt_id);
|
||||
int4store(buf + MYSQLND_STMT_ID_LENGTH, max_rows);
|
||||
|
||||
if (conn->command->stmt_fetch(conn, payload) == FAIL) {
|
||||
COPY_CLIENT_ERROR(stmt->error_info, *conn->error_info);
|
||||
return FAIL;
|
||||
}
|
||||
return PASS;
|
||||
}
|
||||
|
||||
static zend_bool mysqlnd_stmt_check_state(const MYSQLND_STMT_DATA *stmt)
|
||||
{
|
||||
const MYSQLND_CONN_DATA *conn = stmt->conn;
|
||||
if (stmt->state != MYSQLND_STMT_WAITING_USE_OR_STORE) {
|
||||
return 0;
|
||||
}
|
||||
if (stmt->cursor_exists) {
|
||||
return GET_CONNECTION_STATE(&conn->state) == CONN_READY;
|
||||
} else {
|
||||
return GET_CONNECTION_STATE(&conn->state) == CONN_FETCHING_DATA;
|
||||
}
|
||||
}
|
||||
|
||||
/* {{{ mysqlnd_stmt::store_result */
|
||||
static MYSQLND_RES *
|
||||
MYSQLND_METHOD(mysqlnd_stmt, store_result)(MYSQLND_STMT * const s)
|
||||
@@ -57,14 +87,8 @@ MYSQLND_METHOD(mysqlnd_stmt, store_result)(MYSQLND_STMT * const s)
|
||||
DBG_RETURN(NULL);
|
||||
}
|
||||
|
||||
if (stmt->cursor_exists) {
|
||||
/* Silently convert buffered to unbuffered, for now */
|
||||
DBG_RETURN(s->m->use_result(s));
|
||||
}
|
||||
|
||||
/* Nothing to store for UPSERT/LOAD DATA*/
|
||||
if (GET_CONNECTION_STATE(&conn->state) != CONN_FETCHING_DATA || stmt->state != MYSQLND_STMT_WAITING_USE_OR_STORE)
|
||||
{
|
||||
if (!mysqlnd_stmt_check_state(stmt)) {
|
||||
SET_CLIENT_ERROR(conn->error_info, CR_COMMANDS_OUT_OF_SYNC, UNKNOWN_SQLSTATE, mysqlnd_out_of_sync);
|
||||
DBG_RETURN(NULL);
|
||||
}
|
||||
@@ -75,6 +99,12 @@ MYSQLND_METHOD(mysqlnd_stmt, store_result)(MYSQLND_STMT * const s)
|
||||
SET_EMPTY_ERROR(conn->error_info);
|
||||
MYSQLND_INC_CONN_STATISTIC(conn->stats, STAT_PS_BUFFERED_SETS);
|
||||
|
||||
if (stmt->cursor_exists) {
|
||||
if (mysqlnd_stmt_send_cursor_fetch_command(stmt, -1) == FAIL) {
|
||||
DBG_RETURN(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
result = stmt->result;
|
||||
result->type = MYSQLND_RES_PS_BUF;
|
||||
/* result->m.row_decoder = php_mysqlnd_rowp_read_binary_protocol; */
|
||||
@@ -149,19 +179,8 @@ MYSQLND_METHOD(mysqlnd_stmt, get_result)(MYSQLND_STMT * const s)
|
||||
DBG_RETURN(NULL);
|
||||
}
|
||||
|
||||
if (stmt->cursor_exists) {
|
||||
/* Prepared statement cursors are not supported as of yet */
|
||||
char * msg;
|
||||
mnd_sprintf(&msg, 0, "%s() cannot be used with cursors", get_active_function_name());
|
||||
SET_CLIENT_ERROR(stmt->error_info, CR_NOT_IMPLEMENTED, UNKNOWN_SQLSTATE, msg);
|
||||
if (msg) {
|
||||
mnd_sprintf_free(msg);
|
||||
}
|
||||
DBG_RETURN(NULL);
|
||||
}
|
||||
|
||||
/* Nothing to store for UPSERT/LOAD DATA*/
|
||||
if (GET_CONNECTION_STATE(&conn->state) != CONN_FETCHING_DATA || stmt->state != MYSQLND_STMT_WAITING_USE_OR_STORE) {
|
||||
if (!mysqlnd_stmt_check_state(stmt)) {
|
||||
SET_CLIENT_ERROR(stmt->error_info, CR_COMMANDS_OUT_OF_SYNC, UNKNOWN_SQLSTATE, mysqlnd_out_of_sync);
|
||||
DBG_RETURN(NULL);
|
||||
}
|
||||
@@ -170,6 +189,12 @@ MYSQLND_METHOD(mysqlnd_stmt, get_result)(MYSQLND_STMT * const s)
|
||||
SET_EMPTY_ERROR(conn->error_info);
|
||||
MYSQLND_INC_CONN_STATISTIC(conn->stats, STAT_BUFFERED_SETS);
|
||||
|
||||
if (stmt->cursor_exists) {
|
||||
if (mysqlnd_stmt_send_cursor_fetch_command(stmt, -1) == FAIL) {
|
||||
DBG_RETURN(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
do {
|
||||
result = conn->m->result_init(stmt->result->field_count);
|
||||
if (!result) {
|
||||
@@ -578,28 +603,30 @@ mysqlnd_stmt_execute_parse_response(MYSQLND_STMT * const s, enum_mysqlnd_parse_e
|
||||
DBG_INF_FMT("server_status=%u cursor=%u", UPSERT_STATUS_GET_SERVER_STATUS(stmt->upsert_status),
|
||||
UPSERT_STATUS_GET_SERVER_STATUS(stmt->upsert_status) & SERVER_STATUS_CURSOR_EXISTS);
|
||||
|
||||
if (UPSERT_STATUS_GET_SERVER_STATUS(stmt->upsert_status) & SERVER_STATUS_CURSOR_EXISTS) {
|
||||
DBG_INF("cursor exists");
|
||||
stmt->cursor_exists = TRUE;
|
||||
SET_CONNECTION_STATE(&conn->state, CONN_READY);
|
||||
/* Only cursor read */
|
||||
stmt->default_rset_handler = s->m->use_result;
|
||||
DBG_INF("use_result");
|
||||
} else if (stmt->flags & CURSOR_TYPE_READ_ONLY) {
|
||||
DBG_INF("asked for cursor but got none");
|
||||
/*
|
||||
We have asked for CURSOR but got no cursor, because the condition
|
||||
above is not fulfilled. Then...
|
||||
if (stmt->flags & CURSOR_TYPE_READ_ONLY) {
|
||||
if (UPSERT_STATUS_GET_SERVER_STATUS(stmt->upsert_status) & SERVER_STATUS_CURSOR_EXISTS) {
|
||||
DBG_INF("cursor exists");
|
||||
stmt->cursor_exists = TRUE;
|
||||
SET_CONNECTION_STATE(&conn->state, CONN_READY);
|
||||
/* Only cursor read */
|
||||
stmt->default_rset_handler = s->m->use_result;
|
||||
DBG_INF("use_result");
|
||||
} else {
|
||||
DBG_INF("asked for cursor but got none");
|
||||
/*
|
||||
We have asked for CURSOR but got no cursor, because the condition
|
||||
above is not fulfilled. Then...
|
||||
|
||||
This is a single-row result set, a result set with no rows, EXPLAIN,
|
||||
SHOW VARIABLES, or some other command which either a) bypasses the
|
||||
cursors framework in the server and writes rows directly to the
|
||||
network or b) is more efficient if all (few) result set rows are
|
||||
precached on client and server's resources are freed.
|
||||
*/
|
||||
/* preferred is buffered read */
|
||||
stmt->default_rset_handler = s->m->store_result;
|
||||
DBG_INF("store_result");
|
||||
This is a single-row result set, a result set with no rows, EXPLAIN,
|
||||
SHOW VARIABLES, or some other command which either a) bypasses the
|
||||
cursors framework in the server and writes rows directly to the
|
||||
network or b) is more efficient if all (few) result set rows are
|
||||
precached on client and server's resources are freed.
|
||||
*/
|
||||
/* preferred is buffered read */
|
||||
stmt->default_rset_handler = s->m->store_result;
|
||||
DBG_INF("store_result");
|
||||
}
|
||||
} else {
|
||||
DBG_INF("no cursor");
|
||||
/* preferred is unbuffered read */
|
||||
@@ -957,11 +984,7 @@ MYSQLND_METHOD(mysqlnd_stmt, use_result)(MYSQLND_STMT * s)
|
||||
}
|
||||
DBG_INF_FMT("stmt=%lu", stmt->stmt_id);
|
||||
|
||||
if (!stmt->field_count ||
|
||||
(!stmt->cursor_exists && GET_CONNECTION_STATE(&conn->state) != CONN_FETCHING_DATA) ||
|
||||
(stmt->cursor_exists && GET_CONNECTION_STATE(&conn->state) != CONN_READY) ||
|
||||
(stmt->state != MYSQLND_STMT_WAITING_USE_OR_STORE))
|
||||
{
|
||||
if (!stmt->field_count || !mysqlnd_stmt_check_state(stmt)) {
|
||||
SET_CLIENT_ERROR(conn->error_info, CR_COMMANDS_OUT_OF_SYNC, UNKNOWN_SQLSTATE, mysqlnd_out_of_sync);
|
||||
DBG_ERR("command out of sync");
|
||||
DBG_RETURN(NULL);
|
||||
@@ -991,7 +1014,6 @@ mysqlnd_fetch_stmt_row_cursor(MYSQLND_RES * result, void * param, const unsigned
|
||||
MYSQLND_STMT * s = (MYSQLND_STMT *) param;
|
||||
MYSQLND_STMT_DATA * stmt = s? s->data : NULL;
|
||||
MYSQLND_CONN_DATA * conn = stmt? stmt->conn : NULL;
|
||||
zend_uchar buf[MYSQLND_STMT_ID_LENGTH /* statement id */ + 4 /* number of rows to fetch */];
|
||||
MYSQLND_PACKET_ROW * row_packet;
|
||||
|
||||
DBG_ENTER("mysqlnd_fetch_stmt_row_cursor");
|
||||
@@ -1015,18 +1037,9 @@ mysqlnd_fetch_stmt_row_cursor(MYSQLND_RES * result, void * param, const unsigned
|
||||
SET_EMPTY_ERROR(stmt->error_info);
|
||||
SET_EMPTY_ERROR(conn->error_info);
|
||||
|
||||
int4store(buf, stmt->stmt_id);
|
||||
int4store(buf + MYSQLND_STMT_ID_LENGTH, 1); /* for now fetch only one row */
|
||||
|
||||
{
|
||||
const MYSQLND_CSTRING payload = {(const char*) buf, sizeof(buf)};
|
||||
|
||||
ret = conn->command->stmt_fetch(conn, payload);
|
||||
if (ret == FAIL) {
|
||||
COPY_CLIENT_ERROR(stmt->error_info, *conn->error_info);
|
||||
DBG_RETURN(FAIL);
|
||||
}
|
||||
|
||||
/* for now fetch only one row */
|
||||
if (mysqlnd_stmt_send_cursor_fetch_command(stmt, 1) == FAIL) {
|
||||
DBG_RETURN(FAIL);
|
||||
}
|
||||
|
||||
row_packet->skip_extraction = stmt->result_bind? FALSE:TRUE;
|
||||
|
||||
@@ -1604,8 +1604,28 @@ php_mysqlnd_rowp_read_text_protocol_aux(MYSQLND_ROW_BUFFER * row_buffer, zval *
|
||||
}
|
||||
MYSQLND_INC_CONN_STATISTIC_W_VALUE2(stats, statistic, 1, STAT_BYTES_RECEIVED_PURE_DATA_TEXT, len);
|
||||
}
|
||||
if (fields_metadata[i].type == MYSQL_TYPE_BIT) {
|
||||
/*
|
||||
BIT fields are specially handled. As they come as bit mask, they have
|
||||
to be converted to human-readable representation.
|
||||
*/
|
||||
ps_fetch_from_1_to_8_bytes(current_field, &(fields_metadata[i]), 0, (const zend_uchar **) &p, len);
|
||||
/*
|
||||
We have advanced in ps_fetch_from_1_to_8_bytes. We should go back because
|
||||
later in this function there will be an advancement.
|
||||
*/
|
||||
p -= len;
|
||||
if (Z_TYPE_P(current_field) == IS_LONG && !as_int_or_float) {
|
||||
/* we are using the text protocol, so convert to string */
|
||||
char tmp[22];
|
||||
const size_t tmp_len = sprintf((char *)&tmp, ZEND_ULONG_FMT, Z_LVAL_P(current_field));
|
||||
ZVAL_STRINGL(current_field, tmp, tmp_len);
|
||||
} else if (Z_TYPE_P(current_field) == IS_STRING) {
|
||||
/* nothing to do here, as we want a string and ps_fetch_from_1_to_8_bytes() has given us one */
|
||||
}
|
||||
}
|
||||
#ifdef MYSQLND_STRING_TO_INT_CONVERSION
|
||||
if (as_int_or_float && perm_bind.php_type == IS_LONG) {
|
||||
else if (as_int_or_float && perm_bind.php_type == IS_LONG) {
|
||||
zend_uchar save = *(p + len);
|
||||
/* We have to make it ASCIIZ temporarily */
|
||||
*(p + len) = '\0';
|
||||
@@ -1649,28 +1669,9 @@ php_mysqlnd_rowp_read_text_protocol_aux(MYSQLND_ROW_BUFFER * row_buffer, zval *
|
||||
*(p + len) = '\0';
|
||||
ZVAL_DOUBLE(current_field, atof((char *) p));
|
||||
*(p + len) = save;
|
||||
} else
|
||||
}
|
||||
#endif /* MYSQLND_STRING_TO_INT_CONVERSION */
|
||||
if (fields_metadata[i].type == MYSQL_TYPE_BIT) {
|
||||
/*
|
||||
BIT fields are specially handled. As they come as bit mask, they have
|
||||
to be converted to human-readable representation.
|
||||
*/
|
||||
ps_fetch_from_1_to_8_bytes(current_field, &(fields_metadata[i]), 0, (const zend_uchar **) &p, len);
|
||||
/*
|
||||
We have advanced in ps_fetch_from_1_to_8_bytes. We should go back because
|
||||
later in this function there will be an advancement.
|
||||
*/
|
||||
p -= len;
|
||||
if (Z_TYPE_P(current_field) == IS_LONG && !as_int_or_float) {
|
||||
/* we are using the text protocol, so convert to string */
|
||||
char tmp[22];
|
||||
const size_t tmp_len = sprintf((char *)&tmp, ZEND_ULONG_FMT, Z_LVAL_P(current_field));
|
||||
ZVAL_STRINGL(current_field, tmp, tmp_len);
|
||||
} else if (Z_TYPE_P(current_field) == IS_STRING) {
|
||||
/* nothing to do here, as we want a string and ps_fetch_from_1_to_8_bytes() has given us one */
|
||||
}
|
||||
} else {
|
||||
else {
|
||||
ZVAL_STRINGL_FAST(current_field, (char *)p, len);
|
||||
}
|
||||
p += len;
|
||||
|
||||
+31
-14
@@ -8,7 +8,7 @@ http://pear.php.net/dtd/package-2.0.xsd">
|
||||
<summary>Extension for Oracle Database</summary>
|
||||
|
||||
<description>
|
||||
The OCI8 extension let you access Oracle Database.
|
||||
The OCI8 extension lets you access Oracle Database.
|
||||
|
||||
Use 'pecl install oci8' to install for PHP 8.
|
||||
|
||||
@@ -53,12 +53,12 @@ Oracle's standard cross-version connectivity applies. For example, PHP OCI8 lin
|
||||
<active>no</active>
|
||||
</lead>
|
||||
|
||||
<date>2020-11-26</date>
|
||||
<date>2020-12-21</date>
|
||||
<time>12:00:00</time>
|
||||
|
||||
<version>
|
||||
<release>3.0.0</release>
|
||||
<api>3.0.0</api>
|
||||
<release>3.0.1</release>
|
||||
<api>3.0.1</api>
|
||||
</version>
|
||||
<stability>
|
||||
<release>stable</release>
|
||||
@@ -68,15 +68,7 @@ Oracle's standard cross-version connectivity applies. For example, PHP OCI8 lin
|
||||
<notes>
|
||||
This version is for PHP 8 only.
|
||||
|
||||
Deprecated old OCI8 function aliases. (Jens de Nies)
|
||||
|
||||
Removed obsolete no-op function oci_internal_debug(). (Jens de Nies)
|
||||
|
||||
The OCI-Lob class is now called OCILob for standards compliance.
|
||||
|
||||
The OCI-Collection class is now called OCICollection for standards compliance.
|
||||
|
||||
Generate arginfo from function stubs. (Jens de Nies)
|
||||
Updated Windows build environment to build with newer Oracle Client libraries. (cmb)
|
||||
</notes>
|
||||
<contents>
|
||||
<dir name="/">
|
||||
@@ -451,7 +443,7 @@ Oracle's standard cross-version connectivity applies. For example, PHP OCI8 lin
|
||||
<dependencies>
|
||||
<required>
|
||||
<php>
|
||||
<min>7.0.0</min>
|
||||
<min>8.0.0</min>
|
||||
</php>
|
||||
<pearinstaller>
|
||||
<min>1.4.0b1</min>
|
||||
@@ -484,6 +476,31 @@ Internal change: Convert some parameter parsing to the Fast Parameter Parsing AP
|
||||
</notes>
|
||||
</release>
|
||||
|
||||
<release>
|
||||
<version>
|
||||
<release>3.0.0</release>
|
||||
<api>3.0.0</api>
|
||||
</version>
|
||||
<stability>
|
||||
<release>stable</release>
|
||||
<api>stable</api>
|
||||
</stability>
|
||||
<license uri="http://www.php.net/license">PHP</license>
|
||||
<notes>
|
||||
This version is for PHP 8 only.
|
||||
|
||||
Deprecated old OCI8 function aliases. (Jens de Nies)
|
||||
|
||||
Removed obsolete no-op function oci_internal_debug(). (Jens de Nies)
|
||||
|
||||
The OCI-Lob class is now called OCILob for standards compliance.
|
||||
|
||||
The OCI-Collection class is now called OCICollection for standards compliance.
|
||||
|
||||
Generate arginfo from function stubs. (Jens de Nies)
|
||||
</notes>
|
||||
</release>
|
||||
|
||||
<release>
|
||||
<version>
|
||||
<release>2.1.8</release>
|
||||
|
||||
+1
-1
@@ -41,7 +41,7 @@
|
||||
*/
|
||||
#undef PHP_OCI8_VERSION
|
||||
#endif
|
||||
#define PHP_OCI8_VERSION "3.0.0"
|
||||
#define PHP_OCI8_VERSION "3.0.1"
|
||||
|
||||
extern zend_module_entry oci8_module_entry;
|
||||
#define phpext_oci8_ptr &oci8_module_entry
|
||||
|
||||
@@ -57,11 +57,11 @@ function get_attr($conn)
|
||||
?>
|
||||
--EXPECT--
|
||||
**Test 1.1 - Default values for the attribute **************
|
||||
The value of DRIVER_NAME is PHP OCI8 : 3.0.0
|
||||
The value of DRIVER_NAME is PHP OCI8 : 3.0.1
|
||||
|
||||
***Test 1.2 - Get the values from different connections **************
|
||||
Testing with oci_pconnect()
|
||||
The value of DRIVER_NAME is PHP OCI8 : 3.0.0
|
||||
The value of DRIVER_NAME is PHP OCI8 : 3.0.1
|
||||
Testing with oci_new_connect()
|
||||
The value of DRIVER_NAME is PHP OCI8 : 3.0.0
|
||||
The value of DRIVER_NAME is PHP OCI8 : 3.0.1
|
||||
Done
|
||||
+6
-5
@@ -963,6 +963,7 @@ PHP_FUNCTION(odbc_prepare)
|
||||
typedef struct odbc_params_t {
|
||||
SQLLEN vallen;
|
||||
int fp;
|
||||
zend_string *zstr;
|
||||
} odbc_params_t;
|
||||
|
||||
static void odbc_release_params(odbc_result *result, odbc_params_t *params) {
|
||||
@@ -971,6 +972,9 @@ static void odbc_release_params(odbc_result *result, odbc_params_t *params) {
|
||||
if (params[i].fp != -1) {
|
||||
close(params[i].fp);
|
||||
}
|
||||
if (params[i].zstr) {
|
||||
zend_string_release(params[i].zstr);
|
||||
}
|
||||
}
|
||||
efree(params);
|
||||
}
|
||||
@@ -1004,6 +1008,7 @@ PHP_FUNCTION(odbc_execute)
|
||||
params = (odbc_params_t *)safe_emalloc(sizeof(odbc_params_t), result->numparams, 0);
|
||||
for(i = 0; i < result->numparams; i++) {
|
||||
params[i].fp = -1;
|
||||
params[i].zstr = NULL;
|
||||
}
|
||||
|
||||
i = 1;
|
||||
@@ -1017,6 +1022,7 @@ PHP_FUNCTION(odbc_execute)
|
||||
|
||||
params[i-1].vallen = ZSTR_LEN(tmpstr);
|
||||
params[i-1].fp = -1;
|
||||
params[i-1].zstr = tmpstr;
|
||||
|
||||
if (IS_SQL_BINARY(result->param_info[i-1].sqltype)) {
|
||||
ctype = SQL_C_BINARY;
|
||||
@@ -1030,7 +1036,6 @@ PHP_FUNCTION(odbc_execute)
|
||||
|
||||
if (ZSTR_LEN(tmpstr) != strlen(ZSTR_VAL(tmpstr))) {
|
||||
odbc_release_params(result, params);
|
||||
zend_string_release(tmpstr);
|
||||
RETURN_FALSE;
|
||||
}
|
||||
filename = estrndup(&ZSTR_VAL(tmpstr)[1], ZSTR_LEN(tmpstr) - 2);
|
||||
@@ -1040,14 +1045,12 @@ PHP_FUNCTION(odbc_execute)
|
||||
if (php_check_open_basedir(filename)) {
|
||||
efree(filename);
|
||||
odbc_release_params(result, params);
|
||||
zend_string_release(tmpstr);
|
||||
RETURN_FALSE;
|
||||
}
|
||||
|
||||
if ((params[i-1].fp = open(filename,O_RDONLY)) == -1) {
|
||||
php_error_docref(NULL, E_WARNING,"Can't open file %s", filename);
|
||||
odbc_release_params(result, params);
|
||||
zend_string_release(tmpstr);
|
||||
efree(filename);
|
||||
RETURN_FALSE;
|
||||
}
|
||||
@@ -1076,10 +1079,8 @@ PHP_FUNCTION(odbc_execute)
|
||||
if (rc == SQL_ERROR) {
|
||||
odbc_sql_error(result->conn_ptr, result->stmt, "SQLBindParameter");
|
||||
odbc_release_params(result, params);
|
||||
zend_string_release(tmpstr);
|
||||
RETURN_FALSE;
|
||||
}
|
||||
zend_string_release(tmpstr);
|
||||
if (++i > result->numparams) break;
|
||||
} ZEND_HASH_FOREACH_END();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
--TEST--
|
||||
Bug #80592 (all floats are the same in ODBC parameters)
|
||||
--SKIPIF--
|
||||
<?php include 'skipif.inc'; ?>
|
||||
--FILE--
|
||||
<?php
|
||||
include 'config.inc';
|
||||
|
||||
$conn = odbc_connect($dsn, $user, $pass);
|
||||
odbc_exec($conn,"CREATE TABLE bug80592 (f1 float not null, f2 float not null, f3 float not null)");
|
||||
$stmt = odbc_prepare($conn, "INSERT INTO bug80592 (f1, f2, f3) values (?, ?, ?)");
|
||||
odbc_execute($stmt, [1.0, 2.0, 3.0]);
|
||||
$res = odbc_exec($conn, "SELECT f1, f2, f3 from bug80592");
|
||||
var_dump(odbc_fetch_array($res));
|
||||
?>
|
||||
--CLEAN--
|
||||
<?php
|
||||
include 'config.inc';
|
||||
|
||||
$conn = odbc_connect($dsn, $user, $pass);
|
||||
odbc_exec($conn, "DROP TABLE bug80592");
|
||||
?>
|
||||
--EXPECT--
|
||||
array(3) {
|
||||
["f1"]=>
|
||||
string(3) "1.0"
|
||||
["f2"]=>
|
||||
string(3) "2.0"
|
||||
["f3"]=>
|
||||
string(3) "3.0"
|
||||
}
|
||||
@@ -462,12 +462,12 @@ static const func_info_t func_infos[] = {
|
||||
F1("mysqli_get_charset", MAY_BE_NULL | MAY_BE_OBJECT),
|
||||
F1("mysqli_fetch_array", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY),
|
||||
F1("mysqli_fetch_assoc", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_ANY),
|
||||
F1("mysqli_fetch_all", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY),
|
||||
F1("mysqli_fetch_all", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY),
|
||||
F1("mysqli_fetch_object", MAY_BE_NULL | MAY_BE_OBJECT),
|
||||
F1("mysqli_affected_rows", MAY_BE_LONG | MAY_BE_STRING),
|
||||
F1("mysqli_character_set_name", MAY_BE_NULL | MAY_BE_STRING),
|
||||
F1("mysqli_character_set_name", MAY_BE_STRING),
|
||||
F0("mysqli_debug", MAY_BE_TRUE),
|
||||
F1("mysqli_error", MAY_BE_NULL | MAY_BE_STRING),
|
||||
F1("mysqli_error", MAY_BE_STRING),
|
||||
F1("mysqli_reap_async_query", MAY_BE_FALSE | MAY_BE_TRUE | MAY_BE_OBJECT),
|
||||
F1("mysqli_stmt_get_result", MAY_BE_FALSE | MAY_BE_OBJECT),
|
||||
F1("mysqli_get_warnings", MAY_BE_FALSE | MAY_BE_OBJECT),
|
||||
@@ -490,13 +490,13 @@ static const func_info_t func_infos[] = {
|
||||
F1("mysqli_stmt_affected_rows", MAY_BE_LONG | MAY_BE_STRING),
|
||||
F1("mysqli_stmt_insert_id", MAY_BE_LONG | MAY_BE_STRING),
|
||||
F1("mysqli_stmt_num_rows", MAY_BE_LONG | MAY_BE_STRING),
|
||||
F1("mysqli_sqlstate", MAY_BE_NULL | MAY_BE_STRING),
|
||||
F1("mysqli_sqlstate", MAY_BE_STRING),
|
||||
F0("mysqli_ssl_set", MAY_BE_TRUE),
|
||||
F1("mysqli_stat", MAY_BE_FALSE | MAY_BE_STRING),
|
||||
F1("mysqli_stmt_error", MAY_BE_NULL | MAY_BE_STRING),
|
||||
F1("mysqli_stmt_error", MAY_BE_STRING),
|
||||
F1("mysqli_stmt_init", MAY_BE_FALSE | MAY_BE_OBJECT),
|
||||
F1("mysqli_stmt_result_metadata", MAY_BE_FALSE | MAY_BE_OBJECT),
|
||||
F1("mysqli_stmt_sqlstate", MAY_BE_NULL | MAY_BE_STRING),
|
||||
F1("mysqli_stmt_sqlstate", MAY_BE_STRING),
|
||||
F1("mysqli_store_result", MAY_BE_FALSE | MAY_BE_OBJECT),
|
||||
F1("mysqli_use_result", MAY_BE_FALSE | MAY_BE_OBJECT),
|
||||
|
||||
|
||||
@@ -2842,7 +2842,7 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op
|
||||
res_addr,
|
||||
zend_may_throw(opline, ssa_op, op_array, ssa),
|
||||
smart_branch_opcode, target_label, target_label2,
|
||||
NULL)) {
|
||||
NULL, 0)) {
|
||||
goto jit_failure;
|
||||
}
|
||||
goto done;
|
||||
@@ -2871,7 +2871,7 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op
|
||||
RES_REG_ADDR(),
|
||||
zend_may_throw(opline, ssa_op, op_array, ssa),
|
||||
smart_branch_opcode, target_label, target_label2,
|
||||
NULL)) {
|
||||
NULL, 0)) {
|
||||
goto jit_failure;
|
||||
}
|
||||
goto done;
|
||||
@@ -3962,15 +3962,24 @@ ZEND_EXT_API void zend_jit_unprotect(void)
|
||||
{
|
||||
#ifdef HAVE_MPROTECT
|
||||
if (!(JIT_G(debug) & (ZEND_JIT_DEBUG_GDB|ZEND_JIT_DEBUG_PERF_DUMP))) {
|
||||
if (mprotect(dasm_buf, dasm_size, PROT_READ | PROT_WRITE) != 0) {
|
||||
int opts = PROT_READ | PROT_WRITE;
|
||||
#ifdef ZTS
|
||||
/* Another thread may be executing JITed code. */
|
||||
opts |= PROT_EXEC;
|
||||
#endif
|
||||
if (mprotect(dasm_buf, dasm_size, opts) != 0) {
|
||||
fprintf(stderr, "mprotect() failed [%d] %s\n", errno, strerror(errno));
|
||||
}
|
||||
}
|
||||
#elif _WIN32
|
||||
if (!(JIT_G(debug) & (ZEND_JIT_DEBUG_GDB|ZEND_JIT_DEBUG_PERF_DUMP))) {
|
||||
DWORD old;
|
||||
|
||||
if (!VirtualProtect(dasm_buf, dasm_size, PAGE_READWRITE, &old)) {
|
||||
DWORD old, new;
|
||||
#ifdef ZTS
|
||||
new = PAGE_EXECUTE_READWRITE;
|
||||
#else
|
||||
new = PAGE_READWRITE;
|
||||
#endif
|
||||
if (!VirtualProtect(dasm_buf, dasm_size, new, &old)) {
|
||||
DWORD err = GetLastError();
|
||||
char *msg = php_win32_error_to_msg(err);
|
||||
fprintf(stderr, "VirtualProtect() failed [%u] %s\n", err, msg);
|
||||
|
||||
@@ -1625,6 +1625,10 @@ static zend_ssa *zend_jit_trace_build_tssa(zend_jit_trace_rec *trace_buffer, uin
|
||||
break;
|
||||
}
|
||||
ADD_OP2_TRACE_GUARD();
|
||||
if (op1_type != IS_UNKNOWN
|
||||
&& (tssa->var_info[tssa->ops[idx].op1_use].type & MAY_BE_REF)) {
|
||||
ADD_OP1_TRACE_GUARD();
|
||||
}
|
||||
break;
|
||||
case ZEND_CAST:
|
||||
if (opline->extended_value != op1_type) {
|
||||
@@ -3431,6 +3435,89 @@ static void zend_jit_trace_update_condition_ranges(const zend_op *opline, const
|
||||
}
|
||||
}
|
||||
|
||||
static zend_bool zend_jit_may_skip_comparison(const zend_op *opline, const zend_ssa_op *ssa_op, const zend_ssa *ssa, const zend_op **ssa_opcodes)
|
||||
{
|
||||
zend_uchar prev_opcode;
|
||||
|
||||
if (opline->op1_type == IS_CONST
|
||||
&& Z_TYPE_P(RT_CONSTANT(opline, opline->op1)) == IS_LONG
|
||||
&& Z_LVAL_P(RT_CONSTANT(opline, opline->op1)) == 0) {
|
||||
if (ssa_op->op2_use >= 0) {
|
||||
if ((ssa_op-1)->op1_def == ssa_op->op2_use) {
|
||||
prev_opcode = ssa_opcodes[(ssa_op - ssa->ops) - 1]->opcode;
|
||||
if (prev_opcode == ZEND_PRE_INC
|
||||
|| prev_opcode == ZEND_PRE_DEC
|
||||
|| prev_opcode == ZEND_POST_INC
|
||||
|| prev_opcode == ZEND_POST_DEC) {
|
||||
return 1;
|
||||
}
|
||||
} else if ((ssa_op-1)->result_def == ssa_op->op2_use) {
|
||||
prev_opcode = ssa_opcodes[(ssa_op - ssa->ops) - 1]->opcode;
|
||||
if (prev_opcode == ZEND_ADD
|
||||
|| prev_opcode == ZEND_SUB) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (opline->op2_type == IS_CONST
|
||||
&& Z_TYPE_P(RT_CONSTANT(opline, opline->op2)) == IS_LONG
|
||||
&& Z_LVAL_P(RT_CONSTANT(opline, opline->op2)) == 0) {
|
||||
if (ssa_op->op1_use >= 0) {
|
||||
if ((ssa_op-1)->op1_def == ssa_op->op1_use) {
|
||||
prev_opcode = ssa_opcodes[(ssa_op - ssa->ops) - 1]->opcode;
|
||||
if (prev_opcode == ZEND_PRE_INC
|
||||
|| prev_opcode == ZEND_PRE_DEC
|
||||
|| prev_opcode == ZEND_POST_INC
|
||||
|| prev_opcode == ZEND_POST_DEC) {
|
||||
return 1;
|
||||
}
|
||||
} else if ((ssa_op-1)->result_def == ssa_op->op1_use) {
|
||||
prev_opcode = ssa_opcodes[(ssa_op - ssa->ops) - 1]->opcode;
|
||||
if (prev_opcode == ZEND_ADD
|
||||
|| prev_opcode == ZEND_SUB) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
const zend_ssa_op *prev_ssa_op = ssa_op - 1;
|
||||
prev_opcode = ssa_opcodes[prev_ssa_op - ssa->ops]->opcode;
|
||||
|
||||
if ((prev_opcode == ZEND_JMPZ || prev_opcode == ZEND_JMPNZ)
|
||||
&& prev_ssa_op != ssa->ops
|
||||
&& prev_ssa_op->op1_use >= 0
|
||||
&& prev_ssa_op->op1_use == (prev_ssa_op-1)->result_def) {
|
||||
prev_ssa_op--;
|
||||
prev_opcode = ssa_opcodes[prev_ssa_op - ssa->ops]->opcode;
|
||||
}
|
||||
|
||||
if (ssa_op->op1_use == prev_ssa_op->op1_use
|
||||
&& ssa_op->op2_use == prev_ssa_op->op2_use) {
|
||||
if (prev_opcode == ZEND_IS_EQUAL
|
||||
|| prev_opcode == ZEND_IS_NOT_EQUAL
|
||||
|| prev_opcode == ZEND_IS_SMALLER
|
||||
|| prev_opcode == ZEND_IS_SMALLER_OR_EQUAL
|
||||
|| prev_opcode == ZEND_CASE
|
||||
|| prev_opcode == ZEND_IS_IDENTICAL
|
||||
|| prev_opcode == ZEND_IS_NOT_IDENTICAL
|
||||
|| prev_opcode == ZEND_CASE_STRICT) {
|
||||
if (ssa_op->op1_use < 0) {
|
||||
if (opline->op1.constant != ssa_opcodes[prev_ssa_op - ssa->ops]->op1.constant) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (ssa_op->op2_use < 0) {
|
||||
if (opline->op2.constant != ssa_opcodes[prev_ssa_op - ssa->ops]->op2.constant) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t parent_trace, uint32_t exit_num)
|
||||
{
|
||||
const void *handler = NULL;
|
||||
@@ -3451,6 +3538,7 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
|
||||
const void *exit_addr;
|
||||
uint32_t op1_info, op1_def_info, op2_info, res_info, res_use_info, op1_data_info;
|
||||
zend_bool send_result = 0;
|
||||
zend_bool skip_comparison;
|
||||
zend_jit_addr op1_addr, op1_def_addr, op2_addr, op2_def_addr, res_addr;
|
||||
zend_class_entry *ce;
|
||||
zend_bool ce_is_instanceof;
|
||||
@@ -4422,6 +4510,7 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
|
||||
op2_info = OP2_INFO();
|
||||
CHECK_OP2_TRACE_TYPE();
|
||||
op1_info = OP1_INFO();
|
||||
CHECK_OP1_TRACE_TYPE();
|
||||
op1_def_info = OP1_DEF_INFO();
|
||||
op1_addr = OP1_REG_ADDR();
|
||||
op1_def_addr = OP1_DEF_REG_ADDR();
|
||||
@@ -4675,8 +4764,13 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
|
||||
case ZEND_IS_SMALLER_OR_EQUAL:
|
||||
case ZEND_CASE:
|
||||
op1_info = OP1_INFO();
|
||||
CHECK_OP1_TRACE_TYPE();
|
||||
op2_info = OP2_INFO();
|
||||
skip_comparison =
|
||||
ssa_op != ssa->ops &&
|
||||
(op1_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_LONG &&
|
||||
(op2_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_LONG &&
|
||||
zend_jit_may_skip_comparison(opline, ssa_op, ssa, ssa_opcodes);
|
||||
CHECK_OP1_TRACE_TYPE();
|
||||
CHECK_OP2_TRACE_TYPE();
|
||||
if ((opline->result_type & (IS_SMART_BRANCH_JMPZ|IS_SMART_BRANCH_JMPNZ)) != 0) {
|
||||
zend_bool exit_if_true = 0;
|
||||
@@ -4697,7 +4791,7 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
|
||||
op2_info, OP2_RANGE(), OP2_REG_ADDR(),
|
||||
RES_REG_ADDR(),
|
||||
zend_may_throw(opline, ssa_op, op_array, ssa),
|
||||
smart_branch_opcode, -1, -1, exit_addr)) {
|
||||
smart_branch_opcode, -1, -1, exit_addr, skip_comparison)) {
|
||||
goto jit_failure;
|
||||
}
|
||||
zend_jit_trace_update_condition_ranges(opline, ssa_op, op_array, ssa, exit_if_true);
|
||||
@@ -4709,7 +4803,7 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
|
||||
op2_info, OP2_RANGE(), OP2_REG_ADDR(),
|
||||
RES_REG_ADDR(),
|
||||
zend_may_throw(opline, ssa_op, op_array, ssa),
|
||||
smart_branch_opcode, -1, -1, exit_addr)) {
|
||||
smart_branch_opcode, -1, -1, exit_addr, skip_comparison)) {
|
||||
goto jit_failure;
|
||||
}
|
||||
}
|
||||
@@ -4718,8 +4812,13 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
|
||||
case ZEND_IS_NOT_IDENTICAL:
|
||||
case ZEND_CASE_STRICT:
|
||||
op1_info = OP1_INFO();
|
||||
CHECK_OP1_TRACE_TYPE();
|
||||
op2_info = OP2_INFO();
|
||||
skip_comparison =
|
||||
ssa_op != ssa->ops &&
|
||||
(op1_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_LONG &&
|
||||
(op2_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_LONG &&
|
||||
zend_jit_may_skip_comparison(opline, ssa_op, ssa, ssa_opcodes);
|
||||
CHECK_OP1_TRACE_TYPE();
|
||||
CHECK_OP2_TRACE_TYPE();
|
||||
if ((opline->result_type & (IS_SMART_BRANCH_JMPZ|IS_SMART_BRANCH_JMPNZ)) != 0) {
|
||||
zend_bool exit_if_true = 0;
|
||||
@@ -4743,7 +4842,7 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
|
||||
op2_info, OP2_RANGE(), OP2_REG_ADDR(),
|
||||
RES_REG_ADDR(),
|
||||
zend_may_throw(opline, ssa_op, op_array, ssa),
|
||||
smart_branch_opcode, -1, -1, exit_addr)) {
|
||||
smart_branch_opcode, -1, -1, exit_addr, skip_comparison)) {
|
||||
goto jit_failure;
|
||||
}
|
||||
zend_jit_trace_update_condition_ranges(opline, ssa_op, op_array, ssa, exit_if_true);
|
||||
@@ -4755,7 +4854,7 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
|
||||
op2_info, OP2_RANGE(), OP2_REG_ADDR(),
|
||||
RES_REG_ADDR(),
|
||||
zend_may_throw(opline, ssa_op, op_array, ssa),
|
||||
smart_branch_opcode, -1, -1, exit_addr)) {
|
||||
smart_branch_opcode, -1, -1, exit_addr, skip_comparison)) {
|
||||
goto jit_failure;
|
||||
}
|
||||
}
|
||||
@@ -7530,6 +7629,11 @@ static void zend_jit_trace_init_caches(void)
|
||||
static void zend_jit_trace_reset_caches(void)
|
||||
{
|
||||
JIT_G(tracing) = 0;
|
||||
#ifdef ZTS
|
||||
if (!JIT_G(exit_counters)) {
|
||||
JIT_G(exit_counters) = calloc(JIT_G(max_exit_counters), 1);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void zend_jit_trace_restart(void)
|
||||
|
||||
@@ -6745,7 +6745,8 @@ static int zend_jit_cmp_long_long(dasm_State **Dst,
|
||||
zend_uchar smart_branch_opcode,
|
||||
uint32_t target_label,
|
||||
uint32_t target_label2,
|
||||
const void *exit_addr)
|
||||
const void *exit_addr,
|
||||
zend_bool skip_comparison)
|
||||
{
|
||||
zend_bool swap = 0;
|
||||
zend_bool result;
|
||||
@@ -6780,7 +6781,13 @@ static int zend_jit_cmp_long_long(dasm_State **Dst,
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (Z_MODE(op1_addr) == IS_REG) {
|
||||
if (skip_comparison) {
|
||||
if (Z_MODE(op1_addr) != IS_REG &&
|
||||
(Z_MODE(op2_addr) == IS_REG ||
|
||||
(Z_MODE(op1_addr) == IS_CONST_ZVAL && Z_MODE(op2_addr) != IS_CONST_ZVAL))) {
|
||||
swap = 1;
|
||||
}
|
||||
} else if (Z_MODE(op1_addr) == IS_REG) {
|
||||
if (Z_MODE(op2_addr) == IS_CONST_ZVAL && Z_LVAL_P(Z_ZV(op2_addr)) == 0) {
|
||||
| test Ra(Z_REG(op1_addr)), Ra(Z_REG(op1_addr))
|
||||
} else {
|
||||
@@ -7567,7 +7574,8 @@ static int zend_jit_cmp(dasm_State **Dst,
|
||||
zend_uchar smart_branch_opcode,
|
||||
uint32_t target_label,
|
||||
uint32_t target_label2,
|
||||
const void *exit_addr)
|
||||
const void *exit_addr,
|
||||
zend_bool skip_comparison)
|
||||
{
|
||||
zend_bool same_ops = (opline->op1_type == opline->op2_type) && (opline->op1.var == opline->op2.var);
|
||||
zend_bool has_slow;
|
||||
@@ -7603,7 +7611,7 @@ static int zend_jit_cmp(dasm_State **Dst,
|
||||
| IF_NOT_ZVAL_TYPE op2_addr, IS_LONG, >9
|
||||
}
|
||||
}
|
||||
if (!zend_jit_cmp_long_long(Dst, opline, op1_range, op1_addr, op2_range, op2_addr, res_addr, smart_branch_opcode, target_label, target_label2, exit_addr)) {
|
||||
if (!zend_jit_cmp_long_long(Dst, opline, op1_range, op1_addr, op2_range, op2_addr, res_addr, smart_branch_opcode, target_label, target_label2, exit_addr, skip_comparison)) {
|
||||
return 0;
|
||||
}
|
||||
if (op1_info & MAY_BE_DOUBLE) {
|
||||
@@ -7805,7 +7813,8 @@ static int zend_jit_identical(dasm_State **Dst,
|
||||
zend_uchar smart_branch_opcode,
|
||||
uint32_t target_label,
|
||||
uint32_t target_label2,
|
||||
const void *exit_addr)
|
||||
const void *exit_addr,
|
||||
zend_bool skip_comparison)
|
||||
{
|
||||
uint32_t identical_label = (uint32_t)-1;
|
||||
uint32_t not_identical_label = (uint32_t)-1;
|
||||
@@ -7838,7 +7847,7 @@ static int zend_jit_identical(dasm_State **Dst,
|
||||
|
||||
if ((op1_info & (MAY_BE_REF|MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_LONG &&
|
||||
(op2_info & (MAY_BE_REF|MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_LONG) {
|
||||
if (!zend_jit_cmp_long_long(Dst, opline, op1_range, op1_addr, op2_range, op2_addr, res_addr, smart_branch_opcode, target_label, target_label2, exit_addr)) {
|
||||
if (!zend_jit_cmp_long_long(Dst, opline, op1_range, op1_addr, op2_range, op2_addr, res_addr, smart_branch_opcode, target_label, target_label2, exit_addr, skip_comparison)) {
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
@@ -8725,7 +8734,7 @@ static int zend_jit_stack_check(dasm_State **Dst, const zend_op *opline, uint32_
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int zend_jit_push_call_frame(dasm_State **Dst, const zend_op *opline, zend_function *func, zend_bool is_closure, zend_bool use_this, zend_bool stack_check)
|
||||
static int zend_jit_push_call_frame(dasm_State **Dst, const zend_op *opline, const zend_op_array *op_array, zend_function *func, zend_bool is_closure, zend_bool use_this, zend_bool stack_check)
|
||||
{
|
||||
uint32_t used_stack;
|
||||
|
||||
@@ -8798,7 +8807,7 @@ static int zend_jit_push_call_frame(dasm_State **Dst, const zend_op *opline, zen
|
||||
#ifdef _WIN32
|
||||
if (0) {
|
||||
#else
|
||||
if (func && func->type == ZEND_INTERNAL_FUNCTION) {
|
||||
if (opline->opcode == ZEND_INIT_FCALL && func && func->type == ZEND_INTERNAL_FUNCTION) {
|
||||
#endif
|
||||
| SET_EX_OPLINE opline, r0
|
||||
| EXT_CALL zend_jit_int_extend_stack_helper, r0
|
||||
@@ -8830,7 +8839,7 @@ static int zend_jit_push_call_frame(dasm_State **Dst, const zend_op *opline, zen
|
||||
#ifdef _WIN32
|
||||
if (0) {
|
||||
#else
|
||||
if (func && func->type == ZEND_INTERNAL_FUNCTION) {
|
||||
if (opline->opcode == ZEND_INIT_FCALL && func && func->type == ZEND_INTERNAL_FUNCTION) {
|
||||
#endif
|
||||
| // call->func = func;
|
||||
|1:
|
||||
@@ -8838,7 +8847,14 @@ static int zend_jit_push_call_frame(dasm_State **Dst, const zend_op *opline, zen
|
||||
} else {
|
||||
if (!is_closure) {
|
||||
| // call->func = func;
|
||||
| mov aword EX:RX->func, r0
|
||||
if (func
|
||||
&& op_array == &func->op_array
|
||||
&& (func->op_array.fn_flags & ZEND_ACC_IMMUTABLE)
|
||||
&& (sizeof(void*) != 8 || IS_SIGNED_32BIT(func))) {
|
||||
| ADDR_OP2_2 mov, aword EX:RX->func, func, r1
|
||||
} else {
|
||||
| mov aword EX:RX->func, r0
|
||||
}
|
||||
} else {
|
||||
| // call->func = &closure->func;
|
||||
| lea r1, aword [r0 + offsetof(zend_closure, func)]
|
||||
@@ -9200,8 +9216,11 @@ static int zend_jit_init_fcall(dasm_State **Dst, const zend_op *opline, uint32_t
|
||||
#endif
|
||||
/* load constant address later */
|
||||
} else if (func && op_array == &func->op_array) {
|
||||
/* recursive call */
|
||||
| mov r0, EX->func
|
||||
/* recursive call */
|
||||
if (!(func->op_array.fn_flags & ZEND_ACC_IMMUTABLE) ||
|
||||
(sizeof(void*) == 8 && !IS_SIGNED_32BIT(func))) {
|
||||
| mov r0, EX->func
|
||||
}
|
||||
} else {
|
||||
| // if (CACHED_PTR(opline->result.num))
|
||||
| mov r0, EX->run_time_cache
|
||||
@@ -9289,7 +9308,7 @@ static int zend_jit_init_fcall(dasm_State **Dst, const zend_op *opline, uint32_t
|
||||
|3:
|
||||
}
|
||||
|
||||
if (!zend_jit_push_call_frame(Dst, opline, func, 0, 0, stack_check)) {
|
||||
if (!zend_jit_push_call_frame(Dst, opline, op_array, func, 0, 0, stack_check)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -9534,7 +9553,7 @@ static int zend_jit_init_method_call(dasm_State **Dst,
|
||||
}
|
||||
|
||||
if (!func || (func->common.fn_flags & ZEND_ACC_STATIC) == 0) {
|
||||
if (!zend_jit_push_call_frame(Dst, opline, func, 0, use_this, stack_check)) {
|
||||
if (!zend_jit_push_call_frame(Dst, opline, NULL, func, 0, use_this, stack_check)) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -9633,7 +9652,7 @@ static int zend_jit_init_closure_call(dasm_State **Dst,
|
||||
}
|
||||
}
|
||||
|
||||
if (!zend_jit_push_call_frame(Dst, opline, func, 1, 0, stack_check)) {
|
||||
if (!zend_jit_push_call_frame(Dst, opline, NULL, func, 1, 0, stack_check)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -11412,6 +11431,13 @@ static int zend_jit_return(dasm_State **Dst, const zend_op *opline, const zend_o
|
||||
return_value_used = -1;
|
||||
}
|
||||
|
||||
if (ZEND_OBSERVER_ENABLED) {
|
||||
| LOAD_ZVAL_ADDR FCARG2a, op1_addr
|
||||
| mov FCARG1a, FP
|
||||
| SET_EX_OPLINE opline, r0
|
||||
| EXT_CALL zend_observer_fcall_end, r0
|
||||
}
|
||||
|
||||
// if (!EX(return_value))
|
||||
if (Z_MODE(op1_addr) == IS_REG && Z_REG(op1_addr) == ZREG_R1) {
|
||||
if (return_value_used != 0) {
|
||||
@@ -11478,12 +11504,6 @@ static int zend_jit_return(dasm_State **Dst, const zend_op *opline, const zend_o
|
||||
|
||||
if (return_value_used == 0) {
|
||||
|9:
|
||||
if (ZEND_OBSERVER_ENABLED) {
|
||||
| xor FCARG2a, FCARG2a
|
||||
| mov FCARG1a, FP
|
||||
| SET_EX_OPLINE opline, r0
|
||||
| EXT_CALL zend_observer_fcall_end, r0
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -11552,12 +11572,6 @@ static int zend_jit_return(dasm_State **Dst, const zend_op *opline, const zend_o
|
||||
}
|
||||
|
||||
|9:
|
||||
if (ZEND_OBSERVER_ENABLED) {
|
||||
| LOAD_ZVAL_ADDR FCARG2a, ret_addr
|
||||
| mov FCARG1a, FP
|
||||
| SET_EX_OPLINE opline, r0
|
||||
| EXT_CALL zend_observer_fcall_end, r0
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -70,6 +70,8 @@ CODE;
|
||||
$serverCode = sprintf($serverCode, $certFile);
|
||||
|
||||
$clientCode = <<<'CODE'
|
||||
phpt_wait();
|
||||
|
||||
$cmd = 'openssl s_client -connect 127.0.0.1:64321';
|
||||
$descriptorSpec = [["pipe", "r"], ["pipe", "w"], ["pipe", "w"]];
|
||||
$process = proc_open($cmd, $descriptorSpec, $pipes);
|
||||
|
||||
+10
-11
@@ -138,23 +138,22 @@ int pdo_stmt_describe_columns(pdo_stmt_t *stmt) /* {{{ */
|
||||
|
||||
/* if we are applying case conversions on column names, do so now */
|
||||
if (stmt->dbh->native_case != stmt->dbh->desired_case && stmt->dbh->desired_case != PDO_CASE_NATURAL) {
|
||||
char *s = ZSTR_VAL(stmt->columns[col].name);
|
||||
|
||||
zend_string *orig_name = stmt->columns[col].name;
|
||||
switch (stmt->dbh->desired_case) {
|
||||
case PDO_CASE_UPPER:
|
||||
case PDO_CASE_LOWER:
|
||||
stmt->columns[col].name = zend_string_tolower(orig_name);
|
||||
zend_string_release(orig_name);
|
||||
break;
|
||||
case PDO_CASE_UPPER: {
|
||||
stmt->columns[col].name = zend_string_separate(orig_name, 0);
|
||||
char *s = ZSTR_VAL(stmt->columns[col].name);
|
||||
while (*s != '\0') {
|
||||
*s = toupper(*s);
|
||||
s++;
|
||||
}
|
||||
break;
|
||||
case PDO_CASE_LOWER:
|
||||
while (*s != '\0') {
|
||||
*s = tolower(*s);
|
||||
s++;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
;
|
||||
}
|
||||
EMPTY_SWITCH_DEFAULT_CASE()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -136,7 +136,7 @@ static const char classes_array[] = {
|
||||
/* 092 \ */ 0,
|
||||
/* 093 ] */ 0,
|
||||
/* 094 ^ */ 0,
|
||||
/* 095 _ */ 65, /* CHR_IDENT | CHR_INTRODUCER */
|
||||
/* 095 _ */ 68, /* CHR_IDENT | CHR_INTRODUCER */
|
||||
/* 096 ` */ 0,
|
||||
/* 097 a */ 37, /* CHR_LETTER | CHR_IDENT | CHR_HEX */
|
||||
/* 098 b */ 37, /* CHR_LETTER | CHR_IDENT | CHR_HEX */
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
--TEST--
|
||||
Bug #80521 (Parameters with underscores no longer recognized)
|
||||
--SKIPIF--
|
||||
<?php require('skipif.inc'); ?>
|
||||
--FILE--
|
||||
<?php
|
||||
require 'testdb.inc';
|
||||
|
||||
$dbh->exec("CREATE TABLE bug80521 (foo INTEGER)");
|
||||
var_dump($dbh->prepare("SELECT foo FROM bug80521 WHERE foo = :foo_bar"));
|
||||
?>
|
||||
--EXPECTF--
|
||||
object(PDOStatement)#%d (1) {
|
||||
["queryString"]=>
|
||||
string(45) "SELECT foo FROM bug80521 WHERE foo = :foo_bar"
|
||||
}
|
||||
--CLEAN--
|
||||
<?php
|
||||
require 'testdb.inc';
|
||||
$dbh->exec("DROP TABLE bug80521");
|
||||
?>
|
||||
@@ -367,6 +367,10 @@ static const char * const pdo_param_event_names[] =
|
||||
"PDO_PARAM_EVT_NORMALIZE",
|
||||
};
|
||||
|
||||
#ifndef PDO_USE_MYSQLND
|
||||
static unsigned char libmysql_false_buffer = 0;
|
||||
static unsigned char libmysql_true_buffer = 1;
|
||||
#endif
|
||||
|
||||
static int pdo_mysql_stmt_param_hook(pdo_stmt_t *stmt, struct pdo_bound_param_data *param, enum pdo_param_event event_type) /* {{{ */
|
||||
{
|
||||
@@ -503,6 +507,16 @@ static int pdo_mysql_stmt_param_hook(pdo_stmt_t *stmt, struct pdo_bound_param_da
|
||||
*b->length = Z_STRLEN_P(parameter);
|
||||
PDO_DBG_RETURN(1);
|
||||
|
||||
case IS_FALSE:
|
||||
b->buffer_type = MYSQL_TYPE_TINY;
|
||||
b->buffer = &libmysql_false_buffer;
|
||||
PDO_DBG_RETURN(1);
|
||||
|
||||
case IS_TRUE:
|
||||
b->buffer_type = MYSQL_TYPE_TINY;
|
||||
b->buffer = &libmysql_true_buffer;
|
||||
PDO_DBG_RETURN(1);
|
||||
|
||||
case IS_LONG:
|
||||
b->buffer_type = MYSQL_TYPE_LONG;
|
||||
b->buffer = &Z_LVAL_P(parameter);
|
||||
@@ -619,7 +633,11 @@ static int pdo_mysql_stmt_describe(pdo_stmt_t *stmt, int colno) /* {{{ */
|
||||
if (S->H->fetch_table_names) {
|
||||
cols[i].name = strpprintf(0, "%s.%s", S->fields[i].table, S->fields[i].name);
|
||||
} else {
|
||||
#ifdef PDO_USE_MYSQLND
|
||||
cols[i].name = zend_string_copy(S->fields[i].sname);
|
||||
#else
|
||||
cols[i].name = zend_string_init(S->fields[i].name, S->fields[i].name_length, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
cols[i].precision = S->fields[i].decimals;
|
||||
|
||||
@@ -51,8 +51,15 @@ SQL
|
||||
}
|
||||
|
||||
// invalid offset
|
||||
$tmp = @$stmt->getColumnMeta(-1);
|
||||
printf(" 1.3 Expecting false got %s\n", var_export($tmp, true));
|
||||
echo " 1.3 ";
|
||||
try {
|
||||
$tmp = $stmt->getColumnMeta(-1);
|
||||
} catch (ValueError $e) {
|
||||
if (false !== $tmp) {
|
||||
printf("[1.3] Expecting false got %s\n", var_export($tmp, true));
|
||||
}
|
||||
echo $e->getMessage(), "\n";
|
||||
}
|
||||
|
||||
// PDOStatement::getColumnMeta(): Argument #1 must be of type int, array given in
|
||||
echo " 1.4 ";
|
||||
@@ -311,7 +318,7 @@ Preparations before the test
|
||||
Test 1. calling function with invalid parameters
|
||||
1.1 Expecting false got false
|
||||
1.2 PDOStatement::getColumnMeta() expects exactly 1 argument, 0 given
|
||||
1.3 Expecting false got false
|
||||
1.3 PDOStatement::getColumnMeta(): Argument #1 ($column) must be greater than or equal to 0
|
||||
1.4 PDOStatement::getColumnMeta(): Argument #1 ($column) must be of type int, array given
|
||||
1.5 PDOStatement::getColumnMeta() expects exactly 1 argument, 2 given
|
||||
1.6 Expecting false because of invalid offset got false
|
||||
|
||||
+12
-8
@@ -609,7 +609,7 @@ PHP_METHOD(Phar, webPhar)
|
||||
if (NULL == (z_script_name = zend_hash_str_find(_server, "SCRIPT_NAME", sizeof("SCRIPT_NAME")-1)) ||
|
||||
IS_STRING != Z_TYPE_P(z_script_name) ||
|
||||
!strstr(Z_STRVAL_P(z_script_name), basename)) {
|
||||
return;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if (NULL != (z_path_info = zend_hash_str_find(_server, "PATH_INFO", sizeof("PATH_INFO")-1)) &&
|
||||
@@ -634,7 +634,7 @@ PHP_METHOD(Phar, webPhar)
|
||||
testit = sapi_getenv("SCRIPT_NAME", sizeof("SCRIPT_NAME")-1);
|
||||
if (!(pt = strstr(testit, basename))) {
|
||||
efree(testit);
|
||||
return;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
path_info = sapi_getenv("PATH_INFO", sizeof("PATH_INFO")-1);
|
||||
@@ -659,7 +659,7 @@ PHP_METHOD(Phar, webPhar)
|
||||
|
||||
if (!(pt = strstr(path_info, basename))) {
|
||||
/* this can happen with rewrite rules - and we have no idea what to do then, so return */
|
||||
return;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
entry_len = strlen(path_info);
|
||||
@@ -707,7 +707,6 @@ PHP_METHOD(Phar, webPhar)
|
||||
efree(pt);
|
||||
|
||||
zend_bailout();
|
||||
return;
|
||||
default:
|
||||
zend_throw_exception_ex(phar_ce_PharException, 0, "phar error: rewrite callback must return a string or false");
|
||||
|
||||
@@ -718,6 +717,9 @@ cleanup_fail:
|
||||
}
|
||||
efree(entry);
|
||||
efree(pt);
|
||||
#ifdef PHP_WIN32
|
||||
efree(fname);
|
||||
#endif
|
||||
RETURN_THROWS();
|
||||
}
|
||||
}
|
||||
@@ -791,9 +793,6 @@ cleanup_fail:
|
||||
if (FAILURE == phar_get_archive(&phar, fname, fname_len, NULL, 0, NULL) ||
|
||||
(info = phar_get_entry_info(phar, entry, entry_len, NULL, 0)) == NULL) {
|
||||
phar_do_404(phar, fname, fname_len, f404, f404_len, entry, entry_len);
|
||||
#ifdef PHP_WIN32
|
||||
efree(fname);
|
||||
#endif
|
||||
zend_bailout();
|
||||
}
|
||||
|
||||
@@ -847,6 +846,11 @@ cleanup_fail:
|
||||
code = phar_file_type(&PHAR_G(mime_types), entry, &mime_type);
|
||||
}
|
||||
phar_file_action(phar, info, mime_type, code, entry, entry_len, fname, pt, ru, ru_len);
|
||||
|
||||
finish: ;
|
||||
#ifdef PHP_WIN32
|
||||
efree(fname);
|
||||
#endif
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
@@ -4234,7 +4238,7 @@ static int phar_extract_file(zend_bool overwrite, phar_entry_info *entry, char *
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
if (!phar_get_efp(entry, 0)) {
|
||||
if ((phar_get_fp_type(entry) == PHAR_FP && (entry->flags & PHAR_ENT_COMPRESSION_MASK)) || !phar_get_efp(entry, 0)) {
|
||||
if (FAILURE == phar_open_entry_fp(entry, error, 1)) {
|
||||
if (error) {
|
||||
spprintf(error, 4096, "Cannot extract \"%s\" to \"%s\", unable to open internal file pointer: %s", entry->filename, fullpath, *error);
|
||||
|
||||
@@ -134,10 +134,10 @@ class Phar extends RecursiveDirectoryIterator implements Countable, ArrayAccess
|
||||
public function setSignatureAlgorithm(int $algo, ?string $privateKey = null) {}
|
||||
|
||||
/**
|
||||
* @param resource $stub
|
||||
* @param resource|string $stub
|
||||
* @return bool
|
||||
*/
|
||||
public function setStub($stub, int $length = -1) {}
|
||||
public function setStub($stub, int $length = UNKNOWN) {}
|
||||
|
||||
/** @return void */
|
||||
public function startBuffering() {}
|
||||
@@ -298,7 +298,7 @@ class PharData extends RecursiveDirectoryIterator implements Countable, ArrayAcc
|
||||
* @return mixed
|
||||
* @implementation-alias Phar::getMetadata
|
||||
*/
|
||||
public function getMetadata(array $unserialize_options = []) {}
|
||||
public function getMetadata(array $unserializeOptions = []) {}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
@@ -408,11 +408,11 @@ class PharData extends RecursiveDirectoryIterator implements Countable, ArrayAcc
|
||||
public function setSignatureAlgorithm(int $algo, ?string $privateKey = null) {}
|
||||
|
||||
/**
|
||||
* @param resource $newstub
|
||||
* @param resource|string $stub
|
||||
* @return bool
|
||||
* @implementation-alias Phar::setStub
|
||||
*/
|
||||
public function setStub($newstub, int $maxlen = -1) {}
|
||||
public function setStub($stub, int $length = UNKNOWN) {}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* This is a generated file, edit the .stub.php file instead.
|
||||
* Stub hash: e06a2ea3d97778e61aca0f91fda7b72c29ef171d */
|
||||
* Stub hash: 3575a0330ff6102461655bc84add44e8b08b585f */
|
||||
|
||||
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Phar___construct, 0, 0, 1)
|
||||
ZEND_ARG_TYPE_INFO(0, filename, IS_STRING, 0)
|
||||
@@ -139,7 +139,7 @@ ZEND_END_ARG_INFO()
|
||||
|
||||
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Phar_setStub, 0, 0, 1)
|
||||
ZEND_ARG_INFO(0, stub)
|
||||
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, length, IS_LONG, 0, "-1")
|
||||
ZEND_ARG_TYPE_INFO(0, length, IS_LONG, 0)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
#define arginfo_class_Phar_startBuffering arginfo_class_Phar___destruct
|
||||
@@ -254,9 +254,7 @@ ZEND_END_ARG_INFO()
|
||||
|
||||
#define arginfo_class_PharData_getPath arginfo_class_Phar___destruct
|
||||
|
||||
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_PharData_getMetadata, 0, 0, 0)
|
||||
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, unserialize_options, IS_ARRAY, 0, "[]")
|
||||
ZEND_END_ARG_INFO()
|
||||
#define arginfo_class_PharData_getMetadata arginfo_class_Phar_getMetadata
|
||||
|
||||
#define arginfo_class_PharData_getModified arginfo_class_Phar___destruct
|
||||
|
||||
@@ -292,10 +290,7 @@ ZEND_END_ARG_INFO()
|
||||
|
||||
#define arginfo_class_PharData_setSignatureAlgorithm arginfo_class_Phar_setSignatureAlgorithm
|
||||
|
||||
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_PharData_setStub, 0, 0, 1)
|
||||
ZEND_ARG_INFO(0, newstub)
|
||||
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, maxlen, IS_LONG, 0, "-1")
|
||||
ZEND_END_ARG_INFO()
|
||||
#define arginfo_class_PharData_setStub arginfo_class_Phar_setStub
|
||||
|
||||
#define arginfo_class_PharData_startBuffering arginfo_class_Phar___destruct
|
||||
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
--TEST--
|
||||
Bug #69279 (Compressed ZIP Phar extractTo() creates garbage files)
|
||||
--SKIPIF--
|
||||
<?php
|
||||
if (!extension_loaded('phar')) die('skip phar extension not available');
|
||||
?>
|
||||
--INI--
|
||||
phar.readonly=0
|
||||
--FILE--
|
||||
<?php
|
||||
$w = new Phar(__DIR__ . "/bug69279.phar.zip");
|
||||
$w["bug69279.txt"] = "Sample content.";
|
||||
$w->compressFiles(Phar::GZ);
|
||||
unset($w);
|
||||
|
||||
$r = new Phar(__DIR__ . "/bug69279.phar.zip");
|
||||
var_dump($r["bug69279.txt"]->isCompressed());
|
||||
|
||||
$r->extractTo(__DIR__, NULL, TRUE);
|
||||
var_dump(file_get_contents(__DIR__ . "/bug69279.txt"));
|
||||
?>
|
||||
--EXPECT--
|
||||
bool(true)
|
||||
string(15) "Sample content."
|
||||
--CLEAN--
|
||||
<?php
|
||||
@unlink(__DIR__ . "/bug69279.txt");
|
||||
@unlink(__DIR__ . "/bug69279.phar.zip");
|
||||
?>
|
||||
@@ -0,0 +1,26 @@
|
||||
--TEST--
|
||||
Bug #69279 (Compressed ZIP Phar extractTo() creates garbage files)
|
||||
--SKIPIF--
|
||||
<?php
|
||||
if (!extension_loaded('phar')) die('skip phar extension not available');
|
||||
?>
|
||||
--FILE--
|
||||
<?php
|
||||
$phar = new PharData(__DIR__ . '/bug69279a.zip');
|
||||
mkdir(__DIR__ . '/bug69279a');
|
||||
var_dump($phar->extractTo(__DIR__ . '/bug69279a', null, true));
|
||||
var_dump(strncmp(file_get_contents(__DIR__ . '/bug69279a/1.txt'), 'Lorem ipsum', 11));
|
||||
var_dump(strncmp(file_get_contents(__DIR__ . '/bug69279a/2.txt'), 'foo', 3));
|
||||
var_dump(strncmp(file_get_contents(__DIR__ . '/bug69279a/3.txt'), 'Lorem ipsum', 11));
|
||||
?>
|
||||
--EXPECT--
|
||||
bool(true)
|
||||
int(0)
|
||||
int(0)
|
||||
int(0)
|
||||
--CLEAN--
|
||||
<?php
|
||||
@unlink(__DIR__ . '/bug69279a/1.txt');
|
||||
@unlink(__DIR__ . '/bug69279a/2.txt');
|
||||
@unlink(__DIR__ . '/bug69279a/3.txt');
|
||||
@rmdir(__DIR__ . '/bug69279a');
|
||||
Binary file not shown.
@@ -12,7 +12,7 @@ $r = new Phar($fname, 0);
|
||||
}
|
||||
?>
|
||||
--EXPECTF--
|
||||
UnexpectedValueException: phar error: corrupted central directory entry, no magic signature in zip-based phar "%sbug69441.phar" in %sbug69441.php:%d
|
||||
UnexpectedValueException: phar error: end of central directory not found in zip-based phar "%sbug69441.phar" in %sbug69441.php:%d
|
||||
Stack trace:
|
||||
#0 %s%ebug69441.php(%d): Phar->__construct('%s', 0)
|
||||
#1 {main}
|
||||
@@ -0,0 +1,13 @@
|
||||
--TEST--
|
||||
Bug #77565 (Incorrect locator detection in ZIP-based phars)
|
||||
--SKIPIF--
|
||||
<?php
|
||||
if (!extension_loaded('phar')) die('skip phar extension not available');
|
||||
?>
|
||||
--FILE--
|
||||
<?php
|
||||
$phar = new PharData(__DIR__ . '/bug77565.zip');
|
||||
var_dump($phar['1.zip']->getFilename());
|
||||
?>
|
||||
--EXPECT--
|
||||
string(5) "1.zip"
|
||||
Binary file not shown.
@@ -0,0 +1,35 @@
|
||||
--TEST--
|
||||
Bug #79912 (Phar::decompressFiles not working)
|
||||
--SKIPIF--
|
||||
<?php
|
||||
if (!extension_loaded('phar')) die('skip phar extension is not available');
|
||||
?>
|
||||
--INI--
|
||||
phar.readonly=0
|
||||
--FILE--
|
||||
<?php
|
||||
$phar = new Phar(__DIR__ . "/bug79912.phar");
|
||||
$phar->addFromString("test.txt", "This is a test file.This is a test file.This is a test file.");
|
||||
$file = $phar["test.txt"];
|
||||
var_dump($file->compress(Phar::GZ)); //true (success)
|
||||
var_dump($file->getContent());
|
||||
var_dump($file->isCompressed()); //true (the file is compressed)
|
||||
var_dump($phar->decompressFiles()); //true (success)
|
||||
var_dump($file->isCompressed()); //false (the file should not be compressed anymore)
|
||||
var_dump($phar->extractTo(__DIR__ . "/bug79912")); //true
|
||||
var_dump(file_get_contents(__DIR__ . "/bug79912/test.txt")); //the extracted file in the folder should be decompressed
|
||||
?>
|
||||
--EXPECT--
|
||||
bool(true)
|
||||
string(60) "This is a test file.This is a test file.This is a test file."
|
||||
bool(true)
|
||||
bool(true)
|
||||
bool(false)
|
||||
bool(true)
|
||||
string(60) "This is a test file.This is a test file.This is a test file."
|
||||
--CLEAN--
|
||||
<?php
|
||||
@unlink(__DIR__ . "/bug79912/test.txt");
|
||||
@rmdir(__DIR__ . "/bug79912");
|
||||
@unlink(__DIR__ . "/bug79912.phar");
|
||||
?>
|
||||
@@ -1,5 +1,7 @@
|
||||
--TEST--
|
||||
Phar: invalid aliases
|
||||
--INI--
|
||||
phar.require_hash=0
|
||||
--SKIPIF--
|
||||
<?php if (!extension_loaded("phar")) die("skip"); ?>
|
||||
<?php if (!extension_loaded("zlib")) die("skip no zlib"); ?>
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
--TEST--
|
||||
Phar: process bzip2-compressed zip entry
|
||||
--INI--
|
||||
phar.require_hash=0
|
||||
--SKIPIF--
|
||||
<?php if (!extension_loaded("phar")) die("skip"); ?>
|
||||
<?php if (!extension_loaded("bz2")) die("skip bz2 not available"); ?>
|
||||
|
||||
Loaded 100 of 204 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user