To prevent uploads from overwriting each other in our media folder, is there a way to generate a unique name for a file upon upload?
Example:
Uploadingunknown.jpg
(again) would be renamed to[random-hash].jpg
on the server
Would this be accomplished by means of a middleware or something I'm missing?
Aka: handlers
in the Upload Options described here: https://payloadcms.com/docs/upload/overview#enabling-uploads
Thank you for responses / feedback!
I found this thread because I want to sanitize filenames to not include spaces.
Since uploads always have a URL attached, should this maybe be a core functionality?
something like sanitizeFilename: true
?
Solved it like this if anyone cares:
import { CollectionBeforeOperationHook } from 'payload/types'
/**
* Sanitizes the filename for upload collections to not include spaces or special characters
*/
export const sanitizeFileName: CollectionBeforeOperationHook = async ({
args,
}) => {
const files = args.req?.files
if (
files !== undefined &&
files !== null &&
typeof files === 'object' &&
files.file !== undefined &&
files.file !== null &&
typeof files.file === 'object' &&
files.file.name !== undefined &&
files.file.name !== null &&
typeof files.file.name === 'string'
) {
files.file.name = files.file.name.replace(/[^a-z0-9.]/gi, '_').toLowerCase()
}
}
Uploaded files having the same name as something already in storage will be renamed with a -n
suffix for uniqueness such that unknown.jpg
uploaded a 2nd time is saved as unknown-1.jpg
. This should be happening automatically for you. If that is not the case you can open a bug for this issue.
If you prefer to have a unique hash instead, you'd need to do a bit of work which I can go into some detail if you want.
Let me know what you think!
Adding to this, it looks like a beforeOperation
hook on the collection is also suitable for this. A quick and dirty example:
beforeOperation: [async ({ args }) => {
const files = args.req?.files;
if (files && files.file && files.file.name) {
const parts = files.file.name.split('.');
files.file.name = `${(Math.random() + 1).toString(36).substring(2)}.${parts[parts.length - 1]}`;
}
}]
It just replaces the filename in the request before anything is saved. Note that this does not at all guarantee that the filename is unique, although depending on usage collision are probably rare anyway and in case they do happen we can rely on the built-in functionality of adding the -n
suffix as Dan pointed out.
Using handlers
on the upload might be 'better', but I prefer using a hook to stay consistent with the rest of my application.
+1. This is probably what I'd do. Hell yeah, beforeOperation
! The use cases for that one are less than the beforeChange
, etc. but I always knew there were use cases out there!!!
fwiw stumbled on this discussion searching for a way to encode upload filenames that had spaces in them.
good for this purpose too right?
hooks: {
beforeOperation: [
async ({ args }) => {
const files = args.req?.files;
if (files && files.file && files.file.name) {
files.file.name = encodeURIComponent(files.file.name);
}
}
]
},
Star
Discord
online
Get help straight from the Payload team with an Enterprise License.