readFiles function
Reads file(s) from a multipart/form-data request for a specific field name.
Example usage:
final files = await readFiles(event,
fieldName: 'photos',
hashFileName: true,
maxFileSize: 5 // 5MB limit
);
Parameters:
fieldName
: The form field name containing the file(s)customFilePath
: Optional custom path to save uploaded fileshashFileName
: If true, generates a unique hashed filename (default: false)maxFileSize
: Maximum file size in MB (default: 10MB)
Returns a List of file information maps containing:
{
'path': String, // File path on disk
'mimeType': String, // File content type
'originalname': String, // Original file name
'fieldName': String, // Form field name
'size': int, // File size in bytes
'filename': String // current file name
}
Returns null if no files are found for the specified fieldName.
Throws CreateError if:
- Request is not multipart/form-data
- Boundary is missing in content type
- File size exceeds maxFileSize
- File upload fails
Implementation
Future<List<Map<String, dynamic>>?> readFiles(H4Event event,
{required String fieldName,
String? customFilePath,
bool hashFileName = false,
int maxFileSize = 10}) async {
final HttpRequest request = event.node["value"]!;
final contentType = request.headers.contentType;
if (contentType?.mimeType != 'multipart/form-data') {
throw CreateError(
message: 'Files can only be uploaded using multipart/form-data');
}
final boundary = contentType!.parameters['boundary'];
if (boundary == null) {
throw CreateError(message: 'Missing boundary in multipart/form-data');
}
final mimeTransformer = MimeMultipartTransformer(boundary);
final parts = request.cast<List<int>>().transform(mimeTransformer);
List<Map<String, dynamic>> files = [];
try {
await for (final part in parts) {
final headers = part.headers;
final contentType = headers['content-type'];
final contentDisposition = headers['content-disposition'];
final nameMatch =
RegExp(r'name="([^"]*)"').firstMatch(contentDisposition ?? '');
final currentFieldName = nameMatch?.group(1);
final filenameMatch =
RegExp(r'filename="([^"]*)"').firstMatch(contentDisposition ?? '');
final filename = filenameMatch?.group(1);
// Only process if it matches the requested fieldName and has a filename
if (currentFieldName == fieldName && filename != null) {
final fileInfo = await _streamToStorage(part,
originalFilename: filename,
customFilePath: customFilePath,
hashFileName: hashFileName,
maxFileSize: maxFileSize);
files.add({
'path': fileInfo['path'],
'mimeType': contentType,
'originalname': filename,
'fieldName': fieldName,
'size': fileInfo['size'],
'filename': fileInfo['filename'],
});
}
}
return files.isEmpty ? null : files;
} catch (e) {
throw CreateError(
message: 'Failed to read files from formdata: ${e.toString()}');
}
}