[php-src] PHP-8.5: Merge branch 'PHP-8.4' into PHP-8.5

David Carlier <[email protected]>
Newsgroups gmane.comp.php.cvs.general
Message-ID <[email protected]>
Author: David Carlier (devnexen)
Date: 2026-08-26T12:38:18+01:00

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

Merge branch 'PHP-8.4' into PHP-8.5

* PHP-8.4:
  Fix GH-23457: imagebmp() is extremely slow when writing to a file

Changed paths:
  A  ext/gd/tests/gh23457.phpt
  M  ext/gd/gd.c


Diff:

diff --git a/ext/gd/gd.c b/ext/gd/gd.c
index 3370dbd05403..4221999385a1 100644
--- a/ext/gd/gd.c
+++ b/ext/gd/gd.c
@@ -4337,21 +4337,39 @@ static void _php_image_output_ctxfree(struct gdIOCtx *ctx) /* {{{ */
 	efree(ctx);
 } /* }}} */
 
+typedef struct {
+	gdIOCtx ctx;
+	size_t buf_len;
+	unsigned char buf[8192];
+} php_gd_stream_ctx;
+
+static void _php_image_stream_flush(php_gd_stream_ctx *stream_ctx) /* {{{ */
+{
+	if (stream_ctx->buf_len) {
+		php_stream_write((php_stream *) stream_ctx->ctx.data, (char *) stream_ctx->buf, stream_ctx->buf_len);
+		stream_ctx->buf_len = 0;
+	}
+} /* }}} */
+
 static void _php_image_stream_putc(struct gdIOCtx *ctx, int c) /* {{{ */ {
-	char ch = (char) c;
-	php_stream * stream = (php_stream *)ctx->data;
-	php_stream_write(stream, &ch, 1);
+	php_gd_stream_ctx *stream_ctx = (php_gd_stream_ctx *) ctx;
+	if (stream_ctx->buf_len == sizeof(stream_ctx->buf)) {
+		_php_image_stream_flush(stream_ctx);
+	}
+	stream_ctx->buf[stream_ctx->buf_len++] = (unsigned char) c;
 } /* }}} */
 
 static int _php_image_stream_putbuf(struct gdIOCtx *ctx, const void* buf, int l) /* {{{ */
 {
 	php_stream * stream = (php_stream *)ctx->data;
+	_php_image_stream_flush((php_gd_stream_ctx *) ctx);
 	return php_stream_write(stream, (void *)buf, l);
 } /* }}} */
 
 static void _php_image_stream_ctxfree(struct gdIOCtx *ctx) /* {{{ */
 {
 	if(ctx->data) {
+		_php_image_stream_flush((php_gd_stream_ctx *) ctx);
 		ctx->data = NULL;
 	}
 	efree(ctx);
@@ -4360,6 +4378,7 @@ static void _php_image_stream_ctxfree(struct gdIOCtx *ctx) /* {{{ */
 static void _php_image_stream_ctxfreeandclose(struct gdIOCtx *ctx) /* {{{ */
 {
 	if(ctx->data) {
+		_php_image_stream_flush((php_gd_stream_ctx *) ctx);
 		php_stream_close((php_stream *) ctx->data);
 		ctx->data = NULL;
 	}
@@ -4367,7 +4386,8 @@ static void _php_image_stream_ctxfreeandclose(struct gdIOCtx *ctx) /* {{{ */
 } /* }}} */
 
 static gdIOCtx *create_stream_context(php_stream *stream, int close_stream) {
-	gdIOCtx *ctx = ecalloc(1, sizeof(gdIOCtx));
+	php_gd_stream_ctx *stream_ctx = ecalloc(1, sizeof(php_gd_stream_ctx));
+	gdIOCtx *ctx = &stream_ctx->ctx;
 
 	ctx->putC = _php_image_stream_putc;
 	ctx->putBuf = _php_image_stream_putbuf;
diff --git a/ext/gd/tests/gh23457.phpt b/ext/gd/tests/gh23457.phpt
new file mode 100644
index 000000000000..77a3a61900d1
--- /dev/null
+++ b/ext/gd/tests/gh23457.phpt
@@ -0,0 +1,37 @@
+--TEST--
+GH-23457 (imagebmp() writes to the stream one byte at a time)
+--EXTENSIONS--
+gd
+--FILE--
+<?php
+class write_counter
+{
+    public $context;
+
+    public static int $writes = 0;
+
+    public function stream_open(string $path, string $mode, int $options, ?string &$opened_path): bool
+    {
+        return true;
+    }
+
+    public function stream_write(string $data): int
+    {
+        self::$writes++;
+        return strlen($data);
+    }
+
+    public function stream_close(): void
+    {
+    }
+}
+
+stream_wrapper_register('gh23457', write_counter::class);
+
+$im = imagecreatetruecolor(200, 200);
+var_dump(imagebmp($im, 'gh23457://image.bmp'));
+var_dump(write_counter::$writes < 100);
+?>
+--EXPECT--
+bool(true)
+bool(true)
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.