I'm getting confused about how to save an image content inside of a database table.
Please see the fourth line of code. I'm sure that this restful method (using POST) is working because getSize() returns the true value.
Also, if I debug what returns the 5th line I get something like the next one:
So, I'm not sure if what am I missing to save this data into the database.
$personId = Input::get('PersonId');
$file = Input::file('media');
$tmppath = $file->getRealPath();
$content = file_get_contents($tmppath); //$file->getSize();
// return $content;
$model = Person::find($personId);
$model->Photo = $content;
$model->save();
$result = array(
"success" => true,
"data" => $personId,
"error" => ""
);
You need to save the file to the server and only store the path in the database.
Write an appropriate method, ideally you can store it in a trait.
private function saveFileToDisk($file, $fileName)
{
$path = public_path() . '/uploads/';
return $file->move($path, $fileName . $file->getClientOriginalExtension());
}
An then pass the file input to your method and provide a name for the file:
$model->Photo = $this->saveFileToDisk(Input::file('media'), $model->Name);
Obvisouly you need to validate you input before all this.
Related
I have a functionality which will get user input and file input in a form and sent it as an email. I am using this code to capture those files:
$attachments_array = NULL;
foreach($_FILES as $userfile){
// store the file information to variables for easier access
$tmp_name = $userfile['tmp_name'];
$type = $userfile['type'];
$name = $userfile['name'];
$size = $userfile['size'];
if($tmp_name != ""){
$data=array(
'tmpfname' => $tmp_name,
'filename' => $name,
'type' => $type,
);
$attachments_array[] = $data;
}
}
So I am getting the user file input and putting it into $attachments_array . But what if I have a fixed file located somewhere like in:
https://www.myurl.com/A_Beginners_Guide_to_Outsourcing.pdf
How do I pass that into the attachments array? I am trying:
$attachments_array[] = file_get_contents('https://www.myurl.com/A_Beginners_Guide_to_Outsourcing.pdf');
But seems not working. I would like to pass it in the attachment array like the $data variable.
file_get_contents only gets the actual content of a file and returns it.
You would need to create an associative array and fill all used parameters by yourself, and perhaps save the file somewhere locally, depending on what are the further steps in your file processing.
$row = array();
$row['filename'] = 'A_Beginners_Guide_to_Outsourcing.pdf';
$row['type'] = "application/pdf"; // you might need some other method of getting a file type.
$tmp_path = "/my/tmp/path/".$row['filename'];
$body = file_get_contents('https://www.myurl.com/A_Beginners_Guide_to_Outsourcing.pdf');
file_put_contents($tmp_path, $body); // btw, be careful of what you save on your server..
$row['tmpfname'] = $tmp_path;
$attachments_array[] = $row;
I'm using Laravel 5.4.*. I've this simple code in a helper file to upload images/gif in S3 bucket under a folder named say "instant_gifs/". The code is below:
if ( !function_exists('uploadFile') ) {
function uploadFile($fileContent, $fileName, $size='full', $disk='s3')
{
$rv = '';
if( empty($fileContent) ) {
return $rv;
}
if($size == 'full') {
dump($fileName);
$path = Storage::disk($disk)->put(
$fileName,
$fileContent,
'public'
);
}
if ( $path ) {
$rv = $fileName;
}
return $rv;
}
}
From the controller, I'm calling the helper method as below:
$file = $request->gif;
$file_name = 'instant_gifs/' . $user_id . '_' . time() . '_' . $file->getClientOriginalName();
$result = uploadFile($file, $file_name);
In the the $fileName parameter of the helper method, I'm providing the fileName as for example in this format:
"instant_gifs/83_1518596022_giphy.gif"
but after the upload, I see that the file gets stored under this folder
"vvstorage/instant_gifs/83_1518596022_giphy.gif/CRm1o1YEcvX3fAulDeDfwT7DIMCxOKG8WFGcA3lB.gif"
with a random file name
CRm1o1YEcvX3fAulDeDfwT7DIMCxOKG8WFGcA3lB.gif
Whereas, according to the code, it should get stored in this path:
"vvstorage/instant_gifs/83_1518596022_giphy.gif"
Doesn't get any explanation why this is happening. Any clue will be appreciated.
BucketName = vvstorage
Folder I'm mimicking = instant_gifs
After some research & testing, found the issue. put() method expects the 2nd parameter as the file contents or stream not the file object. In my code, I was sending the file as $file = $request->gif; or $file = $request->file('gif'); hoping that Storage class will implicitly get the file contents. But to get the expected result, I needed to call the helper method from the controller as below. Notice the file_get_contents() part.
$file = $request->gif;
$file_name = 'instant_gifs/' . $user_id . '_' . time() . '_' . $file>getClientOriginalName();
$result = uploadFile( file_get_contents($file), $file_name );
Now, I got the image correctly stored under the correct path for example in /instant_gifs/9_1518633281_IMG_7491.jpg.
Now, let me compare/summarize the available methods for achieving the same result:
1) put():
$path = Storage::disk('s3')->put(
'/instant_gifs/9_1518633281_IMG_7491.jpg', #$path
file_get_contents($request->file('gif')), #$fileContent
'public' #$visibility
Got it stored in /vvstorage/instant_gifs/9_1518633281_IMG_7491.jpg
2) putFileAs(): To achieve the same thing withputFileAs(), I needed to write it as below. 1st parameter expects the directory name, I left it blank as I'm mimicking the directory name in s3 through the filename.
$path = Storage::disk('s3')->putFileAs(
'', ## 1st parameter expects directory name, I left it blank as I'm mimicking the directory name through the filename
'/instant_gifs/9_1518633281_IMG_7491.jpg',
$request->file('gif'), ## 3rd parameter file resource
['visibility' => 'public'] #$options
);
Got it stored in /vvstorage/instant_gifs/9_1518633281_IMG_7491.jpg
3) storeAs():
$path = $request->file('gif')->storeAs(
'', #$path
'/instant_gifs/9_1518633281_IMG_7491.jpg', #$fileName
['disk'=>'s3', 'visibility'=>'public'] #$options
);
Got it stored in /vvstorage/instant_gifs/9_1518633281_IMG_7491.jpg
Extras::
4) For storing Thumbnails through put(). Example of stream() ...
$imgThumb = Image::make($request->file('image'))->resize(300, 300)->stream(); ##create thumbnail
$path = Storage::disk('s3')->put(
'profilethumbs/' . $imgName,
$imgThumb->__toString(),
'public'
);
Hope that it helps someone.
1.) Why is there vvstorage in the url?
It is appending that route because your root folder inside of your configuration for S3 is set as vvstorage, so whenever you upload to S3 all files will be prepended with vvstorage.
2.) Why random name even when you passed the name of the file?
Because when using put the file will get a unique ID generated and set as it's file name so no matter what you pass, it won't save the file under the name you wanted. But if you use putFileAs then you can override the default behaviour of put and pass a name of the file.
Hope this clarifies it
PHP question on how to return a specific value from another class in a seperate file. So I have created a uploader class to handle and store files uploaded by users. But trying to connect the dots back to the orginal request which if for lets say a specific page - how can i pass a specific value back after I set the values in the other file... code example below.
Thanks Citti
//file 1 //store page request
public function store()
{
//pass the uploaded file to be uploaded and stored
$this->uploader->upload(RequestFile::file('assetfile'));
$page = new Page;
$page->user_id = $asset->user()->id;
$page->assetfile = $file->user_id; <--- ? see below
$page->save();
}
//file 2 //store physical file and create record in DB
class Uploader {
public function upload($file)
{
$extension = $file->getClientOriginalExtension();
$string = str_random(30);
$uploadName = $string . '.' . $extension;
$destinationPath = storage_path() . '/app/uploads/' . Request::user()->id;
$file->move($destinationPath, $uploadName);
$file = new File;
$file->user_id = $asset->user()->id;
$file->assetfile = $uploadId;
$file->save();
$return $file->user_id; ?!?
What you could try is session variables?
Be sure to start sessions on both file 1 and file 2 via:
session_start();
Now, in your upload function, you can declare a session variable
$_SESSION['specificValue'] = $valueSetInUpload;
Now, back on your first file you can access the variable inside of your store function with
$valueSetInUpload = $_SESSION['specificValue'];
I believe this is what you are asking, but I could be wrong.
To return values from a function, you use "return value" and you just have to store that to a variable or output it. Something like:
public function store() {
$fileId = $this->uploader->upload(RequestFile::file('assetfile'));
$page = new Page;
$page->user_id = $asset->user()->id;
$page->assetfile = $fileId;
$page->save();
}
//file 2 //store physical file and create record in DB
class Uploader {
public function upload($file) {
$extension = $file->getClientOriginalExtension();
$string = str_random(30);
$uploadName = $string . '.' . $extension;
$destinationPath = storage_path() . '/app/uploads/' . Request::user()->id;
$file->move($destinationPath, $uploadName);
$file = new File;
$file->user_id = $asset->user()->id;
$file->assetfile = $uploadId;
$file->save();
return $file->user_id;
}
}
I have this jquery code in a view, relating to my uploads controller:
function screenshot(){
var dataUrl = renderer.domElement.toDataURL("image/png");
$.post("picturepicker", {dataUrl: dataUrl, uploadnumber: 2
}
}
It successfully sends data to this function:
public function picturepicker(){
...
if($this->request->is('post')){
define('UPLOAD_DIR', WWW_ROOT . 'img/'); // increase validation
$img = $_POST['dataUrl']; // Tried $this->request['dataURL'], retrieved 'dataURL' just fine
$upload = $_POST['uploadnumber']; // tried $this->request['uploadnumber'], did not retrieve 'uploadnumber'
$img = str_replace('data:image/png;base64,', '', $img);
$img = str_replace(' ', '+', $img);
$data = base64_decode($img);
$file = UPLOAD_DIR . $upload . '.png'; // UPLOAD_DIR . uniqid() . '.png';
$success = file_put_contents($file, $data);
print $success ? $file : 'Unable to save the file.';
Which works fine, except that every time I ran the javascript, a new database row is created. Since I have no create function, I imagine that somehow jquery is inadvertently calling this function:
public function upload(){
if ($this->request->is('post')) {
//var_dump($this->request->data);
$this->Upload->create();
....
However, I doubt that since the rows are still added even when I delete all references to the create function.
So why might this happen, and how should I fix it? I am suspecting that somehow the jquery code is calling all of my functions, and that I need to put an if block around any of the others that take post data. I have been told that this should not be the case, and that perhaps cake's routing is to blame. Alternatively, I might have missed something in the cake documentation - perhaps cake is set up to make a new DB row for EVERY post request, and I need to tell it not to somehow.
i have an issue with uploading multiple files to disk. here is my code.
i have a request with 2 pictures that gets sent to a upload function. the 2 pictures are in a var called $multiUpload
$folderPath = '/var/www/';
if (is_array($multiUpload)){
$file = array();
$filename = array();
foreach($multiUpload as $key=>$val){
// get the file extension
$file[] = explode('.',$val);
// create custom file name
$filename[] = time().'.'.$file[$key][1];
//send to the upload function
$this->uploadToDisk($folderPath, $filename[$key]);
// sleep 1 sec so that the pic names will be different
sleep(1);
}
return $filename;
}
public function uploadToDisk($folderPath, $filename)
{
$adapter = new Zend_File_Transfer_Adapter_Http();
$adapter->setDestination($folderPath);
$adapter->addFilter( 'Rename',array(
'target' => $folderPath."/".$filename,
'overwrite' => true
) );
if ($adapter->receive()) {
$message = "success";
} else {
$message = "fail";
}
return $message;
}
this will return
Array
(
[0] => Array
(
[0] => 1332977938.jpg
[1] => 1332977939.jpg
)
)
but only array[0][0] or 1332977938.jpg will actually get saves to the disk.
Why are they now both get saved? wired
any ideas?
I suspect the second call to uploadToDisk is returning fail because you can only call Zend_File_Transfer_Adapter_Http::receive() once for each file. Since you are not specifying a file when calling receive, it is receiving all of the files the first time you call uploadToDisk and subsequently is failing with a File Upload Attack error.
Here is some code you can try. This tries to receive each file individually and then save them one at a time with each call to uploadToDisk.
A few notes about the code:
The first parameter to uploadToDisk ($val) may need to be changed as I am not sure what the original values are. It should correspond to one of the element names used for the file upload (See Zend_File_Transfer_Adapter_Http::getFileInfo()) for a list of the files.
I changed the method for generating a unique filename so you don't have to sleep(1)
Zend_File_Transfer_Adapter_Abstract::setDestination() is deprecated and will go away in the future. Instead, just use the Rename filter. When using Rename, setDestination() has no effect.
And here it is...
<?php
$folderPath = '/var/www/';
if (is_array($multiUpload)){
$filenames = array();
foreach($multiUpload as $key => $val){
// get the file extension
$ext = explode('.', $val);
$ext = $ext[sizeof($ext) - 1];
// create custom file name
do {
$filename = uniqid(time()) . '.' . $ext;
$diskPath = $folderPath . $filename;
} while (file_exists($diskPath));
$filenames[$key] = $filename;
//send to the upload function
// $val is the file to receive, $diskPath is where it will be moved to
$this->uploadToDisk($val, $diskPath);
}
return $filename;
}
public function uploadToDisk($file, $filename)
{
// create the transfer adapter
// note that setDestination is deprecated, instead use the Rename filter
$adapter = new Zend_File_Transfer_Adapter_Http();
$adapter->addFilter('Rename', array(
'target' => $filename,
'overwrite' => true
));
// try to receive one file
if ($adapter->receive($file)) {
$message = "success";
} else {
$message = "fail";
}
return $message;
}