PHPExcel_Writer_Excel5_Writer
[ class tree: PHPExcel_Writer_Excel5_Writer ] [ index: PHPExcel_Writer_Excel5_Writer ] [ all elements ]

Source for file Worksheet.php

Documentation is available at Worksheet.php

  1. <?php
  2. /*
  3. *  Module written/ported by Xavier Noguer <xnoguer@rezebra.com>
  4. *
  5. *  The majority of this is _NOT_ my code.  I simply ported it from the
  6. *  PERL Spreadsheet::WriteExcel module.
  7. *
  8. *  The author of the Spreadsheet::WriteExcel module is John McNamara
  9. *  <jmcnamara@cpan.org>
  10. *
  11. *  I _DO_ maintain this code, and John McNamara has nothing to do with the
  12. *  porting of this code to PHP.  Any questions directly related to this
  13. *  class library should be directed to me.
  14. *
  15. *  License Information:
  16. *
  17. *    PHPExcel_Writer_Excel5_Writer:  A library for generating Excel Spreadsheets
  18. *    Copyright (c) 2002-2003 Xavier Noguer xnoguer@rezebra.com
  19. *
  20. *    This library is free software; you can redistribute it and/or
  21. *    modify it under the terms of the GNU Lesser General Public
  22. *    License as published by the Free Software Foundation; either
  23. *    version 2.1 of the License, or (at your option) any later version.
  24. *
  25. *    This library is distributed in the hope that it will be useful,
  26. *    but WITHOUT ANY WARRANTY; without even the implied warranty of
  27. *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  28. *    Lesser General Public License for more details.
  29. *
  30. *    You should have received a copy of the GNU Lesser General Public
  31. *    License along with this library; if not, write to the Free Software
  32. *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  33. */
  34.  
  35. require_once 'PHPExcel/Writer/Excel5/Parser.php';
  36. require_once 'PHPExcel/Writer/Excel5/BIFFwriter.php';
  37.  
  38. /**
  39. * Class for generating Excel Spreadsheets
  40. *
  41. @author   Xavier Noguer <xnoguer@rezebra.com>
  42. @category FileFormats
  43. @package  PHPExcel_Writer_Excel5_Writer
  44. */
  45.  
  46. {
  47.     /**
  48.     * Name of the Worksheet
  49.     * @var string 
  50.     */
  51.     var $name;
  52.  
  53.     /**
  54.     * Index for the Worksheet
  55.     * @var integer 
  56.     */
  57.     var $index;
  58.  
  59.     /**
  60.     * Reference to the (default) Format object for URLs
  61.     * @var object Format 
  62.     */
  63.     var $_url_format;
  64.  
  65.     /**
  66.     * Reference to the parser used for parsing formulas
  67.     * @var object Format 
  68.     */
  69.     var $_parser;
  70.  
  71.     /**
  72.     * Filehandle to the temporary file for storing data
  73.     * @var resource 
  74.     */
  75.     var $_filehandle;
  76.  
  77.     /**
  78.     * Boolean indicating if we are using a temporary file for storing data
  79.     * @var bool 
  80.     */
  81.     var $_using_tmpfile;
  82.  
  83.     /**
  84.     * Maximum number of rows for an Excel spreadsheet (BIFF5)
  85.     * @var integer 
  86.     */
  87.     var $_xls_rowmax;
  88.  
  89.     /**
  90.     * Maximum number of columns for an Excel spreadsheet (BIFF5)
  91.     * @var integer 
  92.     */
  93.     var $_xls_colmax;
  94.  
  95.     /**
  96.     * Maximum number of characters for a string (LABEL record in BIFF5)
  97.     * @var integer 
  98.     */
  99.     var $_xls_strmax;
  100.  
  101.     /**
  102.     * First row for the DIMENSIONS record
  103.     * @var integer 
  104.     * @see _storeDimensions()
  105.     */
  106.     var $_dim_rowmin;
  107.  
  108.     /**
  109.     * Last row for the DIMENSIONS record
  110.     * @var integer 
  111.     * @see _storeDimensions()
  112.     */
  113.     var $_dim_rowmax;
  114.  
  115.     /**
  116.     * First column for the DIMENSIONS record
  117.     * @var integer 
  118.     * @see _storeDimensions()
  119.     */
  120.     var $_dim_colmin;
  121.  
  122.     /**
  123.     * Last column for the DIMENSIONS record
  124.     * @var integer 
  125.     * @see _storeDimensions()
  126.     */
  127.     var $_dim_colmax;
  128.  
  129.     /**
  130.      * Default column character width
  131.      */
  132.     private $_defColWidth = 8;
  133.  
  134.     /**
  135.      * Default row height in twips = 1/20 point
  136.      */
  137.     private $_defaultRowHeight = null;
  138.  
  139.     /**
  140.     * Array containing format information for columns
  141.     * @var array 
  142.     */
  143.     var $_colinfo;
  144.  
  145.     /**
  146.     * Array containing the selected area for the worksheet
  147.     * @var array 
  148.     */
  149.     var $_selection;
  150.  
  151.     /**
  152.     * Array containing the panes for the worksheet
  153.     * @var array 
  154.     */
  155.     var $_panes;
  156.  
  157.     /**
  158.     * The active pane for the worksheet
  159.     * @var integer 
  160.     */
  161.     var $_active_pane;
  162.  
  163.     /**
  164.     * Bit specifying if panes are frozen
  165.     * @var integer 
  166.     */
  167.     var $_frozen;
  168.  
  169.     /**
  170.     * Bit specifying if the worksheet is selected
  171.     * @var integer 
  172.     */
  173.     var $selected;
  174.  
  175.     /**
  176.     * The paper size (for printing) (DOCUMENT!!!)
  177.     * @var integer 
  178.     */
  179.     var $_paper_size;
  180.  
  181.     /**
  182.     * Bit specifying paper orientation (for printing). 0 => landscape, 1 => portrait
  183.     * @var integer 
  184.     */
  185.     var $_orientation;
  186.  
  187.     /**
  188.     * The page header caption
  189.     * @var string 
  190.     */
  191.     var $_header;
  192.  
  193.     /**
  194.     * The page footer caption
  195.     * @var string 
  196.     */
  197.     var $_footer;
  198.  
  199.     /**
  200.     * The horizontal centering value for the page
  201.     * @var integer 
  202.     */
  203.     var $_hcenter;
  204.  
  205.     /**
  206.     * The vertical centering value for the page
  207.     * @var integer 
  208.     */
  209.     var $_vcenter;
  210.  
  211.     /**
  212.     * The margin for the header
  213.     * @var float 
  214.     */
  215.     var $_margin_head;
  216.  
  217.     /**
  218.     * The margin for the footer
  219.     * @var float 
  220.     */
  221.     var $_margin_foot;
  222.  
  223.     /**
  224.     * The left margin for the worksheet in inches
  225.     * @var float 
  226.     */
  227.     var $_margin_left;
  228.  
  229.     /**
  230.     * The right margin for the worksheet in inches
  231.     * @var float 
  232.     */
  233.     var $_margin_right;
  234.  
  235.     /**
  236.     * The top margin for the worksheet in inches
  237.     * @var float 
  238.     */
  239.     var $_margin_top;
  240.  
  241.     /**
  242.     * The bottom margin for the worksheet in inches
  243.     * @var float 
  244.     */
  245.     var $_margin_bottom;
  246.  
  247.     /**
  248.     * First row to reapeat on each printed page
  249.     * @var integer 
  250.     */
  251.     var $title_rowmin;
  252.  
  253.     /**
  254.     * Last row to reapeat on each printed page
  255.     * @var integer 
  256.     */
  257.     var $title_rowmax;
  258.  
  259.     /**
  260.     * First column to reapeat on each printed page
  261.     * @var integer 
  262.     */
  263.     var $title_colmin;
  264.  
  265.     /**
  266.     * First row of the area to print
  267.     * @var integer 
  268.     */
  269.     var $print_rowmin;
  270.  
  271.     /**
  272.     * Last row to of the area to print
  273.     * @var integer 
  274.     */
  275.     var $print_rowmax;
  276.  
  277.     /**
  278.     * First column of the area to print
  279.     * @var integer 
  280.     */
  281.     var $print_colmin;
  282.  
  283.     /**
  284.     * Last column of the area to print
  285.     * @var integer 
  286.     */
  287.     var $print_colmax;
  288.  
  289.     /**
  290.     * Whether to use outline.
  291.     * @var integer 
  292.     */
  293.     var $_outline_on;
  294.  
  295.     /**
  296.     * Auto outline styles.
  297.     * @var bool 
  298.     */
  299.     var $_outline_style;
  300.  
  301.     /**
  302.     * Whether to have outline summary below.
  303.     * @var bool 
  304.     */
  305.     var $_outline_below;
  306.  
  307.     /**
  308.     * Whether to have outline summary at the right.
  309.     * @var bool 
  310.     */
  311.     var $_outline_right;
  312.  
  313.     /**
  314.     * Outline row level.
  315.     * @var integer 
  316.     */
  317.     var $_outline_row_level;
  318.  
  319.     /**
  320.     * Whether to fit to page when printing or not.
  321.     * @var bool 
  322.     */
  323.     var $_fit_page;
  324.  
  325.     /**
  326.     * Number of pages to fit wide
  327.     * @var integer 
  328.     */
  329.     var $_fit_width;
  330.  
  331.     /**
  332.     * Number of pages to fit high
  333.     * @var integer 
  334.     */
  335.     var $_fit_height;
  336.  
  337.     /**
  338.     * Reference to the total number of strings in the workbook
  339.     * @var integer 
  340.     */
  341.     var $_str_total;
  342.  
  343.     /**
  344.     * Reference to the number of unique strings in the workbook
  345.     * @var integer 
  346.     */
  347.     var $_str_unique;
  348.  
  349.     /**
  350.     * Reference to the array containing all the unique strings in the workbook
  351.     * @var array 
  352.     */
  353.     var $_str_table;
  354.  
  355.     /**
  356.     * Merged cell ranges
  357.     * @var array 
  358.     */
  359.     var $_merged_ranges;
  360.  
  361.     /**
  362.     * Charset encoding currently used when calling writeString()
  363.     * @var string 
  364.     */
  365.     var $_input_encoding;
  366.  
  367.     /**
  368.     * The temporary dir for storing files
  369.     * @var string 
  370.     */
  371.     var $_tmp_dir;
  372.  
  373.     /**
  374.     * List of temporary files created
  375.     * @var array 
  376.     */
  377.     var $_tempFilesCreated = array();
  378.  
  379.     /**
  380.      * Index of first used row (at least 0)
  381.      * @var int 
  382.      */
  383.     private $_firstRowIndex;
  384.  
  385.     /**
  386.      * Index of last used row. (no used rows means -1)
  387.      * @var int 
  388.      */
  389.     private $_lastRowIndex;
  390.  
  391.     /**
  392.      * Index of first used column (at least 0)
  393.      * @var int 
  394.      */
  395.     private $_firstColumnIndex;
  396.  
  397.     /**
  398.      * Index of last used column (no used columns means -1)
  399.      * @var int 
  400.      */
  401.     private $_lastColumnIndex;
  402.  
  403.     /**
  404.     * Constructor
  405.     *
  406.     * @param string  $name         The name of the new worksheet
  407.     * @param integer $index        The index of the new worksheet
  408.     * @param mixed   &$activesheet The current activesheet of the workbook we belong to
  409.     * @param mixed   &$firstsheet  The first worksheet in the workbook we belong to
  410.     * @param mixed   &$url_format  The default format for hyperlinks
  411.     * @param mixed   &$parser      The formula parser created for the Workbook
  412.     * @param string   $tempDir      The temporary directory to be used
  413.     * @access private
  414.     */
  415.     function PHPExcel_Writer_Excel5_Worksheet($BIFF_version$name,
  416.                                                 $index&$activesheet,
  417.                                                 &$firstsheet&$str_total,
  418.                                                 &$str_unique&$str_table,
  419.                                                 &$url_format&$parser$tempDir '')
  420.     {
  421.         // It needs to call its parent's constructor explicitly
  422.         $this->PHPExcel_Writer_Excel5_BIFFwriter();
  423.         $this->_BIFF_version    = $BIFF_version;
  424.         $rowmax                    65536// 16384 in Excel 5
  425.         $colmax                    256;
  426.  
  427.         $this->name                = $name;
  428.         $this->index            = $index;
  429.         $this->activesheet        &$activesheet;
  430.         $this->firstsheet        &$firstsheet;
  431.         $this->_str_total        = &$str_total;
  432.         $this->_str_unique        = &$str_unique;
  433.         $this->_str_table        = &$str_table;
  434.         $this->_url_format        = &$url_format;
  435.         $this->_parser            = &$parser;
  436.  
  437.         //$this->ext_sheets        = array();
  438.         $this->_filehandle        = '';
  439.         $this->_using_tmpfile    = true;
  440.         //$this->fileclosed        = 0;
  441.         //$this->offset            = 0;
  442.         $this->_xls_rowmax        = $rowmax;
  443.         $this->_xls_colmax        = $colmax;
  444.         $this->_xls_strmax        = 255;
  445.         $this->_dim_rowmin        = $rowmax 1;
  446.         $this->_dim_rowmax        = 0;
  447.         $this->_dim_colmin        = $colmax 1;
  448.         $this->_dim_colmax        = 0;
  449.         $this->_colinfo            = array();
  450.         $this->_selection        = array(0,0,0,0);
  451.         $this->_panes            = array();
  452.         $this->_active_pane        = 3;
  453.         $this->_frozen            = 0;
  454.         $this->selected            = 0;
  455.  
  456.         $this->_paper_size        = 0x0;
  457.         $this->_orientation        = 0x1;
  458.         $this->_header            = '';
  459.         $this->_footer            = '';
  460.         $this->_hcenter            = 0;
  461.         $this->_vcenter            = 0;
  462.         $this->_margin_head        = 0.50;
  463.         $this->_margin_foot        = 0.50;
  464.         $this->_margin_left        = 0.75;
  465.         $this->_margin_right    = 0.75;
  466.         $this->_margin_top        = 1.00;
  467.         $this->_margin_bottom    = 1.00;
  468.  
  469.         $this->title_rowmin        = null;
  470.         $this->title_rowmax        = null;
  471.         $this->title_colmin        = null;
  472.         $this->title_colmax        null;
  473.         $this->print_rowmin        = null;
  474.         $this->print_rowmax        = null;
  475.         $this->print_colmin        = null;
  476.         $this->print_colmax        = null;
  477.  
  478.         $this->_print_gridlines        1;
  479.         $this->_screen_gridlines    1;
  480.         $this->_print_headers        0;
  481.  
  482.         $this->_fit_page        = 0;
  483.         $this->_fit_width        = 0;
  484.         $this->_fit_height        = 0;
  485.  
  486.         $this->_hbreaks            array();
  487.         $this->_vbreaks            array();
  488.  
  489.         $this->_protect            0;
  490.         $this->_password        null;
  491.  
  492.         $this->col_sizes        array();
  493.         $this->_row_sizes        array();
  494.  
  495.         $this->_zoom            100;
  496.         $this->_print_scale        100;
  497.  
  498.         $this->_outline_row_level    = 0;
  499.         $this->_outline_style        = 0;
  500.         $this->_outline_below        = 1;
  501.         $this->_outline_right        = 1;
  502.         $this->_outline_on            = 1;
  503.  
  504.         $this->_merged_ranges    = array();
  505.  
  506.         $this->_input_encoding    = '';
  507.  
  508.         $this->_dv                array();
  509.  
  510.         $this->_tmp_dir            = $tempDir;
  511.  
  512.         $this->_initialize();
  513.     }
  514.  
  515.     /**
  516.      * Cleanup
  517.      */
  518.     public function cleanup({
  519.         @fclose($this->_filehandle);
  520.  
  521.         foreach ($this->_tempFilesCreated as $file{
  522.             @unlink($file);
  523.         }
  524.     }
  525.  
  526.     /**
  527.     * Open a tmp file to store the majority of the Worksheet data. If this fails,
  528.     * for example due to write permissions, store the data in memory. This can be
  529.     * slow for large files.
  530.     *
  531.     * @access private
  532.     */
  533.     function _initialize()
  534.     {
  535.         // Open tmp file for storing Worksheet data
  536.         $fileName tempnam($this->_tmp_dir'XLSHEET');
  537.         $fh fopen($fileName'w+');
  538.         if ($fh{
  539.             // Store filehandle
  540.             $this->_filehandle = $fh;
  541.             $this->_tempFilesCreated[$fileName;
  542.         else {
  543.             // If tmpfile() fails store data in memory
  544.             $this->_using_tmpfile = false;
  545.         }
  546.     }
  547.  
  548.     /**
  549.     * Sets the temp dir used for storing files
  550.     *
  551.     * @access public
  552.     * @param string $dir The dir to be used as temp dir
  553.     * @return true if given dir is valid, false otherwise
  554.     */
  555.     function setTempDir($dir)
  556.     {
  557.         if (is_dir($dir)) {
  558.             $this->_tmp_dir = $dir;
  559.             return true;
  560.         }
  561.         return false;
  562.     }
  563.  
  564.     /**
  565.     * Add data to the beginning of the workbook (note the reverse order)
  566.     * and to the end of the workbook.
  567.     *
  568.     * @access public
  569.     * @see PHPExcel_Writer_Excel5_Workbook::storeWorkbook()
  570.     * @param array $sheetnames The array of sheetnames from the Workbook this
  571.     *                           worksheet belongs to
  572.     */
  573.     function close($sheetnames)
  574.     {
  575.         $num_sheets count($sheetnames);
  576.  
  577.         /***********************************************
  578.         * Prepend in reverse order!!
  579.         */
  580.  
  581.         // Prepend the sheet dimensions
  582.         $this->_storeDimensions();
  583.  
  584.         // Prepend the sheet password
  585.         $this->_storePassword();
  586.  
  587.         // Prepend the sheet protection
  588.         $this->_storeProtect();
  589.  
  590.         // Prepend the page setup
  591.         $this->_storeSetup();
  592.  
  593.         /* FIXME: margins are actually appended */
  594.         // Prepend the bottom margin
  595.         $this->_storeMarginBottom();
  596.  
  597.         // Prepend the top margin
  598.         $this->_storeMarginTop();
  599.  
  600.         // Prepend the right margin
  601.         $this->_storeMarginRight();
  602.  
  603.         // Prepend the left margin
  604.         $this->_storeMarginLeft();
  605.  
  606.         // Prepend the page vertical centering
  607.         $this->_storeVcenter();
  608.  
  609.         // Prepend the page horizontal centering
  610.         $this->_storeHcenter();
  611.  
  612.         // Prepend the page footer
  613.         $this->_storeFooter();
  614.  
  615.         // Prepend the page header
  616.         $this->_storeHeader();
  617.  
  618.         // Prepend the vertical page breaks
  619.         $this->_storeVbreak();
  620.  
  621.         // Prepend the horizontal page breaks
  622.         $this->_storeHbreak();
  623.  
  624.         // Prepend WSBOOL
  625.         $this->_storeWsbool();
  626.  
  627.         // Prepend DEFAULTROWHEIGHT
  628.         if ($this->_BIFF_version == 0x0600{
  629.             $this->_storeDefaultRowHeight();
  630.         }
  631.  
  632.         // Prepend GRIDSET
  633.         $this->_storeGridset();
  634.  
  635.          //  Prepend GUTS
  636.         $this->_storeGuts();
  637.  
  638.         // Prepend PRINTGRIDLINES
  639.         $this->_storePrintGridlines();
  640.  
  641.         // Prepend PRINTHEADERS
  642.         $this->_storePrintHeaders();
  643.  
  644.         // Prepend EXTERNSHEET references
  645.         if ($this->_BIFF_version == 0x0500{
  646.             for ($i $num_sheets$i 0--$i{
  647.                 $sheetname $sheetnames[$i-1];
  648.                 $this->_storeExternsheet($sheetname);
  649.             }
  650.         }
  651.  
  652.         // Prepend the EXTERNCOUNT of external references.
  653.         if ($this->_BIFF_version == 0x0500{
  654.             $this->_storeExterncount($num_sheets);
  655.         }
  656.  
  657.         // Prepend the COLINFO records if they exist
  658.         if (!empty($this->_colinfo)) {
  659.             $colcount count($this->_colinfo);
  660.             for ($i 0$i $colcount++$i{
  661.                 $this->_storeColinfo($this->_colinfo[$i]);
  662.             }
  663.         }
  664.  
  665.         // Prepend the DEFCOLWIDTH record
  666.         $this->_storeDefcol();
  667.  
  668.         // Prepend the BOF record
  669.         $this->_storeBof(0x0010);
  670.  
  671.         /*
  672.         * End of prepend. Read upwards from here.
  673.         ***********************************************/
  674.  
  675.         // Append
  676.         $this->_storeWindow2();
  677.         $this->_storeZoom();
  678.         if (!empty($this->_panes)) {
  679.             $this->_storePanes($this->_panes);
  680.         }
  681.         $this->_storeSelection($this->_selection);
  682.         $this->_storeMergedCells();
  683.         /* TODO: add data validity */
  684.         /*if ($this->_BIFF_version == 0x0600) {
  685.             $this->_storeDataValidity();
  686.         }*/
  687.         $this->_storeEof();
  688.     }
  689.  
  690.     /**
  691.     * Retrieve the worksheet name.
  692.     * This is usefull when creating worksheets without a name.
  693.     *
  694.     * @access public
  695.     * @return string The worksheet's name
  696.     */
  697.     function getName()
  698.     {
  699.         return $this->name;
  700.     }
  701.  
  702.     /**
  703.     * Retrieves data from memory in one chunk, or from disk in $buffer
  704.     * sized chunks.
  705.     *
  706.     * @return string The data
  707.     */
  708.     function getData()
  709.     {
  710.         $buffer 4096;
  711.  
  712.         // Return data stored in memory
  713.         if (isset($this->_data)) {
  714.             $tmp   $this->_data;
  715.             unset($this->_data);
  716.             $fh    $this->_filehandle;
  717.             if ($this->_using_tmpfile{
  718.                 fseek($fh0);
  719.             }
  720.             return $tmp;
  721.         }
  722.         // Return data stored on disk
  723.         if ($this->_using_tmpfile{
  724.             if ($tmp fread($this->_filehandle$buffer)) {
  725.                 return $tmp;
  726.             }
  727.         }
  728.  
  729.         // No data to return
  730.         return '';
  731.     }
  732.  
  733.     /**
  734.     * Sets a merged cell range
  735.     *
  736.     * @access public
  737.     * @param integer $first_row First row of the area to merge
  738.     * @param integer $first_col First column of the area to merge
  739.     * @param integer $last_row  Last row of the area to merge
  740.     * @param integer $last_col  Last column of the area to merge
  741.     */
  742.     function setMerge($first_row$first_col$last_row$last_col)
  743.     {
  744.         if (($last_row $first_row|| ($last_col $first_col)) {
  745.             return;
  746.         }
  747.         // don't check rowmin, rowmax, etc... because we don't know when this
  748.         // is going to be called
  749.         $this->_merged_ranges[array($first_row$first_col$last_row$last_col);
  750.     }
  751.  
  752.     /**
  753.     * Set this worksheet as a selected worksheet,
  754.     * i.e. the worksheet has its tab highlighted.
  755.     *
  756.     * @access public
  757.     */
  758.     function select()
  759.     {
  760.         $this->selected = 1;
  761.     }
  762.  
  763.     /**
  764.     * Set this worksheet as the active worksheet,
  765.     * i.e. the worksheet that is displayed when the workbook is opened.
  766.     * Also set it as selected.
  767.     *
  768.     * @access public
  769.     */
  770.     function activate()
  771.     {
  772.         $this->selected = 1;
  773.         $this->activesheet $this->index;
  774.     }
  775.  
  776.     /**
  777.     * Set this worksheet as the first visible sheet.
  778.     * This is necessary when there are a large number of worksheets and the
  779.     * activated worksheet is not visible on the screen.
  780.     *
  781.     * @access public
  782.     */
  783.     function setFirstSheet()
  784.     {
  785.         $this->firstsheet $this->index;
  786.     }
  787.  
  788.     /**
  789.     * Set the worksheet protection flag
  790.     * to prevent accidental modification and to
  791.     * hide formulas if the locked and hidden format properties have been set.
  792.     *
  793.     * @access public
  794.     * @param string $password The password to use for protecting the sheet.
  795.     */
  796.     function protect($password$encoded false)
  797.     {
  798.         $this->_protect   1;
  799.         $this->_password  ($encoded $password $this->_encodePassword($password));
  800.     }
  801.  
  802.     /**
  803.     * Set the width of a single column or a range of columns.
  804.     *
  805.     * @access public
  806.     * @param integer $firstcol first column on the range
  807.     * @param integer $lastcol  last column on the range
  808.     * @param integer $width    width to set
  809.     * @param mixed   $format   The optional XF format to apply to the columns
  810.     * @param integer $hidden   The optional hidden atribute
  811.     * @param integer $level    The optional outline level
  812.     */
  813.     function setColumn($firstcol$lastcol$width$format null$hidden 0$level 0)
  814.     {
  815.         $this->_colinfo[array($firstcol$lastcol$width&$format$hidden$level);
  816.  
  817.         // Set width to zero if column is hidden
  818.         $width ($hidden$width;
  819.  
  820.         for ($col $firstcol$col <= $lastcol++$col{
  821.             $this->col_sizes[$col$width;
  822.         }
  823.     }
  824.  
  825.     /**
  826.     * Set which cell or cells are selected in a worksheet
  827.     *
  828.     * @access public
  829.     * @param integer $first_row    first row in the selected quadrant
  830.     * @param integer $first_column first column in the selected quadrant
  831.     * @param integer $last_row     last row in the selected quadrant
  832.     * @param integer $last_column  last column in the selected quadrant
  833.     */
  834.     function setSelection($first_row,$first_column,$last_row,$last_column)
  835.     {
  836.         $this->_selection = array($first_row,$first_column,$last_row,$last_column);
  837.     }
  838.  
  839.     /**
  840.     * Set panes and mark them as frozen.
  841.     *
  842.     * @access public
  843.     * @param array $panes This is the only parameter received and is composed of the following:
  844.     *                      0 => Vertical split position,
  845.     *                      1 => Horizontal split position
  846.     *                      2 => Top row visible
  847.     *                      3 => Leftmost column visible
  848.     *                      4 => Active pane
  849.     */
  850.     function freezePanes($panes)
  851.     {
  852.         $this->_frozen = 1;
  853.         $this->_panes  = $panes;
  854.     }
  855.  
  856.     /**
  857.     * Set panes and mark them as unfrozen.
  858.     *
  859.     * @access public
  860.     * @param array $panes This is the only parameter received and is composed of the following:
  861.     *                      0 => Vertical split position,
  862.     *                      1 => Horizontal split position
  863.     *                      2 => Top row visible
  864.     *                      3 => Leftmost column visible
  865.     *                      4 => Active pane
  866.     */
  867.     function thawPanes($panes)
  868.     {
  869.         $this->_frozen = 0;
  870.         $this->_panes  = $panes;
  871.     }
  872.  
  873.     /**
  874.     * Set the page orientation as portrait.
  875.     *
  876.     * @access public
  877.     */
  878.     function setPortrait()
  879.     {
  880.         $this->_orientation = 1;
  881.     }
  882.  
  883.     /**
  884.     * Set the page orientation as landscape.
  885.     *
  886.     * @access public
  887.     */
  888.     function setLandscape()
  889.     {
  890.         $this->_orientation = 0;
  891.     }
  892.  
  893.     /**
  894.     * Set the paper type. Ex. 1 = US Letter, 9 = A4
  895.     *
  896.     * @access public
  897.     * @param integer $size The type of paper size to use
  898.     */
  899.     function setPaper($size 0)
  900.     {
  901.         $this->_paper_size = $size;
  902.     }
  903.  
  904.  
  905.     /**
  906.     * Set the page header caption and optional margin.
  907.     *
  908.     * @access public
  909.     * @param string $string The header text
  910.     * @param float  $margin optional head margin in inches.
  911.     */
  912.     function setHeader($string,$margin 0.50)
  913.     {
  914.         if (strlen($string>= 255{
  915.             //carp 'Header string must be less than 255 characters';
  916.             return;
  917.         }
  918.         $this->_header      = $string;
  919.         $this->_margin_head = $margin;
  920.     }
  921.  
  922.     /**
  923.     * Set the page footer caption and optional margin.
  924.     *
  925.     * @access public
  926.     * @param string $string The footer text
  927.     * @param float  $margin optional foot margin in inches.
  928.     */
  929.     function setFooter($string,$margin 0.50)
  930.     {
  931.         if (strlen($string>= 255{
  932.             //carp 'Footer string must be less than 255 characters';
  933.             return;
  934.         }
  935.         $this->_footer      = $string;
  936.         $this->_margin_foot = $margin;
  937.     }
  938.  
  939.     /**
  940.     * Center the page horinzontally.
  941.     *
  942.     * @access public
  943.     * @param integer $center the optional value for centering. Defaults to 1 (center).
  944.     */
  945.     function centerHorizontally($center 1)
  946.     {
  947.         $this->_hcenter = $center;
  948.     }
  949.  
  950.     /**
  951.     * Center the page vertically.
  952.     *
  953.     * @access public
  954.     * @param integer $center the optional value for centering. Defaults to 1 (center).
  955.     */
  956.     function centerVertically($center 1)
  957.     {
  958.         $this->_vcenter = $center;
  959.     }
  960.  
  961.     /**
  962.     * Set all the page margins to the same value in inches.
  963.     *
  964.     * @access public
  965.     * @param float $margin The margin to set in inches
  966.     */
  967.     function setMargins($margin)
  968.     {
  969.         $this->setMarginLeft($margin);
  970.         $this->setMarginRight($margin);
  971.         $this->setMarginTop($margin);
  972.         $this->setMarginBottom($margin);
  973.     }
  974.  
  975.     /**
  976.     * Set the left and right margins to the same value in inches.
  977.     *
  978.     * @access public
  979.     * @param float $margin The margin to set in inches
  980.     */
  981.     function setMargins_LR($margin)
  982.     {
  983.         $this->setMarginLeft($margin);
  984.         $this->setMarginRight($margin);
  985.     }
  986.  
  987.     /**
  988.     * Set the top and bottom margins to the same value in inches.
  989.     *
  990.     * @access public
  991.     * @param float $margin The margin to set in inches
  992.     */
  993.     function setMargins_TB($margin)
  994.     {
  995.         $this->setMarginTop($margin);
  996.         $this->setMarginBottom($margin);
  997.     }
  998.  
  999.     /**
  1000.     * Set the left margin in inches.
  1001.     *
  1002.     * @access public
  1003.     * @param float $margin The margin to set in inches
  1004.     */
  1005.     function setMarginLeft($margin 0.75)
  1006.     {
  1007.         $this->_margin_left = $margin;
  1008.     }
  1009.  
  1010.     /**
  1011.     * Set the right margin in inches.
  1012.     *
  1013.     * @access public
  1014.     * @param float $margin The margin to set in inches
  1015.     */
  1016.     function setMarginRight($margin 0.75)
  1017.     {
  1018.         $this->_margin_right = $margin;
  1019.     }
  1020.  
  1021.     /**
  1022.     * Set the top margin in inches.
  1023.     *
  1024.     * @access public
  1025.     * @param float $margin The margin to set in inches
  1026.     */
  1027.     function setMarginTop($margin 1.00)
  1028.     {
  1029.         $this->_margin_top = $margin;
  1030.     }
  1031.  
  1032.     /**
  1033.     * Set the bottom margin in inches.
  1034.     *
  1035.     * @access public
  1036.     * @param float $margin The margin to set in inches
  1037.     */
  1038.     function setMarginBottom($margin 1.00)
  1039.     {
  1040.         $this->_margin_bottom = $margin;
  1041.     }
  1042.  
  1043.     /**
  1044.     * Set the rows to repeat at the top of each printed page.
  1045.     *
  1046.     * @access public
  1047.     * @param integer $first_row First row to repeat
  1048.     * @param integer $last_row  Last row to repeat. Optional.
  1049.     */
  1050.     function repeatRows($first_row$last_row null)
  1051.     {
  1052.         $this->title_rowmin  = $first_row;
  1053.         if (isset($last_row)) //Second row is optional
  1054.             $this->title_rowmax  = $last_row;
  1055.         else {
  1056.             $this->title_rowmax  = $first_row;
  1057.         }
  1058.     }
  1059.  
  1060.     /**
  1061.     * Set the columns to repeat at the left hand side of each printed page.
  1062.     *
  1063.     * @access public
  1064.     * @param integer $first_col First column to repeat
  1065.     * @param integer $last_col  Last column to repeat. Optional.
  1066.     */
  1067.     function repeatColumns($first_col$last_col null)
  1068.     {
  1069.         $this->title_colmin  = $first_col;
  1070.         if (isset($last_col)) // Second col is optional
  1071.             $this->title_colmax  $last_col;
  1072.         else {
  1073.             $this->title_colmax  $first_col;
  1074.         }
  1075.     }
  1076.  
  1077.     /**
  1078.     * Set the area of each worksheet that will be printed.
  1079.     *
  1080.     * @access public
  1081.     * @param integer $first_row First row of the area to print
  1082.     * @param integer $first_col First column of the area to print
  1083.     * @param integer $last_row  Last row of the area to print
  1084.     * @param integer $last_col  Last column of the area to print
  1085.     */
  1086.     function printArea($first_row$first_col$last_row$last_col)
  1087.     {
  1088.         $this->print_rowmin  = $first_row;
  1089.         $this->print_colmin  = $first_col;
  1090.         $this->print_rowmax  = $last_row;
  1091.         $this->print_colmax  = $last_col;
  1092.     }
  1093.  
  1094.  
  1095.     /**
  1096.     * Set the option to hide gridlines on the printed page.
  1097.     *
  1098.     * @access public
  1099.     */
  1100.     function hideGridlines()
  1101.     {
  1102.         $this->_print_gridlines 0;
  1103.     }
  1104.  
  1105.     /**
  1106.     * Set the option to hide gridlines on the worksheet (as seen on the screen).
  1107.     *
  1108.     * @access public
  1109.     */
  1110.     function hideScreenGridlines()
  1111.     {
  1112.         $this->_screen_gridlines 0;
  1113.     }
  1114.  
  1115.     /**
  1116.     * Set the option to print the row and column headers on the printed page.
  1117.     *
  1118.     * @access public
  1119.     * @param integer $print Whether to print the headers or not. Defaults to 1 (print).
  1120.     */
  1121.     function printRowColHeaders($print 1)
  1122.     {
  1123.         $this->_print_headers $print;
  1124.     }
  1125.  
  1126.     /**
  1127.     * Set the vertical and horizontal number of pages that will define the maximum area printed.
  1128.     * It doesn't seem to work with OpenOffice.
  1129.     *
  1130.     * @access public
  1131.     * @param  integer $width  Maximun width of printed area in pages
  1132.     * @param  integer $height Maximun heigth of printed area in pages
  1133.     * @see setPrintScale()
  1134.     */
  1135.     function fitToPages($width$height)
  1136.     {
  1137.         $this->_fit_page      = 1;
  1138.         $this->_fit_width     = $width;
  1139.         $this->_fit_height    = $height;
  1140.     }
  1141.  
  1142.     /**
  1143.     * Store the horizontal page breaks on a worksheet (for printing).
  1144.     * The breaks represent the row after which the break is inserted.
  1145.     *
  1146.     * @access public
  1147.     * @param array $breaks Array containing the horizontal page breaks
  1148.     */
  1149.     function setHPagebreaks($breaks)
  1150.     {
  1151.         foreach ($breaks as $break{
  1152.             array_push($this->_hbreaks$break);
  1153.         }
  1154.     }
  1155.  
  1156.     /**
  1157.     * Store the vertical page breaks on a worksheet (for printing).
  1158.     * The breaks represent the column after which the break is inserted.
  1159.     *
  1160.     * @access public
  1161.     * @param array $breaks Array containing the vertical page breaks
  1162.     */
  1163.     function setVPagebreaks($breaks)
  1164.     {
  1165.         foreach ($breaks as $break{
  1166.             array_push($this->_vbreaks$break);
  1167.         }
  1168.     }
  1169.  
  1170.  
  1171.     /**
  1172.     * Set the worksheet zoom factor.
  1173.     *
  1174.     * @access public
  1175.     * @param integer $scale The zoom factor
  1176.     */
  1177.     function setZoom($scale 100)
  1178.     {
  1179.         // Confine the scale to Excel's range
  1180.         if ($scale 10 || $scale 400{
  1181.             throw new Exception("Zoom factor $scale outside range: 10 <= zoom <= 400");
  1182.             $scale 100;
  1183.         }
  1184.  
  1185.         $this->_zoom floor($scale);
  1186.     }
  1187.  
  1188.     /**
  1189.     * Set the scale factor for the printed page.
  1190.     * It turns off the "fit to page" option
  1191.     *
  1192.     * @access public
  1193.     * @param integer $scale The optional scale factor. Defaults to 100
  1194.     */
  1195.     function setPrintScale($scale 100)
  1196.     {
  1197.         // Confine the scale to Excel's range
  1198.         if ($scale 10 || $scale 400{
  1199.             throw new Exception("Print scale $scale outside range: 10 <= zoom <= 400");
  1200.             $scale 100;
  1201.         }
  1202.  
  1203.         // Turn off "fit to page" option
  1204.         $this->_fit_page = 0;
  1205.  
  1206.         $this->_print_scale floor($scale);
  1207.     }
  1208.  
  1209.     /**
  1210.     * Map to the appropriate write method acording to the token recieved.
  1211.     *
  1212.     * @access public
  1213.     * @param integer $row    The row of the cell we are writing to
  1214.     * @param integer $col    The column of the cell we are writing to
  1215.     * @param mixed   $token  What we are writing
  1216.     * @param mixed   $format The optional format to apply to the cell
  1217.     */
  1218.     function write($row$col$token$format null$numberFormat null)
  1219.     {
  1220.         // Check for a cell reference in A1 notation and substitute row and column
  1221.         /*if ($_[0] =~ /^\D/) {
  1222.             @_ = $this->_substituteCellref(@_);
  1223.         }*/
  1224.  
  1225.         if (($numberFormat != 'General'&& (PHPExcel_Shared_Date::isDateTimeFormatCode($numberFormat))) {
  1226.             if (is_string($token)) {
  1227.                 //    Error string
  1228.                 return $this->writeString($row$col$token$format);
  1229.             elseif (!is_float($token)) {
  1230.                 //    PHP serialized date/time or date/time object
  1231.                 return $this->writeNumber($row$colPHPExcel_Shared_Date::PHPToExcel($token)$format);
  1232.             else {
  1233.                 //    Excel serialized date/time
  1234.                 return $this->writeNumber($row$col$token$format);
  1235.             }
  1236.         elseif (preg_match("/^([+-]?)(?=\d|\.\d)\d*(\.\d*)?([Ee]([+-]?\d+))?$/"$token)) {
  1237.             // Match number
  1238.             return $this->writeNumber($row$col$token$format);
  1239.         elseif (preg_match("/^[fh]tt?p:\/\//"$token)) {
  1240.             // Match http or ftp URL
  1241.             return $this->writeUrl($row$col$token''$format);
  1242.         elseif (preg_match("/^mailto:/"$token)) {
  1243.             // Match mailto:
  1244.             return $this->writeUrl($row$col$token''$format);
  1245.         elseif (preg_match("/^(?:in|ex)ternal:/"$token)) {
  1246.             // Match internal or external sheet link
  1247.             return $this->writeUrl($row$col$token''$format);
  1248.         elseif (preg_match("/^=/"$token)) {
  1249.             // Match formula
  1250.             return $this->writeFormula($row$col$token$format);
  1251.         elseif (preg_match("/^@/"$token)) {
  1252.             // Match formula
  1253.             return $this->writeFormula($row$col$token$format);
  1254.         elseif ($token == ''{
  1255.             // Match blank
  1256.             return $this->writeBlank($row$col$format);
  1257.         else {
  1258.             // Default: match string
  1259.             return $this->writeString($row$col$token$format);
  1260.         }
  1261.     }
  1262.  
  1263.     /**
  1264.     * Write an array of values as a row
  1265.     *
  1266.     * @access public
  1267.     * @param integer $row    The row we are writing to
  1268.     * @param integer $col    The first col (leftmost col) we are writing to
  1269.     * @param array   $val    The array of values to write
  1270.     * @param mixed   $format The optional format to apply to the cell
  1271.     */
  1272.  
  1273.     function writeRow($row$col$val$format null$numberFormat null)
  1274.     {
  1275.         $retval '';
  1276.         if (is_array($val)) {
  1277.             foreach ($val as $v{
  1278.                 if (is_array($v)) {
  1279.                     $this->writeCol($row$col$v$format$numberFormat null);
  1280.                 else {
  1281.                     $this->write($row$col$v$format$numberFormat);
  1282.                 }
  1283.                 ++$col;
  1284.             }
  1285.         else {
  1286.             throw new Exception('$val needs to be an array');
  1287.         }
  1288.         return($retval);
  1289.     }
  1290.  
  1291.     /**
  1292.     * Write an array of values as a column
  1293.     *
  1294.     * @access public
  1295.     * @param integer $row    The first row (uppermost row) we are writing to
  1296.     * @param integer $col    The col we are writing to
  1297.     * @param array   $val    The array of values to write
  1298.     * @param mixed   $format The optional format to apply to the cell
  1299.     */
  1300.  
  1301.     function writeCol($row$col$val$format null$numberFormat null)
  1302.     {
  1303.         $retval '';
  1304.         if (is_array($val)) {
  1305.             foreach ($val as $v{
  1306.                 $this->write($row$col$v$format$numberFormat);
  1307.                 ++$row;
  1308.             }
  1309.         else {
  1310.             throw new Exception('$val needs to be an array');
  1311.         }
  1312.         return($retval);
  1313.     }
  1314.  
  1315.     /**
  1316.     * Returns an index to the XF record in the workbook
  1317.     *
  1318.     * @access private
  1319.     * @param mixed &$format The optional XF format
  1320.     * @return integer The XF record index
  1321.     */
  1322.     function _XF(&$format)
  1323.     {
  1324.         if ($format{
  1325.             return($format->getXfIndex());
  1326.         else {
  1327.             return(0x0F);
  1328.         }
  1329.     }
  1330.  
  1331.  
  1332.     /******************************************************************************
  1333.     *******************************************************************************
  1334.     *
  1335.     * Internal methods
  1336.     */
  1337.  
  1338.  
  1339.     /**
  1340.     * Store Worksheet data in memory using the parent's class append() or to a
  1341.     * temporary file, the default.
  1342.     *
  1343.     * @access private
  1344.     * @param string $data The binary data to append
  1345.     */
  1346.     function _append($data)
  1347.     {
  1348.         if ($this->_using_tmpfile{
  1349.             // Add CONTINUE records if necessary
  1350.             if (strlen($data$this->_limit{
  1351.                 $data $this->_addContinue($data);
  1352.             }
  1353.             fwrite($this->_filehandle$data);
  1354.             $this->_datasize += strlen($data);
  1355.         else {
  1356.             parent::_append($data);
  1357.         }
  1358.     }
  1359.  
  1360.     /**
  1361.     * Substitute an Excel cell reference in A1 notation for  zero based row and
  1362.     * column values in an argument list.
  1363.     *
  1364.     * Ex: ("A4", "Hello") is converted to (3, 0, "Hello").
  1365.     *
  1366.     * @access private
  1367.     * @param string $cell The cell reference. Or range of cells.
  1368.     * @return array 
  1369.     */
  1370.     function _substituteCellref($cell)
  1371.     {
  1372.         $cell strtoupper($cell);
  1373.  
  1374.         // Convert a column range: 'A:A' or 'B:G'
  1375.         if (preg_match("/([A-I]?[A-Z]):([A-I]?[A-Z])/"$cell$match)) {
  1376.             list($no_use$col1=  $this->_cellToRowcol($match[1.'1')// Add a dummy row
  1377.             list($no_use$col2=  $this->_cellToRowcol($match[2.'1')// Add a dummy row
  1378.             return(array($col1$col2));
  1379.         }
  1380.  
  1381.         // Convert a cell range: 'A1:B7'
  1382.         if (preg_match("/\$?([A-I]?[A-Z]\$?\d+):\$?([A-I]?[A-Z]\$?\d+)/"$cell$match)) {
  1383.             list($row1$col1=  $this->_cellToRowcol($match[1]);
  1384.             list($row2$col2=  $this->_cellToRowcol($match[2]);
  1385.             return(array($row1$col1$row2$col2));
  1386.         }
  1387.  
  1388.         // Convert a cell reference: 'A1' or 'AD2000'
  1389.         if (preg_match("/\$?([A-I]?[A-Z]\$?\d+)/"$cell)) {
  1390.             list($row1$col1=  $this->_cellToRowcol($match[1]);
  1391.             return(array($row1$col1));
  1392.         }
  1393.  
  1394.         // TODO use real error codes
  1395.         throw new Exception("Unknown cell reference $cell");
  1396.     }
  1397.  
  1398.     /**
  1399.     * Convert an Excel cell reference in A1 notation to a zero based row and column
  1400.     * reference; converts C1 to (0, 2).
  1401.     *
  1402.     * @access private
  1403.     * @param string $cell The cell reference.
  1404.     * @return array containing (row, column)
  1405.     */
  1406.     function _cellToRowcol($cell)
  1407.     {
  1408.         preg_match("/\$?([A-I]?[A-Z])\$?(\d+)/",$cell,$match);
  1409.         $col     $match[1];
  1410.         $row     $match[2];
  1411.  
  1412.         // Convert base26 column string to number
  1413.         $chars split(''$col);
  1414.         $expn  0;
  1415.         $col   0;
  1416.  
  1417.         while ($chars{
  1418.             $char array_pop($chars);        // LS char first
  1419.             $col += (ord($char-ord('A'+1pow(26,$expn);
  1420.             ++$expn;
  1421.         }
  1422.  
  1423.         // Convert 1-index to zero-index
  1424.         --$row;
  1425.         --$col;
  1426.  
  1427.         return(array($row$col));
  1428.     }
  1429.  
  1430.     /**
  1431.     * Based on the algorithm provided by Daniel Rentz of OpenOffice.
  1432.     *
  1433.     * @access private
  1434.     * @param string $plaintext The password to be encoded in plaintext.
  1435.     * @return string The encoded password
  1436.     */
  1437.     function _encodePassword($plaintext)
  1438.     {
  1439.         $password 0x0000;
  1440.         $i        1;       // char position
  1441.  
  1442.         // split the plain text password in its component characters
  1443.         $chars preg_split('//'$plaintext-1PREG_SPLIT_NO_EMPTY);
  1444.         foreach ($chars as $char{
  1445.             $value        ord($char<< $i;   // shifted ASCII value
  1446.             $rotated_bits $value >> 15;       // rotated bits beyond bit 15
  1447.             $value       &= 0x7fff;             // first 15 bits
  1448.             $password    ^= ($value $rotated_bits);
  1449.             ++$i;
  1450.         }
  1451.  
  1452.         $password ^= strlen($plaintext);
  1453.         $password ^= 0xCE4B;
  1454.  
  1455.         return($password);
  1456.     }
  1457.  
  1458.     /**
  1459.     * This method sets the properties for outlining and grouping. The defaults
  1460.     * correspond to Excel's defaults.
  1461.     *
  1462.     * @param bool $visible 
  1463.     * @param bool $symbols_below 
  1464.     * @param bool $symbols_right 
  1465.     * @param bool $auto_style 
  1466.     */
  1467.     function setOutline($visible true$symbols_below true$symbols_right true$auto_style false)
  1468.     {
  1469.         $this->_outline_on    = $visible;
  1470.         $this->_outline_below = $symbols_below;
  1471.         $this->_outline_right = $symbols_right;
  1472.         $this->_outline_style = $auto_style;
  1473.  
  1474.         // Ensure this is a boolean vale for Window2
  1475.         if ($this->_outline_on{
  1476.             $this->_outline_on = 1;
  1477.         }
  1478.      }
  1479.  
  1480.     /******************************************************************************
  1481.     *******************************************************************************
  1482.     *
  1483.     * BIFF RECORDS
  1484.     */
  1485.  
  1486.  
  1487.     /**
  1488.     * Write a double to the specified row and column (zero indexed).
  1489.     * An integer can be written as a double. Excel will display an
  1490.     * integer. $format is optional.
  1491.     *
  1492.     * Returns  0 : normal termination
  1493.     *         -2 : row or column out of range
  1494.     *
  1495.     * @access public
  1496.     * @param integer $row    Zero indexed row
  1497.     * @param integer $col    Zero indexed column
  1498.     * @param float   $num    The number to write
  1499.     * @param mixed   $format The optional XF format
  1500.     * @return integer 
  1501.     */
  1502.     function writeNumber($row$col$num$format null)
  1503.     {
  1504.         $record    0x0203;                 // Record identifier
  1505.         $length    0x000E;                 // Number of bytes to follow
  1506.  
  1507.         $xf        $this->_XF($format);    // The cell format
  1508.  
  1509.         // Check that row and col are valid and store max and min values
  1510.         if ($row >= $this->_xls_rowmax{
  1511.             return(-2);
  1512.         }
  1513.         if ($col >= $this->_xls_colmax{
  1514.             return(-2);
  1515.         }
  1516.         if ($row <  $this->_dim_rowmin)  {
  1517.             $this->_dim_rowmin = $row;
  1518.         }
  1519.         if ($row >  $this->_dim_rowmax)  {
  1520.             $this->_dim_rowmax = $row;
  1521.         }
  1522.         if ($col <  $this->_dim_colmin)  {
  1523.             $this->_dim_colmin = $col;
  1524.         }
  1525.         if ($col >  $this->_dim_colmax)  {
  1526.             $this->_dim_colmax = $col;
  1527.         }
  1528.  
  1529.         $header    pack("vv",  $record$length);
  1530.         $data      pack("vvv"$row$col$xf);
  1531.         $xl_double pack("d",   $num);
  1532.         if ($this->_byte_order// if it's Big Endian
  1533.             $xl_double strrev($xl_double);
  1534.         }
  1535.  
  1536.         $this->_append($header.$data.$xl_double);
  1537.         return(0);
  1538.     }
  1539.  
  1540.     /**
  1541.     * Write a string to the specified row and column (zero indexed).
  1542.     * NOTE: there is an Excel 5 defined limit of 255 characters.
  1543.     * $format is optional.
  1544.     * Returns  0 : normal termination
  1545.     *         -2 : row or column out of range
  1546.     *         -3 : long string truncated to 255 chars
  1547.     *
  1548.     * @access public
  1549.     * @param integer $row    Zero indexed row
  1550.     * @param integer $col    Zero indexed column
  1551.     * @param string  $str    The string to write
  1552.     * @param mixed   $format The XF format for the cell
  1553.     * @return integer 
  1554.     */
  1555.     function writeString($row$col$str$format null)
  1556.     {
  1557.         if ($this->_BIFF_version == 0x0600{
  1558.             return $this->writeStringBIFF8($row$col$str$format);
  1559.         }
  1560.         $strlen    strlen($str);
  1561.         $record    0x0204;                   // Record identifier
  1562.         $length    0x0008 $strlen;         // Bytes to follow
  1563.         $xf        $this->_XF($format);      // The cell format
  1564.  
  1565.         $str_error 0;
  1566.  
  1567.         // Check that row and col are valid and store max and min values
  1568.         if ($row >= $this->_xls_rowmax{
  1569.             return(-2);
  1570.         }
  1571.         if ($col >= $this->_xls_colmax{
  1572.             return(-2);
  1573.         }
  1574.         if ($row <  $this->_dim_rowmin{
  1575.             $this->_dim_rowmin = $row;
  1576.         }
  1577.         if ($row >  $this->_dim_rowmax{
  1578.             $this->_dim_rowmax = $row;
  1579.         }
  1580.         if ($col <  $this->_dim_colmin{
  1581.             $this->_dim_colmin = $col;
  1582.         }
  1583.         if ($col >  $this->_dim_colmax{
  1584.             $this->_dim_colmax = $col;
  1585.         }
  1586.  
  1587.         if ($strlen $this->_xls_strmax// LABEL must be < 255 chars
  1588.             $str       substr($str0$this->_xls_strmax);
  1589.             $length    0x0008 $this->_xls_strmax;
  1590.             $strlen    $this->_xls_strmax;
  1591.             $str_error = -3;
  1592.         }
  1593.  
  1594.         $header    pack("vv",   $record$length);
  1595.         $data      pack("vvvv"$row$col$xf$strlen);
  1596.         $this->_append($header $data $str);
  1597.         return($str_error);
  1598.     }
  1599.  
  1600.     var $_biff8_input_encoding = 'UTF-16LE';
  1601.     function setBIFF8InputEncoding($encoding{
  1602.         if ($encoding != 'UTF-16LE' && !function_exists('iconv')) {
  1603.             $this->raiseError("Using an input encoding other than UTF-16LE requires PHP support for iconv");
  1604.         }
  1605.         $this->_biff8_input_encoding = $encoding;
  1606.     }
  1607.  
  1608.     /**
  1609.     * Sets Input Encoding for writing strings
  1610.     *
  1611.     * @access public
  1612.     * @param string $encoding The encoding. Ex: 'UTF-16LE', 'utf-8', 'ISO-859-7'
  1613.     */
  1614.     function setInputEncoding($encoding)
  1615.     {
  1616.          if ($encoding != 'UTF-16LE' && !function_exists('iconv')) {
  1617.              throw new Exception("Using an input encoding other than UTF-16LE requires PHP support for iconv");
  1618.          }
  1619.          $this->_input_encoding = $encoding;
  1620.     }
  1621.  
  1622.     /**
  1623.     * Write a string to the specified row and column (zero indexed).
  1624.     * This is the BIFF8 version (no 255 chars limit).
  1625.     * $format is optional.
  1626.     * Returns  0 : normal termination
  1627.     *         -2 : row or column out of range
  1628.     *         -3 : long string truncated to 255 chars
  1629.     *
  1630.     * @access public
  1631.     * @param integer $row    Zero indexed row
  1632.     * @param integer $col    Zero indexed column
  1633.     * @param string  $str    The string to write
  1634.     * @param mixed   $format The XF format for the cell
  1635.     * @return integer 
  1636.     */
  1637.     function writeStringBIFF8($row$col$str$format null)
  1638.     {
  1639.         if ($this->_input_encoding == 'UTF-16LE')
  1640.         {
  1641.             $strlen function_exists('mb_strlen'mb_strlen($str'UTF-16LE'(strlen($str2);
  1642.             $encoding  0x1;
  1643.         }
  1644.         elseif ($this->_input_encoding != '')
  1645.         {
  1646.             $str iconv($this->_input_encoding'UTF-16LE'$str);
  1647.             $strlen function_exists('mb_strlen'mb_strlen($str'UTF-16LE'(strlen($str2);
  1648.             $encoding  0x1;
  1649.         }
  1650.         else
  1651.         {
  1652.             $strlen    strlen($str);
  1653.             $encoding  0x0;
  1654.         }
  1655.         $record    0x00FD;                   // Record identifier
  1656.         $length    0x000A;                   // Bytes to follow
  1657.         $xf        $this->_XF($format);      // The cell format
  1658.  
  1659.         $str_error 0;
  1660.  
  1661.         // Check that row and col are valid and store max and min values
  1662.         if ($this->_checkRowCol($row$col== false{
  1663.             return -2;
  1664.         }
  1665.  
  1666.         $str pack('vC'$strlen$encoding).$str;
  1667.  
  1668.         /* check if string is already present */
  1669.         if (!isset($this->_str_table[$str])) {
  1670.             $this->_str_table[$str$this->_str_unique++;
  1671.         }
  1672.         $this->_str_total++;
  1673.  
  1674.         $header    pack('vv',   $record$length);
  1675.         $data      pack('vvvV'$row$col$xf$this->_str_table[$str]);
  1676.         $this->_append($header.$data);
  1677.         return $str_error;
  1678.     }
  1679.  
  1680.     /**
  1681.     * Check row and col before writing to a cell, and update the sheet's
  1682.     * dimensions accordingly
  1683.     *
  1684.     * @access private
  1685.     * @param integer $row    Zero indexed row
  1686.     * @param integer $col    Zero indexed column
  1687.     * @return boolean true for success, false if row and/or col are grester
  1688.     *                  then maximums allowed.
  1689.     */
  1690.     function _checkRowCol($row$col)
  1691.     {
  1692.         if ($row >= $this->_xls_rowmax{
  1693.             return false;
  1694.         }
  1695.         if ($col >= $this->_xls_colmax{
  1696.             return false;
  1697.         }
  1698.         if ($row <  $this->_dim_rowmin{
  1699.             $this->_dim_rowmin = $row;
  1700.         }
  1701.         if ($row >  $this->_dim_rowmax{
  1702.             $this->_dim_rowmax = $row;
  1703.         }
  1704.         if ($col <  $this->_dim_colmin{
  1705.             $this->_dim_colmin = $col;
  1706.         }
  1707.         if ($col >  $this->_dim_colmax{
  1708.             $this->_dim_colmax = $col;
  1709.         }
  1710.         return true;
  1711.     }
  1712.  
  1713.     /**
  1714.     * Writes a note associated with the cell given by the row and column.
  1715.     * NOTE records don't have a length limit.
  1716.     *
  1717.     * @access public
  1718.     * @param integer $row    Zero indexed row
  1719.     * @param integer $col    Zero indexed column
  1720.     * @param string  $note   The note to write
  1721.     */
  1722.     function writeNote($row$col$note)
  1723.     {
  1724.         $note_length    strlen($note);
  1725.         $record         0x001C;                // Record identifier
  1726.         $max_length     2048;                  // Maximun length for a NOTE record
  1727.         //$length      = 0x0006 + $note_length;    // Bytes to follow
  1728.  
  1729.         // Check that row and col are valid and store max and min values
  1730.         if ($row >= $this->_xls_rowmax{
  1731.             return(-2);
  1732.         }
  1733.         if ($col >= $this->_xls_colmax{
  1734.             return(-2);
  1735.         }
  1736.         if ($row <  $this->_dim_rowmin{
  1737.             $this->_dim_rowmin = $row;
  1738.         }
  1739.         if ($row >  $this->_dim_rowmax{
  1740.             $this->_dim_rowmax = $row;
  1741.         }
  1742.         if ($col <  $this->_dim_colmin{
  1743.             $this->_dim_colmin = $col;
  1744.         }
  1745.         if ($col >  $this->_dim_colmax{
  1746.             $this->_dim_colmax = $col;
  1747.         }
  1748.  
  1749.         // Length for this record is no more than 2048 + 6
  1750.         $length    0x0006 min($note_length2048);
  1751.         $header    pack("vv",   $record$length);
  1752.         $data      pack("vvv"$row$col$note_length);
  1753.         $this->_append($header $data substr($note02048));
  1754.  
  1755.         for ($i $max_length$i $note_length$i += $max_length{
  1756.             $chunk  substr($note$i$max_length);
  1757.             $length 0x0006 strlen($chunk);
  1758.             $header pack("vv",   $record$length);
  1759.             $data   pack("vvv"-10strlen($chunk));
  1760.             $this->_append($header.$data.$chunk);
  1761.         }
  1762.         return(0);
  1763.     }
  1764.  
  1765.     /**
  1766.     * Write a blank cell to the specified row and column (zero indexed).
  1767.     * A blank cell is used to specify formatting without adding a string
  1768.     * or a number.
  1769.     *
  1770.     * A blank cell without a format serves no purpose. Therefore, we don't write
  1771.     * a BLANK record unless a format is specified.
  1772.     *
  1773.     * Returns  0 : normal termination (including no format)
  1774.     *         -1 : insufficient number of arguments
  1775.     *         -2 : row or column out of range
  1776.     *
  1777.     * @access public
  1778.     * @param integer $row    Zero indexed row
  1779.     * @param integer $col    Zero indexed column
  1780.     * @param mixed   $format The XF format
  1781.     */
  1782.     function writeBlank($row$col$format)
  1783.     {
  1784.         // Don't write a blank cell unless it has a format
  1785.         if (!$format{
  1786.             return(0);
  1787.         }
  1788.  
  1789.         $record    0x0201;                 // Record identifier
  1790.         $length    0x0006;                 // Number of bytes to follow
  1791.         $xf        $this->_XF($format);    // The cell format
  1792.  
  1793.         // Check that row and col are valid and store max and min values
  1794.         if ($row >= $this->_xls_rowmax{
  1795.             return(-2);
  1796.         }
  1797.         if ($col >= $this->_xls_colmax{
  1798.             return(-2);
  1799.         }
  1800.         if ($row <  $this->_dim_rowmin{
  1801.             $this->_dim_rowmin = $row;
  1802.         }
  1803.         if ($row >  $this->_dim_rowmax{
  1804.             $this->_dim_rowmax = $row;
  1805.         }
  1806.         if ($col <  $this->_dim_colmin{
  1807.             $this->_dim_colmin = $col;
  1808.         }
  1809.         if ($col >  $this->_dim_colmax{
  1810.             $this->_dim_colmax = $col;
  1811.         }
  1812.  
  1813.         $header    pack("vv",  $record$length);
  1814.         $data      pack("vvv"$row$col$xf);
  1815.         $this->_append($header $data);
  1816.         return 0;
  1817.     }
  1818.  
  1819.     /**
  1820.      * Write a boolean or an error type to the specified row and column (zero indexed)
  1821.      */
  1822.     public function writeBoolErr($row$col$value$isError$format)
  1823.     {
  1824.         $record 0x0205;
  1825.         $length 8;
  1826.         $xf $this->_XF($format);
  1827.  
  1828.         // Check that row and col are valid and store max and min values
  1829.         if ($row >= $this->_xls_rowmax{
  1830.             return(-2);
  1831.         }
  1832.         if ($col >= $this->_xls_colmax{
  1833.             return(-2);
  1834.         }
  1835.         if ($row <  $this->_dim_rowmin)  {
  1836.             $this->_dim_rowmin = $row;
  1837.         }
  1838.         if ($row >  $this->_dim_rowmax)  {
  1839.             $this->_dim_rowmax = $row;
  1840.         }
  1841.         if ($col <  $this->_dim_colmin)  {
  1842.             $this->_dim_colmin = $col;
  1843.         }
  1844.         if ($col >  $this->_dim_colmax)  {
  1845.             $this->_dim_colmax = $col;
  1846.         }
  1847.  
  1848.         $header    pack("vv",  $record$length);
  1849.         $data      pack("vvvCC"$row$col$xf$value$isError);
  1850.         $this->_append($header $data);
  1851.         return 0;
  1852.     }
  1853.  
  1854.     /**
  1855.     * Write a formula to the specified row and column (zero indexed).
  1856.     * The textual representation of the formula is passed to the parser in
  1857.     * Parser.php which returns a packed binary string.
  1858.     *
  1859.     * Returns  0 : normal termination
  1860.     *         -1 : formula errors (bad formula)
  1861.     *         -2 : row or column out of range
  1862.     *
  1863.     * @access public
  1864.     * @param integer $row     Zero indexed row
  1865.     * @param integer $col     Zero indexed column
  1866.     * @param string  $formula The formula text string
  1867.     * @param mixed   $format  The optional XF format
  1868.     * @return integer 
  1869.     */
  1870.     function writeFormula($row$col$formula$format null)
  1871.     {
  1872.         $record    0x0006;     // Record identifier
  1873.  
  1874.         // Excel normally stores the last calculated value of the formula in $num.
  1875.         // Clearly we are not in a position to calculate this a priori. Instead
  1876.         // we set $num to zero and set the option flags in $grbit to ensure
  1877.         // automatic calculation of the formula when the file is opened.
  1878.         //
  1879.         $xf        $this->_XF($format)// The cell format
  1880.         $num       0x00;                // Current value of formula
  1881.         $grbit     0x03;                // Option flags
  1882.         $unknown   0x0000;              // Must be zero
  1883.  
  1884.  
  1885.         // Check that row and col are valid and store max and min values
  1886.         if ($this->_checkRowCol($row$col== false{
  1887.             return -2;
  1888.         }
  1889.  
  1890.         // Strip the '=' or '@' sign at the beginning of the formula string
  1891.         if (preg_match("/^=/"$formula)) {
  1892.             $formula preg_replace("/(^=)/"""$formula);
  1893.         elseif (preg_match("/^@/"$formula)) {
  1894.             $formula preg_replace("/(^@)/"""$formula);
  1895.         else {
  1896.             // Error handling
  1897.             $this->writeString($row$col'Unrecognised character for formula');
  1898.             return -1;
  1899.         }
  1900.  
  1901.         // Parse the formula using the parser in Parser.php
  1902.         $error $this->_parser->parse($formula);
  1903.  
  1904.         $formula $this->_parser->toReversePolish();
  1905.  
  1906.         $formlen    strlen($formula);    // Length of the binary string
  1907.         $length     0x16 $formlen;     // Length of the record data
  1908.  
  1909.         $header    pack("vv",      $record$length);
  1910.         $data      pack("vvvdvVv"$row$col$xf$num,
  1911.                                      $grbit$unknown$formlen);
  1912.  
  1913.         $this->_append($header $data $formula);
  1914.         return 0;
  1915.     }
  1916.  
  1917.     /**
  1918.     * Write a hyperlink.
  1919.     * This is comprised of two elements: the visible label and
  1920.     * the invisible link. The visible label is the same as the link unless an
  1921.     * alternative string is specified. The label is written using the
  1922.     * writeString() method. Therefore the 255 characters string limit applies.
  1923.     * $string and $format are optional.
  1924.     *
  1925.     * The hyperlink can be to a http, ftp, mail, internal sheet (not yet), or external
  1926.     * directory url.
  1927.     *
  1928.     * Returns  0 : normal termination
  1929.     *         -2 : row or column out of range
  1930.     *         -3 : long string truncated to 255 chars
  1931.     *
  1932.     * @access public
  1933.     * @param integer $row    Row
  1934.     * @param integer $col    Column
  1935.     * @param string  $url    URL string
  1936.     * @return integer 
  1937.     */
  1938.     function writeUrl($row$col$url)
  1939.     {
  1940.         // Add start row and col to arg list
  1941.         return($this->_writeUrlRange($row$col$row$col$url));
  1942.     }
  1943.  
  1944.     /**
  1945.     * This is the more general form of writeUrl(). It allows a hyperlink to be
  1946.     * written to a range of cells. This function also decides the type of hyperlink
  1947.     * to be written. These are either, Web (http, ftp, mailto), Internal
  1948.     * (Sheet1!A1) or external ('c:\temp\foo.xls#Sheet1!A1').
  1949.     *
  1950.     * @access private
  1951.     * @see writeUrl()
  1952.     * @param integer $row1   Start row
  1953.     * @param integer $col1   Start column
  1954.     * @param integer $row2   End row
  1955.     * @param integer $col2   End column
  1956.     * @param string  $url    URL string
  1957.     * @return integer 
  1958.     */
  1959.  
  1960.     function _writeUrlRange($row1$col1$row2$col2$url)
  1961.     {
  1962.  
  1963.         // Check for internal/external sheet links or default to web link
  1964.         if (preg_match('[^internal:]'$url)) {
  1965.             return($this->_writeUrlInternal($row1$col1$row2$col2$url));
  1966.         }
  1967.         if (preg_match('[^external:]'$url)) {
  1968.             return($this->_writeUrlExternal($row1$col1$row2$col2$url));
  1969.         }
  1970.         return($this->_writeUrlWeb($row1$col1$row2$col2$url));
  1971.     }
  1972.  
  1973.  
  1974.     /**
  1975.     * Used to write http, ftp and mailto hyperlinks.
  1976.     * The link type ($options) is 0x03 is the same as absolute dir ref without
  1977.     * sheet. However it is differentiated by the $unknown2 data stream.
  1978.     *
  1979.     * @access private
  1980.     * @see writeUrl()
  1981.     * @param integer $row1   Start row
  1982.     * @param integer $col1   Start column
  1983.     * @param integer $row2   End row
  1984.     * @param integer $col2   End column
  1985.     * @param string  $url    URL string
  1986.     * @return integer 
  1987.     */
  1988.     function _writeUrlWeb($row1$col1$row2$col2$url)
  1989.     {
  1990.         $record      0x01B8;                       // Record identifier
  1991.         $length      0x00000;                      // Bytes to follow
  1992.  
  1993.         // Pack the undocumented parts of the hyperlink stream
  1994.         $unknown1    pack("H*""D0C9EA79F9BACE118C8200AA004BA90B02000000");
  1995.         $unknown2    pack("H*""E0C9EA79F9BACE118C8200AA004BA90B");
  1996.  
  1997.         // Pack the option flags
  1998.         $options     pack("V"0x03);
  1999.  
  2000.         // Convert URL to a null terminated wchar string
  2001.         $url         join("\0"preg_split("''"$url-1PREG_SPLIT_NO_EMPTY));
  2002.         $url         $url "\0\0\0";
  2003.  
  2004.         // Pack the length of the URL
  2005.         $url_len     pack("V"strlen($url));
  2006.  
  2007.         // Calculate the data length
  2008.         $length      0x34 strlen($url);
  2009.  
  2010.         // Pack the header data
  2011.         $header      pack("vv",   $record$length);
  2012.         $data        pack("vvvv"$row1$row2$col1$col2);
  2013.  
  2014.         // Write the packed data
  2015.         $this->_append($header $data .
  2016.                        $unknown1 $options .
  2017.                        $unknown2 $url_len $url);
  2018.         return 0;
  2019.     }
  2020.  
  2021.     /**
  2022.     * Used to write internal reference hyperlinks such as "Sheet1!A1".
  2023.     *
  2024.     * @access private
  2025.     * @see writeUrl()
  2026.     * @param integer $row1   Start row
  2027.     * @param integer $col1   Start column
  2028.     * @param integer $row2   End row
  2029.     * @param integer $col2   End column
  2030.     * @param string  $url    URL string
  2031.     * @return integer 
  2032.     */
  2033.     function _writeUrlInternal($row1$col1$row2$col2$url)
  2034.     {
  2035.         $record      0x01B8;                       // Record identifier
  2036.         $length      0x00000;                      // Bytes to follow
  2037.  
  2038.         // Strip URL type
  2039.         $url preg_replace('/^internal:/'''$url);
  2040.  
  2041.         // Pack the undocumented parts of the hyperlink stream
  2042.         $unknown1    pack("H*""D0C9EA79F9BACE118C8200AA004BA90B02000000");
  2043.  
  2044.         // Pack the option flags
  2045.         $options     pack("V"0x08);
  2046.  
  2047.         // Convert the URL type and to a null terminated wchar string
  2048.         $url         join("\0"preg_split("''"$url-1PREG_SPLIT_NO_EMPTY));
  2049.         $url         $url "\0\0\0";
  2050.  
  2051.         // Pack the length of the URL as chars (not wchars)
  2052.         $url_len     pack("V"floor(strlen($url)/2));
  2053.  
  2054.         // Calculate the data length
  2055.         $length      0x24 strlen($url);
  2056.  
  2057.         // Pack the header data
  2058.         $header      pack("vv",   $record$length);
  2059.         $data        pack("vvvv"$row1$row2$col1$col2);
  2060.  
  2061.         // Write the packed data
  2062.         $this->_append($header $data .
  2063.                        $unknown1 $options .
  2064.                        $url_len $url);
  2065.         return 0;
  2066.     }
  2067.  
  2068.     /**
  2069.     * Write links to external directory names such as 'c:\foo.xls',
  2070.     * c:\foo.xls#Sheet1!A1', '../../foo.xls'. and '../../foo.xls#Sheet1!A1'.
  2071.     *
  2072.     * Note: Excel writes some relative links with the $dir_long string. We ignore
  2073.     * these cases for the sake of simpler code.
  2074.     *
  2075.     * @access private
  2076.     * @see writeUrl()
  2077.     * @param integer $row1   Start row
  2078.     * @param integer $col1   Start column
  2079.     * @param integer $row2   End row
  2080.     * @param integer $col2   End column
  2081.     * @param string  $url    URL string
  2082.     * @return integer 
  2083.     */
  2084.     function _writeUrlExternal($row1$col1$row2$col2$url)
  2085.     {
  2086.         // Network drives are different. We will handle them separately
  2087.         // MS/Novell network drives and shares start with \\
  2088.         if (preg_match('[^external:\\\\]'$url)) {
  2089.             return//($this->_writeUrlExternal_net($row1, $col1, $row2, $col2, $url, $str, $format));
  2090.         }
  2091.  
  2092.         $record      0x01B8;                       // Record identifier
  2093.         $length      0x00000;                      // Bytes to follow
  2094.  
  2095.         // Strip URL type and change Unix dir separator to Dos style (if needed)
  2096.         //
  2097.         $url preg_replace('/^external:/'''$url);
  2098.         $url preg_replace('/\//'"\\"$url);
  2099.  
  2100.         // Determine if the link is relative or absolute:
  2101.         //   relative if link contains no dir separator, "somefile.xls"
  2102.         //   relative if link starts with up-dir, "..\..\somefile.xls"
  2103.         //   otherwise, absolute
  2104.  
  2105.         $absolute    0x02// Bit mask
  2106.         if (!preg_match("/\\\/"$url)) {
  2107.             $absolute    0x00;
  2108.         }
  2109.         if (preg_match("/^\.\.\\\/"$url)) {
  2110.             $absolute    0x00;
  2111.         }
  2112.         $link_type               0x01 $absolute;
  2113.  
  2114.         // Determine if the link contains a sheet reference and change some of the
  2115.         // parameters accordingly.
  2116.         // Split the dir name and sheet name (if it exists)
  2117.         /*if (preg_match("/\#/", $url)) {
  2118.             list($dir_long, $sheet) = split("\#", $url);
  2119.         } else {
  2120.             $dir_long = $url;
  2121.         }
  2122.  
  2123.         if (isset($sheet)) {
  2124.             $link_type |= 0x08;
  2125.             $sheet_len  = pack("V", strlen($sheet) + 0x01);
  2126.             $sheet      = join("\0", split('', $sheet));
  2127.             $sheet     .= "\0\0\0";
  2128.         } else {
  2129.             $sheet_len   = '';
  2130.             $sheet       = '';
  2131.         }*/
  2132.         $dir_long $url;
  2133.         if (preg_match("/\#/"$url)) {
  2134.             $link_type |= 0x08;
  2135.         }
  2136.  
  2137.  
  2138.  
  2139.         // Pack the link type
  2140.         $link_type   pack("V"$link_type);
  2141.  
  2142.         // Calculate the up-level dir count e.g.. (..\..\..\ == 3)
  2143.         $up_count    preg_match_all("/\.\.\\\/"$dir_long$useless);
  2144.         $up_count    pack("v"$up_count);
  2145.  
  2146.         // Store the short dos dir name (null terminated)
  2147.         $dir_short   preg_replace("/\.\.\\\/"''$dir_long"\0";
  2148.  
  2149.         // Store the long dir name as a wchar string (non-null terminated)
  2150.         //$dir_long       = join("\0", split('', $dir_long));
  2151.         $dir_long       $dir_long "\0";
  2152.  
  2153.         // Pack the lengths of the dir strings
  2154.         $dir_short_len pack("V"strlen($dir_short)      );
  2155.         $dir_long_len  pack("V"strlen($dir_long)       );
  2156.         $stream_len    pack("V"0);//strlen($dir_long) + 0x06);
  2157.  
  2158.         // Pack the undocumented parts of the hyperlink stream
  2159.         $unknown1 pack("H*",'D0C9EA79F9BACE118C8200AA004BA90B02000000'       );
  2160.         $unknown2 pack("H*",'0303000000000000C000000000000046'               );
  2161.         $unknown3 pack("H*",'FFFFADDE000000000000000000000000000000000000000');
  2162.         $unknown4 pack("v",  0x03                                            );
  2163.  
  2164.         // Pack the main data stream
  2165.         $data        pack("vvvv"$row1$row2$col1$col2.
  2166.                           $unknown1     .
  2167.                           $link_type    .
  2168.                           $unknown2     .
  2169.                           $up_count     .
  2170.                           $dir_short_len.
  2171.                           $dir_short    .
  2172.                           $unknown3     .
  2173.                           $stream_len   ;/*.
  2174.                           $dir_long_len .
  2175.                           $unknown4     .
  2176.                           $dir_long     .
  2177.                           $sheet_len    .
  2178.                           $sheet        ;*/
  2179.  
  2180.         // Pack the header data
  2181.         $length   strlen($data);
  2182.         $header   pack("vv"$record$length);
  2183.  
  2184.         // Write the packed data
  2185.         $this->_append($header$data);
  2186.         return 0;
  2187.     }
  2188.  
  2189.  
  2190.     /**
  2191.      * Set the default column (character) width
  2192.      *
  2193.      * @param integer $width 
  2194.      */
  2195.     public function setDefColWidth($width)
  2196.     {
  2197.         $this->_defColWidth = $width;
  2198.     }
  2199.  
  2200.     /**
  2201.      * Set the default row height in twips = 1/20 of a point
  2202.      */
  2203.     public function setDefaultRowHeight($height)
  2204.     {
  2205.         $this->_defaultRowHeight = $height;
  2206.     }
  2207.  
  2208.     /**
  2209.     * This method is used to set the height and format for a row.
  2210.     *
  2211.     * @access public
  2212.     * @param integer $row    The row to set
  2213.     * @param integer $height Height we are giving to the row.
  2214.     *                         Use null to set XF without setting height
  2215.     * @param mixed   $format XF format we are giving to the row
  2216.     * @param bool    $hidden The optional hidden attribute
  2217.     * @param integer $level  The optional outline level for row, in range [0,7]
  2218.     */
  2219.     function setRow($row$height$format null$hidden false$level 0)
  2220.     {
  2221.         $record      0x0208;               // Record identifier
  2222.         $length      0x0010;               // Number of bytes to follow
  2223.  
  2224.         $colMic      0x0000;               // First defined column
  2225.         $colMac      0x0000;               // Last defined column
  2226.         $irwMac      0x0000;               // Used by Excel to optimise loading
  2227.         $reserved    0x0000;               // Reserved
  2228.         $grbit       0x0000;               // Option flags
  2229.         $ixfe        $this->_XF($format);  // XF index
  2230.  
  2231.         if $height ){
  2232.             $height null;
  2233.         }
  2234.  
  2235.         // set _row_sizes so _sizeRow() can use it
  2236.         $this->_row_sizes[$row$height;
  2237.  
  2238.         // Use setRow($row, null, $XF) to set XF format without setting height
  2239.         if ($height != null{
  2240.             $miyRw $height 20;  // row height
  2241.         else {
  2242.             $miyRw 0xff;          // default row height is 256
  2243.         }
  2244.  
  2245.         $level max(0min($level7));  // level should be between 0 and 7
  2246.         $this->_outline_row_level = max($level$this->_outline_row_level);
  2247.  
  2248.  
  2249.         // Set the options flags. fUnsynced is used to show that the font and row
  2250.         // heights are not compatible. This is usually the case for WriteExcel.
  2251.         // The collapsed flag 0x10 doesn't seem to be used to indicate that a row
  2252.         // is collapsed. Instead it is used to indicate that the previous row is
  2253.         // collapsed. The zero height flag, 0x20, is used to collapse a row.
  2254.  
  2255.         $grbit |= $level;
  2256.         if ($hidden{
  2257.             $grbit |= 0x0020;
  2258.         }
  2259.         $grbit |= 0x0040// fUnsynced
  2260.         if ($format{
  2261.             $grbit |= 0x0080;
  2262.         }
  2263.         $grbit |= 0x0100;
  2264.  
  2265.         $header   pack("vv",       $record$length);
  2266.         $data     pack("vvvvvvvv"$row$colMic$colMac$miyRw,
  2267.                                      $irwMac,$reserved$grbit$ixfe);
  2268.         $this->_append($header.$data);
  2269.     }
  2270.  
  2271.     /**
  2272.     * Writes Excel DIMENSIONS to define the area in which there is data.
  2273.     *
  2274.     * @access private
  2275.     */
  2276.     function _storeDimensions()
  2277.     {
  2278.         $record    0x0200;                 // Record identifier
  2279.         $row_min   $this->_dim_rowmin;     // First row
  2280.         $row_max   $this->_dim_rowmax + 1// Last row plus 1
  2281.         $col_min   $this->_dim_colmin;     // First column
  2282.         $col_max   $this->_dim_colmax + 1// Last column plus 1
  2283.         $reserved  0x0000;                 // Reserved by Excel
  2284.  
  2285.         if ($this->_BIFF_version == 0x0500{
  2286.             $length    0x000A;               // Number of bytes to follow
  2287.             $data      pack("vvvvv"$row_min$row_max,
  2288.                                        $col_min$col_max$reserved);
  2289.         elseif ($this->_BIFF_version == 0x0600{
  2290.             $length    0x000E;
  2291.             //$data      = pack("VVvvv", $row_min, $row_max,
  2292.             //                           $col_min, $col_max, $reserved);
  2293.             $data pack("VVvvv"$this->_firstRowIndex$this->_lastRowIndex + 1,
  2294.                             $this->_firstColumnIndex$this->_lastColumnIndex + 1$reserved);
  2295.         }
  2296.         $header pack("vv"$record$length);
  2297.         $this->_prepend($header.$data);
  2298.     }
  2299.  
  2300.     /**
  2301.     * Write BIFF record Window2.
  2302.     *
  2303.     * @access private
  2304.     */
  2305.     function _storeWindow2()
  2306.     {
  2307.         $record         0x023E;     // Record identifier
  2308.         if ($this->_BIFF_version == 0x0500{
  2309.             $length         0x000A;     // Number of bytes to follow
  2310.         elseif ($this->_BIFF_version == 0x0600{
  2311.             $length         0x0012;
  2312.         }
  2313.  
  2314.         $grbit          0x00B6;     // Option flags
  2315.         $rwTop          0x0000;     // Top row visible in window
  2316.         $colLeft        0x0000;     // Leftmost column visible in window
  2317.  
  2318.  
  2319.         // The options flags that comprise $grbit
  2320.         $fDspFmla       0;                     // 0 - bit
  2321.         $fDspGrid       $this->_screen_gridlines// 1
  2322.         $fDspRwCol      1;                     // 2
  2323.         $fFrozen        $this->_frozen;        // 3
  2324.         $fDspZeros      1;                     // 4
  2325.         $fDefaultHdr    1;                     // 5
  2326.         $fArabic        0;                     // 6
  2327.         $fDspGuts       $this->_outline_on;    // 7
  2328.         $fFrozenNoSplit 0;                     // 0 - bit
  2329.         $fSelected      $this->selected;       // 1
  2330.         $fPaged         1;                     // 2
  2331.  
  2332.         $grbit             $fDspFmla;
  2333.         $grbit            |= $fDspGrid       << 1;
  2334.         $grbit            |= $fDspRwCol      << 2;
  2335.         $grbit            |= $fFrozen        << 3;
  2336.         $grbit            |= $fDspZeros      << 4;
  2337.         $grbit            |= $fDefaultHdr    << 5;
  2338.         $grbit            |= $fArabic        << 6;
  2339.         $grbit            |= $fDspGuts       << 7;
  2340.         $grbit            |= $fFrozenNoSplit << 8;
  2341.         $grbit            |= $fSelected      << 9;
  2342.         $grbit            |= $fPaged         << 10;
  2343.  
  2344.         $header  pack("vv",   $record$length);
  2345.         $data    pack("vvv"$grbit$rwTop$colLeft);
  2346.         // FIXME !!!
  2347.         if ($this->_BIFF_version == 0x0500{
  2348.             $rgbHdr         0x00000000// Row/column heading and gridline color
  2349.             $data .= pack("V"$rgbHdr);
  2350.         elseif ($this->_BIFF_version == 0x0600{
  2351.             $rgbHdr       0x0040// Row/column heading and gridline color index
  2352.             $zoom_factor_page_break 0x0000;
  2353.             $zoom_factor_normal     0x0000;
  2354.             $data .= pack("vvvvV"$rgbHdr0x0000$zoom_factor_page_break$zoom_factor_normal0x00000000);
  2355.         }
  2356.         $this->_append($header.$data);
  2357.     }
  2358.  
  2359.     /**
  2360.      * Write BIFF record DEFAULTROWHEIGHT.
  2361.      *
  2362.      * @access private
  2363.      */
  2364.     private function _storeDefaultRowHeight()
  2365.     {
  2366.         if (isset($this->_defaultRowHeight)) {
  2367.             $record   0x0225;      // Record identifier
  2368.             $length   0x0004;      // Number of bytes to follow
  2369.  
  2370.             $header   pack("vv"$record$length);
  2371.             $data     pack("vv",  1$this->_defaultRowHeight);
  2372.             $this->_prepend($header $data);
  2373.         }
  2374.     }
  2375.  
  2376.     /**
  2377.     * Write BIFF record DEFCOLWIDTH if COLINFO records are in use.
  2378.     *
  2379.     * @access private
  2380.     */
  2381.     function _storeDefcol()
  2382.     {
  2383.         $record   0x0055;      // Record identifier
  2384.         $length   0x0002;      // Number of bytes to follow
  2385.         //$colwidth = 0x0008;      // Default column width
  2386.  
  2387.         $header   pack("vv"$record$length);
  2388.         //$data     = pack("v",  $colwidth);
  2389.         $data     pack("v",  $this->_defColWidth);
  2390.         $this->_prepend($header $data);
  2391.     }
  2392.  
  2393.     /**
  2394.     * Write BIFF record COLINFO to define column widths
  2395.     *
  2396.     * Note: The SDK says the record length is 0x0B but Excel writes a 0x0C
  2397.     * length record.
  2398.     *
  2399.     * @access private
  2400.     * @param array $col_array This is the only parameter received and is composed of the following:
  2401.     *                 0 => First formatted column,
  2402.     *                 1 => Last formatted column,
  2403.     *                 2 => Col width (8.43 is Excel default),
  2404.     *                 3 => The optional XF format of the column,
  2405.     *                 4 => Option flags.
  2406.     *                 5 => Optional outline level
  2407.     */
  2408.     function _storeColinfo($col_array)
  2409.     {
  2410.         if (isset($col_array[0])) {
  2411.             $colFirst $col_array[0];
  2412.         }
  2413.         if (isset($col_array[1])) {
  2414.             $colLast $col_array[1];
  2415.         }
  2416.         if (isset($col_array[2])) {
  2417.             $coldx $col_array[2];
  2418.         else {
  2419.             $coldx 8.43;
  2420.         }
  2421.         if (isset($col_array[3])) {
  2422.             $format $col_array[3];
  2423.         else {
  2424.             $format 0;
  2425.         }
  2426.         if (isset($col_array[4])) {
  2427.             $grbit $col_array[4];
  2428.         else {
  2429.             $grbit 0;
  2430.         }
  2431.         if (isset($col_array[5])) {
  2432.             $level $col_array[5];
  2433.         else {
  2434.             $level 0;
  2435.         }
  2436.         $record   0x007D;          // Record identifier
  2437.         $length   0x000B;          // Number of bytes to follow
  2438.  
  2439.         $coldx   += 0.72;            // Fudge. Excel subtracts 0.72 !?
  2440.         $coldx   *= 256;             // Convert to units of 1/256 of a char
  2441.  
  2442.         $ixfe     $this->_XF($format);
  2443.         $reserved 0x00;            // Reserved
  2444.  
  2445.         $level max(0min($level7));
  2446.         $grbit |= $level << 8;
  2447.  
  2448.         $header   pack("vv",     $record$length);
  2449.         $data     pack("vvvvvC"$colFirst$colLast$coldx,
  2450.                                    $ixfe$grbit$reserved);
  2451.         $this->_prepend($header.$data);
  2452.     }
  2453.  
  2454.     /**
  2455.     * Write BIFF record SELECTION.
  2456.     *
  2457.     * @access private
  2458.     * @param array $array array containing ($rwFirst,$colFirst,$rwLast,$colLast)
  2459.     * @see setSelection()
  2460.     */
  2461.     function _storeSelection($array)
  2462.     {
  2463.         list($rwFirst,$colFirst,$rwLast,$colLast$array;
  2464.         $record   0x001D;                  // Record identifier
  2465.         $length   0x000F;                  // Number of bytes to follow
  2466.  
  2467.         $pnn      $this->_active_pane;     // Pane position
  2468.         $rwAct    $rwFirst;                // Active row
  2469.         $colAct   $colFirst;               // Active column
  2470.         $irefAct  0;                       // Active cell ref
  2471.         $cref     1;                       // Number of refs
  2472.  
  2473.         if (!isset($rwLast)) {
  2474.             $rwLast   $rwFirst;       // Last  row in reference
  2475.         }
  2476.         if (!isset($colLast)) {
  2477.             $colLast  $colFirst;      // Last  col in reference
  2478.         }
  2479.  
  2480.         // Swap last row/col for first row/col as necessary
  2481.         if ($rwFirst $rwLast{
  2482.             list($rwFirst$rwLastarray($rwLast$rwFirst);
  2483.         }
  2484.  
  2485.         if ($colFirst $colLast{
  2486.             list($colFirst$colLastarray($colLast$colFirst);
  2487.         }
  2488.  
  2489.         $header   pack("vv",         $record$length);
  2490.         $data     pack("CvvvvvvCC",  $pnn$rwAct$colAct,
  2491.                                        $irefAct$cref,
  2492.                                        $rwFirst$rwLast,
  2493.                                        $colFirst$colLast);
  2494.         $this->_append($header $data);
  2495.     }
  2496.  
  2497.     /**
  2498.     * Store the MERGEDCELLS record for all ranges of merged cells
  2499.     *
  2500.     * @access private
  2501.     */
  2502.     function _storeMergedCells()
  2503.     {
  2504.         // if there are no merged cell ranges set, return
  2505.         if (count($this->_merged_ranges== 0{
  2506.             return;
  2507.         }
  2508.         $record   0x00E5;
  2509.         $length   count($this->_merged_ranges8;
  2510.  
  2511.         $header   pack('vv'$record$length);
  2512.         $data     pack('v',  count($this->_merged_ranges));
  2513.         foreach ($this->_merged_ranges as $range{
  2514.             $data .= pack('vvvv'$range[0]$range[2]$range[1]$range[3]);
  2515.         }
  2516.         $this->_append($header $data);
  2517.     }
  2518.  
  2519.     /**
  2520.     * Write BIFF record EXTERNCOUNT to indicate the number of external sheet
  2521.     * references in a worksheet.
  2522.     *
  2523.     * Excel only stores references to external sheets that are used in formulas.
  2524.     * For simplicity we store references to all the sheets in the workbook
  2525.     * regardless of whether they are used or not. This reduces the overall
  2526.     * complexity and eliminates the need for a two way dialogue between the formula
  2527.     * parser the worksheet objects.
  2528.     *
  2529.     * @access private
  2530.     * @param integer $count The number of external sheet references in this worksheet
  2531.     */
  2532.     function _storeExterncount($count)
  2533.     {
  2534.         $record 0x0016;          // Record identifier
  2535.         $length 0x0002;          // Number of bytes to follow
  2536.  
  2537.         $header pack("vv"$record$length);
  2538.         $data   pack("v",  $count);
  2539.         $this->_prepend($header $data);
  2540.     }
  2541.  
  2542.     /**
  2543.     * Writes the Excel BIFF EXTERNSHEET record. These references are used by
  2544.     * formulas. A formula references a sheet name via an index. Since we store a
  2545.     * reference to all of the external worksheets the EXTERNSHEET index is the same
  2546.     * as the worksheet index.
  2547.     *
  2548.     * @access private
  2549.     * @param string $sheetname The name of a external worksheet
  2550.     */
  2551.     function _storeExternsheet($sheetname)
  2552.     {
  2553.         $record    0x0017;         // Record identifier
  2554.  
  2555.         // References to the current sheet are encoded differently to references to
  2556.         // external sheets.
  2557.         //
  2558.         if ($this->name == $sheetname{
  2559.             $sheetname '';
  2560.             $length    0x02;  // The following 2 bytes
  2561.             $cch       1;     // The following byte
  2562.             $rgch      0x02;  // Self reference
  2563.         else {
  2564.             $length    0x02 strlen($sheetname);
  2565.             $cch       strlen($sheetname);
  2566.             $rgch      0x03;  // Reference to a sheet in the current workbook
  2567.         }
  2568.  
  2569.         $header pack("vv",  $record$length);
  2570.         $data   pack("CC"$cch$rgch);
  2571.         $this->_prepend($header $data $sheetname);
  2572.     }
  2573.  
  2574.     /**
  2575.     * Writes the Excel BIFF PANE record.
  2576.     * The panes can either be frozen or thawed (unfrozen).
  2577.     * Frozen panes are specified in terms of an integer number of rows and columns.
  2578.     * Thawed panes are specified in terms of Excel's units for rows and columns.
  2579.     *
  2580.     * @access private
  2581.     * @param array $panes This is the only parameter received and is composed of the following:
  2582.     *                      0 => Vertical split position,
  2583.     *                      1 => Horizontal split position
  2584.     *                      2 => Top row visible
  2585.     *                      3 => Leftmost column visible
  2586.     *                      4 => Active pane
  2587.     */
  2588.     function _storePanes($panes)
  2589.     {
  2590.         $y       = isset($panes[0]$panes[0null;
  2591.         $x       = isset($panes[1]$panes[1null;
  2592.         $rwTop   = isset($panes[2]$panes[2null;
  2593.         $colLeft = isset($panes[3]$panes[3null;
  2594.         if (count($panes4// if Active pane was received
  2595.             $pnnAct $panes[4];
  2596.         else {
  2597.             $pnnAct null;
  2598.         }
  2599.         $record  0x0041;       // Record identifier
  2600.         $length  0x000A;       // Number of bytes to follow
  2601.  
  2602.         // Code specific to frozen or thawed panes.
  2603.         if ($this->_frozen{
  2604.             // Set default values for $rwTop and $colLeft
  2605.             if (!isset($rwTop)) {
  2606.                 $rwTop   $y;
  2607.             }
  2608.             if (!isset($colLeft)) {
  2609.                 $colLeft $x;
  2610.             }
  2611.         else {
  2612.             // Set default values for $rwTop and $colLeft
  2613.             if (!isset($rwTop)) {
  2614.                 $rwTop   0;
  2615.             }
  2616.             if (!isset($colLeft)) {
  2617.                 $colLeft 0;
  2618.             }
  2619.  
  2620.             // Convert Excel's row and column units to the internal units.
  2621.             // The default row height is 12.75
  2622.             // The default column width is 8.43
  2623.             // The following slope and intersection values were interpolated.
  2624.             //
  2625.             $y 20*$y      255;
  2626.             $x 113.879*$x 390;
  2627.         }
  2628.  
  2629.  
  2630.         // Determine which pane should be active. There is also the undocumented
  2631.         // option to override this should it be necessary: may be removed later.
  2632.         //
  2633.         if (!isset($pnnAct)) {
  2634.             if ($x != && $y != 0{
  2635.                 $pnnAct 0// Bottom right
  2636.             }
  2637.             if ($x != && $y == 0{
  2638.                 $pnnAct 1// Top right
  2639.             }
  2640.             if ($x == && $y != 0{
  2641.                 $pnnAct 2// Bottom left
  2642.             }
  2643.             if ($x == && $y == 0{
  2644.                 $pnnAct 3// Top left
  2645.             }
  2646.         }
  2647.  
  2648.         $this->_active_pane = $pnnAct// Used in _storeSelection
  2649.  
  2650.         $header     pack("vv",    $record$length);
  2651.         $data       pack("vvvvv"$x$y$rwTop$colLeft$pnnAct);
  2652.         $this->_append($header $data);
  2653.     }
  2654.  
  2655.     /**
  2656.     * Store the page setup SETUP BIFF record.
  2657.     *
  2658.     * @access private
  2659.     */
  2660.     function _storeSetup()
  2661.     {
  2662.         $record       0x00A1;                  // Record identifier
  2663.         $length       0x0022;                  // Number of bytes to follow
  2664.  
  2665.         $iPaperSize   $this->_paper_size;    // Paper size
  2666.         $iScale       $this->_print_scale;   // Print scaling factor
  2667.         $iPageStart   0x01;                 // Starting page number
  2668.         $iFitWidth    $this->_fit_width;    // Fit to number of pages wide
  2669.         $iFitHeight   $this->_fit_height;   // Fit to number of pages high
  2670.         $grbit        0x00;                 // Option flags
  2671.         $iRes         0x0258;               // Print resolution
  2672.         $iVRes        0x0258;               // Vertical print resolution
  2673.         $numHdr       $this->_margin_head;  // Header Margin
  2674.         $numFtr       $this->_margin_foot;   // Footer Margin
  2675.         $iCopies      0x01;                 // Number of copies
  2676.  
  2677.         $fLeftToRight 0x0;                     // Print over then down
  2678.         $fLandscape   $this->_orientation;     // Page orientation
  2679.         $fNoPls       0x0;                     // Setup not read from printer
  2680.         $fNoColor     0x0;                     // Print black and white
  2681.         $fDraft       0x0;                     // Print draft quality
  2682.         $fNotes       0x0;                     // Print notes
  2683.         $fNoOrient    0x0;                     // Orientation not set
  2684.         $fUsePage     0x0;                     // Use custom starting page
  2685.  
  2686.         $grbit           $fLeftToRight;
  2687.         $grbit          |= $fLandscape    << 1;
  2688.         $grbit          |= $fNoPls        << 2;
  2689.         $grbit          |= $fNoColor      << 3;
  2690.         $grbit          |= $fDraft        << 4;
  2691.         $grbit          |= $fNotes        << 5;
  2692.         $grbit          |= $fNoOrient     << 6;
  2693.         $grbit          |= $fUsePage      << 7;
  2694.  
  2695.         $numHdr pack("d"$numHdr);
  2696.         $numFtr pack("d"$numFtr);
  2697.         if ($this->_byte_order// if it's Big Endian
  2698.             $numHdr strrev($numHdr);
  2699.             $numFtr strrev($numFtr);
  2700.         }
  2701.  
  2702.         $header pack("vv"$record$length);
  2703.         $data1  pack("vvvvvvvv"$iPaperSize,
  2704.                                    $iScale,
  2705.                                    $iPageStart,
  2706.                                    $iFitWidth,
  2707.                                    $iFitHeight,
  2708.                                    $grbit,
  2709.                                    $iRes,
  2710.                                    $iVRes);
  2711.         $data2  $numHdr.$numFtr;
  2712.         $data3  pack("v"$iCopies);
  2713.         $this->_prepend($header $data1 $data2 $data3);
  2714.     }
  2715.  
  2716.     /**
  2717.     * Store the header caption BIFF record.
  2718.     *
  2719.     * @access private
  2720.     */
  2721.     function _storeHeader()
  2722.     {
  2723.         $record  0x0014;               // Record identifier
  2724.  
  2725.         $str      $this->_header;       // header string
  2726.         $cch      strlen($str);         // Length of header string
  2727.         if ($this->_BIFF_version == 0x0600{
  2728.             $encoding 0x0;                  // TODO: Unicode support
  2729.             $length   $cch;             // Bytes to follow
  2730.         else {
  2731.             $length  $cch;             // Bytes to follow
  2732.         }
  2733.  
  2734.         $header   pack("vv"$record$length);
  2735.         if ($this->_BIFF_version == 0x0600{
  2736.             $data     pack("vC",  $cch$encoding);
  2737.         else {
  2738.             $data      pack("C",  $cch);
  2739.         }
  2740.  
  2741.         $this->_prepend($header.$data.$str);
  2742.     }
  2743.  
  2744.     /**
  2745.     * Store the footer caption BIFF record.
  2746.     *
  2747.     * @access private
  2748.     */
  2749.     function _storeFooter()
  2750.     {
  2751.         $record  0x0015;               // Record identifier
  2752.  
  2753.         $str      $this->_footer;       // Footer string
  2754.         $cch      strlen($str);         // Length of footer string
  2755.         if ($this->_BIFF_version == 0x0600{
  2756.             $encoding 0x0;                  // TODO: Unicode support
  2757.             $length   $cch;             // Bytes to follow
  2758.         else {
  2759.             $length  $cch;
  2760.         }
  2761.  
  2762.         $header    pack("vv"$record$length);
  2763.         if ($this->_BIFF_version == 0x0600{
  2764.             $data      pack("vC",  $cch$encoding);
  2765.         else {
  2766.             $data      pack("C",  $cch);
  2767.         }
  2768.  
  2769.         $this->_prepend($header $data $str);
  2770.     }
  2771.  
  2772.     /**
  2773.     * Store the horizontal centering HCENTER BIFF record.
  2774.     *
  2775.     * @access private
  2776.     */
  2777.     function _storeHcenter()
  2778.     {
  2779.         $record   0x0083;              // Record identifier
  2780.         $length   0x0002;              // Bytes to follow
  2781.  
  2782.         $fHCenter $this->_hcenter;     // Horizontal centering
  2783.  
  2784.         $header    pack("vv"$record$length);
  2785.         $data      pack("v",  $fHCenter);
  2786.  
  2787.         $this->_prepend($header.$data);
  2788.     }
  2789.  
  2790.     /**
  2791.     * Store the vertical centering VCENTER BIFF record.
  2792.     *
  2793.     * @access private
  2794.     */
  2795.     function _storeVcenter()
  2796.     {
  2797.         $record   0x0084;              // Record identifier
  2798.         $length   0x0002;              // Bytes to follow
  2799.  
  2800.         $fVCenter $this->_vcenter;     // Horizontal centering
  2801.  
  2802.         $header    pack("vv"$record$length);
  2803.         $data      pack("v",  $fVCenter);
  2804.         $this->_prepend($header $data);
  2805.     }
  2806.  
  2807.     /**
  2808.     * Store the LEFTMARGIN BIFF record.
  2809.     *
  2810.     * @access private
  2811.     */
  2812.     function _storeMarginLeft()
  2813.     {
  2814.         $record  0x0026;                   // Record identifier
  2815.         $length  0x0008;                   // Bytes to follow
  2816.  
  2817.         $margin  $this->_margin_left;       // Margin in inches
  2818.  
  2819.         $header    pack("vv",  $record$length);
  2820.         $data      pack("d",   $margin);
  2821.         if ($this->_byte_order// if it's Big Endian
  2822.             $data strrev($data);
  2823.         }
  2824.  
  2825.         $this->_prepend($header $data);
  2826.     }
  2827.  
  2828.     /**
  2829.     * Store the RIGHTMARGIN BIFF record.
  2830.     *
  2831.     * @access private
  2832.     */
  2833.     function _storeMarginRight()
  2834.     {
  2835.         $record  0x0027;                   // Record identifier
  2836.         $length  0x0008;                   // Bytes to follow
  2837.  
  2838.         $margin  $this->_margin_right;      // Margin in inches
  2839.  
  2840.         $header    pack("vv",  $record$length);
  2841.         $data      pack("d",   $margin);
  2842.         if ($this->_byte_order// if it's Big Endian
  2843.             $data strrev($data);
  2844.         }
  2845.  
  2846.         $this->_prepend($header $data);
  2847.     }
  2848.  
  2849.     /**
  2850.     * Store the TOPMARGIN BIFF record.
  2851.     *
  2852.     * @access private
  2853.     */
  2854.     function _storeMarginTop()
  2855.     {
  2856.         $record  0x0028;                   // Record identifier
  2857.         $length  0x0008;                   // Bytes to follow
  2858.  
  2859.         $margin  $this->_margin_top;        // Margin in inches
  2860.  
  2861.         $header    pack("vv",  $record$length);
  2862.         $data      pack("d",   $margin);
  2863.         if ($this->_byte_order// if it's Big Endian
  2864.             $data strrev($data);
  2865.         }
  2866.  
  2867.         $this->_prepend($header $data);
  2868.     }
  2869.  
  2870.     /**
  2871.     * Store the BOTTOMMARGIN BIFF record.
  2872.     *
  2873.     * @access private
  2874.     */
  2875.     function _storeMarginBottom()
  2876.     {
  2877.         $record  0x0029;                   // Record identifier
  2878.         $length  0x0008;                   // Bytes to follow
  2879.  
  2880.         $margin  $this->_margin_bottom;     // Margin in inches
  2881.  
  2882.         $header    pack("vv",  $record$length);
  2883.         $data      pack("d",   $margin);
  2884.         if ($this->_byte_order// if it's Big Endian
  2885.             $data strrev($data);
  2886.         }
  2887.  
  2888.         $this->_prepend($header $data);
  2889.     }
  2890.  
  2891.     /**
  2892.     * Merges the area given by its arguments.
  2893.     * This is an Excel97/2000 method. It is required to perform more complicated
  2894.     * merging than the normal setAlign('merge').
  2895.     *
  2896.     * @access public
  2897.     * @param integer $first_row First row of the area to merge
  2898.     * @param integer $first_col First column of the area to merge
  2899.     * @param integer $last_row  Last row of the area to merge
  2900.     * @param integer $last_col  Last column of the area to merge
  2901.     */
  2902.     function mergeCells($first_row$first_col$last_row$last_col)
  2903.     {
  2904.         $record  0x00E5;                   // Record identifier
  2905.         $length  0x000A;                   // Bytes to follow
  2906.         $cref     1;                       // Number of refs
  2907.  
  2908.         // Swap last row/col for first row/col as necessary
  2909.         if ($first_row $last_row{
  2910.             list($first_row$last_rowarray($last_row$first_row);
  2911.         }
  2912.  
  2913.         if ($first_col $last_col{
  2914.             list($first_col$last_colarray($last_col$first_col);
  2915.         }
  2916.  
  2917.         $header   pack("vv",    $record$length);
  2918.         $data     pack("vvvvv"$cref$first_row$last_row,
  2919.                                   $first_col$last_col);
  2920.  
  2921.         $this->_append($header.$data);
  2922.     }
  2923.  
  2924.     /**
  2925.     * Write the PRINTHEADERS BIFF record.
  2926.     *
  2927.     * @access private
  2928.     */
  2929.     function _storePrintHeaders()
  2930.     {
  2931.         $record      0x002a;                   // Record identifier
  2932.         $length      0x0002;                   // Bytes to follow
  2933.  
  2934.         $fPrintRwCol $this->_print_headers;     // Boolean flag
  2935.  
  2936.         $header      pack("vv"$record$length);
  2937.         $data        pack("v"$fPrintRwCol);
  2938.         $this->_prepend($header $data);
  2939.     }
  2940.  
  2941.     /**
  2942.     * Write the PRINTGRIDLINES BIFF record. Must be used in conjunction with the
  2943.     * GRIDSET record.
  2944.     *
  2945.     * @access private
  2946.     */
  2947.     function _storePrintGridlines()
  2948.     {
  2949.         $record      0x002b;                    // Record identifier
  2950.         $length      0x0002;                    // Bytes to follow
  2951.  
  2952.         $fPrintGrid  $this->_print_gridlines;    // Boolean flag
  2953.  
  2954.         $header      pack("vv"$record$length);
  2955.         $data        pack("v"$fPrintGrid);
  2956.         $this->_prepend($header $data);
  2957.     }
  2958.  
  2959.     /**
  2960.     * Write the GRIDSET BIFF record. Must be used in conjunction with the
  2961.     * PRINTGRIDLINES record.
  2962.     *
  2963.     * @access private
  2964.     */
  2965.     function _storeGridset()
  2966.     {
  2967.         $record      0x0082;                        // Record identifier
  2968.         $length      0x0002;                        // Bytes to follow
  2969.  
  2970.         $fGridSet    !($this->_print_gridlines);     // Boolean flag
  2971.  
  2972.         $header      pack("vv",  $record$length);
  2973.         $data        pack("v",   $fGridSet);
  2974.         $this->_prepend($header $data);
  2975.     }
  2976.  
  2977.     /**
  2978.     * Write the GUTS BIFF record. This is used to configure the gutter margins
  2979.     * where Excel outline symbols are displayed. The visibility of the gutters is
  2980.     * controlled by a flag in WSBOOL.
  2981.     *
  2982.     * @see _storeWsbool()
  2983.     * @access private
  2984.     */
  2985.     function _storeGuts()
  2986.     {
  2987.         $record      0x0080;   // Record identifier
  2988.         $length      0x0008;   // Bytes to follow
  2989.  
  2990.         $dxRwGut     0x0000;   // Size of row gutter
  2991.         $dxColGut    0x0000;   // Size of col gutter
  2992.  
  2993.         $row_level   $this->_outline_row_level;
  2994.         $col_level   0;
  2995.  
  2996.         // Calculate the maximum column outline level. The equivalent calculation
  2997.         // for the row outline level is carried out in setRow().
  2998.         $colcount count($this->_colinfo);
  2999.         for ($i 0$i $colcount++$i{
  3000.             $col_level max($this->_colinfo[$i][5]$col_level);
  3001.         }
  3002.  
  3003.         // Set the limits for the outline levels (0 <= x <= 7).
  3004.         $col_level max(0min($col_level7));
  3005.  
  3006.         // The displayed level is one greater than the max outline levels
  3007.         if ($row_level{
  3008.             ++$row_level;
  3009.         }
  3010.         if ($col_level{
  3011.             ++$col_level;
  3012.         }
  3013.  
  3014.         $header      pack("vv",   $record$length);
  3015.         $data        pack("vvvv"$dxRwGut$dxColGut$row_level$col_level);
  3016.  
  3017.         $this->_prepend($header.$data);
  3018.     }
  3019.  
  3020.  
  3021.     /**
  3022.     * Write the WSBOOL BIFF record, mainly for fit-to-page. Used in conjunction
  3023.     * with the SETUP record.
  3024.     *
  3025.     * @access private
  3026.     */
  3027.     function _storeWsbool()
  3028.     {
  3029.         $record      0x0081;   // Record identifier
  3030.         $length      0x0002;   // Bytes to follow
  3031.         $grbit       0x0000;
  3032.  
  3033.         // The only option that is of interest is the flag for fit to page. So we
  3034.         // set all the options in one go.
  3035.         //
  3036.         /*if ($this->_fit_page) {
  3037.             $grbit = 0x05c1;
  3038.         } else {
  3039.             $grbit = 0x04c1;
  3040.         }*/
  3041.         // Set the option flags
  3042.         $grbit |= 0x0001;                           // Auto page breaks visible
  3043.         if ($this->_outline_style{
  3044.             $grbit |= 0x0020// Auto outline styles
  3045.         }
  3046.         if ($this->_outline_below{
  3047.             $grbit |= 0x0040// Outline summary below
  3048.         }
  3049.         if ($this->_outline_right{
  3050.             $grbit |= 0x0080// Outline summary right
  3051.         }
  3052.         if ($this->_fit_page{
  3053.             $grbit |= 0x0100// Page setup fit to page
  3054.         }
  3055.         if ($this->_outline_on{
  3056.             $grbit |= 0x0400// Outline symbols displayed
  3057.         }
  3058.  
  3059.         $header      pack("vv"$record$length);
  3060.         $data        pack("v",  $grbit);
  3061.         $this->_prepend($header $data);
  3062.     }
  3063.  
  3064.     /**
  3065.     * Write the HORIZONTALPAGEBREAKS BIFF record.
  3066.     *
  3067.     * @access private
  3068.     */
  3069.     function _storeHbreak()
  3070.     {
  3071.         // Return if the user hasn't specified pagebreaks
  3072.         if (empty($this->_hbreaks)) {
  3073.             return;
  3074.         }
  3075.  
  3076.         // Sort and filter array of page breaks
  3077.         $breaks $this->_hbreaks;
  3078.         sort($breaksSORT_NUMERIC);
  3079.         if ($breaks[0== 0// don't use first break if it's 0
  3080.             array_shift($breaks);
  3081.         }
  3082.  
  3083.         $record  0x001b;               // Record identifier
  3084.         $cbrk    count($breaks);       // Number of page breaks
  3085.         if ($this->_BIFF_version == 0x0600{
  3086.             $length  6*$cbrk;      // Bytes to follow
  3087.         else {
  3088.             $length  2*$cbrk;      // Bytes to follow
  3089.         }
  3090.  
  3091.         $header  pack("vv"$record$length);
  3092.         $data    pack("v",  $cbrk);
  3093.  
  3094.         // Append each page break
  3095.         foreach ($breaks as $break{
  3096.             if ($this->_BIFF_version == 0x0600{
  3097.                 $data .= pack("vvv"$break0x00000x00ff);
  3098.             else {
  3099.                 $data .= pack("v"$break);
  3100.             }
  3101.         }
  3102.  
  3103.         $this->_prepend($header.$data);
  3104.     }
  3105.  
  3106.  
  3107.     /**
  3108.     * Write the VERTICALPAGEBREAKS BIFF record.
  3109.     *
  3110.     * @access private
  3111.     */
  3112.     function _storeVbreak()
  3113.     {
  3114.         // Return if the user hasn't specified pagebreaks
  3115.         if (empty($this->_vbreaks)) {
  3116.             return;
  3117.         }
  3118.  
  3119.         // 1000 vertical pagebreaks appears to be an internal Excel 5 limit.
  3120.         // It is slightly higher in Excel 97/200, approx. 1026
  3121.         $breaks array_slice($this->_vbreaks,0,1000);
  3122.  
  3123.         // Sort and filter array of page breaks
  3124.         sort($breaksSORT_NUMERIC);
  3125.         if ($breaks[0== 0// don't use first break if it's 0
  3126.             array_shift($breaks);
  3127.         }
  3128.  
  3129.         $record  0x001a;               // Record identifier
  3130.         $cbrk    count($breaks);       // Number of page breaks
  3131.         if ($this->_BIFF_version == 0x0600{
  3132.             $length  6*$cbrk;      // Bytes to follow
  3133.         else {
  3134.             $length  2*$cbrk;      // Bytes to follow
  3135.         }
  3136.  
  3137.         $header  pack("vv",  $record$length);
  3138.         $data    pack("v",   $cbrk);
  3139.  
  3140.         // Append each page break
  3141.         foreach ($breaks as $break{
  3142.             if ($this->_BIFF_version == 0x0600{
  3143.                 $data .= pack("vvv"$break0x00000xffff);
  3144.             else {
  3145.                 $data .= pack("v"$break);
  3146.             }
  3147.         }
  3148.  
  3149.         $this->_prepend($header $data);
  3150.     }
  3151.  
  3152.     /**
  3153.     * Set the Biff PROTECT record to indicate that the worksheet is protected.
  3154.     *
  3155.     * @access private
  3156.     */
  3157.     function _storeProtect()
  3158.     {
  3159.         // Exit unless sheet protection has been specified
  3160.         if ($this->_protect == 0{
  3161.             return;
  3162.         }
  3163.  
  3164.         $record      0x0012;             // Record identifier
  3165.         $length      0x0002;             // Bytes to follow
  3166.  
  3167.         $fLock       $this->_protect;    // Worksheet is protected
  3168.  
  3169.         $header      pack("vv"$record$length);
  3170.         $data        pack("v",  $fLock);
  3171.  
  3172.         $this->_prepend($header.$data);
  3173.     }
  3174.  
  3175.     /**
  3176.     * Write the worksheet PASSWORD record.
  3177.     *
  3178.     * @access private
  3179.     */
  3180.     function _storePassword()
  3181.     {
  3182.         // Exit unless sheet protection and password have been specified
  3183.         if (($this->_protect == 0|| (!isset($this->_password))) {
  3184.             return;
  3185.         }
  3186.  
  3187.         $record      0x0013;               // Record identifier
  3188.         $length      0x0002;               // Bytes to follow
  3189.  
  3190.         $wPassword   $this->_password;     // Encoded password
  3191.  
  3192.         $header      pack("vv"$record$length);
  3193.         $data        pack("v",  $wPassword);
  3194.  
  3195.         $this->_prepend($header $data);
  3196.     }
  3197.  
  3198.  
  3199.     /**
  3200.     * Insert a 24bit bitmap image in a worksheet.
  3201.     *
  3202.     * @access public
  3203.     * @param integer $row     The row we are going to insert the bitmap into
  3204.     * @param integer $col     The column we are going to insert the bitmap into
  3205.     * @param mixed   $bitmap  The bitmap filename or GD-image resource
  3206.     * @param integer $x       The horizontal position (offset) of the image inside the cell.
  3207.     * @param integer $y       The vertical position (offset) of the image inside the cell.
  3208.     * @param float   $scale_x The horizontal scale
  3209.     * @param float   $scale_y The vertical scale
  3210.     */
  3211.     function insertBitmap($row$col$bitmap$x 0$y 0$scale_x 1$scale_y 1)
  3212.     {
  3213.         $bitmap_array (is_resource($bitmap$this->_processBitmapGd($bitmap$this->_processBitmap($bitmap));
  3214.         list($width$height$size$data$bitmap_array//$this->_processBitmap($bitmap);
  3215.  
  3216.         // Scale the frame of the image.
  3217.         $width  *= $scale_x;
  3218.         $height *= $scale_y;
  3219.  
  3220.         // Calculate the vertices of the image and write the OBJ record
  3221.         $this->_positionImage($col$row$x$y$width$height);
  3222.  
  3223.         // Write the IMDATA record to store the bitmap data
  3224.         $record      0x007f;
  3225.         $length      $size;
  3226.         $cf          0x09;
  3227.         $env         0x01;
  3228.         $lcb         $size;
  3229.  
  3230.         $header      pack("vvvvV"$record$length$cf$env$lcb);
  3231.         $this->_append($header.$data);
  3232.     }
  3233.  
  3234.     /**
  3235.     * Calculate the vertices that define the position of the image as required by
  3236.     * the OBJ record.
  3237.     *
  3238.     *         +------------+------------+
  3239.     *         |     A      |      B     |
  3240.     *   +-----+------------+------------+
  3241.     *   |     |(x1,y1)     |            |
  3242.     *   |  1  |(A1)._______|______      |
  3243.     *   |     |    |              |     |
  3244.     *   |     |    |              |     |
  3245.     *   +-----+----|    BITMAP    |-----+
  3246.     *   |     |    |              |     |
  3247.     *   |  2  |    |______________.     |
  3248.     *   |     |            |        (B2)|
  3249.     *   |     |            |     (x2,y2)|
  3250.     *   +---- +------------+------------+
  3251.     *
  3252.     * Example of a bitmap that covers some of the area from cell A1 to cell B2.
  3253.     *
  3254.     * Based on the width and height of the bitmap we need to calculate 8 vars:
  3255.     *     $col_start, $row_start, $col_end, $row_end, $x1, $y1, $x2, $y2.
  3256.     * The width and height of the cells are also variable and have to be taken into
  3257.     * account.
  3258.     * The values of $col_start and $row_start are passed in from the calling
  3259.     * function. The values of $col_end and $row_end are calculated by subtracting
  3260.     * the width and height of the bitmap from the width and height of the
  3261.     * underlying cells.
  3262.     * The vertices are expressed as a percentage of the underlying cell width as
  3263.     * follows (rhs values are in pixels):
  3264.     *
  3265.     *       x1 = X / W *1024
  3266.     *       y1 = Y / H *256
  3267.     *       x2 = (X-1) / W *1024
  3268.     *       y2 = (Y-1) / H *256
  3269.     *
  3270.     *       Where:  X is distance from the left side of the underlying cell
  3271.     *               Y is distance from the top of the underlying cell
  3272.     *               W is the width of the cell
  3273.     *               H is the height of the cell
  3274.     *
  3275.     * @access private
  3276.     * @note  the SDK incorrectly states that the height should be expressed as a
  3277.     *         percentage of 1024.
  3278.     * @param integer $col_start Col containing upper left corner of object
  3279.     * @param integer $row_start Row containing top left corner of object
  3280.     * @param integer $x1        Distance to left side of object
  3281.     * @param integer $y1        Distance to top of object
  3282.     * @param integer $width     Width of image frame
  3283.     * @param integer $height    Height of image frame
  3284.     */
  3285.     function _positionImage($col_start$row_start$x1$y1$width$height)
  3286.     {
  3287.         // Initialise end cell to the same as the start cell
  3288.         $col_end    $col_start;  // Col containing lower right corner of object
  3289.         $row_end    $row_start;  // Row containing bottom right corner of object
  3290.  
  3291.         // Zero the specified offset if greater than the cell dimensions
  3292.         if ($x1 >= $this->_sizeCol($col_start)) {
  3293.             $x1 0;
  3294.         }
  3295.         if ($y1 >= $this->_sizeRow($row_start)) {
  3296.             $y1 0;
  3297.         }
  3298.  
  3299.         $width      $width  $x1 -1;
  3300.         $height     $height $y1 -1;
  3301.  
  3302.         // Subtract the underlying cell widths to find the end cell of the image
  3303.         while ($width >= $this->_sizeCol($col_end)) {
  3304.             $width -= $this->_sizeCol($col_end);
  3305.             ++$col_end;
  3306.         }
  3307.  
  3308.         // Subtract the underlying cell heights to find the end cell of the image
  3309.         while ($height >= $this->_sizeRow($row_end)) {
  3310.             $height -= $this->_sizeRow($row_end);
  3311.             ++$row_end;
  3312.         }
  3313.  
  3314.         // Bitmap isn't allowed to start or finish in a hidden cell, i.e. a cell
  3315.         // with zero eight or width.
  3316.         //
  3317.         if ($this->_sizeCol($col_start== 0{
  3318.             return;
  3319.         }
  3320.         if ($this->_sizeCol($col_end)   == 0{
  3321.             return;
  3322.         }
  3323.         if ($this->_sizeRow($row_start== 0{
  3324.             return;
  3325.         }
  3326.         if ($this->_sizeRow($row_end)   == 0{
  3327.             return;
  3328.         }
  3329.  
  3330.         // Convert the pixel values to the percentage value expected by Excel
  3331.         $x1 $x1     $this->_sizeCol($col_start)   1024;
  3332.         $y1 $y1     $this->_sizeRow($row_start)   *  256;
  3333.         $x2 $width  $this->_sizeCol($col_end)     1024// Distance to right side of object
  3334.         $y2 $height $this->_sizeRow($row_end)     *  256// Distance to bottom of object
  3335.  
  3336.         $this->_storeObjPicture($col_start$x1,
  3337.                                  $row_start$y1,
  3338.                                  $col_end$x2,
  3339.                                  $row_end$y2);
  3340.     }
  3341.  
  3342.     /**
  3343.     * Convert the width of a cell from user's units to pixels. By interpolation
  3344.     * the relationship is: y = 7x +5. If the width hasn't been set by the user we
  3345.     * use the default value. If the col is hidden we use a value of zero.
  3346.     *
  3347.     * @access private
  3348.     * @param integer $col The column
  3349.     * @return integer The width in pixels
  3350.     */
  3351.     function _sizeCol($col)
  3352.     {
  3353.         // Look up the cell value to see if it has been changed
  3354.         if (isset($this->col_sizes[$col])) {
  3355.             if ($this->col_sizes[$col== 0{
  3356.                 return(0);
  3357.             else {
  3358.                 return(floor($this->col_sizes[$col5));
  3359.             }
  3360.         else {
  3361.             return(64);
  3362.         }
  3363.     }
  3364.  
  3365.     /**
  3366.     * Convert the height of a cell from user's units to pixels. By interpolation
  3367.     * the relationship is: y = 4/3x. If the height hasn't been set by the user we
  3368.     * use the default value. If the row is hidden we use a value of zero. (Not
  3369.     * possible to hide row yet).
  3370.     *
  3371.     * @access private
  3372.     * @param integer $row The row
  3373.     * @return integer The width in pixels
  3374.     */
  3375.     function _sizeRow($row)
  3376.     {
  3377.         // Look up the cell value to see if it has been changed
  3378.         if (isset($this->_row_sizes[$row])) {
  3379.             if ($this->_row_sizes[$row== 0{
  3380.                 return(0);
  3381.             else {
  3382.                 return(floor(4/$this->_row_sizes[$row]));
  3383.             }
  3384.         else {
  3385.             return(17);
  3386.         }
  3387.     }
  3388.  
  3389.     /**
  3390.     * Store the OBJ record that precedes an IMDATA record. This could be generalise
  3391.     * to support other Excel objects.
  3392.     *
  3393.     * @access private
  3394.     * @param integer $colL Column containing upper left corner of object
  3395.     * @param integer $dxL  Distance from left side of cell
  3396.     * @param integer $rwT  Row containing top left corner of object
  3397.     * @param integer $dyT  Distance from top of cell
  3398.     * @param integer $colR Column containing lower right corner of object
  3399.     * @param integer $dxR  Distance from right of cell
  3400.     * @param integer $rwB  Row containing bottom right corner of object
  3401.     * @param integer $dyB  Distance from bottom of cell
  3402.     */
  3403.     function _storeObjPicture($colL,$dxL,$rwT,$dyT,$colR,$dxR,$rwB,$dyB)
  3404.     {
  3405.         $record      0x005d;   // Record identifier
  3406.         $length      0x003c;   // Bytes to follow
  3407.  
  3408.         $cObj        0x0001;   // Count of objects in file (set to 1)
  3409.         $OT          0x0008;   // Object type. 8 = Picture
  3410.         $id          0x0001;   // Object ID
  3411.         $grbit       0x0614;   // Option flags
  3412.  
  3413.         $cbMacro     0x0000;   // Length of FMLA structure
  3414.         $Reserved1   0x0000;   // Reserved
  3415.         $Reserved2   0x0000;   // Reserved
  3416.  
  3417.         $icvBack     0x09;     // Background colour
  3418.         $icvFore     0x09;     // Foreground colour
  3419.         $fls         0x00;     // Fill pattern
  3420.         $fAuto       0x00;     // Automatic fill
  3421.         $icv         0x08;     // Line colour
  3422.         $lns         0xff;     // Line style
  3423.         $lnw         0x01;     // Line weight
  3424.         $fAutoB      0x00;     // Automatic border
  3425.         $frs         0x0000;   // Frame style
  3426.         $cf          0x0009;   // Image format, 9 = bitmap
  3427.         $Reserved3   0x0000;   // Reserved
  3428.         $cbPictFmla  0x0000;   // Length of FMLA structure
  3429.         $Reserved4   0x0000;   // Reserved
  3430.         $grbit2      0x0001;   // Option flags
  3431.         $Reserved5   0x0000;   // Reserved
  3432.  
  3433.  
  3434.         $header      pack("vv"$record$length);
  3435.         $data        pack("V"$cObj);
  3436.         $data       .= pack("v"$OT);
  3437.         $data       .= pack("v"$id);
  3438.         $data       .= pack("v"$grbit);
  3439.         $data       .= pack("v"$colL);
  3440.         $data       .= pack("v"$dxL);
  3441.         $data       .= pack("v"$rwT);
  3442.         $data       .= pack("v"$dyT);
  3443.         $data       .= pack("v"$colR);
  3444.         $data       .= pack("v"$dxR);
  3445.         $data       .= pack("v"$rwB);
  3446.         $data       .= pack("v"$dyB);
  3447.         $data       .= pack("v"$cbMacro);
  3448.         $data       .= pack("V"$Reserved1);
  3449.         $data       .= pack("v"$Reserved2);
  3450.         $data       .= pack("C"$icvBack);
  3451.         $data       .= pack("C"$icvFore);
  3452.         $data       .= pack("C"$fls);
  3453.         $data       .= pack("C"$fAuto);
  3454.         $data       .= pack("C"$icv);
  3455.         $data       .= pack("C"$lns);
  3456.         $data       .= pack("C"$lnw);
  3457.         $data       .= pack("C"$fAutoB);
  3458.         $data       .= pack("v"$frs);
  3459.         $data       .= pack("V"$cf);
  3460.         $data       .= pack("v"$Reserved3);
  3461.         $data       .= pack("v"$cbPictFmla);
  3462.         $data       .= pack("v"$Reserved4);
  3463.         $data       .= pack("v"$grbit2);
  3464.         $data       .= pack("V"$Reserved5);
  3465.  
  3466.         $this->_append($header $data);
  3467.     }
  3468.  
  3469.     /**
  3470.     * Convert a GD-image into the internal format.
  3471.     *
  3472.     * @access private
  3473.     * @param resource $image The image to process
  3474.     * @return array Array with data and properties of the bitmap
  3475.     */
  3476.     function _processBitmapGd($image{
  3477.         $width imagesx($image);
  3478.         $height imagesy($image);
  3479.  
  3480.         $data pack("Vvvvv"0x000c$width$height0x010x18);
  3481.         for ($j=$height$j--{
  3482.             for ($i=0$i $width++$i{
  3483.                 $color imagecolorsforindex($imageimagecolorat($image$i$j));
  3484.                 foreach (array("red""green""blue"as $key{
  3485.                     $color[$key$color[$keyround((255 $color[$key]$color["alpha"127);
  3486.                 }
  3487.                 $data .= chr($color["blue"]chr($color["green"]chr($color["red"]);
  3488.             }
  3489.             if (3*$width 4{
  3490.                 $data .= str_repeat("\x00"3*$width 4);
  3491.             }
  3492.         }
  3493.  
  3494.         return array($width$heightstrlen($data)$data);
  3495.     }
  3496.  
  3497.     /**
  3498.     * Convert a 24 bit bitmap into the modified internal format used by Windows.
  3499.     * This is described in BITMAPCOREHEADER and BITMAPCOREINFO structures in the
  3500.     * MSDN library.
  3501.     *
  3502.     * @access private
  3503.     * @param string $bitmap The bitmap to process
  3504.     * @return array Array with data and properties of the bitmap
  3505.     */
  3506.     function _processBitmap($bitmap)
  3507.     {
  3508.         // Open file.
  3509.         $bmp_fd @fopen($bitmap,"rb");
  3510.         if (!$bmp_fd{
  3511.             throw new Exception("Couldn't import $bitmap");
  3512.         }
  3513.  
  3514.         // Slurp the file into a string.
  3515.         $data fread($bmp_fdfilesize($bitmap));
  3516.  
  3517.         // Check that the file is big enough to be a bitmap.
  3518.         if (strlen($data<= 0x36{
  3519.             throw new Exception("$bitmap doesn't contain enough data.\n");
  3520.         }
  3521.  
  3522.         // The first 2 bytes are used to identify the bitmap.
  3523.         $identity unpack("A2ident"$data);
  3524.         if ($identity['ident'!= "BM"{
  3525.             throw new Exception("$bitmap doesn't appear to be a valid bitmap image.\n");
  3526.         }
  3527.  
  3528.         // Remove bitmap data: ID.
  3529.         $data substr($data2);
  3530.  
  3531.         // Read and remove the bitmap size. This is more reliable than reading
  3532.         // the data size at offset 0x22.
  3533.         //
  3534.         $size_array   unpack("Vsa"substr($data04));
  3535.         $size   $size_array['sa'];
  3536.         $data   substr($data4);
  3537.         $size  -= 0x36// Subtract size of bitmap header.
  3538.         $size  += 0x0C// Add size of BIFF header.
  3539.  
  3540.         // Remove bitmap data: reserved, offset, header length.
  3541.         $data substr($data12);
  3542.  
  3543.         // Read and remove the bitmap width and height. Verify the sizes.
  3544.         $width_and_height unpack("V2"substr($data08));
  3545.         $width  $width_and_height[1];
  3546.         $height $width_and_height[2];
  3547.         $data   substr($data8);
  3548.         if ($width 0xFFFF{
  3549.             throw new Exception("$bitmap: largest image width supported is 65k.\n");
  3550.         }
  3551.         if ($height 0xFFFF{
  3552.             throw new Exception("$bitmap: largest image height supported is 65k.\n");
  3553.         }
  3554.  
  3555.         // Read and remove the bitmap planes and bpp data. Verify them.
  3556.         $planes_and_bitcount unpack("v2"substr($data04));
  3557.         $data substr($data4);
  3558.         if ($planes_and_bitcount[2!= 24// Bitcount
  3559.             throw new Exception("$bitmap isn't a 24bit true color bitmap.\n");
  3560.         }
  3561.         if ($planes_and_bitcount[1!= 1{
  3562.             throw new Exception("$bitmap: only 1 plane supported in bitmap image.\n");
  3563.         }
  3564.  
  3565.         // Read and remove the bitmap compression. Verify compression.
  3566.         $compression unpack("Vcomp"substr($data04));
  3567.         $data substr($data4);
  3568.  
  3569.         //$compression = 0;
  3570.         if ($compression['comp'!= 0{
  3571.             throw new Exception("$bitmap: compression not supported in bitmap image.\n");
  3572.         }
  3573.  
  3574.         // Remove bitmap data: data size, hres, vres, colours, imp. colours.
  3575.         $data substr($data20);
  3576.  
  3577.         // Add the BITMAPCOREHEADER data
  3578.         $header  pack("Vvvvv"0x000c$width$height0x010x18);
  3579.         $data    $header $data;
  3580.  
  3581.         return (array($width$height$size$data));
  3582.     }
  3583.  
  3584.     /**
  3585.     * Store the window zoom factor. This should be a reduced fraction but for
  3586.     * simplicity we will store all fractions with a numerator of 100.
  3587.     *
  3588.     * @access private
  3589.     */
  3590.     function _storeZoom()
  3591.     {
  3592.         // If scale is 100 we don't need to write a record
  3593.         if ($this->_zoom == 100{
  3594.             return;
  3595.         }
  3596.  
  3597.         $record      0x00A0;               // Record identifier
  3598.         $length      0x0004;               // Bytes to follow
  3599.  
  3600.         $header      pack("vv"$record$length);
  3601.         $data        pack("vv"$this->_zoom100);
  3602.         $this->_append($header $data);
  3603.     }
  3604.  
  3605.     /**
  3606.     * Store the DVAL and DV records.
  3607.     *
  3608.     * @access private
  3609.     */
  3610.     function _storeDataValidity()
  3611.     {
  3612.         $record      0x01b2;      // Record identifier
  3613.         $length      0x0012;      // Bytes to follow
  3614.  
  3615.         $grbit       0x0002;      // Prompt box at cell, no cached validity data at DV records
  3616.         $horPos      0x00000000;  // Horizontal position of prompt box, if fixed position
  3617.         $verPos      0x00000000;  // Vertical position of prompt box, if fixed position
  3618.         $objId       0xffffffff;  // Object identifier of drop down arrow object, or -1 if not visible
  3619.  
  3620.         $header      pack('vv'$record$length);
  3621.         $data        pack('vVVVV'$grbit$horPos$verPos$objId,
  3622.                                      count($this->_dv));
  3623.         $this->_append($header.$data);
  3624.  
  3625.         $record 0x01be;              // Record identifier
  3626.         foreach ($this->_dv as $dv{
  3627.             $length strlen($dv);      // Bytes to follow
  3628.             $header pack("vv"$record$length);
  3629.             $this->_append($header $dv);
  3630.         }
  3631.     }
  3632.  
  3633.     /**
  3634.      * Set sheet dimensions
  3635.      *
  3636.      * @param int $firstRowIndex 
  3637.      * @param int $lastRowIndex 
  3638.      * @param int $firstColumnIndex 
  3639.      * @param int $lastColumnIndex 
  3640.      */
  3641.     public function setDimensions($firstRowIndex 0$lastRowIndex = -1$firstColumnIndex 0$lastColumnIndex = -1)
  3642.     {
  3643.         $this->_firstRowIndex = $firstRowIndex;
  3644.         $this->_lastRowIndex = $lastRowIndex;
  3645.         $this->_firstColumnIndex = $firstColumnIndex;
  3646.         $this->_lastColumnIndex = $lastColumnIndex;
  3647.     }
  3648.  
  3649. }

Documentation generated on Mon, 27 Oct 2008 08:42:11 +0100 by phpDocumentor 1.4.1