Jump to content

Managing a Page's files by filename


evan
 Share

Recommended Posts

Individually managing files stored in a Page's multi-file File fieldtype by filename wasn't as easy as I hoped it would be.

I was using Dropzone.js to upload files, and wanted to allow the user to delete their uploaded files individually.  Unfortunately, it appears that the filenames are sanitized in a somewhat hidden way.  To match my raw filename with the one stored in PW, I had to to instantiate WireUpload to use its validateFilename method:

$u = new WireUpload('empty');
$sanitizedName = $u->validateFilename($filename);
$file = $myPage->files->get('name='.$sanitizedName );
$myPage->files->delete($file);
$myPage->page->save();

Is there a better way to do this that I'm missing?  It might make sense to have this method exposed as $sanitizer->filename, if not.

As a side note, I also noticed that WireUpload has the method setLowercase(bool), but it doesn't seem to work -- I tried setting it false, but my uploads were still being renamed in lowercase.  Is there some other point further down the line at which it's being modified?

Link to comment
Share on other sites

May I ask why aren't you providing the delete-links through the field itself by looping through the items it contains and using the hash of the files to reference them? In other words, why do you need to work with the original filenames? Just to make my point clear 

// Generate delete-links

foreach($myPage->files as $file)
{
  echo "<a href='{$myPage->url}?action=deleteFile&hash={$file->hash}'>".htmlentities($file->name)."</a><br />\n";
}

// Then on your controller you can retrieve the file with

$file = $myPage->files->get("hash=".$sanitizer->selectorValue($input->get->hash));
$myPage->files->delete($file);
$myPage->save();

In the actual implementation you should of course validate the request and also use POST instead of GET, but my point was to just demonstrate the usage of the hash.

  • Like 1
Link to comment
Share on other sites

Interesting, thanks!  Didn't know about the hash property, I would much rather use that.  Is that documented somewhere?

Currently my JS uploads each file with individual AJAX requests, and generates a file UI element and delete button.  Basically I need a way to keep my UI in sync with what's actually uploaded.  Ideally my AJAX endpoint could just respond with the individual file hash and I could match it with the UI element.  So I guess my question is, can I access or generate the file hash on an individual per-request basis?

Link to comment
Share on other sites

Figured it out...not really complicated, I think I was just getting sleepy/myopic:

// Instantiate the class and give it the name of the HTML field
$u = new WireUpload('file');

if (count($u->execute())) {
    foreach($u->execute() as $filename) {
        $p->files->add($filename);
        echo $p->files->last()->hash; // Returns the hash
    }
    $p->save();
} else {
    return false;
}

And on the JS side, I set an attribute of UI element to the response upon successful upload.

Link to comment
Share on other sites

Interesting, thanks!  Didn't know about the hash property, I would much rather use that.  Is that documented somewhere?

Hey! Sorry for the late response - I've been fairly busy lately. First of all, no, I don't think it's documented anywhere else but here: https://github.com/ryancramerdesign/ProcessWire/blob/dev/wire/core/Pagefile.php#L441-L444

The reason for that probably is because it's very rarely needed.

Figured it out...not really complicated

I'm glad you worked it out. However I would like to mention that you should rather do 

// Process the upload only once
$filenames = $u->execute();

if(count($filenames)) {
  // If there's always just one file, no looping needed
  $pagefile = new Pagefile($p->files, $filenames[0]);
  $p->files->add($pagefile);
  $p->save();

  echo $pagefile->hash;
}

You don't need to use the last() -trick - internally ProcessWire is changing the string you are passing to add() to a Pagefile object anyway.

Also I assume you haven't enabled zip-file extraction? Because then you should handle all the files returned from the execute() - then you would also have to separate the hashes with something you can parse.

  • Like 1
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...