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.

General Questions /

General questions about getting started with SilverStripe that don't fit in any of the categories above.

Moderators: martimiz, Sean, biapar, Willr, Ingo, swaiba, simon_w

Help with add_extension()/renaming images on upload


Go to End
Reply


9 Posts   1834 Views

Avatar
kinglozzer

Community Member, 166 Posts

9 July 2012 at 10:03pm

Edited: 09/07/2012 10:05pm

Hi guys & girls,

I'll try to keep this post as short as possible or it could go on for ages! I have a class 'Client' which extends DataObject. I have an UploadField (I'm running SS3) with only image file extensions allowed. I now want to rename each image as it is uploaded to be a random string.

I've written a class ('RenameImage') which extends DataExtension to do this, but I can't get it to do anything. I tried adding this to my 'Client' class:

Object::add_extension('Image', 'RenameImage');

but I don't think this will work as my 'Image' field is in fact an UploadField (I've also tried UploadField as the first argument anyway). I also tried this:

public static $extensions = array('RenameImage');


but again had no joy. I'm a bit stumped for ideas :/

Anyone done anything similar or can point me in the right direction?

Thanks

Avatar
copernican

Community Member, 189 Posts

9 July 2012 at 11:23pm

Edited: 09/07/2012 11:23pm

You could try extending UploadField instead of DataExtension ie

class MyUploadField extends UploadField {

}

and then check UploadField and see which function is responsible for naming the file on upload and customize it in your new class. Finally, in your client class

public function getCMSFields(){
$fields->addFieldToTab('Root.Main', new MyUploadField('Image','Image'));
}

Avatar
kinglozzer

Community Member, 166 Posts

10 July 2012 at 12:23am

Edited: 10/07/2012 3:08am

Thanks for the idea, I'll take a look into it.

EDIT:

Can't seem to find any docs on UploadField at the moment, I found this on Github:
[url]https://github.com/silverstripe/sapphire/blob/master/forms/UploadField.php[/url]
but, unless I'm missing something, there's nothing in there for doing stuff with filenames :(

Cheers

Avatar
copernican

Community Member, 189 Posts

10 July 2012 at 1:49pm

Try looking at the function on line #432 - [url]https://github.com/silverstripe/sapphire/blob/master/forms/UploadField.php#L432[/url]

It looks like the name might be set there but I'm not sure without trying. If I get a chance tomorrow to look at this more closely I will. Let me know if you have make progress though.

Avatar
kinglozzer

Community Member, 166 Posts

10 July 2012 at 8:05pm

Edited: 10/07/2012 8:41pm

Had a look through there, could only find getName, no setter.

http://api.silverstripe.org/3.0/framework/filesystem/File.html#methodsetFilename

This one might be the one I'm looking for, will have a play around with it

Thanks

Edit or perhaps it isn't the one I was looking for!

Second edit

I had a go at your initial idea of extending UploadField, as I found this:
[url]http://api.silverstripe.org/3.0/framework/forms/UploadField.html[/url]

It's done something, as now when I click to upload a file I get this: SyntaxError: JSON.parse: unexpected character

What I did was literally copy and paste the upload function from the github page, and replace "'name' => $tmpfile['name']" with "'name' => doRename($tmpfile['name'])" - where doRename is a function that does hash_hmac() on the name with the client's individual key.

Will start debugging, thanks for the help so far!

So close!

It's now renaming the file on the form field, but not actually renaming the file itself :(

I needed to add the function to both $return arrays, one near the beginning of the function and one near the end. I guess I now just need to figure out at which point it's actually writing the file and intercept it before then.

Cheers

Avatar
copernican

Community Member, 189 Posts

13 July 2012 at 12:18am

Hey kinglozzer

Sorry for the late reply but I spent sometime on this last night. Like you I can get the filename changed on the form field and I managed to change the Name in the database but I could not change the actually file name.

I'm thinking this is more challenging then I initially thought and we may not be looking in the right place. I'm interesting in solving this problem though.

Maybe somebody else has an idea or suggestion on where we could look?

Avatar
kinglozzer

Community Member, 166 Posts

13 July 2012 at 12:41am

Edited: 13/07/2012 12:43am

Hey IOTI,

I did actually get this working, but completely forgot to post back!

The final bits I replaced were just before and after this code:

// Get the uploaded file into a new file object.
try {
   $this->upload->loadIntoFile($tmpfile, $fileObject, $this->folderName);
} catch (Exception $e) {
// we shouldn't get an error here, but just in case
   $return['error'] = $e->getMessage();
}

Just before (immediately before the 'try' block), I added this:

$ext = array_reverse(explode('.',$tmpfile['name'])); // explode filename into array, reverse array, first array key will then be file extension
$tmpfile['name'] = hash_hmac('sha256', $tmpfile['name'], '12345') . '.' . $ext[0];

(though obviously I'd replace the hmac with something a bit better!)

I then edited the last $return array to look like this (though on reflection, I don't think I needed to):

$return = array_merge($return, array(
   'id' => $file->ID,
   'name' => $tmpfile['name'],
   'url' => $file->getURL(),
   'thumbnail_url' => $file->UploadFieldThumbnailURL,
   'edit_url' => $file->UploadFieldEditLink,
   'size' => $file->getAbsoluteSize(),
   'buttons' => $file->UploadFieldFileButtons
));

Here is my final upload() function (which is only doing hash_hmac('sha265', $filename, '12345') at the moment)

public function upload(SS_HTTPRequest $request) {
   if($this->isDisabled() || $this->isReadonly()) return $this->httpError(403);

      // Protect against CSRF on destructive action
      $token = $this->getForm()->getSecurityToken();
      if(!$token->checkRequest($request)) return $this->httpError(400);

      $name = $this->getName();
      $tmpfile = $request->postVar($name);
      $record = $this->getRecord();

      // Check if the file has been uploaded into the temporary storage.
      if (!$tmpfile) {
         $return = array('error' => _t('UploadField.FIELDNOTSET', 'File information not found'));
      } else {
         $return = array(
            'name' => hash_hmac('sha256', $tmpfile['name'], '12345'),
            'size' => $tmpfile['size'],
            'type' => $tmpfile['type'],
            'error' => $tmpfile['error']
         );
      }

      // Check for constraints on the record to which the file will be attached.
      if (!$return['error'] && $this->relationAutoSetting && $record && $record->exists()) {
         $tooManyFiles = false;
         // Some relationships allow many files to be attached.
         if ($this->getConfig('allowedMaxFileNumber') && ($record->has_many($name) || $record->many_many($name))) {
            if(!$record->isInDB()) $record->write();
            $tooManyFiles = $record->{$name}()->count() >= $this->getConfig('allowedMaxFileNumber');
         // has_one only allows one file at any given time.
         } elseif($record->has_one($name)) {
            $tooManyFiles = $record->{$name}() && $record->{$name}()->exists();
         }

         // Report the constraint violation.
         if ($tooManyFiles) {
            if(!$this->getConfig('allowedMaxFileNumber')) $this->setConfig('allowedMaxFileNumber', 1);
            $return['error'] = _t(
               'UploadField.MAXNUMBEROFFILES',
               'Max number of {count} file(s) exceeded.',
               array('count' => $this->getConfig('allowedMaxFileNumber'))
            );
         }
      }

      // Process the uploaded file
      if (!$return['error']) {
         $fileObject = null;

         if ($this->relationAutoSetting) {
            // Search for relations that can hold the uploaded files.
            if ($relationClass = $this->getRelationAutosetClass()) {
               // Create new object explicitly. Otherwise rely on Upload::load to choose the class.
               $fileObject = Object::create($relationClass);
            }
         }
         $ext = array_reverse(explode('.',$tmpfile['name']));
         $tmpfile['name'] = hash_hmac('sha256', $tmpfile['name'], '12345') . '.' . $ext[0];

         // Get the uploaded file into a new file object.
         try {
            $this->upload->loadIntoFile($tmpfile, $fileObject, $this->folderName);
         } catch (Exception $e) {
            // we shouldn't get an error here, but just in case
            $return['error'] = $e->getMessage();
         }

         if (!$return['error']) {
            if ($this->upload->isError()) {
               $return['error'] = implode(' '.PHP_EOL, $this->upload->getErrors());
            } else {
               $file = $this->upload->getFile();

               // Attach the file to the related record.
               if ($this->relationAutoSetting) {
                  $this->attachFile($file);
               }

               // Collect all output data.
               $file = $this->customiseFile($file);
               $return = array_merge($return, array(
                  'id' => $file->ID,
                  'name' => $tmpfile['name'],
                  'url' => $file->getURL(),
                  'thumbnail_url' => $file->UploadFieldThumbnailURL,
                  'edit_url' => $file->UploadFieldEditLink,
                  'size' => $file->getAbsoluteSize(),
                  'buttons' => $file->UploadFieldFileButtons
               ));
            }
         }
      }
      $response = new SS_HTTPResponse(Convert::raw2json(array($return)));
      $response->addHeader('Content-Type', 'text/plain');
      return $response;
   }

Avatar
copernican

Community Member, 189 Posts

13 July 2012 at 12:46am

Ahh so it was the $tmpfile. Good job!

I kept trying to work with $fileObject which was only modifying the database fields. Now I'll know for the future if I ever have to modify my file uploads :)

Go to Top