Laravel get mimeType from uploaded image - php

I am using jQuery file uploader to upload a resized image, convert it to blob and save it as blob into a DB.
For the database I also need to save the mimeType, which I see in the request, which I receive, but I dont understand how to get the mimeType value.
The code to send the image:
var formData = new FormData();
formData.append("_token", $('meta[name="csrf-token"]').attr('content'));
formData.append("user_id_val", $('.user-general-i').data('userid'));
// HTML file input, chosen by user
formData.append("userfile", data.files[0]);
var request = new XMLHttpRequest();
request.open("POST", "http://localhost.eu/home/create_comment_images");
request.onload = function(oEvent) {
if (request.status == 200) {
console.log('success');
} else {
console.log(request.status);
}
};
request.send(formData);
Code on the server:
public function create_comment_images(Request $data) {
\Log::info($data);
try {
$path = $data->userfile;
$logo = file_get_contents($path);
$base64 = base64_encode($logo);
return ['success' => true];
} catch (\Exception $e) {
return ['success' => false, 'message' => $e->getMessage()];
}
return ['success' => false, 'message' => 'Something went wrong'];
}
The log info shows me this:
array (
'_token' => 'QxOqetFU2Re6fwe442vksGNnvV0C88v8dcrFpAp',
'user_id_val' => '568092',
'userfile' =>
Illuminate\Http\UploadedFile::__set_state(array(
'test' => false,
'originalName' => 'Unbenannt.png',
'mimeType' => 'image/png',
'error' => 0,
'hashName' => NULL,
)),
)
I am almost there, I need the get the mimeType information from the array.
I tried:
$data->userfile->mime_content_type
$data->userfile->mimeType
$data->userfile['mimeType']
$data->userfile[0]['mimeType']
Nothing works. Any ideas how to extract that information?

On Laravel you can use the intervention library. This library is very powerfull you can change the format, resize and do all kind of stuff.
Here a basic example..
// read image from temporary file
$img = Image::make($_FILES['image']['tmp_name']);
// get or sets the mime type.
$mimeType = $img::mime();
// save image
$img->save('foo/bar.jpg');
// Get image as string.
$string = base64_encode($img->encode('jpg'));
Intervention Reference

To get the mimetype from the uploaded file header, you can call getMimeType() on the \Illuminate\Http\UploadedFile class.
$uploadedFile = $data->file('userfile');// or
$mimeType = $uploadedFile->getMimeType()

Related

How to upload files to S3 bucket from url directly

I am getting some MMS messages from my users. Those MMS are coming via twilio. So twilio storing those files into their server and I can visit those files from twilio. But in my case, I need to store those files into S3 and show into our system from S3. I can store those files into my local folder or my server. But I am not finding any way to store file into the S3 directly from the url.
This is what I have done to store into the local directory from url.
// url of my file. Mostly it will be image.
$url = 'urlofmyfile';
// Path where I am saving. Keeping for jpg for now
$img = 'file/sms/file.jpg';
// saving the file into the folder
file_put_contents($img, file_get_contents($url));
And this is how I am saving my files into S3 if anyone want to upload it directly into my system. For example if any user want to upload their profile picture.
public function saveToS3Bucket($uploadFileName, $imageTmpName) {
$s3Client = new \Aws\S3\S3Client([
'version' => env('S3_BUCKET_VERSION'),
'region' => env('S3_BUCKET_REGION'),
'credentials' => array(
'key' => env('S3_BUCKET_KEY'),
'secret' => env('S3_BUCKET_SECRET'),
)
]);
try {
$s3Client->putObject([
'Bucket' => env('S3_BUCKET_NAME'),
'Key' => $uploadFileName,
'SourceFile' => $imageTmpName,
'StorageClass' => 'REDUCED_REDUNDANCY',
'ACL' => 'public-read'
]);
return true;
} catch (S3Exception $e) {
echo $e->getMessage() . PHP_EOL;
return false;
}
}
Those above codes are working fine. But I am not finding any way to store into S3 from url. Please note I am writing code in CakePHP.
Have a look at the Twilio Function below, it should point you in the right direction.
It was derived from this Twilio Blog:
Encrypting and Storing Twilio Flex Recordings Off-site
const axios = require('axios');
let AWS = require('aws-sdk');
const S3UploadStream = require('s3-upload-stream');
exports.handler = async function(context, event, callback) {
// Set the region
AWS.config.update({region: 'us-west-2'});
AWS.config.update({ accessKeyId: context.AWSaccessKeyId, secretAccessKey: context.AWSsecretAccessKey });
// The name of the bucket that you have created
const BUCKET_NAME = 'winston';
const fileUrl = "https://a.b.twil.io/assets/KittehWinston.jpg";
const fileName = "winston.jpg";
const s3Stream = S3UploadStream(new AWS.S3());
// call S3 to retrieve upload file to specified bucket
let upload = s3Stream.upload({Bucket: BUCKET_NAME, Key: fileName, ContentType: 'image/jpeg', ACL: 'public-read' });
const fileUpload = await uploadFile(fileUrl, upload)
.then(result => callback(null, `success: ${JSON.stringify(result)}`))
.catch(err => callback(err.message));
async function uploadFile (url, upload) {
const response = await axios({
url,
method: 'GET',
responseType: 'stream'
})
response.data.pipe(upload);
return new Promise((resolve, reject) => {
upload.on('uploaded', resolve)
upload.on('error', reject)
})
}
};

VueJs Laravel Image Upload

Like the title says, I'm trying to do an image upload from VueJs to a Laravel endpoint. I discovered that the only way(if there is another please tell me) is to send the base64 of the image through the request. On the Vue side I think everything is covered.
However, on the Laravel side is where it gets complicated. I can't decode the base64 string that gets passed, and when I try to store the image in my AWS S3 bucket, it doesn't store properly. Here is the code:
VueJS
<template>
<input type="file" name="image" class="form-control" #change="imagePreview($event)">
</template>
methods: {
submitForm(){
axios.defaults.headers.post['Content-Type'] = 'multipart/form-data';
axios.post(this.$apiUrl + '/article', {
image: this.image
}).then(response => {
flash(response.data.message, 'success');
}).catch(e => {
console.log(e);
})
},
imagePreview(event) {
let input = event.target;
if (input.files && input.files[0]) {
var reader = new FileReader();
let vm = this;
reader.onload = e => {
this.previewImageUrl = e.target.result;
vm.image = e.target.result;
}
reader.readAsDataURL(input.files[0]);
}
}
}
Laravel:
$this->validate($request, [
'image' => 'required',
]);
// return response()->json(base64_decode($request->image));
$timestampName = microtime(true) . '.jpg';
$url = env('AWS_URL') . '/article_images/' .$timestampName;
Storage::disk('s3')->put($timestampName, base64_decode($request->image));
If I add the image validation rule, it says it's not an image..
I would also like to retrieve the extension if possible.
you can do it using FormData in JS part and use getClientOriginalExtension() on the file to get the extension in Laravel.
VueJS
imagePreview(event) {
let selectedFile = event.target.files[0];
vm.image = selectedFile;
}
submitForm(){
let fomrData = new FormData();
formData.append('image', vm.image);
axios.post(this.$apiUrl + '/article', formData, {
headers: {
'Content-Type': 'multipart/form-data'
}
})
.then(response => {
flash(response.data.message, 'success');
})
.catch(e => {
console.log(e);
});
}
Laravel
$this->validate($request, [
'image' => 'required',
]);
$image = $request->file('image');
$extension = $image->getClientOriginalExtension(); // Get the extension
$timestampName = microtime(true) . '.' . $extension;
$url = env('AWS_URL') . '/article_images/' .$timestampName;
Storage::disk('s3')->put($url, file_get_contents($image));
Here is a link that might be useful
Hope that it helps.

Laravel: Uploading of file to storage not working

I'm trying to upload image to storage. I'm currently got this object but seems unfortunate to save on app/storage
Illuminate\Http\UploadedFile Object
(
[test:Symfony\Component\HttpFoundation\File\UploadedFile:private] =>
[originalName:Symfony\Component\HttpFoundation\File\UploadedFile:private] => lamborghini_veneno_art_minimalism_99945_1366x768.jpg
[mimeType:Symfony\Component\HttpFoundation\File\UploadedFile:private] => image/jpeg
[size:Symfony\Component\HttpFoundation\File\UploadedFile:private] => 117303
[error:Symfony\Component\HttpFoundation\File\UploadedFile:private] => 0
[hashName:protected] =>
[pathName:SplFileInfo:private] => C:\xampp\tmp\php82F7.tmp
[fileName:SplFileInfo:private] => php82F7.tmp
)
Here is my code.
In profile.vue I have click event from input file.
onFilePicked(event){
const files = event.target.files
const data = new FormData();
data.append('avatar', files[0]);
this.$store.dispatch('uploadImage_profile',data)
.then(response=>{
})
.catch(error=>{
})
}
Then send using axios
axios({
url: '/prod/api/uploadImage_profile',
method: 'post',
data: obj
})
.then(response=>{
if(response.status == 200){
resolve(response.data)
}
})
.catch(error=>{
if(error.response){
reject(error.response.data);
}
})
And my Controller.php
public function uploadImage_profile(Request $request){
$response = [];
//var_dump($request->file('avatar'));
//$path = $request->file('avatar')->store('avatars');
if($request->hasFile('avatar')){
$file = $request->file('avatar');
Storage::put('file.jpg', $file);
}
return response()->json($response);
}
You need to set Content-Type as multipart/form-data in your axios post request:
axios({
url: '/prod/api/uploadImage_profile',
method: 'post',
data: obj,
headers: {
'Content-Type': 'multipart/form-data'
}
})
Try this way:
$file = $request->file('avatar');
$destinationPath = storage_path() . '/folder'; // directory under which you want to store the file
if( $file ->move( $destinationPath, $file ) )
{
// image moved successfuly
}
else
{
// fail to move image
}

Zend File Transfer Adapter Http is breaking my AJAX response, why?

I am working in Zend Framework 1 and I have this function in a controller:
public function uploadAction()
{
$this->_helper->layout->disableLayout();
$this->_helper->viewRenderer->setNoRender();
$data = [];
if ($this->getRequest()->isPost()) {
$path = /cronjobs/uploads';
// Clean $path directory OOP way using SPL
$di = new RecursiveDirectoryIterator($path, FilesystemIterator::SKIP_DOTS);
$ri = new RecursiveIteratorIterator($di, RecursiveIteratorIterator::CHILD_FIRST);
foreach ($ri as $file) {
$file->isDir() ? rmdir($file) : unlink($file);
}
$adapter = new Zend_File_Transfer_Adapter_Http();
$adapter->addValidator('Extension', false, ['extension' => 'csv', 'case' => true]);
$adapter->addValidator('MimeType', false, ['extension' => 'text/plain']);
// Check if the uploaded file is valid
$errors[] = $adapter->isValid() === false ? $adapter->getMessages() : '';
$file = (array) $adapter->getFileInfo()['file'];
$ext = end(explode('.', $file['name']));
$new_path = $file['tmp_name'];
// Check file size
$checkFileSize = Attachment::checkMaxfileSize($file['size']);
if (!$checkFileSize['accept']) {
echo json_encode($checkFileSize['message']);
return true;
}
$data['file'] = array(
'name' => $file['name'],
'size' => $adapter->getFileSize(),
'file_path' => $new_path,
'file_ext' => $ext
);
$data['var'] = '';
} else {
$data['error'] = 'Invalid request.';
}
return $this->_helper->json($data);
}
This method is called trough AJAX as follow:
$('#fileupload').show().fileupload({
url: url,
type: "POST",
cache: false,
dataType: 'json',
done: function (e, data) {
console.log(data.result);
},
error: function (xhr, textStatus, errorThrown) {
console.log(xhr + " " + textStatus + " " + errorThrown);
}
})
For some reason as soon as I call $adapter->isValid() in the controller the AJAX response gets break. I can say the problem is there because if I comment that piece of code everything works fine.
This is the message I am getting currently:
POST http://localhost/admin/upload net::ERR_EMPTY_RESPONSE
massive_charge_types_file_upload.js:147 [object Object] error
After read all of the following topics:
net::ERR_EMPTY_RESPONSE when post with ajax
Getting ERR_EMPTY_RESPONSE on $.POST
PHP Jquery Ajax call throws net::ERR_EMPTY_RESPONSE
and many more in Google
I am out of ideas and I am stuck since can't find what's causing the behavior.
UPDATE:
I believe the problem is on the isValid() method which return a boolean but for some reason this is breaking my response. Any ideas?
Can any help me with this?
It seems the syntax of your MimeType validator is wrong:
$adapter->addValidator('MimeType', false, ['extension' => 'text/plain']);
Should probably be:
$upload->addValidator('MimeType', false, array('text/plain'));
As described:
https://framework.zend.com/manual/1.12/en/zend.file.transfer.validators.html
Since your file won't pass the (impossible) validation test - I am guessing this is what then leads to no results?
After a few tries I got it working by adding the following:
if ($adapter->isValid() === false) {
$data['error'][] = $adapter->getMessages();
echo json_encode($data);
return true;
}
I need to use raw json_encode() PHP function, if I use the Zend Framework JSON helper as for example: $this->_helper->json($data) the response didn't work.
I believe this is a restriction for the Jquery plugin not sure tough.

Dropzone and non-object error

I'm trying to implement dropzonejs file upload on my website, but I'm getting this error
{"error":{"type":"Symfony\\Component\\Debug\\Exception\\FatalErrorException","message":"Call to a member function isValid() on a non-object","file":"C:\\Users\\Username\\Desktop\\localhost\\Project\\app\\controllers\\FileController.php","line":147}}
I have this inside the head tag. I check if the file is an Image and then check the dimensions before sending the file in to the controller. If the file is not an image I send it straight to the controller.
<script type="text/javascript">
$(function() {
Dropzone.options.createFile = {
accept: function(file, done) {
// checking if the filetype is an image to check the dimensions
if ((/\.(gif|jpg|jpeg|tiff|png)$/i).test(file.name)) {
var pixels = 0;
var reader = new FileReader();
reader.onload = (function(file) {
var image = new Image();
image.src = file.target.result;
image.onload = function() {
width = this.width;
height = this.height;
if(width < 800 || height < 300) {
done('image is not 800x300 pixels!');
} else {
done();
}
};
});
reader.readAsDataURL(file);
} else {
// if the file is not an image
done();
}
},
url: '/process/create-file',
previewsContainer: ".dropzone-previews",
uploadMultiple: true,
parallelUploads: 100,
maxFiles: 100,
}
});
</script>
This is the stripped controller, I removed a chunk of the code to make it shorter. Because the error is right at the top.
public function postCreateFile()
{
if(!Input::hasFile('file'))
return Response::json('Where is the file?', 400);
$file = Input::file('file');
if($file->isValid()){
// do stuff
}
}
if I add return var_dump($file) before the $file->isValid() line I get this response
array (size=2) '_token' => string 'BtN7aFkEUQvXlaJDzxx28e4WMI08h5bl3VqrEaHR' (length=40) 'file' => array (size=1) 0 => object(Symfony\Component\HttpFoundation\File\UploadedFile)[9] private 'test' => boolean false private 'originalName' => string '65VWl.jpg' (length=9) private 'mimeType' => string 'image/jpeg' (length=10) private 'size' => int 260740 private 'error' => int 0
And here is the form. I have enctype and files set to true, but still I get an error with a message "non-object" as described above.
{{ Form::open(array('class' => 'dropzone', 'id' => 'create-file', 'url' => 'process/create-file', 'enctype' => 'multipart/form-data', 'files' => true)) }}
<div class="dropzone-previews" id="giga-drop">
<div class="fallback">
{{ Form::file('file') }}
</div>
</div>
{{ Form::close() }}
Any ideas why am I getting this error?
Thanks for #Maerlyn for pointing out it was an array.
Also I found this link that I didn't notice when searching before Laravel and Dropzonejs, files are not uploaded correctly
I had to modify my $file variable to this:
$file = Input::file('file'); // didn't work
$file = Input::file('file')[0]; // works

Categories