[php-src] master: ext/gd: Add ZPP specifier for array|float parameters (#23384)

Weilin Du via GitHub <[email protected]>
Newsgroups gmane.comp.php.cvs.general
Message-ID <[email protected]>
Author: Weilin Du (LamentXU123)
Committer: GitHub (web-flow)
Pusher: LamentXU123
Date: 2026-08-21T00:05:00+08:00

Commit: https://github.com/php/php-src/commit/dcce3459c6ef79af600d5c1c06cd4d73206250af
Raw diff: https://github.com/php/php-src/commit/dcce3459c6ef79af600d5c1c06cd4d73206250af.diff

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.

Changed paths:
  A  ext/gd/tests/imageaffinematrixget_zpp_strict_mode.phpt
  A  ext/gd/tests/imageaffinematrixget_zpp_weak_mode.phpt
  M  NEWS
  M  UPGRADING
  M  UPGRADING.INTERNALS
  M  ext/gd/gd.c
  M  ext/gd/gd.stub.php
  M  ext/gd/gd_arginfo.h
  M  ext/gd/tests/bug67248.phpt
  M  ext/gd/tests/bug71952.phpt


Diff:

diff --git a/NEWS b/NEWS
index 1569f2e064d5..78265622e7d7 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 a99299098f98..5054e0a4d81f 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 a83b4f882fe2..dc2a35cc9c2c 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 f178cea1d799..48f594663b3e 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 0632724b44f3..6a5882c8be75 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 6b6327fd682f..978a7744ec28 100644
--- a/ext/gd/gd_arginfo.h
+++ b/ext/gd/gd_arginfo.h
@@ -1,5 +1,5 @@
 /* This is a generated file, edit gd.stub.php instead.
- * Stub hash: 2cdc0b485d9b62bb9021973d3c8cce0169b21ac0 */
+ * Stub hash: 21f8a978b8e54da880315dd9dfeecaf0f7d5593b */
 
 ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_gd_info, 0, 0, IS_ARRAY, 0)
 ZEND_END_ARG_INFO()
@@ -538,7 +538,7 @@ ZEND_END_ARG_INFO()
 
 ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_imageaffinematrixget, 0, 2, MAY_BE_ARRAY|MAY_BE_FALSE)
 	ZEND_ARG_TYPE_INFO(0, type, IS_LONG, 0)
-	ZEND_ARG_INFO(0, options)
+	ZEND_ARG_TYPE_MASK(0, options, MAY_BE_ARRAY|MAY_BE_DOUBLE, NULL)
 ZEND_END_ARG_INFO()
 
 ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_imageaffinematrixconcat, 0, 2, MAY_BE_ARRAY|MAY_BE_FALSE)
diff --git a/ext/gd/tests/bug67248.phpt b/ext/gd/tests/bug67248.phpt
index 5f00b94fadcd..9dbbca9fc68c 100644
--- a/ext/gd/tests/bug67248.phpt
+++ b/ext/gd/tests/bug67248.phpt
@@ -17,55 +17,10 @@ for($i=0;$i<7;$i++) {
 }
 ?>
 --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 fa583fc795e8..cc86984e9ae0 100644
--- a/ext/gd/tests/bug71952.phpt
+++ b/ext/gd/tests/bug71952.phpt
@@ -5,8 +5,13 @@ gd
 --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 000000000000..1fe66b0e516f
--- /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 000000000000..ffd5523fb83b
--- /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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.