@@ -30,6 +30,33 @@ function generateNewFileName(filePath: string, callback: (newName: string) => vo
3030 checkExistence ( newPath ) ;
3131}
3232
33+ /**
34+ * Fixes encoding issues where UTF-8 bytes are incorrectly interpreted as Latin-1.
35+ *
36+ * Multer uses Busboy internally, which defaults to 'latin1' charset for parsing
37+ * Content-Disposition header parameters (like filenames). This causes UTF-8
38+ * characters to be misinterpreted.
39+ *
40+ * Example: 'ø' (UTF-8: 0xC3 0xB8) gets misinterpreted as 'ø' (Latin-1: 0xC3 0xB8)
41+ *
42+ * Solution: Convert the string back to bytes using Latin-1 (which preserves
43+ * byte values), then re-interpret those bytes as UTF-8.
44+ *
45+ * Note: This is the standard workaround since Multer doesn't expose Busboy's
46+ * defParamCharset option directly.
47+ * @link https://github.com/expressjs/multer/issues/1104
48+ */
49+ function fixFilenameEncoding ( filename : string ) : string {
50+ try {
51+ // Convert the string back to bytes using Latin-1 (which preserves byte values),
52+ // then re-interpret those bytes as UTF-8
53+ return Buffer . from ( filename , 'latin1' ) . toString ( 'utf8' ) ;
54+ } catch ( error ) {
55+ // If conversion fails, return the original filename
56+ return filename ;
57+ }
58+ }
59+
3360// Define multer storage object
3461export const storage = multer . diskStorage ( {
3562 destination : function ( _req , file , cb ) {
@@ -40,7 +67,8 @@ export const storage = multer.diskStorage({
4067
4168 ensureDirectory ( publicDir . uploadsDir ) ;
4269
43- const sanitisedName = sanitize ( file . originalname ) ;
70+ const fixedFilename = fixFilenameEncoding ( file . originalname ) ;
71+ const sanitisedName = sanitize ( fixedFilename ) ;
4472 const filePath = path . join ( publicDir . uploadsDir , sanitisedName ) ;
4573
4674 // Check if file already exists
0 commit comments