From 7a50ec4ed631405c7222c890aef8fb7a6dcc5183 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Fri, 1 Nov 2024 14:57:32 +0100 Subject: [PATCH 1/4] Expose gfxinfo as php_gfxinfo This is necessary for future commits, when we extend the image handling to support extensions adding their own handlers. Also extend the struct with fields for when the width and height are not numbers but strings (e.g. for SVG). --- ext/standard/image.c | 109 ++++++++++++++++++--------------------- ext/standard/php_image.h | 10 ++++ 2 files changed, 60 insertions(+), 59 deletions(-) diff --git a/ext/standard/image.c b/ext/standard/image.c index ef0ddade3be3c..f7bcb01f2df45 100644 --- a/ext/standard/image.c +++ b/ext/standard/image.c @@ -59,20 +59,11 @@ PHPAPI const char php_sig_heix[4] = {'h', 'e', 'i', 'x'}; /* REMEMBER TO ADD MIME-TYPE TO FUNCTION php_image_type_to_mime_type */ /* PCX must check first 64bytes and byte 0=0x0a and byte2 < 0x06 */ -/* return info as a struct, to make expansion easier */ - -struct gfxinfo { - unsigned int width; - unsigned int height; - unsigned int bits; - unsigned int channels; -}; - /* {{{ php_handle_gif * routine to handle GIF files. If only everything were that easy... ;} */ -static struct gfxinfo *php_handle_gif (php_stream * stream) +static struct php_gfxinfo *php_handle_gif (php_stream * stream) { - struct gfxinfo *result = NULL; + struct php_gfxinfo *result = NULL; unsigned char dim[5]; if (php_stream_seek(stream, 3, SEEK_CUR)) @@ -81,7 +72,7 @@ static struct gfxinfo *php_handle_gif (php_stream * stream) if (php_stream_read(stream, (char*)dim, sizeof(dim)) != sizeof(dim)) return NULL; - result = (struct gfxinfo *) ecalloc(1, sizeof(struct gfxinfo)); + result = (struct php_gfxinfo *) ecalloc(1, sizeof(struct php_gfxinfo)); result->width = (unsigned int)dim[0] | (((unsigned int)dim[1])<<8); result->height = (unsigned int)dim[2] | (((unsigned int)dim[3])<<8); result->bits = dim[4]&0x80 ? ((((unsigned int)dim[4])&0x07) + 1) : 0; @@ -92,9 +83,9 @@ static struct gfxinfo *php_handle_gif (php_stream * stream) /* }}} */ /* {{{ php_handle_psd */ -static struct gfxinfo *php_handle_psd (php_stream * stream) +static struct php_gfxinfo *php_handle_psd (php_stream * stream) { - struct gfxinfo *result = NULL; + struct php_gfxinfo *result = NULL; unsigned char dim[8]; if (php_stream_seek(stream, 11, SEEK_CUR)) @@ -103,7 +94,7 @@ static struct gfxinfo *php_handle_psd (php_stream * stream) if (php_stream_read(stream, (char*)dim, sizeof(dim)) != sizeof(dim)) return NULL; - result = (struct gfxinfo *) ecalloc(1, sizeof(struct gfxinfo)); + result = (struct php_gfxinfo *) ecalloc(1, sizeof(struct php_gfxinfo)); result->height = (((unsigned int)dim[0]) << 24) + (((unsigned int)dim[1]) << 16) + (((unsigned int)dim[2]) << 8) + ((unsigned int)dim[3]); result->width = (((unsigned int)dim[4]) << 24) + (((unsigned int)dim[5]) << 16) + (((unsigned int)dim[6]) << 8) + ((unsigned int)dim[7]); @@ -112,9 +103,9 @@ static struct gfxinfo *php_handle_psd (php_stream * stream) /* }}} */ /* {{{ php_handle_bmp */ -static struct gfxinfo *php_handle_bmp (php_stream * stream) +static struct php_gfxinfo *php_handle_bmp (php_stream * stream) { - struct gfxinfo *result = NULL; + struct php_gfxinfo *result = NULL; unsigned char dim[16]; int size; @@ -126,12 +117,12 @@ static struct gfxinfo *php_handle_bmp (php_stream * stream) size = (((unsigned int)dim[ 3]) << 24) + (((unsigned int)dim[ 2]) << 16) + (((unsigned int)dim[ 1]) << 8) + ((unsigned int) dim[ 0]); if (size == 12) { - result = (struct gfxinfo *) ecalloc (1, sizeof(struct gfxinfo)); + result = (struct php_gfxinfo *) ecalloc (1, sizeof(struct php_gfxinfo)); result->width = (((unsigned int)dim[ 5]) << 8) + ((unsigned int) dim[ 4]); result->height = (((unsigned int)dim[ 7]) << 8) + ((unsigned int) dim[ 6]); result->bits = ((unsigned int)dim[11]); } else if (size > 12 && (size <= 64 || size == 108 || size == 124)) { - result = (struct gfxinfo *) ecalloc (1, sizeof(struct gfxinfo)); + result = (struct php_gfxinfo *) ecalloc (1, sizeof(struct php_gfxinfo)); result->width = (((unsigned int)dim[ 7]) << 24) + (((unsigned int)dim[ 6]) << 16) + (((unsigned int)dim[ 5]) << 8) + ((unsigned int) dim[ 4]); result->height = (((unsigned int)dim[11]) << 24) + (((unsigned int)dim[10]) << 16) + (((unsigned int)dim[ 9]) << 8) + ((unsigned int) dim[ 8]); result->height = abs((int32_t)result->height); @@ -162,9 +153,9 @@ static unsigned long int php_swf_get_bits (unsigned char* buffer, unsigned int p #if defined(HAVE_ZLIB) && !defined(COMPILE_DL_ZLIB) /* {{{ php_handle_swc */ -static struct gfxinfo *php_handle_swc(php_stream * stream) +static struct php_gfxinfo *php_handle_swc(php_stream * stream) { - struct gfxinfo *result = NULL; + struct php_gfxinfo *result = NULL; long bits; unsigned char a[64]; @@ -231,7 +222,7 @@ static struct gfxinfo *php_handle_swc(php_stream * stream) } if (!status) { - result = (struct gfxinfo *) ecalloc (1, sizeof (struct gfxinfo)); + result = (struct php_gfxinfo *) ecalloc (1, sizeof (struct php_gfxinfo)); bits = php_swf_get_bits (b, 0, 5); result->width = (php_swf_get_bits (b, 5 + bits, bits) - php_swf_get_bits (b, 5, bits)) / 20; @@ -248,9 +239,9 @@ static struct gfxinfo *php_handle_swc(php_stream * stream) #endif /* {{{ php_handle_swf */ -static struct gfxinfo *php_handle_swf (php_stream * stream) +static struct php_gfxinfo *php_handle_swf (php_stream * stream) { - struct gfxinfo *result = NULL; + struct php_gfxinfo *result = NULL; long bits; unsigned char a[32]; @@ -260,7 +251,7 @@ static struct gfxinfo *php_handle_swf (php_stream * stream) if (php_stream_read(stream, (char*)a, sizeof(a)) != sizeof(a)) return NULL; - result = (struct gfxinfo *) ecalloc (1, sizeof (struct gfxinfo)); + result = (struct php_gfxinfo *) ecalloc (1, sizeof (struct php_gfxinfo)); bits = php_swf_get_bits (a, 0, 5); result->width = (php_swf_get_bits (a, 5 + bits, bits) - php_swf_get_bits (a, 5, bits)) / 20; @@ -274,9 +265,9 @@ static struct gfxinfo *php_handle_swf (php_stream * stream) /* {{{ php_handle_png * routine to handle PNG files */ -static struct gfxinfo *php_handle_png (php_stream * stream) +static struct php_gfxinfo *php_handle_png (php_stream * stream) { - struct gfxinfo *result = NULL; + struct php_gfxinfo *result = NULL; unsigned char dim[9]; /* Width: 4 bytes * Height: 4 bytes @@ -293,7 +284,7 @@ static struct gfxinfo *php_handle_png (php_stream * stream) if((php_stream_read(stream, (char*)dim, sizeof(dim))) < sizeof(dim)) return NULL; - result = (struct gfxinfo *) ecalloc(1, sizeof(struct gfxinfo)); + result = (struct php_gfxinfo *) ecalloc(1, sizeof(struct php_gfxinfo)); result->width = (((unsigned int)dim[0]) << 24) + (((unsigned int)dim[1]) << 16) + (((unsigned int)dim[2]) << 8) + ((unsigned int)dim[3]); result->height = (((unsigned int)dim[4]) << 24) + (((unsigned int)dim[5]) << 16) + (((unsigned int)dim[6]) << 8) + ((unsigned int)dim[7]); result->bits = (unsigned int)dim[8]; @@ -452,9 +443,9 @@ static int php_read_APP(php_stream * stream, unsigned int marker, zval *info) /* {{{ php_handle_jpeg main loop to parse JPEG structure */ -static struct gfxinfo *php_handle_jpeg (php_stream * stream, zval *info) +static struct php_gfxinfo *php_handle_jpeg (php_stream * stream, zval *info) { - struct gfxinfo *result = NULL; + struct php_gfxinfo *result = NULL; unsigned int marker = M_PSEUDO; unsigned short length, ff_read=1; @@ -477,7 +468,7 @@ static struct gfxinfo *php_handle_jpeg (php_stream * stream, zval *info) case M_SOF15: if (result == NULL) { /* handle SOFn block */ - result = (struct gfxinfo *) ecalloc(1, sizeof(struct gfxinfo)); + result = (struct php_gfxinfo *) ecalloc(1, sizeof(struct php_gfxinfo)); length = php_read2(stream); result->bits = php_stream_getc(stream); result->height = php_read2(stream); @@ -580,9 +571,9 @@ static unsigned int php_read4(php_stream * stream) /* {{{ php_handle_jpc Main loop to parse JPEG2000 raw codestream structure */ -static struct gfxinfo *php_handle_jpc(php_stream * stream) +static struct php_gfxinfo *php_handle_jpc(php_stream * stream) { - struct gfxinfo *result = NULL; + struct php_gfxinfo *result = NULL; int highest_bit_depth, bit_depth; unsigned char first_marker_id; unsigned int i; @@ -603,7 +594,7 @@ static struct gfxinfo *php_handle_jpc(php_stream * stream) return NULL; } - result = (struct gfxinfo *)ecalloc(1, sizeof(struct gfxinfo)); + result = (struct php_gfxinfo *)ecalloc(1, sizeof(struct php_gfxinfo)); php_read2(stream); /* Lsiz */ php_read2(stream); /* Rsiz */ @@ -651,9 +642,9 @@ static struct gfxinfo *php_handle_jpc(php_stream * stream) /* {{{ php_handle_jp2 main loop to parse JPEG 2000 JP2 wrapper format structure */ -static struct gfxinfo *php_handle_jp2(php_stream *stream) +static struct php_gfxinfo *php_handle_jp2(php_stream *stream) { - struct gfxinfo *result = NULL; + struct php_gfxinfo *result = NULL; unsigned int box_length; unsigned int box_type; char jp2c_box_id[] = {(char)0x6a, (char)0x70, (char)0x32, (char)0x63}; @@ -777,9 +768,9 @@ static unsigned php_ifd_get32u(void *Long, int motorola_intel) /* {{{ php_handle_tiff main loop to parse TIFF structure */ -static struct gfxinfo *php_handle_tiff (php_stream * stream, zval *info, int motorola_intel) +static struct php_gfxinfo *php_handle_tiff (php_stream * stream, zval *info, int motorola_intel) { - struct gfxinfo *result = NULL; + struct php_gfxinfo *result = NULL; int i, num_entries; unsigned char *dir_entry; size_t ifd_size, dir_size, entry_value, width=0, height=0, ifd_addr; @@ -845,7 +836,7 @@ static struct gfxinfo *php_handle_tiff (php_stream * stream, zval *info, int mot efree(ifd_data); if ( width && height) { /* not the same when in for-loop */ - result = (struct gfxinfo *) ecalloc(1, sizeof(struct gfxinfo)); + result = (struct php_gfxinfo *) ecalloc(1, sizeof(struct php_gfxinfo)); result->height = height; result->width = width; result->bits = 0; @@ -857,9 +848,9 @@ static struct gfxinfo *php_handle_tiff (php_stream * stream, zval *info, int mot /* }}} */ /* {{{ php_handle_psd */ -static struct gfxinfo *php_handle_iff(php_stream * stream) +static struct php_gfxinfo *php_handle_iff(php_stream * stream) { - struct gfxinfo * result; + struct php_gfxinfo * result; unsigned char a[10]; int chunkId; int size; @@ -893,7 +884,7 @@ static struct gfxinfo *php_handle_iff(php_stream * stream) height = php_ifd_get16s(a+2, 1); bits = a[8] & 0xff; if (width > 0 && height > 0 && bits > 0 && bits < 33) { - result = (struct gfxinfo *) ecalloc(1, sizeof(struct gfxinfo)); + result = (struct php_gfxinfo *) ecalloc(1, sizeof(struct php_gfxinfo)); result->width = width; result->height = height; result->bits = bits; @@ -918,7 +909,7 @@ static struct gfxinfo *php_handle_iff(php_stream * stream) * int Number of columns * int Number of rows */ -static int php_get_wbmp(php_stream *stream, struct gfxinfo **result, int check) +static int php_get_wbmp(php_stream *stream, struct php_gfxinfo **result, int check) { int i, width = 0, height = 0; @@ -979,9 +970,9 @@ static int php_get_wbmp(php_stream *stream, struct gfxinfo **result, int check) /* }}} */ /* {{{ php_handle_wbmp */ -static struct gfxinfo *php_handle_wbmp(php_stream * stream) +static struct php_gfxinfo *php_handle_wbmp(php_stream * stream) { - struct gfxinfo *result = (struct gfxinfo *) ecalloc(1, sizeof(struct gfxinfo)); + struct php_gfxinfo *result = (struct php_gfxinfo *) ecalloc(1, sizeof(struct php_gfxinfo)); if (!php_get_wbmp(stream, &result, 0)) { efree(result); @@ -993,7 +984,7 @@ static struct gfxinfo *php_handle_wbmp(php_stream * stream) /* }}} */ /* {{{ php_get_xbm */ -static int php_get_xbm(php_stream *stream, struct gfxinfo **result) +static int php_get_xbm(php_stream *stream, struct php_gfxinfo **result) { char *fline; char *iname; @@ -1040,7 +1031,7 @@ static int php_get_xbm(php_stream *stream, struct gfxinfo **result) if (width && height) { if (result) { - *result = (struct gfxinfo *) ecalloc(1, sizeof(struct gfxinfo)); + *result = (struct php_gfxinfo *) ecalloc(1, sizeof(struct php_gfxinfo)); (*result)->width = width; (*result)->height = height; } @@ -1052,18 +1043,18 @@ static int php_get_xbm(php_stream *stream, struct gfxinfo **result) /* }}} */ /* {{{ php_handle_xbm */ -static struct gfxinfo *php_handle_xbm(php_stream * stream) +static struct php_gfxinfo *php_handle_xbm(php_stream * stream) { - struct gfxinfo *result; + struct php_gfxinfo *result; php_get_xbm(stream, &result); return result; } /* }}} */ /* {{{ php_handle_ico */ -static struct gfxinfo *php_handle_ico(php_stream * stream) +static struct php_gfxinfo *php_handle_ico(php_stream * stream) { - struct gfxinfo *result = NULL; + struct php_gfxinfo *result = NULL; unsigned char dim[16]; int num_icons = 0; @@ -1075,7 +1066,7 @@ static struct gfxinfo *php_handle_ico(php_stream * stream) if (num_icons < 1 || num_icons > 255) return NULL; - result = (struct gfxinfo *) ecalloc(1, sizeof(struct gfxinfo)); + result = (struct php_gfxinfo *) ecalloc(1, sizeof(struct php_gfxinfo)); while (num_icons > 0) { @@ -1102,9 +1093,9 @@ static struct gfxinfo *php_handle_ico(php_stream * stream) /* }}} */ /* {{{ php_handle_webp */ -static struct gfxinfo *php_handle_webp(php_stream * stream) +static struct php_gfxinfo *php_handle_webp(php_stream * stream) { - struct gfxinfo *result = NULL; + struct php_gfxinfo *result = NULL; const char sig[3] = {'V', 'P', '8'}; unsigned char buf[18]; char format; @@ -1125,7 +1116,7 @@ static struct gfxinfo *php_handle_webp(php_stream * stream) return NULL; } - result = (struct gfxinfo *) ecalloc(1, sizeof(struct gfxinfo)); + result = (struct php_gfxinfo *) ecalloc(1, sizeof(struct php_gfxinfo)); switch (format) { case ' ': @@ -1187,14 +1178,14 @@ static void php_avif_stream_skip(void* stream, size_t num_bytes) { * declared as invalid. Around 450 bytes are usually enough. * Transforms such as mirror and rotation are not applied on width and height. */ -static struct gfxinfo *php_handle_avif(php_stream * stream) { - struct gfxinfo* result = NULL; +static struct php_gfxinfo *php_handle_avif(php_stream * stream) { + struct php_gfxinfo* result = NULL; AvifInfoFeatures features; struct php_avif_stream avif_stream; avif_stream.stream = stream; if (AvifInfoGetFeaturesStream(&avif_stream, php_avif_stream_read, php_avif_stream_skip, &features) == kAvifInfoOk) { - result = (struct gfxinfo*)ecalloc(1, sizeof(struct gfxinfo)); + result = (struct php_gfxinfo*)ecalloc(1, sizeof(struct php_gfxinfo)); result->width = features.width; result->height = features.height; result->bits = features.bit_depth; @@ -1463,7 +1454,7 @@ PHPAPI int php_getimagetype(php_stream *stream, const char *input, char *filetyp static void php_getimagesize_from_stream(php_stream *stream, char *input, zval *info, INTERNAL_FUNCTION_PARAMETERS) /* {{{ */ { int itype = 0; - struct gfxinfo *result = NULL; + struct php_gfxinfo *result = NULL; if (!stream) { RETURN_FALSE; diff --git a/ext/standard/php_image.h b/ext/standard/php_image.h index f0f3edb7283eb..41f16c29906bb 100644 --- a/ext/standard/php_image.h +++ b/ext/standard/php_image.h @@ -56,4 +56,14 @@ PHPAPI char * php_image_type_to_mime_type(int image_type); PHPAPI bool php_is_image_avif(php_stream *stream); +/* return info as a struct, to make expansion easier */ +struct php_gfxinfo { + unsigned int width; + unsigned int height; + zend_string *width_str; + zend_string *height_str; + unsigned int bits; + unsigned int channels; +}; + #endif /* PHP_IMAGE_H */ From 4afb8cab083b8af9d6fe2938df98cef9c792d3ab Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Fri, 1 Nov 2024 14:59:43 +0100 Subject: [PATCH 2/4] Add API to register custom image handlers This is modelled similarly to the password registry API. We have an array to which new handlers can be added, and when a built-in handler cannot handle the image, we try the handlers in the array. The standard module is in control of registering a new constant for the image file type so that no clashes can occur. It also updates the image file type count constant. As such, the registration may only happen during module startup. --- ext/standard/basic_functions.c | 2 + ext/standard/basic_functions.stub.php | 2 +- ext/standard/basic_functions_arginfo.h | 4 +- ext/standard/image.c | 98 ++++++++++++++++--- ext/standard/php_image.h | 25 ++++- .../image_type_to_mime_type_variation3.phpt | 54 +++++----- 6 files changed, 145 insertions(+), 40 deletions(-) diff --git a/ext/standard/basic_functions.c b/ext/standard/basic_functions.c index ea2f8884bdef6..24f7f9267209c 100644 --- a/ext/standard/basic_functions.c +++ b/ext/standard/basic_functions.c @@ -303,6 +303,7 @@ PHP_MINIT_FUNCTION(basic) /* {{{ */ BASIC_MINIT_SUBMODULE(standard_filters) BASIC_MINIT_SUBMODULE(user_filters) BASIC_MINIT_SUBMODULE(password) + BASIC_MINIT_SUBMODULE(image) #ifdef ZTS BASIC_MINIT_SUBMODULE(localeconv) @@ -376,6 +377,7 @@ PHP_MSHUTDOWN_FUNCTION(basic) /* {{{ */ #endif BASIC_MSHUTDOWN_SUBMODULE(crypt) BASIC_MSHUTDOWN_SUBMODULE(password) + BASIC_MSHUTDOWN_SUBMODULE(image) return SUCCESS; } diff --git a/ext/standard/basic_functions.stub.php b/ext/standard/basic_functions.stub.php index c401fd7afcd0b..2d4798a14db78 100644 --- a/ext/standard/basic_functions.stub.php +++ b/ext/standard/basic_functions.stub.php @@ -658,7 +658,7 @@ const IMAGETYPE_UNKNOWN = UNKNOWN; /** * @var int - * @cvalue IMAGE_FILETYPE_COUNT + * @cvalue IMAGE_FILETYPE_FIXED_COUNT */ const IMAGETYPE_COUNT = UNKNOWN; diff --git a/ext/standard/basic_functions_arginfo.h b/ext/standard/basic_functions_arginfo.h index b181d7a4244de..6c31b6a83528c 100644 --- a/ext/standard/basic_functions_arginfo.h +++ b/ext/standard/basic_functions_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 33629477a13fc7b675fe47eeaaac0d9e15dd2e17 */ + * Stub hash: dcc4e6865dac52b23534b6ef61c0d6be766af6b9 */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_set_time_limit, 0, 1, _IS_BOOL, 0) ZEND_ARG_TYPE_INFO(0, seconds, IS_LONG, 0) @@ -3647,7 +3647,7 @@ static void register_basic_functions_symbols(int module_number) REGISTER_LONG_CONSTANT("IMAGETYPE_AVIF", IMAGE_FILETYPE_AVIF, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("IMAGETYPE_HEIF", IMAGE_FILETYPE_HEIF, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("IMAGETYPE_UNKNOWN", IMAGE_FILETYPE_UNKNOWN, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("IMAGETYPE_COUNT", IMAGE_FILETYPE_COUNT, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("IMAGETYPE_COUNT", IMAGE_FILETYPE_FIXED_COUNT, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("INFO_GENERAL", PHP_INFO_GENERAL, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("INFO_CREDITS", PHP_INFO_CREDITS, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("INFO_CONFIGURATION", PHP_INFO_CONFIGURATION, CONST_PERSISTENT); diff --git a/ext/standard/image.c b/ext/standard/image.c index f7bcb01f2df45..5678ae52c985f 100644 --- a/ext/standard/image.c +++ b/ext/standard/image.c @@ -56,6 +56,9 @@ PHPAPI const char php_sig_mif1[4] = {'m', 'i', 'f', '1'}; PHPAPI const char php_sig_heic[4] = {'h', 'e', 'i', 'c'}; PHPAPI const char php_sig_heix[4] = {'h', 'e', 'i', 'x'}; +static zend_array php_image_handlers; +static int php_image_handler_next_id = IMAGE_FILETYPE_FIXED_COUNT; + /* REMEMBER TO ADD MIME-TYPE TO FUNCTION php_image_type_to_mime_type */ /* PCX must check first 64bytes and byte 0=0x0a and byte2 < 0x06 */ @@ -1214,7 +1217,7 @@ bool php_is_image_avif(php_stream* stream) { /* {{{ php_image_type_to_mime_type * Convert internal image_type to mime type */ -PHPAPI char * php_image_type_to_mime_type(int image_type) +PHPAPI const char * php_image_type_to_mime_type(int image_type) { switch( image_type) { case IMAGE_FILETYPE_GIF: @@ -1251,7 +1254,13 @@ PHPAPI char * php_image_type_to_mime_type(int image_type) return "image/avif"; case IMAGE_FILETYPE_HEIF: return "image/heif"; - default: + default: { + const struct php_image_handler *handler = zend_hash_index_find_ptr(&php_image_handlers, (zend_ulong) image_type); + if (handler) { + return handler->mime_type; + } + ZEND_FALLTHROUGH; + } case IMAGE_FILETYPE_UNKNOWN: return "application/octet-stream"; /* suppose binary format */ } @@ -1267,7 +1276,7 @@ PHP_FUNCTION(image_type_to_mime_type) Z_PARAM_LONG(p_image_type) ZEND_PARSE_PARAMETERS_END(); - ZVAL_STRING(return_value, (char*)php_image_type_to_mime_type(p_image_type)); + ZVAL_STRING(return_value, php_image_type_to_mime_type(p_image_type)); } /* }}} */ @@ -1339,7 +1348,13 @@ PHP_FUNCTION(image_type_to_extension) case IMAGE_FILETYPE_HEIF: imgext = ".heif"; break; - break; + default: { + const struct php_image_handler *handler = zend_hash_index_find_ptr(&php_image_handlers, (zend_ulong) image_type); + if (handler) { + imgext = handler->extension; + } + break; + } } if (imgext) { @@ -1447,6 +1462,15 @@ PHPAPI int php_getimagetype(php_stream *stream, const char *input, char *filetyp return IMAGE_FILETYPE_XBM; } + zend_ulong h; + zval *zv; + ZEND_HASH_FOREACH_NUM_KEY_VAL(&php_image_handlers, h, zv) { + const struct php_image_handler *handler = Z_PTR_P(zv); + if (handler->identify(stream) == SUCCESS) { + return (int) h; + } + } ZEND_HASH_FOREACH_END(); + return IMAGE_FILETYPE_UNKNOWN; } /* }}} */ @@ -1455,6 +1479,7 @@ static void php_getimagesize_from_stream(php_stream *stream, char *input, zval * { int itype = 0; struct php_gfxinfo *result = NULL; + const char *mime_type = NULL; if (!stream) { RETURN_FALSE; @@ -1479,6 +1504,7 @@ static void php_getimagesize_from_stream(php_stream *stream, char *input, zval * result = php_handle_swf(stream); break; case IMAGE_FILETYPE_SWC: + /* TODO: with the new php_image_register_handler() APIs, this restriction could be solved */ #if defined(HAVE_ZLIB) && !defined(COMPILE_DL_ZLIB) result = php_handle_swc(stream); #else @@ -1526,19 +1552,36 @@ static void php_getimagesize_from_stream(php_stream *stream, char *input, zval * result = php_handle_avif(stream); } break; - default: + default: { + struct php_image_handler* handler = zend_hash_index_find_ptr(&php_image_handlers, (zend_ulong) itype); + if (handler) { + result = handler->get_info(stream); + mime_type = handler->mime_type; + break; + } + ZEND_FALLTHROUGH; + } case IMAGE_FILETYPE_UNKNOWN: break; } if (result) { - char temp[MAX_LENGTH_OF_LONG * 2 + sizeof("width=\"\" height=\"\"")]; array_init(return_value); - add_index_long(return_value, 0, result->width); - add_index_long(return_value, 1, result->height); + if (result->width_str) { + add_index_str(return_value, 0, result->width_str); + add_index_str(return_value, 1, result->height_str); + } else { + add_index_long(return_value, 0, result->width); + add_index_long(return_value, 1, result->height); + } add_index_long(return_value, 2, itype); - snprintf(temp, sizeof(temp), "width=\"%d\" height=\"%d\"", result->width, result->height); - add_index_string(return_value, 3, temp); + if (result->width_str) { + add_index_str(return_value, 3, zend_strpprintf_unchecked(0, "width=\"%S\" height=\"%S\"", result->width_str, result->height_str)); + } else { + char temp[MAX_LENGTH_OF_LONG * 2 + sizeof("width=\"\" height=\"\"")]; + snprintf(temp, sizeof(temp), "width=\"%d\" height=\"%d\"", result->width, result->height); + add_index_string(return_value, 3, temp); + } if (result->bits != 0) { add_assoc_long(return_value, "bits", result->bits); @@ -1546,7 +1589,7 @@ static void php_getimagesize_from_stream(php_stream *stream, char *input, zval * if (result->channels != 0) { add_assoc_long(return_value, "channels", result->channels); } - add_assoc_string(return_value, "mime", (char*)php_image_type_to_mime_type(itype)); + add_assoc_string(return_value, "mime", mime_type ? mime_type : php_image_type_to_mime_type(itype)); efree(result); } else { RETURN_FALSE; @@ -1609,3 +1652,36 @@ PHP_FUNCTION(getimagesizefromstring) php_getimagesize_from_any(INTERNAL_FUNCTION_PARAM_PASSTHRU, FROM_DATA); } /* }}} */ + +PHP_MINIT_FUNCTION(image) +{ + zend_hash_init(&php_image_handlers, 4, NULL, NULL, true); + return SUCCESS; +} + +PHP_MSHUTDOWN_FUNCTION(image) +{ +#ifdef ZTS + if (!tsrm_is_main_thread()) { + return SUCCESS; + } +#endif + zend_hash_destroy(&php_image_handlers); + return SUCCESS; +} + +extern zend_module_entry basic_functions_module; + +int php_image_register_handler(const struct php_image_handler *handler) +{ + zend_hash_index_add_ptr(&php_image_handlers, (zend_ulong) php_image_handler_next_id, (void *) handler); + zend_register_long_constant(handler->const_name, strlen(handler->const_name), php_image_handler_next_id, CONST_PERSISTENT, basic_functions_module.module_number); + Z_LVAL_P(zend_get_constant_str(ZEND_STRL("IMAGETYPE_COUNT")))++; + return php_image_handler_next_id++; +} + +zend_result php_image_unregister_handler(int image_type) +{ + ZEND_ASSERT(image_type >= IMAGE_FILETYPE_FIXED_COUNT); + return zend_hash_index_del(&php_image_handlers, (zend_ulong) image_type); +} diff --git a/ext/standard/php_image.h b/ext/standard/php_image.h index 41f16c29906bb..cec163ac1561f 100644 --- a/ext/standard/php_image.h +++ b/ext/standard/php_image.h @@ -18,6 +18,9 @@ #ifndef PHP_IMAGE_H #define PHP_IMAGE_H +PHP_MINIT_FUNCTION(image); +PHP_MSHUTDOWN_FUNCTION(image); + /* {{{ enum image_filetype This enum is used to have ext/standard/image.c and ext/exif/exif.c use the same constants for file types. @@ -46,13 +49,13 @@ typedef enum IMAGE_FILETYPE_AVIF, IMAGE_FILETYPE_HEIF, /* WHEN EXTENDING: PLEASE ALSO REGISTER IN basic_function.stub.php */ - IMAGE_FILETYPE_COUNT + IMAGE_FILETYPE_FIXED_COUNT } image_filetype; /* }}} */ PHPAPI int php_getimagetype(php_stream *stream, const char *input, char *filetype); -PHPAPI char * php_image_type_to_mime_type(int image_type); +PHPAPI const char * php_image_type_to_mime_type(int image_type); PHPAPI bool php_is_image_avif(php_stream *stream); @@ -66,4 +69,22 @@ struct php_gfxinfo { unsigned int channels; }; +typedef zend_result (*php_image_identify)(php_stream *stream); +typedef struct php_gfxinfo *(*php_image_get_info)(php_stream *stream); + +struct php_image_handler { + const char *mime_type; + const char *extension; + const char *const_name; + php_image_identify identify; + php_image_get_info get_info; +}; + +#define PHP_IMAGE_CONST_NAME(suffix) ("IMAGETYPE_" suffix) + +/* This should only be called on module init */ +PHPAPI int php_image_register_handler(const struct php_image_handler *handler); +/* This should only be called on module shutdown */ +PHPAPI zend_result php_image_unregister_handler(int image_type); + #endif /* PHP_IMAGE_H */ diff --git a/ext/standard/tests/image/image_type_to_mime_type_variation3.phpt b/ext/standard/tests/image/image_type_to_mime_type_variation3.phpt index 6626dc5a07c03..e4178426bc700 100644 --- a/ext/standard/tests/image/image_type_to_mime_type_variation3.phpt +++ b/ext/standard/tests/image/image_type_to_mime_type_variation3.phpt @@ -1,81 +1,87 @@ --TEST-- -image_type_to_mime_type() (passinf equivalent integer values) +image_type_to_mime_type() (passing equivalent integer values) --CREDITS-- Sanjay Mantoor --FILE-- ---EXPECTREGEX-- -\*\*\* Testing image_type_to_mime_type\(\) : usage variations \*\*\* +--EXPECT-- +*** Testing image_type_to_mime_type() : usage variations *** -- Iteration 0 -- -string\(24\) "application\/octet-stream" +string(24) "application/octet-stream" -- Iteration 1 -- -string\(9\) "image\/gif" +string(9) "image/gif" -- Iteration 2 -- -string\(10\) "image\/jpeg" +string(10) "image/jpeg" -- Iteration 3 -- -string\(9\) "image\/png" +string(9) "image/png" -- Iteration 4 -- -string\(29\) "application\/x-shockwave-flash" +string(29) "application/x-shockwave-flash" -- Iteration 5 -- -string\(9\) "image\/psd" +string(9) "image/psd" -- Iteration 6 -- -string\(9\) "image\/bmp" +string(9) "image/bmp" -- Iteration 7 -- -string\(10\) "image\/tiff" +string(10) "image/tiff" -- Iteration 8 -- -string\(10\) "image\/tiff" +string(10) "image/tiff" -- Iteration 9 -- -string\(24\) "application\/octet-stream" +string(24) "application/octet-stream" -- Iteration 10 -- -string\(9\) "image\/jp2" +string(9) "image/jp2" -- Iteration 11 -- -string\(24\) "application\/octet-stream" +string(24) "application/octet-stream" -- Iteration 12 -- -string\(24\) "application\/octet-stream" +string(24) "application/octet-stream" -- Iteration 13 -- -string\(2[49]\) "application\/(x-shockwave-flash|octet-stream)" +string(29) "application/x-shockwave-flash" -- Iteration 14 -- -string\(9\) "image\/iff" +string(9) "image/iff" -- Iteration 15 -- -string\(18\) "image\/vnd.wap.wbmp" +string(18) "image/vnd.wap.wbmp" -- Iteration 16 -- -string\(9\) "image\/xbm" +string(9) "image/xbm" -- Iteration 17 -- -string\(24\) "image\/vnd.microsoft.icon" +string(24) "image/vnd.microsoft.icon" -- Iteration 18 -- -string\(10\) "image\/webp" +string(10) "image/webp" -- Iteration 19 -- -string\(10\) "image\/avif" +string(10) "image/avif" -- Iteration 20 -- string\(10\) "image\/heif" -- Iteration 21 -- string\(24\) "application\/octet-stream" + +-- Iteration 999 -- +string(24) "application/octet-stream" From 3fe026a9aa80b1e817d3f05bc51dc98488e2c7a9 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Fri, 1 Nov 2024 15:00:36 +0100 Subject: [PATCH 3/4] Implement SVG image handler This implements an SVG handler using the libxml reader API. This does not parse the entire document but instead uses a pull parser to locate the root element, check whether it's an svg root, do some extra sanity checks on the attribute, and fill in the php_gfxinfo structure. --- ext/libxml/config.w32 | 2 +- ext/libxml/config0.m4 | 2 +- ext/libxml/image_svg.c | 178 ++++++++++++++++++ ext/libxml/image_svg.h | 25 +++ ext/libxml/libxml.c | 13 +- ext/libxml/tests/image/getimagesize.phpt | 98 ++++++++++ ext/libxml/tests/image/imagetype_svg.phpt | 16 ++ ext/standard/image.c | 26 ++- ext/standard/php_image.h | 4 +- ext/standard/tests/image/bug13213.phpt | 6 +- ext/standard/tests/image/bug70052.phpt | 6 +- ext/standard/tests/image/bug71848.phpt | 6 +- ext/standard/tests/image/bug72278.phpt | 6 +- ext/standard/tests/image/bug75708.phpt | 7 +- ext/standard/tests/image/getimagesize.phpt | 108 +++++++++-- .../tests/image/getimagesize_246x247.phpt | 6 +- .../tests/image/getimagesize_256_ico.phpt | 6 +- .../tests/image/getimagesize_384x385.phpt | 6 +- .../tests/image/getimagesize_basic.phpt | 54 +++++- .../tests/image/getimagesize_swc.phpt | 6 +- .../tests/image/getimagesize_tif_mm.phpt | 6 +- .../tests/image/getimagesize_variation4.phpt | 6 +- .../image/getimagesize_variation_005.phpt | 6 +- .../tests/image/getimagesize_wbmp.phpt | 6 +- .../tests/image/getimagesize_xbm.phpt | 6 +- .../tests/image/getimagesizefromstring1.phpt | 12 +- .../image_type_to_mime_type_variation3.phpt | 7 +- 27 files changed, 565 insertions(+), 65 deletions(-) create mode 100644 ext/libxml/image_svg.c create mode 100644 ext/libxml/image_svg.h create mode 100644 ext/libxml/tests/image/getimagesize.phpt create mode 100644 ext/libxml/tests/image/imagetype_svg.phpt diff --git a/ext/libxml/config.w32 b/ext/libxml/config.w32 index cc5f284dbc1c1..2362ea0c2ba31 100644 --- a/ext/libxml/config.w32 +++ b/ext/libxml/config.w32 @@ -11,7 +11,7 @@ if (PHP_LIBXML == "yes") { if (GREP_HEADER("libxml/xmlversion.h", "#define\\s+LIBXML_VERSION\\s+(\\d+)", PHP_PHP_BUILD + "\\include\\libxml2") && +RegExp.$1 >= 20904) { - EXTENSION("libxml", "libxml.c mime_sniff.c", false /* never shared */, "/DZEND_ENABLE_STATIC_TSRMLS_CACHE=1"); + EXTENSION("libxml", "libxml.c mime_sniff.c image_svg.c", false /* never shared */, "/DZEND_ENABLE_STATIC_TSRMLS_CACHE=1"); AC_DEFINE("HAVE_LIBXML", 1, "Define to 1 if the PHP extension 'libxml' is available."); ADD_FLAG("CFLAGS_LIBXML", "/D LIBXML_STATIC /D LIBXML_STATIC_FOR_DLL /D HAVE_WIN32_THREADS "); if (!PHP_LIBXML_SHARED) { diff --git a/ext/libxml/config0.m4 b/ext/libxml/config0.m4 index 67ffa9a78ce44..5b400751d1b50 100644 --- a/ext/libxml/config0.m4 +++ b/ext/libxml/config0.m4 @@ -12,7 +12,7 @@ if test "$PHP_LIBXML" != "no"; then AC_DEFINE([HAVE_LIBXML], [1], [Define to 1 if the PHP extension 'libxml' is available.]) PHP_NEW_EXTENSION([libxml], - [libxml.c mime_sniff.c], + [libxml.c mime_sniff.c image_svg.c], [$ext_shared],, [-DZEND_ENABLE_STATIC_TSRMLS_CACHE=1]) PHP_INSTALL_HEADERS([ext/libxml], [php_libxml.h]) diff --git a/ext/libxml/image_svg.c b/ext/libxml/image_svg.c new file mode 100644 index 0000000000000..091f7e283168e --- /dev/null +++ b/ext/libxml/image_svg.c @@ -0,0 +1,178 @@ +/* + +----------------------------------------------------------------------+ + | Copyright (c) The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | https://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Niels Dossche | + +----------------------------------------------------------------------+ + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "php.h" +#include "image_svg.h" +#include "php_libxml.h" + +#include "ext/standard/php_image.h" + +#include + +#ifdef HAVE_LIBXML + +static int svg_image_type_id; + +static int php_libxml_svg_stream_read(void *context, char *buffer, int len) +{ + return php_stream_read(context, buffer, len); +} + +/* Sanity check that the input only contains characters valid for a dimension (numbers with units, e.g. 5cm). + * This also protects the user against injecting XSS. + * Only accept [0-9]+[a-zA-Z]* */ +static bool php_libxml_parse_dimension(const xmlChar *input, const xmlChar **unit_position) +{ + if (!(*input >= '0' && *input <= '9')) { + return false; + } + + input++; + + while (*input) { + if (!(*input >= '0' && *input <= '9')) { + if ((*input >= 'a' && *input <= 'z') || (*input >= 'A' && *input <= 'Z')) { + break; + } + return false; + } + input++; + } + + *unit_position = input; + + while (*input) { + if (!((*input >= 'a' && *input <= 'z') || (*input >= 'A' && *input <= 'Z'))) { + return false; + } + input++; + } + + return true; +} + +zend_result php_libxml_svg_image_handle(php_stream *stream, struct php_gfxinfo **result) +{ + if (php_stream_rewind(stream)) { + return FAILURE; + } + + /* Early check before doing more expensive work */ + if (php_stream_getc(stream) != '<') { + return FAILURE; + } + + if (php_stream_rewind(stream)) { + return FAILURE; + } + + PHP_LIBXML_SANITIZE_GLOBALS(reader_for_stream); + xmlTextReaderPtr reader = xmlReaderForIO( + php_libxml_svg_stream_read, + NULL, + stream, + NULL, + NULL, + XML_PARSE_NOWARNING | XML_PARSE_NOERROR | XML_PARSE_NONET + ); + PHP_LIBXML_RESTORE_GLOBALS(reader_for_stream); + + if (!reader) { + return FAILURE; + } + + bool is_svg = false; + while (xmlTextReaderRead(reader) == 1) { + if (xmlTextReaderNodeType(reader) == XML_READER_TYPE_ELEMENT) { + /* Root must be an svg element */ + const xmlChar *name = xmlTextReaderConstLocalName(reader); + if (!name || strcasecmp((const char *) name, "svg") != 0) { + break; + } + + xmlChar *width = xmlTextReaderGetAttribute(reader, BAD_CAST "width"); + xmlChar *height = xmlTextReaderGetAttribute(reader, BAD_CAST "height"); + const xmlChar *width_unit_position, *height_unit_position; + if (!width || !height + || !php_libxml_parse_dimension(width, &width_unit_position) + || !php_libxml_parse_dimension(height, &height_unit_position)) { + xmlFree(width); + xmlFree(height); + break; + } + + is_svg = true; + if (result) { + *result = ecalloc(1, sizeof(**result)); + (*result)->width = ZEND_STRTOL((const char *) width, NULL, 10); + (*result)->height = ZEND_STRTOL((const char *) height, NULL, 10); + if (*width_unit_position) { + (*result)->width_unit = zend_string_init((const char*) width_unit_position, + xmlStrlen(width_unit_position), false); + } + if (*height_unit_position) { + (*result)->height_unit = zend_string_init((const char*) height_unit_position, + xmlStrlen(height_unit_position), false); + } + } + + xmlFree(width); + xmlFree(height); + break; + } + } + + xmlFreeTextReader(reader); + + return is_svg ? SUCCESS : FAILURE; +} + +zend_result php_libxml_svg_image_identify(php_stream *stream) +{ + return php_libxml_svg_image_handle(stream, NULL); +} + +struct php_gfxinfo *php_libxml_svg_image_get_info(php_stream *stream) +{ + struct php_gfxinfo *result = NULL; + zend_result status = php_libxml_svg_image_handle(stream, &result); + ZEND_ASSERT((status == SUCCESS) == (result != NULL)); + return result; +} + +static const struct php_image_handler svg_image_handler = { + "image/svg+xml", + ".svg", + PHP_IMAGE_CONST_NAME("SVG"), + php_libxml_svg_image_identify, + php_libxml_svg_image_get_info, +}; + +void php_libxml_register_image_svg_handler(void) +{ + svg_image_type_id = php_image_register_handler(&svg_image_handler); +} + +zend_result php_libxml_unregister_image_svg_handler(void) +{ + return php_image_unregister_handler(svg_image_type_id); +} + +#endif diff --git a/ext/libxml/image_svg.h b/ext/libxml/image_svg.h new file mode 100644 index 0000000000000..d023334af36b6 --- /dev/null +++ b/ext/libxml/image_svg.h @@ -0,0 +1,25 @@ +/* + +----------------------------------------------------------------------+ + | Copyright (c) The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | https://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Niels Dossche | + +----------------------------------------------------------------------+ + */ + +#ifndef LIBXML_IMAGE_SVG +#define LIBXML_IMAGE_SVG + +#include "zend.h" + +void php_libxml_register_image_svg_handler(void); +zend_result php_libxml_unregister_image_svg_handler(void); + +#endif diff --git a/ext/libxml/libxml.c b/ext/libxml/libxml.c index 03a89c7aad51d..de42b176b3fdf 100644 --- a/ext/libxml/libxml.c +++ b/ext/libxml/libxml.c @@ -43,6 +43,7 @@ #endif #include "php_libxml.h" +#include "image_svg.h" #define PHP_LIBXML_LOADED_VERSION ((char *)xmlParserVersion) @@ -84,8 +85,14 @@ static zend_long php_libxml_default_dump_doc_to_file(const char *filename, xmlDo /* }}} */ +static const zend_module_dep libxml_deps[] = { + ZEND_MOD_REQUIRED("standard") + ZEND_MOD_END +}; + zend_module_entry libxml_module_entry = { - STANDARD_MODULE_HEADER, + STANDARD_MODULE_HEADER_EX, NULL, + libxml_deps, "libxml", /* extension name */ ext_functions, /* extension function list */ PHP_MINIT(libxml), /* extension-wide startup function */ @@ -969,6 +976,8 @@ static PHP_MINIT_FUNCTION(libxml) xmlOutputBufferCreateFilenameDefault(php_libxml_output_buffer_create_filename); } + php_libxml_register_image_svg_handler(); + return SUCCESS; } @@ -1010,7 +1019,7 @@ static PHP_MSHUTDOWN_FUNCTION(libxml) } php_libxml_shutdown(); - return SUCCESS; + return php_libxml_unregister_image_svg_handler(); } static zend_result php_libxml_post_deactivate(void) diff --git a/ext/libxml/tests/image/getimagesize.phpt b/ext/libxml/tests/image/getimagesize.phpt new file mode 100644 index 0000000000000..22c099395c3dd --- /dev/null +++ b/ext/libxml/tests/image/getimagesize.phpt @@ -0,0 +1,98 @@ +--TEST-- +getimagesize() with svg input +--EXTENSIONS-- +libxml +--FILE-- +", + "svg width=\"1\" height=\"1\"", + << + + +XML, + "", + "", + "", + "", + "", + "", + "", + "", +]; + +foreach ($inputs as $input) { + var_dump(getimagesizefromstring($input)); +} + +?> +--EXPECTF-- +bool(false) +bool(false) +array(6) { + [0]=> + int(4) + [1]=> + int(8) + [2]=> + int(%d) + ["mime"]=> + string(13) "image/svg+xml" + ["width_unit"]=> + string(2) "cm" + ["height_unit"]=> + string(2) "cm" +} +array(7) { + [0]=> + int(1) + [1]=> + int(1) + [2]=> + int(%d) + [3]=> + string(20) "width="1" height="1"" + ["mime"]=> + string(13) "image/svg+xml" + ["width_unit"]=> + string(2) "px" + ["height_unit"]=> + string(2) "px" +} +array(7) { + [0]=> + int(1) + [1]=> + int(1) + [2]=> + int(%d) + [3]=> + string(20) "width="1" height="1"" + ["mime"]=> + string(13) "image/svg+xml" + ["width_unit"]=> + string(2) "px" + ["height_unit"]=> + string(2) "px" +} +array(6) { + [0]=> + int(1) + [1]=> + int(1) + [2]=> + int(%d) + ["mime"]=> + string(13) "image/svg+xml" + ["width_unit"]=> + string(2) "px" + ["height_unit"]=> + string(2) "mm" +} +bool(false) +bool(false) +bool(false) +bool(false) +bool(false) diff --git a/ext/libxml/tests/image/imagetype_svg.phpt b/ext/libxml/tests/image/imagetype_svg.phpt new file mode 100644 index 0000000000000..4115e6a1c8955 --- /dev/null +++ b/ext/libxml/tests/image/imagetype_svg.phpt @@ -0,0 +1,16 @@ +--TEST-- +imagetype API with svg extension +--EXTENSIONS-- +libxml +--FILE-- + IMAGETYPE_SVG); +var_dump(image_type_to_extension(IMAGETYPE_SVG)); +var_dump(image_type_to_mime_type(IMAGETYPE_SVG)); + +?> +--EXPECT-- +bool(true) +string(4) ".svg" +string(13) "image/svg+xml" diff --git a/ext/standard/image.c b/ext/standard/image.c index 5678ae52c985f..8556320e671a3 100644 --- a/ext/standard/image.c +++ b/ext/standard/image.c @@ -1567,17 +1567,11 @@ static void php_getimagesize_from_stream(php_stream *stream, char *input, zval * if (result) { array_init(return_value); - if (result->width_str) { - add_index_str(return_value, 0, result->width_str); - add_index_str(return_value, 1, result->height_str); - } else { - add_index_long(return_value, 0, result->width); - add_index_long(return_value, 1, result->height); - } + add_index_long(return_value, 0, result->width); + add_index_long(return_value, 1, result->height); add_index_long(return_value, 2, itype); - if (result->width_str) { - add_index_str(return_value, 3, zend_strpprintf_unchecked(0, "width=\"%S\" height=\"%S\"", result->width_str, result->height_str)); - } else { + if ((!result->width_unit || zend_string_equals_literal(result->width_unit, "px")) + && (!result->height_unit || zend_string_equals_literal(result->height_unit, "px"))) { char temp[MAX_LENGTH_OF_LONG * 2 + sizeof("width=\"\" height=\"\"")]; snprintf(temp, sizeof(temp), "width=\"%d\" height=\"%d\"", result->width, result->height); add_index_string(return_value, 3, temp); @@ -1590,6 +1584,18 @@ static void php_getimagesize_from_stream(php_stream *stream, char *input, zval * add_assoc_long(return_value, "channels", result->channels); } add_assoc_string(return_value, "mime", mime_type ? mime_type : php_image_type_to_mime_type(itype)); + + if (result->width_unit) { + add_assoc_str(return_value, "width_unit", result->width_unit); + } else { + add_assoc_string(return_value, "width_unit", "px"); + } + if (result->height_unit) { + add_assoc_str(return_value, "height_unit", result->height_unit); + } else { + add_assoc_string(return_value, "height_unit", "px"); + } + efree(result); } else { RETURN_FALSE; diff --git a/ext/standard/php_image.h b/ext/standard/php_image.h index cec163ac1561f..6a4e0987d13db 100644 --- a/ext/standard/php_image.h +++ b/ext/standard/php_image.h @@ -63,8 +63,8 @@ PHPAPI bool php_is_image_avif(php_stream *stream); struct php_gfxinfo { unsigned int width; unsigned int height; - zend_string *width_str; - zend_string *height_str; + zend_string *width_unit; + zend_string *height_unit; unsigned int bits; unsigned int channels; }; diff --git a/ext/standard/tests/image/bug13213.phpt b/ext/standard/tests/image/bug13213.phpt index 61fe245efed29..dd5821a830358 100644 --- a/ext/standard/tests/image/bug13213.phpt +++ b/ext/standard/tests/image/bug13213.phpt @@ -6,7 +6,7 @@ var_dump(GetImageSize(__DIR__.'/bug13213.jpg')); ?> --EXPECTF-- Warning: getimagesize(): Corrupt JPEG data: 2 extraneous bytes before marker in %s%ebug13213.php on line %d -array(7) { +array(9) { [0]=> int(1) [1]=> @@ -21,4 +21,8 @@ array(7) { int(3) ["mime"]=> string(10) "image/jpeg" + ["width_unit"]=> + string(2) "px" + ["height_unit"]=> + string(2) "px" } diff --git a/ext/standard/tests/image/bug70052.phpt b/ext/standard/tests/image/bug70052.phpt index 76ebda92b220f..252f8921e2925 100644 --- a/ext/standard/tests/image/bug70052.phpt +++ b/ext/standard/tests/image/bug70052.phpt @@ -7,7 +7,7 @@ var_dump(getimagesize(__DIR__ . '/bug70052_2.wbmp')); ?> --EXPECT-- bool(false) -array(5) { +array(7) { [0]=> int(3) [1]=> @@ -18,4 +18,8 @@ array(5) { string(20) "width="3" height="3"" ["mime"]=> string(18) "image/vnd.wap.wbmp" + ["width_unit"]=> + string(2) "px" + ["height_unit"]=> + string(2) "px" } diff --git a/ext/standard/tests/image/bug71848.phpt b/ext/standard/tests/image/bug71848.phpt index 25c05689e6e9c..1c15c87011cf6 100644 --- a/ext/standard/tests/image/bug71848.phpt +++ b/ext/standard/tests/image/bug71848.phpt @@ -6,7 +6,7 @@ var_dump(getimagesize(__DIR__ . '/bug71848.jpg', $info)); var_dump(array_keys($info)); ?> --EXPECT-- -array(7) { +array(9) { [0]=> int(8) [1]=> @@ -21,6 +21,10 @@ array(7) { int(3) ["mime"]=> string(10) "image/jpeg" + ["width_unit"]=> + string(2) "px" + ["height_unit"]=> + string(2) "px" } array(2) { [0]=> diff --git a/ext/standard/tests/image/bug72278.phpt b/ext/standard/tests/image/bug72278.phpt index 074338c18aebc..21079246a5d75 100644 --- a/ext/standard/tests/image/bug72278.phpt +++ b/ext/standard/tests/image/bug72278.phpt @@ -8,7 +8,7 @@ var_dump(getimagesize(FILENAME)); ?> --EXPECTF-- Warning: getimagesize(): Corrupt JPEG data: 3 extraneous bytes before marker in %s%ebug72278.php on line %d -array(7) { +array(9) { [0]=> int(300) [1]=> @@ -23,4 +23,8 @@ array(7) { int(3) ["mime"]=> string(10) "image/jpeg" + ["width_unit"]=> + string(2) "px" + ["height_unit"]=> + string(2) "px" } diff --git a/ext/standard/tests/image/bug75708.phpt b/ext/standard/tests/image/bug75708.phpt index 3c81c67cf5ddb..b1a5ee6116c7a 100644 --- a/ext/standard/tests/image/bug75708.phpt +++ b/ext/standard/tests/image/bug75708.phpt @@ -41,7 +41,7 @@ var_dump(getimagesize('fs://bug75708.jpg', $info)); ?> --EXPECT-- -array(7) { +array(9) { [0]=> int(10) [1]=> @@ -56,5 +56,8 @@ array(7) { int(3) ["mime"]=> string(10) "image/jpeg" + ["width_unit"]=> + string(2) "px" + ["height_unit"]=> + string(2) "px" } - diff --git a/ext/standard/tests/image/getimagesize.phpt b/ext/standard/tests/image/getimagesize.phpt index 085bf96287b91..81c4f8dc6b5ca 100644 --- a/ext/standard/tests/image/getimagesize.phpt +++ b/ext/standard/tests/image/getimagesize.phpt @@ -25,7 +25,7 @@ GetImageSize() --EXPECT-- array(18) { ["test-1pix.bmp"]=> - array(6) { + array(8) { [0]=> int(1) [1]=> @@ -38,9 +38,13 @@ array(18) { int(24) ["mime"]=> string(9) "image/bmp" + ["width_unit"]=> + string(2) "px" + ["height_unit"]=> + string(2) "px" } ["test12pix.webp"]=> - array(6) { + array(8) { [0]=> int(4) [1]=> @@ -53,9 +57,13 @@ array(18) { int(8) ["mime"]=> string(10) "image/webp" + ["width_unit"]=> + string(2) "px" + ["height_unit"]=> + string(2) "px" } ["test1bpix.bmp"]=> - array(6) { + array(8) { [0]=> int(1) [1]=> @@ -68,9 +76,13 @@ array(18) { int(32) ["mime"]=> string(9) "image/bmp" + ["width_unit"]=> + string(2) "px" + ["height_unit"]=> + string(2) "px" } ["test1pix.avif"]=> - array(7) { + array(9) { [0]=> int(102) [1]=> @@ -85,9 +97,13 @@ array(18) { int(4) ["mime"]=> string(10) "image/avif" + ["width_unit"]=> + string(2) "px" + ["height_unit"]=> + string(2) "px" } ["test1pix.bmp"]=> - array(6) { + array(8) { [0]=> int(1) [1]=> @@ -100,9 +116,13 @@ array(18) { int(24) ["mime"]=> string(9) "image/bmp" + ["width_unit"]=> + string(2) "px" + ["height_unit"]=> + string(2) "px" } ["test1pix.jp2"]=> - array(7) { + array(9) { [0]=> int(1) [1]=> @@ -117,9 +137,13 @@ array(18) { int(3) ["mime"]=> string(9) "image/jp2" + ["width_unit"]=> + string(2) "px" + ["height_unit"]=> + string(2) "px" } ["test1pix.jpc"]=> - array(7) { + array(9) { [0]=> int(1) [1]=> @@ -134,9 +158,13 @@ array(18) { int(3) ["mime"]=> string(24) "application/octet-stream" + ["width_unit"]=> + string(2) "px" + ["height_unit"]=> + string(2) "px" } ["test1pix.jpg"]=> - array(7) { + array(9) { [0]=> int(1) [1]=> @@ -151,9 +179,13 @@ array(18) { int(3) ["mime"]=> string(10) "image/jpeg" + ["width_unit"]=> + string(2) "px" + ["height_unit"]=> + string(2) "px" } ["test2pix.gif"]=> - array(7) { + array(9) { [0]=> int(2) [1]=> @@ -168,9 +200,13 @@ array(18) { int(3) ["mime"]=> string(9) "image/gif" + ["width_unit"]=> + string(2) "px" + ["height_unit"]=> + string(2) "px" } ["test3llpix.webp"]=> - array(6) { + array(8) { [0]=> int(1) [1]=> @@ -183,9 +219,13 @@ array(18) { int(8) ["mime"]=> string(10) "image/webp" + ["width_unit"]=> + string(2) "px" + ["height_unit"]=> + string(2) "px" } ["test3pix.webp"]=> - array(6) { + array(8) { [0]=> int(1) [1]=> @@ -198,9 +238,13 @@ array(18) { int(8) ["mime"]=> string(10) "image/webp" + ["width_unit"]=> + string(2) "px" + ["height_unit"]=> + string(2) "px" } ["test4pix.gif"]=> - array(7) { + array(9) { [0]=> int(4) [1]=> @@ -215,9 +259,13 @@ array(18) { int(3) ["mime"]=> string(9) "image/gif" + ["width_unit"]=> + string(2) "px" + ["height_unit"]=> + string(2) "px" } ["test4pix.heic"]=> - array(7) { + array(9) { [0]=> int(54) [1]=> @@ -232,9 +280,13 @@ array(18) { int(3) ["mime"]=> string(10) "image/heif" + ["width_unit"]=> + string(2) "px" + ["height_unit"]=> + string(2) "px" } ["test4pix.iff"]=> - array(6) { + array(8) { [0]=> int(4) [1]=> @@ -247,9 +299,13 @@ array(18) { int(4) ["mime"]=> string(9) "image/iff" + ["width_unit"]=> + string(2) "px" + ["height_unit"]=> + string(2) "px" } ["test4pix.png"]=> - array(6) { + array(8) { [0]=> int(4) [1]=> @@ -262,9 +318,13 @@ array(18) { int(4) ["mime"]=> string(9) "image/png" + ["width_unit"]=> + string(2) "px" + ["height_unit"]=> + string(2) "px" } ["test4pix.psd"]=> - array(5) { + array(7) { [0]=> int(4) [1]=> @@ -275,9 +335,13 @@ array(18) { string(20) "width="4" height="1"" ["mime"]=> string(9) "image/psd" + ["width_unit"]=> + string(2) "px" + ["height_unit"]=> + string(2) "px" } ["test4pix.swf"]=> - array(5) { + array(7) { [0]=> int(550) [1]=> @@ -288,9 +352,13 @@ array(18) { string(24) "width="550" height="400"" ["mime"]=> string(29) "application/x-shockwave-flash" + ["width_unit"]=> + string(2) "px" + ["height_unit"]=> + string(2) "px" } ["test4pix.tiff"]=> - array(5) { + array(7) { [0]=> int(4) [1]=> @@ -301,5 +369,9 @@ array(18) { string(20) "width="4" height="1"" ["mime"]=> string(10) "image/tiff" + ["width_unit"]=> + string(2) "px" + ["height_unit"]=> + string(2) "px" } } diff --git a/ext/standard/tests/image/getimagesize_246x247.phpt b/ext/standard/tests/image/getimagesize_246x247.phpt index c716ac3aebc08..abf5bec0412a8 100644 --- a/ext/standard/tests/image/getimagesize_246x247.phpt +++ b/ext/standard/tests/image/getimagesize_246x247.phpt @@ -25,7 +25,7 @@ GetImageSize() with 246x247 pixels --EXPECT-- array(1) { ["246x247.png"]=> - array(6) { + array(8) { [0]=> int(246) [1]=> @@ -38,5 +38,9 @@ array(1) { int(4) ["mime"]=> string(9) "image/png" + ["width_unit"]=> + string(2) "px" + ["height_unit"]=> + string(2) "px" } } diff --git a/ext/standard/tests/image/getimagesize_256_ico.phpt b/ext/standard/tests/image/getimagesize_256_ico.phpt index 770985c6aec54..7f1fff07a3a25 100644 --- a/ext/standard/tests/image/getimagesize_256_ico.phpt +++ b/ext/standard/tests/image/getimagesize_256_ico.phpt @@ -9,7 +9,7 @@ var_dump(getimagesize(__DIR__ . "/32x256.ico")); ===DONE=== --EXPECT-- *** Testing getimagesize() : 256px ico *** -array(6) { +array(8) { [0]=> int(32) [1]=> @@ -22,5 +22,9 @@ array(6) { int(8) ["mime"]=> string(24) "image/vnd.microsoft.icon" + ["width_unit"]=> + string(2) "px" + ["height_unit"]=> + string(2) "px" } ===DONE=== diff --git a/ext/standard/tests/image/getimagesize_384x385.phpt b/ext/standard/tests/image/getimagesize_384x385.phpt index 57dc8a7192159..69705080cad02 100644 --- a/ext/standard/tests/image/getimagesize_384x385.phpt +++ b/ext/standard/tests/image/getimagesize_384x385.phpt @@ -25,7 +25,7 @@ GetImageSize() with 384x385 pixels --EXPECT-- array(1) { ["384x385.png"]=> - array(6) { + array(8) { [0]=> int(384) [1]=> @@ -38,5 +38,9 @@ array(1) { int(1) ["mime"]=> string(9) "image/png" + ["width_unit"]=> + string(2) "px" + ["height_unit"]=> + string(2) "px" } } diff --git a/ext/standard/tests/image/getimagesize_basic.phpt b/ext/standard/tests/image/getimagesize_basic.phpt index f1a6d108d31bd..3dd1823437c20 100644 --- a/ext/standard/tests/image/getimagesize_basic.phpt +++ b/ext/standard/tests/image/getimagesize_basic.phpt @@ -44,7 +44,7 @@ foreach($imagetype_filenames as $key => $filename) { *** Testing getimagesize() : basic functionality *** -- GIF image file (200x100.gif) -- -array(7) { +array(9) { [0]=> int(200) [1]=> @@ -59,12 +59,16 @@ array(7) { int(3) ["mime"]=> string(9) "image/gif" + ["width_unit"]=> + string(2) "px" + ["height_unit"]=> + string(2) "px" } array(0) { } -- JPEG image file (200x100.jpg) -- -array(7) { +array(9) { [0]=> int(200) [1]=> @@ -79,6 +83,10 @@ array(7) { int(3) ["mime"]=> string(10) "image/jpeg" + ["width_unit"]=> + string(2) "px" + ["height_unit"]=> + string(2) "px" } array(1) { ["APP0"]=> @@ -86,7 +94,7 @@ array(1) { } -- PNG image file (200x100.png) -- -array(6) { +array(8) { [0]=> int(200) [1]=> @@ -99,12 +107,16 @@ array(6) { int(8) ["mime"]=> string(9) "image/png" + ["width_unit"]=> + string(2) "px" + ["height_unit"]=> + string(2) "px" } array(0) { } -- SWF image file (200x100.swf) -- -array(5) { +array(7) { [0]=> int(200) [1]=> @@ -115,12 +127,16 @@ array(5) { string(24) "width="200" height="100"" ["mime"]=> string(29) "application/x-shockwave-flash" + ["width_unit"]=> + string(2) "px" + ["height_unit"]=> + string(2) "px" } array(0) { } -- BMP image file (200x100.bmp) -- -array(6) { +array(8) { [0]=> int(200) [1]=> @@ -133,12 +149,16 @@ array(6) { int(24) ["mime"]=> string(9) "image/bmp" + ["width_unit"]=> + string(2) "px" + ["height_unit"]=> + string(2) "px" } array(0) { } -- TIFF intel byte order image file (200x100.tiff) -- -array(5) { +array(7) { [0]=> int(200) [1]=> @@ -149,12 +169,16 @@ array(5) { string(24) "width="200" height="100"" ["mime"]=> string(10) "image/tiff" + ["width_unit"]=> + string(2) "px" + ["height_unit"]=> + string(2) "px" } array(0) { } -- JPC image file (test1pix.jpc) -- -array(7) { +array(9) { [0]=> int(1) [1]=> @@ -169,12 +193,16 @@ array(7) { int(3) ["mime"]=> string(24) "application/octet-stream" + ["width_unit"]=> + string(2) "px" + ["height_unit"]=> + string(2) "px" } array(0) { } -- JP2 image file (test1pix.jp2) -- -array(7) { +array(9) { [0]=> int(1) [1]=> @@ -189,12 +217,16 @@ array(7) { int(3) ["mime"]=> string(9) "image/jp2" + ["width_unit"]=> + string(2) "px" + ["height_unit"]=> + string(2) "px" } array(0) { } -- IFF image file (test4pix.iff) -- -array(6) { +array(8) { [0]=> int(4) [1]=> @@ -207,6 +239,10 @@ array(6) { int(4) ["mime"]=> string(9) "image/iff" + ["width_unit"]=> + string(2) "px" + ["height_unit"]=> + string(2) "px" } array(0) { } diff --git a/ext/standard/tests/image/getimagesize_swc.phpt b/ext/standard/tests/image/getimagesize_swc.phpt index 7dff107d477ee..f5031e7a223c7 100644 --- a/ext/standard/tests/image/getimagesize_swc.phpt +++ b/ext/standard/tests/image/getimagesize_swc.phpt @@ -13,7 +13,7 @@ if (!defined("IMAGETYPE_SWC")) { var_dump(getimagesize(__DIR__ . "/test13pix.swf")); ?> --EXPECT-- -array(5) { +array(7) { [0]=> int(550) [1]=> @@ -24,4 +24,8 @@ array(5) { string(24) "width="550" height="400"" ["mime"]=> string(29) "application/x-shockwave-flash" + ["width_unit"]=> + string(2) "px" + ["height_unit"]=> + string(2) "px" } diff --git a/ext/standard/tests/image/getimagesize_tif_mm.phpt b/ext/standard/tests/image/getimagesize_tif_mm.phpt index cd6f32f4d3785..58047f6134dc4 100644 --- a/ext/standard/tests/image/getimagesize_tif_mm.phpt +++ b/ext/standard/tests/image/getimagesize_tif_mm.phpt @@ -9,7 +9,7 @@ var_dump($arr); ?> --EXPECT-- *** Testing getimagesize() : tiff_mm format *** -array(5) { +array(7) { [0]=> int(2) [1]=> @@ -20,6 +20,10 @@ array(5) { string(20) "width="2" height="2"" ["mime"]=> string(10) "image/tiff" + ["width_unit"]=> + string(2) "px" + ["height_unit"]=> + string(2) "px" } array(0) { } diff --git a/ext/standard/tests/image/getimagesize_variation4.phpt b/ext/standard/tests/image/getimagesize_variation4.phpt index 658ce84d518cb..49b924ffe77b9 100644 --- a/ext/standard/tests/image/getimagesize_variation4.phpt +++ b/ext/standard/tests/image/getimagesize_variation4.phpt @@ -17,7 +17,7 @@ var_dump( $info ); ?> --EXPECT-- *** Testing getimagesize() : variation *** -array(5) { +array(7) { [0]=> int(550) [1]=> @@ -28,6 +28,10 @@ array(5) { string(24) "width="550" height="400"" ["mime"]=> string(29) "application/x-shockwave-flash" + ["width_unit"]=> + string(2) "px" + ["height_unit"]=> + string(2) "px" } array(0) { } diff --git a/ext/standard/tests/image/getimagesize_variation_005.phpt b/ext/standard/tests/image/getimagesize_variation_005.phpt index 8e471e50a23a7..c6d083b23b5e4 100644 --- a/ext/standard/tests/image/getimagesize_variation_005.phpt +++ b/ext/standard/tests/image/getimagesize_variation_005.phpt @@ -17,7 +17,7 @@ var_dump( $info ); ?> --EXPECT-- *** Testing getimagesize() : basic functionality *** -array(5) { +array(7) { [0]=> int(550) [1]=> @@ -28,6 +28,10 @@ array(5) { string(24) "width="550" height="400"" ["mime"]=> string(29) "application/x-shockwave-flash" + ["width_unit"]=> + string(2) "px" + ["height_unit"]=> + string(2) "px" } array(0) { } diff --git a/ext/standard/tests/image/getimagesize_wbmp.phpt b/ext/standard/tests/image/getimagesize_wbmp.phpt index 0b0ebe52347d9..97151d8412460 100644 --- a/ext/standard/tests/image/getimagesize_wbmp.phpt +++ b/ext/standard/tests/image/getimagesize_wbmp.phpt @@ -9,7 +9,7 @@ var_dump($arr); ?> --EXPECT-- *** Testing getimagesize() : wbmp format *** -array(5) { +array(7) { [0]=> int(75) [1]=> @@ -20,6 +20,10 @@ array(5) { string(22) "width="75" height="50"" ["mime"]=> string(18) "image/vnd.wap.wbmp" + ["width_unit"]=> + string(2) "px" + ["height_unit"]=> + string(2) "px" } array(0) { } diff --git a/ext/standard/tests/image/getimagesize_xbm.phpt b/ext/standard/tests/image/getimagesize_xbm.phpt index 5ecd6ad206348..4f7f7965dd657 100644 --- a/ext/standard/tests/image/getimagesize_xbm.phpt +++ b/ext/standard/tests/image/getimagesize_xbm.phpt @@ -9,7 +9,7 @@ var_dump($arr); ?> --EXPECT-- *** Testing getimagesize() : xbm format *** -array(5) { +array(7) { [0]=> int(75) [1]=> @@ -20,6 +20,10 @@ array(5) { string(22) "width="75" height="50"" ["mime"]=> string(9) "image/xbm" + ["width_unit"]=> + string(2) "px" + ["height_unit"]=> + string(2) "px" } array(0) { } diff --git a/ext/standard/tests/image/getimagesizefromstring1.phpt b/ext/standard/tests/image/getimagesizefromstring1.phpt index 6202b38e89654..0037c292f7009 100644 --- a/ext/standard/tests/image/getimagesizefromstring1.phpt +++ b/ext/standard/tests/image/getimagesizefromstring1.phpt @@ -14,7 +14,7 @@ var_dump($i1); var_dump($i2); ?> --EXPECT-- -array(7) { +array(9) { [0]=> int(120) [1]=> @@ -29,8 +29,12 @@ array(7) { int(3) ["mime"]=> string(9) "image/gif" + ["width_unit"]=> + string(2) "px" + ["height_unit"]=> + string(2) "px" } -array(7) { +array(9) { [0]=> int(120) [1]=> @@ -45,4 +49,8 @@ array(7) { int(3) ["mime"]=> string(9) "image/gif" + ["width_unit"]=> + string(2) "px" + ["height_unit"]=> + string(2) "px" } diff --git a/ext/standard/tests/image/image_type_to_mime_type_variation3.phpt b/ext/standard/tests/image/image_type_to_mime_type_variation3.phpt index e4178426bc700..8bd62188d216c 100644 --- a/ext/standard/tests/image/image_type_to_mime_type_variation3.phpt +++ b/ext/standard/tests/image/image_type_to_mime_type_variation3.phpt @@ -6,7 +6,7 @@ Sanjay Mantoor Date: Fri, 1 Nov 2024 15:58:35 +0100 Subject: [PATCH 4/4] UPGRADING, UPGRADING.INTERNALS, and NEWS for SVG and extensible image API --- NEWS | 2 ++ UPGRADING | 12 ++++++++++++ UPGRADING.INTERNALS | 4 ++++ 3 files changed, 18 insertions(+) diff --git a/NEWS b/NEWS index 7ed6c5fb825a3..8d5a63de6976a 100644 --- a/NEWS +++ b/NEWS @@ -16,6 +16,8 @@ PHP NEWS - Standard: . Add HEIF/HEIC support to getimagesize. (Benstone Zhang) + . Implement #71517 (Implement SVG support for getimagesize() and friends). + (nielsdos) - URI: . Empty host handling is fixed. (Máté Kocsis) diff --git a/UPGRADING b/UPGRADING index 86a7482802e85..c7b6dc88822b5 100644 --- a/UPGRADING +++ b/UPGRADING @@ -246,6 +246,15 @@ PHP 8.5 UPGRADE NOTES ignored. This change affects only the sendmail transport. . getimagesize() now supports HEIF/HEIC images. +- Standard: + . getimagesize() now supports SVG images when ext-libxml is also loaded. + Similarly, image_type_to_extension() and image_type_to_extension() + now also handle IMAGETYPE_SVG. + . The array returned by getimagesize() now has two additional entries: + "width_unit" and "height_unit" to indicate in which units the dimensions + are expressed. These units are px by default. They are not necessarily + the same (just to give one example: one may be cm and the other may be px). + - XSL: . The $namespace argument of XSLTProcessor::getParameter(), XSLTProcessor::setParameter() and XSLTProcessor::removeParameter() @@ -566,6 +575,9 @@ PHP 8.5 UPGRADE NOTES . T_VOID_CAST. . T_PIPE. +- Standard: + . IMAGETYPE_SVG when libxml is loaded. + ======================================== 11. Changes to INI File Handling ======================================== diff --git a/UPGRADING.INTERNALS b/UPGRADING.INTERNALS index 0e0a0e94c9477..7733ce6cf7be7 100644 --- a/UPGRADING.INTERNALS +++ b/UPGRADING.INTERNALS @@ -134,6 +134,10 @@ PHP 8.5 INTERNALS UPGRADE NOTES . The php_std_date() function has been removed. Use php_format_date() with the "D, d M Y H:i:s \\G\\M\\T" format instead. . Added php_url_encode_to_smart_str() to encode a URL to a smart_str buffer. + . The functionality of getimagesize(), image_type_to_mime_type(), + and image_type_to_extension() is now extensible using the internal APIs + php_image_register_handler() and php_image_unregister_handler() in + php_image.h. ======================== 4. OpCode changes