Multiple file upload in vibe.d
Previously, I wrote a post on how to submit a form in vibe.d including a file upload. Now its time to demo multiple file upload which sometimes come in handy. This post serves as continuation so refer to it to catch up.
Similar to the previous post, we will create an upload
function which will
handle file uploads on the server side. However, I will only implement the
multiple file upload functionality without boring you with textual data which I
did previously. Create a new
vibe.d project and build upon it to a point where you have the upload
function
(You may use code from the previous post).
So lets rock and roll ASAP, shall we. Multiple file input (of any number) can be
specified in an HTML form by appending square brackets ("[]"
) to the value of
the name
property.
Using JavaScript, you can dynamically add file inputs to allow user to upload several file at a time.
The diet template code will be:
doctype html
head
title File upload
body
form(method='post',action='/upload',enctype='multipart/form-data')
p
label(for='picture[]') Select multiple pictures
br
input(name='picture[]', type='file')
br
input(name='picture[]', type='file')
button(type='submit') Upload
The enctype='multipart/form-data'
is necessary to submit files in a form as
discussed in my previous post. As you can see, the value of the name
property
of all the file inputs is picture[]
. This makes it easy to identify all those
files, as we will see below, as belonging to the same category. This is
particularly useful for uploading one or more of a certain file without having
to give each file a unique name
value for identification on the server side.
Within the upload
function, add the following code:
void upload(HTTPServerRequest req, HTTPServerResponse res)
{
import std.conv: to;
import std.path: extension;
foreach(nameAttr, picture; req.files) {
// Extract file extension
string ext = extension(to!string(picture.filename));
// Sort files based on "name" attribute
// Only files with name="picture[]" will be uploaded
if (nameAttr == "picture[]" && (ext == ".png" || ext == ".jpg"))
{
import std.datetime: Clock;
// Rename uploaded file using current timestamp to make it unique
string newFileName = "image_" ~ to!string(Clock.currTime.toUnixTime) ~ ext;
try {
logInfo("Move successful!");
moveFile(picture.tempPath, Path("./public/pictures/" ~ newFileName));
} catch (Exception e) {
logInfo("Exception thrown");
copyFile(picture.tempPath, Path("./public/pictures/" ~ newFileName));
}
}
}
res.redirect("/");
}
The extension of each uploaded file is extracted using the extension
function
from std.path
to be used in renaming. We then iterate over the submitted files
in the form to filter out those that do not have a name
value of picture[]
.
As common in file uploads, you may also choose to only allow files of certain
extension (".png", ".jpg", ".jpeg", ".gif,", ".pdf", etc), which I implemented
only for image files with either ".png" or ".jpg" extension.
Uploaded files may contain certain characters which are not allowed in some
Operating Systems, and one approach is by giving each file a custom file name
which you can guarantee will not cause any issues. I therefore renamed each file
as "image_"
appended with the current
Unix timestamp and the file
extension. The file is then moved to public/pictures/
or copied in-case an
exception is thrown (who knows what else can happen).
Make sure you create the
pictures
directory in yourpublic
folder.
That's all it takes to upload multiple files in vibe.d, I may demo how to
implement the same functionality using the Web Interface
of vibe.d but not
until I write an introductory blog about it and why you really need to use it
in most cases.