[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)