wp/wp-admin/includes/image.php
changeset 19 3d72ae0968f4
parent 18 be944660c56a
child 21 48c4eec2b7e6
equal deleted inserted replaced
18:be944660c56a 19:3d72ae0968f4
    61 	$result = $editor->save( $dst_file );
    61 	$result = $editor->save( $dst_file );
    62 	if ( is_wp_error( $result ) ) {
    62 	if ( is_wp_error( $result ) ) {
    63 		return $result;
    63 		return $result;
    64 	}
    64 	}
    65 
    65 
       
    66 	if ( ! empty( $result['path'] ) ) {
       
    67 		return $result['path'];
       
    68 	}
       
    69 
    66 	return $dst_file;
    70 	return $dst_file;
    67 }
    71 }
    68 
    72 
    69 /**
    73 /**
    70  * Compare the existing image sub-sizes (as saved in the attachment meta)
    74  * Compare the existing image sub-sizes (as saved in the attachment meta)
    73  * Registered sub-sizes that are larger than the image are skipped.
    77  * Registered sub-sizes that are larger than the image are skipped.
    74  *
    78  *
    75  * @since 5.3.0
    79  * @since 5.3.0
    76  *
    80  *
    77  * @param int $attachment_id The image attachment post ID.
    81  * @param int $attachment_id The image attachment post ID.
    78  * @return array An array of the image sub-sizes that are currently defined but don't exist for this image.
    82  * @return array[] Associative array of arrays of image sub-size information for
       
    83  *                 missing image sizes, keyed by image size name.
    79  */
    84  */
    80 function wp_get_missing_image_subsizes( $attachment_id ) {
    85 function wp_get_missing_image_subsizes( $attachment_id ) {
    81 	if ( ! wp_attachment_is_image( $attachment_id ) ) {
    86 	if ( ! wp_attachment_is_image( $attachment_id ) ) {
    82 		return array();
    87 		return array();
    83 	}
    88 	}
   129 	/**
   134 	/**
   130 	 * Filters the array of missing image sub-sizes for an uploaded image.
   135 	 * Filters the array of missing image sub-sizes for an uploaded image.
   131 	 *
   136 	 *
   132 	 * @since 5.3.0
   137 	 * @since 5.3.0
   133 	 *
   138 	 *
   134 	 * @param array $missing_sizes Array with the missing image sub-sizes.
   139 	 * @param array[] $missing_sizes Associative array of arrays of image sub-size information for
   135 	 * @param array $image_meta    The image meta data.
   140 	 *                               missing image sizes, keyed by image size name.
   136 	 * @param int   $attachment_id The image attachment post ID.
   141 	 * @param array   $image_meta    The image meta data.
       
   142 	 * @param int     $attachment_id The image attachment post ID.
   137 	 */
   143 	 */
   138 	return apply_filters( 'wp_get_missing_image_subsizes', $missing_sizes, $image_meta, $attachment_id );
   144 	return apply_filters( 'wp_get_missing_image_subsizes', $missing_sizes, $image_meta, $attachment_id );
   139 }
   145 }
   140 
   146 
   141 /**
   147 /**
   206 	$image_meta['file'] = _wp_relative_upload_path( $new_file );
   212 	$image_meta['file'] = _wp_relative_upload_path( $new_file );
   207 
   213 
   208 	// Store the original image file name in image_meta.
   214 	// Store the original image file name in image_meta.
   209 	$image_meta['original_image'] = wp_basename( $original_file );
   215 	$image_meta['original_image'] = wp_basename( $original_file );
   210 
   216 
       
   217 	// Add image file size.
       
   218 	$image_meta['filesize'] = wp_filesize( $new_file );
       
   219 
   211 	return $image_meta;
   220 	return $image_meta;
   212 }
   221 }
   213 
   222 
   214 /**
   223 /**
   215  * Creates image sub-sizes, adds the new data to the image meta `sizes` array, and updates the image metadata.
   224  * Creates image sub-sizes, adds the new data to the image meta `sizes` array, and updates the image metadata.
   218  * sub-size is created. If there was an error, it is added to the returned image metadata array.
   227  * sub-size is created. If there was an error, it is added to the returned image metadata array.
   219  *
   228  *
   220  * @since 5.3.0
   229  * @since 5.3.0
   221  *
   230  *
   222  * @param string $file          Full path to the image file.
   231  * @param string $file          Full path to the image file.
   223  * @param int    $attachment_id Attachment Id to process.
   232  * @param int    $attachment_id Attachment ID to process.
   224  * @return array The image attachment meta data.
   233  * @return array The image attachment meta data.
   225  */
   234  */
   226 function wp_create_image_subsizes( $file, $attachment_id ) {
   235 function wp_create_image_subsizes( $file, $attachment_id ) {
   227 	$imagesize = wp_getimagesize( $file );
   236 	$imagesize = wp_getimagesize( $file );
   228 
   237 
   231 		return array();
   240 		return array();
   232 	}
   241 	}
   233 
   242 
   234 	// Default image meta.
   243 	// Default image meta.
   235 	$image_meta = array(
   244 	$image_meta = array(
   236 		'width'  => $imagesize[0],
   245 		'width'    => $imagesize[0],
   237 		'height' => $imagesize[1],
   246 		'height'   => $imagesize[1],
   238 		'file'   => _wp_relative_upload_path( $file ),
   247 		'file'     => _wp_relative_upload_path( $file ),
   239 		'sizes'  => array(),
   248 		'filesize' => wp_filesize( $file ),
       
   249 		'sizes'    => array(),
   240 	);
   250 	);
   241 
   251 
   242 	// Fetch additional metadata from EXIF/IPTC.
   252 	// Fetch additional metadata from EXIF/IPTC.
   243 	$exif_meta = wp_read_image_metadata( $file );
   253 	$exif_meta = wp_read_image_metadata( $file );
   244 
   254 
   376  * @access private
   386  * @access private
   377  *
   387  *
   378  * @param array  $new_sizes     Array defining what sizes to create.
   388  * @param array  $new_sizes     Array defining what sizes to create.
   379  * @param string $file          Full path to the image file.
   389  * @param string $file          Full path to the image file.
   380  * @param array  $image_meta    The attachment meta data array.
   390  * @param array  $image_meta    The attachment meta data array.
   381  * @param int    $attachment_id Attachment Id to process.
   391  * @param int    $attachment_id Attachment ID to process.
   382  * @return array The attachment meta data with updated `sizes` array. Includes an array of errors encountered while resizing.
   392  * @return array The attachment meta data with updated `sizes` array. Includes an array of errors encountered while resizing.
   383  */
   393  */
   384 function _wp_make_subsizes( $new_sizes, $file, $image_meta, $attachment_id ) {
   394 function _wp_make_subsizes( $new_sizes, $file, $image_meta, $attachment_id ) {
   385 	if ( empty( $image_meta ) || ! is_array( $image_meta ) ) {
   395 	if ( empty( $image_meta ) || ! is_array( $image_meta ) ) {
   386 		// Not an image attachment.
   396 		// Not an image attachment.
   466 /**
   476 /**
   467  * Generate attachment meta data and create image sub-sizes for images.
   477  * Generate attachment meta data and create image sub-sizes for images.
   468  *
   478  *
   469  * @since 2.1.0
   479  * @since 2.1.0
   470  *
   480  *
   471  * @param int    $attachment_id Attachment Id to process.
   481  * @param int    $attachment_id Attachment ID to process.
   472  * @param string $file          Filepath of the Attached image.
   482  * @param string $file          Filepath of the attached image.
   473  * @return array Metadata for attachment.
   483  * @return array Metadata for attachment.
   474  */
   484  */
   475 function wp_generate_attachment_metadata( $attachment_id, $file ) {
   485 function wp_generate_attachment_metadata( $attachment_id, $file ) {
   476 	$attachment = get_post( $attachment_id );
   486 	$attachment = get_post( $attachment_id );
   477 
   487 
   625 	}
   635 	}
   626 
   636 
   627 	// Remove the blob of binary data from the array.
   637 	// Remove the blob of binary data from the array.
   628 	unset( $metadata['image']['data'] );
   638 	unset( $metadata['image']['data'] );
   629 
   639 
       
   640 	// Capture file size for cases where it has not been captured yet, such as PDFs.
       
   641 	if ( ! isset( $metadata['filesize'] ) && file_exists( $file ) ) {
       
   642 		$metadata['filesize'] = wp_filesize( $file );
       
   643 	}
       
   644 
   630 	/**
   645 	/**
   631 	 * Filters the generated attachment meta data.
   646 	 * Filters the generated attachment meta data.
   632 	 *
   647 	 *
   633 	 * @since 2.1.0
   648 	 * @since 2.1.0
   634 	 * @since 5.3.0 The `$context` parameter was added.
   649 	 * @since 5.3.0 The `$context` parameter was added.
   644 /**
   659 /**
   645  * Convert a fraction string to a decimal.
   660  * Convert a fraction string to a decimal.
   646  *
   661  *
   647  * @since 2.5.0
   662  * @since 2.5.0
   648  *
   663  *
   649  * @param string $str
   664  * @param string $str Fraction string.
   650  * @return int|float
   665  * @return int|float Returns calculated fraction or integer 0 on invalid input.
   651  */
   666  */
   652 function wp_exif_frac2dec( $str ) {
   667 function wp_exif_frac2dec( $str ) {
   653 	if ( false === strpos( $str, '/' ) ) {
   668 	if ( ! is_scalar( $str ) || is_bool( $str ) ) {
   654 		return $str;
   669 		return 0;
       
   670 	}
       
   671 
       
   672 	if ( ! is_string( $str ) ) {
       
   673 		return $str; // This can only be an integer or float, so this is fine.
       
   674 	}
       
   675 
       
   676 	// Fractions passed as a string must contain a single `/`.
       
   677 	if ( substr_count( $str, '/' ) !== 1 ) {
       
   678 		if ( is_numeric( $str ) ) {
       
   679 			return (float) $str;
       
   680 		}
       
   681 
       
   682 		return 0;
   655 	}
   683 	}
   656 
   684 
   657 	list( $numerator, $denominator ) = explode( '/', $str );
   685 	list( $numerator, $denominator ) = explode( '/', $str );
   658 	if ( ! empty( $denominator ) ) {
   686 
   659 		return $numerator / $denominator;
   687 	// Both the numerator and the denominator must be numbers.
   660 	}
   688 	if ( ! is_numeric( $numerator ) || ! is_numeric( $denominator ) ) {
   661 	return $str;
   689 		return 0;
       
   690 	}
       
   691 
       
   692 	// The denominator must not be zero.
       
   693 	if ( 0 == $denominator ) { // phpcs:ignore WordPress.PHP.StrictComparisons.LooseComparison -- Deliberate loose comparison.
       
   694 		return 0;
       
   695 	}
       
   696 
       
   697 	return $numerator / $denominator;
   662 }
   698 }
   663 
   699 
   664 /**
   700 /**
   665  * Convert the exif date format to a unix timestamp.
   701  * Convert the exif date format to a unix timestamp.
   666  *
   702  *
   667  * @since 2.5.0
   703  * @since 2.5.0
   668  *
   704  *
   669  * @param string $str
   705  * @param string $str A date string expected to be in Exif format (Y:m:d H:i:s).
   670  * @return int
   706  * @return int|false The unix timestamp, or false on failure.
   671  */
   707  */
   672 function wp_exif_date2ts( $str ) {
   708 function wp_exif_date2ts( $str ) {
   673 	list( $date, $time ) = explode( ' ', trim( $str ) );
   709 	list( $date, $time ) = explode( ' ', trim( $str ) );
   674 	list( $y, $m, $d )   = explode( ':', $date );
   710 	list( $y, $m, $d )   = explode( ':', $date );
   675 
   711 
   738 			} else {
   774 			} else {
   739 				// phpcs:ignore WordPress.PHP.NoSilencedErrors -- Silencing notice and warning is intentional. See https://core.trac.wordpress.org/ticket/42480
   775 				// phpcs:ignore WordPress.PHP.NoSilencedErrors -- Silencing notice and warning is intentional. See https://core.trac.wordpress.org/ticket/42480
   740 				$iptc = @iptcparse( $info['APP13'] );
   776 				$iptc = @iptcparse( $info['APP13'] );
   741 			}
   777 			}
   742 
   778 
       
   779 			if ( ! is_array( $iptc ) ) {
       
   780 				$iptc = array();
       
   781 			}
       
   782 
   743 			// Headline, "A brief synopsis of the caption".
   783 			// Headline, "A brief synopsis of the caption".
   744 			if ( ! empty( $iptc['2#105'][0] ) ) {
   784 			if ( ! empty( $iptc['2#105'][0] ) ) {
   745 				$meta['title'] = trim( $iptc['2#105'][0] );
   785 				$meta['title'] = trim( $iptc['2#105'][0] );
   746 				/*
   786 				/*
   747 				* Title, "Many use the Title field to store the filename of the image,
   787 				* Title, "Many use the Title field to store the filename of the image,
   791 	/**
   831 	/**
   792 	 * Filters the image types to check for exif data.
   832 	 * Filters the image types to check for exif data.
   793 	 *
   833 	 *
   794 	 * @since 2.5.0
   834 	 * @since 2.5.0
   795 	 *
   835 	 *
   796 	 * @param array $image_types Image types to check for exif data.
   836 	 * @param int[] $image_types Array of image types to check for exif data. Each value
       
   837 	 *                           is usually one of the `IMAGETYPE_*` constants.
   797 	 */
   838 	 */
   798 	$exif_image_types = apply_filters( 'wp_read_image_metadata_types', array( IMAGETYPE_JPEG, IMAGETYPE_TIFF_II, IMAGETYPE_TIFF_MM ) );
   839 	$exif_image_types = apply_filters( 'wp_read_image_metadata_types', array( IMAGETYPE_JPEG, IMAGETYPE_TIFF_II, IMAGETYPE_TIFF_MM ) );
   799 
   840 
   800 	if ( is_callable( 'exif_read_data' ) && in_array( $image_type, $exif_image_types, true ) ) {
   841 	if ( is_callable( 'exif_read_data' ) && in_array( $image_type, $exif_image_types, true ) ) {
   801 		// Don't silence errors when in debug mode, unless running unit tests.
   842 		// Don't silence errors when in debug mode, unless running unit tests.
   806 		} else {
   847 		} else {
   807 			// phpcs:ignore WordPress.PHP.NoSilencedErrors -- Silencing notice and warning is intentional. See https://core.trac.wordpress.org/ticket/42480
   848 			// phpcs:ignore WordPress.PHP.NoSilencedErrors -- Silencing notice and warning is intentional. See https://core.trac.wordpress.org/ticket/42480
   808 			$exif = @exif_read_data( $file );
   849 			$exif = @exif_read_data( $file );
   809 		}
   850 		}
   810 
   851 
       
   852 		if ( ! is_array( $exif ) ) {
       
   853 			$exif = array();
       
   854 		}
       
   855 
   811 		if ( ! empty( $exif['ImageDescription'] ) ) {
   856 		if ( ! empty( $exif['ImageDescription'] ) ) {
   812 			mbstring_binary_safe_encoding();
   857 			mbstring_binary_safe_encoding();
   813 			$description_length = strlen( $exif['ImageDescription'] );
   858 			$description_length = strlen( $exif['ImageDescription'] );
   814 			reset_mbstring_encoding();
   859 			reset_mbstring_encoding();
   815 
   860 
   838 		}
   883 		}
   839 
   884 
   840 		if ( empty( $meta['copyright'] ) && ! empty( $exif['Copyright'] ) ) {
   885 		if ( empty( $meta['copyright'] ) && ! empty( $exif['Copyright'] ) ) {
   841 			$meta['copyright'] = trim( $exif['Copyright'] );
   886 			$meta['copyright'] = trim( $exif['Copyright'] );
   842 		}
   887 		}
   843 		if ( ! empty( $exif['FNumber'] ) ) {
   888 		if ( ! empty( $exif['FNumber'] ) && is_scalar( $exif['FNumber'] ) ) {
   844 			$meta['aperture'] = round( wp_exif_frac2dec( $exif['FNumber'] ), 2 );
   889 			$meta['aperture'] = round( wp_exif_frac2dec( $exif['FNumber'] ), 2 );
   845 		}
   890 		}
   846 		if ( ! empty( $exif['Model'] ) ) {
   891 		if ( ! empty( $exif['Model'] ) ) {
   847 			$meta['camera'] = trim( $exif['Model'] );
   892 			$meta['camera'] = trim( $exif['Model'] );
   848 		}
   893 		}
   849 		if ( empty( $meta['created_timestamp'] ) && ! empty( $exif['DateTimeDigitized'] ) ) {
   894 		if ( empty( $meta['created_timestamp'] ) && ! empty( $exif['DateTimeDigitized'] ) ) {
   850 			$meta['created_timestamp'] = wp_exif_date2ts( $exif['DateTimeDigitized'] );
   895 			$meta['created_timestamp'] = wp_exif_date2ts( $exif['DateTimeDigitized'] );
   851 		}
   896 		}
   852 		if ( ! empty( $exif['FocalLength'] ) ) {
   897 		if ( ! empty( $exif['FocalLength'] ) ) {
   853 			$meta['focal_length'] = (string) wp_exif_frac2dec( $exif['FocalLength'] );
   898 			$meta['focal_length'] = (string) $exif['FocalLength'];
       
   899 			if ( is_scalar( $exif['FocalLength'] ) ) {
       
   900 				$meta['focal_length'] = (string) wp_exif_frac2dec( $exif['FocalLength'] );
       
   901 			}
   854 		}
   902 		}
   855 		if ( ! empty( $exif['ISOSpeedRatings'] ) ) {
   903 		if ( ! empty( $exif['ISOSpeedRatings'] ) ) {
   856 			$meta['iso'] = is_array( $exif['ISOSpeedRatings'] ) ? reset( $exif['ISOSpeedRatings'] ) : $exif['ISOSpeedRatings'];
   904 			$meta['iso'] = is_array( $exif['ISOSpeedRatings'] ) ? reset( $exif['ISOSpeedRatings'] ) : $exif['ISOSpeedRatings'];
   857 			$meta['iso'] = trim( $meta['iso'] );
   905 			$meta['iso'] = trim( $meta['iso'] );
   858 		}
   906 		}
   859 		if ( ! empty( $exif['ExposureTime'] ) ) {
   907 		if ( ! empty( $exif['ExposureTime'] ) ) {
   860 			$meta['shutter_speed'] = (string) wp_exif_frac2dec( $exif['ExposureTime'] );
   908 			$meta['shutter_speed'] = (string) $exif['ExposureTime'];
       
   909 			if ( is_scalar( $exif['ExposureTime'] ) ) {
       
   910 				$meta['shutter_speed'] = (string) wp_exif_frac2dec( $exif['ExposureTime'] );
       
   911 			}
   861 		}
   912 		}
   862 		if ( ! empty( $exif['Orientation'] ) ) {
   913 		if ( ! empty( $exif['Orientation'] ) ) {
   863 			$meta['orientation'] = $exif['Orientation'];
   914 			$meta['orientation'] = $exif['Orientation'];
   864 		}
   915 		}
   865 	}
   916 	}
   915  *
   966  *
   916  * @param string $path File path to test.
   967  * @param string $path File path to test.
   917  * @return bool True if suitable, false if not suitable.
   968  * @return bool True if suitable, false if not suitable.
   918  */
   969  */
   919 function file_is_displayable_image( $path ) {
   970 function file_is_displayable_image( $path ) {
   920 	$displayable_image_types = array( IMAGETYPE_GIF, IMAGETYPE_JPEG, IMAGETYPE_PNG, IMAGETYPE_BMP, IMAGETYPE_ICO, IMAGETYPE_WEBP ); // phpcs:ignore PHPCompatibility.Constants.NewConstants.imagetype_webpFound
   971 	$displayable_image_types = array( IMAGETYPE_GIF, IMAGETYPE_JPEG, IMAGETYPE_PNG, IMAGETYPE_BMP, IMAGETYPE_ICO, IMAGETYPE_WEBP );
   921 
   972 
   922 	$info = wp_getimagesize( $path );
   973 	$info = wp_getimagesize( $path );
   923 	if ( empty( $info ) ) {
   974 	if ( empty( $info ) ) {
   924 		$result = false;
   975 		$result = false;
   925 	} elseif ( ! in_array( $info[2], $displayable_image_types, true ) ) {
   976 	} elseif ( ! in_array( $info[2], $displayable_image_types, true ) ) {