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
Related
first of all to explain what I mean by my question, when I upload my files to the local storage I save them the following way:
$files = $request->file('files');
if ($request->hasFile('files')) {
foreach ($files as $file) {
//Get filename with the extension
$fileNameWithExt = $file->getClientOriginalName();
//Filename to store example: lead_4_document.pdf
$fileNameToStore = 'lead_' . $lead->id . '_' . $fileNameWithExt;
//Upload image
$path = $file->storeAs('/user_uploads', $fileNameToStore);
$lead->uploadFile()->create(array('filename' => $fileNameToStore, 'file_url' => $path, 'lead_id' => $lead->id));
}
}
So essentially I prepend lead_ the lead id and another _ to whatever the file is originally called during upload. The problem I face now is that I need to retrieve the associated files according to my lead ids. Here is my attempt so far:
$searchParam = 'lead_'.$lead->id.'_';
//$fileNames = File::glob('storage/user_uploads/'.$searchParam.'*');
//$files = File::get($fileNames);
$allFiles = Storage::files('user_uploads');
dd($allFiles);
Just to clarify, the 'File::glob' way seems to work, though it only outputs the names of the files not the actual files as object, which is what I need.
Okay, so I took a step back and went about this whole associated uploaded file to lead relationship a different way. Here is how I did it, just in case anyone stumbles across this and find themselves in the same boat as me.
The file upload now does a couple of things:
//check if file(s) is present in the request
if ($request->hasFile('files')) {
//checks if a directory already exists for a given lead (by id)
if (Storage::exists('/leads/'.$request->lead_id)) {
//if yes set the directory path to the existing folder
$directory = '/leads/'.$request->lead_id;
}
else {
//if not create a new directory with the lead id
Storage::makeDirectory('/leads/'.$request->lead_id);
$directory = '/leads/'.$request->lead_id;
}
foreach ($files as $file) {
//Get filename with the extension
$fileNameWithExt = $file->getClientOriginalName();
//Filename to store example: lead_4_document.pdf
$fileNameToStore = 'lead_' . $lead->id . '_' . $fileNameWithExt;
//Upload image
//'/user_uploads'
$file->storeAs($directory, $fileNameToStore);
//$lead->uploadFile()->create(array('filename' => $fileNameToStore, 'file_url' => $path, 'lead_id' => $lead->id));
}
}
So essentially, instead of trying to put all files into a single folder then checking the individual files for the 'lead_##' prepend, I instead create a folder with the id of the lead, this I then use the following way in my view function:
$directory = '/leads/'.$lead->id;
if (Storage::exists($directory)) {
$files = File::files('storage/'.$directory);
}
else {
$files = '';
}
Simply checking if the directory exists with the given lead ID, then if there are files uploaded either assign it the content, or set it blank (this is used for displaying an 'attachments' section on my page if not empty).
This is my upload php:
if (trim($_FILES['path_filename']['name']))
{
if (File::upload($_FILES['path_filename'], dirname(realpath(__FILE__)) . '/../tests'))
{
$test->setPathFilename('../tests/' . $_FILES['path_filename']['name']);
}
}
}
else
{
if ($aux)
{
$aux = str_replace("\\", "/", $aux);
$aux = preg_replace("/[\/]+/", "/", $aux);
$test->setPathFilename($aux);
}
}
$_POST["upload_file"] = $test->getPathFilename();
This above code is working well, I mean, upload to server is working and also getting Path File Name and insert into sql table is working too.
Example: When I upload a file for example: ABC.jpg , it will upload to tests folder and also Path File Name is (( ../tests/ABC.jpg )) and it will insert to sql table.
The problem is here:
I changed global function to rename files automatically by using this following code:
Before It was:
$destinationName = $file['name'];
I changed it to:
$ext = pathinfo($file["name"], PATHINFO_EXTENSION);
$destinationName = sha1_file($file["tmp_name"]).time().".".$ext;
Now, After upload file to tests folder, it will be renamed automatically, but still Path File name is same, It's ABC.jpg not renamed file in tests folder.
How to get Renamed Path File Name ???
I really appreciate your help on this issue.
Thanks in advance
Use basename() to get the filename from a path.
$filename = basename('/path/to/file.ext');
This will give you: file.ext
To rename the path file name you could use this:
if ( !file_exists( $path ) ) {
mkdir( $path, 0777, true );
}
This will make sure the path exist and if it doesn't it will created. Now we can rename()
rename( __FILE__ "/new/path/".$file_name );
This will move it between directories if necessary.
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.
I am able to get the web path to the file like so:
$filename = 'elephant.jpg';
$path_to_file = $this->getSkinUrl('manufacturertab');
$full_path = $path_to_file . '/' . $filename;
But if the file doesn't exist, then I end up with a broken image link.
I tried this:
if(!file_exists($full_path)) {
Mage::log('File doesn\'t exist.');
} else {
?><img src="<?php echo $full_path ?>" /><?php
}
Of course that didn't work because file_exists does not work on urls.
How do I solve this?
1.)
Can I translate between system paths and web urls in Magento?
e.g. something like (pseudocode):
$system_path = $this->getSystemPath('manufacturertab');
That looks symmetrical and portable.
or
2.)
Is there some PHP or Magento function for checking remote resource existence? But that seems a waste, since the resource is really local. It would be stupid for PHP to use an http method to check a local file, wouldn't it be?
Solution I am currently using:
$system_path = Mage::getBaseDir('skin') . '/frontend/default/mytheme/manufacturertab'; // portable, but not pretty
$file_path = $system_path . '/' . $filename;
I then check if file_exists and if it does, I display the img. But I don't like the asymmetry between having to hard-code part of the path for the system path, and using a method for the url path. It would be nice to have a method for both.
Function
$localPath = Mage::getSingleton( 'core/design_package' )->getFilename( 'manufacturertab/' . $filename, array( '_type' => 'skin', '_default' => false ) );
will return the same path as
$urlPath = $this->getSkinUrl( 'manufacturertab/' . $filename );
but on your local file system. You can omit the '_default' => false parameter and it will stil work (I left it there just because getSkinUrl also sets it internaly).
Note that the parameter for getSkinUrl and getFilename can be either a file or a directory but you should always use the entire path (with file name) so that the fallback mechanism will work correctly.
Consider the situation
skin/default/default/manufacturertab/a.jpg
skin/yourtheme/default/manufacturertab/b.jpg
In this case the call to getSkinUrl or getFilename would return the path to a.jpg and b.jpg in both cases if file name is provided as a parameter but for your case where you only set the folder name it would return skin/yourtheme/default/manufacturertab/ for both cases and when you would attach the file name and check for a.jpg the check would fail. That's why you shold always provide the entire path as the parameter.
You will still have to use your own function to check if the file exists as getFilename function returns default path if file doesn't exist (returns skin/default/default/manufacturertab/foo.jpg if manufacturertab/foo.jpg doesn't exist).
it help me:
$url = getimagesize($imagepath); //print_r($url); returns an array
if (!is_array($url))
{
//if file does not exists
$imagepath=Mage::getDesign()->getSkinUrl('default path to image');
}
$fileUrl = $this->getSkinUrl('images/elephant.jpg');
$filePath = str_replace( Mage::getBaseUrl(), Mage::getBaseDir() . '/', $fileUrl);
if (file_exists($filePath)) {
// display image ($fileUrl)
}
you can use
$thumb_image = file_get_contents($full_path) //if full path is url
//then check for empty
if (#$http_response_header == NULL) {
// run check
}
you can also use curl or try this link http://junal.wordpress.com/2008/07/22/checking-if-an-image-url-exist/
Mage::getBaseDir() is what you're asking for. For your scenario, getSkinBaseDir() will perform a better job.
$filename = 'elephant.jpg';
$full_path = Mage::getDesign()->getSkinBaseDir().'/manufacturertab/'.$filename;
$full_URL=$this->getSkinUrl('manufacturertab/').$filename;
if(!is_file($full_path)) {
Mage::log('File doesn\'t exist.');
} else {
?><img src="<?php echo $full_URL ?>" /><?php
}
Note that for the <img src> you'll need the URL, not the system path. ...
is_file(), rather than file_exists(), in this case, might be a good option if you're sure you're checking a file, not a dir.
You could use the following:
$file = 'http://mysite.co.za/files/image.jpg';
$file_exists = (#fopen($file, "r")) ? true : false;
Worked for me when trying to check if an image exists on the URL
I made Joomla admin component according to Joomla guide - http://docs.joomla.org/Developing_a_Model-View-Controller_Component/2.5/Developing_a_Basic_Component
In that i need to have file uploader which let user to upload single file.
In administrator\components\com_invoicemanager\models\forms\invoicemanager.xml i have defined
<field name="invoice" type="file"/>
In the controller administrator\components\com_invoicemanager\controllers\invoicemanager.php im trying to retrieve that file like below. But its not working (can't retrieve file)
Where am i doing it wrong ?
How can i get file and save it on disk ?
class InvoiceManagerControllerInvoiceManager extends JControllerForm
{
function save(){
$file = JRequest::getVar( 'invoice', '', 'files', 'array' );
var_dump($file);
exit(0);
}
}
make sure that you have included enctype="multipart/form-data" in the form that the file is being submitting. This is a common mistake
/// Get the file data array from the request.
$file = JRequest::getVar( 'Filedata', '', 'files', 'array' );
/// Make the file name safe.
jimport('joomla.filesystem.file');
$file['name'] = JFile::makeSafe($file['name']);
/// Move the uploaded file into a permanent location.
if (isset( $file['name'] )) {
/// Make sure that the full file path is safe.
$filepath = JPath::clean( $somepath.'/'.strtolower( $file['name'] ) );
/// Move the uploaded file.
JFile::upload( $file['tmp_name'], $filepath );}
Think i found the solution :)
$file = JRequest::getVar('jform', null, 'files', 'array');
Saving part is mentioned here - http://docs.joomla.org/Secure_coding_guidelines
For uploading the file from your component, you need to write your code in the controller file and you can extend the save() method. check the code given below -
public function save($data = array(), $key = 'id')
{
// Neccesary libraries and variables
jimport('joomla.filesystem.file');
//Debugging
ini_set("display_error" , 1);
error_reporting(E_ALL);
// Get input object
$jinput = JFactory::getApplication()->input;
// Get posted data
$data = $jinput->get('jform', null, 'raw');
$file = $jinput->files->get('jform');
// renaming the file
$file_ext=explode('.',JFile::makeSafe($file['invoice']['name'])); // invoice - file handler name
$filename = round(microtime(true)) . '.' . strtolower(end($file_ext));
// Move the uploaded file into a permanent location.
if ( $filename != '' ) {
// Make sure that the full file path is safe.
$filepath = JPath::clean( JPATH_ROOT."/media/your_component_name/files/". $filename );
// Move the uploaded file.
if (JFile::upload( $file['invoice']['tmp_name'], $filepath )) {
echo "success :)";
} else {
echo "failed :(";
}
$data['name'] = $filename ; // getting file name
$data['path'] = $filepath ; // getting file path
$data['size'] = $file['invoice']['size'] ; // getting file size
}
JRequest::setVar('jform', $data, 'post');
$return = parent::save($data);
return $return;
}
Joomla 2.5 & 3 style:
$app = JFactory::getApplication();
$input = $app->input;
$file= $input->files->get('file');
if(isset($file['name']))
{
jimport('joomla.filesystem.file');
$file['name'] = strtolower(JFile::makeSafe($file['name']));
$fileRelativePath = '/pathToTheRightFolder/'.$file['name'];
$fileAbsolutePath = JPath::clean( JPATH_ROOT.$fileRelativePath);
JFile::upload( $file['tmp_name'], $fileAbsolutePath );
}
http://docs.joomla.org/How_to_use_the_filesystem_package
has a full upload sample.
Little sample where admin choose the file type or all, enter the users to access the form upload. Folder to upload files in Joomla directory or with absolute path. Only selected users access the form upload.