Laravel + Image Intervention : Force download of file that is not saved - laravel

I want to simply upload files , resize them and then force a download for every uploaded file. I do not want to save the files.
Resizing etc. works fine, however I cannot manage to force the download of the new file.
$content = $image->stream('jpg');
return response()->download($content, $name);
The shown snippet results in
is_file() expects parameter 1 to be a valid path, string given
Most probably because $content is not a path but the actual data.
Is there a way to enforce the download without saving it first?

Try this:
$url = "https://cdn.psychologytoday.com/sites/default/files/blogs/38/2008/12/2598-75772.jpg";
$name = 'happy.jpg';
$image = Image::make($url)->encode('jpg');
$headers = [
'Content-Type' => 'image/jpeg',
'Content-Disposition' => 'attachment; filename='. $name,
];
return response()->stream(function() use ($image) {
echo $image;
}, 200, $headers);
Here's what we're doing. We're using Intervention Image to encode that image into the correct file type format for us. Then we're setting the browser headers ourselves to tell the browser what type of file it is and that we want the browser to treat it as a downloadable attachment. Lastly, we return the response using Laravel's stream() method and use a closure. We tell the closure it has access to the encoded data of the image with use ($image) and then we simply echo that raw data onto the page. From there we tell the browser the HTTP code is 200 (OK), and then give it our headers to tell the browser what to do.
Your problem was that Laravel's handy download() method is expecting it to be a file on the file system. So we have to stream it and manually set the headers ourselves.
You will need to write some additional code to handle different file extensions for the encode() method Intervention uses as well as the Content-Type returned. You can find a list of all available mime types here.
I hope this helps.
Edit: Later versions of Laravel introduced the deleteFileAfterSend() method on the response object. If you are okay with temporarily saving the file to the server you can do this:
return response()->download($path)->deleteFileAfterSend();

Related

Access multiple file upload with laravel

I have a form in my vue.js frontend where i upload multiple images and asynchronously send it to the backend.
But it seems laravel cant understand it as a file because it's more than one.. And it works fine if it was just a single image without multiple attribute attached to the input field.By the way, i used form data to process the form.. Even tried to stringify the array of files and decode it in the backend still doesnt work.. It is processing it as a strings. When i loop through the files and try to use the function getClientOriginalName() (as i would with single upload) i get 'Call to undefined method stdClass::getClientOriginalName()'.. Also figured that the stdClass is an obj of numbers when i checked..
Below is my code.
let product_img_array = this.image_data.map(item => item.file);
let payload = new FormData;
payload.append("all_images", JSON.stringify(product_img_array));
Backend:
foreach (json_decode(request()->all_images) as $key => $value) {
dd($value->getClientOriginalName()); //this returns the error i mentioned above
dd($value);//this returns {#325} as i said earlier.
}
What is it i'm doing wrongly, probably there is a way of doing this and i'm off track. Please your help is appreciated ..

Laravel download pdf file stored in separate Laravel app

I have 2 Laravel(5.8) apps. One is a user application, the other is more of an API.
The Api has pdfs stored in the storage directory, I need to be able to allow a user to download the pdfs in the other application.
Really got no clue how to send the file over from app to the other.
The user app makes an api to the api with relevant file ids and things (fine), just can't work out how to send the file back, and then download it on the other end.
Tried things like return response()->stream($pdf) on the api and return response()->download($responeFromApiCall) and loads of other things but really getting nowhere fast.
Any advice welcome.
The laravel code you posted is basically correct, you can use one of stream(), download() or file() helper to serve a file.
file()
Serve a file using a binary response, the most straightforward solution.
// optional headers
$headers = [];
return response()->file(storage_path('myfile.zip'), $optionalHeaders);
You can also use your own absolute file path instead of the storage_path helper.
download()
The download helper is similar to file(), but it also sets a Content-Disposition header which will result in a download-popup if you retrieve the file using your browser.
$location = storage_path('myfiles/invoice_document.pdf');
// Optional: serve the file under a different filename:
$filename = 'mycustomfilename.pdf';
// optional headers
$headers = [];
return response()->download($location, $filename, $headers);
stream()
The stream() helper is a bit more complex and results in reading and serving a file in chunks. This can be used for situations where the filesize is unknown (like passing through another incoming stream from an API). It results in a Transfer-Encoding: chunked header which indicates that the data stream is divided into a series of non-overlapping chunks:
// optional status code
$status = 200;
// optional headers
$headers = [];
// The stream helper requires a callback:
return response()->stream(function() {
// Load a file from storage.
$stream = Storage::readStream('somebigfile.zip');
fpassthru($stream);
if(is_resource($stream)) {
fclose($stream);
}
}, $status, $headers);
Note: Storage::readStream takes the default storage disk as defined in config/filesystems.php. You can change disks using Storage::disk('aws')->readStream(...).
Retrieving your served file
Say your file is served under GET example.com/file, then another application can retrieve it with curl (assuming PHP). A popular wrapper for this would be Guzzle:
$client = new \GuzzleHttp\Client();
$file_path = __DIR__ . '/received_file.pdf';
$response = $client->get('http://example.com/file', ['sink' => $file_path]);
You can derive the filename and extension from the request itself by the way.
If your frontend is javascript, then you can retrieve the file as well but this another component which I dont have one simple example for.
So if I understand correctly you have two systems: user app and api. You want to serve a pdf from user app to the actual user. The user app does a call to api, which works fine. Your issue is converting the response of the api to a response which you can serve from your user app, correct?
In that case I'd say you want to proxy the response from the api via the user app to the user. I don't know what the connection between the user app and the api is, but if you use Guzzle you could look at this answer I posted before.
Here are the steps you should follow to get the PDF:
Make an API call using AJAX ( you are probably already doing it ) from your public site ( User site ) to the API server, with file ID.
API server fetches the PDF, copy it to the public/users/ directory, generate the URL of that PDF file.
Send the URL as a response back to the User site. Using JS add a button/ link in the DOM, to that PDF file.
Example:
jQuery.post(ajaxurl, data, function(response) {
var responseData = JSON.parse(response);
var result = responseData.result;
var pdf_path = responseData.pdf_path;
$(".nametag-loader").remove();
$(".pdf-download-wrapper").append("<a class='download-link' href='"+ pdf_path +"' target='_blank'>Download</a>");
});

Using Perl, How do I save an image from an external script (PHP) URL

I have a Perl script that needs to retrieve an image from an external URL and save it locally. In some cases, the URL is a direct URL to a PNG file and my code works perfectly to capture the image data and save it locally.
My Perl code looks like this:
$ua = LWP::UserAgent->new();
$ua->agent("MyAgent");
$response = $ua->get($iconpath);
$content = $response->decoded_content(charset => 'none');
open(ICONFILE, ">$localimagefile");
binmode(ICONFILE);
print ICONFILE $content;
close(ICONFILE);
But in some cases, the URL for the image on the external site (iconpath) is a PHP script, like this:
http://forecast.weather.gov/DualImage.php?i=sct&j=hi_tsra&jp=30
In this case, the local image file is created, but it's zero bytes. When I try to dump $content after the request, it's empty and it's length is zero. For a direct URL to a PNG file, this same code works perfectly and saves a valid copy of the image file on the server.
I've tried various methods using wget, curl, backticks, and LWP:Simple (getstore), but I always have the same empty file results with the images generated externally using the PHP URL.
Any ideas how to do this would be greatly appreciated.
The problem was that the actual data returned from the weather API had the "&" character replaced by the HTML entity code & amp ; (ignore spaces -- added so it shows up here). I didn't notice this when I dumped the returned URL to the browser since it simply displayed as a regular ampersand (&). The simple solution was to replace the HTML entities with actual ampersand characters before calling the ->get with that URL, which works perfectly and returns the image data or saves it directly when using ":content_file => $filename" in the ->get call.

Receiving binary data using enyo.Ajax

I am trying to download a image, which is nothing but a chunk of binary data, using imagelink. For downloading i am using enyo.Ajax module. It is giving back an warning : "Ajax request set to handleAs JSON but data was not in JSON format " .
following is what i have implemented till now.
enyo.kind({
name:"enyo.sample.ajaxapp",
components:[
{kind:"onyx.Input",name:"urlinput", placeholder:"Input URL",classes:"input"},
{kind:"onyx.Button",name:"download",ontap:"fetch",classes:"button",content:"Fetch"},
{kind:"enyo.Control",name:"image",tag:"img",classes:"image"}
],
fetch:function(inSender,inEvent){
var ajax= new enyo.Ajax({
url:this.$.urlinput.getValue(),
handleAs:'blob'
});
ajax.go();
ajax.responseType='blob';
ajax.response(this,"processResponse");
ajax.error(this,"errorResponse");
},
processResponse:function(inSender,inResponse){
var img=this.$.image;
var blob=inResponse;
//var data=window.URL.createObjectURL(blob);
img.setSrc(blob);
},
errorResponse:function(inSender,inResponse){
console.log("error occured");
}
});
I wants to know whether is it not possible to get data apart from json/text/xml? If not, then how can i modify my code to get it downloaded. By default all the data received as JSON, so i am setting handleAs to bolb while creating ajax object. Do i need to change contentType or something else.
I don't think Ajax is the best way to request image data. You have (at least) two solutions:
Set the src attribute on an <img> tag and use onload to know
when the resource was downloaded.
Base 64 encode the image from the
server and set the src as the encoded data plus the appropriate
header info.
See this question for more details: Asynchronously load images with jQuery

External Links in CodeIgniter

I have the following code:
<div><strong>Name: </strong><?php echo anchor('http://'.$link, $row->Name); ?></div>
Which takes a users input for a link ($link) and puts the url into an anchor tag. It, however, is not redirecting to the external link but simply amending the base url for the site with the stored URL. I attempted to add 'http://' to the beginning of the submitted link which works unless the user has already supplied http in the link input. Any advice on how to overcome this would be amazing.
Yes, per the documentation, anchor() creates links based on your site's URL.
If things are working as expected when URL's are prefixed with http://, but you're having trouble with users sometimes adding http:// and sometimes not, you could simply check the link to determine whether it's ok, or if you need to prefix it. Here's a basic example using strpos:
if(strpos($link, 'http') === FALSE){
// link needs a prefix...
$link = 'http://' . link;
} else {
// link is ok!
}
...use CodeIgniter's prep_url() function (thanks to #cchana for reminding me of it!):
This function will add http:// in the event that a scheme is missing from a URL. Pass the URL string to the function like this:
$url = "example.com";
$url = prep_url($url);

Resources