[Solved] .xlsx Working In Localhost, Not Working In Production Server

Not sure what’s wrong. I’m using PHPExcel, and the file itself works flawlessly.

I serve both .CSV and .XLSX. .CSV works in both localhost and server, but .XLSX doesn’t do anything. It just opens the link as an empty page, and does nothing. Also, curiously enough, when I download the .XLSX in localhost it automatically opens the XLSX file, while the CSV just downloads like normal.

By the way, I’m using nGinx. I thought it could be a mime problem, but it doesn’t seem to be the case.

This is my code:




class Reporter {


    //Mime types for each kind of possible report file type.

    private $mimeType=array('csv'=>'text/csv', 'xlsx'=>'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');

    //Variables to make documents.

    private $excelObject=null;

    private $documentProperties=null;


    public function createReport($ext, $name, $data){

        //Load the PHPExcel library if the file is not an CSV

        if($ext!='csv'){

            //Unregister Yii's autoload to prevent conflict with the library's autoloader.

            spl_autoload_unregister(array('YiiBase','autoload'));

            Yii::import('application.vendors.classes.*');

            require_once('PHPExcel.php');

            //After the library is imported, register Yii's autoloader again.

            spl_autoload_register(array('YiiBase','autoload'));


            //Initialize variables for PHPExcel

            $this->excelObject=new PHPExcel();

            $this->documentProperties=new PHPExcel_DocumentProperties();

            $this->documentProperties->setCompany("MyName");

            $this->documentProperties->setCreator("MyName");

            $this->documentProperties->setTitle("Title");

            $this->excelObject->setProperties($this->documentProperties);

        }


        //Generate the file name. It uses the user_id, a timestamp, a provided name and the file extension.

        $filename=Yii::app()->user->id.'-'.time().'-'.$name.'.'.$ext;

        $filepath=Yii::app()->basePath.'/'.$filename;


        //Prepare the headers

        header('Content-Description: File Transfer');

        header('Content-Type: '.$this->mimeType[$ext]); //Content-Type mime Type defined by the extension.

        header('Content-Disposition: attachment; filename='.$filename);

        header('Content-Transfer-Encoding: binary');

        header('Expires: 0');

        header('Cache-Control: must-revalidate');

        header('Pragma: public');


        //Generate a report depending on the solicited file ex: csv, xls, xlsx, pdf, etc.

        switch($ext){

            case 'csv':

                //CSVs don't need the PHPExcel library. Just make a file and generate CSV lines.

                $this->createCSV($filepath, $data);

                break;

            case 'xls':

                break;

            case 'xlsx':

                $this->createXLSX($filepath, $data);

                break;

        }


        //Header added after the file was created to be able to check its size

        header('Content-Length: ' . filesize($filepath));


        //Clean the buffer, read the file so that the user sees/downloads it, then remove the file.

        ob_clean();

        flush();

        readfile($filepath);

        unlink($filepath);

    }


    public function createXLSX($filepath, $data){

        $sheet=$this->excelObject->getActiveSheet();

        $headers=array();

        foreach($data as $key=>$row){

            if($key==0){

                //Add headers to the spreadsheet.

                $i=0;

                foreach($row as $head=>$element){

                    $sheet->setCellValueByColumnAndRow($i, $key+1, $head);

                    $headers[$i]=$head;

                    $i++;

                }

            }

            foreach($headers as $j=>$header)

                $sheet->setCellValueByColumnAndRow($j, $key+2, $row[$header]);

        }

        $objWriter = new PHPExcel_Writer_Excel2007($this->excelObject);

        $objWriter->save($filepath);

    }


    public function createCSV($filepath, $data){

        $file=fopen($filepath, 'w');

        foreach($data as $key=>$row){

            if($key==0){

                $headers=array_keys($row);

                fputcsv($file, $headers);

            }

            fputcsv($file, $row);

        }

        fclose($file);

    }

}



I call createReport, and CSV is all right, but XLSX is not downloading anything.

Seems like the file is not being created in the server. For whatever reason… some extension maybe. I’ll post findings. Can’t be permissions, since the CSV works just fine.

No errors are being displayed, so I have no clue what’s wrong either.

Getting closer.

A blank page is shown when the following code runs:




spl_autoload_unregister(array('YiiBase','autoload'));

Yii::import('application.vendors.classes.*');

require_once('PHPExcel.php');

//After the library is imported, register Yii's autoloader again.

spl_autoload_register(array('YiiBase','autoload'));



The exact problem is




require_once('PHPExcel.php');



If I comment that out, no blank page happens, but of course the code won’t work without it because the class PHPExcel is not loaded yet.

Edit: Seems like the Yii::import() line is not needed. I need more testing, but it seems to work just fine without it.

Solved the problem.

It’s ridiculous, I lost like 7 hours with this, and the solution was:


spl_autoload_unregister(array('YiiBase','autoload'));

Yii::import('application.vendors.classes.*');

require_once('PHPExcel.php');

//After the library is imported, register Yii's autoloader again.

spl_autoload_register(array('YiiBase','autoload'));

Move the first spl below the Yii::import:




Yii::import('application.vendors.classes.*');

spl_autoload_unregister(array('YiiBase','autoload'));

require_once('PHPExcel.php');

//After the library is imported, register Yii's autoloader again.

spl_autoload_register(array('YiiBase','autoload'));

I also had to modify the require_once path from this:


require_once('PHPExcel.php');

To this:


require_once(Yii::app()->basePath.'/vendors/Classes/PHPExcel.php');

Why it was working in localhost, is beyond me. Some evil leprechauns were just messing with me. I could find no error whatsoever. The PHP error log showed some weird “Class ‘CListIterator’ not found in /usr/share/nginx/html/YiiRoot/framework/collections/CList.php on line 90”, which caused me to be curious about the autoloader doing something wrong, but there was never a clear message of what was happening. I just randomly moved stuff.

There’s still an issue of the file not being deleted after being downloaded, but I don’t think that it will be hard to solve.

… hope this helps some poor soul that has a similar problem.