Commit dcce3459c6e for php.net
commit dcce3459c6ef79af600d5c1c06cd4d73206250af
Author: Weilin Du <weilindu@php.net>
Date: Fri Aug 21 00:05:00 2026 +0800
ext/gd: Add ZPP specifier for array|float parameters (#23384)
Follow-up #23356.
Fixed imageaffinematrixget() to enforce the documented array|float type
for the $options parameter.
diff --git a/NEWS b/NEWS
index 1569f2e064d..78265622e7d 100644
--- a/NEWS
+++ b/NEWS
@@ -33,6 +33,8 @@ PHP NEWS
- GD:
. Fixed imageaffinematrixget() and imageaffinematrixconcat() reporting the
wrong argument in error messages. (Weilin Du)
+ . Fixed imageaffinematrixget() to enforce the documented array|float type
+ for the $options parameter. (Weilin Du)
- Intl:
. Fixed grapheme_strrev() treating UBRK_DONE as a byte index and leaving
diff --git a/UPGRADING b/UPGRADING
index a99299098f9..5054e0a4d81 100644
--- a/UPGRADING
+++ b/UPGRADING
@@ -51,6 +51,9 @@ PHP 8.6 UPGRADE NOTES
- GD:
. imagesetstyle(), imagefilter() and imagecrop() filter their array arguments
types / values and raise a TypeError / ValueError accordingly.
+ . imageaffinematrixget() now enforces the documented array|float type for the
+ $options parameter, including the corresponding weak and strict typing
+ behavior.
- GMP:
. GMP power and shift operators now throw a ValueError when GMP right operands
diff --git a/UPGRADING.INTERNALS b/UPGRADING.INTERNALS
index a83b4f882fe..dc2a35cc9c2 100644
--- a/UPGRADING.INTERNALS
+++ b/UPGRADING.INTERNALS
@@ -185,6 +185,8 @@ PHP 8.6 INTERNALS UPGRADE NOTES
. Added zend_ast_call_get_args() to fetch the argument node from any call
node.
. Added Z_PARAM_ENUM().
+ . Added PHP_GD_Z_PARAM_ARRAY_HT_OR_DOUBLE() in ext/gd to parse array|float
+ arguments into either a HashTable pointer or a double.
. Added zend_enum_fetch_case_id().
. Added zend_enum_get_case_by_id().
. Added zend_bin2hex() and zend_bin2hex_str() as helper functions to remove
diff --git a/ext/gd/gd.c b/ext/gd/gd.c
index f178cea1d79..48f594663b3 100644
--- a/ext/gd/gd.c
+++ b/ext/gd/gd.c
@@ -4152,37 +4152,51 @@ PHP_FUNCTION(imageaffine)
}
/* }}} */
+#define PHP_GD_Z_PARAM_ARRAY_HT_OR_DOUBLE(dest_ht, dest_double) \
+ Z_PARAM_PROLOGUE(0, 0); \
+ if (EXPECTED(Z_TYPE_P(_arg) == IS_ARRAY)) { \
+ dest_ht = Z_ARRVAL_P(_arg); \
+ } else { \
+ dest_ht = NULL; \
+ if (UNEXPECTED(!zend_parse_arg_double(_arg, &dest_double, NULL, false, _i))) { \
+ zend_argument_type_error(_i, "must be of type array|float, %s given", zend_zval_value_name(_arg)); \
+ _error_code = ZPP_ERROR_FAILURE; \
+ break; \
+ } \
+ }
+
/* {{{ Return an image containing the affine tramsformed src image, using an optional clipping area */
PHP_FUNCTION(imageaffinematrixget)
{
double affine[6];
+ double dval_option = 0.0;
zend_long type;
- zval *options = NULL;
+ HashTable *options;
zval *tmp;
int res = GD_FALSE;
ZEND_PARSE_PARAMETERS_START(2, 2)
Z_PARAM_LONG(type)
- Z_PARAM_ZVAL(options)
+ PHP_GD_Z_PARAM_ARRAY_HT_OR_DOUBLE(options, dval_option)
ZEND_PARSE_PARAMETERS_END();
switch((gdAffineStandardMatrix)type) {
case GD_AFFINE_TRANSLATE:
case GD_AFFINE_SCALE: {
double x, y;
- if (Z_TYPE_P(options) != IS_ARRAY) {
+ if (options == NULL) {
zend_argument_type_error(2, "must be of type array when using translate or scale");
RETURN_THROWS();
}
- if ((tmp = zend_hash_str_find(Z_ARRVAL_P(options), "x", sizeof("x") - 1)) != NULL) {
+ if ((tmp = zend_hash_str_find(options, "x", sizeof("x") - 1)) != NULL) {
x = zval_get_double(tmp);
} else {
zend_argument_value_error(2, "must have an \"x\" key");
RETURN_THROWS();
}
- if ((tmp = zend_hash_str_find(Z_ARRVAL_P(options), "y", sizeof("y") - 1)) != NULL) {
+ if ((tmp = zend_hash_str_find(options, "y", sizeof("y") - 1)) != NULL) {
y = zval_get_double(tmp);
} else {
zend_argument_value_error(2, "must have a \"y\" key");
@@ -4202,7 +4216,11 @@ PHP_FUNCTION(imageaffinematrixget)
case GD_AFFINE_SHEAR_VERTICAL: {
double angle;
- angle = zval_get_double(options);
+ if (options != NULL) {
+ zend_argument_type_error(2, "must be of type float when using rotate or shear");
+ RETURN_THROWS();
+ }
+ angle = dval_option;
if (type == GD_AFFINE_SHEAR_HORIZONTAL) {
res = gdAffineShearHorizontal(affine, angle);
diff --git a/ext/gd/gd.stub.php b/ext/gd/gd.stub.php
index 0632724b44f..6a5882c8be7 100644
--- a/ext/gd/gd.stub.php
+++ b/ext/gd/gd.stub.php
@@ -762,11 +762,10 @@ function imagescale(GdImage $image, int $width, int $height = -1, int $mode = IM
function imageaffine(GdImage $image, array $affine, ?array $clip = null): GdImage|false {}
/**
- * @param array|float $options
* @refcount 1
* @return array<int, float>|false
*/
-function imageaffinematrixget(int $type, $options): array|false {}
+function imageaffinematrixget(int $type, array|float $options): array|false {}
/**
* @return array<int, float>|false
diff --git a/ext/gd/gd_arginfo.h b/ext/gd/gd_arginfo.h
index 6b6327fd682..978a7744ec2 100644
Binary files a/ext/gd/gd_arginfo.h and b/ext/gd/gd_arginfo.h differ
diff --git a/ext/gd/tests/bug67248.phpt b/ext/gd/tests/bug67248.phpt
index 5f00b94fadc..9dbbca9fc68 100644
--- a/ext/gd/tests/bug67248.phpt
+++ b/ext/gd/tests/bug67248.phpt
@@ -17,55 +17,10 @@
}
?>
--EXPECTF--
-!! [TypeError] imageaffinematrixget(): Argument #2 ($options) must be of type array when using translate or scale
-!! [TypeError] imageaffinematrixget(): Argument #2 ($options) must be of type array when using translate or scale
-
-Warning: Object of class stdClass could not be converted to float in %s on line %d
-array(6) {
- [0]=>
- float(%f)
- [1]=>
- float(%f)
- [2]=>
- float(%f)
- [3]=>
- float(%f)
- [4]=>
- float(0)
- [5]=>
- float(0)
-}
-
-Warning: Object of class stdClass could not be converted to float in %s on line %d
-array(6) {
- [0]=>
- float(1)
- [1]=>
- float(0)
- [2]=>
- float(%f)
- [3]=>
- float(1)
- [4]=>
- float(0)
- [5]=>
- float(0)
-}
-
-Warning: Object of class stdClass could not be converted to float in %s on line %d
-array(6) {
- [0]=>
- float(1)
- [1]=>
- float(%f)
- [2]=>
- float(0)
- [3]=>
- float(1)
- [4]=>
- float(0)
- [5]=>
- float(0)
-}
-!! [ValueError] imageaffinematrixget(): Argument #1 ($type) must be a valid element type
-!! [ValueError] imageaffinematrixget(): Argument #1 ($type) must be a valid element type
+!! [TypeError] imageaffinematrixget(): Argument #2 ($options) must be of type array|float, stdClass given
+!! [TypeError] imageaffinematrixget(): Argument #2 ($options) must be of type array|float, stdClass given
+!! [TypeError] imageaffinematrixget(): Argument #2 ($options) must be of type array|float, stdClass given
+!! [TypeError] imageaffinematrixget(): Argument #2 ($options) must be of type array|float, stdClass given
+!! [TypeError] imageaffinematrixget(): Argument #2 ($options) must be of type array|float, stdClass given
+!! [TypeError] imageaffinematrixget(): Argument #2 ($options) must be of type array|float, stdClass given
+!! [TypeError] imageaffinematrixget(): Argument #2 ($options) must be of type array|float, stdClass given
diff --git a/ext/gd/tests/bug71952.phpt b/ext/gd/tests/bug71952.phpt
index fa583fc795e..cc86984e9ae 100644
--- a/ext/gd/tests/bug71952.phpt
+++ b/ext/gd/tests/bug71952.phpt
@@ -5,8 +5,13 @@
--FILE--
<?php
$vals=[str_repeat("A","200"),0,1,2,3,4,5,6,7,8,9];
-imageaffinematrixget(4,$vals[0]);
+try {
+ imageaffinematrixget(4, $vals[0]);
+} catch (TypeError $e) {
+ echo $e::class, ': ', $e->getMessage(), "\n";
+}
var_dump($vals[0]);
?>
--EXPECT--
+TypeError: imageaffinematrixget(): Argument #2 ($options) must be of type array|float, string given
string(200) "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
diff --git a/ext/gd/tests/imageaffinematrixget_zpp_strict_mode.phpt b/ext/gd/tests/imageaffinematrixget_zpp_strict_mode.phpt
new file mode 100644
index 00000000000..1fe66b0e516
--- /dev/null
+++ b/ext/gd/tests/imageaffinematrixget_zpp_strict_mode.phpt
@@ -0,0 +1,66 @@
+--TEST--
+imageaffinematrixget() array|float parameter coercions (strict mode)
+--EXTENSIONS--
+gd
+--FILE--
+<?php
+
+declare(strict_types=1);
+
+$values = [
+ 'null' => null,
+ 'false' => false,
+ 'true' => true,
+ 'int' => 42,
+ 'float' => 73.5,
+ 'numeric string' => '15',
+ 'non-numeric string' => 'string',
+ 'array' => [],
+ 'object' => new stdClass(),
+];
+
+foreach ($values as $name => $value) {
+ echo "$name:\n";
+ try {
+ imageaffinematrixget(IMG_AFFINE_ROTATE, $value);
+ echo "accepted\n";
+ } catch (Throwable $e) {
+ echo $e::class, ': ', $e->getMessage(), "\n";
+ }
+}
+
+echo "array for translate:\n";
+imageaffinematrixget(IMG_AFFINE_TRANSLATE, ['x' => 1, 'y' => 2]);
+echo "accepted\n";
+
+echo "float for translate:\n";
+try {
+ imageaffinematrixget(IMG_AFFINE_TRANSLATE, 1.0);
+} catch (Throwable $e) {
+ echo $e::class, ': ', $e->getMessage(), "\n";
+}
+
+?>
+--EXPECT--
+null:
+TypeError: imageaffinematrixget(): Argument #2 ($options) must be of type array|float, null given
+false:
+TypeError: imageaffinematrixget(): Argument #2 ($options) must be of type array|float, false given
+true:
+TypeError: imageaffinematrixget(): Argument #2 ($options) must be of type array|float, true given
+int:
+accepted
+float:
+accepted
+numeric string:
+TypeError: imageaffinematrixget(): Argument #2 ($options) must be of type array|float, string given
+non-numeric string:
+TypeError: imageaffinematrixget(): Argument #2 ($options) must be of type array|float, string given
+array:
+TypeError: imageaffinematrixget(): Argument #2 ($options) must be of type float when using rotate or shear
+object:
+TypeError: imageaffinematrixget(): Argument #2 ($options) must be of type array|float, stdClass given
+array for translate:
+accepted
+float for translate:
+TypeError: imageaffinematrixget(): Argument #2 ($options) must be of type array when using translate or scale
diff --git a/ext/gd/tests/imageaffinematrixget_zpp_weak_mode.phpt b/ext/gd/tests/imageaffinematrixget_zpp_weak_mode.phpt
new file mode 100644
index 00000000000..ffd5523fb83
--- /dev/null
+++ b/ext/gd/tests/imageaffinematrixget_zpp_weak_mode.phpt
@@ -0,0 +1,66 @@
+--TEST--
+imageaffinematrixget() array|float parameter coercions (weak mode)
+--EXTENSIONS--
+gd
+--FILE--
+<?php
+
+$values = [
+ 'null' => null,
+ 'false' => false,
+ 'true' => true,
+ 'int' => 42,
+ 'float' => 73.5,
+ 'numeric string' => '15',
+ 'non-numeric string' => 'string',
+ 'array' => [],
+ 'object' => new stdClass(),
+];
+
+foreach ($values as $name => $value) {
+ echo "$name:\n";
+ try {
+ imageaffinematrixget(IMG_AFFINE_ROTATE, $value);
+ echo "accepted\n";
+ } catch (Throwable $e) {
+ echo $e::class, ': ', $e->getMessage(), "\n";
+ }
+}
+
+echo "array for translate:\n";
+imageaffinematrixget(IMG_AFFINE_TRANSLATE, ['x' => 1, 'y' => 2]);
+echo "accepted\n";
+
+echo "float for translate:\n";
+try {
+ imageaffinematrixget(IMG_AFFINE_TRANSLATE, 1.0);
+} catch (Throwable $e) {
+ echo $e::class, ': ', $e->getMessage(), "\n";
+}
+
+?>
+--EXPECTF--
+null:
+
+Deprecated: imageaffinematrixget(): Passing null to parameter #2 ($options) of type array|float is deprecated in %s on line %d
+accepted
+false:
+accepted
+true:
+accepted
+int:
+accepted
+float:
+accepted
+numeric string:
+accepted
+non-numeric string:
+TypeError: imageaffinematrixget(): Argument #2 ($options) must be of type array|float, string given
+array:
+TypeError: imageaffinematrixget(): Argument #2 ($options) must be of type float when using rotate or shear
+object:
+TypeError: imageaffinematrixget(): Argument #2 ($options) must be of type array|float, stdClass given
+array for translate:
+accepted
+float for translate:
+TypeError: imageaffinematrixget(): Argument #2 ($options) must be of type array when using translate or scale