I'm working on a feature to define a limit size of a pdf file to be uploaded. That part is ok, but I also need to define a limit for how many pages a pdf file has, and I couldn't find any answer to that. I am using NestJS, and my code block looks like this so far:
@UseInterceptors(
FilesInterceptor('files', 10, {
limits: { fileSize: 10242880 },
fileFilter: (req, file, callback) => {
if (!file.originalname.match(/\.(jpg|jpeg|png|pdf)$/)) {
req.fileValidationError =
'Invalid file type provided. Valid types: [jpg, jpeg, png, pdf]';
//TODO: Add validation to check if the file is pdf, and if so, define a limit of pages for the file. (max * pages)
callback(null, false);
}
const fileSize = parseInt(req.headers['content-length']);
if (fileSize > 10242880) {
req.fileValidationError = 'File size exceeds the maximum limit [10mb]';
callback(null, false);
}
callback(null, true);
if (!file.originalname.match(/\.(pdf)$/)) {
//what to do here??
}
},
})
The multer options available in the interface, are the following. Maybe any of them can provide me with such an info, but I would really appreciate a hand with this. Thanks
export interface MulterOptions {
dest?: string;
/** The storage engine to use for uploaded files. */
storage?: any;
/**
* An object specifying the size limits of the following optional properties. This object is passed to busboy
* directly, and the details of properties can be found on https://github.com/mscdex/busboy#busboy-methods
*/
limits?: {
/** Max field name size (Default: 100 bytes) */
fieldNameSize?: number;
/** Max field value size (Default: 1MB) */
fieldSize?: number;
/** Max number of non- file fields (Default: Infinity) */
fields?: number;
/** For multipart forms, the max file size (in bytes)(Default: Infinity) */
fileSize?: number;
/** For multipart forms, the max number of file fields (Default: Infinity) */
files?: number;
/** For multipart forms, the max number of parts (fields + files)(Default: Infinity) */
parts?: number;
/** For multipart forms, the max number of header key=> value pairs to parse Default: 2000(same as node's http). */
headerPairs?: number;
};
/** Keep the full path of files instead of just the base name (Default: false) */
preservePath?: boolean;
fileFilter?(req: any, file: {
/** Field name specified in the form */
fieldname: string;
/** Name of the file on the user's computer */
originalname: string;
/** Encoding type of the file */
encoding: string;
/** Mime type of the file */
mimetype: string;
/** Size of the file in bytes */
size: number;
/** The folder to which the file has been saved (DiskStorage) */
destination: string;
/** The name of the file within the destination (DiskStorage) */
filename: string;
/** Location of the uploaded file (DiskStorage) */
path: string;
/** A Buffer of the entire file (MemoryStorage) */
buffer: Buffer;
}, callback: (error: Error | null, acceptFile: boolean) => void): void;
}
The best solution I was able to provide was using pdf-lib. I moved the page limit check, outside the FIleFilter from multer, because there is no buffer from a file at that point. The solution was used inside a different function, as suggested by @bogdanoff
try {
for (const file of files) {
const isPdf = file.mimetype === 'application/pdf';
if (isPdf) {
const loadPdf = PDFDocument.load(file.buffer);
//the PDFDocument above, is the pdf-lib imported
const pdf = await loadPdf;
const pagesCount = pdf.getPageCount();
if (pagesCount > 5) {
throw new BadRequestException({
statusCode: 400,
message: 'PDF file must have a maximum of 5 pages.',
});
}
}
}
} catch (error) {
this.commonLogger.error({
error,
serviceName: this.controllerName,
method: 'createCredential',
params: { vendorId, userId, credentialDto },
});
throw new BadRequestException({ statusCode: 400, message: error.message });
}
}