@@ -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
@@ -1205,7 +1208,7 @@ bool php_is_image_avif(php_stream* stream) {
12051208
12061209/* {{{ php_image_type_to_mime_type
12071210 * Convert internal image_type to mime type */
1208- PHPAPI char * php_image_type_to_mime_type (int image_type )
1211+ PHPAPI const char * php_image_type_to_mime_type (int image_type )
12091212{
12101213 switch ( image_type ) {
12111214 case IMAGE_FILETYPE_GIF :
@@ -1240,7 +1243,13 @@ PHPAPI char * php_image_type_to_mime_type(int image_type)
12401243 return "image/webp" ;
12411244 case IMAGE_FILETYPE_AVIF :
12421245 return "image/avif" ;
1243- default :
1246+ default : {
1247+ const struct php_image_handler * handler = zend_hash_index_find_ptr (& php_image_handlers , (zend_ulong ) image_type );
1248+ if (handler ) {
1249+ return handler -> mime_type ;
1250+ }
1251+ ZEND_FALLTHROUGH ;
1252+ }
12441253 case IMAGE_FILETYPE_UNKNOWN :
12451254 return "application/octet-stream" ; /* suppose binary format */
12461255 }
@@ -1256,7 +1265,7 @@ PHP_FUNCTION(image_type_to_mime_type)
12561265 Z_PARAM_LONG (p_image_type )
12571266 ZEND_PARSE_PARAMETERS_END ();
12581267
1259- ZVAL_STRING (return_value , ( char * ) php_image_type_to_mime_type (p_image_type ));
1268+ ZVAL_STRING (return_value , php_image_type_to_mime_type (p_image_type ));
12601269}
12611270/* }}} */
12621271
@@ -1325,6 +1334,13 @@ PHP_FUNCTION(image_type_to_extension)
13251334 case IMAGE_FILETYPE_AVIF :
13261335 imgext = ".avif" ;
13271336 break ;
1337+ default : {
1338+ const struct php_image_handler * handler = zend_hash_index_find_ptr (& php_image_handlers , (zend_ulong ) image_type );
1339+ if (handler ) {
1340+ imgext = handler -> extension ;
1341+ }
1342+ break ;
1343+ }
13281344 }
13291345
13301346 if (imgext ) {
@@ -1427,6 +1443,15 @@ PHPAPI int php_getimagetype(php_stream *stream, const char *input, char *filetyp
14271443 return IMAGE_FILETYPE_XBM ;
14281444 }
14291445
1446+ zend_ulong h ;
1447+ zval * zv ;
1448+ ZEND_HASH_FOREACH_NUM_KEY_VAL (& php_image_handlers , h , zv ) {
1449+ const struct php_image_handler * handler = Z_PTR_P (zv );
1450+ if (handler -> identify (stream ) == SUCCESS ) {
1451+ return (int ) h ;
1452+ }
1453+ } ZEND_HASH_FOREACH_END ();
1454+
14301455 return IMAGE_FILETYPE_UNKNOWN ;
14311456}
14321457/* }}} */
@@ -1435,6 +1460,7 @@ static void php_getimagesize_from_stream(php_stream *stream, char *input, zval *
14351460{
14361461 int itype = 0 ;
14371462 struct php_gfxinfo * result = NULL ;
1463+ const char * mime_type = NULL ;
14381464
14391465 if (!stream ) {
14401466 RETURN_FALSE ;
@@ -1459,6 +1485,7 @@ static void php_getimagesize_from_stream(php_stream *stream, char *input, zval *
14591485 result = php_handle_swf (stream );
14601486 break ;
14611487 case IMAGE_FILETYPE_SWC :
1488+ /* TODO: with the new php_image_register_handler() APIs, this restriction could be solved */
14621489#if defined(HAVE_ZLIB ) && !defined(COMPILE_DL_ZLIB )
14631490 result = php_handle_swc (stream );
14641491#else
@@ -1501,27 +1528,44 @@ static void php_getimagesize_from_stream(php_stream *stream, char *input, zval *
15011528 case IMAGE_FILETYPE_AVIF :
15021529 result = php_handle_avif (stream );
15031530 break ;
1504- default :
1531+ default : {
1532+ struct php_image_handler * handler = zend_hash_index_find_ptr (& php_image_handlers , (zend_ulong ) itype );
1533+ if (handler ) {
1534+ result = handler -> get_info (stream );
1535+ mime_type = handler -> mime_type ;
1536+ break ;
1537+ }
1538+ ZEND_FALLTHROUGH ;
1539+ }
15051540 case IMAGE_FILETYPE_UNKNOWN :
15061541 break ;
15071542 }
15081543
15091544 if (result ) {
1510- char temp [MAX_LENGTH_OF_LONG * 2 + sizeof ("width=\"\" height=\"\"" )];
15111545 array_init (return_value );
1512- add_index_long (return_value , 0 , result -> width );
1513- add_index_long (return_value , 1 , result -> height );
1546+ if (result -> width_str ) {
1547+ add_index_str (return_value , 0 , result -> width_str );
1548+ add_index_str (return_value , 1 , result -> height_str );
1549+ } else {
1550+ add_index_long (return_value , 0 , result -> width );
1551+ add_index_long (return_value , 1 , result -> height );
1552+ }
15141553 add_index_long (return_value , 2 , itype );
1515- snprintf (temp , sizeof (temp ), "width=\"%d\" height=\"%d\"" , result -> width , result -> height );
1516- add_index_string (return_value , 3 , temp );
1554+ if (result -> width_str ) {
1555+ add_index_str (return_value , 3 , zend_strpprintf_unchecked (0 , "width=\"%S\" height=\"%S\"" , result -> width_str , result -> height_str ));
1556+ } else {
1557+ char temp [MAX_LENGTH_OF_LONG * 2 + sizeof ("width=\"\" height=\"\"" )];
1558+ snprintf (temp , sizeof (temp ), "width=\"%d\" height=\"%d\"" , result -> width , result -> height );
1559+ add_index_string (return_value , 3 , temp );
1560+ }
15171561
15181562 if (result -> bits != 0 ) {
15191563 add_assoc_long (return_value , "bits" , result -> bits );
15201564 }
15211565 if (result -> channels != 0 ) {
15221566 add_assoc_long (return_value , "channels" , result -> channels );
15231567 }
1524- add_assoc_string (return_value , "mime" , ( char * ) php_image_type_to_mime_type (itype ));
1568+ add_assoc_string (return_value , "mime" , mime_type ? mime_type : php_image_type_to_mime_type (itype ));
15251569 efree (result );
15261570 } else {
15271571 RETURN_FALSE ;
@@ -1584,3 +1628,36 @@ PHP_FUNCTION(getimagesizefromstring)
15841628 php_getimagesize_from_any (INTERNAL_FUNCTION_PARAM_PASSTHRU , FROM_DATA );
15851629}
15861630/* }}} */
1631+
1632+ PHP_MINIT_FUNCTION (image )
1633+ {
1634+ zend_hash_init (& php_image_handlers , 4 , NULL , NULL , true);
1635+ return SUCCESS ;
1636+ }
1637+
1638+ PHP_MSHUTDOWN_FUNCTION (image )
1639+ {
1640+ #ifdef ZTS
1641+ if (!tsrm_is_main_thread ()) {
1642+ return SUCCESS ;
1643+ }
1644+ #endif
1645+ zend_hash_destroy (& php_image_handlers );
1646+ return SUCCESS ;
1647+ }
1648+
1649+ extern zend_module_entry basic_functions_module ;
1650+
1651+ int php_image_register_handler (const struct php_image_handler * handler )
1652+ {
1653+ zend_hash_index_add_ptr (& php_image_handlers , (zend_ulong ) php_image_handler_next_id , (void * ) handler );
1654+ zend_register_long_constant (handler -> const_name , strlen (handler -> const_name ), php_image_handler_next_id , CONST_PERSISTENT , basic_functions_module .module_number );
1655+ Z_LVAL_P (zend_get_constant_str (ZEND_STRL ("IMAGETYPE_COUNT" )))++ ;
1656+ return php_image_handler_next_id ++ ;
1657+ }
1658+
1659+ zend_result php_image_unregister_handler (int image_type )
1660+ {
1661+ ZEND_ASSERT (image_type >= IMAGE_FILETYPE_FIXED_COUNT );
1662+ return zend_hash_index_del (& php_image_handlers , (zend_ulong ) image_type );
1663+ }
0 commit comments