Simplify your stack and build anything. Or everything.
Build tomorrow’s web with a modern solution you truly own.
Code-based nature means you can build on top of it to power anything.
It’s time to take back your content infrastructure.

Rename File On Upload? Not Overwriting Other Uploads

default discord avatar
andrewstanton2 years ago
3 5

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!

  • Selected Answer
    default discord avatar
    christian-reichartlast year

    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()
      }
    }
    2 replies
  • default discord avatar
    ccssmnn11 months ago

    I've tried a beforeChange-Hook to manipulate the filename in the document. This changed the document entry, but not the actual file name. Also, the resized image names were still based on the original name.

    I now use this hook here to set a nanoid as the filename. Thank you so much!

  • default discord avatar
    linobino17 months ago

    Using this in Payload v3.0.0-beta.19:

    import type { CollectionBeforeOperationHook } from "payload/types";
    import slugify from "slugify";
    
    /**
     * Sanitizes the filename for upload collections to not include spaces or special characters
     */
    export const sanitizeFileName: CollectionBeforeOperationHook = async ({
      req,
    }) => {
      const file = req.file;
      if (typeof file?.name === "string") {
        file.name = slugify(file.name, { strict: true });
      }
    }
  • discord user avatar
    DanRibbens
    2 years 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
    SimonVreman2 years 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
    2 years 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
    andwrobs2 years 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);
            }
          }
        ]
      },
  • default discord avatar
    wkentdag7 months ago

    IMO the options passed to sanitize-filename (invoked here) should be configurable. For context there's some discussion in discord here

  • default discord avatar
    vojtech-cerveny5 months ago

    Anything from suggestions works for me, so I needed to debug it and this works for me.
    Version 3.0.0-beta.58

    import { CollectionConfig } from 'payload'
    
    export const Media: CollectionConfig = {
      slug: 'media',
      upload: true,
    
      fields: [
        {
          name: 'text',
          type: 'text',
        },
      ],
      hooks: {
        beforeOperation: [
          async (req) => {
            if (req.operation === 'create') {
              if (req.req.file)
                req.req.file.name = req.req.file?.name.replace(/[^a-z0-9.]/gi, '').toLowerCase()
            }
          },
        ],
      },
    }
Star on GitHub

Star

Chat on Discord

Discord

online

Can't find what you're looking for?

Get dedicated engineering support directly from the Payload team..