Robin S Posted September 1, 2023 Share Posted September 1, 2023 ProcessWire automatically sanitises the names of files that are uploaded to a Files field. For example, a file named "Café meals under $30.pdf" will become "cafe_meals_under_30.pdf" after it is uploaded. Since v3.0.212 ProcessWire stores the original unsanitised filename of each uploaded file, and this is accessible via $pagefile->uploadNamehttps://processwire.com/blog/posts/pw-3.0.226/#file-and-image-improvementshttps://processwire.com/api/ref/pagefile/upload-name/ So if I have a field named "files" on my page and I want to provide downloads of the files with their original filename I can output links like this: $out = ''; foreach($page->files as $file) { // uploadName is entity-encoded when output formatting is on $original_name_unencoded = html_entity_decode($file->uploadName); $out .= "<p><a href='$file->url' download='$original_name_unencoded'>$file->uploadName</a></p>"; } echo $out; So far, so good. But I want my site visitors to be able to view PDFs in the browser rather than force a download, yet if they do download them after viewing them I want the files to get the original filename. For this I can use a URL hook to deliver the PDF via PHP rather than directly loading the file. In /site/ready.php: $wire->addHook('/view-pdf/{page_id}/{filename}', function($event) { $id = (int) $event->page_id; $filename = $event->wire()->sanitizer->text($event->filename); if(!$id || !$filename) return 'Invalid request'; // Get the Pagefile via PagefilesManager $pm = $event->wire()->pages->get($id)->filesManager; $file = $pm->getFile($filename); if(!$file) return 'File not found'; // uploadName is entity-encoded when output formatting is on $original_name_unencoded = html_entity_decode($file->uploadName); // Set headers and output the PDF content header("Content-Type: application/pdf"); header("Content-Disposition: inline; filename=$original_name_unencoded"); header("Content-Transfer-Encoding: binary"); header("Accept-Ranges: bytes"); @readfile($file->filename); return true; }); In the page template file: $out = ''; foreach($page->files as $file) { if($file->ext === 'pdf') { // Deliver PDF files via the URL hook $out .= "<p><a href='/view-pdf/$page->id/$file->basename'>$file->uploadName</a></p>"; } else { // Other files receive a download attribute // uploadName is entity-encoded when output formatting is on $original_name_unencoded = html_entity_decode($file->uploadName); $out .= "<p><a href='$file->url' download='$original_name_unencoded'>$file->uploadName</a></p>"; } } echo $out; 14 1 Link to comment Share on other sites More sharing options...
Jim Bailie Posted September 1, 2023 Share Posted September 1, 2023 @Robin S This is really neat the more I look at it. I wonder if I can drop the upload name into a template field so the admins have a visual frame of reference on the admin screen. Will try this out. 1 Link to comment Share on other sites More sharing options...
Robin S Posted September 1, 2023 Author Share Posted September 1, 2023 1 hour ago, Jim Bailie said: I wonder if I can drop the upload name into a template field so the admins have a visual frame of reference on the admin screen. The upload name is shown in a tooltip when you hover on the file icon in the inputfield: If you want something that's always visible you could hook into the inputfield rendering: // Display upload name in InputfieldFile $wire->addHookAfter('InputfieldFile::renderItem', function(HookEvent $event) { /** @var Pagefile $pagefile */ $pagefile = $event->arguments(0); $event->return = "<p class='upload-name'>$pagefile->uploadName</p>" . $event->return; }); And then style it with some custom admin CSS: .InputfieldFileItem .upload-name { color:white; line-height:1.33; padding:6px 10px; margin:0; background-color:#606060; } There are several ways you can add custom CSS to the PW admin - here is one: // Add custom CSS to admin $wire->addHookAfter('AdminTheme::getExtraMarkup', function(HookEvent $event) { $config = $event->wire()->config; $parts = $event->return; $css_url = $config->urls->templates . 'admin-assets/admin-custom.css'; $modified = filemtime(rtrim($config->paths->root, '/') . $css_url); $parts['head'] .= "<link rel='stylesheet' href='$css_url?m=$modified'>"; $event->return = $parts; }); Result: 5 1 Link to comment Share on other sites More sharing options...
Jim Bailie Posted September 2, 2023 Share Posted September 2, 2023 Hmm. Wow. This is great! I've got some work to do this weekend. I'll be testing this asap, but I will ask you in advance: Do you think the replace/rename module will preserve the upload name after replacement? Edit BTW, PW 3.0.226 - I'm not seeing the uploadName in the tooltip. The upload name was "conservation_station_tester2$$$.pdf" (see below) Good News -- I AM seeing upload names when looping via the API for files that have been manually uploaded Bad News -- Rename/Replace module DOES REMOVE the original upload name and replaces with the sanitized version. Bad News -- Uploading a file via the API places the SANITIZED value into uploadName I'd be grateful for any more insights or ideas you may have on how to proceed. Thanks again!! Link to comment Share on other sites More sharing options...
bernhard Posted September 3, 2023 Share Posted September 3, 2023 12 hours ago, Jim Bailie said: Bad News -- Uploading a file via the API places the SANITIZED value into uploadName How did you upload the file via api? Can you give a quick example to reproduce the issue? If you do that and post it to this issue and mention Ryan I guess chances are high that he will fix this quickly. At least I suggested the uploadName feature on Feb 16 and he implemented it on Feb 17 ? Maybe he just didn't think of API uploads. 2 Link to comment Share on other sites More sharing options...
Jim Bailie Posted September 3, 2023 Share Posted September 3, 2023 8 hours ago, bernhard said: How did you upload the file via api? Can you give a quick example to reproduce the issue? If you do that and post it to this issue and mention Ryan I guess chances are high that he will fix this quickly. At least I suggested the uploadName feature on Feb 16 and he implemented it on Feb 17 ? Maybe he just didn't think of API uploads. @bernhard Here's the test code. Pretty simple; it uploads the file fine with the sanitized file name. When I loop through after, it outputs the file name and upload name which are the same. $path = "/var/www/dvmrebuild/storage/"; $fileName = "My_Test_File3$$$.pdf"; $p = $pages->get(1214); $p->of(false); $p->venue_files->add($path . $fileName); $p->save('venue_files'); foreach ($p->venue_files AS $vfile) { echo $vfile->name . ' => ' . html_entity_decode($vfile->uploadName) . '<br>'; } # Outputs: # my_test_file3.pdf => my_test_file3.pdf Link to comment Share on other sites More sharing options...
bernhard Posted September 3, 2023 Share Posted September 3, 2023 I've added your example to the mentioned issue: https://github.com/processwire/processwire-requests/issues/56#issuecomment-1704363956 1 1 Link to comment Share on other sites More sharing options...
Jim Bailie Posted September 3, 2023 Share Posted September 3, 2023 @bernhard Thanks for doing that. I'll dig up my github info and give a thumbs up. In the meantime, I'll try to cobble something together with some file template fields and some of @Robin S's examples above and in another post. I also wonder if the fact that the API does not preserve the uploadName cascades down to the fact that the uploadName is not set in Robin's file rename/replace module. Link to comment Share on other sites More sharing options...
bernhard Posted September 3, 2023 Share Posted September 3, 2023 I've just tested this: $home->of(false); $home->rockfrontend_favicon->add(__DIR__ . "/Test$$$.png"); $home->save(); bd($home->rockfrontend_favicon->uploadName()); Which resulted in this: So that confirms that uploadName() does not work for API added files. 1 Link to comment Share on other sites More sharing options...
Robin S Posted September 4, 2023 Author Share Posted September 4, 2023 @Jim Bailie, I've released v0.2.0 of Files Rename Replace which will now retain the uploadName property when a file is replaced. 1 Link to comment Share on other sites More sharing options...
Jim Bailie Posted September 4, 2023 Share Posted September 4, 2023 @Robin S It works! I was studying your module to see if I could start digging into it, but right now it might be one pay grade above where I'm currently at; though I feel like I'm catching up. Thank you again. And just FYI, note the placement of the rename/replace link: I'm on Windows, Firefox, Monitor at standard 1920 x Whatever Link to comment Share on other sites More sharing options...
Jim Bailie Posted September 5, 2023 Share Posted September 5, 2023 Update: Somehow by looking at Pagefile.php I was able to figure out how to set the uploadName via the API. It seems to work... $path = "/var/www/dvmrebuild/storage/"; $fileName = "My_Test_File4$$$.pdf"; $p = $pages->get(1214); $p->of(false); $p->venue_files->add($path . $fileName); $p->save('venue_files'); $p->of(false); $vfile = $p->venue_files->last(); $vfile->file_upload_date = date('Y-m-d'); $vfile->file_title = 'My Test File 4'; $vfile->file_original_name = $fileName; $vfile->filedata('uploadName', htmlentities($fileName)); $p->save('venue_files'); Link to comment Share on other sites More sharing options...
Robin S Posted September 5, 2023 Author Share Posted September 5, 2023 @Jim Bailie, I updated the styling in a new release of the module. 1 minute ago, Jim Bailie said: $vfile->filedata('uploadName', htmlentities($fileName)); You don't want to encode entities when you set the value or you'll get a double-encoded string when you get uploadName when output formatting is on. 1 Link to comment Share on other sites More sharing options...
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now