@@ -52,6 +52,9 @@ PHPAPI const char php_sig_ico[4] = {(char)0x00, (char)0x00, (char)0x01, (char)0x
5252PHPAPI const char php_sig_riff [4 ] = {'R' , 'I' , 'F' , 'F' };
5353PHPAPI const char php_sig_webp [4 ] = {'W' , 'E' , 'B' , 'P' };
5454
55+ static zend_array php_image_handlers ;
56+ static int php_image_handler_next_id = IMAGE_FILETYPE_FIXED_COUNT ;
57+
5558/* REMEMBER TO ADD MIME-TYPE TO FUNCTION php_image_type_to_mime_type */
5659/* PCX must check first 64bytes and byte 0=0x0a and byte2 < 0x06 */
5760
@@ -1210,7 +1213,7 @@ bool php_is_image_avif(php_stream* stream) {
12101213
12111214/* {{{ php_image_type_to_mime_type
12121215 * Convert internal image_type to mime type */
1213- PHPAPI char * php_image_type_to_mime_type (int image_type )
1216+ PHPAPI const char * php_image_type_to_mime_type (int image_type )
12141217{
12151218 switch ( image_type ) {
12161219 case IMAGE_FILETYPE_GIF :
@@ -1245,7 +1248,13 @@ PHPAPI char * php_image_type_to_mime_type(int image_type)
12451248 return "image/webp" ;
12461249 case IMAGE_FILETYPE_AVIF :
12471250 return "image/avif" ;
1248- default :
1251+ default : {
1252+ const struct php_image_handler * handler = zend_hash_index_find_ptr (& php_image_handlers , (zend_ulong ) image_type );
1253+ if (handler ) {
1254+ return handler -> mime_type ;
1255+ }
1256+ ZEND_FALLTHROUGH ;
1257+ }
12491258 case IMAGE_FILETYPE_UNKNOWN :
12501259 return "application/octet-stream" ; /* suppose binary format */
12511260 }
@@ -1261,7 +1270,7 @@ PHP_FUNCTION(image_type_to_mime_type)
12611270 Z_PARAM_LONG (p_image_type )
12621271 ZEND_PARSE_PARAMETERS_END ();
12631272
1264- ZVAL_STRING (return_value , ( char * ) php_image_type_to_mime_type (p_image_type ));
1273+ ZVAL_STRING (return_value , php_image_type_to_mime_type (p_image_type ));
12651274}
12661275/* }}} */
12671276
@@ -1330,6 +1339,13 @@ PHP_FUNCTION(image_type_to_extension)
13301339 case IMAGE_FILETYPE_AVIF :
13311340 imgext = ".avif" ;
13321341 break ;
1342+ default : {
1343+ const struct php_image_handler * handler = zend_hash_index_find_ptr (& php_image_handlers , (zend_ulong ) image_type );
1344+ if (handler ) {
1345+ imgext = handler -> extension ;
1346+ }
1347+ break ;
1348+ }
13331349 }
13341350
13351351 if (imgext ) {
@@ -1432,6 +1448,15 @@ PHPAPI int php_getimagetype(php_stream *stream, const char *input, char *filetyp
14321448 return IMAGE_FILETYPE_XBM ;
14331449 }
14341450
1451+ zend_ulong h ;
1452+ zval * zv ;
1453+ ZEND_HASH_FOREACH_NUM_KEY_VAL (& php_image_handlers , h , zv ) {
1454+ const struct php_image_handler * handler = Z_PTR_P (zv );
1455+ if (handler -> identify (stream ) == SUCCESS ) {
1456+ return (int ) h ;
1457+ }
1458+ } ZEND_HASH_FOREACH_END ();
1459+
14351460 return IMAGE_FILETYPE_UNKNOWN ;
14361461}
14371462/* }}} */
@@ -1440,6 +1465,7 @@ static void php_getimagesize_from_stream(php_stream *stream, char *input, zval *
14401465{
14411466 int itype = 0 ;
14421467 struct php_gfxinfo * result = NULL ;
1468+ const char * mime_type = NULL ;
14431469
14441470 if (!stream ) {
14451471 RETURN_FALSE ;
@@ -1464,6 +1490,7 @@ static void php_getimagesize_from_stream(php_stream *stream, char *input, zval *
14641490 result = php_handle_swf (stream );
14651491 break ;
14661492 case IMAGE_FILETYPE_SWC :
1493+ /* TODO: with the new php_image_register_handler() APIs, this restriction could be solved */
14671494#if defined(HAVE_ZLIB ) && !defined(COMPILE_DL_ZLIB )
14681495 result = php_handle_swc (stream );
14691496#else
@@ -1506,27 +1533,44 @@ static void php_getimagesize_from_stream(php_stream *stream, char *input, zval *
15061533 case IMAGE_FILETYPE_AVIF :
15071534 result = php_handle_avif (stream );
15081535 break ;
1509- default :
1536+ default : {
1537+ struct php_image_handler * handler = zend_hash_index_find_ptr (& php_image_handlers , (zend_ulong ) itype );
1538+ if (handler ) {
1539+ result = handler -> get_info (stream );
1540+ mime_type = handler -> mime_type ;
1541+ break ;
1542+ }
1543+ ZEND_FALLTHROUGH ;
1544+ }
15101545 case IMAGE_FILETYPE_UNKNOWN :
15111546 break ;
15121547 }
15131548
15141549 if (result ) {
1515- char temp [MAX_LENGTH_OF_LONG * 2 + sizeof ("width=\"\" height=\"\"" )];
15161550 array_init (return_value );
1517- add_index_long (return_value , 0 , result -> width );
1518- add_index_long (return_value , 1 , result -> height );
1551+ if (result -> width_str ) {
1552+ add_index_str (return_value , 0 , result -> width_str );
1553+ add_index_str (return_value , 1 , result -> height_str );
1554+ } else {
1555+ add_index_long (return_value , 0 , result -> width );
1556+ add_index_long (return_value , 1 , result -> height );
1557+ }
15191558 add_index_long (return_value , 2 , itype );
1520- snprintf (temp , sizeof (temp ), "width=\"%d\" height=\"%d\"" , result -> width , result -> height );
1521- add_index_string (return_value , 3 , temp );
1559+ if (result -> width_str ) {
1560+ add_index_str (return_value , 3 , zend_strpprintf_unchecked (0 , "width=\"%S\" height=\"%S\"" , result -> width_str , result -> height_str ));
1561+ } else {
1562+ char temp [MAX_LENGTH_OF_LONG * 2 + sizeof ("width=\"\" height=\"\"" )];
1563+ snprintf (temp , sizeof (temp ), "width=\"%d\" height=\"%d\"" , result -> width , result -> height );
1564+ add_index_string (return_value , 3 , temp );
1565+ }
15221566
15231567 if (result -> bits != 0 ) {
15241568 add_assoc_long (return_value , "bits" , result -> bits );
15251569 }
15261570 if (result -> channels != 0 ) {
15271571 add_assoc_long (return_value , "channels" , result -> channels );
15281572 }
1529- add_assoc_string (return_value , "mime" , ( char * ) php_image_type_to_mime_type (itype ));
1573+ add_assoc_string (return_value , "mime" , mime_type ? mime_type : php_image_type_to_mime_type (itype ));
15301574 efree (result );
15311575 } else {
15321576 RETURN_FALSE ;
@@ -1589,3 +1633,36 @@ PHP_FUNCTION(getimagesizefromstring)
15891633 php_getimagesize_from_any (INTERNAL_FUNCTION_PARAM_PASSTHRU , FROM_DATA );
15901634}
15911635/* }}} */
1636+
1637+ PHP_MINIT_FUNCTION (image )
1638+ {
1639+ zend_hash_init (& php_image_handlers , 4 , NULL , NULL , true);
1640+ return SUCCESS ;
1641+ }
1642+
1643+ PHP_MSHUTDOWN_FUNCTION (image )
1644+ {
1645+ #ifdef ZTS
1646+ if (!tsrm_is_main_thread ()) {
1647+ return SUCCESS ;
1648+ }
1649+ #endif
1650+ zend_hash_destroy (& php_image_handlers );
1651+ return SUCCESS ;
1652+ }
1653+
1654+ extern zend_module_entry basic_functions_module ;
1655+
1656+ int php_image_register_handler (const struct php_image_handler * handler )
1657+ {
1658+ zend_hash_index_add_ptr (& php_image_handlers , (zend_ulong ) php_image_handler_next_id , (void * ) handler );
1659+ zend_register_long_constant (handler -> const_name , strlen (handler -> const_name ), php_image_handler_next_id , CONST_PERSISTENT , basic_functions_module .module_number );
1660+ Z_LVAL_P (zend_get_constant_str (ZEND_STRL ("IMAGETYPE_COUNT" )))++ ;
1661+ return php_image_handler_next_id ++ ;
1662+ }
1663+
1664+ zend_result php_image_unregister_handler (int image_type )
1665+ {
1666+ ZEND_ASSERT (image_type >= IMAGE_FILETYPE_FIXED_COUNT );
1667+ return zend_hash_index_del (& php_image_handlers , (zend_ulong ) image_type );
1668+ }
0 commit comments