diff --git a/examples/with-koa2.js b/examples/with-koa2.js index 1ecef737..b8cd6b62 100644 --- a/examples/with-koa2.js +++ b/examples/with-koa2.js @@ -11,7 +11,16 @@ app.on('error', (err) => { app.use(async (ctx, next) => { if (ctx.url === '/api/upload' && ctx.method.toLowerCase() === 'post') { - const form = formidable({ multiples: true }); + let i = 0; + const form = formidable({ + multiples: true, + keepExtensions: true, + // must return absolute path + filename: (part, $self) => { + i += 1; + return `${$self.uploadDir}/sasasa${i}`; + }, + }); // not very elegant, but that's for now if you don't want touse `koa-better-body` // or other middlewares. diff --git a/src/Formidable.js b/src/Formidable.js index c9a0d662..5d3f7a1f 100644 --- a/src/Formidable.js +++ b/src/Formidable.js @@ -44,11 +44,6 @@ class IncomingForm extends EventEmitter { this.uploaddir = dir; this.uploadDir = dir; - this.options.filename = - typeof this.options.filename === 'function' - ? this.options.filename.bind(this) - : this._uploadPath.bind(this); - // initialize with null [ 'error', @@ -61,6 +56,18 @@ class IncomingForm extends EventEmitter { this[key] = null; }); + const hasRename = typeof this.options.filename === 'function'; + + if (this.options.keepExtensions === true && hasRename) { + this._rename = (part) => { + const resultFilepath = this.options.filename.call(this, part, this); + + return this._uploadPath(part, resultFilepath); + }; + } else { + this._rename = (part) => this._uploadPath(part); + } + this._flushing = 0; this._fieldsSize = 0; this._fileSize = 0; @@ -290,7 +297,7 @@ class IncomingForm extends EventEmitter { this._flushing += 1; const file = new File({ - path: this.options.filename(part, this), + path: this._rename(part), name: part.filename, type: part.mime, hash: this.options.hash, @@ -433,17 +440,29 @@ class IncomingForm extends EventEmitter { filename = filename.replace(/&#([\d]{4});/g, (_, code) => String.fromCharCode(code), ); + return filename; } - _uploadPath(part) { - const name = `${this.uploadDir}${path.sep}${toHexoId()}`; + _getExtension(str) { + const basename = path.basename(str); + const firstDot = basename.indexOf('.'); + const lastDot = basename.lastIndexOf('.'); + const extname = path.extname(basename).replace(/(\.[a-z0-9]+).*/i, '$1'); - if (part && this.options.keepExtensions) { - let ext = path.extname(typeof part === 'string' ? part : part.filename); - ext = ext.replace(/(\.[a-z0-9]+).*/i, '$1'); + if (firstDot === lastDot) { + return extname; + } + + return basename.slice(firstDot, lastDot) + extname; + } + + _uploadPath(part, fp) { + const name = fp || `${this.uploadDir}${path.sep}${toHexoId()}`; - return `${name}${ext}`; + if (part && this.options.keepExtensions) { + const filename = typeof part === 'string' ? part : part.filename; + return `${name}${this._getExtension(filename)}`; } return name;