Showing posts with label pclzip. Show all posts
Showing posts with label pclzip. Show all posts

Monday, 10 February 2014

How to use PHP Excel without php built in zip archive

"Fatal error: Class 'ZIPARCHIVE' not found"

I found myself in in the situation that I had to use PHPExcel to generate some graphs. Sounds easy enough, and it kind of is, but... after I develop locally on my machine running php 5.3 I face myself with the challenge that I have to install the code on a machine running php 5.1.2 (not suported by PHPExcel). I soon found out that the main problem is the fact that php 5.1 dose not have ZipArchive or PHPExcel_Shared_ZipArchive, you can install them but with a lot of headache and a lot of trying (more than 1 solutions available for more than 1 case) and to be honest, that solution was not the proper way to do it as this was a production server with a lot of stuff on it (you don't want to mess it up).
Maybe a guru server admin could find a proper solution, but I am not that, I am a dev, so... I started researching to find a way to change to another lib that works on 5.1. And so I found... nothing!!! (at least after 2-3h of research and reading a lot of useless forum posts).
As my search was not fruitful and time consuming and annoying I moved my atention to something I love but not like doing: hacking the code ( hacking the code of a maintained lib is not encouraged as this may lead to rough upgrades with lots of diffs etc.  ).
After a little more research and documentation I found pclzip as a php standalone lib here and I found that PHPExcel has a very simple way of changing the ziping class in the settings.
So this is what I have done:

  1. imported the pclzip lib
  2. created a wrapper class for compatibility reasons (pclzip dose not have the function names implemented in the other to libs)
  3. added my wrapper class as a ziping method in settings.php
  4. forced PHPExcel to use my class for ziping
NOTICE: This was tested only for writing, so I have no ideea what will happen when reading, but that is the subject of another post.

Here is a short description of the code I created:

################################################
// pclzip.extended.php
################################################

include('pclzip.lib.php');  // PhpConcept Library - Zip Module 2.8.2 -  http://www.phpconcept.net
class PCLZipExtended{
 // just a place holder
 function PCLZipExtended(){
  
 }
 
 private $zip;
 private $temp_dir;
 // implementation of function open
 // this function needs to create the zip file
 // pclzip dose not create the file untill any action is taken (create/append)
 function open($pFilename,$zipCreate){
  $this->zip = new PclZip($pFilename);
  $this->zip->create(array());
  
  return file_exists($pFilename);
 }
 // implementation of addFromString function
 // needs to save the string to a local file and then append it to the archive
 // keeping the paths is a ***ch
 function addFromString($_location,$data){
  $location=$this->tempdir().$_location;
  if(!file_exists(dirname($location)))
   mkdir(dirname($location), 0777, true);
  file_put_contents($location,$data);
  $loc_to_add = explode('/',$location);
  array_shift ($loc_to_add);
  array_pop ($loc_to_add);
  $loc_to_add = implode('/',$loc_to_add);
  $this->zip->add($location,$loc_to_add,dirname($location));
 }
 // we are done and we can clean up after our selfs 
 function close(){
  
  // do cleanup
  $this->rrmdir($this->tempdir());
 }
 // generate a temp dir to store the files needed for the zip
 // or if we already done this return it
 // and yes php 5.1 dose not have sys_get_temp_dir
 private function tempdir($dir='') {
  if(isset($temp_dir)) return $temp_dir;
  $tempfile=tempnam($dir,'');
  if (file_exists($tempfile)) { unlink($tempfile); }
  mkdir($tempfile);
  if (is_dir($tempfile)) { return $temp_dir=$tempfile.'/'; }
  return false;
 }
 // recursive delete for php
 private function rrmdir($dir='') {
  if (is_dir($dir)) {
   $objects = scandir($dir);
   foreach ($objects as $object) {
    if ($object != "." && $object != "..") {
     if (filetype($dir."/".$object) == "dir") rmdir($dir."/".$object); else unlink($dir."/".$object);
    }
   }
   reset($objects);
   rmdir($dir);
  }
 }
 
}

################################################
// PHPExcel: PHPExcel/PHPExcel/Settings.php
################################################

################

    const PCLZIP        = 'PHPExcel_Shared_ZipArchive';
// line: 42 added just this
    const PCLZIP_SOURCE = 'PCLZipExtended';
// line: 42 added just this
    const ZIPARCHIVE    = 'ZipArchive';

################


        if (($zipClass === self::PCLZIP) ||
// line: 120 added just this
            ($zipClass === self::PCLZIP_SOURCE) ||
// line: 120 added just this
            ($zipClass === self::ZIPARCHIVE)) {

################

################################################
// Main php file that dose all the work
################################################

        include('modules/ER_Reports/pclzip.extended.php');
        include('modules/ER_Reports/PHPExcel/PHPExcel.php');
        PHPExcel_Settings::setZipClass(PHPExcel_Settings::PCLZIP_SOURCE);
        $er = new ER_Reports();


And that's all folks!!!!