I'm trying to upload some photos and handle this with the build in Laravel functions. But I can't for the life of me figure out how to do this properly. I have been able to actually upload something, but I've run into a few problems. This is the code I have right now:
If looked at the documentation, and found this function: $file = Input::file('photo'); I've used this function, and what the content of $file becomes is an instance of Symfony\Component\HttpFoundation\File\UploadedFile, which, as the documentation tells us, "extends the PHP SplFileInfo class and provides a variety of methods for interacting with the file." http://laravel.com/docs/4.2/requests#files
Then I used this function Input::file('photo')->move($destinationPath); which should but the file in the desired folder on the server. And it did. But now comes the problem. Now all uploaded files have a filename like phpgoJnLc, and without an extension.
I've looked at the functions available from SplFileInfo and tried getExtension which give me an empty string and getFilename which also gives me something like phpgoJnLc.
Then I looked around on the internet and found a few part of code from Laravel 3, where they did something like this:
$filename = Str::random(20) .'.'. File::extension(Input::file('photo.name'));
But the result of this is give me only the result from Str::random(20) followed by a dot. Again, no file extension.
So, what am I doing wrong? How to upload a file with Laravel 4?
Looking in that same class file I see a getClientOriginalName() function...
$file = Input::file('photo');
$file->move($destinationPath,$file->getClientOriginalName());
... which ais ssuming you want to keep the original name your client sets... which could be hazardous, do some safety checks on it would be my advice. Getting the extensionname only is done with ->getClientOriginalExtension(), so you could also only save that part & add a random string before that in the second argument of the move() function.
This worked for me, especially when you want to change the name of the uploaded image:
$filename = 'New_Name'.'.'.Input::file('photo')->getClientOriginalExtension();
You can also generate a name for the file with the original file extension like so:
$filename = Str::random(20) . '.' . Input::file('image')->guessExtension();
if you try to use the following in Laravel 4:
$filename = Str::random(20) .'.'. File::extension(Input::file('photo.name'));
you will get this error:
'Call to undefined method Illuminate\Filesystem\Filesystem::guessExtension()'
Related
(It's API only) I'm using JasperPHP to generate reports, the user can choose the extension (xls or pdf). After I process the data, then I save the file/report locally, it's in "storage/app/jasper/example1234.pdf".
So at the end of the function I do this:
// more code
$file = $path . $filename . '.' . $extension; // file path
// more code
return response()->file($file);
And it works, I can get the file using ReactJS. OK! But I wanted to delete the file before the "return", but if I do that the file will not be read on the "return". That's why I wanted to save it in a variable/memory first, delete the file locally and then return.
Note I tried to get the file using several methods, such as "Storage::get()", but they all generate errors on "return", stating that "string file" is expected but "resource" was given.
Response facade has deleteFileAfterSend() method. You can use it like the following:
return response()->file($file)->deleteFileAfterSend();
I have tried to setup an upload script in Laravel and have followed the instructions in the docs.
I created a Symlink using the Laravel script and it looks like the following
storage -> /Users/username/Sites/switch/storage/app/public
The problem arrives when I go to upload the image and then get result of the image url in return. As you can see to match the symlink I set the folder to be public below.
$path = $request->file('manufacturer_image_name')->store('public');
echo asset($path);
and this returns
http://127.0.0.1:8000/public/XxIX7L75cLZ7cf2xzejc3E6STrcjfeeu3AQcSKz1.png
the problem is this doesn't work and throws a 404 but if I manually change the url from "public" to "storage" it will find the image.
http://127.0.0.1:8000/storage/XxIX7L75cLZ7cf2xzejc3E6STrcjfeeu3AQcSKz1.png
Shouldn't
echo asset($path);
be returning a url containing storage instead of public?
assett($path) is for generating a URL for assets that are just in the public folder, things like the Mix generated CSS and JS files. If you user Laravel Storage to save the file, you also have to use Laravel storage to generate the file URL.
Storage::url('file.jpg');
Well, there are a lot of ways to do that, pick anyone which fits you best.
// using storage_path helper
storage_path('public/' . $filename);
// you could make a double-check with File::exist() method
$path = storage_path('public/' . $filename);
if (!File::exists($path)) {
abort(404);
}
// using asset helper
asset('storage/your_folder/image.png');
// using url helper
url('storage/your_folder/image.png');
// using Storage facade
Storage::url($photoLink)
Here is the simplest and exact thing for your issue
if(!empty($request->file('manufacturer_image_name'))){
$path = storage_path('public/image/');
$image_path = Storage::disk('public')->put('manufacturer_image_name', $request->file('manufacturer_image_name'));
//Assuming you have a model called Manufacturer and created $manufacturer = new Manufacturer()
$manufacturer->manufacturer_image_name = isset($image_path) ? "storage/".$image_path : "";
}
Thanks for the help, I discovered this answer the fits nearly perfectly what I am after. Laravel: Storage not putting file inside public folder
This was what I ended up with.
if($request->file('manufacturer_image_name')){
$path = Storage::disk('public')->put('logo', $request->file('manufacturer_image_name'));
echo $path;
}
$path now returns "logo/filename.ext" instead of "public/ or storage/" so I can store this directly in the db.
I have a function that will upload product images to dropbox after an order has been made in my website.
I customize the path name to :
$dropBoxRoot = '/Comp#'.$user['company_id'].'/Prop#'.$user['object_id'].'/Order#'.$orderId.'/'.$product;
I checked if the said path has existed by using the getDelta function.
//let's assume $this-client has already instantiated
$checkIfFolderExist = $this->client->getDelta(null, $dropBoxRoot);
After that, I uploaded that image by doing this:
//the actual path : /Comp#119/Prop#5/Order#120/Product1/image.png
$this->client->uploadFile($dropBoxRoot.'/'.$fileName, WriteMode::add(), $file, $size);
The image is uploaded in the dropbox. I can see it there inside the path but after uploading, the uploadFile function returns an exception:
(1/1) InvalidArgumentException
'path': bad path: must start with "/": "image.png"
in Path.php (line 141)
If anyone has the same situation, I would like to ask your advices. Thanks in advance!
I just found out that it will return the error if the path parameter is concatenated.
In uploadFile function, I made it like this:
$dropBoxRoot.'/'.$fileName
So I make a new variable to concatenate the final path:
$finalPath = $dropBoxRoot.'/'.$fileName;
$this->client->uploadFile($finalPath, WriteMode::add(), $file, $size);
And so it returns without the exception this time.
So I'm working on a basic file upload system that for the most part seems to be working. Most files go through perfectly and upload without a hitch, but for some reason, other files do not and I get the following error:
This isn't a permissions error as it does work for some files - I don't believe it to be a filesize or filetype issue either.
My upload method is as follows:
$file = Input::file('photo');
$destinationPath = 'user_img/';
$extension = $file->getClientOriginalExtension();
$rand = str_random(12);
$filename = 'usr_'. Auth::user()->id . '_str=' . $rand . '_file='. Crypt::encrypt($file->getClientOriginalName()) .'.'. $extension;
$upload_success = $file->move($destinationPath, $filename);
I'm not finding any solution on the web, and I can't figure out why it's throwing this exception. Any ideas?
I don't want to count all characters in the filename in the screenshot, but there could be an issue with the length of your file name. Wikipedia Filename - Length Restrictions
In my case, this was the issue: using reserved characters in a file name.
This is how i was getting the file name:
$photo_name = "User_".md5($user->id).'_'.date('Y-m-d H:i:s').".$ext";
This would mean that the eventual file name would have characters like -,: and _. On reading this Wikipedia article https://en.wikipedia.org/wiki/Filename#Reserved_characters_and_words , i realised that the : (colon) is a reserved character and once i got rid of it (by amending the timestamp section to date('Ymd_His'), the error was gone and the upload was successful.
Ah damn, it seems as my filelengths were over 255 characters and thus the filesystem wasn't liking it. I've changed from Crypt to MD5 and the issue is now resolved.
Something similar happened to me, the context was this: through the view I was loading a file through an input. When I tried to save the file to a folder, I got this error. I use laravel 9 with livewire.
In the end I just had to use the methods provided by liveware:
$filename = time() . $this->documento->getClientOriginalName();
$this->documento->storeAs('documents', $filename, 'public');
Fuentes: https://laravel-livewire.com/docs/2.x/file-uploads
The Problem
I'm having an issue with the PHP function is_file().
Some preliminaries: I'm developing on Ubuntu 12.04, 32-bit, using PHP 5.5.10 and Apache 2.4.9.
I'm currently rewriting some working code to convert it to a library in Laravel (completed with a Facade and a ServiceProvider). I'm doing this mainly to clean up some code I wrote when I was young and foolish (about 6 months ago) and to implement unit testing. The library I'm writing provides methods for taking a contract (of which there are two distinct types, with more to come) and finding the path to a PDF document (the scanned paper contract). My methods for finding the path work fine and the tests are all passing.
In my old code, I used to do this:
/**
* Get a scanned contract and return it to the client
*
* #param string $type
* The contract type. Must be either static::CONTRACT1 or static::CONTRACT2.
*
* #param string $contract_id
* The contract ID
*
* #return Response
*/
public static function get($type, $contract_id)
{
// get the file name
//
$results = static::getFileName($type, $contract_id);
// did we find a file? if not, throw a ScannedContractNotFoundException
//
if(!$results)
throw new \MyApplication\Exceptions\ScannedContractNotFoundException("No file found for $type contract $contract_id");
// get the path and file name
//
$path = $results['path'];
$name = $results['name'];
// get the full path
//
$file = $path.$name;
// get the file size
//
$contents = file_get_contents($file);
$fsize = strlen($contents);
// push the file to the client
//
header("Content-type: application/pdf");
header("Content-Disposition: inline; filename=\"".$name."\"");
header("Content-length: $fsize");
header("Cache-control: private");
echo $contents;
exit;
}
And it worked just fine.
Now I'm trying to rewrite it to get rid of the echo and move the code that actually does the work of sending the file to a controller. That code will look like this:
$x = \MyApplication\Models\Contract1::find($id);
$file = \ScannedContracts::getFileName($x);
$path = $file["path"].$file["name"];
return \Response::download($path, $file["name"]);
However, this code is throwing a FileNotFoundException. The code where the exception is being thrown looks like this:
public function __construct($path, $checkPath = true)
{
if ($checkPath && !is_file($path)) {
throw new FileNotFoundException($path);
}
...
Clearly the problem is with the if statement, and in particular the call to is_file().
I have written a little script to test this with a path which is known to be good and is_file() returns false.
When I copy a file to my "public" folder, it works fine.
In the documentation for the is_file() function there is a comment stating that the permissions for the parent folder must be +x. I've examined the permissions, and the folder is world-executable, as is the parent, and the grand-parent, and the great-grand-parent, etc.
There are two possible confounding factors: first, the files I'm working with are located on a CIFS/Samba share. I should mention that the paths in question are absolute paths to the mounted share.
The closest issue to this I've found on SO is PHP is_file returns false (incorrectly) for Windows share on Ubuntu, but that doesn't have a resolution. I've also searched for PHP bug reports, but there's nothing.
Second, some of the paths contain spaces. I've tried escaping them every way I can think of, but it doesn't help.
In the absence of a solution, I'll have to do it the old fashioned way, but I really wanted to do it using the functions Laravel provides.
Questions
Do I need to escape spaces in a path passed to is_file()?
Does anyone know of a fix or a workaround that doesn't a) require changing code in a 3rd party library, or b) require wholesale changes to permissions or other configuration on the CIFS/Samba server?
Thanks in advance!
I think you need to sanitize filenames when upload to directory
function sanitize_file_name( $str ) {
return preg_replace("/[^a-z0-9\.]/", "", strtolower($str));
}