[php-src] master: Merge branch '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:24+01:00

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

Merge branch 'PHP-8.5'

* PHP-8.5:
  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 48f594663b3e..a6d51ccbce81 100644
--- a/ext/gd/gd.c
+++ b/ext/gd/gd.c
@@ -4440,21 +4440,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);
@@ -4463,6 +4481,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;
 	}
@@ -4470,7 +4489,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.