I am using Lumen and I have an audio file in my uploads/videos/. I want to return the URL of the exact path (like app.com/videos/one.mp4).
I have achieved same thing in a very bad-practiced way by putting /{fileName} in routes, giving /one.mp4 and by removing the extension from String as soon as I receive the data (one.mp4). This is a bad way because I'm using a plugin that only accepts direct links.
(So for example, when I take link from any mp4 link (with extension), it works, but when I try it with my method, it doesn't
I found this example for Laravel, however Lumen apparently doesn't accept ->where:
Route::get('file/{filename}', 'FileController#getFile')->where('filename', '^[^/]+$');
and
public function getFile($filename)
{
return response()->download(storage_path($filename), null, [], null);
}
But when I try it in Lumen, I receive:
Call to undefined method Laravel\Lumen\Application::where()
What is the way of setting a route that receives filename with extension as parameters and returns the mp4 file in directory. So basically, I want to hit url myapi.com/videos/two.mp4 and play two.mp4 as soon as I hit to the link.
(Please note that I store the filename in database without extension, just as two for two.mp4.)
Example link format: https://v.cdn.vine.co/r/videos/12B2B2092B1284614590713798656_4be40e9deb2.4.1.3029273185552527049.mp4
Update:
This below chunk plays the audio in Chrome but not the app, may it be because of the app itself rather than Lumen? But it's playing successfully the above Vine link.
$app->get('/player/{filename}', 'PlayerController#show')
public function show ($filename)
{
$this->playVid($filename, 'videos');
}
public function playVid($filename, $showType)
{
if (file_exists("../uploads/" . $showType . "/" . $filename)) {
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$type = finfo_file($finfo, "../uploads/" . $showType . "/" . $filename);
header("Content-Type: " . $type);
readfile("../uploads/" . $showType . "/" . $filename);
}
}
If so, what is the difference between my file & Vine file? When I open both of the videos in browser, right+click and check source, both videos have type="video/mp4"
More information on Question: https://stackoverflow.com/questions/34369823/same-video-from-my-api-url-doesnt-work-where-works-from-online-url-from-proj
Update: I realised my problem was caused because I was using readFile, but I wanted to use streaming. If you believe that's the problem, refer here - https://stackoverflow.com/a/34435905/4705339
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 am using drupal as a back end.
in drupal I get some .pdf files. and then zip them using drupal zip archive. then saving this archive in my server tmp folder, i get the tmp folder using php sys_get_temp_dir()
now...
what should i return to the front end (Angular) so that the user can download this folder..
this is an example code i used for zipping:
$nodesIds = [1024, 1023, 1022]; // those are just some example ids, i get the real ids from the front end post request.
$zipName = $this->generateUniqueName();
$zip = new \ZipArchive;if(!$zip->open(sys_get_temp_dir() . '/' . $zipName, constant("ZipArchive::CREATE"))) {
return new JsonResponse('could not open zip');
}
foreach ($nodesIds as $id) {
$node = \Drupal\node\Entity\Node::load($id);
$uri = $node->filed_file->entity->getFileUri();
$name = $node->field_file->entity->id() . '_'. $node->field_file->entity->getFilename();
$url = $file_system->realpath($uri);
$zip->addFile($url, $name);
}
$zip->close();
i tried returning a link to the zipped folder in the server:
return new JsonResponse(sys_get_temp_dir() . '/' . $zipName);
but i dont know what to do with that from angular.
Also tried to return a stream using symfony:
$stream = new Stream(sys_get_temp_dir() . '/' . $zipName);
$response = new BinaryFileResponse($stream);
a stream and not a file because the user chooses which files to zip.. so they can choose as much as they want.. it might get to even a 100 .pdf files ..
every thing works fine and i get the zipped folder in tmp.. but now what ?
I want to download this zipped folder to the user browser..
but I do not know how!. should I return the zipped folder, then in angular use it as a blob or somehow deal with it and serve it to the user,,
or maybe the right way is to send back the link to its location in the tmp folder,, and in angular i only access that location and somehow get the folder (i dont know if this is even possible due to permissions and security), or is there another better way that I do not know about.
thank you very much.
When i upload my files to the server, it works fine and displays in my public folder as img/php786W. I am currently trying to retrieve my folder but i get file not found on server.
In my controller, $filename is returning the original name of the file on the server. So it does not match to be found although it is the same file.
How can i get this done? I tried to use hashName() but that won't work
Controller
$file_path = public_path() . '/img/'. $filename;
if (file_exists($file_path->hashName()))
{
return Response::download($file_path, $filename, [
'Content-Length: '. filesize($file_path)
]);
}
else
{
// Error
}
Use
return response()->download($pathToFile);
If this does not work you have either permissions problem, or the file simply does not exist
See docs
I am making an external API call which returns several objects with download URL inside. Those are all PDF-s of which I would like to provide a single ZIP download link.
The way it works now is that I am downloading every single PDF to a specific user folder, and then making a ZIP out of it and presenting it back to user.
I see this as a somewhat slow and inefficient of doing things as the user will have to trigger another download for the ZIP, and this way I am making user wait basically for 2 downloads of the same file batch.
Is there a smarter way to deal with this?
$path = '/user_downloads/' . Auth::user()->id . '/';
if (!Storage::disk('uploads')->has($path)) {
Storage::disk('uploads')->makeDirectory($path);
}
$zipper = new \Chumper\Zipper\Zipper;
$zip_filename = 'zipped/' . uniqid() . '_merged.zip';
foreach (json_decode($res)->hits as $hit) {
$filename = public_path() . $path . uniqid() . '_file.pdf';
copy($hit->document_download_link, $filename);
$zipper->make($zip_filename)->add($filename);
}
The add method can receive an array of files, so, I would create the array of files inside the foreach and when finished, create the zip:
foreach (json_decode($res)->hits as $hit) {
copy($hit->document_download_link, $filename);
$files[] = public_path() . $path . uniqid() . '_file.pdf';
}
$zipper->make($zip_filename)->add($files);
This question has a couple of ways you could present the files to the user on by one but this is less user friendly and might get blocked by browsers.
You could probably also use JSZip (haven't looked too closely at it) but that would use the browser's RAM to compress the PDF's which is not ideal, especially on mobile devices.
I think your current solution is the best one.