Skip to content

Commit

Permalink
Ensure images with dimensions in name are supported
Browse files Browse the repository at this point in the history
Tachyon would previsouly assume that an image with a suffix like `-123x456.jpg` was from a thumbnail and attempt to infer the size from that. This update checks whether that suffix matches an image GUID, if it does then its an original file and should not have the dimensions inferred or have the suffix stripped off.

Fixes #43
  • Loading branch information
roborourke committed Nov 2, 2020
1 parent 945ce40 commit 4066af8
Show file tree
Hide file tree
Showing 4 changed files with 124 additions and 25 deletions.
74 changes: 50 additions & 24 deletions inc/class-tachyon.php
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,24 @@ public static function parse_dimensions_from_filename( $src ) {
return array( false, false );
}

/**
* Get an attachment post ID by GUID.
*
* @param string $src The attachment source.
* @return int|false
*/
public static function get_attachment_by_guid( $src ) {
global $wpdb;

// Trim the host name portion of the source as this could potentially have changed.
$src_path = wp_parse_url( $src, PHP_URL_PATH );

// Try to fetch the post ID by GUID.
$id = $wpdb->get_var( $wpdb->prepare( "SELECT ID FROM {$wpdb->posts} WHERE post_type = 'attachment' AND guid LIKE '%%%s' LIMIT 1;", $src_path ) );

return $id ?? false;
}

/**
* Identify images in post content, and if images are local (uploaded to the current site), pass through Tachyon.
*
Expand Down Expand Up @@ -192,29 +210,30 @@ public static function filter_the_content( $content ) {
if ( preg_match( '#height=["|\']?([\d%]+)["|\']?#i', $images['img_tag'][ $index ], $height_string ) )
$height = $height_string[1];

// Detect WP registered image size from HTML class
if ( preg_match( '#class=["|\']?[^"\']*size-([^"\'\s]+)[^"\']*["|\']?#i', $images['img_tag'][ $index ], $matches ) ) {
$size = array_pop( $matches );
}
// If image tag lacks width or height arguments, try to determine from strings WP appends to resized image filenames.
if ( ! $width || ! $height ) {
if ( ! isset( $size ) && ( ! $width || ! $height ) ) {
$size_from_file = static::parse_dimensions_from_filename( $src );
$width = $width ?: $size_from_file[0];
$height = $height ?: $size_from_file[1];
// Check if this isn't a full size URL before inferring dimensions.
if ( $size_from_file[0] !== false && $size_from_file[1] !== false ) {
$attachment_id = self::get_attachment_by_guid( $src );
if ( $attachment_id ) {
$fullsize_url = true;
} else {
$width = $size_from_file[0];
$height = $size_from_file[1];
}
}
}

// Can't pass both a relative width and height, so unset the height in favor of not breaking the horizontal layout.
if ( false !== strpos( $width, '%' ) && false !== strpos( $height, '%' ) )
$width = $height = false;

// Detect WP registered image size from HTML class
if ( preg_match( '#class=["|\']?[^"\']*size-([^"\'\s]+)[^"\']*["|\']?#i', $images['img_tag'][ $index ], $matches ) ) {
$size = array_pop( $matches );
if ( false === $width && false === $height && isset( $size ) && array_key_exists( $size, $image_sizes ) ) {
$size_from_wp = wp_get_attachment_image_src( $attachment_id, $size );
$width = $size_from_wp[1];
$height = $size_from_wp[2];
$transform = $image_sizes[ $size ]['crop'] ? 'resize' : 'fit';
}
}

// WP Attachment ID, if uploaded to this site
if (
preg_match( '#class=["|\']?[^"\']*wp-image-([\d]+)[^"\']*["|\']?#i', $images['img_tag'][ $index ], $class_attachment_id ) &&
Expand Down Expand Up @@ -334,15 +353,6 @@ public static function filter_the_content( $content ) {
$transform = 'fit';
}

// Detect if image source is for a custom-cropped thumbnail and prevent further URL manipulation.
if ( ! $fullsize_url && preg_match_all( '#-e[a-z0-9]+(-\d+x\d+)?\.(' . implode('|', self::$extensions ) . '){1}$#i', basename( $src ), $filename ) )
$fullsize_url = true;

// Build URL, first maybe removing WP's resized string so we pass the original image to Tachyon
if ( ! $fullsize_url ) {
$src = self::strip_image_dimensions_maybe( $src );
}

// Build array of Tachyon args and expose to filter before passing to Tachyon URL function
$args = array();

Expand Down Expand Up @@ -395,6 +405,15 @@ public static function filter_the_content( $content ) {
$size = [ $width, $height ];
}

// Detect if image source is for a custom-cropped thumbnail and prevent further URL manipulation.
if ( ! $fullsize_url && preg_match_all( '#-e[a-z0-9]+(-\d+x\d+)?\.(' . implode('|', self::$extensions ) . '){1}$#i', basename( $src ), $filename ) )
$fullsize_url = true;

// Build URL, first maybe removing WP's resized string so we pass the original image to Tachyon
if ( ! $fullsize_url ) {
$src = self::strip_image_dimensions_maybe( $src );
}

/**
* Filter the array of Tachyon arguments added to an image when it goes through Tachyon.
* By default, only includes width and height values.
Expand Down Expand Up @@ -826,6 +845,13 @@ public static function validate_image_url( $url ) {
* @return string
**/
protected static function strip_image_dimensions_maybe( $src ) {
// Check we can find the attachment by that name
$attachment_id = self::get_attachment_by_guid( $src );
if ( $attachment_id ) {
// Prevent stripping dimenions from src.
return $src;
}

// Build URL, first removing WP's resized string so we pass the original image to Tachyon
if ( preg_match( '#(-\d+x\d+)\.(' . implode( '|', self::$extensions ) . '){1}$#i', $src, $src_parts ) ) {
$src = str_replace( $src_parts[1], '', $src );
Expand Down
2 changes: 1 addition & 1 deletion tests/bootstrap.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
// 2. Plugin installed inside of WordPress.org developer checkout
// 3. Tests checked out to /tmp
if ( false !== getenv( 'WP_DEVELOP_DIR' ) ) {
$test_root = getenv( 'WP_DEVELOP_DIR' ) . '/tests/phpunit';
$test_root = getenv( 'WP_DEVELOP_DIR' );
} elseif ( file_exists( '../../../../tests/phpunit/includes/bootstrap.php' ) ) {
$test_root = '../../../../tests/phpunit';
} elseif ( file_exists( '/tmp/wordpress-tests-lib/includes/bootstrap.php' ) ) {
Expand Down
Binary file added tests/data/tachyon-1132x687.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
73 changes: 73 additions & 0 deletions tests/tests/class-resizing.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,17 @@ class Tests_Resizing extends WP_UnitTestCase {
*
* tachyon.jpg: 1280x719
* tachyon-large.jpg: 5312x2988
* tachyon-1132x687.jpg: 1280x719
* Photo by Digital Buggu from Pexels
* @link https://www.pexels.com/photo/0-7-rpm-171195/
*/
static public function wpSetUpBeforeClass( $factory ) {
global $_wp_additional_image_sizes;
self::$wp_additional_image_sizes = $_wp_additional_image_sizes;

// Ensure pre WP 5.3.1 behaviour with image file having dimensions in file name.
add_filter( 'wp_unique_filename', __NAMESPACE__ . '\\Tests_Resizing::unique_filename_override' );

self::setup_custom_sizes();

self::$attachment_ids['tachyon'] = $factory->attachment->create_upload_object(
Expand All @@ -43,6 +47,10 @@ static public function wpSetUpBeforeClass( $factory ) {
self::$attachment_ids['tachyon-large'] = $factory->attachment->create_upload_object(
realpath( __DIR__ . '/../data/tachyon-large.jpg')
);

self::$attachment_ids['tachyon-1132x687'] = $factory->attachment->create_upload_object(
realpath( __DIR__ . '/../data/tachyon-1132x687.jpg')
);
}

/**
Expand Down Expand Up @@ -72,6 +80,25 @@ public static function wpTearDownAfterClass() {
}
} );
rmdir( $uploads_dir );

remove_filter( 'wp_unique_filename', __NAMESPACE__ . '\\Tests_Resizing::unique_filename_override' );
}

/**
* Prevents WP from fixing the file name during upload.
*
* This occurs if the file name contains dimensions as a suffix.
* This is to help test for backwards compat with WP 5.3.0 and earlier.
*
* @param string $filename
* @return string
*/
public static function unique_filename_override( $filename ) {
if ( strpos( $filename, 'tachyon-1132x687' ) === false ) {
return $filename;
}

return str_replace( '-1.jpg', '.jpg', $filename );
}

function setUp() {
Expand Down Expand Up @@ -411,6 +438,30 @@ function data_filtered_url() {
],
[ 1000, 1000 ],
],
[
'tachyon-1132x687',
'large',
[
'http://tachy.on/u/tachyon-1132x687.jpg?fit=1024,719',
'http://tachy.on/u/tachyon-1132x687.jpg?resize=1024,575',
'http://tachy.on/u/tachyon-1132x687.jpg?fit=1024,1024',
'http://tachy.on/u/tachyon-1132x687.jpg?w=1024&h=575',
'http://tachy.on/u/tachyon-1132x687-1.jpg?fit=1024,719',
'http://tachy.on/u/tachyon-1132x687-1.jpg?resize=1024,575',
'http://tachy.on/u/tachyon-1132x687-1.jpg?fit=1024,1024',
'http://tachy.on/u/tachyon-1132x687-1.jpg?w=1024&h=575',
],
[ 1024, 575 ],
],
[
'tachyon-1132x687',
'full',
[
'http://tachy.on/u/tachyon-1132x687.jpg',
'http://tachy.on/u/tachyon-1132x687-1.jpg',
],
[ 1280, 719 ],
],
];
}

Expand Down Expand Up @@ -720,6 +771,28 @@ function data_content_filtering() {
'http://tachy.on/u/tachyon.jpg?resize=150,150',
],
],
// Unknown attachment ID, unknown size, original file name contains dimensions.
[
'tachyon-1132x687',
'<p><img class="alignnone" src="%%BASE_URL%%/tachyon-1132x687.jpg" alt="" /></p>',
[
'http://tachy.on/u/tachyon-1132x687.jpg',
],
],
[
'tachyon-1132x687',
'<p><img class="alignnone" src="%%BASE_URL%%/tachyon-1132x687-150x150.jpg" alt="" width="150" height="150" /></p>',
[
'http://tachy.on/u/tachyon-1132x687.jpg?resize=150,150',
],
],
[
'tachyon-1132x687',
'<p><img class="alignnone" src="%%BASE_URL%%/tachyon-1132x687-150x150.jpg" alt="" /></p>',
[
'http://tachy.on/u/tachyon-1132x687.jpg?resize=150,150',
],
],
];
}
}

0 comments on commit 4066af8

Please sign in to comment.