Fixed more rows when reporting to Excel Reports. Greater then 65535 rows.
authorJoe Hunt <joe.hunt.consulting@gmail.com>
Thu, 8 Jun 2017 06:32:44 +0000 (08:32 +0200)
committerJoe Hunt <joe.hunt.consulting@gmail.com>
Thu, 8 Jun 2017 06:32:44 +0000 (08:32 +0200)
reporting/includes/Workbook.php
reporting/includes/excel_report.inc

index 718bdb66343e1bec237c5d543d7ce6af309e799f..30a716cbc41894863ed1fe91be8aa5e8be1555a6 100644 (file)
@@ -102,382 +102,795 @@ define('SPREADSHEET_EXCEL_WRITER_EQ', "=");
 */
 define('SPREADSHEET_EXCEL_WRITER_NE', "<>");
 
-/**
-* Class for creating OLE streams for Excel Spreadsheets
-*
-* @author Xavier Noguer <xnoguer@rezebra.com>
-* @package Spreadsheet_WriteExcel
-*/
-class OLEwriter
+define('PpsType_Root', 5);
+define('PpsType_Dir', 1);
+define('PpsType_File', 2);
+define('DataSizeSmall', 0x1000);
+define('LongIntSize', 4);
+define('PpsSize', 0x80);
+
+function Asc2Ucs($sAsc) 
 {
-    /**
-    * Filename for the OLE stream
-    * @var string
-    * @see _initialize()
-    */
-    var $_OLEfilename;
+    return implode("\x00", (preg_split('//', $sAsc, -1, PREG_SPLIT_NO_EMPTY)))."\x00";
+}
 
-    /**
-    * Filehandle for the OLE stream
-    * @var resource
-    */
-    var $_filehandle;
+function Ucs2Asc($sUcs) 
+{
+    $chars=explode("\x00", $sUcs);
+    array_pop($chars);
+    return implode("", $chars);
+}
 
-    /**
-    * Name of the temporal file in case OLE stream goes to stdout
-    * @var string
-    */
-    var $_tmp_filename;
+function OLEDate2Local($sDateTime) 
+{
+}
 
-    /**
-    * Variable for preventing closing two times
-    * @var integer
-    */
-    var $_fileclosed;
+#------------------------------------------------------------------------------
+# Localtime->OLE Date
+#------------------------------------------------------------------------------
+function LocalDate2OLE($raDate) 
+{
+}
 
-    /**
-    * Size of the data to be written to the OLE stream
-    * @var integer
-    */
-    var $_biffsize;
+function _leapYear($iYear) 
+{
+    return ((($iYear % 4)==0) && (($iYear % 100) || ($iYear % 400)==0)) ? 1 : 0;
+}
 
-    /**
-    * Real data size to be written to the OLE stream
-    * @var integer
-    */
-    var $_booksize;
+function _yearDays($iYear) 
+{
+    return _leapYear($iYear) ? 366 : 365;
+}
 
-    /**
-    * Number of big blocks in the OLE stream
-    * @var integer
-    */
-    var $_big_blocks;
+function _monthDays($iMon, $iYear) 
+{
+    if ($iMon == 1 || $iMon ==  3 || $iMon ==  5 || $iMon == 7 ||
+        $iMon == 8 || $iMon == 10 || $iMon == 12) 
+        return 31;
+    elseif ($iMon == 4 || $iMon == 6 || $iMon == 9 || $iMon == 11) 
+        return 30;
+    elseif ($iMon == 2) 
+        return _leapYear($iYear) ? 29 : 28;
+}
 
-    /**
-    * Number of list blocks in the OLE stream
-    * @var integer
-    */
-    var $_list_blocks;
+/*
+ * This is the OLE::Storage_Lite Perl package ported to PHP
+ * OLE::Storage_Lite was written by Kawai Takanori, kwitknr@cpan.org
+ */
 
-    /**
-    * Number of big blocks in the OLE stream
-    * @var integer
-    */
-    var $_root_start;
+class ole_pps 
+{
+    var $No;
+    var $Name;
+    var $Type;
+    var $PrevPps;
+    var $NextPps;
+    var $DirPps;
+    var $Time1st;
+    var $Time2nd;
+    var $StartBlock;
+    var $Size;
+    var $Data;
+    var $Child;
+    var $_PPS_FILE;
+
+    #------------------------------------------------------------------------------
+    # _new (OLE::Storage_Lite::PPS)
+    #   for OLE::Storage_Lite
+    #------------------------------------------------------------------------------
+    function ole_pps($iNo, $sNm, $iType, $iPrev, $iNext, $iDir,
+                     $raTime1st, $raTime2nd, $iStart, $iSize,
+                     $sData=false, $raChild=false) 
+    {
+        #1. Constructor for OLE::Storage_Lite
+
+        $this->No         = $iNo;
+        $this->Name       = $sNm;
+        $this->Type       = $iType;
+        $this->PrevPps    = $iPrev;
+        $this->NextPps    = $iNext;
+        $this->DirPps     = $iDir;
+        $this->Time1st    = $raTime1st;
+        $this->Time2nd    = $raTime2nd;
+        $this->StartBlock = $iStart;
+        $this->Size       = $iSize;
+        $this->Data       = $sData;
+        $this->Child      = $raChild;
+        $this->_PPS_FILE  = NULL;
+    }
+
+    #------------------------------------------------------------------------------
+    # _DataLen (OLE::Storage_Lite::PPS)
+    # Check for update
+    #------------------------------------------------------------------------------
+    function _DataLen() 
+    {
+        if ($this->Data===false) 
+            return 0;
+
+        if ($this->_PPS_FILE) 
+            return filesize($this->_PPS_FILE);
+
+        return strlen($this->Data);
+    }
+
+    #------------------------------------------------------------------------------
+    # _makeSmallData (OLE::Storage_Lite::PPS)
+    #------------------------------------------------------------------------------
+    function _makeSmallData(&$aList, $rhInfo) 
+    {
+        //my ($sRes);
+        $FILE = $rhInfo->_FILEH_;
+        $iSmBlk = 0;
+        $sRes = '';
+
+        for ($c=0;$c<sizeof($aList);$c++) 
+        {
+            $oPps=&$aList[$c];
 
-    /**
-    * Constructor for the OLEwriter class
-    *
-    * @param string $OLEfilename the name of the file for the OLE stream
-    */
-    function OLEwriter($OLEfilename)
-    {
-        $this->_OLEfilename  = $OLEfilename;
-        $this->_filehandle   = '';
-        $this->_tmp_filename = '';
-        $this->_fileclosed   = 0;
-        $this->_biff_only    = 0;
-        //$this->_size_allowed = 0;
-        $this->_biffsize     = 0;
-        $this->_booksize     = 0;
-        $this->_big_blocks   = 0;
-        $this->_list_blocks  = 0;
-        $this->_root_start   = 0;
-        //$this->_block_count  = 4;
-        $this->_initialize();
-    }
+            #1. Make SBD, small data string
 
-    /**
-    * Check for a valid filename and store the filehandle.
-    * Filehandle "-" writes to STDOUT
-    *
-    * @access private
-    */
-    function _initialize()
-    {
-        $OLEfile = $this->_OLEfilename;
+            if ($oPps->Type==PpsType_File) 
+            {
+                if ($oPps->Size<=0) 
+                    continue;
 
-        if (($OLEfile == '-') or ($OLEfile == '')) {
-            $this->_tmp_filename = tempnam("/tmp", "OLEwriter");
-            $fh = fopen($this->_tmp_filename, "wb");
-            if ($fh == false) {
-                die("Can't create temporary file.");
-            }
-        } else {
-            // Create a new file, open for writing (in binmode)
-            $fh = fopen($OLEfile, "wb");
-            if ($fh == false) {
-                die("Can't open $OLEfile. It may be in use or protected.");
+                if($oPps->Size < $rhInfo->_SMALL_SIZE) 
+                {
+                    $iSmbCnt = floor($oPps->Size / $rhInfo->_SMALL_BLOCK_SIZE) +
+                               (($oPps->Size % $rhInfo->_SMALL_BLOCK_SIZE) ? 1 : 0);
+                    #1.1 Add to SBD
+                    for ($i = 0; $i<($iSmbCnt-1); $i++) 
+                        fputs($FILE, pack("V", $i+$iSmBlk+1));
+                    fputs($FILE, pack("V", -2));
+
+                    #1.2 Add to Data String(this will be written for RootEntry)
+                    #Check for update
+                    if ($oPps->_PPS_FILE) 
+                    {
+                        //my $sBuff;
+                        fseek($oPps->_PPS_FILE, 0, SEEK_SET); #To The Top
+                        while ($sBuff=fread($oPps->_PPS_FILE, 4096)) 
+                            $sRes .= $sBuff;
+                    } 
+                    else 
+                        $sRes .= $oPps->Data;
+                    if($oPps->Size % $rhInfo->_SMALL_BLOCK_SIZE) 
+                    {
+                        $sRes .= (str_repeat("\x00",
+                                  ($rhInfo->_SMALL_BLOCK_SIZE -
+                                  ($oPps->Size % $rhInfo->_SMALL_BLOCK_SIZE))));
+                    }
+                    #1.3 Set for PPS
+                    $oPps->StartBlock = $iSmBlk;
+                    $iSmBlk += $iSmbCnt;
+                }
             }
-        }
-
-        // Store filehandle
-        $this->_filehandle = $fh;
-    }
-
-
-    /**
-    * Set the size of the data to be written to the OLE stream.
-    * The maximun size comes from this:
-    *   $big_blocks = (109 depot block x (128 -1 marker word)
-    *                 - (1 x end words)) = 13842
-    *   $maxsize    = $big_blocks * 512 bytes = 7087104
-    *
-    * @access public
-    * @see Spreadsheet_Excel_Writer_Workbook::store_OLE_file()
-    * @param integer $biffsize The size of the data to be written to the OLE stream
-    * @return integer 1 for success
-    */
-    function setSize($biffsize)
-    {
-        $maxsize = 7087104; // TODO: extend max size
 
-        if ($biffsize > $maxsize) {
-            die("Maximum file size, $maxsize, exceeded.");
         }
-
-        $this->_biffsize = $biffsize;
-        // Set the min file size to 4k to avoid having to use small blocks
-        if ($biffsize > 4096) {
-            $this->_booksize = $biffsize;
-        } else {
-            $this->_booksize = 4096;
-        }
-        //$this->_size_allowed = 1;
-        return(1);
+        $iSbCnt = floor($rhInfo->_BIG_BLOCK_SIZE / LongIntSize);
+        if ($iSmBlk  % $iSbCnt) 
+            fputs($FILE, str_repeat(pack("V", -1), $iSbCnt - ($iSmBlk % $iSbCnt)));
+        #2. Write SBD with adjusting length for block
+        return $sRes;
+    }
+
+    #------------------------------------------------------------------------------
+    # _savePpsWk (OLE::Storage_Lite::PPS)
+    #------------------------------------------------------------------------------
+    function _savePpsWk($rhInfo) 
+    {
+        #1. Write PPS
+        $FILE=$rhInfo->_FILEH_;
+        fputs($FILE,
+              $this->Name.
+              str_repeat("\x00", 64 - strlen($this->Name)).      #  64
+              pack("v", strlen($this->Name) + 2).                #  66
+              pack("c", $this->Type).                            #  67
+              pack("c", 0x00). #UK                               #  68
+              pack("V", $this->PrevPps). #Prev                   #  72
+              pack("V", $this->NextPps). #Next                   #  76
+              pack("V", $this->DirPps).  #Dir                    #  80
+              "\x00\x09\x02\x00".                                #  84
+              "\x00\x00\x00\x00".                                #  88
+              "\xc0\x00\x00\x00".                                #  92
+              "\x00\x00\x00\x46".                                #  96
+              "\x00\x00\x00\x00".                                # 100
+                         "\x00\x00\x00\x00\x00\x00\x00\x00".
+                         "\x00\x00\x00\x00\x00\x00\x00\x00".
+              pack("V", ($this->StartBlock!==false) ?
+                        $this->StartBlock : 0).                  # 120
+              pack("V", ($this->Size!==false) ?
+                        $this->Size : 0).                        # 124
+              pack("V", 0)                                       # 128
+        );
     }
 
+}
 
-    /**
-    * Calculate various sizes needed for the OLE stream
-    *
-    * @access private
-    */
-    function _calculateSizes()
-    {
-        $datasize = $this->_booksize;
-        if ($datasize % 512 == 0) {
-            $this->_big_blocks = $datasize/512;
-        } else {
-            $this->_big_blocks = floor($datasize/512) + 1;
-        }
-        // There are 127 list blocks and 1 marker blocks for each big block
-        // depot + 1 end of chain block
-        $this->_list_blocks = floor(($this->_big_blocks)/127) + 1;
-        $this->_root_start  = $this->_big_blocks;
-    }
+/*
+ * This is the OLE::Storage_Lite Perl package ported to PHP
+ * OLE::Storage_Lite was written by Kawai Takanori, kwitknr@cpan.org
+ */
 
-    /**
-    * Write root entry, big block list and close the filehandle.
-    * This routine is used to explicitly close the open filehandle without
-    * having to wait for DESTROY.
-    *
-    * @access public
-    * @see Spreadsheet_Excel_Writer_Workbook::store_OLE_file()
-    */
-    function close()
-    {
-        //return if not $this->{_size_allowed};
-        $this->_writePadding();
-        $this->_writePropertyStorage();
-        $this->_writeBigBlockDepot();
-        // Close the filehandle
-        fclose($this->_filehandle);
-        if (($this->_OLEfilename == '-') or ($this->_OLEfilename == '')) {
-            $fh = fopen($this->_tmp_filename, "rb");
-            if ($fh == false) {
-                die("Can't read temporary file.");
+class ole_pps_file extends ole_pps 
+{
+    function ole_pps_file($sNm, $sData=false, $sFile=false) 
+    {
+        $this->No         = false;
+        $this->Name       = $sNm;
+        $this->Type       = PpsType_File;
+        $this->PrevPps    = false;
+        $this->NextPps    = false;
+        $this->DirPps     = false;
+        $this->Time1st    = false;
+        $this->Time2nd    = false;
+        $this->StartBlock = false;
+        $this->Size       = false;
+        $this->Data       = ($sFile===false) ? $sData : '';
+        $this->Child      = false;
+
+        if ($sFile!==false) 
+        {
+            if (is_ressource($sFile)) 
+                $this->_PPS_FILE=$sFile;
+            elseif ($sFile=="") 
+            {
+                $fname=tempnam("php_ole");
+                $this->_PPS_FILE=fopen($fname, "r+b");
+            } 
+            else 
+            {
+                $fname=$sFile;
+                $this->_PPS_FILE=fopen($fname, "r+b");
             }
-            fpassthru($fh);
-            @unlink($this->_tmp_filename);
-        }
-        $this->_fileclosed = 1;
-    }
-
-
-    /**
-    * Write BIFF data to OLE file.
-    *
-    * @param string $data string of bytes to be written
-    */
-    function write($data)
-    {
-        fwrite($this->_filehandle, $data, strlen($data));
-    }
-
-
-    /**
-    * Write OLE header block.
-    */
-    function writeHeader()
-    {
-        $this->_calculateSizes();
-        $root_start      = $this->_root_start;
-        $num_lists       = $this->_list_blocks;
-        $id              = pack("nnnn", 0xD0CF, 0x11E0, 0xA1B1, 0x1AE1);
-        $unknown1        = pack("VVVV", 0x00, 0x00, 0x00, 0x00);
-        $unknown2        = pack("vv",   0x3E, 0x03);
-        $unknown3        = pack("v",    -2);
-        $unknown4        = pack("v",    0x09);
-        $unknown5        = pack("VVV",  0x06, 0x00, 0x00);
-        $num_bbd_blocks  = pack("V",    $num_lists);
-        $root_startblock = pack("V",    $root_start);
-        $unknown6        = pack("VV",   0x00, 0x1000);
-        $sbd_startblock  = pack("V",    -2);
-        $unknown7        = pack("VVV",  0x00, -2 ,0x00);
-        $unused          = pack("V",    -1);
-
-        fwrite($this->_filehandle, $id);
-        fwrite($this->_filehandle, $unknown1);
-        fwrite($this->_filehandle, $unknown2);
-        fwrite($this->_filehandle, $unknown3);
-        fwrite($this->_filehandle, $unknown4);
-        fwrite($this->_filehandle, $unknown5);
-        fwrite($this->_filehandle, $num_bbd_blocks);
-        fwrite($this->_filehandle, $root_startblock);
-        fwrite($this->_filehandle, $unknown6);
-        fwrite($this->_filehandle, $sbd_startblock);
-        fwrite($this->_filehandle, $unknown7);
-
-        for ($i=1; $i <= $num_lists; $i++) {
-            $root_start++;
-            fwrite($this->_filehandle, pack("V",$root_start));
-        }
-        for ($i = $num_lists; $i <=108; $i++) {
-            fwrite($this->_filehandle, $unused);
-        }
-    }
-
-
-    /**
-    * Write big block depot.
-    *
-    * @access private
-    */
-    function _writeBigBlockDepot()
-    {
-        $num_blocks   = $this->_big_blocks;
-        $num_lists    = $this->_list_blocks;
-        $total_blocks = $num_lists *128;
-        $used_blocks  = $num_blocks + $num_lists +2;
-
-        $marker       = pack("V", -3);
-        $end_of_chain = pack("V", -2);
-        $unused       = pack("V", -1);
-
-        for ($i = 1; $i < $num_blocks; $i++) {
-            fwrite($this->_filehandle, pack("V",$i));
-        }
-
-        fwrite($this->_filehandle, $end_of_chain);
-        fwrite($this->_filehandle, $end_of_chain);
-        for ($i = 0; $i < $num_lists; $i++) {
-            fwrite($this->_filehandle, $marker);
-        }
 
-        for ($i = $used_blocks; $i <= $total_blocks; $i++) {
-            fwrite($this->_filehandle, $unused);
+            if ($sData!==false) 
+                fputs($this->_PPS_FILE, $sData);
         }
     }
 
-    /**
-    * Write property storage. TODO: add summary sheets
-    *
-    * @access private
-    */
-    function _writePropertyStorage()
+    function append ($sData) 
     {
-        //$rootsize = -2;
-        /***************  name         type   dir start size */
-        $this->_writePps("Root Entry", 0x05,   1,   -2, 0x00);
-        $this->_writePps("Book",       0x02,  -1, 0x00, $this->_booksize);
-        $this->_writePps('',           0x00,  -1, 0x00, 0x0000);
-        $this->_writePps('',           0x00,  -1, 0x00, 0x0000);
+        if ($this->_PPS_FILE) 
+            fputs($this->_PPS_FILE, $sData);
+        else 
+            $this->Data.=$sData;
     }
+}
 
-/**
-* Write property sheet in property storage
-*
-* @param string  $name  name of the property storage.
-* @param integer $type  type of the property storage.
-* @param integer $dir   dir of the property storage.
-* @param integer $start start of the property storage.
-* @param integer $size  size of the property storage.
-* @access private
-*/
-    function _writePps($name, $type, $dir, $start, $size)
-    {
-        $length  = 0;
-        $rawname = '';
-
-        if ($name != '') {
-            $name = $name . "\0";
-            $name_length = strlen($name);
-            for ($i = 0; $i < $name_length; $i++) {
-                // Simulate a Unicode string
-                $rawname .= pack("H*",dechex(ord($name{$i}))).pack("C",0);
-            }
-            $length = strlen($name) * 2;
-        }
-
-        $zero            = pack("C",  0);
-        $pps_sizeofname  = pack("v",  $length);    // 0x40
-        $pps_type        = pack("v",  $type);      // 0x42
-        $pps_prev        = pack("V",  -1);         // 0x44
-        $pps_next        = pack("V",  -1);         // 0x48
-        $pps_dir         = pack("V",  $dir);       // 0x4c
-
-        $unknown1        = pack("V",  0);
-
-        $pps_ts1s        = pack("V",  0);          // 0x64
-        $pps_ts1d        = pack("V",  0);          // 0x68
-        $pps_ts2s        = pack("V",  0);          // 0x6c
-        $pps_ts2d        = pack("V",  0);          // 0x70
-        $pps_sb          = pack("V",  $start);     // 0x74
-        $pps_size        = pack("V",  $size);      // 0x78
-
-
-        fwrite($this->_filehandle, $rawname);
-        for ($i = 0; $i < (64 -$length); $i++) {
-            fwrite($this->_filehandle, $zero);
-        }
-        fwrite($this->_filehandle, $pps_sizeofname);
-        fwrite($this->_filehandle, $pps_type);
-        fwrite($this->_filehandle, $pps_prev);
-        fwrite($this->_filehandle, $pps_next);
-        fwrite($this->_filehandle, $pps_dir);
-        for ($i = 0; $i < 5; $i++) {
-            fwrite($this->_filehandle, $unknown1);
-        }
-        fwrite($this->_filehandle, $pps_ts1s);
-        fwrite($this->_filehandle, $pps_ts1d);
-        fwrite($this->_filehandle, $pps_ts2d);
-        fwrite($this->_filehandle, $pps_ts2d);
-        fwrite($this->_filehandle, $pps_sb);
-        fwrite($this->_filehandle, $pps_size);
-        fwrite($this->_filehandle, $unknown1);
-    }
+/*
+ * This is the OLE::Storage_Lite Perl package ported to PHP
+ * OLE::Storage_Lite was written by Kawai Takanori, kwitknr@cpan.org
+ */
 
-    /**
-    * Pad the end of the file
-    *
-    * @access private
-    */
-    function _writePadding()
-    {
-        $biffsize = $this->_biffsize;
-        if ($biffsize < 4096) {
-            $min_size = 4096;
-        } else {
-            $min_size = 512;
-        }
-        if ($biffsize % $min_size != 0) {
-            $padding  = $min_size - ($biffsize % $min_size);
-            for ($i = 0; $i < $padding; $i++) {
-                fwrite($this->_filehandle, "\0");
-            }
-        }
-    }
+class ole_pps_root extends ole_pps 
+{
+    function ole_pps_root($raTime1st=false, $raTime2nd=false, $raChild=false) 
+    {
+        $this->No         = false;
+        $this->Name       = Asc2Ucs('Root Entry');
+        $this->Type       = PpsType_Root;
+        $this->PrevPps    = false;
+        $this->NextPps    = false;
+        $this->DirPps     = false;
+        $this->Time1st    = $raTime1st;
+        $this->Time2nd    = $raTime2nd;
+        $this->StartBlock = false;
+        $this->Size       = false;
+        $this->Data       = false;
+        $this->Child      = $raChild;
+    }
+
+       #------------------------------------------------------------------------------
+       # save (OLE::Storage_Lite::PPS::Root)
+       #------------------------------------------------------------------------------
+       function save($sFile, $bNoAs=false, $rhInfo=false) 
+       {
+               #0.Initial Setting for saving
+
+               if (!$rhInfo) 
+                       $rhInfo=new stdClass();
+
+               $rhInfo->_BIG_BLOCK_SIZE = $rhInfo->_SMALL_BLOCK_SIZE = 0;
+               $rhInfo->_BIG_BLOCK_SIZE=pow(2, (($rhInfo->_BIG_BLOCK_SIZE) ?
+                       _adjust2($rhInfo->_BIG_BLOCK_SIZE) : 9));
+               $rhInfo->_SMALL_BLOCK_SIZE=pow(2, (($rhInfo->_SMALL_BLOCK_SIZE) ?
+                       _adjust2($rhInfo->_SMALL_BLOCK_SIZE) : 6));
+               $rhInfo->_SMALL_SIZE = 0x1000;
+               $rhInfo->_PPS_SIZE = 0x80;
+
+               #1.Open File
+               #1.1 $sFile is Ref of scalar
+               if(is_resource($sFile)) 
+               {
+                       $oIo=$sFile;
+                       $rhInfo->_FILEH_ = $oIo;
+               }
+               #1.2 $sFile is a simple filename string
+               else 
+               {
+                       $oIo=fopen("$sFile", "wb");
+                       $rhInfo->_FILEH_ = $oIo;
+               }
+
+               $iBlk = 0;
+               #1. Make an array of PPS (for Save)
+               $aList=array();
+               $list=array(&$this);
+               if($bNoAs) 
+                       $this->_savePpsSetPnt2($list, $aList, $rhInfo);
+               else 
+                       $this->_savePpsSetPnt($list, $aList, $rhInfo);
+               list($iSBDcnt, $iBBcnt, $iPPScnt) = $this->_calcSize($aList, $rhInfo);
+               #2.Save Header
+               $this->_saveHeader($rhInfo, $iSBDcnt, $iBBcnt, $iPPScnt);
+
+               #3.Make Small Data string (write SBD)
+               $sSmWk = $this->_makeSmallData($aList, $rhInfo);
+               $this->Data = $sSmWk;  #Small Datas become RootEntry Data
+
+               #4. Write BB
+               $iBBlk = $iSBDcnt;
+               $this->_saveBigData($iBBlk, $aList, $rhInfo);
+               #5. Write PPS
+               $this->_savePps($aList, $rhInfo);
+               #6. Write BD and BDList and Adding Header informations
+               $this->_saveBbd($iSBDcnt, $iBBcnt, $iPPScnt,  $rhInfo); 
+               #7.Close File
+               fclose($rhInfo->_FILEH_);
+       }
+
+       #------------------------------------------------------------------------------
+       # _calcSize (OLE::Storage_Lite::PPS)
+       #------------------------------------------------------------------------------
+       function _calcSize(&$raList, $rhInfo) 
+       {
+               #0. Calculate Basic Setting
+               $iSBDcnt=0;
+               $iBBcnt=0;
+               $iPPScnt = 0;
+               $iSmallLen = 0;
+               $iSBcnt = 0;
+
+               for ($c=0;$c<sizeof($raList);$c++) 
+               {
+               $oPps=&$raList[$c];
+
+               if($oPps->Type==PpsType_File) 
+               {
+                       $oPps->Size = $oPps->_DataLen();  #Mod
+                       if($oPps->Size < $rhInfo->_SMALL_SIZE) 
+                       {
+                               $iSBcnt += floor($oPps->Size / $rhInfo->_SMALL_BLOCK_SIZE) +
+                               (($oPps->Size % $rhInfo->_SMALL_BLOCK_SIZE) ? 1 : 0);
+                       } 
+                       else 
+                       {
+                               $iBBcnt += 
+                               (floor($oPps->Size/ $rhInfo->_BIG_BLOCK_SIZE) +
+                               (($oPps->Size % $rhInfo->_BIG_BLOCK_SIZE)? 1: 0));
+                       }
+               }
+               }       
+               $iSmallLen = $iSBcnt * $rhInfo->_SMALL_BLOCK_SIZE;
+               $iSlCnt = floor($rhInfo->_BIG_BLOCK_SIZE / LongIntSize);
+               $iSBDcnt = floor($iSBcnt / $iSlCnt)+ (($iSBcnt % $iSlCnt) ? 1 : 0);
+               $iBBcnt +=  (floor($iSmallLen/ $rhInfo->_BIG_BLOCK_SIZE) +
+               (( $iSmallLen% $rhInfo->_BIG_BLOCK_SIZE) ? 1 : 0));
+               $iCnt = sizeof($raList);
+               $iBdCnt = $rhInfo->_BIG_BLOCK_SIZE/PpsSize;
+               $iPPScnt = (floor($iCnt/$iBdCnt) + (($iCnt % $iBdCnt) ? 1 : 0));
+
+               return array($iSBDcnt, $iBBcnt, $iPPScnt);
+       }
+
+       #------------------------------------------------------------------------------
+       # _adjust2 (OLE::Storage_Lite::PPS::Root)
+       #------------------------------------------------------------------------------
+       function _adjust2($i2) 
+       {
+               $iWk = log($i2)/log(2);
+               return ($iWk > int($iWk)) ? floor($iWk)+1 : $iWk;
+       }
+
+       #------------------------------------------------------------------------------
+       # _saveHeader (OLE::Storage_Lite::PPS::Root)
+       #------------------------------------------------------------------------------
+       function _saveHeader($rhInfo, $iSBDcnt, $iBBcnt, $iPPScnt) 
+       {
+               $FILE = $rhInfo->_FILEH_;
+
+               #0. Calculate Basic Setting
+               $iBlCnt = $rhInfo->_BIG_BLOCK_SIZE / LongIntSize;
+               $i1stBdL = ($rhInfo->_BIG_BLOCK_SIZE - 0x4C) / LongIntSize;
+
+               $iBdExL = 0;
+               $iAll = $iBBcnt + $iPPScnt + $iSBDcnt;
+               $iAllW = $iAll;
+               $iBdCntW = floor($iAllW / $iBlCnt) + (($iAllW % $iBlCnt) ? 1 : 0);
+               $iBdCnt = floor(($iAll + $iBdCntW) / $iBlCnt) + ((($iAllW+$iBdCntW) % $iBlCnt) ? 1 : 0);
+               //my $i;
+
+               #0.1 Calculate BD count
+               if ($iBdCnt > $i1stBdL) 
+               {
+                       // TODO: is do-while correct here?
+                       do 
+                       {
+                       $iBdExL++;
+                       $iAllW++;
+                       $iBdCntW = floor($iAllW / $iBlCnt) + (($iAllW % $iBlCnt) ? 1 : 0);
+                       $iBdCnt = floor(($iAllW + $iBdCntW) / $iBlCnt) + ((($iAllW+$iBdCntW) % $iBlCnt) ? 1 : 0);
+               } 
+               while($iBdCnt > ($iBdExL*$iBlCnt+ $i1stBdL));
+               }
+
+               #1.Save Header
+               fputs($FILE,
+            "\xD0\xCF\x11\xE0\xA1\xB1\x1A\xE1".
+            "\x00\x00\x00\x00".
+            "\x00\x00\x00\x00".
+            "\x00\x00\x00\x00".
+            "\x00\x00\x00\x00".
+            pack("v", 0x3b).
+            pack("v", 0x03).
+            pack("v", -2).
+            pack("v", 9).
+            pack("v", 6).
+            pack("v", 0).
+            "\x00\x00\x00\x00".
+            "\x00\x00\x00\x00".
+            pack("V", $iBdCnt).
+            pack("V", $iBBcnt+$iSBDcnt). #ROOT START
+            pack("V", 0).
+            pack("V", 0x1000).
+            pack("V", 0).                  #Small Block Depot
+            pack("V", 1)
+       );
+               #2. Extra BDList Start, Count
+               if($iBdCnt < $i1stBdL) 
+               {
+               fputs($FILE, 
+                pack("V", -2).     #Extra BDList Start
+                pack("V", 0)       #Extra BDList Count
+               );
+               } 
+               else 
+               {
+               fputs($FILE,
+               pack("V", $iAll+$iBdCnt).
+               pack("V", $iBdExL)
+           );
+               }
+
+               #3. BDList
+       for ($i=0;($i<$i1stBdL) && ($i < $iBdCnt); $i++) 
+               fputs($FILE, pack("V", $iAll+$i));
+       if ($i<$i1stBdL) 
+       {
+                       // TODO: Check, if str_repeat is binary safe
+               fputs($FILE, str_repeat((pack("V", -1)), ($i1stBdL-$i)));
+       }
+       }
+
+       #------------------------------------------------------------------------------
+       # _saveBigData (OLE::Storage_Lite::PPS)
+       #------------------------------------------------------------------------------
+       function _saveBigData(&$iStBlk, &$raList, $rhInfo) 
+       {
+
+               //return;//!!!
+
+               $iRes = 0;
+               $FILE = $rhInfo->_FILEH_;
+
+               #1.Write Big (ge 0x1000) Data into Block
+               for ($c=0;$c<sizeof($raList);$c++) 
+               {
+               $oPps=&$raList[$c];
+               if($oPps->Type!=PpsType_Dir) 
+               {
+                               #print "PPS: $oPps DEF:", defined($oPps->{Data}), "\n";
+                       $oPps->Size = $oPps->_DataLen();  #Mod
+                       if(($oPps->Size >= $rhInfo->_SMALL_SIZE) ||
+                       (($oPps->Type == PpsType_Root) && $oPps->Data!==false)) 
+               {
+                       #1.1 Write Data
+                       #Check for update
+                       if($oPps->_PPS_FILE) 
+                       {
+                               //my $sBuff;
+                               $iLen = 0;
+                               fseek($oPps->_PPS_FILE, 0, SEEK_SET); #To The Top
+                               while ($sBuff=fread($oPps->_PPS_FILE, 4096)) 
+                               {
+                               $iLen += length($sBuff);
+                               fputs($FILE, $sBuff);           #Check for update
+                               }
+                       } 
+                       else 
+                               fputs($FILE, $oPps->Data);
+                       if ($oPps->Size % $rhInfo->_BIG_BLOCK_SIZE) 
+                       {
+                                               // TODO: Check, if str_repeat() is binary safe
+                               fputs($FILE, str_repeat("\x00", 
+                               ($rhInfo->_BIG_BLOCK_SIZE - 
+                            ($oPps->Size % $rhInfo->_BIG_BLOCK_SIZE)))
+                       );
+                       }
+                       #1.2 Set For PPS
+                       $oPps->StartBlock = $iStBlk;
+                       $iStBlk += 
+                       (floor($oPps->Size/ $rhInfo->_BIG_BLOCK_SIZE) +
+                        (($oPps->Size % $rhInfo->_BIG_BLOCK_SIZE) ? 1 : 0));
+                       }
+               }
+               }
+       }
+
+       #------------------------------------------------------------------------------
+       # _savePps (OLE::Storage_Lite::PPS::Root)
+       #------------------------------------------------------------------------------
+       function _savePps(&$raList, $rhInfo) 
+       {
+               #0. Initial
+               $FILE = $rhInfo->_FILEH_;
+               #2. Save PPS
+               for ($c=0;$c<sizeof($raList);$c++) 
+               {
+               $oItem=&$raList[$c];
+               $oItem->_savePpsWk($rhInfo);
+               }
+               #3. Adjust for Block
+               $iCnt = sizeof($raList);
+               $iBCnt = $rhInfo->_BIG_BLOCK_SIZE / $rhInfo->_PPS_SIZE;
+               if($iCnt % $iBCnt) 
+               fputs($FILE, str_repeat("\x00", (($iBCnt - ($iCnt % $iBCnt)) * $rhInfo->_PPS_SIZE)));
+               return (floor($iCnt / $iBCnt) + (($iCnt % $iBCnt) ? 1 : 0));
+       }
+
+       #------------------------------------------------------------------------------
+       # _savePpsSetPnt2 (OLE::Storage_Lite::PPS::Root)
+       #  For Test
+       #------------------------------------------------------------------------------
+       function _savePpsSetPnt2(&$aThis, &$raList, $rhInfo) 
+       {
+               #1. make Array as Children-Relations
+               #1.1 if No Children
+               if (!is_array($aThis) || sizeof($aThis)==0) 
+               return 0xFFFFFFFF;
+               elseif (sizeof($aThis)==1) 
+               {
+                       #1.2 Just Only one
+               array_push($raList, $aThis[0]);
+               $aThis[0]->No = sizeof($raList)-1;
+               $aThis[0]->PrevPps = 0xFFFFFFFF;
+               $aThis[0]->NextPps = 0xFFFFFFFF;
+               $aThis[0]->DirPps = $this->_savePpsSetPnt2($aThis[0]->Child, $raList, $rhInfo);
+               return $aThis[0]->No;
+               } 
+               else 
+               {
+                       #1.3 Array
+               $iCnt = sizeof($aThis);
+                       #1.3.1 Define Center
+               $iPos = 0; #int($iCnt/ 2);     #$iCnt 
+
+               $aWk = $aThis;
+               $aPrev = (sizeof($aThis) > 2) ? array_splice($aWk, 1, 1) : array(); #$iPos);
+               $aNext = array_splice($aWk, 1); #, $iCnt - $iPos -1);
+               $aThis[$iPos]->PrevPps = $this->_savePpsSetPnt2($aPrev, $raList, $rhInfo);
+               array_push($raList, $aThis[$iPos]);
+               $aThis[$iPos]->No = sizeof($raList)-1;
+
+                       #1.3.2 Devide a array into Previous,Next
+               $aThis[$iPos]->NextPps = $this->_savePpsSetPnt2($aNext, $raList, $rhInfo);
+               $aThis[$iPos]->DirPps = $this->_savePpsSetPnt2($aThis[$iPos]->Child, $raList, $rhInfo);
+               return $aThis[$iPos]->No;
+               }
+       }
+
+       #------------------------------------------------------------------------------
+       # _savePpsSetPnt2 (OLE::Storage_Lite::PPS::Root)
+       #  For Test
+       #------------------------------------------------------------------------------
+       function _savePpsSetPnt2s(&$aThis, &$raList, $rhInfo) 
+       {
+               #1. make Array as Children-Relations
+               #1.1 if No Children
+               if (!is_array($aThis) || sizeof($aThis)==0) 
+               return 0xFFFFFFFF;
+               elseif (sizeof($aThis)==1) 
+               {
+                       #1.2 Just Only one
+               array_push($raList, $aThis[0]);
+               $aThis[0]->No = sizeof($raList)-1;
+               $aThis[0]->PrevPps = 0xFFFFFFFF;
+               $aThis[0]->NextPps = 0xFFFFFFFF;
+               $aThis[0]->DirPps = $this->_savePpsSetPnt2($aThis[0]->Child, $raList, $rhInfo);
+               return $aThis[0]->No;
+               } 
+               else 
+               {
+                       #1.3 Array
+               $iCnt = sizeof($aThis);
+                       #1.3.1 Define Center
+               $iPos = 0; #int($iCnt/ 2);     #$iCnt 
+               array_push($raList, $aThis[$iPos]);
+               $aThis[$iPos]->No = sizeof($raList)-1;
+               $aWk = $aThis;
+                       #1.3.2 Devide a array into Previous,Next
+               $aPrev = array_splice($aWk, 0, $iPos);
+               $aNext = array_splice($aWk, 1, $iCnt - $iPos - 1);
+               $aThis[$iPos]->PrevPps = $this->_savePpsSetPnt2($aPrev, $raList, $rhInfo);
+               $aThis[$iPos]->NextPps = $this->_savePpsSetPnt2($aNext, $raList, $rhInfo);
+               $aThis[$iPos]->DirPps = $this->_savePpsSetPnt2($aThis[$iPos]->Child, $raList, $rhInfo);
+               return $aThis[$iPos]->No;
+               }
+       }
+
+       #------------------------------------------------------------------------------
+       # _savePpsSetPnt (OLE::Storage_Lite::PPS::Root)
+       #------------------------------------------------------------------------------
+       function _savePpsSetPnt(&$aThis, &$raList, $rhInfo) 
+       {
+
+               //print "yyy type: ".gettype($aThis)."<br>\n";
+               //print "yyy name: ".$aThis[0]->Name."<br>\n";
+
+               #1. make Array as Children-Relations
+               #1.1 if No Children
+               if (!is_array($aThis) || sizeof($aThis)==0) 
+               {
+               return 0xFFFFFFFF;
+               } 
+               elseif (sizeof($aThis)==1) 
+               {
+                       #1.2 Just Only one
+               array_push($raList, $aThis[0]);
+               $aThis[0]->No = sizeof($raList)-1;
+               $aThis[0]->PrevPps = 0xFFFFFFFF;
+               $aThis[0]->NextPps = 0xFFFFFFFF;
+               $aThis[0]->DirPps = $this->_savePpsSetPnt($aThis[0]->Child, $raList, $rhInfo);
+               return $aThis[0]->No;
+               } 
+               else 
+               {       
+                       #1.3 Array
+               $iCnt = sizeof($aThis);
+                       #1.3.1 Define Center
+               $iPos = floor($iCnt/2);     #$iCnt 
+               array_push($raList, $aThis[$iPos]);
+               $aThis[$iPos]->No = sizeof($raList)-1;
+               $aWk = $aThis;
+                       #1.3.2 Devide a array into Previous,Next
+               $aPrev = splice($aWk, 0, $iPos);
+               $aNext = splice($aWk, 1, $iCnt - $iPos - 1);
+               $aThis[$iPos]->PrevPps = $this->_savePpsSetPnt($aPrev, $raList, $rhInfo);
+               $aThis[$iPos]->NextPps = $this->_savePpsSetPnt($aNext, $raList, $rhInfo);
+               $aThis[$iPos]->DirPps = $this->_savePpsSetPnt($aThis[$iPos]->Child, $raList, $rhInfo);
+               return $aThis[$iPos]->No;
+               }
+       }
+
+       #------------------------------------------------------------------------------
+       # _savePpsSetPnt (OLE::Storage_Lite::PPS::Root)
+       #------------------------------------------------------------------------------
+       function _savePpsSetPnt1(&$aThis, &$raList, $rhInfo) 
+       {
+               #1. make Array as Children-Relations
+               #1.1 if No Children
+               if (!is_array($aThis) || sizeof($aThis)==0) 
+               {
+                       return 0xFFFFFFFF;
+               } 
+               elseif (sizeof($aThis)==1) 
+               {
+                       #1.2 Just Only one
+                       array_push($raList, $aThis[0]);
+                       $aThis[0]->No = sizeof($raList)-1;
+                       $aThis[0]->PrevPps = 0xFFFFFFFF;
+                       $aThis[0]->NextPps = 0xFFFFFFFF;
+                       $aThis[0]->DirPps = $this->_savePpsSetPnt($aThis[0]->Child, $raList, $rhInfo);
+                       return $aThis[0]->No;
+               } 
+               else 
+               {
+                       #1.3 Array
+                       $iCnt = sizeof($aThis);
+                       #1.3.1 Define Center
+                       $iPos = floor($iCnt / 2);     #$iCnt 
+                       array_push($raList, $aThis[$iPos]);
+                       $aThis[$iPos]->No = sizeof($raList)-1;
+                       $aWk = $aThis;
+                       #1.3.2 Devide a array into Previous,Next
+                       $aPrev = splice($aWk, 0, $iPos);
+                       $aNext = splice($aWk, 1, $iCnt - $iPos - 1);
+                       $aThis[$iPos]->PrevPps = $this->_savePpsSetPnt($aPrev, $raList, $rhInfo);
+                       $aThis[$iPos]->NextPps = $this->_savePpsSetPnt($aNext, $raList, $rhInfo);
+                       $aThis[$iPos]->DirPps = $this->_savePpsSetPnt($aThis[$iPos]->Child, $raList, $rhInfo);
+                       return $aThis[$iPos]->No;
+               }
+       }
+
+       #------------------------------------------------------------------------------
+       # _saveBbd (OLE::Storage_Lite)
+       #------------------------------------------------------------------------------
+       function _saveBbd($iSbdSize, $iBsize, $iPpsCnt, $rhInfo) 
+       {
+               $FILE = $rhInfo->_FILEH_;
+               #0. Calculate Basic Setting
+               $iBbCnt = $rhInfo->_BIG_BLOCK_SIZE / LongIntSize;
+               $i1stBdL = ($rhInfo->_BIG_BLOCK_SIZE - 0x4C) / LongIntSize;
+
+               $iBdExL = 0;
+               $iAll = $iBsize + $iPpsCnt + $iSbdSize;
+               $iAllW = $iAll;
+               $iBdCntW = floor($iAllW / $iBbCnt) + (($iAllW % $iBbCnt) ? 1 : 0);
+               $iBdCnt = floor(($iAll + $iBdCntW) / $iBbCnt) + ((($iAllW+$iBdCntW) % $iBbCnt)? 1: 0);
+               //my $i;
+               #0.1 Calculate BD count
+               if ($iBdCnt >$i1stBdL) 
+               {
+                       // TODO: do-while correct here?
+               do 
+               {
+                       $iBdExL++;
+                       $iAllW++;
+                       $iBdCntW = floor($iAllW / $iBbCnt) + (($iAllW % $iBbCnt) ? 1 : 0);
+                       $iBdCnt = floor(($iAllW + $iBdCntW) / $iBbCnt) + ((($iAllW+$iBdCntW) % $iBbCnt) ? 1 : 0);
+               } 
+               while ($iBdCnt > ($iBdExL*$iBbCnt+$i1stBdL));
+               }
+
+               #1. Making BD
+               #1.1 Set for SBD
+               if($iSbdSize > 0) 
+               {
+               for ($i = 0; $i<($iSbdSize-1); $i++) 
+                       fputs($FILE, pack("V", $i+1));
+               fputs($FILE, pack("V", -2));
+               }
+               #1.2 Set for B
+               for ($i = 0; $i<($iBsize-1); $i++) 
+               fputs($FILE, pack("V", $i+$iSbdSize+1));
+               fputs($FILE, pack("V", -2));
+
+               #1.3 Set for PPS
+               for ($i = 0; $i<($iPpsCnt-1); $i++) 
+               fputs($FILE, pack("V", $i+$iSbdSize+$iBsize+1));
+               fputs($FILE, pack("V", -2));
+               #1.4 Set for BBD itself ( 0xFFFFFFFD : BBD)
+               for ($i=0; $i<$iBdCnt;$i++) 
+               fputs($FILE, pack("V", 0xFFFFFFFD));
+               #1.5 Set for ExtraBDList
+               for ($i=0; $i<$iBdExL;$i++) 
+               fputs($FILE, pack("V", 0xFFFFFFFC));
+               #1.6 Adjust for Block
+               if(($iAllW + $iBdCnt) % $iBbCnt) 
+               fputs($FILE, str_repeat(pack("V", -1), ($iBbCnt - (($iAllW + $iBdCnt) % $iBbCnt))));
+
+               #2.Extra BDList
+               if($iBdCnt > $i1stBdL)  
+               {
+               $iN=0;
+               $iNb=0;
+               for ($i=$i1stBdL;$i<$iBdCnt; $i++, $iN++) 
+               {
+                       if($iN>=($iBbCnt-1)) 
+                       {
+                               $iN = 0;
+                               $iNb++;
+                               fputs($FILE, pack("V", $iAll+$iBdCnt+$iNb));
+                       }
+                       fputs($FILE, pack("V", $iBsize+$iSbdSize+$iPpsCnt+$i));
+               }
+               if(($iBdCnt-$i1stBdL) % ($iBbCnt-1)) 
+                       fputs($FILE, str_repeat(pack("V", -1), (($iBbCnt-1) - (($iBdCnt-$i1stBdL) % ($iBbCnt-1)))));
+               fputs($FILE, pack("V", -2));
+               }
+       }
 }
 
 /**
@@ -7399,21 +7812,24 @@ class Spreadsheet_Excel_Writer_Workbook extends Spreadsheet_Excel_Writer_BIFFwri
     */
     function _storeOLEFile()
     {
-        $OLE  = new OLEwriter($this->_filename);
-        // Write Worksheet data if data <~ 7MB
-        if ($OLE->setSize($this->_biffsize))
-        {
-            $OLE->writeHeader();
-            $OLE->write($this->_data);
-            foreach($this->_worksheets as $sheet) 
-            {
-                while ($tmp = $sheet->getData()) {
-                    $OLE->write($tmp);
-                }
+        if($this->_BIFF_version == 0x0600) {
+            $OLE = new ole_pps_file(Asc2Ucs('Workbook'));
+        } else {
+            $OLE = new ole_pps_file(Asc2Ucs('Book'));
+        }
+
+        $OLE->append($this->_data);
+
+        $total_worksheets = count($this->_worksheets);
+        for ($i = 0; $i < $total_worksheets; $i++) {
+            while ($tmp = $this->_worksheets[$i]->getData()) {
+                $OLE->append($tmp);
             }
         }
-        $OLE->close();
-        return true;
+
+        $root = new ole_pps_root(false, false, array($OLE));
+
+        $root->save($this->_filename);
     }
 
     /**
index c6f0d4436039b97519644a57e94f08c915baae3d..3786a91aaf9d92bcba4522a2096473deac9dc390 100644 (file)
@@ -13,6 +13,7 @@ include_once($path_to_root . "/reporting/includes/Workbook.php");
 include_once($path_to_root . "/admin/db/company_db.inc");
 include_once($path_to_root . "/admin/db/fiscalyears_db.inc");
 include_once($path_to_root . "/config.php");
+define('MAX_ROW_SHEET', 65530);
 // xls version
 class FrontReport extends Spreadsheet_Excel_Writer_Workbook
 {
@@ -86,7 +87,7 @@ class FrontReport extends Spreadsheet_Excel_Writer_Workbook
                $this->Spreadsheet_Excel_Writer_Workbook($this->path."/".$this->unique_name);
                if ($this->code != "iso-8859-1")
                        $this->setVersion(8); // set biff version to 8 (0x0006 internal)
-               $this->sheet =& $this->addWorksheet($this->worksheetNameGenerator($this->title));
+               $this->sheet = $this->addWorksheet($this->worksheetNameGenerator($this->title));
                if ($this->code != "iso-8859-1")
                        $this->sheet->setInputEncoding($this->code); // set sheet encoding
                if ($rtl)
@@ -641,6 +642,17 @@ class FrontReport extends Spreadsheet_Excel_Writer_Workbook
        function NewLine($l=1, $np=0, $h=NULL)
        {
                $this->y += $l;
+               if ($this->y > MAX_ROW_SHEET)
+               {
+                       $this->y = 0;
+                       $this->sheet = $this->addWorksheet();
+                       if ($this->code != "iso-8859-1")
+                               $this->sheet->setInputEncoding($this->code); // set sheet encoding
+                       if ($_SESSION['language']->dir == 'rtl')
+                               $this->sheet->setRTL();
+                       for ($i = 0; $i < $this->numcols; $i++)
+                               $this->sheet->setColumn($i, $i, $this->px2units($this->cols[$i + 1] - $this->cols[$i]));
+               }
        }
        
        function NewPage()