Render view after image file is downloaded in Yii - php

public function actionViewDownload(){
// some in internal processing php commands (no echo)
exec($command); // command to be executed compulsary
$file = "/images/sample.jpg"; // some images file
if (file_exists($file)) {
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename='.basename($file));
header('Content-Transfer-Encoding: binary');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($file));
readfile($file);
}
$this->render('view',array('data'=>$data)); // render the other view of the controller after/during download.
}
I need to execute a command, then download the image file and after or during downloading render, the view.
If I render the view before downloading it prompts "Header cannot be modified. Headers already sent"
and if I render the view after the download then view is now shown on browser but the file gets downloaded.
My question here is that how can I achieve three tasks : execution of the command (this must be first), render and download.

By the looks of it you are trying to do something like sourceforge does when you ask to download a project where the deliverable is pushed to the user as the page is rendered.
I am assuming that the exec generates the image.
You really need to split this into 2 actions:
public function actionViewDownload(){
// some in internal processing php commands (no echo)
exec($command); // command to be executed compulsory
$file = "/images/sample.jpg"; // some images file
$this->render('view',array(
'data'=>$data,
'img'=>$file)
);
}
Then the view contains something like:
<img src="<?php echo controller/getdeliverible?file=$img; ?>"/>
which in turn calls:
public function actionGetDeliverible($file){
if (file_exists($file)) {
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename='.basename($file));
header('Content-Transfer-Encoding: binary');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($file));
readfile($file);
}
}
My above code is rough (you'll have to fill it in properly) but you get the idea. Basically as the view is rendered the image will pop up and ask you to save it. It will appear to the user that both things are happening together.
The nice thing about doing it this way is that you can do something after you have read the image to the user like delete it if it was a temporary file so it can't be downloaded again.

Related

Problem Opening a PDF File with Adobe Reader That Is Downloaded from MySQL database via PHP

I have written some PHP code that downloads a PDF file from a MySQL database on a server. The code works great and I can view/download/open the PDF file from various browsers. However, when I download the file and try to open up via Adobe Reader I get a message that says the file could not be opened because "because it is either not a supported file type or because the file has been damaged (for example, it was sent as an email attachment and wasn't correctly decoded)"
I am sure it is something dumb that I am forgetting to do in my code. Below is the PHP code that I am using:
// Downloads files
if (isset($_GET['scenario_id'])) {
$scenario_id = $_GET['scenario_id'];
// fetch file to download from database
$sql = "SELECT * FROM market_plans_pdfs WHERE scenario_id=$scenario_id";
$result = mysqli_query($connect, $sql);
$file = mysqli_fetch_assoc($result);
$pdf_file=$file['pdf_file'];
$filename=$file['scenario_name'];
if (isset($filename)) {
header('Content-Description: File Transfer');
header('Content-Type: application/pdf');
header('Content-Disposition: inline; filename="'.basename($filename).'"');//set content-disposition as "inline" as opposed to "attachment" so that it opens first in the browser
header('Content-Transfer-Encoding: binary');
header('Accept-Ranges: bytes');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
#readfile("data:application/pdf;base64,$pdf_file");
}
}
Any help would be appreciated as I have tried various solutions online with no success.
When you are changing some headers you have to do it before any output, because header must be sent at the beginning, for example:
This is invalid:
echo 'Test';
header('Content-Description: File Transfer');
Thats not your case, but you do similar mistake, on the other end.
When you are printing a file data, for example, as you do in your question, there is no function to tell that "your data ends here", just whole output is taken as file.
If you can't separate your file transfer from other output there is simple solution, try it out:
if (isset($filename)) {
header('Content-Description: File Transfer');
header('Content-Type: application/pdf');
header('Content-Disposition: inline; filename="'.basename($filename).'"');//set content-disposition as "inline" as opposed to "attachment" so that it opens first in the browser
header('Content-Transfer-Encoding: binary');
header('Accept-Ranges: bytes');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
echo base64_decode($pdf_file);
exit(); // nothing else will happen, no website which is shown otherwise
}

blank page when using php readfile() in wordpress template

I have a form which the user fills out with their details & serial number, the software installer is then downloaded, named as their input. e.g. serial.exe
Once the form is submitted I check the file exists and then attempt the file download:
$directory = get_template_directory();
$file = $directory . '/filename.exe';
if (file_exists($file)) {
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="'.$Serial.'.exe"');
header('Content-Transfer-Encoding: binary');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Pragma: public');
header('Content-Length: ' . filesize($file));
readfile($file);
exit;
}
This causes the loading to freeze, nothing below this code is loaded but i can't see any errors & no file is generated.
If i change the file to a .png the code works.
I've also copied the same code to a php page outside of wordpress, the same code runs & downloads the file as desired.
Is it possible that Wordpress is somehow blocking the readfile() request because its an .exe?
EDIT:
It appears to be a problem with the size of the file, rather than the type of file.
A small .exe file has worked & is downloaded correctly.

How do I force download of a file through Flysystem?

I may be missing something exceptionally obvious here, but I'm using yii2-flysystem along with Dropbox to read and write files.
I can upload and write them to Dropbox with no problem but then, when reading like this:
$file = Yii::$app->dropboxFs->read($fn);
..all that gives me is a string (/tmp/phpQkg8mJ).
How do I actually force the download of the file that I'm reading? I'm not sure what that temporary file location actually relates to.
Try function readfile().
According to example, your code should be looks something like this:
if (file_exists($file)) {
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="'.basename($file).'"');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($file));
readfile($file);
exit;
}

PHP header download (Laravel)

I have a simple problem. I am trying to make header download (Save as dialog window) to download file from server. My code:
public function downloadBill()
{
$id = Input::get('post_id');
$db = DB::connection('smsservice');
$file_ = $db->table('bills')->where('id', $id)->pluck('blob');
$filename = 'download.txt';
File::put($filename, base64_decode($file_));
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename='.basename($filename));
header('Content-Transfer-Encoding: binary');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($filename));
}
Save as dialog starts, and I can download file download.txt, but the file is emtpy 0 kb, which draws me to the conclusion that location of download is not equal to the location of the of saved "download.txt". I tried putting file to diferent locations, even on the D:\ disk as well, but I didn't manage to make it work. Can someone help me, please?
Laravel has a built-in method for returning a download response. response()->download($filePath);. This will handle everything needed for the file to be downloaded, automatically http://laravel.com/docs/5.1/responses#file-downloads
I'd also be inclined to use the storage_path() function to save the file into an explicitly known, suitable directory rather than letting PHP save it where it likes.
$filename = storage_path(sprintf('/downloads/%s.txt', $id));

Incorrect Headers?

What I'm trying to do:
Im trying to push a jpg file to download witout user seeing the URL. In this case the file is located at: http://www.example.com/upload/asdasdsadpokdaspdso/36.jpg.
My current code:
header('Content-type: application/octet-stream');
header('Content-Disposition: attachment; filename="'.$download->name.'.jpg"');
readfile($weburl."/upload/".$hiddenpassage."/".$download->link);
My vars / db values:
$weburl = "http://wwww.example.com";
$hiddenpassage = "asdasdsadpokdaspdso";
$download->link = 36.jpg //not a var, just drom db.
$download->name = The First Test Product //not a var, just from db.
The problem:
When I get the download I open it and I get the following error:
The file “The First Test Product (28).jpg” could not be opened.
It may be damaged or use a file format that Preview doesn’t recognize.
Renaming .jpg to .txt:
http://pastebin.com/K9NGL5RP
Most of that is the content of the page I downloaded it from.
I think you need to specify the whole header (untested). Specially the Content-Length.:
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename='.$download->name.'.jpg');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($weburl."/upload/".$hiddenpassage."/".$download->link));
readfile($weburl."/upload/".$hiddenpassage."/".$download->link);
Hope this helps.

Categories