response::download is doing nothing - laravel-4

I am having problems getting files to download outside of the public folder. Here is the Scenario:
These files cannot be accessed from anywhere but through this application and these downloads must go through access control. So a user can't download the file if they are not logged in and have permission to.
I have a route defined with a get variable. This ID goes into the controller and the controller calls the method below:
public static function downloadFile($id){
$file = FileManager::find($id);
//PDF file is stored under app/storage/files/
$download= app_path().substr($file->location,6);///home/coursesupport/public_html/app/storage/files/fom01/7-2/activities-and-demos.pdf
$fileName = substr($download,strrpos($download,'/')+1);//activities-and-demos.pdf
$mime = mime_content_type($download);//application/pdf
$headers = array(
'Content-Type: '.$mime,
"Content-Description" => "File Transfer",
"Content-Disposition" => "attachment; filename=" . $fileName
);
return Response::download($download, $fileName, $headers);
}
the problem is it does nothing, just opens a blank page. Am I missing something? oh yeah, and the link to the route mentioned above opens a blank tab.
I appreciate any help. Thanks!

It should work by doing only this:
public static function downloadFile($id)
{
$file = FileManager::find($id);
$download= app_path().substr($file->location,6);
$fileName = substr($download,strrpos($download,'/')+1);
return Response::download($download, $fileName);
}

Make sure your route is actually returning the returned response. Eg:
Route::get('download', function()
{
return DownloadHandler::downloadFile(1);
});
Without the return in the route the IlluminateResponse will do nothing.

Related

Are laravel's routes safeguarding enough against file traversal attacks?

Route::get('/transaction/{name}', 'TransactionController#download');
public function download($name){
$path = storage_path('app/something/') . $name . '.xml';
return response()->download($path);
}
The user shall using this action only be able to download .xml files in app/something.
Is it possible to to download data outside of the specified app/something folder.
Laravel doesn't protect against traversal attacks - the router will return any value with your code example, meaning that someone could get access to your filesystem!
You an use PHP's basename() to sanitise $name by removing any path references from the string:
Route::get('/transaction/{name}', 'TransactionController#download');
public function download($name){
$path = storage_path('app/something/') . basename($name, '.xml') . '.xml';
return response()->download($path);
}
As far as i know Laravel will compile your path to:
#^/transaction/(?P<name>[^/]++)$#s
So simple / will not not work..
You could use more sophisticated backslash - but it depends on server..
At the end - Remember not to trust all user input.. No matter does it goes through routing or received directly..
Updated answer
As you can see below, it's definitely possible to do malicious stuff within Laravel routes. Given your function setup, the chance of someone doing something you don't want is small, because he/she can only alter the $name variable.
You can still write some extra code like this (found on viblo.asia):
$basepath = '/foo/bar/baz/'; // Path to xml file
$realBase = realpath($basepath);
$userpath = $basepath . $_GET['path'];
$realUserPath = realpath($userpath);
if ($realUserPath === false || strpos($realUserPath, $realBase) !== 0) {
//Directory Traversal!
} else {
//Good path!
}
To prevent users from accessing files they aren't allowed to.
Old, but relevant answer
Just tried this in Homestead:
Route::get(
'/',
function () {
dump(exec('ls ' . storage_path() . '/../../../'));
}
);
And that prints the corresponding folder just fine:
So I'd say that it's definitely possible to do stuff outside of the specified folder. Try this for yourself for example:
Route::get(
'/',
function () {
for ($i = 0; $i < 10; $i++) {
$path = str_repeat('/..', $i);
dump(exec('ls ' . storage_path() . $path));
}
}
);
And see your folders appear on screen when you hit the / route.

How to display file which had already upload laravel 5.2?

I upload file in to my database and moved that file as same name in documents folder in a root path like below :)
public function store(PslCall $call,Request $request)
{
$this->validate($request, $this->rules);
$uploadDestinationPath = base_path() . '/documents/';
$current_id = Document::where('call_id',$call->id)->count()+1;
if ($request->hasFile('file'))
{
$file =$request->file;
$fileName = $file->getClientOriginalName();
$file->move($uploadDestinationPath, $call->id.'_'.$current_id.'_'.$fileName);
}
$input = $request->all();
$input['file'] = $call->id.'_'.$current_id.'_'.$fileName;
$input['call_id'] = $call->id;
Auth::user()->documents()->create($input);
return Redirect::route('calls.documents.index',$call->id)->with('message','You have successfully submitted');
}
its works perfect now im display in my index page all the files like below :)
<td>{{strtoupper($document->title)}}</td>
<td>{{$document->file}}</td>
now my route file i have route to display my file like this :
Route::get('documents/{file}',function() {
return 'hi';
});
here im getting hi output when i click <td>{{$document->file}}</td> this path
but i want know how to display file which i upload same file name ?
As documentation says if you want to display the file content then you may use inside your route function something like:
return response()->file('pathToFile');
If download the file is what you want, then try to use instead:
return response()->download('pathToFile');

return file response in laravel not working

I'm using laravel 5.2 , I've used response()->file() function to return file. On localhost it is working as expected but on live server file is being downloaded automatically (with no extension). But i wish to open it instead of downlod. Anyone can help?
Here is my code:
public function returnFile($slug)
{$file = Mixes::where('id_name,'=',$slug)->get()->first();
return response()->file('./path/to/file/'.$file->name);}
Thanks.
You'll need to add header to your response.
Response with header example:
$response->header('Content-Type', 'application/pdf');
Simple example:
$file = File::get($file);
$response = Response::make($file, 200);
$response->header('Content-Type', 'application/pdf');
return $response;
Then the file will display in your browser window.
This solution will work with files pdf,docx,doc,xls.
Hope it will help!

Unlink, image into directory

I have a file called delete.php inside where I created this code:
// check if the 'id' variable is set in URL, and check that it is valid
if (isset($_GET['id']) && is_numeric($_GET['id']))
{
// get id value
$id = #$_GET['id'];
$img = #$_GET['h_image'];
if(file_exists($img)){
unlink('../images/'.$img);
}
// delete the entry
$result = DB::table('questions')
->where('id', '=', $id)
->delete();
// redirect back to the view page
header("Location: index.php");
}
else
// if id isn't set, or isn't valid, redirect back to view page
{
header("Location: index.php");
}
The content is properly deleted from the database, but unfortunately I can not erase the image corresponding to the directory "images".
I tried with unlink, but by mistake.
How can I do?
Obviously the image must match the content to be deleted.
Thanks guys, I hope for your help.
I did so, but always from tabase but not delete the image from the directory:
Maybe I'm wrong path of the image? The GET?
// get id value
$id = #$_GET['id'];
$path = #$_GET['img'];
if(file_exists($path))
unlink("images/".$path);

Laravel 4 get image from url

OK so when I want to upload an image. I usually do something like:
$file = Input::file('image');
$destinationPath = 'whereEver';
$filename = $file->getClientOriginalName();
$uploadSuccess = Input::file('image')->move($destinationPath, $filename);
if( $uploadSuccess ) {
// save the url
}
This works fine when the user uploads the image. But how do I save an image from an URL???
If I try something like:
$url = 'http://www.whereEver.com/some/image';
$file = file_get_contents($url);
and then:
$filename = $file->getClientOriginalName();
$uploadSuccess = Input::file('image')->move($destinationPath, $filename);
I get the following error:
Call to a member function move() on a non-object
So, how do I upload an image from a URL with laravel 4??
Amy help greatly appreciated.
I don't know if this will help you a lot but you might want to look at the Intervention Library. It's originally intended to be used as an image manipulation library but it provides saving image from url:
$image = Image::make('http://someurl.com/image.jpg')->save('/path/saveAsImageName.jpg');
$url = "http://example.com/123.jpg";
$url_arr = explode ('/', $url);
$ct = count($url_arr);
$name = $url_arr[$ct-1];
$name_div = explode('.', $name);
$ct_dot = count($name_div);
$img_type = $name_div[$ct_dot -1];
$destinationPath = public_path().'/img/'.$name;
file_put_contents($destinationPath, file_get_contents($url));
this will save the image to your /public/img, filename will be the original file name which is 123.jpg for the above case.
the get image name referred from here
Laravel's Input::file method is only used when you upload files by POST request I think. The error you get is because file_get_contents doesn't return you laravel's class. And you don't have to use move() method or it's analog, because the file you get from url isn't uploaded to your tmp folder.
Instead, I think you should use PHP upload an image file through url what is described here.
Like:
// Your file
$file = 'http://....';
// Open the file to get existing content
$data = file_get_contents($file);
// New file
$new = '/var/www/uploads/';
// Write the contents back to a new file
file_put_contents($new, $data);
I can't check it right now but it seems like not a bad solution. Just get data from url and then save it whereever you want

Resources