Support for Drupal 7 is ending on 5 January 2025—it’s time to migrate to Drupal 10! Learn about the many benefits of Drupal 10 and find migration tools in our resource center.
Problem/Motivation
If file is converted to another format, i.e. from jpg to gif, filepath does not match anymore. We already have a piece of code to match converted image uri but it works only for non-private files.
See Drupal\image\Controller\ImageStyleDownloadController::deliver()
:
// Don't try to generate file if source is missing.
if (!file_exists($image_uri)) {
// If the image style converted the extension, it has been added to the
// original file, resulting in filenames like image.png.jpeg. So to find
// the actual source image, we remove the extension and check if that
// image exists.
$path_info = pathinfo($image_uri);
$converted_image_uri = $path_info['dirname'] . DIRECTORY_SEPARATOR . $path_info['filename'];
if (!file_exists($converted_image_uri)) {
$this->logger->notice('Source image at %source_image_path not found while trying to generate derivative image at %derivative_path.', array('%source_image_path' => $image_uri, '%derivative_path' => $derivative_uri));
return new Response($this->t('Error generating image, missing source file.'), 404);
}
else {
// The converted file does exist, use it as the source.
$image_uri = $converted_image_uri;
}
}
Proposed resolution
- Wait for #2702227: Image styles for private files are serving the original instead of derivative
- Pass the correct image URI to the implementations of
hook_file_download
. The image URI should be one of the following:- The requested image URI when the file exists.
- The converted image URI when the file exists and the image style has converted the file extension. Update the code to correctly get the image URI without the converted extension for any file scheme.
- Accommodate changes in #3127116: Image styles - thumbnails are broken in config page when private file system is used for the image module's sample images.
Remaining tasks
as above
User interface changes
none
API changes
none
Data model changes
none
Comment | File | Size | Author |
---|
Issue fork drupal-2786735
Show commands
Start within a Git clone of the project using the version control instructions.
Or, if you do not have SSH keys set up on git.drupalcode.org:
Comments
Comment #2
zaporylieComment #3
zaporylieNo longer postponed since #2702227: Image styles for private files are serving the original instead of derivative is in.
Comment #4
zaporylieOnly patch but it would need some tests too.
Comment #5
zaporylieComment #6
claudiu.cristeaWe need tests. Please post also a "test only" patch that proves the bug.
Comment #9
jefuri CreditAttribution: jefuri as a volunteer and at Synetic commentedRerolled it against the 8.5.x branch.
Comment #12
eiriksmHere is a test only patch and a patch with the test.
Did not add an interdiff, since it's literally the same as the test-only patch :)
Comment #14
eiriksmHm, interestingly enough it seems the logic we depend on here, does not work if the file is in the top directory.
This code ends up checking if private:/test_image.png exists.
While if the image was inside of "images" it would end up checking if private://images/test_image.png
This also fails for public files by the way. And is tracked in the issue #2630230: Image effect convert fails when image file is in the public files root.
So not sure if we should postpone until that one is landed?
Comment #16
TrevorBradley CreditAttribution: TrevorBradley commented+1 to patch #12 - which solves my issue over in #3072051: "Convert JPG" Image Effect doesn't work for private files
Comment #18
TrevorBradley CreditAttribution: TrevorBradley commentedHmm, something's not quite right here - patch #12 works (converting PDF to JPG) but the server seems to serve it up as the wrong file type. It displays fine on Chrome on Linux, shows up as a question mark on Safari. I open the myfile.pdf.jpeg image in a new tab, Chrome says it's having difficulty displaying the PDF.
If I move the generated myfile.pdf.jpeg to a public portion of the server, it serves up just fine.
So even with patch #12, there's something wildly wrong about the returned mimetype.
Comment #19
TrevorBradley CreditAttribution: TrevorBradley commentedComment #20
TrevorBradley CreditAttribution: TrevorBradley commentedJust starting to look at this.
I've found the issue. Originally, I was thinking that private file headers were being incorrectly generated by this block of code:
This is using the original $image_url to generate the headers. But if the content type had changed in the derivative form (like PDF to JPEG), $headers would remain an application/pdf. I thought this should be $derivative_url, not $image_url. But $derivative_url isn't a file in the file DB table, so this method of figuring out the mimetype would fail.
What I later noticed is that derivative image's $headers are recalculated just a few lines down in the same function:
The problem with this is that $headers['Content-Type'] and $headers['Content-Length'] are already set, and this += operator on the $headers array is not replacing existing values. As defined on php.net:
The + operator returns the right-hand array appended to the left-hand array; for keys that exist in both arrays, the elements from the left-hand array will be used, and the matching elements from the right-hand array will be ignored.
Instead, this additional block works great:
I'm not sure why the += operator was there. Presumably the headers from the derivative file are really want we really want to serve up here.
Here's a patch that should work much better.
Comment #21
TrevorBradley CreditAttribution: TrevorBradley commentedComment #25
PhilippVerpoortJust to say that I installed the patch mentioned in #20, and it seems to be working on my end! JPEG images in the private file system are converted correctly, and I haven't come across any issues yet.
Hope this gets submitted soon!
Comment #29
Prashant.cThanks to https://www.drupal.org/project/drupal/issues/2786735#comment-13378964 after doing research for 2 hours this patch worked for me on Drupal 9.3.
I was also using "Convert" on all image styles in Drupal and the Private File system and was not able to generate image styles.
Thanks to all the contributers.
Comment #30
bceyssensI can confirm patch #20 works as expected!
Comment #31
immaculatexavier CreditAttribution: immaculatexavier as a volunteer and at Srijan | A Material+ Company for Drupal India Association commentedRerolled patch against #20 for 9.5.
Comment #32
ranjith_kumar_k_u CreditAttribution: ranjith_kumar_k_u at Zyxware Technologies commentedComment #34
bceyssensRerolled patch against #20 for 9.4.3.
Comment #36
johnle CreditAttribution: johnle commentedTested the latest patch on #34, if the private files in in the root, ie private://something.jpg.webp
converts the uri to `private://./something.jpg, which will failed on the invoke call below
Can we make the converted image to remove the period of the path file is in the root something like this?
Comment #37
johnle CreditAttribution: johnle commentedHere is the updated patch to fixed the root path to show up correctly when the converted images are in the root private path.
Comment #38
Anybody#3310963: Wrong file header returned, when converting an image for example to webp seems to have the same root cause, described in #20 so the priority is definitely major here.
Comment #39
ravi.shankar CreditAttribution: ravi.shankar at OpenSense Labs commentedTried to fix the failed test of patch #37.
Comment #41
tbsiqueiraI tested patch #39 and everything is working as expected.
Comment #42
PhilYPatching Drupal 9.4.8 with #39 generates image styles (with WEBP convertion) in private folder.
Thanks
Comment #43
SocialNicheGuru CreditAttribution: SocialNicheGuru commentedI am getting intermittent file not being found after applying the patch. The image will not appear and I cannot refresh the page to bring it back. Instead I have to flush image style cache, drush if my-image-style, then it will be regenerated.
I am not sure why the image url is what it is.
I am using the private file system. I am converting a jpg to webp
Drupal 9.5.8
php8.1
the image url is:
http://mysite/system/files/styles/my-image-style/private/2023-05/myimage.jpg.webp?itok=R0SbukIK
might be helpful: https://www.drupal8.ovh/en/tutoriels/83/get-a-image-file-path-src-on-dru...
The url seems odd.
1. On the sever the converted images are in
mysite/private/files/styles/my-image-style/private/2023-05
So the actual file is here:
private/files/styles/my-image-style/private/2023-05/myimage.jpg.webp.
The url that the site accesses is the public file system mysites/files/styles/ then seems to append a path.
Is this what should be happening with the Convert function?
Comment #47
recrit CreditAttribution: recrit at Phase2 commentedThe test "testImageStylePrivateWithConversion" was failing since the "ImageStyleDownloadController" converted the image URI to "private://./image-test_0.png" instead of "private://image-test_0.png".
Original conversion code in "ImageStyleDownloadController":
To "reduce" the extensions correctly, a new utility function was created in image.module. This may not be the best place for it but I wanted it globally available. The original URI also needed to be reduced in the "image_file_download" hook so that it pass the correct original URI to the file_download hooks.
image.module:
Comment #48
recrit CreditAttribution: recrit at Phase2 commentedComment #49
poker10 CreditAttribution: poker10 at ActivIT s.r.o. commentedThere is a related/duplicate issue: #2786763: Incorrect headers for image derivative if effect "Convert" in use and file stored in private filesystem, which is trying to fix the headers in
ImageStyleDownloadController::deliver()
as well. I think we should remove the fix from this MR, so that we do not combine multiple fixes in one issue (otherwise we need an explanation, why it needs to be fixed together, because it seems to be unrelated to the original issue summary). If needed, this issue can be postponed on that fix. Thanks!Comment #50
recrit CreditAttribution: recrit at Phase2 commented@poker10 - I reverted the file header changes in this issue and created new patches in #2786763: Incorrect headers for image derivative if effect "Convert" in use and file stored in private filesystem.
Comment #51
recrit CreditAttribution: recrit at Phase2 commentedAttached is a static patch of the MR 4772 at commit 5d72a9763e.
Comment #52
recrit CreditAttribution: recrit at Phase2 commentedComment #54
recrit CreditAttribution: recrit at Phase2 commentedComment #55
SocialNicheGuru CreditAttribution: SocialNicheGuru commentedComment #57
smustgrave CreditAttribution: smustgrave at Mobomo commentedRebased the issue to run the test only
Which is good.
Did some manual testing next
Installed Media library
Updated Image bundle image field to use private folder vs public
Setup a private folder
Updated thumbnail image style to convert to JPEG
Created a Media object and the thumbnail failed to generate
Applied MR 4772
Refreshed the page and the thumbnail generated
Hiding patches to make it more clear for committers.
Comment #58
alexpottNice to see some progress on this old bug. I've added some comments to the MR that can be addressed.
Comment #59
recrit CreditAttribution: recrit at Phase2 commentedComment #60
smustgrave CreditAttribution: smustgrave at Mobomo commentedSeems the test-only feature of gitlab doesn't work with javascript tests yet. But ran locally and confirmed the test failure.
Testing this out following the title, confirmed the problem and that the MR does fix it.
Left 1 small nitpicky comment on the MR.
Comment #61
recrit CreditAttribution: recrit at Phase2 commentedComment #62
smustgrave CreditAttribution: smustgrave at Mobomo commentedThanks LGTM!
Comment #63
alexpottWe also need to add a test when someone uploads a file like with additional dots in the name not related to the convert plugin - ie something like:
test.me.jpg
or eventest.jpg.jpg
where the user has unnecessarily doubled the file extension.Comment #64
viniciusrp CreditAttribution: viniciusrp at Open Social commentedI recreate the patch #39 to be compatible with Drupal 10.2.4.
Comment #65
LeDucDuBleuet CreditAttribution: LeDucDuBleuet commentedPatch in comment #64 is working on Drupal 10.2.4 under Open Social 12.2.0.
Thank you.
Comment #66
fskreuz CreditAttribution: fskreuz at Portland Webworks commentedThe patch in #64 contains the fix from https://www.drupal.org/project/drupal/issues/2786763
But according to #49, #50, and #51, 2786763's fix should not be included.
Comment #68
recrit CreditAttribution: recrit at Phase2 commentedComment #69
recrit CreditAttribution: recrit at Phase2 commentedhiding patches that are not from the MR
Comment #70
smustgrave CreditAttribution: smustgrave at Mobomo commentedMR appears to have test failures.
A rebase may solve some of them.
Comment #74
recrit CreditAttribution: recrit at Phase2 commented@smustgrave I created a clean MR !7349 but there are still failures that are not related to the changes in this issue - https://git.drupalcode.org/issue/drupal-2786735/-/pipelines/138852/failures. Failed test appears to be "Drupal\Tests\image\Functional\ImageAdminStylesTest"
I am seeing the same errors on other MRs too - example https://git.drupalcode.org/issue/drupal-2786763/-/pipelines/138806/failures.- this appears to be different.Comment #75
recrit CreditAttribution: recrit at Phase2 commentedThis may be related to this issue since the failure is for a private scheme test "Drupal\Tests\image\Functional\ImageAdminStylesTest:testPreviewImageShowInPrivateScheme"
Comment #76
recrit CreditAttribution: recrit at Phase2 commentedSome more debugging: The changes in #3127116: Image styles - thumbnails are broken in config page when private file system is used to target the sample images is causing this test failure. This change was committed in February 2024 and it removes the scheme when the sample images are requested. See commit fcc1ba6.
Comment #77
recrit CreditAttribution: recrit at Phase2 commentedComment #78
recrit CreditAttribution: recrit at Phase2 commentedCause of test failure:
Failed test:
Drupal\Tests\image\Functional\ImageAdminStylesTest::testPreviewImageShowInPrivateScheme
The following code that was added in #3127116: Image styles - thumbnails are broken in config page when private file system is used must be after the
hook_file_download
has been called since that hook is expected a URI and not a file path.Fix implemented:
- Moved the code that removes the scheme from
$image_uri
to after thehook_file_download
call.- Added a check for
$image_uri !== $sample_image_uri
when checking whether to test the converted image uri.Comment #79
recrit CreditAttribution: recrit at Phase2 commentedComment #80
smustgrave CreditAttribution: smustgrave at Mobomo commentedTest only feature showed the coverage
Issue summary solution appears slightly different then the fix if that could be updated
But solution seems fine and does solve the issue so probably fine to self RTBC after updating the IS.
Comment #81
recrit CreditAttribution: recrit at Phase2 commentedComment #82
recrit CreditAttribution: recrit at Phase2 commentedComment #83
recrit CreditAttribution: recrit at Phase2 commentedthe "Proposed resolution" in the issue summary has been updated to reflect the final solution
Comment #84
alexpottCommitted and pushed 31f9e8a9c6 to 11.x and 36619bd1b4 to 10.3.x and 0299bec90b to 10.2.x. Thanks!