29

I want to generate an MS Excel file from PHP. I know one can do something like this:

header ( "Content-type: application/vnd.ms-excel" );
header ( "Content-Disposition: attachment; filename=foo_bar.xls" );

But it will generate a file with just one Sheet. What I want is generating a file with multiple sheets. How can I do that? Maybe there's a third party library, but I haven't found too much.

pnuts
  • 58,317
  • 11
  • 87
  • 139
Cristian
  • 198,401
  • 62
  • 356
  • 264
  • 3
    Just a small note on the wording of your question; you say you're already generating a file with just one sheet, but the code you posted above doesn't generate anything, it only sets up the download of an already existing file. Do you already have a file called foo_bar.xls? Or is there code missing that generates the file with just one Sheet. – lucideer Jul 16 '10 at 23:27
  • @lucideer I was just showing that I know how to generate an XLS file. Just for avoiding answers that suggest doing what I have already done. Of course, the code that generates the file is complete; I was just showing a fragment of it. – Cristian Jul 17 '10 at 03:46
  • Just to clarify, I believe what OP meant is that he can stream a CSV file, but with those headers, and it will be disposed of by most browsers as a XLS file. (I have done this before) He was not aware of the PHPExcel-type approach in the accepted answer. – Oliver Williams Nov 17 '15 at 17:22

4 Answers4

83

Try looking at PHPExcel. This is a simple example that creates an Excel file with two sheets:

<?php
require_once 'PHPExcel.php';
require_once 'PHPExcel/IOFactory.php';

// Create new PHPExcel object
$objPHPExcel = new PHPExcel();

// Create a first sheet, representing sales data
$objPHPExcel->setActiveSheetIndex(0);
$objPHPExcel->getActiveSheet()->setCellValue('A1', 'Something');

// Rename sheet
$objPHPExcel->getActiveSheet()->setTitle('Name of Sheet 1');

// Create a new worksheet, after the default sheet
$objPHPExcel->createSheet();

// Add some data to the second sheet, resembling some different data types
$objPHPExcel->setActiveSheetIndex(1);
$objPHPExcel->getActiveSheet()->setCellValue('A1', 'More data');

// Rename 2nd sheet
$objPHPExcel->getActiveSheet()->setTitle('Second sheet');

// Redirect output to a client’s web browser (Excel5)
header('Content-Type: application/vnd.ms-excel');
header('Content-Disposition: attachment;filename="name_of_file.xls"');
header('Cache-Control: max-age=0');
$objWriter = PHPExcel_IOFactory::createWriter($objPHPExcel, 'Excel5');
$objWriter->save('php://output');
psorensen
  • 809
  • 4
  • 17
  • 33
Mark Baker
  • 209,507
  • 32
  • 346
  • 385
  • Thanks for editing in an example Cristian. Hope you find the library easy to use – Mark Baker Jul 17 '10 at 09:58
  • This library is simply awesome... in fact, I'm want to donate an amount of money. Thanks for sharing! – Cristian Jul 17 '10 at 14:12
  • 1
    @Christian - I do have a vested interest in sharing: I am one of the main authors :-) – Mark Baker Jul 17 '10 at 19:10
  • +1 For you. Thank you Mark Baker. I was searching the same thing. – w3uiguru Apr 13 '12 at 10:22
  • Dear @MarkBaker THANK YOU for such an awesome piece of software. You rule. – Petrogad Jul 24 '12 at 01:07
  • Thanks @MarkBaker for the example! Worked like a charm! +1 – Joseph Aug 31 '12 at 02:19
  • @MarkBaker -Thanks for your answer, If i want to change the storing path of the file, then what i need to change. i.e. i want to save file to particular location in my drive. – Vimal Patel Nov 19 '13 at 10:17
  • 1
    @Vimal - for storing on the server: delete the lines setting headers, and replace 'php://output' in the call to save() with the filepath/filename of your choice.... for telling the browser where the file should be stored if downloaded to the user, forget it - browsers don't work that way and you have no control over where the users chooses to store a file on his own PC – Mark Baker Nov 19 '13 at 10:20
  • 1
    Hello, I appreciate your answer but in line `$objPHPExcel->getActiveSheet()->setCellValue('A1', 'Something');` it write on first column and first row, i have dynamic row and colum and want to write. it depends on data in database. So please explain it or let me know documentation of it. – Keyur Mistry Nov 07 '14 at 10:13
  • @user3540050 - In the line `$objPHPExcel->getActiveSheet()->setCellValue('A1', 'Something');`, the value `A1` is the Excel cell address (column `A`, row `1`), change `A1` to `B5` to write to column `B` row `5`, etc.... this really is how MS Excel works, not complex rocket science – Mark Baker Nov 07 '14 at 11:04
  • @MarkBaker - yes thanks for working on that. I intend to write a script that will turn a database into a spreadsheet, with each sheet being a table and the sheet itself mimicking the CSV export of the data. I can do it based on this information, but wondered if your codebase has a faster method to take a 2d array and convert it to a sheet. Thanks! This is for office staff to get a quick overview in a format they understand. – Oliver Williams Nov 17 '15 at 16:37
  • @OliverWilliams - Should really be a new question, but the worksheet has a `fromArray()` method that does what you ask.... however, you're better working a row at a time from the db rather than building large arrays in memory – Mark Baker Nov 17 '15 at 16:42
  • @MarkBaker, thanks and I agree. When I complete the script I'll post as an answered question. – Oliver Williams Nov 17 '15 at 16:45
3

If you mean like have your PHP script create an Excel file, write some stuff to it on any sheet, etc, then offer that up for the client to download, you can just use PHP's built-in COM extension. See: http://us2.php.net/manual/en/class.com.php for all sorts of examples. However, you will need Excel (or a clone like OpenOffice) installed on the server. If you don't, perhaps Mark Baker's answer above will work instead without it.

bob-the-destroyer
  • 3,164
  • 2
  • 23
  • 30
  • I don't believe that Open Office supports COM, I think that's limited to a range of MS applications, which does limit this option to a Windows server. COM is pretty powerful, and very efficient, but sadly not well documented – Mark Baker Jul 17 '10 at 09:38
  • @Mark Baker: OpenOffice supports COM. See: http://wiki.services.openoffice.org/wiki/Documentation/DevGuide/ProUNO/Bridge/Automation_Bridge – bob-the-destroyer Jul 17 '10 at 19:49
  • Thanks for the pointer, that's very useful to know... I'll have to do some playing with it – Mark Baker Jul 17 '10 at 19:51
  • Np. Mimicking COM on other OS's is possible (XPCOM, CORBA), but it looks painfully complex, and unknown if PHP would even work with those. I'm sure you can also fake it using WINE. OSX (http://macdevcenter.com/pub/a/mac/2004/04/16/com_osx.html?page=1) should work with it out of the box. – bob-the-destroyer Jul 17 '10 at 20:44
  • Forgot to mention: I can't find the citation on PHP's manual any longer, but it did suggest not using COM on a server. This is good advice. If clients are accessing the same Excel file, corruptions can occur. If something causes a popup prompt like "Are you sure you want to do this?", the request will hang expecting *the server itself* to click OK. – bob-the-destroyer Aug 06 '10 at 02:48
0

Solution

<?php
    require_once 'PHPExcel.php';
    require_once 'PHPExcel/IOFactory.php';
    //Update the multiple sheets in PHP excel
    $report_file = 'Report_' . date('Y-m-d') . '.xlsx';
    $report_file_exists  = 0;
    //If the file doesnot exist , create new otherwise append the data at last
    if (!file_exists($report_file)) {
        objPHPExcel = new PHPExcel();
    }
    else {
        $report_file_exists = 1;
        $objPHPExcel = PHPExcel_IOFactory::load($report_file);
    }
    $columns = [
        'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
        'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'
   ];
    //Sheet details
    $sheet_details = [
        //1st sheet details
        0 => [
            'sheet_title'   => 'Products',
            'sheet_heading' => ['Article_Number','Name'],
            'sheet_data'    => ['1234','Pen']
        ],
        //2nd Sheet Details
        1 => [
            'sheet_title'   => 'Categories',
            'sheet_heading' => ['Category Id','Name'],
            'sheet_data'    => [123,'Accessories']
        ]
    ];                      
    $sheet_count = 0;
    $row = 1;
    $column = 0;
    while ($sheet_count <= count($sheet_details)) {
        $objWorkSheet = '';
        if ($report_file_exists == 0) {
            if ($sheet_count > 0) {
                $objWorkSheet = $objPHPExcel->createSheet($sheet_count);
            } 
            else {
                $objWorkSheet = $objPHPExcel->getActiveSheet();
            }
            $row = 1;
            $column = 0;
            foreach ($sheet_details[$sheet_count]['sheet_heading'] as $head) {
                $objWorkSheet->setCellValue($columns[$column] . $row, $head);
                $column++;
            }
       }
       else {
           $objPHPExcel->setActiveSheetIndex($sheet_count);
           $objWorkSheet = $objPHPExcel->getActiveSheet($sheet_count);
       }
       $row = $objWorkSheet->getHighestRow() + 1; //row count
       foreach ($sheet_details[$sheet_count]['sheet_data'] as $report_details) {
           $column = 0;
           foreach ($report_details as $data) {
                $objWorkSheet->setCellValue($columns[$column] . $row, $data);
                $column++;
            }
            $row++;
        }
        $objWorkSheet->setTitle($sheet_details[$sheet_count]['sheet_title']);
        $sheet_count++;
    }
    $objWriter = new PHPExcel_Writer_Excel2007($objPHPExcel);
    $objWriter->save($report_file);
?>
GYaN
  • 2,327
  • 4
  • 19
  • 39
Gangadhar
  • 11
  • 2
0

Solution

$objPHPExcel = new PHPExcel();
$objPHPExcel->getProperties()->setCreator("creater");
$objPHPExcel->getProperties()->setLastModifiedBy("Middle field");
$objPHPExcel->getProperties()->setSubject("Subject");
$objWorkSheet = $objPHPExcel->createSheet();
$work_sheet_count=3//number of sheets you want to create
$work_sheet=0;
while($work_sheet<=$work_sheet_count){ 
    if($work_sheet==0){
        $objWorkSheet->setTitle("Worksheet$work_sheet");
        $objPHPExcel->setActiveSheetIndex($work_sheet)
            ->setCellValue('A1', 'SR No. In sheet 1')
            ->getStyle('A1')
            ->getFont()
            ->setBold(true);
        $objPHPExcel->setActiveSheetIndex($work_sheet)
            ->setCellValueByColumnAndRow($col++, $row++, $i++);//setting value by column and row indexes if needed
    }
    if($work_sheet==1){
        $objWorkSheet->setTitle("Worksheet$work_sheet");
        $objPHPExcel->setActiveSheetIndex($work_sheet)
            ->setCellValue('A1', 'SR No. In sheet 2')
            ->getStyle('A1')
            ->getFont()
            ->setBold(true);
        $objPHPExcel->setActiveSheetIndex($work_sheet)
            ->setCellValueByColumnAndRow($col++, $row++, $i++);//setting value by column and row indexes if needed
    }
    if($work_sheet==2){
        $objWorkSheet = $objPHPExcel->createSheet($work_sheet_count);
        $objWorkSheet->setTitle("Worksheet$work_sheet");
        $objPHPExcel->setActiveSheetIndex($work_sheet)
            ->setCellValue('A1', 'SR No. In sheet 3')
            ->getStyle('A1')
            ->getFont()
            ->setBold(true);
        $objPHPExcel->setActiveSheetIndex($work_sheet)
            ->setCellValueByColumnAndRow($col++, $row++, $i++);//setting value by column and row indexes if needed
    }
    $work_sheet++;
}
$filename='file-name'.'.xls'; //save our workbook as this file name
header('Content-Type: application/vnd.ms-excel'); //mime type
header('Content-Disposition: attachment;filename="'.$filename.'"'); //tell browser what's the file name
header('Cache-Control: max-age=0'); //no cache`
$objWriter = PHPExcel_IOFactory::createWriter($objPHPExcel, 'Excel5');
$objWriter->save('php://output');
GYaN
  • 2,327
  • 4
  • 19
  • 39
ABDUL JAMAL
  • 452
  • 7
  • 12