Original filename in preview and download, but custom stored filename in FileUpload

I basically want to change the name of the file that is being downloaded. But I cant find the function that does that. My suspicions say that its only done by JS. But if that is the case then how can I change the name of the file being downloaded? (I dont want to change anything in the database). Even better, I want to show the original name of the file in the preview, but not when viewing on another tab (I have secure storage via controller)
30 Replies
DarkKnight
DarkKnight7mo ago
WHen a file is uploaded the name of it is changed to a hash string. For example this function. The url works fine, but if I change the "name" to another string, then it shows the hash string, and not the string that I gave it. ANy ideas why?
$this->getUploadedFileUsing(static function (BaseFileUpload $component, string $file, string|array|null $storedFileNames): ?array {
$storage = Storage::disk('.....');
// dd($storedFileNames);

$shouldFetchFileInformation = $component->shouldFetchFileInformation();

if ($shouldFetchFileInformation) {
try {
if (!$storage->exists($file)) {
return null;
}
} catch (UnableToCheckFileExistence $exception) {
return null;
}
}

$url = null;

if ($component->getVisibility() === 'private') {
try {
$url = $storage->temporaryUrl(
$file,
now()->addMinutes(5),
);
} catch (Throwable $exception) {
// This driver does not support creating temporary URLs.
}
}

// $url - ...
return [
'name' => "original file",
'size' => $shouldFetchFileInformation ? $storage->size($file) : 0,
'type' => $shouldFetchFileInformation ? $storage->mimeType($file) : null,
'url' => $url,
];
});
$this->getUploadedFileUsing(static function (BaseFileUpload $component, string $file, string|array|null $storedFileNames): ?array {
$storage = Storage::disk('.....');
// dd($storedFileNames);

$shouldFetchFileInformation = $component->shouldFetchFileInformation();

if ($shouldFetchFileInformation) {
try {
if (!$storage->exists($file)) {
return null;
}
} catch (UnableToCheckFileExistence $exception) {
return null;
}
}

$url = null;

if ($component->getVisibility() === 'private') {
try {
$url = $storage->temporaryUrl(
$file,
now()->addMinutes(5),
);
} catch (Throwable $exception) {
// This driver does not support creating temporary URLs.
}
}

// $url - ...
return [
'name' => "original file",
'size' => $shouldFetchFileInformation ? $storage->size($file) : 0,
'type' => $shouldFetchFileInformation ? $storage->mimeType($file) : null,
'url' => $url,
];
});
It should be mentioned this is inside the setup() method, on a custom FileUpload component that extends FileUpload I have seen something similar with #curator . In the storage folder the file is in the form of a uuid, but it appears on the page with its original name
awcodes
awcodes7mo ago
Curator captures all the information it needs and stores that in its own table. For file upload there’s not a separate table unless you make one and use relationships. Maybe this is more of what you’re looking for https://filamentphp.com/docs/3.x/forms/fields/file-upload#storing-original-file-names-independently
DarkKnight
DarkKnight7mo ago
Hello. Uhm, not quite. I already have that.
DarkKnight
DarkKnight7mo ago
So when you preview a file or want to download, how can I make it such that the name appearing is the original file name? I know how to get the original file name, but not how to return it 🤔
No description
DarkKnight
DarkKnight7mo ago
I tried to understand the magic you made in your plugin, but couldnt quite figure it out
awcodes
awcodes7mo ago
Using the storage facade you can change the name of the downloaded file. https://laravel.com/docs/10.x/filesystem#downloading-files
Laravel - The PHP Framework For Web Artisans
Laravel is a PHP web application framework with expressive, elegant syntax. We’ve already laid the foundation — freeing you to create without sweating the small things.
awcodes
awcodes7mo ago
Not sure how to do it with the fileuploads built in download method though.
DarkKnight
DarkKnight7mo ago
Thanks, will have a look Hello. I tried, but im only able to download it with a custom file name
DarkKnight
DarkKnight7mo ago
The url is called in web.php which calls a Controller
class FileController extends Controller
{
public function show($uuid, $filename)
{
/**
* Sanitize and validate the filename input.. For example, a user might try to access files they shouldn't by
* using ../ sequences in the filename (known as a directory traversal attack).
*/
$filename = htmlspecialchars($filename);

$fileRecord = Files::where('file_name', $filename)->first();

// Initialize Storage
$storage = Storage::disk(config('app.private_folder'));

if (!$fileRecord || !$storage->exists($filename)) {
abort(404);
}

// Dynamically get the model class from the file record
$modelClass = $fileRecord->model_name;

/**
* You always haver permission to see your profile.
* But we make sure that the logged in user is the owner of the profile picture.
*/
if (class_exists($modelClass) && $modelClass == BreezySession::class) {
if ($fileRecord->file_uuid === $uuid && $fileRecord->user_id === auth()->user()->id) {
return $storage->response($filename);
}
}

// Check if the class exists and if the user has the permission
if (class_exists($modelClass) && auth()->user()->can('viewAny', $modelClass)) {
if ($fileRecord->file_uuid === $uuid) {

$headers = [
'Content-Disposition' => 'inline; filename=Test', // Use the original name for inline display
];
// dd($storage->response($filename, 200, $headers));
return $storage->response($filename, 200, $headers);
}
}

abort(403); // Forbidden access
}
}
class FileController extends Controller
{
public function show($uuid, $filename)
{
/**
* Sanitize and validate the filename input.. For example, a user might try to access files they shouldn't by
* using ../ sequences in the filename (known as a directory traversal attack).
*/
$filename = htmlspecialchars($filename);

$fileRecord = Files::where('file_name', $filename)->first();

// Initialize Storage
$storage = Storage::disk(config('app.private_folder'));

if (!$fileRecord || !$storage->exists($filename)) {
abort(404);
}

// Dynamically get the model class from the file record
$modelClass = $fileRecord->model_name;

/**
* You always haver permission to see your profile.
* But we make sure that the logged in user is the owner of the profile picture.
*/
if (class_exists($modelClass) && $modelClass == BreezySession::class) {
if ($fileRecord->file_uuid === $uuid && $fileRecord->user_id === auth()->user()->id) {
return $storage->response($filename);
}
}

// Check if the class exists and if the user has the permission
if (class_exists($modelClass) && auth()->user()->can('viewAny', $modelClass)) {
if ($fileRecord->file_uuid === $uuid) {

$headers = [
'Content-Disposition' => 'inline; filename=Test', // Use the original name for inline display
];
// dd($storage->response($filename, 200, $headers));
return $storage->response($filename, 200, $headers);
}
}

abort(403); // Forbidden access
}
}
Any help is appreciated:) any help?
DarkKnight
DarkKnight7mo ago
Even this function:
/**
* @return array<array{name: string, size: int, type: string, url: string} | null> | null
*/
public function getUploadedFiles(): ?array
{
$urls = [];

foreach ($this->getState() ?? [] as $fileKey => $file) {
if ($file instanceof TemporaryUploadedFile) {
$urls[$fileKey] = null;

continue;
}

$callback = $this->getUploadedFileUsing;

if (!$callback) {
return [$fileKey => null];
}

$urls[$fileKey] = $this->evaluate($callback, [
'file' => $file,
'storedFileNames' => $this->getStoredFileNames(),
]) ?: null;
}
dd($urls);

return $urls;
}
/**
* @return array<array{name: string, size: int, type: string, url: string} | null> | null
*/
public function getUploadedFiles(): ?array
{
$urls = [];

foreach ($this->getState() ?? [] as $fileKey => $file) {
if ($file instanceof TemporaryUploadedFile) {
$urls[$fileKey] = null;

continue;
}

$callback = $this->getUploadedFileUsing;

if (!$callback) {
return [$fileKey => null];
}

$urls[$fileKey] = $this->evaluate($callback, [
'file' => $file,
'storedFileNames' => $this->getStoredFileNames(),
]) ?: null;
}
dd($urls);

return $urls;
}
returns
No description
DarkKnight
DarkKnight7mo ago
And this is how I save the file:
class ExpenseFileUpload extends FileUpload
{
protected function setUp(): void
{
parent::setUp();

$this->getUploadedFileUsing(static function (BaseFileUpload $component, string $file, string|array|null $storedFileNames): ?array {
$storage = Storage::disk(...);

$shouldFetchFileInformation = $component->shouldFetchFileInformation();

if ($shouldFetchFileInformation) {
try {
if (!$storage->exists($file)) {
return null;
}
} catch (UnableToCheckFileExistence $exception) {
return null;
}
}

$url = null;

if ($component->getVisibility() === 'private') {
try {
$url = $storage->temporaryUrl(
$file,
now()->addMinutes(5),
);
} catch (Throwable $exception) {
// This driver does not support creating temporary URLs.
}
}

$fileRecord = Files::where('file_name', $file)->first();

$uuid = $fileRecord->file_uuid;

// $url ??= ...

return [
'name' => "test",
'size' => $shouldFetchFileInformation ? $storage->size($file) : 0,
'type' => $shouldFetchFileInformation ? $storage->mimeType($file) : null,
'url' => $url,
];
});

$this->getUploadedFileNameForStorageUsing(

// Flle name is generated randomly and checked if it exists in the database (unique)
function () {
$randomHex = null;
do {
$randomHex = bin2hex(random_bytes(16));
} while (...)->first());

return $randomHex;
}
);
}
}
class ExpenseFileUpload extends FileUpload
{
protected function setUp(): void
{
parent::setUp();

$this->getUploadedFileUsing(static function (BaseFileUpload $component, string $file, string|array|null $storedFileNames): ?array {
$storage = Storage::disk(...);

$shouldFetchFileInformation = $component->shouldFetchFileInformation();

if ($shouldFetchFileInformation) {
try {
if (!$storage->exists($file)) {
return null;
}
} catch (UnableToCheckFileExistence $exception) {
return null;
}
}

$url = null;

if ($component->getVisibility() === 'private') {
try {
$url = $storage->temporaryUrl(
$file,
now()->addMinutes(5),
);
} catch (Throwable $exception) {
// This driver does not support creating temporary URLs.
}
}

$fileRecord = Files::where('file_name', $file)->first();

$uuid = $fileRecord->file_uuid;

// $url ??= ...

return [
'name' => "test",
'size' => $shouldFetchFileInformation ? $storage->size($file) : 0,
'type' => $shouldFetchFileInformation ? $storage->mimeType($file) : null,
'url' => $url,
];
});

$this->getUploadedFileNameForStorageUsing(

// Flle name is generated randomly and checked if it exists in the database (unique)
function () {
$randomHex = null;
do {
$randomHex = bin2hex(random_bytes(16));
} while (...)->first());

return $randomHex;
}
);
}
}
Even changing the size to lets say 3, doesnt change the size shown, which tells me something else is going on
return [
'name' => "test",
'size' => $shouldFetchFileInformation ? 3 : 0,
'type' => $shouldFetchFileInformation ? $storage->mimeType($file) : null,
'url' => $url,
];
return [
'name' => "test",
'size' => $shouldFetchFileInformation ? 3 : 0,
'type' => $shouldFetchFileInformation ? $storage->mimeType($file) : null,
'url' => $url,
];
DarkKnight
DarkKnight7mo ago
No description
awcodes
awcodes7mo ago
Do you have a repo you could share? Having trouble following the bits and pieces. Feel free to dm me with the repo if you don’t want to share it here.
DarkKnight
DarkKnight7mo ago
I will make a reproduction repo, and share it with you! Thank you for your time
awcodes
awcodes7mo ago
No worries.
DarkKnight
DarkKnight7mo ago
pm sent:) As for the custom view you told me about. Can I change the name of the file being displayed from the blade file? That is also ok with me
awcodes
awcodes7mo ago
In a custom view you can display anything you want, it’s just a blade file.
DarkKnight
DarkKnight7mo ago
Ah, what about the file-upload blade file?
awcodes
awcodes7mo ago
I wouldn’t, that’s a core file. And it’s also relative to the filepond implementation. My custom views just use img tags not the fileupload or filepond. It’s just blade and html.
DarkKnight
DarkKnight7mo ago
Gotcha. Thanks. So no easy easy way for the moment
awcodes
awcodes7mo ago
Depends on your definition of easy. Lol. But changing a core blade view and alpine component that uses a 3rd party plugin is not going to be easy, ever.
DarkKnight
DarkKnight7mo ago
Yeah, it could also break things in the future
awcodes
awcodes7mo ago
Yep. Personally, I think you’re trying to over complicate something that ultimately doesn’t matter. But you have to understand the context in which you are trying to hijack the system. You’re trying to hijack the preview file name inside the 3rd party package and if they don’t have an api to do that then it can’t be done. All the previews in curator don’t have anything to do with the FileUpload field or FilePond. Anywhere those are used still show the filename and not anything else. Because the filename shown in the actual FileUpload in the green area at the top doesn’t matter.
DarkKnight
DarkKnight7mo ago
I see. Then I will stop trying because its not worth my efforts 😅. I already wasted 2 full days.
awcodes
awcodes7mo ago
It’s just the physical name of the file in storage and that could be a temp filename or the actual filename depending on what point in the process of saving the record your at.
DarkKnight
DarkKnight7mo ago
I just find it weird because the getUploadedFileUsing() returns the original name in the array, but I still got the custom name xd I will just wait/hope for FilePond to release an implementation
awcodes
awcodes7mo ago
FilePond just uses the actual filename. And to my knowledge there’s nothing you can do about that.
DarkKnight
DarkKnight7mo ago
Thanks for letting me know:)
Omar M.
Omar M.4mo ago
Hi, i have the same problem, but i found a solution!! i create a action in the 'actions' section from my relationmanager, you can adjust to your needs, the code is: Action::make('download') ->label('Descargar') ->color('info') ->action(function ($record) { // the original file name is in the field 'nombre_original' , return Response::download('storage/'.$record['archivo'], $record['nombre_original']); }),