void _uploadFile(Event event) async {
print("called");
final files = uploadInput.files;
final file = files![0];
_fileNameController.text = file.name;
// Get the file contents as a List<int>
final reader = new FileReader();
reader.readAsArrayBuffer(file);
await reader.onLoad.first;
final contents = reader.result as List<int>;
// Encode the file contents as a base64 string
final encodedFile = base64Encode(contents);
var response = await http.post(Uri.parse("http://url/img_test/img.php"),
body: jsonEncode(<String, String>{
'file': encodedFile,
})
);
print(response.body);
if (response.statusCode == 200) {
// Handle the success case
print("ok");
} else {
// Handle the error case
print("try");
}
}
I all ready set as file in body but till it shows
Error shows in flutter
Warning: Undefined array key "file" in M:\WEB\htdocs\img_test\img.php on line 7
PHP API:
<?php
move_uploaded_file($_FILES['file']['tmp_name'], 'uploads/' . $_FILES['file']['name']);
?>
your request post not send file, this string value, you can try decode in your php file like this
$base64string = "data:image/jpeg;base64,".$POST['file'];
list($type, $base64string) = explode(';', $base64string);
list(,$extension) = explode('/',$type);
list(,$base64string) = explode(',', $base64string);
$fileName = uniqid()'.'.$extension;
$imageFile = base64_decode($base64string);
file_put_contents($path.$fileName, $imageFile);
I'm unable to upload files using the Dio plugin and I can not figure out where's the problem. In Laravel the request is always empty.
What have I done so far:
Double check if the file path really exists using existsSync() function
Changed the Content-Type to application/x-www-form-urlencoded
Validated if the file is actually being uploaded - seems yes (?)
This is my flutter code:
File myFile = new File('/storage/emulated/0/Download/demo.docx');
FormData form = new FormData.from({
'title': 'Just testing',
'file': new UploadFileInfo(myFile, 'demo.docx')
});
Before sending through POST i checked if the file exists and returns true
print(myFile.existsSync());
And set the Content-type properly
Response response = await Dio().post(
myUrl,
data: form,
options: new Options(
contentType: ContentType.parse("application/x-www-form-urlencoded"),
),
);
Printing the result of the form returns
I/flutter (27929): ----dio-boundary-0118165894
I/flutter (27929): Content-Disposition: form-data; name="title"
I/flutter (27929): ----dio-boundary-1759467036
I/flutter (27929): Content-Disposition: form-data; name="file"; filename="demo.docx"
I/flutter (27929): Content-Type: application/octet-stream
Which I believe indicates that the file is being uploaded.
Now in laravel whenever i output the content received it always comes null the key file, but the key title comes with data.
The code print_r(json_encode($request->all())) retrieves
{"title":"Just testing","file":{}}
The same goes for print_r(json_encode($request->file('file'))).
What am i missing?
Solved.
This took me a while to figure it out, but i end up realizing there's two problems with this approach:
Laravel $request is empty, but $_FILES is not
Sending multiple files can not be sent using arrays as the documentation tells
So, in order to achieve my goal which allows the user to select multiple files dynamically and upload them at the same time, here's the logic behind:
Flutter
The form must be created without setting the files right away:
FormData form = new FormData.from(
{
'title': 'Just testing',
});
Since the function .from is a Map<String, dynamic> values can be added after.
/*
* files = List<String> containing all the file paths
*
* It will end up like this:
* file_1 => $_FILES
* file_2 => $_FILES
* file_3 => $_FILES
*/
for (int i = 0; i < files.length; i++) {
form.add('file_' + i.toString(),
new UploadFileInfo(new File(files[i]), files[i].toString()));
}
There is no need to set up a different Content-Type, therefore this is enough:
Response response = await Dio().post(myUrl, data: form);
Laravel / PHP
Forget about accessing the file through $request->file() and instead use the old school approach.
$totalFiles = count($_FILES);
for ($i = 0; $i < $totalFiles; $i++)
{
$file = $_FILES['file_' . $i];
// handle the file normally ...
$fileName = basename($file['name']);
$fileInfo = pathinfo($file);
$fileExtension = $fileInfo['extension'];
move_uploaded_file($file['tmp_name'], $path);
}
I know this is an old post but this may help someone.
this solution works for me, upload multi-file to server use Flutter Dio library and Laravel as backend. correct me if I did it wrong.
Flutter
BaseOptions _dioOption({#required String token}) {
BaseOptions options = new BaseOptions(baseUrl: baseUrl, headers: {
Headers.acceptHeader: Headers.jsonContentType,
Headers.contentTypeHeader: Headers.jsonContentType,
"Authorization": "Bearer $token"
});
return options;
}
dioPostProduct( {#required ProductToUpload productToUpload,
#required String url, String token}) async {
//productToUpload.images is a List<File>
List<Object> filesData = new List<Object>();
for (final file in productToUpload.images) {
filesData.add(MultipartFile.fromFileSync(file.path,
filename: file.path.split('/').last));
}
FormData data = FormData.fromMap({
"subcategory_id": productToUpload.subcategory_id,
"name": productToUpload.name,
"detail": productToUpload.detail,
"price": productToUpload.price,
"condition_id": productToUpload.condition_id,
"images": filesData,
});
Dio dio = new Dio(_dioOption(token: token));
Response response;
response = await dio.post(url, data: data);
if (response.statusCode == 200) {
print(response.data);
}
}
Laravel
For php resize image I use library intervention
$images = Collection::wrap(request()->file('images'));
$directory = '/product_images'; //make sure directory is exist
foreach ($images as $image) {
$basename = Str::random();
$original = $basename . '.' . $image->getClientOriginalExtension();
$thumbnail = $basename . '_thumb.' . $image->getClientOriginalExtension();
Image::make($image)
->fit(400, 400)
->save(public_path($directory . '/' . $thumbnail));
$image->move(public_path($directory), $original);
}
I Convert Base64 string in php to mp3 sound file but produced file wav Corrupted
Before convert tone sound is rustle
Such as voice files that convert :
http://vocaroo.com/i/s1Dlol5Wu3Zo
php code :
<?php
if(isset($_POST['audio'])){
$data = str_replace('data:audio/wav;base64,', '', $_POST['audio']);
$data = base64_decode($data);
$track_name = get_random_string(mt_rand(6,10)) . ".mp3";
$upl_dir = "../up/" . $track_name;
if( !file_put_contents($upl_dir, $data) ){
$response['status'] = 1;
$response['message'] = "File could not be uploaded. Try again >later.";
echo $data;
echo "E1";
}
echo $data;
}
I test sound before convert And was right.
Base64 Code :
https://ufile.io/174101
js code base64 creator:
function base641()
{
Fr.voice.export(function(url){
// console.log("Here is the base64 URL : " + url);
base = url;
ejem2 = 1;
// alert("Check the web console for the URL");
// $("<a href='"+ url +"' target='_blank'></a>")[0].click();
}, "base64");
};
try this :
file_put_contents('audio.mp3', base64_decode($data));
I'm working on a project where i can select an image (simple file select) and send it via JSON to a PHP MySQL insert page.
Upload page looks like this:
if (input.files && input.files[0]) {
var FR = new FileReader();
FR.onload = function(e) {
$('#img').attr("src", e.target.result);
var Naam = $('input[type=file]').val();
$('#base').text(e.target.result);
var Foto = e.target.result;
var Barcode = $('#barcode').val();
obj['Barcode'] = Barcode;
obj['Naam'] = Naam;
obj['Foto'] = Foto;
//execute ajax send
$.ajax({
url : 'insert.php',
type : 'POST',
data : obj,
dataType : 'json',
success : function(msg) {
alert("msg");
}
});
//$.post("insert.php", obj, function (data) {}, "json");
//alert("msg");
};
FR.readAsDataURL(input.files[0]);
and my PHP page:
$Barcode = $_POST["Barcode"];
$Naam = $_POST["Naam"];
$Name = preg_replace('/^.+[\\\\\\/]/', '', $Naam);
$Foto = base64_decode($_POST["Foto"]);
$query = "INSERT INTO voorraad_foto (barbody, location, foto) VALUES ('$Barcode','$Name','{$Foto}')";
$results = mysqli_query($db,$query);
And my table field is a BLOB.
But when it execute this, everything works fine except that it doesn't insert it as a blob, but pure string
I've tried with removing the
preg_replace('#data:image/[^;]+;base64,#', '', $Foto)
but doesn't make any difference, same when trying to add headers, but nothing..
What am i doing wrong, or is there something obvious that i'm not getting?
Thx.
I solved it in some kind of way:
I wrote a function that gets the Base64 string, decodes it and writes it to a Temp file.
Then i read that file again and upload that to my databse.
When success, delete the file.
It may not be the most effecient way, but it works!
function WriteToImageAndGetData($base64_string, $File) {
//Write to file
$ifp = fopen($File, "wb");
$data = explode(',', $base64_string); //Split Base64 string
fwrite($ifp, base64_decode($data[1])); //Decode Base64 string
fclose($ifp);
//Read from file
$fp = fopen($File, 'r');
$data = fread($fp, filesize($File)); //Read file contents
$data = addslashes($data);
fclose($fp);
return $data;
}
I'm working on a generative art project where I would like to allow users to save the resulting images from an algorithm. The general idea is:
Create an image on an HTML5 Canvas using a generative algorithm
When the image is completed, allow users to save the canvas as an image file to the server
Allow the user to either download the image or add it to a gallery of pieces of produced using the algorithm.
However, I’m stuck on the second step. After some help from Google, I found this blog post, which seemed to be exactly what I wanted:
Which led to the JavaScript code:
function saveImage() {
var canvasData = canvas.toDataURL("image/png");
var ajax = new XMLHttpRequest();
ajax.open("POST", "testSave.php", false);
ajax.onreadystatechange = function() {
console.log(ajax.responseText);
}
ajax.setRequestHeader("Content-Type", "application/upload");
ajax.send("imgData=" + canvasData);
}
and corresponding PHP (testSave.php):
<?php
if (isset($GLOBALS["HTTP_RAW_POST_DATA"])) {
$imageData = $GLOBALS['HTTP_RAW_POST_DATA'];
$filteredData = substr($imageData, strpos($imageData, ",") + 1);
$unencodedData = base64_decode($filteredData);
$fp = fopen('/path/to/file.png', 'wb');
fwrite($fp, $unencodedData);
fclose($fp);
}
?>
But this doesn’t seem to do anything at all.
More Googling turns up this blog post which is based off of the previous tutorial. Not very different, but perhaps worth a try:
$data = $_POST['imgData'];
$file = "/path/to/file.png";
$uri = substr($data,strpos($data, ",") + 1);
file_put_contents($file, base64_decode($uri));
echo $file;
This one creates a file (yay) but it’s corrupted and doesn’t seem to contain anything. It also appears to be empty (file size of 0).
Is there anything really obvious that I’m doing wrong? The path where I’m storing my file is writable, so that isn’t an issue, but nothing seems to be happening and I’m not really sure how to debug this.
Edit
Following Salvidor Dali’s link I changed the AJAX request to be:
function saveImage() {
var canvasData = canvas.toDataURL("image/png");
var xmlHttpReq = false;
if (window.XMLHttpRequest) {
ajax = new XMLHttpRequest();
}
else if (window.ActiveXObject) {
ajax = new ActiveXObject("Microsoft.XMLHTTP");
}
ajax.open("POST", "testSave.php", false);
ajax.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
ajax.onreadystatechange = function() {
console.log(ajax.responseText);
}
ajax.send("imgData=" + canvasData);
}
And now the image file is created and isn’t empty! It seems as if the content type matters and that changing it to x-www-form-urlencoded allowed the image data to be sent.
The console returns the (rather large) string of base64 code and the datafile is ~140 kB. However, I still can’t open it and it seems to not be formatted as an image.
Here is an example of how to achieve what you need:
Draw something (taken from canvas tutorial)
<canvas id="myCanvas" width="578" height="200"></canvas>
<script>
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
// begin custom shape
context.beginPath();
context.moveTo(170, 80);
context.bezierCurveTo(130, 100, 130, 150, 230, 150);
context.bezierCurveTo(250, 180, 320, 180, 340, 150);
context.bezierCurveTo(420, 150, 420, 120, 390, 100);
context.bezierCurveTo(430, 40, 370, 30, 340, 50);
context.bezierCurveTo(320, 5, 250, 20, 250, 50);
context.bezierCurveTo(200, 5, 150, 20, 170, 80);
// complete custom shape
context.closePath();
context.lineWidth = 5;
context.fillStyle = '#8ED6FF';
context.fill();
context.strokeStyle = 'blue';
context.stroke();
</script>
Convert canvas image to URL format (base64)
// script
var dataURL = canvas.toDataURL();
Send it to your server via Ajax
$.ajax({
type: "POST",
url: "script.php",
data: {
imgBase64: dataURL
}
}).done(function(o) {
console.log('saved');
// If you want the file to be visible in the browser
// - please modify the callback in javascript. All you
// need is to return the url to the file, you just saved
// and than put the image in your browser.
});
Save base64 on your server as an image (here is how to do this in PHP, the same ideas is in every language. Server side in PHP can be found here):
I played with this two weeks ago, it's very simple. The only problem is that all the tutorials just talk about saving the image locally. This is how I did it:
1) I set up a form so I can use a POST method.
2) When the user is done drawing, he can click the "Save" button.
3) When the button is clicked I take the image data and put it into a hidden field. After that I submit the form.
document.getElementById('my_hidden').value = canvas.toDataURL('image/png');
document.forms["form1"].submit();
4) When the form is submited I have this small php script:
<?php
$upload_dir = somehow_get_upload_dir(); //implement this function yourself
$img = $_POST['my_hidden'];
$img = str_replace('data:image/png;base64,', '', $img);
$img = str_replace(' ', '+', $img);
$data = base64_decode($img);
$file = $upload_dir."image_name.png";
$success = file_put_contents($file, $data);
header('Location: '.$_POST['return_url']);
?>
I think you should convert the image to base64 and then to Blob and send it to the server. When you use base64 images, a lot of lines will be sent to server. With blob, it's only the file.
You can use this code bellow:
function dataURLtoBlob(dataURL) {
let array, binary, i, len;
binary = atob(dataURL.split(',')[1]);
array = [];
i = 0;
len = binary.length;
while (i < len) {
array.push(binary.charCodeAt(i));
i++;
}
return new Blob([new Uint8Array(array)], {
type: 'image/png'
});
};
And canvas code here:
const canvas = document.getElementById('canvas');
const file = dataURLtoBlob( canvas.toDataURL() );
After that you can use ajax with Form:
const fd = new FormData;
fd.append('image', file);
$.ajax({
type: 'POST',
url: '/url-to-save',
data: fd,
processData: false,
contentType: false
});
The code in CoffeeScript syntax:
dataURLtoBlob = (dataURL) ->
# Decode the dataURL
binary = atob(dataURL.split(',')[1])
# Create 8-bit unsigned array
array = []
i = 0
while i < binary.length
array.push binary.charCodeAt(i)
i++
# Return our Blob object
new Blob([ new Uint8Array(array) ], type: 'image/png')
And canvas code here:
canvas = document.getElementById('canvas')
file = dataURLtoBlob(canvas.toDataURL())
After that you can use ajax with Form:
fd = new FormData
# Append our Canvas image file to the form data
fd.append 'image', file
$.ajax
type: 'POST'
url: '/url-to-save'
data: fd
processData: false
contentType: false
Send canvas image to PHP:
var photo = canvas.toDataURL('image/jpeg');
$.ajax({
method: 'POST',
url: 'photo_upload.php',
data: {
photo: photo
}
});
Here's PHP script:
photo_upload.php
<?php
$data = $_POST['photo'];
list($type, $data) = explode(';', $data);
list(, $data) = explode(',', $data);
$data = base64_decode($data);
mkdir($_SERVER['DOCUMENT_ROOT'] . "/photos");
file_put_contents($_SERVER['DOCUMENT_ROOT'] . "/photos/".time().'.png', $data);
die;
?>
I've worked on something similar.
Had to convert canvas Base64-encoded image to Uint8Array Blob.
function b64ToUint8Array(b64Image) {
var img = atob(b64Image.split(',')[1]);
var img_buffer = [];
var i = 0;
while (i < img.length) {
img_buffer.push(img.charCodeAt(i));
i++;
}
return new Uint8Array(img_buffer);
}
var b64Image = canvas.toDataURL('image/jpeg');
var u8Image = b64ToUint8Array(b64Image);
var formData = new FormData();
formData.append("image", new Blob([ u8Image ], {type: "image/jpg"}));
var xhr = new XMLHttpRequest();
xhr.open("POST", "/api/upload", true);
xhr.send(formData);
If you want to save data that is derived from a Javascript canvas.toDataURL() function, you have to convert blanks into plusses. If you do not do that, the decoded data is corrupted:
<?php
$encodedData = str_replace(' ','+',$encodedData);
$decocedData = base64_decode($encodedData);
?>
http://php.net/manual/ro/function.base64-decode.php
In addition to Salvador Dali's answer:
on the server side don't forget that the data comes in base64 string format. It's important because in some programming languages you need to explisitely say that this string should be regarded as bytes not simple Unicode string.
Otherwise decoding won't work: the image will be saved but it will be an unreadable file.
I just made an imageCrop and Upload feature with
https://www.npmjs.com/package/react-image-crop
to get the ImagePreview ( the cropped image rendering in a canvas)
https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/toBlob
canvas.toBlob(function(blob){...}, 'image/jpeg', 0.95);
I prefer sending data in blob with content type image/jpeg rather than toDataURL ( a huge base64 string`
My implementation for uploading to Azure Blob using SAS URL
axios.post(azure_sas_url, image_in_blob, {
headers: {
'x-ms-blob-type': 'BlockBlob',
'Content-Type': 'image/jpeg'
}
})