File is downloading without extension? - php

I am trying to download a PDF file but when i click on the download button it downloads the file without extension. That is there is no PDF extension with the file when i download it!
Action:
public function executeDownload(sfWebRequest $request) {
$this->ebook_id = $request->getParameter('ebook', $this->default_ebook);
$this->ebook = $this->ebooks[$this->ebook_id];
if (!is_array($this->ebook))
return;
// Allow user to download the ebook (and make sure there is no other output)
$this->setLayout(false);
sfConfig::set('sf_web_debug', false);
$content = sfConfig::get('sf_root_dir').'/web'.$this->ebook['ebook'];
//echo "<p>PDF: $content</p>"; var_export(filesize($content));exit;
// Check if the file exists
$this->forward404Unless(file_exists($content));
// Record the download for this eBook
$c = new Criteria();
$c->add(EbookDownloadsPeer::EBOOK_SLUG, $this->ebook_id);
$ebook = EbookDownloadsPeer::doSelectOne($c);
$ebook->setLastDownloaded(time());
$ebook->setEbookDownloads($ebook->getEbookDownloads()+1);
$ebook->save();
// Adding the file to the Response object
$content_type = (in_array($this->ebook_id, array('readyourbody', 'whyamifatigued', 'nutrientsfromfood'))) ? 'application/pdf': 'image/jpeg';
$this->getResponse()->clearHttpHeaders();
$this->getResponse()->setHttpHeader('Pragma: public', true);
$this->getResponse()->setContentType($content_type);
$this->getResponse()->setHttpHeader('Content-Disposition', 'attachment; filename="'.$this->ebook['name'].'"');
$this->getResponse()->setHttpHeader('Content-Length', filesize($content));
$this->getResponse()->sendHttpHeaders();
$this->getResponse()->setContent(readfile($content));
return sfView::NONE;
}
Template:
<div class="cyan3 txt-large txt-c">
<?php echo link_to('Click here','ebooks/download?ebook='.$ebook_id,'') ?> to <?php echo link_to('download it now','ebooks/download?ebook='.$ebook_id,'') ?>!
</div><br />
</div>

Check the contents of the $this->ebook array and look for a field that holds the file extension. Add this value to the line
$this->getResponse()->setHttpHeader('Content-Disposition', 'attachment; filename="'.$this->ebook['name'] . '"');
so it because something like
$this->getResponse()->setHttpHeader('Content-Disposition', 'attachment; filename="'.$this->ebook['name'] . $this->ebook['extension'].'"');

Please append .pdf as extension to your ebook name.
It will work.

Related

How to make android WebView to download file from php based on header content type

I am having a lot of trouble with my lack of java knowledge on how to start a file download from a website that I developed in php.
I use an unusual way to download the file from my php as it is a custom Excel or Word file (thanks to PHPSpreadsheet and PHPWord), here is the code:
Word download :
////save as a file in temp file
$temp_file = tempnam(sys_get_temp_dir(), 'PHPWord');
$templateProcessor->saveAs($temp_file);
//EXPORT WORD PART
header('Content-Type: application/vnd.openxmlformats-officedocument.wordprocessingml.document');
//regardless of what it's named on the server
$filename = "Contrat " . $typeclient . " client " . $array_site[1] . ".docx";
header("Content-Disposition: attachment; filename=" . $filename);
//Read temp file
readfile($temp_file); //or echo file_get_contents($temp_file);
unlink($temp_file); //remove temp file
exit();
Excel download :
$temp_excel = tempnam(sys_get_temp_dir(), 'PHPSpreadsheet');
$writer->save($temp_excel);
//set the header first, so the result will be treated as an xlsx file
header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
//make it an attachment so we can define filename
$filename = 'Chiffrage pour ' . $array_site[1] . '.xlsx';
header('Content-Disposition: attachement;filename=' . $filename);
//Read temp file to save it
readfile($temp_excel);
unlink($temp_excel);
exit();
Moreover, I tried to solve the problem by grabbing some parts of code already available on the internet, here is what my java android application currently contains :
Inside onCreate :
webView.getSettings().setDomStorageEnabled(true);
webView.setDownloadListener(new DownloadListener() {
#Override
public void onDownloadStart(String url, String userAgent, String contentDisposition, String mimeType, long contentLength) {
DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url));
request.setMimeType(mimeType);
//------------------------COOKIE!!------------------------
String cookies = CookieManager.getInstance().getCookie(url);
request.addRequestHeader("cookie", cookies);
//------------------------COOKIE!!------------------------
request.addRequestHeader("User-Agent", userAgent);
request.setDescription("Downloading file...");
request.setTitle(URLUtil.guessFileName(url, contentDisposition, mimeType));
request.allowScanningByMediaScanner();
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, URLUtil.guessFileName(url, contentDisposition, mimeType));
DownloadManager dm = (DownloadManager) getSystemService(DOWNLOAD_SERVICE);
dm.enqueue(request);
Toast.makeText(getApplicationContext(), "Downloading File", Toast.LENGTH_LONG).show();
}
});
For the moment, the Excel file downloads as the .php script that generates it, however when I rename the .php to .xlsx everything works, so Java doesn't seem to like my header from what I understand.
As for the Word, my android app returns "Downloading File" but nothing happens.
Obviously downloading to my android tablet from Google Chrome for example works perfectly, it would annoy me to have to revise my download method but if it turns out to be unavoidable then, why not
Thanks in advance to all of you and have a great day

Downloading excel file from controller in code igniter

I am having the following issue:
I am using code igniter as php framework, and from one of my views I do an ajax call to a function that generates and xlsx file using PHPExcel and data from mysql database. The file is correctly created in the server but when I try to force_download it won't download anything. Here is the php function:
public function generar_excel($idCotizacion){
isLogged($this->session->userdata('logged_in'));
isAdmin($this->session->userdata('logged_in'));
$cotizacion = $this->cotizacion_model->get_cotizacion_by_id($idCotizacion);
$propuestas = $this->propuesta_model->getPropuestasPorCotizacion($idCotizacion);
error_reporting(E_ALL);
date_default_timezone_set('Europe/London');
require_once 'application/libraries/PHPExcel-1.8/Classes/PHPExcel/IOFactory.php';
require_once 'application/libraries/PHPExcel-1.8/Classes/PHPExcel.php';
$excel2 = PHPExcel_IOFactory::createReader('Excel2007');
$excel2 = $excel2->load('prueba.xlsx'); // Empty Sheet
$excel2->setActiveSheetIndex(0);
$excel2->getActiveSheet()->setCellValue('C8', $cotizacion["capitas"])
->setCellValue('C2', $cotizacion["empresa_nombre"])
->setCellValue('C9', $cotizacion["masa_salarial"])
->setCellValue('B11', $cotizacion["aseguradora_actual"])
->setCellValue('B13', $cotizacion["variable"]/100)
->setCellValue('B14', '0.6')
->setCellValue('B12', '0');
$letra = 'C';
foreach($propuestas->result_array() as $row) {
$excel2->getActiveSheet()->setCellValue($letra.'11', $row["nombre"])
->setCellValue($letra.'13', $row["variable"]/100)
->setCellValue($letra.'14', '0.6')
->setCellValue($letra.'12', '0')
->setCellValue($letra.'16', '=C$8*'.$letra.'12+C$9*'.$letra.'13+C$8*'.$letra.'14')
->setCellValue($letra.'17','=(B$16-'.$letra.'16)*13')
->setCellValue($letra.'18','=1-('.$letra.'16/B16)');
++$letra;
}
$objWriter = PHPExcel_IOFactory::createWriter($excel2, 'Excel2007');
$nombreArchivo = 'CuadroComparativo-'.$cotizacion["empresa_nombre"].'.xlsx';
$objWriter->save('uploads/'.$nombreArchivo);
$fileContents = file_get_contents('http://rpm.singleton.com.ar/uploads/'.$nombreArchivo);
//print_r($fileContents);
$this->load->helper('download');
force_download($nombreArchivo, $fileContents);
}
The response and preview from inspecting the browser are unreadable.
Thank you!
Set the MIME type for the data you're sending in the force_download() function. The browser may be either trying to best guess it, or just outputting exactly what you send it (which may be the 'unreadable' data you're referring to).
Try changing your force_download line to:
force_download($nombreArchivo, $fileContents, TRUE);
This will set the MIME type based on your file extension (xlsx), with should force the browser to download the file.
I solved it by adding in the success function of ajax the following:
success: function(json) {
var content = JSON.parse(json);
//alert(content);
if (content.error) {
$('#error').html(content.response);
$('#error').show();
$('#success').hide();
} else {
// alert(content);
location.href="http://rpm.singleton.com.ar/uploads/"+content.response;
//location.href = "<?php echo site_url('administrador'); ?>/" + content.response;
}
},
And in the php i echo the file name.
Try this code:
header('Content-Type: application/vnd.ms-excel');
header("Content-Disposition: attachment; filename={$nombreArchivo}.xls");
$this -> load -> view ('view_file',$fileContents);

Download using Yii::app()->request->SendFile returns corrupted file

I've been trying to download my uploaded file from a specific directory like this:
Yii::app()->request->SendFile($model->statement,
file_get_contents($path.$model->statement)
);
It recognizes the file and downloaded it with the correct name and format, but all I get instead of a 74KB file, is a 1KB corrupted file. Tried other documents such as .doc, .pdf, still the same.
I am not entirely sure about what the file_get_contents actually does as I took this from an example I found.
The file to be downloaded was previously uploaded using
<div class="row">
<?php echo $form->labelEx($model, 'statement'); ?>
<?php echo $form->fileField($model, 'statement', array('size' => 36, 'maxlength' => 255)); ?>
<?php echo $form->error($model, 'statement'); ?>
</div>
in the _form.php and adjusted the actionCreate in the controller:
public function actionCreate($id)
{
$model=new Witness;
$model->ip_id = $id;
// Uncomment the following line if AJAX validation is needed
// $this->performAjaxValidation($model);
$path = Yii::app()->basePath . '/modules/iris/statements';
if (!is_dir($path)) {
mkdir($path);
}
if(isset($_POST['Witness']))
{
$model->attributes=$_POST['Witness'];
if (#!empty($_FILES['Witness']['name']['statement'])) {
$model->statement = $_POST['Witness']['statement'];
if ($model->validate(array('statement'))) {
$model->statement = CUploadedFile::getInstance($model, 'statement');
} else {
$model->statement = '';
}
$model->statement->saveAs($path . '/' . time() . '_' . str_replace(' ', '_', strtolower($model->statement)));
//$model->doc_type = $model->statement->getType();
//$model->doc_size = $model->statement->getSize();
}
$model->statement = time() . '_' . str_replace(' ', '_', strtolower($model->statement));
if($model->save())
$this->redirect(array('ip/view','id'=>$model->ip_id));
}
$this->render('create',array(
'model'=>$model,
));
}
The uploaded files can be opened with no problem. Any idea of why the download corrupted? Do I have to specify the type/size of the file first before downloading?
With a 1kb file it sounds like your server is throwing a php error after the headers have been set.
Open the downloaded file with text editor and check the contents.
I have found another solution instead of using the SendFile function. Put this in the view file to generate the download link:
CHtml::link('Click to download file', array('ip/download&id='.$model->file_id));
where 'ip' the the model name. This will pass file_id to the function actionDownload created in the controller.php:
public function downloadFile($fullpath){
if(!empty($fullpath)){
header("Content-type:application/pdf"); //for pdf file
//header('Content-Type:text/plain; charset=ISO-8859-15');
//if you want to read text file using text/plain header
header('Content-Disposition: attachment; filename="'.basename($fullpath).'"');
header('Content-Length: ' . filesize($fullpath));
readfile($fullpath);
Yii::app()->end();
}
}
public function actionDownload($id){
$model=Ip::model()->findByPk($id);
$path = Yii::app()->basePath . 'location of file to be downloaded'.$model->filename;
$this->downloadFile($path);
}
This should download the file completely. Don't worry about the content-type, I have tried all common file types (.pdf, .doc, .ppt, .png, .jpg), all works perfectly.
In Yii2, a sendFile() signature is
public $this sendFile ( $filePath, $attachmentName = null, $options = [] )
Sending a file:
Yii::$app->response->sendFile('test.zip');
For those, who get full files, but still corrupted:
You should check if other php files are printing output, sometimes whitespace after closing PHP tags can cause problems.
From here
If you take a look into the arguments list of sendFile, you can see that 3rd parameter is mimeType. In fact, you do not present a HTTP headers response, so my prima vista suggestion to you is to try explicitly specify the Content-Type response header:
Yii::app()->request->sendFile(
"Youfile.pdf",
file_get_contents('path/to/file'),
'application/pdf'
);

File only downloading when opened in new window/tab

I have a function that creates different file types depending on a variable, I have it generating an XML, but when I click the link to the page to do so (XML), nothing happens. If I click to open it in a new tab or manually enter the url in the title bar then the file will download as I want it to.
function asset($asset_id, $display = ''){
$this->load->model('model_asset');
$asset = $this->model_asset->get_by_id($asset_id, true);
switch($display) {
case 'xml':
$this->load->helper('array_to_xml_helper');
$asset_arr = get_object_vars($asset);
$filename = $asset->title .'-'. $asset->subtitle . '.xml';
$xml = Array2XML::createXML('asset', $asset_arr);
header ("Content-Type:text/xml");
header('Content-Disposition: attachment; filename="'. $filename .'"');
echo $xml->saveXML();
break;
}
}
How can I make this work with dynamically generated files (I'm using a arraytoxml utility function I found here)
You can try to set file in attachement
Add this to your headers :
Content-disposition: attachment
filename=huge_document.pdf

PHP "save dialog" for file received from web service

I'm using WSO2 WS Framework and I managed to run example in which web service returns an image as a MTOM attachment which is then saved by the client using file_put_contents(...) command.
Service:
<?php
function sendAttachment($msg){
$responsePayloadString = <<<XML
<ns1:download xmlns:ns1="http://wso2.org/wsfphp/samples/mtom">
<ns1:fileName>test.jpg</ns1:fileName>
<ns1:image xmlmime:contentType="image/jpeg" xmlns:xmlmime="http://www.w3.org/2004/06/xmlmime">
<xop:Include xmlns:xop="http://www.w3.org/2004/08/xop/include" href="cid:myid1"></xop:Include>
</ns1:image>
</ns1:download>
XML;
$f = file_get_contents("test.jpg");
$responseMessage = new WSMessage($responsePayloadString,
array( "attachments" => array("myid1" => $f)));
return $responseMessage;
}
$operations = array("download" => "sendAttachment");
$service = new WSService(array("operations" => $operations, "useMTOM" => TRUE));
$service->reply();
?>
Client:
<?php
$requestPayloadString = '<download></download>';
try {
$client = new WSClient(
array( "to" => "http://SPLINTER/MTOM/service.php",
"useMTOM" => TRUE,
"responseXOP" => TRUE));
$requestMessage = new WSMessage($requestPayloadString);
$responseMessage = $client->request($requestMessage);
printf("Response = %s \n", $responseMessage->str);
$cid2stringMap = $responseMessage->attachments;
$cid2contentMap = $responseMessage->cid2contentType;
$imageName;
if($cid2stringMap && $cid2contentMap){
foreach($cid2stringMap as $i=>$value){
$f = $cid2stringMap[$i];
$contentType = $cid2contentMap[$i];
if(strcmp($contentType,"image/jpeg") ==0){
$imageName = $i."."."jpg";
if(stristr(PHP_OS, 'WIN')) {
file_put_contents($imageName, $f);
}else{
file_put_contents("/tmp/".$imageName, $f);
}
}
}
}else{
printf("attachments not received ");
}
} catch (Exception $e) {
if ($e instanceof WSFault) {
printf("Soap Fault: %s\n", $e->Reason);
} else {
printf("Message = %s\n",$e->getMessage());
}
}
?>
Instead of that I would like to open a "Save dialog" to choose between opening or saving the file. When searching for solution I read about setting heders like:
header('Content-type: application/octet-stream');
header('Content-disposition: attachment; filename="test.jpg"');
But it didn't work well. "Save dialog" poped up, but when image couldn't be opened saying that file is empty.
Actually I don't understand very good how this MTOM attachments thing is working. In client code, I think $f is a string and when I do printf($f) it prints 0(zero) so how can I save this string as an image?
If you want to use that headers, you have to output the file content, not save it somewhere.
header('Content-type: application/octet-stream');
header('Content-disposition: attachment; filename="test.jpg"');
// Output file. This must be the ONLY output of the whole script
echo $rawFileContents;
The basics is that at the moment you have your whole file content loaded in a variable (and it seems is $f in your code), you output it instead of write it in a file (as I think you're doing now). So, the three lines of code I gave you should replace the file_put_contents() calls.
Instead, if you want to save the file in your /tmp folder, ok, do it, but then use instead
header('Location: /tmp/' . $imageName);
This way you redirect the user browser directly to the saved file, and let users do what they want with it.

Categories