It seems impossible to use a contrib created stream wrapper without breaking image styles, despite there being code to account for stream wrappers when creating derivative image paths and urls.

For example:

function image_style_url($style_name, $path) {
  $scheme = file_uri_scheme($path);
  if ($scheme === 'private') {
    $target = file_uri_target($path);
    $url = url('system/files/styles/' . $style_name . '/' . $scheme . '/' . $target, array('absolute' => TRUE));
  }
  else {
    $destination = image_style_path($style_name, $path);
    $url = url(file_stream_wrapper_get_instance_by_scheme($scheme)->getDirectoryPath() . '/' . file_uri_target($destination), array('absolute' => TRUE));
  }
  return $url;
}

It seems strange that the private file stream can have a control statement here, but not allow other contrib streams to inject themselves. The problem this creates is that there's no way of allowing images to be generated and then passed off to the end point of the contrib stream before a url is generated. e.g. for an s3 stream wrapper the following url is generated:
http://mybucket.s3.amazonaws.com/styles/thumbnail/s3/field/image/image.jpg
But when this url is used, the image will obviously not be generated. (Not sure why the scheme is being injected into the url path either there, as an aside.)

Comments

justafish’s picture

Version: 7.0-rc1 » 7.x-dev
EvanDonovan’s picture

Priority: Critical » Major

Not sure if this is actually critical, since it is one subsystem, and a more uncommon (but still important) case. Moving to major priority.

justafish’s picture

Status: Active » Needs review
StatusFileSize
new1.26 KB

This works with other stream wrappers if the image module is switched from checking whether a scheme is private to whether a scheme is not public.

Status: Needs review » Needs work

The last submitted patch, image.module.patch, failed testing.

justafish’s picture

StatusFileSize
new1.66 KB

try again...

justafish’s picture

Status: Needs work » Needs review
justafish’s picture

The above patch will cause any files that aren't public:// to be delivered through drupal rather than directly, allowing all schemes to work.
you can test it out if you have an S3 account with this module by the way:
http://drupal.org/project/media_amazon

tstoeckler’s picture

The comment doesn't wrap at 80 chars.
I'm leaving at "needs review" for reviews on the actual patch/implementation.

justafish’s picture

StatusFileSize
new1.51 KB

Fixed comment wrap

eojthebrave’s picture

I don't have a way to test this with an S3 account or other similar stream wrapper, however this looks like a good idea to me and I like the approach taken here.

We don't want to assume that people are only every going to use private:// and public:// for displaying images on their site and since public:// is really the anomaly here basing the logic around checking for public makes the most sense and gives us the most flexibility.

justafish’s picture

Thanks for having a look at it eojthebrave.

Is anyone with an S3 account able to test this? I'd like to get this committed!

pwolanin’s picture

Status: Needs review » Needs work

No, I don't think this is the right approach.

We should have some other flag on a stream wrapper to indicate if it's public or private - we can have multiple public or private schemes that are local or remote - the 2 core provides must not be hard-coded this way.

Possibly we should define additional constants in stream_wrappers.inc?

aaron’s picture

I'm running into a similar problem. I also agree with #12.

An additional thing I've uncovered is that if you send a path to a direct file, it chokes as well; for instance, if you try image_style_url('large', 'modules/image/sample.png'), giving an error: Fatal error: Call to a member function getDirectoryPath() on a non-object in /var/www/d7/modules/image/image.module on line 808. If nothing else, we should change the documentation to reflect the reality, which is that it's not a $path it's looking for, but rather a $uri to a public:// or private:// stream.

recrit’s picture

Adding a private/public constant to the 'type' constants could overload its definition. A separate parameter, 'private' => TRUE, could be a better route.

Having this definition is essential to set up a flexible private file system that allows alternate schemes to be selected but ensures that they are implementing a private scheme.

sun’s picture

Title: Switching file storage to anything other than public/private breaks styles » Switching file storage to anything other than public/private breaks image styles
Version: 7.x-dev » 8.x-dev
Issue tags: +Needs backport to D7
jbrown’s picture

Status: Needs work » Closed (duplicate)
Issue tags: -Needs backport to D7

This has been fixed in 7 and 8.

Anonymous’s picture

Status: Closed (duplicate) » Active

@#17 Has it been fixed in D7? The patch from #9 makes sense, but is not in latest Drupal 7 release.

My reason for re-opening this is trying to use the Cloud Files module. The patch from #9 would help solve the problem of calling remote "file styles" by running them through system/files/styles.

xjm’s picture

Priority: Major » Normal

The patch in #9 was not applied to D7 or D8, but the main issue was apparently fixed in another issue. A link to that other issue would probably be helpful. :)

tms320c’s picture

I have reproduced this problem with trivial stream wrapper that is public: copy/paste but handles different directory (also inside drupal root). It seems to me that the problem is in image_menu() hook. Namely,

$directory_path = file_stream_wrapper_get_instance_by_scheme('public')->getDirectoryPath();
$items[$directory_path . '/styles/%image_style'] = array( ....

Thus, if the file storage is neither public, nor private Drupal won't call image_style_deliver() callback. After I have implemented similar callback in my module the styles start work as they are supposed to. The callback in my module is just a wrapper around image_style_deliver, without any extra processing:

    $directory_path = file_stream_wrapper_get_instance_by_scheme('myscheme')->getDirectoryPath();
    $items[$directory_path . '/styles/%image_style'] = array(
        'title' => 'Generate image style',
        'page callback' => 'mymodule_image_style_deliver',
        'page arguments' => array(count(explode('/', $directory_path)) + 1),

.............

function mymodule_image_style_deliver($style, $scheme) {
    if(function_exists('image_style_deliver')) {
        $args = func_get_args();
        array_shift($args);
        array_shift($args);
        $target = implode('/', $args);
        image_style_deliver($style, $scheme, $target);
    }
}

Probably, it is necessary to use image field approach (see image.field.inc image_field_settings_form() - I use Drupal 7.12) and create routes for all appropriate file storages. For example,

  foreach (file_get_stream_wrappers(STREAM_WRAPPERS_WRITE_VISIBLE) as $scheme => $stream_wrapper) {
    $directory_path = file_stream_wrapper_get_instance_by_scheme($scheme)->getDirectoryPath();
    $items[$directory_path . '/styles/%image_style'] = array( ....
  }

Optionally, add this info to the documentation and warn stream wrappers developers to implement the menu.

Regarding remote file storages. I believe image styles functionality will work correctly if the wrappers correctly implement directory creation functionality. Of course, it may be impossible for some storages and a kind of creative simulation may be realized.

xjm’s picture

Can someone document the steps to reproduce this based on #20, or create an automated test demonstrating the bug?

tms320c’s picture

  1. Install a module that implements stream wrapper with type STREAM_WRAPPERS_WRITE_VISIBLE, and uses directory path that is not equal to public stream directory path (see sample wrapper below)
  2. Attach field_image to an entity that is fieldable and has configuration form
  3. Configure field instance to use this new wrapper (you sould see it in the radio button list)
  4. Go to entity form and upload an image

You will see broken thumbnail immediately, and you can check that the image is where it should be (in sites/all/files/samle), but there is no appropriate directories below it.

// In .inc file
class SampleLocalStreamWrapper extends DrupalLocalStreamWrapper {

    public function getExternalUrl()
    {
        $path = str_replace('\\', '/', $this->getTarget());
        return $GLOBALS['base_url'] . '/' . self::getDirectoryPath() . '/' . drupal_encode_path($path);
    }

    function getDirectoryPath()
    {
        $path = 'sites/all/files/sample';
        return trim($path, '/');
    }
}

// And in a module
function sample_stream_wrappers() {
    return array(
        'sample' => array(
            'name' => t('Sample Files'),
            'class' => 'SampleLocalStreamWrapper',
            'description' => t('Sample local files.'),
            'type' => STREAM_WRAPPERS_WRITE_VISIBLE
        )
    );
}
xjm’s picture

Thanks @tms320c.

Now let's roll #22 into an automated test demonstrating the bug. Create a hidden test module from the snippets above, and then add a test class that installs that test module and follows the STR.

xjm’s picture

Issue tags: +Novice
eojthebrave’s picture

This could probably just go in to the image_module_test module that's in modules/image/tests/ instead of having to create a new module.

tim.plunkett’s picture

Status: Active » Needs review
StatusFileSize
new2.27 KB

Alright, here's a test. Are we sure this was fixed?
The files are correctly uploaded to the stream wrapper's directory, but the image style is not created.

tim.plunkett’s picture

Since the OP and last patch, image_style_url has changed, the stream wrappers have gone PSR-0, and the default value for 'type' is hook_stream_wrappers is STREAM_WRAPPERS_NORMAL which is identical to STREAM_WRAPPERS_WRITE_VISIBLE.

Status: Needs review » Needs work

The last submitted patch, drupal-987846-26.patch, failed testing.

andypost’s picture

Also setting $config_directory_name in settings.php does not work when path is absolute. Probably there's some issue about

xjm’s picture

Issue tags: -Needs tests, -Novice

Thanks @tim.plunkett.

benshell’s picture

I've created a related patch where I took a different approach to figuring out where to store image derivatives: #1821166: Support image style derivatives using a different file scheme than the original image

claudiu.cristea’s picture

@tim.plunkett, Reading you comment from #27 I understand that this patch is no more actual. Should I close the issue or move it back to D7?

Version: 8.0.x-dev » 8.1.x-dev

Drupal 8.0.6 was released on April 6 and is the final bugfix release for the Drupal 8.0.x series. Drupal 8.0.x will not receive any further development aside from security fixes. Drupal 8.1.0-rc1 is now available and sites should prepare to update to 8.1.0.

Bug reports should be targeted against the 8.1.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.2.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

claudiu.cristea’s picture

Version: 8.1.x-dev » 7.x-dev
Issue summary: View changes
Issue tags: -Needs backport to D7
Related issues: +#2770761: Derivatives should not be created on read-only stream wrappers

This is not an issue in D8. Drupal 8 is able to handle sources passed as custom stream wrappers but is buggy when it comes to to read-only stream wrappers. For the D8 read-only wrappers I've opened #2770761: Derivatives should not be created on read-only stream wrappers. This I will move back to Drupal 7 to be fixed there, if case.

Status: Needs work » Closed (outdated)

Automatically closed because Drupal 7 security and bugfix support has ended as of 5 January 2025. If the issue verifiably applies to later versions, please reopen with details and update the version.