5

I wanted to download an excel file generated by using PHPExcel. I followed the code from PHPExcel Force Download Issue and to no avail. After I log the data receive, my console only shows full of these symbols �.However, when I change the $objWriter->save('php://output'); to $objWriter->save('filename.xlsx'); then it just download the file to my root folder in my web server without any indication of downloading a file. Below is the code snippet for my php file

<?php
$con = mysqli_connect('localhost', 'root', '', 'test');
mysqli_select_db($con, 'test');

$qry = "SELECT * FROM lostitem";
$res = mysqli_query($con, $qry);

require_once '/Classes/PHPExcel.php';
include '/Classes/PHPExcel/Writer/Excel2007.php';

// Create new PHPExcel object
$objPHPExcel = new PHPExcel();
/** Determine filename **/
$filename = "report.xlsx";

/** Set header information **/
header('Content-Type: application/vnd.ms-excel');
header('Content-Disposition: attachment;filename="' . $filename . '"');
header('Cache-Control: max-age=0');
$F=$objPHPExcel->getActiveSheet();
$Line=1;
$F->setCellValue('A'.$Line, 'Lost Item ID');
$F->setCellValue('B'.$Line, 'Lost Item Title');
$F->setCellValue('C'.$Line, 'Lost Item Description');
while($Trs=mysqli_fetch_assoc($res)){//extract each record
    ++$Line;
    $F->setCellValue('A'.$Line, $Trs['LostItemID']);
    $F->setCellValue('B'.$Line, $Trs['LostItemTitle']);
    $F->setCellValue('C'.$Line, $Trs['LostItemDescription']);//write in the sheet
    //++$Line;
}
// Redirect output to a client’s web browser (Excel5)
header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
header('Content-Disposition: attachment;filename="'.$filename.'"');
header('Cache-Control: max-age=0');

$objWriter = PHPExcel_IOFactory::createWriter($objPHPExcel, 'Excel2007');
$objWriter->save('php://output');
exit;

?>

Here is my angularjs code snippet:

$scope.getReport = function(type){
        if(type == 'lost'){
            $http.post("getLostItemReport.php")
                .success(function(data, status, headers, config){
                    console.log("Get report data: " + data);
                })
        }
      }

Note: I'm using AngularJS $http.post to call the php file.

Browser: Google Chrome

EDIT: I have tried the sample php code from PHPExcel 01simple-download-xlsx.php and the result also same.

UPDATE:I have found some solution by searching about getting AngularJS by accepting Excel as a response but after download it, it seems the file is corrupted with gibberish text or symbols similar to the one that logs out in my console. Besides that, the filename is random text and numbers instead of the filename I assigned in my php code. The code is as below:

var blob = new Blob([data], {type: "application/vnd.ms-excel"});
                    var objectUrl = URL.createObjectURL(blob);
Community
  • 1
  • 1
imationyj
  • 145
  • 2
  • 8
  • Add headers: http://stackoverflow.com/questions/8566196/phpexcel-to-download – Vladimir Ramik Mar 13 '15 at 03:37
  • Already tried that. You can see them in my code in the questions. – imationyj Mar 13 '15 at 03:41
  • 1
    That "gibberish" ___is___ the Excel file.... Both xls and xlsx are binary formats.... and angular has no idea what to do with a raw binary stream with a content type of `application/vnd.ms-excel` or `application/vnd.openxmlformats-officedocument.spreadsheetml.sheet` – Mark Baker Mar 13 '15 at 08:00
  • Yeah. I also found out that it's actually the excel file. Thanks for pointing out about the point that _angular has no idea what to do with a raw binary stream with a content type of `application/vnd.ms-excel` or `application/vnd.openxmlformats-officedocument.spreadsheetml.sheet`_. Will try to search on solving that issue. – imationyj Mar 13 '15 at 08:52

3 Answers3

2

I have found a solution to download using AngularJS with ability to change the filename on the fly. We will need to download FileSave.js and include in the header of index.html. The code snippet is as below:

main.js

$scope.fetchReport = function(){
            $http({
                url: 'path_to_php_file',
                method: 'POST',
                responseType: 'arraybuffer',
                headers: {
                    'Content-type': 'application/json',
                    'Accept': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
                }
            }).success(function(data){
                var blob = new Blob([data], {type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"});
                saveAs(blob, file_name_to_be+'.xlsx');
            }).error(function(){
                //Some error log
            });
        }

index.html

<button class="btn btn-primary" ng-click="fetchReport()">Get Report</button>

php file is same as in the question, just need to add a few lines before exit;

header('Content-disposition: attachment; filename='.$filename);
header('Content-Length: ' . filesize($filename));
header('Content-Transfer-Encoding: binary');
header('Cache-Control: must-revalidate');
header('Pragma: public');

//Replace php://output with $filename and add code below after that(before exit;)
readfile($filename);

Note: It's only for HTML5 suppported browser.

imationyj
  • 145
  • 2
  • 8
  • That worked well for me, thanks! If I may add, the line `$objWriter->save($filename);` should be called before `header('Content-Length: ' . filesize($filename));` – Pierre Roudaut Sep 02 '16 at 14:06
1

You have the excel file in your root folder right ?

So, I think you can use header('Location: path to your excel file'); This should help you download the file.


There is another option after $objWriter->save('filename.xlsx'); add echo json_encode(readfile($file));

in angular js code use

$scope.getReport = function (type) {
if (type == 'lost') {
    $http({
        url: 'getLostItemReport.php',
        method: 'POST',
        responseType: 'arraybuffer',
        headers: {
            'Content-type': 'application/json',
            'Accept': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
        }
    })
    .success(function (data, status, headers, config) {
        var blob = new Blob([data], {
            type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
        });
        var objectUrl = URL.createObjectURL(blob);
        window.open(objectUrl);
    })
}

And set your header('Content-Type: application/vnd.ms-excel'); to header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');

Try this one.

itssajan
  • 820
  • 8
  • 24
  • May I know where should put that? – imationyj Mar 13 '15 at 05:09
  • after `$objWriter->save('filename.xlsx');` – itssajan Mar 13 '15 at 05:11
  • Tried it. The console still logs out gibberish text and symbols. If I remove the header you mentioned then there are no gibberish text and symbols appear, just that the file is save to my server root folder. EDIT: I wonder whether it's the AngularJS problem or not. hmm... – imationyj Mar 13 '15 at 05:20
  • can u give the code for `header('Location: path to your excel file');` by replacing path with your actual path ? – itssajan Mar 13 '15 at 05:24
  • I have tried your edited solution. My code is `echo json_encode(readfile('filename.xlsx'));` The type in `blob` function that you stated return a corrupted xlsx file, if I change it into `vnd.ms-excel`, I could open the file but the contents are gibberish text. – imationyj Mar 13 '15 at 05:35
  • try giving an absolute path like `header('Location: "http://localhost:8000/filename.xlsx"')` – itssajan Mar 13 '15 at 05:35
  • I have tried it but it returns 403 Forbidden error. The path output becomes `http://localhost:8081/LostNFound/%22http://localhost:8081/LostNFound/report.xlsx%22`. I tried removing the quotation mark, but getting the same gibberish text like before. – imationyj Mar 13 '15 at 05:41
  • can u see the permission set to the excel file. like `chmod file.xlsx` – itssajan Mar 13 '15 at 05:46
  • May I know how do I check it? Just type in `chmod file.xlsx` after `$objWriter->save('filename.xlsx');`? – imationyj Mar 13 '15 at 08:55
  • chmod is a shell command, go to you shell prompt and try chmod. You must be in the same same directory as the file is. Take a look at the link before if you fail to get the permissions http://www.linux.org/threads/file-permissions-chmod.4094/ – itssajan Mar 13 '15 at 10:50
  • I'm unable to use `chmod`. It says it's not recognized as an internal or external command. Btw, I'm using Windows, is this for Linux platform? – imationyj Mar 14 '15 at 08:52
  • Your edited answer for the AngularJS way of downloading the file works. I have found out that I have missed out the `responseType: 'arraybuffer'`. That's why I got gibberish text. But, the filename is still in a random characters and numbers. Wonder how do I change the filename. – imationyj Mar 15 '15 at 01:59
1

I have a very basic solution which i use in my website. Hope this works.

Create a hyperlink and set the href to your excel file and use download attribute.

<a href='file to excel' download='download'>Download Excel File</a>

When You click this link the file would start downloading.

Dalvik
  • 217
  • 1
  • 2
  • 12
  • Nice! That would be a workaround for my project if I still can't find any solution to it. I will just need to generate the file to my server first and click the link to download the file instead of generate on the fly and download afterwards (which is the problem for my question now). Anyway, thanks for the tips. :) – imationyj Mar 13 '15 at 09:01