Rename File On Upload? Not Overwriting Other Uploads

default discord avatar
andrewstanton
12 months ago
2 3

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:
Uploading unknown.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!

  • default discord avatar
    christian-reichart
    8 months ago

    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()
      }
    }
  • discord user avatar
    DanRibbens
    Payload Team
    12 months ago

    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!

  • default discord avatar
    SimonVreman
    11 months ago

    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.

    2 replies
    discord user avatar
    jmikrut
    Payload Team
    11 months ago

    +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!!!

    default discord avatar
    andwrobs
    11 months ago

    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);
            }
          }
        ]
      },
Open the post
Continue the discussion in GitHub
Like what we're doing?
Star us on GitHub!

Star

Connect with the Payload Community on Discord

Discord

online

Can't find what you're looking for?

Get help straight from the Payload team with an Enterprise License.