Skip to main content

This site requires you to update your browser. Your browsing experience maybe affected by not having the most up to date version.

We've moved the forum!

Please use forum.silverstripe.org for any new questions (announcement).
The forum archive will stick around, but will be read only.

You can also use our Slack channel or StackOverflow to ask for help.
Check out our community overview for more options to contribute.

Archive /

Our old forums are still available as a read-only archive.

Moderators: martimiz, Sean, Ed, biapar, Willr, Ingo

How I managed to upload ImageField, SimpleImageField and FileIFrameField into custom folders


Go to End


5 Posts   4343 Views

Avatar
typopunk

Community Member, 6 Posts

4 November 2008 at 8:49am

Edited: 04/11/2008 8:58am

For a site project I wanted to upload images of different sections
into different folders - like forum avatars into "Avatars" and banner
images into "Banners",... In theory it should be possible to define
a custom upload directory for these fields by a setting like

new ImageField("Avatar","Your Avatar",null,null,null, "Avatars")
new SimpleImageField("Banner","Banner Image",null,null,null, "Banners")
new FileIFrameField("Document","Your Document",null,null,null, "Documents")

Actually this doesn't seem to work (versions 2.2.2 and 2.2.3). So here is how
I solved the problem. 4 files need to be adjusted - add the blue parts to
the scripts:

--- sapphire/core/model/Image.php

code starts in line 677:

// Assuming its a decendant of File
$image = new $imageClass();
$folderName=$data['folderName'];
if ($folderName=="" or eregi("\.\.|\:",$folderName))
  $folderName="Uploads";  
$image->loadUploaded($data['Upload'], $folderName);
$owner->$fieldName = $image->ID;

code starts in line 538:

  $fromYourPC = _t('ImageUploader.FROMCOMPUTER', "From your computer");
  $fromTheDB = _t('ImageUploader.FROMFILESTORE', "From the file store");
}
$folderName=urldecode($_GET["folderName"]);
return new Form(
  $this, 
  'EditImageForm', 
  new FieldSet(
    new HiddenField("Class", null, $this->urlParams['Class']),
    new HiddenField("ID", null, $this->urlParams['ID']),
    new HiddenField("Field", null, $this->urlParams['Field']),
    new HiddenField("folderName", null, $folderName),
    new HeaderField($title),
    new SelectionGroup("ImageSource", array(

code starts in line 114:

function loadUploaded($tmpFile, $folderName = 'Uploads') {
  if(parent::loadUploaded($tmpFile, $folderName)) {
    $this->deleteFormattedImages();
    return true;
  }
}

--- sapphire/forms/ImageField.php

code starts in line 31:

  $parentClass = $data->class;
  $parentField = $this->name;
  $iframe = "<iframe name=\"{$this->name}_iframe\"
    src=\"images/iframe/$parentClass/$parentID/$parentField/?folderName=".urlencode($this->folderName)."\"
    style=\"height: 152px; width: 525px; border: none;\" frameborder=\"0\"></iframe>";
  return $iframe . $hiddenField;
} else {

--- sapphire/forms/FileIFrameField.php

code starts in line 24:

  $parentID = $data->ID;
  $parentField = $this->name;
  $iframe = "<iframe name=\"{$this->name}_iframe\"
    src=\"images/iframe/$parentClass/$parentID/$parentField/?folderName=".urlencode($this->folderName)."\"
    style=\"height: 152px; width: 600px; border-style: none;\"></iframe>";
  return $iframe . $hiddenField;
} else {

--- sapphire/forms/SimpleImageField.php

code starts in line 14:

function saveInto(DataObject $record) {
  $fieldName = $this->name;
  if($record) $imageField = $record->$fieldName();
  if($imageField) $imageField->loadUploaded($this->value,$this->folderName);
  $idFieldName = $fieldName . 'ID';
  if($record) $record->$idFieldName = $imageField->ID;
}

That's it. It also works for nested folders like "Uploads/News". This might
not be the best solution and it doesn't solve the problem for all upload
fields but it works for the fields that I use in my project and maybe it
covers your needs as well... :-)
Cheers

Avatar
Liam

Community Member, 470 Posts

4 November 2008 at 3:58pm

Nice work. Is there a ticket for this open already? This problem obviously needs to be fixed up.

Avatar
Sean

Forum Moderator, 922 Posts

4 November 2008 at 4:03pm

Edited: 04/11/2008 4:04pm

Hi typopunk.

Thanks for the hard work getting that done. We'd love to see this get included in the main code base, so it would be great if you could open a new ticket with your patch on our open source tracker.

http://open.silverstripe.com/newticket

You'll have to create a new account on the site if you haven't already. You can do this by visiting http://open.silverstripe.com/register.

Then choose "Patch" for the Type field when creating the ticket, along with your changes as the description in the ticket.

Thanks!

Sean

Avatar
Ingo

Forum Moderator, 801 Posts

12 November 2008 at 11:53am

The problem with specifying foldernames in user-submitted data is security - its very easy to open a "directory traversal" hole. Allowing only folders relative to assets would be a good start, with the help of dirname() and realpath(). Either way, needs rigorous unit tests before any patch can be merged back.

Avatar
typopunk

Community Member, 6 Posts

13 November 2008 at 1:27am

Edited: 13/11/2008 1:28am

That's why I added the line
if ... eregi("\.\.|\:",$folderName))

This should keep all uploads in the assets folder. Maybe this check is too simple. Checking for "^\\" or for existing upload folders might add some more security to it all...

Well, as said "this might not be the best solution and it doesn't solve the problem for all upload fields". I don't think the final/official version should work that way but it's an easy solution to get that function running. As there are so many unanswered requests on this forum related to that topic this now might be something people can work with (use/test/rewrite/extend it) until there is an offical solution for that issue.
Cheers