I'm trying to do a Yesod web app allowing to upload a file and to save it in the temporary folder. I'm using Base64 encoding/decoding. When I upload a text file with this content:
copie carte d'identité
téléphone
autocertfication fiscale
signature
then the content of the file I get in the temporary folder is:
u«Zµìmþ™ZŠvÚ±î¸copie carte d'identité
téléphone
autocertfication fiscale
signature
The input file is UTF8-encoded.
Here is how I handle the file upload with JavaScript:
$("#file").on("change", function() {
let file = this.files[0];
let fileReader = new FileReader();
fileReader.readAsDataURL(file);
fileReader.onload = function() {
let base64 = fileReader.result;
$.ajax({
contentType: "application/json",
processData: false,
url: "@{FileR}",
type: "PUT",
data: JSON.stringify({
_filename: file.name,
_base64: base64
}),
success: function(result) {
// not important
},
dataType: "text"
});
};
fileReader.onerror = function() {
alert(fileReader.error);
};
});
In Haskell, I have:
import qualified Data.ByteString as B
import qualified Data.ByteString.Base64 as B64
import qualified Data.ByteString.Char8 as BC
import System.IO.Temp ( getCanonicalTemporaryDirectory )
base64ToFile :: String -> FilePath -> IO FilePath
base64ToFile b64string fileName = do
let bstring = B64.decodeLenient (BC.pack b64string)
tmpDir <- getCanonicalTemporaryDirectory
let filePath = tmpDir ++ "/" ++ fileName
B.writeFile filePath bstring
return filePath
data File = File {
_filename :: String,
_base64 :: String
} deriving (Show, Generic)
instance FromJSON File
b64FileToFile :: File -> IO FilePath
b64FileToFile file = base64ToFile (_base64 file) (_filename file)
putFileR :: Handler String
putFileR = do
file <- requireCheckJsonBody :: Handler File
liftIO $ b64FileToFile file
I don't know where is the source of the issue, whether this is in the JavaScript step or in the Haskell step. I want to be able to upload a text file, a CSV file, a XLSX file, or an image file.
One has to remove the MIME type from the Base64 string, that is, to take only the part after the comma: