mirror of
https://github.com/moodle/moodle.git
synced 2025-01-18 05:58:34 +01:00
Merge branch 'w51_MDL-37183_m25_excelcleanup' of git://github.com/skodak/moodle
This commit is contained in:
commit
e801c74c54
@ -1,209 +0,0 @@
|
||||
<?php
|
||||
/*
|
||||
* Module written/ported by Xavier Noguer <xnoguer@rezebra.com>
|
||||
*
|
||||
* The majority of this is _NOT_ my code. I simply ported it from the
|
||||
* PERL Spreadsheet::WriteExcel module.
|
||||
*
|
||||
* The author of the Spreadsheet::WriteExcel module is John McNamara
|
||||
* <jmcnamara@cpan.org>
|
||||
*
|
||||
* I _DO_ maintain this code, and John McNamara has nothing to do with the
|
||||
* porting of this code to PHP. Any questions directly related to this
|
||||
* class library should be directed to me.
|
||||
*
|
||||
* License Information:
|
||||
*
|
||||
* Spreadsheet::WriteExcel: A library for generating Excel Spreadsheets
|
||||
* Copyright (C) 2002 Xavier Noguer xnoguer@rezebra.com
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* Class for writing Excel BIFF records.
|
||||
*
|
||||
* From "MICROSOFT EXCEL BINARY FILE FORMAT" by Mark O'Brien (Microsoft Corporation):
|
||||
*
|
||||
* BIFF (BInary File Format) is the file format in which Excel documents are
|
||||
* saved on disk. A BIFF file is a complete description of an Excel document.
|
||||
* BIFF files consist of sequences of variable-length records. There are many
|
||||
* different types of BIFF records. For example, one record type describes a
|
||||
* formula entered into a cell; one describes the size and location of a
|
||||
* window into a document; another describes a picture format.
|
||||
*
|
||||
* @author Xavier Noguer <xnoguer@rezebra.com>
|
||||
* @package Spreadsheet_WriteExcel
|
||||
*/
|
||||
|
||||
class BIFFWriter
|
||||
{
|
||||
var $_BIFF_version = 0x0500;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @access public
|
||||
*/
|
||||
function BIFFwriter()
|
||||
{
|
||||
// The byte order of this architecture. 0 => little endian, 1 => big endian
|
||||
$this->_byte_order = '';
|
||||
// The string containing the data of the BIFF stream
|
||||
$this->_data = '';
|
||||
// Should be the same as strlen($this->_data)
|
||||
$this->_datasize = 0;
|
||||
// The maximun length for a BIFF record. See _add_continue()
|
||||
$this->_limit = 2080;
|
||||
// Set the byte order
|
||||
$this->_set_byte_order();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the byte order and store it as class data to avoid
|
||||
* recalculating it for each call to new().
|
||||
*
|
||||
* @access private
|
||||
*/
|
||||
function _set_byte_order()
|
||||
{
|
||||
if ($this->_byte_order == '')
|
||||
{
|
||||
// Check if "pack" gives the required IEEE 64bit float
|
||||
$teststr = pack("d", 1.2345);
|
||||
$number = pack("C8", 0x8D, 0x97, 0x6E, 0x12, 0x83, 0xC0, 0xF3, 0x3F);
|
||||
if ($number == $teststr) {
|
||||
$byte_order = 0; // Little Endian
|
||||
}
|
||||
elseif ($number == strrev($teststr)){
|
||||
$byte_order = 1; // Big Endian
|
||||
}
|
||||
else {
|
||||
// Give up. I'll fix this in a later version.
|
||||
die("Required floating point format not supported ".
|
||||
"on this platform. See the portability section ".
|
||||
"of the documentation."
|
||||
);
|
||||
}
|
||||
}
|
||||
$this->_byte_order = $byte_order;
|
||||
}
|
||||
|
||||
/**
|
||||
* General storage function
|
||||
*
|
||||
* @param string $data binary data to prepend
|
||||
* @access private
|
||||
*/
|
||||
function _prepend($data)
|
||||
{
|
||||
if (strlen($data) > $this->_limit) {
|
||||
$data = $this->_add_continue($data);
|
||||
}
|
||||
$this->_data = $data.$this->_data;
|
||||
$this->_datasize += strlen($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* General storage function
|
||||
*
|
||||
* @param string $data binary data to append
|
||||
* @access private
|
||||
*/
|
||||
function _append($data)
|
||||
{
|
||||
if (strlen($data) > $this->_limit) {
|
||||
$data = $this->_add_continue($data);
|
||||
}
|
||||
$this->_data = $this->_data.$data;
|
||||
$this->_datasize += strlen($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes Excel BOF record to indicate the beginning of a stream or
|
||||
* sub-stream in the BIFF file.
|
||||
*
|
||||
* @param integer $type type of BIFF file to write: 0x0005 Workbook, 0x0010 Worksheet.
|
||||
* @access private
|
||||
*/
|
||||
function _store_bof($type)
|
||||
{
|
||||
$record = 0x0809; // Record identifier
|
||||
$length = 0x0008; // Number of bytes to follow
|
||||
$version = $this->_BIFF_version;
|
||||
|
||||
// According to the SDK $build and $year should be set to zero.
|
||||
// However, this throws a warning in Excel 5. So, use these
|
||||
// magic numbers.
|
||||
$build = 0x096C;
|
||||
$year = 0x07C9;
|
||||
|
||||
$header = pack("vv", $record, $length);
|
||||
$data = pack("vvvv", $version, $type, $build, $year);
|
||||
$this->_prepend($header.$data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes Excel EOF record to indicate the end of a BIFF stream.
|
||||
*
|
||||
* @access private
|
||||
*/
|
||||
function _store_eof()
|
||||
{
|
||||
$record = 0x000A; // Record identifier
|
||||
$length = 0x0000; // Number of bytes to follow
|
||||
$header = pack("vv", $record, $length);
|
||||
$this->_append($header);
|
||||
}
|
||||
|
||||
/**
|
||||
* Excel limits the size of BIFF records. In Excel 5 the limit is 2084 bytes. In
|
||||
* Excel 97 the limit is 8228 bytes. Records that are longer than these limits
|
||||
* must be split up into CONTINUE blocks.
|
||||
*
|
||||
* This function takes a long BIFF record and inserts CONTINUE records as
|
||||
* necessary.
|
||||
*
|
||||
* @param string $data The original binary data to be written
|
||||
* @return string A very convenient string of continue blocks
|
||||
* @access private
|
||||
*/
|
||||
function _add_continue($data)
|
||||
{
|
||||
$limit = $this->_limit;
|
||||
$record = 0x003C; // Record identifier
|
||||
|
||||
// The first 2080/8224 bytes remain intact. However, we have to change
|
||||
// the length field of the record.
|
||||
$tmp = substr($data, 0, 2).pack("v", $limit-4).substr($data, 4, $limit - 4);
|
||||
|
||||
$header = pack("vv", $record, $limit); // Headers for continue records
|
||||
|
||||
// Retrieve chunks of 2080/8224 bytes +4 for the header.
|
||||
for($i = $limit; $i < strlen($data) - $limit; $i += $limit)
|
||||
{
|
||||
$tmp .= $header;
|
||||
$tmp .= substr($data, $i, $limit);
|
||||
}
|
||||
|
||||
// Retrieve the last chunk of data
|
||||
$header = pack("vv", $record, strlen($data) - $i);
|
||||
$tmp .= $header;
|
||||
$tmp .= substr($data,$i,strlen($data) - $i);
|
||||
|
||||
return($tmp);
|
||||
}
|
||||
}
|
||||
?>
|
@ -1,637 +0,0 @@
|
||||
<?php
|
||||
/*
|
||||
* Module written/ported by Xavier Noguer <xnoguer@rezebra.com>
|
||||
*
|
||||
* The majority of this is _NOT_ my code. I simply ported it from the
|
||||
* PERL Spreadsheet::WriteExcel module.
|
||||
*
|
||||
* The author of the Spreadsheet::WriteExcel module is John McNamara
|
||||
* <jmcnamara@cpan.org>
|
||||
*
|
||||
* I _DO_ maintain this code, and John McNamara has nothing to do with the
|
||||
* porting of this code to PHP. Any questions directly related to this
|
||||
* class library should be directed to me.
|
||||
*
|
||||
* License Information:
|
||||
*
|
||||
* Spreadsheet::WriteExcel: A library for generating Excel Spreadsheets
|
||||
* Copyright (C) 2002 Xavier Noguer xnoguer@rezebra.com
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* Class for generating Excel XF records (formats)
|
||||
*
|
||||
* @author Xavier Noguer <xnoguer@rezebra.com>
|
||||
* @package Spreadsheet_WriteExcel
|
||||
*/
|
||||
|
||||
class Format
|
||||
{
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @access public
|
||||
* @param integer $index the XF index for the format.
|
||||
* @param array $properties array with properties to be set on initialization.
|
||||
*/
|
||||
function Format($index = 0,$properties = array())
|
||||
{
|
||||
$this->xf_index = $index;
|
||||
|
||||
$this->font_index = 0;
|
||||
$this->font = 'Arial';
|
||||
$this->size = 10;
|
||||
$this->bold = 0x0190;
|
||||
$this->_italic = 0;
|
||||
$this->color = 0x7FFF;
|
||||
$this->_underline = 0;
|
||||
$this->font_strikeout = 0;
|
||||
$this->font_outline = 0;
|
||||
$this->font_shadow = 0;
|
||||
$this->font_script = 0;
|
||||
$this->font_family = 0;
|
||||
$this->font_charset = 0;
|
||||
|
||||
$this->_num_format = 0;
|
||||
|
||||
$this->hidden = 0;
|
||||
$this->locked = 1;
|
||||
|
||||
$this->_text_h_align = 0;
|
||||
$this->_text_wrap = 0;
|
||||
$this->text_v_align = 2;
|
||||
$this->text_justlast = 0;
|
||||
$this->rotation = 0;
|
||||
|
||||
$this->fg_color = 0x40;
|
||||
$this->bg_color = 0x41;
|
||||
|
||||
$this->pattern = 0;
|
||||
|
||||
$this->bottom = 0;
|
||||
$this->top = 0;
|
||||
$this->left = 0;
|
||||
$this->right = 0;
|
||||
|
||||
$this->bottom_color = 0x40;
|
||||
$this->top_color = 0x40;
|
||||
$this->left_color = 0x40;
|
||||
$this->right_color = 0x40;
|
||||
|
||||
// Set properties passed to Workbook::add_format()
|
||||
foreach($properties as $property => $value)
|
||||
{
|
||||
if(method_exists($this,"set_$property"))
|
||||
{
|
||||
$aux = 'set_'.$property;
|
||||
$this->$aux($value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate an Excel BIFF XF record (style or cell).
|
||||
*
|
||||
* @param string $style The type of the XF record ('style' or 'cell').
|
||||
* @return string The XF record
|
||||
*/
|
||||
function get_xf($style)
|
||||
{
|
||||
// Set the type of the XF record and some of the attributes.
|
||||
if ($style == "style") {
|
||||
$style = 0xFFF5;
|
||||
}
|
||||
else {
|
||||
$style = $this->locked;
|
||||
$style |= $this->hidden << 1;
|
||||
}
|
||||
|
||||
// Flags to indicate if attributes have been set.
|
||||
$atr_num = ($this->_num_format != 0)?1:0;
|
||||
$atr_fnt = ($this->font_index != 0)?1:0;
|
||||
$atr_alc = ($this->_text_wrap)?1:0;
|
||||
$atr_bdr = ($this->bottom ||
|
||||
$this->top ||
|
||||
$this->left ||
|
||||
$this->right)?1:0;
|
||||
$atr_pat = (($this->fg_color != 0x40) ||
|
||||
($this->bg_color != 0x41) ||
|
||||
$this->pattern)?1:0;
|
||||
$atr_prot = 0;
|
||||
|
||||
// Zero the default border colour if the border has not been set.
|
||||
if ($this->bottom == 0) {
|
||||
$this->bottom_color = 0;
|
||||
}
|
||||
if ($this->top == 0) {
|
||||
$this->top_color = 0;
|
||||
}
|
||||
if ($this->right == 0) {
|
||||
$this->right_color = 0;
|
||||
}
|
||||
if ($this->left == 0) {
|
||||
$this->left_color = 0;
|
||||
}
|
||||
|
||||
$record = 0x00E0; // Record identifier
|
||||
$length = 0x0010; // Number of bytes to follow
|
||||
|
||||
$ifnt = $this->font_index; // Index to FONT record
|
||||
$ifmt = $this->_num_format; // Index to FORMAT record
|
||||
|
||||
$align = $this->_text_h_align; // Alignment
|
||||
$align |= $this->_text_wrap << 3;
|
||||
$align |= $this->text_v_align << 4;
|
||||
$align |= $this->text_justlast << 7;
|
||||
$align |= $this->rotation << 8;
|
||||
$align |= $atr_num << 10;
|
||||
$align |= $atr_fnt << 11;
|
||||
$align |= $atr_alc << 12;
|
||||
$align |= $atr_bdr << 13;
|
||||
$align |= $atr_pat << 14;
|
||||
$align |= $atr_prot << 15;
|
||||
|
||||
$icv = $this->fg_color; // fg and bg pattern colors
|
||||
$icv |= $this->bg_color << 7;
|
||||
|
||||
$fill = $this->pattern; // Fill and border line style
|
||||
$fill |= $this->bottom << 6;
|
||||
$fill |= $this->bottom_color << 9;
|
||||
|
||||
$border1 = $this->top; // Border line style and color
|
||||
$border1 |= $this->left << 3;
|
||||
$border1 |= $this->right << 6;
|
||||
$border1 |= $this->top_color << 9;
|
||||
|
||||
$border2 = $this->left_color; // Border color
|
||||
$border2 |= $this->right_color << 7;
|
||||
|
||||
$header = pack("vv", $record, $length);
|
||||
$data = pack("vvvvvvvv", $ifnt, $ifmt, $style, $align,
|
||||
$icv, $fill,
|
||||
$border1, $border2);
|
||||
return($header.$data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate an Excel BIFF FONT record.
|
||||
*
|
||||
* @see Workbook::_store_all_fonts()
|
||||
* @return string The FONT record
|
||||
*/
|
||||
function get_font()
|
||||
{
|
||||
$dyHeight = $this->size * 20; // Height of font (1/20 of a point)
|
||||
$icv = $this->color; // Index to color palette
|
||||
$bls = $this->bold; // Bold style
|
||||
$sss = $this->font_script; // Superscript/subscript
|
||||
$uls = $this->_underline; // Underline
|
||||
$bFamily = $this->font_family; // Font family
|
||||
$bCharSet = $this->font_charset; // Character set
|
||||
$rgch = $this->font; // Font name
|
||||
|
||||
$cch = strlen($rgch); // Length of font name
|
||||
$record = 0x31; // Record identifier
|
||||
$length = 0x0F + $cch; // Record length
|
||||
$reserved = 0x00; // Reserved
|
||||
$grbit = 0x00; // Font attributes
|
||||
if ($this->_italic) {
|
||||
$grbit |= 0x02;
|
||||
}
|
||||
if ($this->font_strikeout) {
|
||||
$grbit |= 0x08;
|
||||
}
|
||||
if ($this->font_outline) {
|
||||
$grbit |= 0x10;
|
||||
}
|
||||
if ($this->font_shadow) {
|
||||
$grbit |= 0x20;
|
||||
}
|
||||
|
||||
$header = pack("vv", $record, $length);
|
||||
$data = pack("vvvvvCCCCC", $dyHeight, $grbit, $icv, $bls,
|
||||
$sss, $uls, $bFamily,
|
||||
$bCharSet, $reserved, $cch);
|
||||
return($header . $data. $this->font);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a unique hash key for a font. Used by Workbook->_store_all_fonts()
|
||||
*
|
||||
* The elements that form the key are arranged to increase the probability of
|
||||
* generating a unique key. Elements that hold a large range of numbers
|
||||
* (eg. _color) are placed between two binary elements such as _italic
|
||||
*
|
||||
* @return string A key for this font
|
||||
*/
|
||||
function get_font_key()
|
||||
{
|
||||
$key = "$this->font$this->size";
|
||||
$key .= "$this->font_script$this->_underline";
|
||||
$key .= "$this->font_strikeout$this->bold$this->font_outline";
|
||||
$key .= "$this->font_family$this->font_charset";
|
||||
$key .= "$this->font_shadow$this->color$this->_italic";
|
||||
$key = str_replace(" ","_",$key);
|
||||
return ($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the index used by Worksheet->_XF()
|
||||
*
|
||||
* @return integer The index for the XF record
|
||||
*/
|
||||
function get_xf_index()
|
||||
{
|
||||
return($this->xf_index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Used in conjunction with the set_xxx_color methods to convert a color
|
||||
* string into a number. Color range is 0..63 but we will restrict it
|
||||
* to 8..63 to comply with Gnumeric. Colors 0..7 are repeated in 8..15.
|
||||
*
|
||||
* @param string $name_color name of the color (i.e.: 'blue', 'red', etc..). Optional.
|
||||
* @return integer The color index
|
||||
*/
|
||||
function _get_color($name_color = '')
|
||||
{
|
||||
$colors = array(
|
||||
'aqua' => 0x0F,
|
||||
'cyan' => 0x0F,
|
||||
'black' => 0x08,
|
||||
'blue' => 0x0C,
|
||||
'brown' => 0x10,
|
||||
'magenta' => 0x0E,
|
||||
'fuchsia' => 0x0E,
|
||||
'gray' => 0x17,
|
||||
'grey' => 0x17,
|
||||
'green' => 0x11,
|
||||
'lime' => 0x0B,
|
||||
'navy' => 0x12,
|
||||
'orange' => 0x35,
|
||||
'purple' => 0x14,
|
||||
'red' => 0x0A,
|
||||
'silver' => 0x16,
|
||||
'white' => 0x09,
|
||||
'yellow' => 0x0D
|
||||
);
|
||||
|
||||
// Return the default color, 0x7FFF, if undef,
|
||||
if($name_color == '') {
|
||||
return(0x7FFF);
|
||||
}
|
||||
|
||||
// or the color string converted to an integer,
|
||||
if(isset($colors[$name_color])) {
|
||||
return($colors[$name_color]);
|
||||
}
|
||||
|
||||
// or the default color if string is unrecognised,
|
||||
if(preg_match("/\D/",$name_color)) {
|
||||
return(0x7FFF);
|
||||
}
|
||||
|
||||
// or an index < 8 mapped into the correct range,
|
||||
if($name_color < 8) {
|
||||
return($name_color + 8);
|
||||
}
|
||||
|
||||
// or the default color if arg is outside range,
|
||||
if($name_color > 63) {
|
||||
return(0x7FFF);
|
||||
}
|
||||
|
||||
// or an integer in the valid range
|
||||
return($name_color);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set cell alignment.
|
||||
*
|
||||
* @access public
|
||||
* @param string $location alignment for the cell ('left', 'right', etc...).
|
||||
*/
|
||||
function set_align($location)
|
||||
{
|
||||
if (preg_match("/\d/",$location)) {
|
||||
return; // Ignore numbers
|
||||
}
|
||||
|
||||
$location = strtolower($location);
|
||||
|
||||
if ($location == 'left')
|
||||
$this->_text_h_align = 1;
|
||||
if ($location == 'centre')
|
||||
$this->_text_h_align = 2;
|
||||
if ($location == 'center')
|
||||
$this->_text_h_align = 2;
|
||||
if ($location == 'right')
|
||||
$this->_text_h_align = 3;
|
||||
if ($location == 'fill')
|
||||
$this->_text_h_align = 4;
|
||||
if ($location == 'justify')
|
||||
$this->_text_h_align = 5;
|
||||
if ($location == 'merge')
|
||||
$this->_text_h_align = 6;
|
||||
if ($location == 'equal_space') // For T.K.
|
||||
$this->_text_h_align = 7;
|
||||
if ($location == 'top')
|
||||
$this->text_v_align = 0;
|
||||
if ($location == 'vcentre')
|
||||
$this->text_v_align = 1;
|
||||
if ($location == 'vcenter')
|
||||
$this->text_v_align = 1;
|
||||
if ($location == 'bottom')
|
||||
$this->text_v_align = 2;
|
||||
if ($location == 'vjustify')
|
||||
$this->text_v_align = 3;
|
||||
if ($location == 'vequal_space') // For T.K.
|
||||
$this->text_v_align = 4;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is an alias for the unintuitive set_align('merge')
|
||||
*
|
||||
* @access public
|
||||
*/
|
||||
function set_merge()
|
||||
{
|
||||
$this->set_align('merge');
|
||||
}
|
||||
|
||||
/**
|
||||
* Bold has a range 0x64..0x3E8.
|
||||
* 0x190 is normal. 0x2BC is bold.
|
||||
*
|
||||
* @access public
|
||||
* @param integer $weight Weight for the text, 0 maps to 0x190, 1 maps to 0x2BC.
|
||||
It's Optional, default is 1 (bold).
|
||||
*/
|
||||
function set_bold($weight = 1)
|
||||
{
|
||||
if($weight == 1) {
|
||||
$weight = 0x2BC; // Bold text
|
||||
}
|
||||
if($weight == 0) {
|
||||
$weight = 0x190; // Normal text
|
||||
}
|
||||
if($weight < 0x064) {
|
||||
$weight = 0x190; // Lower bound
|
||||
}
|
||||
if($weight > 0x3E8) {
|
||||
$weight = 0x190; // Upper bound
|
||||
}
|
||||
$this->bold = $weight;
|
||||
}
|
||||
|
||||
|
||||
/************************************
|
||||
* FUNCTIONS FOR SETTING CELLS BORDERS
|
||||
*/
|
||||
|
||||
/**
|
||||
* Sets the bottom border of the cell
|
||||
*
|
||||
* @access public
|
||||
* @param integer $style style of the cell border. 1 => thin, 2 => thick.
|
||||
*/
|
||||
function set_bottom($style)
|
||||
{
|
||||
$this->bottom = $style;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the top border of the cell
|
||||
*
|
||||
* @access public
|
||||
* @param integer $style style of the cell top border. 1 => thin, 2 => thick.
|
||||
*/
|
||||
function set_top($style)
|
||||
{
|
||||
$this->top = $style;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the left border of the cell
|
||||
*
|
||||
* @access public
|
||||
* @param integer $style style of the cell left border. 1 => thin, 2 => thick.
|
||||
*/
|
||||
function set_left($style)
|
||||
{
|
||||
$this->left = $style;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the right border of the cell
|
||||
*
|
||||
* @access public
|
||||
* @param integer $style style of the cell right border. 1 => thin, 2 => thick.
|
||||
*/
|
||||
function set_right($style)
|
||||
{
|
||||
$this->right = $style;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set cells borders to the same style
|
||||
*
|
||||
* @access public
|
||||
* @param integer $style style to apply for all cell borders. 1 => thin, 2 => thick.
|
||||
*/
|
||||
function set_border($style)
|
||||
{
|
||||
$this->set_bottom($style);
|
||||
$this->set_top($style);
|
||||
$this->set_left($style);
|
||||
$this->set_right($style);
|
||||
}
|
||||
|
||||
|
||||
/*******************************************
|
||||
* FUNCTIONS FOR SETTING CELLS BORDERS COLORS
|
||||
*/
|
||||
|
||||
/**
|
||||
* Sets all the cell's borders to the same color
|
||||
*
|
||||
* @access public
|
||||
* @param mixed $color The color we are setting. Either a string (like 'blue'),
|
||||
* or an integer (like 0x41).
|
||||
*/
|
||||
function set_border_color($color)
|
||||
{
|
||||
$this->set_bottom_color($color);
|
||||
$this->set_top_color($color);
|
||||
$this->set_left_color($color);
|
||||
$this->set_right_color($color);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the cell's bottom border color
|
||||
*
|
||||
* @access public
|
||||
* @param mixed $color either a string (like 'blue'), or an integer (range is [8...63]).
|
||||
*/
|
||||
function set_bottom_color($color)
|
||||
{
|
||||
$value = $this->_get_color($color);
|
||||
$this->bottom_color = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the cell's top border color
|
||||
*
|
||||
* @access public
|
||||
* @param mixed $color either a string (like 'blue'), or an integer (range is [8...63]).
|
||||
*/
|
||||
function set_top_color($color)
|
||||
{
|
||||
$value = $this->_get_color($color);
|
||||
$this->top_color = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the cell's left border color
|
||||
*
|
||||
* @access public
|
||||
* @param mixed $color either a string (like 'blue'), or an integer (like 0x41).
|
||||
*/
|
||||
function set_left_color($color)
|
||||
{
|
||||
$value = $this->_get_color($color);
|
||||
$this->left_color = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the cell's right border color
|
||||
*
|
||||
* @access public
|
||||
* @param mixed $color either a string (like 'blue'), or an integer (like 0x41).
|
||||
*/
|
||||
function set_right_color($color)
|
||||
{
|
||||
$value = $this->_get_color($color);
|
||||
$this->right_color = $value;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets the cell's foreground color
|
||||
*
|
||||
* @access public
|
||||
* @param mixed $color either a string (like 'blue'), or an integer (like 0x41).
|
||||
*/
|
||||
function set_fg_color($color)
|
||||
{
|
||||
$value = $this->_get_color($color);
|
||||
$this->fg_color = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the cell's background color
|
||||
*
|
||||
* @access public
|
||||
* @param mixed $color either a string (like 'blue'), or an integer (like 0x41).
|
||||
*/
|
||||
function set_bg_color($color)
|
||||
{
|
||||
$value = $this->_get_color($color);
|
||||
$this->bg_color = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the cell's color
|
||||
*
|
||||
* @access public
|
||||
* @param mixed $color either a string (like 'blue'), or an integer (like 0x41).
|
||||
*/
|
||||
function set_color($color)
|
||||
{
|
||||
$value = $this->_get_color($color);
|
||||
$this->color = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the pattern attribute of a cell
|
||||
*
|
||||
* @access public
|
||||
* @param integer $arg Optional. Defaults to 1.
|
||||
*/
|
||||
function set_pattern($arg = 1)
|
||||
{
|
||||
$this->pattern = $arg;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the underline of the text
|
||||
*
|
||||
* @access public
|
||||
* @param integer $underline The value for underline. Possible values are:
|
||||
* 1 => underline, 2 => double underline.
|
||||
*/
|
||||
function set_underline($underline)
|
||||
{
|
||||
$this->_underline = $underline;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the font style as italic
|
||||
*
|
||||
* @access public
|
||||
*/
|
||||
function set_italic()
|
||||
{
|
||||
$this->_italic = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the font size
|
||||
*
|
||||
* @access public
|
||||
* @param integer $size The font size (in pixels I think).
|
||||
*/
|
||||
function set_size($size)
|
||||
{
|
||||
$this->size = $size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the num format
|
||||
*
|
||||
* @access public
|
||||
* @param integer $num_format The num format.
|
||||
*/
|
||||
function set_num_format($num_format)
|
||||
{
|
||||
$this->_num_format = $num_format;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets text wrapping
|
||||
*
|
||||
* @access public
|
||||
* @param integer $text_wrap Optional. 0 => no text wrapping, 1 => text wrapping.
|
||||
* Defaults to 1.
|
||||
*/
|
||||
function set_text_wrap($text_wrap = 1)
|
||||
{
|
||||
$this->_text_wrap = $text_wrap;
|
||||
}
|
||||
}
|
||||
?>
|
@ -1,414 +0,0 @@
|
||||
<?php
|
||||
/*
|
||||
* Module written/ported by Xavier Noguer <xnoguer@rezebra.com>
|
||||
*
|
||||
* The majority of this is _NOT_ my code. I simply ported it from the
|
||||
* PERL Spreadsheet::WriteExcel module.
|
||||
*
|
||||
* The author of the Spreadsheet::WriteExcel module is John McNamara
|
||||
* <jmcnamara@cpan.org>
|
||||
*
|
||||
* I _DO_ maintain this code, and John McNamara has nothing to do with the
|
||||
* porting of this code to PHP. Any questions directly related to this
|
||||
* class library should be directed to me.
|
||||
*
|
||||
* License Information:
|
||||
*
|
||||
* Spreadsheet::WriteExcel: A library for generating Excel Spreadsheets
|
||||
* Copyright (C) 2002 Xavier Noguer xnoguer@rezebra.com
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* Class for creating OLE streams for Excel Spreadsheets
|
||||
*
|
||||
* @author Xavier Noguer <xnoguer@rezebra.com>
|
||||
* @package Spreadsheet_WriteExcel
|
||||
*/
|
||||
class OLEwriter
|
||||
{
|
||||
/**
|
||||
* Filename for the OLE stream
|
||||
* @var string
|
||||
* @see _initialize()
|
||||
*/
|
||||
var $_OLEfilename;
|
||||
|
||||
/**
|
||||
* Filehandle for the OLE stream
|
||||
* @var resource
|
||||
*/
|
||||
var $_filehandle;
|
||||
|
||||
/**
|
||||
* Name of the temporal file in case OLE stream goes to stdout
|
||||
* @var string
|
||||
*/
|
||||
var $_tmp_filename;
|
||||
|
||||
/**
|
||||
* Variable for preventing closing two times
|
||||
* @var integer
|
||||
*/
|
||||
var $_fileclosed;
|
||||
|
||||
/**
|
||||
* Size of the data to be written to the OLE stream
|
||||
* @var integer
|
||||
*/
|
||||
var $_biffsize;
|
||||
|
||||
/**
|
||||
* Real data size to be written to the OLE stream
|
||||
* @var integer
|
||||
*/
|
||||
var $_booksize;
|
||||
|
||||
/**
|
||||
* Number of big blocks in the OLE stream
|
||||
* @var integer
|
||||
*/
|
||||
var $_big_blocks;
|
||||
|
||||
/**
|
||||
* Number of list blocks in the OLE stream
|
||||
* @var integer
|
||||
*/
|
||||
var $_list_blocks;
|
||||
|
||||
/**
|
||||
* Number of big blocks in the OLE stream
|
||||
* @var integer
|
||||
*/
|
||||
var $_root_start;
|
||||
|
||||
/**
|
||||
* Class for creating an OLEwriter
|
||||
*
|
||||
* @param string $OLEfilename the name of the file for the OLE stream
|
||||
*/
|
||||
function OLEwriter($OLEfilename)
|
||||
{
|
||||
$this->_OLEfilename = $OLEfilename;
|
||||
$this->_filehandle = "";
|
||||
$this->_tmp_filename = "";
|
||||
$this->_fileclosed = 0;
|
||||
//$this->_size_allowed = 0;
|
||||
$this->_biffsize = 0;
|
||||
$this->_booksize = 0;
|
||||
$this->_big_blocks = 0;
|
||||
$this->_list_blocks = 0;
|
||||
$this->_root_start = 0;
|
||||
//$this->_block_count = 4;
|
||||
$this->_initialize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for a valid filename and store the filehandle.
|
||||
* Filehandle "-" writes to STDOUT
|
||||
*/
|
||||
function _initialize()
|
||||
{
|
||||
$OLEfile = $this->_OLEfilename;
|
||||
|
||||
if(($OLEfile == '-') or ($OLEfile == ''))
|
||||
{
|
||||
$this->_tmp_filename = tempnam("/tmp", "OLEwriter");
|
||||
$fh = fopen($this->_tmp_filename,"wb");
|
||||
if ($fh == false) {
|
||||
die("Can't create temporary file.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Create a new file, open for writing (in binmode)
|
||||
$fh = fopen($OLEfile,"wb");
|
||||
if ($fh == false) {
|
||||
die("Can't open $OLEfile. It may be in use or protected.");
|
||||
}
|
||||
}
|
||||
|
||||
// Store filehandle
|
||||
$this->_filehandle = $fh;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the size of the data to be written to the OLE stream.
|
||||
* The maximun size comes from this:
|
||||
* $big_blocks = (109 depot block x (128 -1 marker word)
|
||||
* - (1 x end words)) = 13842
|
||||
* $maxsize = $big_blocks * 512 bytes = 7087104
|
||||
*
|
||||
* @access public
|
||||
* @see Workbook::store_OLE_file()
|
||||
* @param integer $biffsize The size of the data to be written to the OLE stream
|
||||
* @return integer 1 for success
|
||||
*/
|
||||
function set_size($biffsize)
|
||||
{
|
||||
$maxsize = 7087104; // TODO: extend max size
|
||||
|
||||
if ($biffsize > $maxsize) {
|
||||
die("Maximum file size, $maxsize, exceeded.");
|
||||
}
|
||||
|
||||
$this->_biffsize = $biffsize;
|
||||
// Set the min file size to 4k to avoid having to use small blocks
|
||||
if ($biffsize > 4096) {
|
||||
$this->_booksize = $biffsize;
|
||||
}
|
||||
else {
|
||||
$this->_booksize = 4096;
|
||||
}
|
||||
//$this->_size_allowed = 1;
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Calculate various sizes needed for the OLE stream
|
||||
*/
|
||||
function _calculate_sizes()
|
||||
{
|
||||
$datasize = $this->_booksize;
|
||||
if ($datasize % 512 == 0) {
|
||||
$this->_big_blocks = $datasize/512;
|
||||
}
|
||||
else {
|
||||
$this->_big_blocks = floor($datasize/512) + 1;
|
||||
}
|
||||
// There are 127 list blocks and 1 marker blocks for each big block
|
||||
// depot + 1 end of chain block
|
||||
$this->_list_blocks = floor(($this->_big_blocks)/127) + 1;
|
||||
$this->_root_start = $this->_big_blocks;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write root entry, big block list and close the filehandle.
|
||||
* This routine is used to explicitly close the open filehandle without
|
||||
* having to wait for DESTROY.
|
||||
*
|
||||
* @access public
|
||||
* @see Workbook::store_OLE_file()
|
||||
*/
|
||||
function close()
|
||||
{
|
||||
//return if not $this->{_size_allowed};
|
||||
$this->_write_padding();
|
||||
$this->_write_property_storage();
|
||||
$this->_write_big_block_depot();
|
||||
// Close the filehandle
|
||||
fclose($this->_filehandle);
|
||||
if(($this->_OLEfilename == '-') or ($this->_OLEfilename == ''))
|
||||
{
|
||||
$fh = fopen($this->_tmp_filename, "rb");
|
||||
if ($fh == false) {
|
||||
die("Can't read temporary file.");
|
||||
}
|
||||
fpassthru($fh);
|
||||
// Delete the temporary file.
|
||||
@unlink($this->_tmp_filename);
|
||||
}
|
||||
$this->_fileclosed = 1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Write BIFF data to OLE file.
|
||||
*
|
||||
* @param string $data string of bytes to be written
|
||||
*/
|
||||
function write($data) //por ahora s<>lo a STDOUT
|
||||
{
|
||||
fwrite($this->_filehandle,$data,strlen($data));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Write OLE header block.
|
||||
*/
|
||||
function write_header()
|
||||
{
|
||||
$this->_calculate_sizes();
|
||||
$root_start = $this->_root_start;
|
||||
$num_lists = $this->_list_blocks;
|
||||
$id = pack("nnnn", 0xD0CF, 0x11E0, 0xA1B1, 0x1AE1);
|
||||
$unknown1 = pack("VVVV", 0x00, 0x00, 0x00, 0x00);
|
||||
$unknown2 = pack("vv", 0x3E, 0x03);
|
||||
$unknown3 = pack("v", -2);
|
||||
$unknown4 = pack("v", 0x09);
|
||||
$unknown5 = pack("VVV", 0x06, 0x00, 0x00);
|
||||
$num_bbd_blocks = pack("V", $num_lists);
|
||||
$root_startblock = pack("V", $root_start);
|
||||
$unknown6 = pack("VV", 0x00, 0x1000);
|
||||
$sbd_startblock = pack("V", -2);
|
||||
$unknown7 = pack("VVV", 0x00, -2 ,0x00);
|
||||
$unused = pack("V", -1);
|
||||
|
||||
fwrite($this->_filehandle,$id);
|
||||
fwrite($this->_filehandle,$unknown1);
|
||||
fwrite($this->_filehandle,$unknown2);
|
||||
fwrite($this->_filehandle,$unknown3);
|
||||
fwrite($this->_filehandle,$unknown4);
|
||||
fwrite($this->_filehandle,$unknown5);
|
||||
fwrite($this->_filehandle,$num_bbd_blocks);
|
||||
fwrite($this->_filehandle,$root_startblock);
|
||||
fwrite($this->_filehandle,$unknown6);
|
||||
fwrite($this->_filehandle,$sbd_startblock);
|
||||
fwrite($this->_filehandle,$unknown7);
|
||||
|
||||
for($i=1; $i <= $num_lists; $i++)
|
||||
{
|
||||
$root_start++;
|
||||
fwrite($this->_filehandle,pack("V",$root_start));
|
||||
}
|
||||
for($i = $num_lists; $i <=108; $i++)
|
||||
{
|
||||
fwrite($this->_filehandle,$unused);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Write big block depot.
|
||||
*/
|
||||
function _write_big_block_depot()
|
||||
{
|
||||
$num_blocks = $this->_big_blocks;
|
||||
$num_lists = $this->_list_blocks;
|
||||
$total_blocks = $num_lists *128;
|
||||
$used_blocks = $num_blocks + $num_lists +2;
|
||||
|
||||
$marker = pack("V", -3);
|
||||
$end_of_chain = pack("V", -2);
|
||||
$unused = pack("V", -1);
|
||||
|
||||
for($i=1; $i < $num_blocks; $i++)
|
||||
{
|
||||
fwrite($this->_filehandle,pack("V",$i));
|
||||
}
|
||||
fwrite($this->_filehandle,$end_of_chain);
|
||||
fwrite($this->_filehandle,$end_of_chain);
|
||||
for($i=0; $i < $num_lists; $i++)
|
||||
{
|
||||
fwrite($this->_filehandle,$marker);
|
||||
}
|
||||
for($i=$used_blocks; $i <= $total_blocks; $i++)
|
||||
{
|
||||
fwrite($this->_filehandle,$unused);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Write property storage. TODO: add summary sheets
|
||||
*/
|
||||
function _write_property_storage()
|
||||
{
|
||||
//$rootsize = -2;
|
||||
/*************** name type dir start size */
|
||||
$this->_write_pps("Root Entry", 0x05, 1, -2, 0x00);
|
||||
$this->_write_pps("Book", 0x02, -1, 0x00, $this->_booksize);
|
||||
$this->_write_pps('', 0x00, -1, 0x00, 0x0000);
|
||||
$this->_write_pps('', 0x00, -1, 0x00, 0x0000);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write property sheet in property storage
|
||||
*
|
||||
* @param string $name name of the property storage.
|
||||
* @param integer $type type of the property storage.
|
||||
* @param integer $dir dir of the property storage.
|
||||
* @param integer $start start of the property storage.
|
||||
* @param integer $size size of the property storage.
|
||||
* @access private
|
||||
*/
|
||||
function _write_pps($name,$type,$dir,$start,$size)
|
||||
{
|
||||
$length = 0;
|
||||
$rawname = '';
|
||||
|
||||
if ($name != '')
|
||||
{
|
||||
$name = $name . "\0";
|
||||
for($i=0;$i<strlen($name);$i++)
|
||||
{
|
||||
// Simulate a Unicode string
|
||||
$rawname .= pack("H*",dechex(ord($name{$i}))).pack("C",0);
|
||||
}
|
||||
$length = strlen($name) * 2;
|
||||
}
|
||||
|
||||
$zero = pack("C", 0);
|
||||
$pps_sizeofname = pack("v", $length); // 0x40
|
||||
$pps_type = pack("v", $type); // 0x42
|
||||
$pps_prev = pack("V", -1); // 0x44
|
||||
$pps_next = pack("V", -1); // 0x48
|
||||
$pps_dir = pack("V", $dir); // 0x4c
|
||||
|
||||
$unknown1 = pack("V", 0);
|
||||
|
||||
$pps_ts1s = pack("V", 0); // 0x64
|
||||
$pps_ts1d = pack("V", 0); // 0x68
|
||||
$pps_ts2s = pack("V", 0); // 0x6c
|
||||
$pps_ts2d = pack("V", 0); // 0x70
|
||||
$pps_sb = pack("V", $start); // 0x74
|
||||
$pps_size = pack("V", $size); // 0x78
|
||||
|
||||
|
||||
fwrite($this->_filehandle,$rawname);
|
||||
for($i=0; $i < (64 -$length); $i++) {
|
||||
fwrite($this->_filehandle,$zero);
|
||||
}
|
||||
fwrite($this->_filehandle,$pps_sizeofname);
|
||||
fwrite($this->_filehandle,$pps_type);
|
||||
fwrite($this->_filehandle,$pps_prev);
|
||||
fwrite($this->_filehandle,$pps_next);
|
||||
fwrite($this->_filehandle,$pps_dir);
|
||||
for($i=0; $i < 5; $i++) {
|
||||
fwrite($this->_filehandle,$unknown1);
|
||||
}
|
||||
fwrite($this->_filehandle,$pps_ts1s);
|
||||
fwrite($this->_filehandle,$pps_ts1d);
|
||||
fwrite($this->_filehandle,$pps_ts2d);
|
||||
fwrite($this->_filehandle,$pps_ts2d);
|
||||
fwrite($this->_filehandle,$pps_sb);
|
||||
fwrite($this->_filehandle,$pps_size);
|
||||
fwrite($this->_filehandle,$unknown1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pad the end of the file
|
||||
*/
|
||||
function _write_padding()
|
||||
{
|
||||
$biffsize = $this->_biffsize;
|
||||
if ($biffsize < 4096) {
|
||||
$min_size = 4096;
|
||||
}
|
||||
else {
|
||||
$min_size = 512;
|
||||
}
|
||||
if ($biffsize % $min_size != 0)
|
||||
{
|
||||
$padding = $min_size - ($biffsize % $min_size);
|
||||
for($i=0; $i < $padding; $i++) {
|
||||
fwrite($this->_filehandle,"\0");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
@ -1,996 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Class for parsing Excel formulas
|
||||
*
|
||||
* License Information:
|
||||
*
|
||||
* Spreadsheet::WriteExcel: A library for generating Excel Spreadsheets
|
||||
* Copyright (C) 2002 Xavier Noguer xnoguer@rezebra.com
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* @const ADD token identifier for character "+"
|
||||
*/
|
||||
define('ADD',"+");
|
||||
|
||||
/**
|
||||
* @const SUB token identifier for character "-"
|
||||
*/
|
||||
define('SUB',"-");
|
||||
|
||||
/**
|
||||
* @const EQUAL token identifier for character "="
|
||||
*/
|
||||
define('EQUAL',"=");
|
||||
|
||||
/**
|
||||
* @const MUL token identifier for character "*"
|
||||
*/
|
||||
define('MUL',"*");
|
||||
|
||||
/**
|
||||
* @const DIV token identifier for character "/"
|
||||
*/
|
||||
define('DIV',"/");
|
||||
|
||||
/**
|
||||
* @const OPEN token identifier for character "("
|
||||
*/
|
||||
define('OPEN',"(");
|
||||
|
||||
/**
|
||||
* @const CLOSE token identifier for character ")"
|
||||
*/
|
||||
define('CLOSE',")");
|
||||
|
||||
/**
|
||||
* @const COMA token identifier for character ","
|
||||
*/
|
||||
define('COMA',",");
|
||||
|
||||
/**
|
||||
* Class for parsing Excel formulas
|
||||
*
|
||||
* @author Xavier Noguer <xnoguer@rezebra.com>
|
||||
* @package Spreadsheet_WriteExcel
|
||||
*/
|
||||
class Parser
|
||||
{
|
||||
/**
|
||||
* The class constructor
|
||||
*
|
||||
* @param integer $byte_order The byte order (Little endian or Big endian) of the architecture
|
||||
(optional). 1 => big endian, 0 (default) => little endian.
|
||||
*/
|
||||
function Parser($byte_order = 0)
|
||||
{
|
||||
$this->_current_char = 0; // The index of the character we are currently looking at.
|
||||
$this->_current_token = ''; // The token we are working on.
|
||||
$this->_formula = ""; // The formula to parse.
|
||||
$this->_lookahead = ''; // The character ahead of the current char.
|
||||
$this->_parse_tree = ''; // The parse tree to be generated.
|
||||
$this->_initialize_hashes(); // Initialize the hashes: ptg's and function's ptg's
|
||||
$this->_byte_order = $byte_order; // Little Endian or Big Endian
|
||||
$this->_func_args = 0; // Number of arguments for the current function
|
||||
$this->_volatile = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the ptg and function hashes.
|
||||
*/
|
||||
function _initialize_hashes()
|
||||
{
|
||||
// The Excel ptg indices
|
||||
$this->ptg = array(
|
||||
'ptgExp' => 0x01,
|
||||
'ptgTbl' => 0x02,
|
||||
'ptgAdd' => 0x03,
|
||||
'ptgSub' => 0x04,
|
||||
'ptgMul' => 0x05,
|
||||
'ptgDiv' => 0x06,
|
||||
'ptgPower' => 0x07,
|
||||
'ptgConcat' => 0x08,
|
||||
'ptgLT' => 0x09,
|
||||
'ptgLE' => 0x0A,
|
||||
'ptgEQ' => 0x0B,
|
||||
'ptgGE' => 0x0C,
|
||||
'ptgGT' => 0x0D,
|
||||
'ptgNE' => 0x0E,
|
||||
'ptgIsect' => 0x0F,
|
||||
'ptgUnion' => 0x10,
|
||||
'ptgRange' => 0x11,
|
||||
'ptgUplus' => 0x12,
|
||||
'ptgUminus' => 0x13,
|
||||
'ptgPercent' => 0x14,
|
||||
'ptgParen' => 0x15,
|
||||
'ptgMissArg' => 0x16,
|
||||
'ptgStr' => 0x17,
|
||||
'ptgAttr' => 0x19,
|
||||
'ptgSheet' => 0x1A,
|
||||
'ptgEndSheet' => 0x1B,
|
||||
'ptgErr' => 0x1C,
|
||||
'ptgBool' => 0x1D,
|
||||
'ptgInt' => 0x1E,
|
||||
'ptgNum' => 0x1F,
|
||||
'ptgArray' => 0x20,
|
||||
'ptgFunc' => 0x21,
|
||||
'ptgFuncVar' => 0x22,
|
||||
'ptgName' => 0x23,
|
||||
'ptgRef' => 0x24,
|
||||
'ptgArea' => 0x25,
|
||||
'ptgMemArea' => 0x26,
|
||||
'ptgMemErr' => 0x27,
|
||||
'ptgMemNoMem' => 0x28,
|
||||
'ptgMemFunc' => 0x29,
|
||||
'ptgRefErr' => 0x2A,
|
||||
'ptgAreaErr' => 0x2B,
|
||||
'ptgRefN' => 0x2C,
|
||||
'ptgAreaN' => 0x2D,
|
||||
'ptgMemAreaN' => 0x2E,
|
||||
'ptgMemNoMemN' => 0x2F,
|
||||
'ptgNameX' => 0x39,
|
||||
'ptgRef3d' => 0x3A,
|
||||
'ptgArea3d' => 0x3B,
|
||||
'ptgRefErr3d' => 0x3C,
|
||||
'ptgAreaErr3d' => 0x3D,
|
||||
'ptgArrayV' => 0x40,
|
||||
'ptgFuncV' => 0x41,
|
||||
'ptgFuncVarV' => 0x42,
|
||||
'ptgNameV' => 0x43,
|
||||
'ptgRefV' => 0x44,
|
||||
'ptgAreaV' => 0x45,
|
||||
'ptgMemAreaV' => 0x46,
|
||||
'ptgMemErrV' => 0x47,
|
||||
'ptgMemNoMemV' => 0x48,
|
||||
'ptgMemFuncV' => 0x49,
|
||||
'ptgRefErrV' => 0x4A,
|
||||
'ptgAreaErrV' => 0x4B,
|
||||
'ptgRefNV' => 0x4C,
|
||||
'ptgAreaNV' => 0x4D,
|
||||
'ptgMemAreaNV' => 0x4E,
|
||||
'ptgMemNoMemN' => 0x4F,
|
||||
'ptgFuncCEV' => 0x58,
|
||||
'ptgNameXV' => 0x59,
|
||||
'ptgRef3dV' => 0x5A,
|
||||
'ptgArea3dV' => 0x5B,
|
||||
'ptgRefErr3dV' => 0x5C,
|
||||
'ptgAreaErr3d' => 0x5D,
|
||||
'ptgArrayA' => 0x60,
|
||||
'ptgFuncA' => 0x61,
|
||||
'ptgFuncVarA' => 0x62,
|
||||
'ptgNameA' => 0x63,
|
||||
'ptgRefA' => 0x64,
|
||||
'ptgAreaA' => 0x65,
|
||||
'ptgMemAreaA' => 0x66,
|
||||
'ptgMemErrA' => 0x67,
|
||||
'ptgMemNoMemA' => 0x68,
|
||||
'ptgMemFuncA' => 0x69,
|
||||
'ptgRefErrA' => 0x6A,
|
||||
'ptgAreaErrA' => 0x6B,
|
||||
'ptgRefNA' => 0x6C,
|
||||
'ptgAreaNA' => 0x6D,
|
||||
'ptgMemAreaNA' => 0x6E,
|
||||
'ptgMemNoMemN' => 0x6F,
|
||||
'ptgFuncCEA' => 0x78,
|
||||
'ptgNameXA' => 0x79,
|
||||
'ptgRef3dA' => 0x7A,
|
||||
'ptgArea3dA' => 0x7B,
|
||||
'ptgRefErr3dA' => 0x7C,
|
||||
'ptgAreaErr3d' => 0x7D
|
||||
);
|
||||
|
||||
// Thanks to Michael Meeks and Gnumeric for the initial arg values.
|
||||
//
|
||||
// The following hash was generated by "function_locale.pl" in the distro.
|
||||
// Refer to function_locale.pl for non-English function names.
|
||||
//
|
||||
// The array elements are as follow:
|
||||
// ptg: The Excel function ptg code.
|
||||
// args: The number of arguments that the function takes:
|
||||
// >=0 is a fixed number of arguments.
|
||||
// -1 is a variable number of arguments.
|
||||
// class: The reference, value or array class of the function args.
|
||||
// vol: The function is volatile.
|
||||
//
|
||||
$this->_functions = array(
|
||||
// function ptg args class vol
|
||||
'COUNT' => array( 0, -1, 0, 0 ),
|
||||
'IF' => array( 1, -1, 1, 0 ),
|
||||
'ISNA' => array( 2, 1, 1, 0 ),
|
||||
'ISERROR' => array( 3, 1, 1, 0 ),
|
||||
'SUM' => array( 4, -1, 0, 0 ),
|
||||
'AVERAGE' => array( 5, -1, 0, 0 ),
|
||||
'MIN' => array( 6, -1, 0, 0 ),
|
||||
'MAX' => array( 7, -1, 0, 0 ),
|
||||
'ROW' => array( 8, -1, 0, 0 ),
|
||||
'COLUMN' => array( 9, -1, 0, 0 ),
|
||||
'NA' => array( 10, 0, 0, 0 ),
|
||||
'NPV' => array( 11, -1, 1, 0 ),
|
||||
'STDEV' => array( 12, -1, 0, 0 ),
|
||||
'DOLLAR' => array( 13, -1, 1, 0 ),
|
||||
'FIXED' => array( 14, -1, 1, 0 ),
|
||||
'SIN' => array( 15, 1, 1, 0 ),
|
||||
'COS' => array( 16, 1, 1, 0 ),
|
||||
'TAN' => array( 17, 1, 1, 0 ),
|
||||
'ATAN' => array( 18, 1, 1, 0 ),
|
||||
'PI' => array( 19, 0, 1, 0 ),
|
||||
'SQRT' => array( 20, 1, 1, 0 ),
|
||||
'EXP' => array( 21, 1, 1, 0 ),
|
||||
'LN' => array( 22, 1, 1, 0 ),
|
||||
'LOG10' => array( 23, 1, 1, 0 ),
|
||||
'ABS' => array( 24, 1, 1, 0 ),
|
||||
'INT' => array( 25, 1, 1, 0 ),
|
||||
'SIGN' => array( 26, 1, 1, 0 ),
|
||||
'ROUND' => array( 27, 2, 1, 0 ),
|
||||
'LOOKUP' => array( 28, -1, 0, 0 ),
|
||||
'INDEX' => array( 29, -1, 0, 1 ),
|
||||
'REPT' => array( 30, 2, 1, 0 ),
|
||||
'MID' => array( 31, 3, 1, 0 ),
|
||||
'LEN' => array( 32, 1, 1, 0 ),
|
||||
'VALUE' => array( 33, 1, 1, 0 ),
|
||||
'TRUE' => array( 34, 0, 1, 0 ),
|
||||
'FALSE' => array( 35, 0, 1, 0 ),
|
||||
'AND' => array( 36, -1, 0, 0 ),
|
||||
'OR' => array( 37, -1, 0, 0 ),
|
||||
'NOT' => array( 38, 1, 1, 0 ),
|
||||
'MOD' => array( 39, 2, 1, 0 ),
|
||||
'DCOUNT' => array( 40, 3, 0, 0 ),
|
||||
'DSUM' => array( 41, 3, 0, 0 ),
|
||||
'DAVERAGE' => array( 42, 3, 0, 0 ),
|
||||
'DMIN' => array( 43, 3, 0, 0 ),
|
||||
'DMAX' => array( 44, 3, 0, 0 ),
|
||||
'DSTDEV' => array( 45, 3, 0, 0 ),
|
||||
'VAR' => array( 46, -1, 0, 0 ),
|
||||
'DVAR' => array( 47, 3, 0, 0 ),
|
||||
'TEXT' => array( 48, 2, 1, 0 ),
|
||||
'LINEST' => array( 49, -1, 0, 0 ),
|
||||
'TREND' => array( 50, -1, 0, 0 ),
|
||||
'LOGEST' => array( 51, -1, 0, 0 ),
|
||||
'GROWTH' => array( 52, -1, 0, 0 ),
|
||||
'PV' => array( 56, -1, 1, 0 ),
|
||||
'FV' => array( 57, -1, 1, 0 ),
|
||||
'NPER' => array( 58, -1, 1, 0 ),
|
||||
'PMT' => array( 59, -1, 1, 0 ),
|
||||
'RATE' => array( 60, -1, 1, 0 ),
|
||||
'MIRR' => array( 61, 3, 0, 0 ),
|
||||
'IRR' => array( 62, -1, 0, 0 ),
|
||||
'RAND' => array( 63, 0, 1, 1 ),
|
||||
'MATCH' => array( 64, -1, 0, 0 ),
|
||||
'DATE' => array( 65, 3, 1, 0 ),
|
||||
'TIME' => array( 66, 3, 1, 0 ),
|
||||
'DAY' => array( 67, 1, 1, 0 ),
|
||||
'MONTH' => array( 68, 1, 1, 0 ),
|
||||
'YEAR' => array( 69, 1, 1, 0 ),
|
||||
'WEEKDAY' => array( 70, -1, 1, 0 ),
|
||||
'HOUR' => array( 71, 1, 1, 0 ),
|
||||
'MINUTE' => array( 72, 1, 1, 0 ),
|
||||
'SECOND' => array( 73, 1, 1, 0 ),
|
||||
'NOW' => array( 74, 0, 1, 1 ),
|
||||
'AREAS' => array( 75, 1, 0, 1 ),
|
||||
'ROWS' => array( 76, 1, 0, 1 ),
|
||||
'COLUMNS' => array( 77, 1, 0, 1 ),
|
||||
'OFFSET' => array( 78, -1, 0, 1 ),
|
||||
'SEARCH' => array( 82, -1, 1, 0 ),
|
||||
'TRANSPOSE' => array( 83, 1, 1, 0 ),
|
||||
'TYPE' => array( 86, 1, 1, 0 ),
|
||||
'ATAN2' => array( 97, 2, 1, 0 ),
|
||||
'ASIN' => array( 98, 1, 1, 0 ),
|
||||
'ACOS' => array( 99, 1, 1, 0 ),
|
||||
'CHOOSE' => array( 100, -1, 1, 0 ),
|
||||
'HLOOKUP' => array( 101, -1, 0, 0 ),
|
||||
'VLOOKUP' => array( 102, -1, 0, 0 ),
|
||||
'ISREF' => array( 105, 1, 0, 0 ),
|
||||
'LOG' => array( 109, -1, 1, 0 ),
|
||||
'CHAR' => array( 111, 1, 1, 0 ),
|
||||
'LOWER' => array( 112, 1, 1, 0 ),
|
||||
'UPPER' => array( 113, 1, 1, 0 ),
|
||||
'PROPER' => array( 114, 1, 1, 0 ),
|
||||
'LEFT' => array( 115, -1, 1, 0 ),
|
||||
'RIGHT' => array( 116, -1, 1, 0 ),
|
||||
'EXACT' => array( 117, 2, 1, 0 ),
|
||||
'TRIM' => array( 118, 1, 1, 0 ),
|
||||
'REPLACE' => array( 119, 4, 1, 0 ),
|
||||
'SUBSTITUTE' => array( 120, -1, 1, 0 ),
|
||||
'CODE' => array( 121, 1, 1, 0 ),
|
||||
'FIND' => array( 124, -1, 1, 0 ),
|
||||
'CELL' => array( 125, -1, 0, 1 ),
|
||||
'ISERR' => array( 126, 1, 1, 0 ),
|
||||
'ISTEXT' => array( 127, 1, 1, 0 ),
|
||||
'ISNUMBER' => array( 128, 1, 1, 0 ),
|
||||
'ISBLANK' => array( 129, 1, 1, 0 ),
|
||||
'T' => array( 130, 1, 0, 0 ),
|
||||
'N' => array( 131, 1, 0, 0 ),
|
||||
'DATEVALUE' => array( 140, 1, 1, 0 ),
|
||||
'TIMEVALUE' => array( 141, 1, 1, 0 ),
|
||||
'SLN' => array( 142, 3, 1, 0 ),
|
||||
'SYD' => array( 143, 4, 1, 0 ),
|
||||
'DDB' => array( 144, -1, 1, 0 ),
|
||||
'INDIRECT' => array( 148, -1, 1, 1 ),
|
||||
'CALL' => array( 150, -1, 1, 0 ),
|
||||
'CLEAN' => array( 162, 1, 1, 0 ),
|
||||
'MDETERM' => array( 163, 1, 2, 0 ),
|
||||
'MINVERSE' => array( 164, 1, 2, 0 ),
|
||||
'MMULT' => array( 165, 2, 2, 0 ),
|
||||
'IPMT' => array( 167, -1, 1, 0 ),
|
||||
'PPMT' => array( 168, -1, 1, 0 ),
|
||||
'COUNTA' => array( 169, -1, 0, 0 ),
|
||||
'PRODUCT' => array( 183, -1, 0, 0 ),
|
||||
'FACT' => array( 184, 1, 1, 0 ),
|
||||
'DPRODUCT' => array( 189, 3, 0, 0 ),
|
||||
'ISNONTEXT' => array( 190, 1, 1, 0 ),
|
||||
'STDEVP' => array( 193, -1, 0, 0 ),
|
||||
'VARP' => array( 194, -1, 0, 0 ),
|
||||
'DSTDEVP' => array( 195, 3, 0, 0 ),
|
||||
'DVARP' => array( 196, 3, 0, 0 ),
|
||||
'TRUNC' => array( 197, -1, 1, 0 ),
|
||||
'ISLOGICAL' => array( 198, 1, 1, 0 ),
|
||||
'DCOUNTA' => array( 199, 3, 0, 0 ),
|
||||
'ROUNDUP' => array( 212, 2, 1, 0 ),
|
||||
'ROUNDDOWN' => array( 213, 2, 1, 0 ),
|
||||
'RANK' => array( 216, -1, 0, 0 ),
|
||||
'ADDRESS' => array( 219, -1, 1, 0 ),
|
||||
'DAYS360' => array( 220, -1, 1, 0 ),
|
||||
'TODAY' => array( 221, 0, 1, 1 ),
|
||||
'VDB' => array( 222, -1, 1, 0 ),
|
||||
'MEDIAN' => array( 227, -1, 0, 0 ),
|
||||
'SUMPRODUCT' => array( 228, -1, 2, 0 ),
|
||||
'SINH' => array( 229, 1, 1, 0 ),
|
||||
'COSH' => array( 230, 1, 1, 0 ),
|
||||
'TANH' => array( 231, 1, 1, 0 ),
|
||||
'ASINH' => array( 232, 1, 1, 0 ),
|
||||
'ACOSH' => array( 233, 1, 1, 0 ),
|
||||
'ATANH' => array( 234, 1, 1, 0 ),
|
||||
'DGET' => array( 235, 3, 0, 0 ),
|
||||
'INFO' => array( 244, 1, 1, 1 ),
|
||||
'DB' => array( 247, -1, 1, 0 ),
|
||||
'FREQUENCY' => array( 252, 2, 0, 0 ),
|
||||
'ERROR.TYPE' => array( 261, 1, 1, 0 ),
|
||||
'REGISTER.ID' => array( 267, -1, 1, 0 ),
|
||||
'AVEDEV' => array( 269, -1, 0, 0 ),
|
||||
'BETADIST' => array( 270, -1, 1, 0 ),
|
||||
'GAMMALN' => array( 271, 1, 1, 0 ),
|
||||
'BETAINV' => array( 272, -1, 1, 0 ),
|
||||
'BINOMDIST' => array( 273, 4, 1, 0 ),
|
||||
'CHIDIST' => array( 274, 2, 1, 0 ),
|
||||
'CHIINV' => array( 275, 2, 1, 0 ),
|
||||
'COMBIN' => array( 276, 2, 1, 0 ),
|
||||
'CONFIDENCE' => array( 277, 3, 1, 0 ),
|
||||
'CRITBINOM' => array( 278, 3, 1, 0 ),
|
||||
'EVEN' => array( 279, 1, 1, 0 ),
|
||||
'EXPONDIST' => array( 280, 3, 1, 0 ),
|
||||
'FDIST' => array( 281, 3, 1, 0 ),
|
||||
'FINV' => array( 282, 3, 1, 0 ),
|
||||
'FISHER' => array( 283, 1, 1, 0 ),
|
||||
'FISHERINV' => array( 284, 1, 1, 0 ),
|
||||
'FLOOR' => array( 285, 2, 1, 0 ),
|
||||
'GAMMADIST' => array( 286, 4, 1, 0 ),
|
||||
'GAMMAINV' => array( 287, 3, 1, 0 ),
|
||||
'CEILING' => array( 288, 2, 1, 0 ),
|
||||
'HYPGEOMDIST' => array( 289, 4, 1, 0 ),
|
||||
'LOGNORMDIST' => array( 290, 3, 1, 0 ),
|
||||
'LOGINV' => array( 291, 3, 1, 0 ),
|
||||
'NEGBINOMDIST' => array( 292, 3, 1, 0 ),
|
||||
'NORMDIST' => array( 293, 4, 1, 0 ),
|
||||
'NORMSDIST' => array( 294, 1, 1, 0 ),
|
||||
'NORMINV' => array( 295, 3, 1, 0 ),
|
||||
'NORMSINV' => array( 296, 1, 1, 0 ),
|
||||
'STANDARDIZE' => array( 297, 3, 1, 0 ),
|
||||
'ODD' => array( 298, 1, 1, 0 ),
|
||||
'PERMUT' => array( 299, 2, 1, 0 ),
|
||||
'POISSON' => array( 300, 3, 1, 0 ),
|
||||
'TDIST' => array( 301, 3, 1, 0 ),
|
||||
'WEIBULL' => array( 302, 4, 1, 0 ),
|
||||
'SUMXMY2' => array( 303, 2, 2, 0 ),
|
||||
'SUMX2MY2' => array( 304, 2, 2, 0 ),
|
||||
'SUMX2PY2' => array( 305, 2, 2, 0 ),
|
||||
'CHITEST' => array( 306, 2, 2, 0 ),
|
||||
'CORREL' => array( 307, 2, 2, 0 ),
|
||||
'COVAR' => array( 308, 2, 2, 0 ),
|
||||
'FORECAST' => array( 309, 3, 2, 0 ),
|
||||
'FTEST' => array( 310, 2, 2, 0 ),
|
||||
'INTERCEPT' => array( 311, 2, 2, 0 ),
|
||||
'PEARSON' => array( 312, 2, 2, 0 ),
|
||||
'RSQ' => array( 313, 2, 2, 0 ),
|
||||
'STEYX' => array( 314, 2, 2, 0 ),
|
||||
'SLOPE' => array( 315, 2, 2, 0 ),
|
||||
'TTEST' => array( 316, 4, 2, 0 ),
|
||||
'PROB' => array( 317, -1, 2, 0 ),
|
||||
'DEVSQ' => array( 318, -1, 0, 0 ),
|
||||
'GEOMEAN' => array( 319, -1, 0, 0 ),
|
||||
'HARMEAN' => array( 320, -1, 0, 0 ),
|
||||
'SUMSQ' => array( 321, -1, 0, 0 ),
|
||||
'KURT' => array( 322, -1, 0, 0 ),
|
||||
'SKEW' => array( 323, -1, 0, 0 ),
|
||||
'ZTEST' => array( 324, -1, 0, 0 ),
|
||||
'LARGE' => array( 325, 2, 0, 0 ),
|
||||
'SMALL' => array( 326, 2, 0, 0 ),
|
||||
'QUARTILE' => array( 327, 2, 0, 0 ),
|
||||
'PERCENTILE' => array( 328, 2, 0, 0 ),
|
||||
'PERCENTRANK' => array( 329, -1, 0, 0 ),
|
||||
'MODE' => array( 330, -1, 2, 0 ),
|
||||
'TRIMMEAN' => array( 331, 2, 0, 0 ),
|
||||
'TINV' => array( 332, 2, 1, 0 ),
|
||||
'CONCATENATE' => array( 336, -1, 1, 0 ),
|
||||
'POWER' => array( 337, 2, 1, 0 ),
|
||||
'RADIANS' => array( 342, 1, 1, 0 ),
|
||||
'DEGREES' => array( 343, 1, 1, 0 ),
|
||||
'SUBTOTAL' => array( 344, -1, 0, 0 ),
|
||||
'SUMIF' => array( 345, -1, 0, 0 ),
|
||||
'COUNTIF' => array( 346, 2, 0, 0 ),
|
||||
'COUNTBLANK' => array( 347, 1, 0, 0 ),
|
||||
'ROMAN' => array( 354, -1, 1, 0 )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a token to the proper ptg value.
|
||||
*
|
||||
* @param mixed $token The token to convert.
|
||||
*/
|
||||
function _convert($token)
|
||||
{
|
||||
if(is_numeric($token))
|
||||
{
|
||||
return($this->_convert_number($token));
|
||||
}
|
||||
// match references like A1
|
||||
elseif(preg_match("/^([A-I]?[A-Z])(\d+)$/",$token))
|
||||
{
|
||||
return($this->_convert_ref2d($token));
|
||||
}
|
||||
// match ranges like A1:B2
|
||||
elseif(preg_match("/^([A-I]?[A-Z])(\d+)\:([A-I]?[A-Z])(\d+)$/",$token))
|
||||
{
|
||||
return($this->_convert_range2d($token));
|
||||
}
|
||||
// match ranges like A1..B2
|
||||
elseif(preg_match("/^([A-I]?[A-Z])(\d+)\.\.([A-I]?[A-Z])(\d+)$/",$token))
|
||||
{
|
||||
return($this->_convert_range2d($token));
|
||||
}
|
||||
elseif(isset($this->ptg[$token])) // operators (including parentheses)
|
||||
{
|
||||
return(pack("C", $this->ptg[$token]));
|
||||
}
|
||||
elseif(preg_match("/[A-Z0-9<>-<2D>\.]+/",$token))
|
||||
{
|
||||
return($this->_convert_function($token,$this->_func_args));
|
||||
}
|
||||
// if it's an argument, ignore the token (the argument remains)
|
||||
elseif($token == 'arg')
|
||||
{
|
||||
$this->_func_args++;
|
||||
return('');
|
||||
}
|
||||
die("Unknown token $token");
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a number token to ptgInt or ptgNum
|
||||
*
|
||||
* @param mixed $num an integer or double for conersion to its ptg value
|
||||
*/
|
||||
function _convert_number($num)
|
||||
{
|
||||
// Integer in the range 0..2**16-1
|
||||
if ((preg_match("/^\d+$/",$num)) and ($num <= 65535)) {
|
||||
return pack("Cv", $this->ptg['ptgInt'], $num);
|
||||
}
|
||||
else // A float
|
||||
{
|
||||
if($this->_byte_order) // if it's Big Endian
|
||||
{
|
||||
$num = strrev($num);
|
||||
}
|
||||
return pack("Cd", $this->ptg['ptgNum'], $num);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a function to a ptgFunc or ptgFuncVarV depending on the number of
|
||||
* args that it takes.
|
||||
*
|
||||
* @param string $token The name of the function for convertion to ptg value.
|
||||
* @param integer $num_args The number of arguments the function recieves.
|
||||
*/
|
||||
function _convert_function($token, $num_args)
|
||||
{
|
||||
$this->_func_args = 0; // re initialize the number of arguments
|
||||
$args = $this->_functions[$token][1];
|
||||
$volatile = $this->_functions[$token][3];
|
||||
|
||||
if($volatile) {
|
||||
$this->_volatile = 1;
|
||||
}
|
||||
// Fixed number of args eg. TIME($i,$j,$k).
|
||||
if ($args >= 0)
|
||||
{
|
||||
return(pack("Cv", $this->ptg['ptgFuncV'], $this->_functions[$token][0]));
|
||||
}
|
||||
// Variable number of args eg. SUM($i,$j,$k, ..).
|
||||
if ($args == -1) {
|
||||
return(pack("CCv", $this->ptg['ptgFuncVarV'], $num_args, $this->_functions[$token][0]));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert an Excel range such as A1:D4 to a ptgRefV.
|
||||
*
|
||||
* @param string $range An Excel range in the A1:A2 or A1..A2 format.
|
||||
*/
|
||||
function _convert_range2d($range)
|
||||
{
|
||||
$class = 2; // as far as I know, this is magick.
|
||||
|
||||
// Split the range into 2 cell refs
|
||||
if(preg_match("/^([A-I]?[A-Z])(\d+)\:([A-I]?[A-Z])(\d+)$/",$range)) {
|
||||
list($cell1, $cell2) = explode(':', $range);
|
||||
}
|
||||
elseif(preg_match("/^([A-I]?[A-Z])(\d+)\.\.([A-I]?[A-Z])(\d+)$/",$range)) {
|
||||
list($cell1, $cell2) = explode('..', $range);
|
||||
}
|
||||
else {
|
||||
die("Unknown range separator");
|
||||
}
|
||||
|
||||
// Convert the cell references
|
||||
list($row1, $col1) = $this->_cell_to_packed_rowcol($cell1);
|
||||
list($row2, $col2) = $this->_cell_to_packed_rowcol($cell2);
|
||||
|
||||
// The ptg value depends on the class of the ptg.
|
||||
if ($class == 0) {
|
||||
$ptgArea = pack("C", $this->ptg['ptgArea']);
|
||||
}
|
||||
elseif ($class == 1) {
|
||||
$ptgArea = pack("C", $this->ptg['ptgAreaV']);
|
||||
}
|
||||
elseif ($class == 2) {
|
||||
$ptgArea = pack("C", $this->ptg['ptgAreaA']);
|
||||
}
|
||||
else{
|
||||
die("Unknown class ");
|
||||
}
|
||||
|
||||
return($ptgArea . $row1 . $row2 . $col1. $col2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert an Excel reference such as A1, $B2, C$3 or $D$4 to a ptgRefV.
|
||||
*
|
||||
* @param string $cell An Excel cell reference
|
||||
*/
|
||||
function _convert_ref2d($cell)
|
||||
{
|
||||
$class = 2; // as far as I know, this is magick.
|
||||
|
||||
// Convert the cell reference
|
||||
list($row, $col) = $this->_cell_to_packed_rowcol($cell);
|
||||
|
||||
// The ptg value depends on the class of the ptg.
|
||||
if ($class == 0) {
|
||||
$ptgRef = pack("C", $this->ptg['ptgRef']);
|
||||
}
|
||||
elseif ($class == 1) {
|
||||
$ptgRef = pack("C", $this->ptg['ptgRefV']);
|
||||
}
|
||||
elseif ($class == 2) {
|
||||
$ptgRef = pack("C", $this->ptg['ptgRefA']);
|
||||
}
|
||||
else{
|
||||
die("Unknown class ");
|
||||
}
|
||||
return $ptgRef.$row.$col;
|
||||
}
|
||||
|
||||
/**
|
||||
* pack() row and column into the required 3 byte format.
|
||||
*
|
||||
* @param string $cell The Excel cell reference to be packed
|
||||
*/
|
||||
function _cell_to_packed_rowcol($cell)
|
||||
{
|
||||
list($row, $col, $row_rel, $col_rel) = $this->_cell_to_rowcol($cell);
|
||||
if ($col >= 256) {
|
||||
die("Column in: $cell greater than 255 ");
|
||||
}
|
||||
if ($row >= 16384) {
|
||||
die("Row in: $cell greater than 16384 ");
|
||||
}
|
||||
|
||||
// Set the high bits to indicate if row or col are relative.
|
||||
$row |= $col_rel << 14;
|
||||
$row |= $row_rel << 15;
|
||||
|
||||
$row = pack('v', $row);
|
||||
$col = pack('C', $col);
|
||||
|
||||
return (array($row, $col));
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert an Excel cell reference such as A1 or $B2 or C$3 or $D$4 to a zero
|
||||
* indexed row and column number. Also returns two boolean values to indicate
|
||||
* whether the row or column are relative references.
|
||||
*
|
||||
* @param string $cell The Excel cell reference in A1 format.
|
||||
*/
|
||||
function _cell_to_rowcol($cell)
|
||||
{
|
||||
preg_match('/(\$)?([A-I]?[A-Z])(\$)?(\d+)/',$cell,$match);
|
||||
// return absolute column if there is a $ in the ref
|
||||
$col_rel = empty($match[1]) ? 1 : 0;
|
||||
$col_ref = $match[2];
|
||||
$row_rel = empty($match[3]) ? 1 : 0;
|
||||
$row = $match[4];
|
||||
|
||||
// Convert base26 column string to a number.
|
||||
$expn = strlen($col_ref) - 1;
|
||||
$col = 0;
|
||||
for($i=0; $i < strlen($col_ref); $i++)
|
||||
{
|
||||
$col += (ord($col_ref{$i}) - ord('A') + 1) * pow(26, $expn);
|
||||
$expn--;
|
||||
}
|
||||
|
||||
// Convert 1-index to zero-index
|
||||
$row--;
|
||||
$col--;
|
||||
|
||||
return(array($row, $col, $row_rel, $col_rel));
|
||||
}
|
||||
|
||||
/**
|
||||
* Advance to the next valid token.
|
||||
*/
|
||||
function _advance()
|
||||
{
|
||||
$i = $this->_current_char;
|
||||
// eat up white spaces
|
||||
if($i < strlen($this->_formula))
|
||||
{
|
||||
while($this->_formula{$i} == " ")
|
||||
{
|
||||
$i++;
|
||||
}
|
||||
if($i < strlen($this->_formula) - 1)
|
||||
{
|
||||
$this->_lookahead = $this->_formula{$i+1};
|
||||
}
|
||||
$token = "";
|
||||
}
|
||||
while($i < strlen($this->_formula))
|
||||
{
|
||||
$token .= $this->_formula{$i};
|
||||
if($this->_match($token) != '')
|
||||
{
|
||||
if($i < strlen($this->_formula) - 1)
|
||||
{
|
||||
$this->_lookahead = $this->_formula{$i+1};
|
||||
}
|
||||
$this->_current_char = $i + 1;
|
||||
$this->_current_token = $token;
|
||||
return(1);
|
||||
}
|
||||
$this->_lookahead = $this->_formula{$i+2};
|
||||
$i++;
|
||||
}
|
||||
//die("Lexical error ".$this->_current_char);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if it's a valid token.
|
||||
*
|
||||
* @param mixed $token The token to check.
|
||||
*/
|
||||
function _match($token)
|
||||
{
|
||||
switch($token)
|
||||
{
|
||||
case ADD:
|
||||
return($token);
|
||||
break;
|
||||
case SUB:
|
||||
return($token);
|
||||
break;
|
||||
case MUL:
|
||||
return($token);
|
||||
break;
|
||||
case DIV:
|
||||
return($token);
|
||||
break;
|
||||
case OPEN:
|
||||
return($token);
|
||||
break;
|
||||
case CLOSE:
|
||||
return($token);
|
||||
break;
|
||||
case COMA:
|
||||
return($token);
|
||||
break;
|
||||
default:
|
||||
// if it's a reference
|
||||
if(preg_match("/^[A-I]?[A-Z][0-9]+$/i",$token) and
|
||||
!preg_match("/[0-9]/",$this->_lookahead) and
|
||||
($this->_lookahead != ':') and ($this->_lookahead != '.'))
|
||||
{
|
||||
return($token);
|
||||
}
|
||||
// if it's a range (A1:A2)
|
||||
elseif(preg_match("/^[A-I]?[A-Z][0-9]+:[A-I]?[A-Z][0-9]+$/i",$token) and
|
||||
!preg_match("/[0-9]/",$this->_lookahead))
|
||||
{
|
||||
return($token);
|
||||
}
|
||||
// if it's a range (A1..A2)
|
||||
elseif(preg_match("/^[A-I]?[A-Z][0-9]+\.\.[A-I]?[A-Z][0-9]+$/i",$token) and
|
||||
!preg_match("/[0-9]/",$this->_lookahead))
|
||||
{
|
||||
return($token);
|
||||
}
|
||||
elseif(is_numeric($token) and !is_numeric($token.$this->_lookahead))
|
||||
{
|
||||
return($token);
|
||||
}
|
||||
// if it's a function call
|
||||
elseif(preg_match("/^[A-Z0-9<>-<2D>\.]+$/i",$token) and ($this->_lookahead == "("))
|
||||
|
||||
{
|
||||
return($token);
|
||||
}
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The parsing method. It parses a formula.
|
||||
*
|
||||
* @access public
|
||||
* @param string $formula The formula to parse, without the initial equal sign (=).
|
||||
*/
|
||||
function parse($formula)
|
||||
{
|
||||
$this->_current_char = 0;
|
||||
$this->_formula = $formula;
|
||||
$this->_lookahead = $formula{1};
|
||||
$this->_advance();
|
||||
$this->_parse_tree = $this->_expression();
|
||||
}
|
||||
|
||||
/**
|
||||
* It parses a expression. It assumes the following rule:
|
||||
* Expr -> Term [("+" | "-") Term]
|
||||
*
|
||||
* @return mixed The parsed ptg'd tree
|
||||
*/
|
||||
function _expression()
|
||||
{
|
||||
$result = $this->_term();
|
||||
while ($this->_current_token == ADD or $this->_current_token == SUB)
|
||||
{
|
||||
if ($this->_current_token == ADD)
|
||||
{
|
||||
$this->_advance();
|
||||
$result = $this->_create_tree('ptgAdd', $result, $this->_term());
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->_advance();
|
||||
$result = $this->_create_tree('ptgSub', $result, $this->_term());
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function just introduces a ptgParen element in the tree, so that Excel
|
||||
* doesn't get confused when working with a parenthesized formula afterwards.
|
||||
*
|
||||
* @see _fact
|
||||
* @return mixed The parsed ptg'd tree
|
||||
*/
|
||||
function _parenthesized_expression()
|
||||
{
|
||||
$result = $this->_create_tree('ptgParen', $this->_expression(), '');
|
||||
return($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* It parses a term. It assumes the following rule:
|
||||
* Term -> Fact [("*" | "/") Fact]
|
||||
*
|
||||
* @return mixed The parsed ptg'd tree
|
||||
*/
|
||||
function _term()
|
||||
{
|
||||
$result = $this->_fact();
|
||||
while ($this->_current_token == MUL || $this->_current_token == DIV)
|
||||
{
|
||||
if ($this->_current_token == MUL)
|
||||
{
|
||||
$this->_advance();
|
||||
$result = $this->_create_tree('ptgMul', $result, $this->_fact());
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->_advance();
|
||||
$result = $this->_create_tree('ptgDiv', $result, $this->_fact());
|
||||
}
|
||||
}
|
||||
return($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* It parses a factor. It assumes the following rule:
|
||||
* Fact -> ( Expr )
|
||||
* | CellRef
|
||||
* | CellRange
|
||||
* | Number
|
||||
* | Function
|
||||
*
|
||||
* @return mixed The parsed ptg'd tree
|
||||
*/
|
||||
function _fact()
|
||||
{
|
||||
if ($this->_current_token == OPEN)
|
||||
{
|
||||
$this->_advance(); // eat the "("
|
||||
$result = $this->_parenthesized_expression();//$this->_expression();
|
||||
|
||||
if ($this->_current_token != CLOSE) {
|
||||
die("')' token expected.");
|
||||
}
|
||||
$this->_advance(); // eat the ")"
|
||||
return($result);
|
||||
}
|
||||
// if it's a reference
|
||||
if (preg_match("/^[A-I]?[A-Z][0-9]+$/i",$this->_current_token))
|
||||
{
|
||||
$result = $this->_create_tree($this->_current_token, '', '');
|
||||
$this->_advance();
|
||||
return($result);
|
||||
}
|
||||
// if it's a range
|
||||
elseif (preg_match("/^[A-I]?[A-Z][0-9]+:[A-I]?[A-Z][0-9]+$/i",$this->_current_token) or
|
||||
preg_match("/^[A-I]?[A-Z][0-9]+\.\.[A-I]?[A-Z][0-9]+$/i",$this->_current_token))
|
||||
{
|
||||
$result = $this->_current_token;
|
||||
$this->_advance();
|
||||
return($result);
|
||||
}
|
||||
elseif (is_numeric($this->_current_token))
|
||||
{
|
||||
$result = $this->_create_tree($this->_current_token, '', '');
|
||||
$this->_advance();
|
||||
return($result);
|
||||
}
|
||||
// if it's a function call
|
||||
elseif (preg_match("/^[A-Z0-9<>-<2D>\.]+$/i",$this->_current_token))
|
||||
{
|
||||
$result = $this->_func();
|
||||
return($result);
|
||||
}
|
||||
die("Sintactic error: ".$this->_current_token.", lookahead: ".
|
||||
$this->_lookahead.", current char: ".$this->_current_char);
|
||||
}
|
||||
|
||||
/**
|
||||
* It parses a function call. It assumes the following rule:
|
||||
* Func -> ( Expr [,Expr]* )
|
||||
*
|
||||
*/
|
||||
function _func()
|
||||
{
|
||||
$num_args = 0; // number of arguments received
|
||||
$function = $this->_current_token;
|
||||
$this->_advance();
|
||||
$this->_advance(); // eat the "("
|
||||
while($this->_current_token != ')')
|
||||
{
|
||||
if($num_args > 0)
|
||||
{
|
||||
if($this->_current_token == COMA) {
|
||||
$this->_advance(); // eat the ","
|
||||
}
|
||||
else {
|
||||
die("Sintactic error: coma expected $num_args");
|
||||
}
|
||||
$result = $this->_create_tree('arg', $result, $this->_expression());
|
||||
}
|
||||
else {
|
||||
$result = $this->_create_tree('arg', '', $this->_expression());
|
||||
}
|
||||
$num_args++;
|
||||
}
|
||||
$args = $this->_functions[$function][1];
|
||||
// If fixed number of args eg. TIME($i,$j,$k). Check that the number of args is valid.
|
||||
if (($args >= 0) and ($args != $num_args))
|
||||
{
|
||||
die("Incorrect number of arguments in function $function() ");
|
||||
}
|
||||
|
||||
$result = $this->_create_tree($function, $result, '');
|
||||
$this->_advance(); // eat the ")"
|
||||
return($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a tree. In fact an array which may have one or two arrays (sub-trees)
|
||||
* as elements.
|
||||
*
|
||||
* @param mixed $value The value of this node.
|
||||
* @param mixed $left The left array (sub-tree) or a final node.
|
||||
* @param mixed $right The right array (sub-tree) or a final node.
|
||||
*/
|
||||
function _create_tree($value, $left, $right)
|
||||
{
|
||||
return array('value' => $value, 'left' => $left, 'right' => $right);
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a string containing the tree in reverse polish notation (What you
|
||||
* would use in a HP calculator stack).
|
||||
* The following tree:
|
||||
*
|
||||
* +
|
||||
* / \
|
||||
* 2 3
|
||||
*
|
||||
* produces: "23+"
|
||||
*
|
||||
* The following tree:
|
||||
*
|
||||
* +
|
||||
* / \
|
||||
* 3 *
|
||||
* / \
|
||||
* 6 A1
|
||||
*
|
||||
* produces: "36A1*+"
|
||||
*
|
||||
* In fact all operands, functions, references, etc... are written as ptg's
|
||||
*
|
||||
* @access public
|
||||
* @param array $tree The optional tree to convert.
|
||||
*/
|
||||
function to_reverse_polish($tree = array())
|
||||
{
|
||||
$polish = ""; // the string we are going to return
|
||||
if (empty($tree)) // If it's the first call use _parse_tree
|
||||
{
|
||||
$tree = $this->_parse_tree;
|
||||
}
|
||||
if (is_array($tree['left']))
|
||||
{
|
||||
$polish .= $this->to_reverse_polish($tree['left']);
|
||||
}
|
||||
elseif($tree['left'] != '') // It's a final node
|
||||
{
|
||||
$polish .= $this->_convert($tree['left']); //$tree['left'];
|
||||
}
|
||||
if (is_array($tree['right']))
|
||||
{
|
||||
$polish .= $this->to_reverse_polish($tree['right']);
|
||||
}
|
||||
elseif($tree['right'] != '') // It's a final node
|
||||
{
|
||||
$polish .= $this->_convert($tree['right']);
|
||||
}
|
||||
$polish .= $this->_convert($tree['value']);
|
||||
return $polish;
|
||||
}
|
||||
}
|
||||
?>
|
@ -1,6 +0,0 @@
|
||||
Spreadsheet WriteExcel
|
||||
----------------------
|
||||
|
||||
This software is under the LGPL license.
|
||||
|
||||
Homepage: http://freshmeat.net/projects/spreadsheet_writeexcel
|
@ -1,954 +0,0 @@
|
||||
<?php
|
||||
/*
|
||||
* Module written/ported by Xavier Noguer <xnoguer@rezebra.com>
|
||||
*
|
||||
* The majority of this is _NOT_ my code. I simply ported it from the
|
||||
* PERL Spreadsheet::WriteExcel module.
|
||||
*
|
||||
* The author of the Spreadsheet::WriteExcel module is John McNamara
|
||||
* <jmcnamara@cpan.org>
|
||||
*
|
||||
* I _DO_ maintain this code, and John McNamara has nothing to do with the
|
||||
* porting of this code to PHP. Any questions directly related to this
|
||||
* class library should be directed to me.
|
||||
*
|
||||
* License Information:
|
||||
*
|
||||
* Spreadsheet::WriteExcel: A library for generating Excel Spreadsheets
|
||||
* Copyright (C) 2002 Xavier Noguer xnoguer@rezebra.com
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
//require_once('Format.php');
|
||||
require_once("$CFG->libdir/excel/Format.php");
|
||||
require_once('OLEwriter.php');
|
||||
require_once('BIFFwriter.php');
|
||||
|
||||
/**
|
||||
* Class for generating Excel Spreadsheets
|
||||
*
|
||||
* @author Xavier Noguer <xnoguer@rezebra.com>
|
||||
* @package Spreadsheet_WriteExcel
|
||||
*/
|
||||
|
||||
class Workbook extends BIFFwriter
|
||||
{
|
||||
/**
|
||||
* Class constructor
|
||||
*
|
||||
* @param string filename for storing the workbook. "-" for writing to stdout.
|
||||
*/
|
||||
function Workbook($filename)
|
||||
{
|
||||
$this->BIFFwriter(); // It needs to call its parent's constructor explicitly
|
||||
|
||||
$this->_filename = $filename;
|
||||
$this->parser = new Parser($this->_byte_order);
|
||||
$this->_1904 = 0;
|
||||
$this->activesheet = 0;
|
||||
$this->firstsheet = 0;
|
||||
$this->selected = 0;
|
||||
$this->xf_index = 16; // 15 style XF's and 1 cell XF.
|
||||
$this->_fileclosed = 0;
|
||||
$this->_biffsize = 0;
|
||||
$this->sheetname = "Sheet";
|
||||
$this->tmp_format = new Format();
|
||||
$this->worksheets = array();
|
||||
$this->sheetnames = array();
|
||||
$this->formats = array();
|
||||
$this->palette = array();
|
||||
|
||||
// Add the default format for hyperlinks
|
||||
$this->url_format =& $this->add_format(array('color' => 'blue', 'underline' => 1));
|
||||
|
||||
// Check for a filename
|
||||
//if ($this->_filename == '') {
|
||||
// die('Filename required by Spreadsheet::WriteExcel->new()');
|
||||
//}
|
||||
|
||||
# Warn if tmpfiles can't be used.
|
||||
//$this->tmpfile_warning();
|
||||
$this->_set_palette_xl97();
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls finalization methods and explicitly close the OLEwriter file
|
||||
* handle.
|
||||
*/
|
||||
function close()
|
||||
{
|
||||
if ($this->_fileclosed) { // Prevent close() from being called twice.
|
||||
return;
|
||||
}
|
||||
$this->store_workbook();
|
||||
$this->_fileclosed = 1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* An accessor for the _worksheets[] array
|
||||
* Returns an array of the worksheet objects in a workbook
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function sheets()
|
||||
{
|
||||
return($this->worksheets());
|
||||
}
|
||||
|
||||
/**
|
||||
* An accessor for the _worksheets[] array.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function worksheets()
|
||||
{
|
||||
return($this->worksheets);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new worksheet to the Excel workbook.
|
||||
* TODO: Add accessor for $this->{_sheetname} for international Excel versions.
|
||||
*
|
||||
* @access public
|
||||
* @param string $name the optional name of the worksheet
|
||||
* @return &object reference to a worksheet object
|
||||
*/
|
||||
function &add_worksheet($name = '')
|
||||
{
|
||||
$index = count($this->worksheets);
|
||||
$sheetname = $this->sheetname;
|
||||
|
||||
if($name == '') {
|
||||
$name = $sheetname.($index+1);
|
||||
}
|
||||
|
||||
// Check that sheetname is <= 31 chars (Excel limit).
|
||||
if(strlen($name) > 31) {
|
||||
die("Sheetname $name must be <= 31 chars");
|
||||
}
|
||||
|
||||
// Check that the worksheet name doesn't already exist: a fatal Excel error.
|
||||
for($i=0; $i < count($this->worksheets); $i++)
|
||||
{
|
||||
if($name == $this->worksheets[$i]->get_name()) {
|
||||
die("Worksheet '$name' already exists");
|
||||
}
|
||||
}
|
||||
|
||||
$worksheet = new Worksheet($name,$index,$this->activesheet,
|
||||
$this->firstsheet,$this->url_format,
|
||||
$this->parser);
|
||||
$this->worksheets[$index] = &$worksheet; // Store ref for iterator
|
||||
$this->sheetnames[$index] = $name; // Store EXTERNSHEET names
|
||||
//$this->parser->set_ext_sheet($name,$index); // Store names in Formula.php
|
||||
return($worksheet);
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED!! Use add_worksheet instead
|
||||
*
|
||||
* @access public
|
||||
* @deprecated Use add_worksheet instead
|
||||
* @param string $name the optional name of the worksheet
|
||||
* @return &object reference to a worksheet object
|
||||
*/
|
||||
function &addworksheet($name = '')
|
||||
{
|
||||
return($this->add_worksheet($name));
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new format to the Excel workbook. This adds an XF record and
|
||||
* a FONT record. Also, pass any properties to the Format constructor.
|
||||
*
|
||||
* @access public
|
||||
* @param array $properties array with properties for initializing the format (see Format.php)
|
||||
* @return &object reference to an XF format
|
||||
*/
|
||||
function &add_format($properties = array())
|
||||
{
|
||||
$format = new Format($this->xf_index,$properties);
|
||||
$this->xf_index += 1;
|
||||
$this->formats[] = &$format;
|
||||
return($format);
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED!! Use add_format instead
|
||||
*
|
||||
* @access public
|
||||
* @deprecated Use add_format instead
|
||||
* @param array $properties array with properties for initializing the format (see Format.php)
|
||||
* @return &object reference to an XF format
|
||||
*/
|
||||
function &addformat($properties = array())
|
||||
{
|
||||
return($this->add_format($properties));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Change the RGB components of the elements in the colour palette.
|
||||
*
|
||||
* @access public
|
||||
* @param integer $index colour index
|
||||
* @param integer $red red RGB value [0-255]
|
||||
* @param integer $green green RGB value [0-255]
|
||||
* @param integer $blue blue RGB value [0-255]
|
||||
* @return integer The palette index for the custom color
|
||||
*/
|
||||
function set_custom_color($index,$red,$green,$blue)
|
||||
{
|
||||
// Match a HTML #xxyyzz style parameter
|
||||
/*if (defined $_[1] and $_[1] =~ /^#(\w\w)(\w\w)(\w\w)/ ) {
|
||||
@_ = ($_[0], hex $1, hex $2, hex $3);
|
||||
}*/
|
||||
|
||||
// Check that the colour index is the right range
|
||||
if ($index < 8 or $index > 64) {
|
||||
die("Color index $index outside range: 8 <= index <= 64");
|
||||
}
|
||||
|
||||
// Check that the colour components are in the right range
|
||||
if ( ($red < 0 or $red > 255) ||
|
||||
($green < 0 or $green > 255) ||
|
||||
($blue < 0 or $blue > 255) )
|
||||
{
|
||||
die("Color component outside range: 0 <= color <= 255");
|
||||
}
|
||||
|
||||
$index -= 8; // Adjust colour index (wingless dragonfly)
|
||||
|
||||
// Set the RGB value
|
||||
$this->palette[$index] = array($red, $green, $blue, 0);
|
||||
return($index + 8);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the colour palette to the Excel 97+ default.
|
||||
*/
|
||||
function _set_palette_xl97()
|
||||
{
|
||||
$this->palette = array(
|
||||
array(0x00, 0x00, 0x00, 0x00), // 8
|
||||
array(0xff, 0xff, 0xff, 0x00), // 9
|
||||
array(0xff, 0x00, 0x00, 0x00), // 10
|
||||
array(0x00, 0xff, 0x00, 0x00), // 11
|
||||
array(0x00, 0x00, 0xff, 0x00), // 12
|
||||
array(0xff, 0xff, 0x00, 0x00), // 13
|
||||
array(0xff, 0x00, 0xff, 0x00), // 14
|
||||
array(0x00, 0xff, 0xff, 0x00), // 15
|
||||
array(0x80, 0x00, 0x00, 0x00), // 16
|
||||
array(0x00, 0x80, 0x00, 0x00), // 17
|
||||
array(0x00, 0x00, 0x80, 0x00), // 18
|
||||
array(0x80, 0x80, 0x00, 0x00), // 19
|
||||
array(0x80, 0x00, 0x80, 0x00), // 20
|
||||
array(0x00, 0x80, 0x80, 0x00), // 21
|
||||
array(0xc0, 0xc0, 0xc0, 0x00), // 22
|
||||
array(0x80, 0x80, 0x80, 0x00), // 23
|
||||
array(0x99, 0x99, 0xff, 0x00), // 24
|
||||
array(0x99, 0x33, 0x66, 0x00), // 25
|
||||
array(0xff, 0xff, 0xcc, 0x00), // 26
|
||||
array(0xcc, 0xff, 0xff, 0x00), // 27
|
||||
array(0x66, 0x00, 0x66, 0x00), // 28
|
||||
array(0xff, 0x80, 0x80, 0x00), // 29
|
||||
array(0x00, 0x66, 0xcc, 0x00), // 30
|
||||
array(0xcc, 0xcc, 0xff, 0x00), // 31
|
||||
array(0x00, 0x00, 0x80, 0x00), // 32
|
||||
array(0xff, 0x00, 0xff, 0x00), // 33
|
||||
array(0xff, 0xff, 0x00, 0x00), // 34
|
||||
array(0x00, 0xff, 0xff, 0x00), // 35
|
||||
array(0x80, 0x00, 0x80, 0x00), // 36
|
||||
array(0x80, 0x00, 0x00, 0x00), // 37
|
||||
array(0x00, 0x80, 0x80, 0x00), // 38
|
||||
array(0x00, 0x00, 0xff, 0x00), // 39
|
||||
array(0x00, 0xcc, 0xff, 0x00), // 40
|
||||
array(0xcc, 0xff, 0xff, 0x00), // 41
|
||||
array(0xcc, 0xff, 0xcc, 0x00), // 42
|
||||
array(0xff, 0xff, 0x99, 0x00), // 43
|
||||
array(0x99, 0xcc, 0xff, 0x00), // 44
|
||||
array(0xff, 0x99, 0xcc, 0x00), // 45
|
||||
array(0xcc, 0x99, 0xff, 0x00), // 46
|
||||
array(0xff, 0xcc, 0x99, 0x00), // 47
|
||||
array(0x33, 0x66, 0xff, 0x00), // 48
|
||||
array(0x33, 0xcc, 0xcc, 0x00), // 49
|
||||
array(0x99, 0xcc, 0x00, 0x00), // 50
|
||||
array(0xff, 0xcc, 0x00, 0x00), // 51
|
||||
array(0xff, 0x99, 0x00, 0x00), // 52
|
||||
array(0xff, 0x66, 0x00, 0x00), // 53
|
||||
array(0x66, 0x66, 0x99, 0x00), // 54
|
||||
array(0x96, 0x96, 0x96, 0x00), // 55
|
||||
array(0x00, 0x33, 0x66, 0x00), // 56
|
||||
array(0x33, 0x99, 0x66, 0x00), // 57
|
||||
array(0x00, 0x33, 0x00, 0x00), // 58
|
||||
array(0x33, 0x33, 0x00, 0x00), // 59
|
||||
array(0x99, 0x33, 0x00, 0x00), // 60
|
||||
array(0x99, 0x33, 0x66, 0x00), // 61
|
||||
array(0x33, 0x33, 0x99, 0x00), // 62
|
||||
array(0x33, 0x33, 0x33, 0x00), // 63
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# _tmpfile_warning()
|
||||
#
|
||||
# Check that tmp files can be created for use in Worksheet.pm. A CGI, mod_perl
|
||||
# or IIS might not have permission to create tmp files. The test is here rather
|
||||
# than in Worksheet.pm so that only one warning is given.
|
||||
#
|
||||
/*sub _tmpfile_warning {
|
||||
|
||||
my $fh = IO::File->new_tmpfile();
|
||||
|
||||
if ((not defined $fh) && ($^W)) {
|
||||
carp("Unable to create tmp files via IO::File->new_tmpfile(). " .
|
||||
"Storing data in memory")
|
||||
}
|
||||
}*/
|
||||
|
||||
/**
|
||||
* Assemble worksheets into a workbook and send the BIFF data to an OLE
|
||||
* storage.
|
||||
*/
|
||||
function store_workbook()
|
||||
{
|
||||
// Ensure that at least one worksheet has been selected.
|
||||
if ($this->activesheet == 0) {
|
||||
$this->worksheets[0]->selected = 1;
|
||||
}
|
||||
|
||||
// Calculate the number of selected worksheet tabs and call the finalization
|
||||
// methods for each worksheet
|
||||
for($i=0; $i < count($this->worksheets); $i++)
|
||||
{
|
||||
if($this->worksheets[$i]->selected)
|
||||
$this->selected++;
|
||||
$this->worksheets[$i]->close($this->sheetnames);
|
||||
}
|
||||
|
||||
// Add Workbook globals
|
||||
$this->_store_bof(0x0005);
|
||||
$this->_store_externs(); // For print area and repeat rows
|
||||
$this->_store_names(); // For print area and repeat rows
|
||||
$this->_store_window1();
|
||||
$this->_store_1904();
|
||||
$this->_store_all_fonts();
|
||||
$this->_store_all_num_formats();
|
||||
$this->_store_all_xfs();
|
||||
$this->_store_all_styles();
|
||||
$this->_store_palette();
|
||||
$this->_calc_sheet_offsets();
|
||||
|
||||
// Add BOUNDSHEET records
|
||||
for($i=0; $i < count($this->worksheets); $i++) {
|
||||
$this->_store_boundsheet($this->worksheets[$i]->name,$this->worksheets[$i]->offset);
|
||||
}
|
||||
|
||||
// End Workbook globals
|
||||
$this->_store_eof();
|
||||
|
||||
// Store the workbook in an OLE container
|
||||
$this->_store_OLE_file();
|
||||
}
|
||||
|
||||
/**
|
||||
* Store the workbook in an OLE container if the total size of the workbook data
|
||||
* is less than ~ 7MB.
|
||||
*/
|
||||
function _store_OLE_file()
|
||||
{
|
||||
$OLE = new OLEwriter($this->_filename);
|
||||
// Write Worksheet data if data <~ 7MB
|
||||
if ($OLE->set_size($this->_biffsize))
|
||||
{
|
||||
$OLE->write_header();
|
||||
$OLE->write($this->_data);
|
||||
foreach($this->worksheets as $sheet)
|
||||
{
|
||||
while ($tmp = $sheet->get_data()) {
|
||||
$OLE->write($tmp);
|
||||
}
|
||||
}
|
||||
}
|
||||
$OLE->close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate offsets for Worksheet BOF records.
|
||||
*/
|
||||
function _calc_sheet_offsets()
|
||||
{
|
||||
$BOF = 11;
|
||||
$EOF = 4;
|
||||
$offset = $this->_datasize;
|
||||
for($i=0; $i < count($this->worksheets); $i++) {
|
||||
$offset += $BOF + strlen($this->worksheets[$i]->name);
|
||||
}
|
||||
$offset += $EOF;
|
||||
for($i=0; $i < count($this->worksheets); $i++) {
|
||||
$this->worksheets[$i]->offset = $offset;
|
||||
$offset += $this->worksheets[$i]->_datasize;
|
||||
}
|
||||
$this->_biffsize = $offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Store the Excel FONT records.
|
||||
*/
|
||||
function _store_all_fonts()
|
||||
{
|
||||
// tmp_format is added by new(). We use this to write the default XF's
|
||||
$format = $this->tmp_format;
|
||||
$font = $format->get_font();
|
||||
|
||||
// Note: Fonts are 0-indexed. According to the SDK there is no index 4,
|
||||
// so the following fonts are 0, 1, 2, 3, 5
|
||||
//
|
||||
for($i=1; $i <= 5; $i++){
|
||||
$this->_append($font);
|
||||
}
|
||||
|
||||
// Iterate through the XF objects and write a FONT record if it isn't the
|
||||
// same as the default FONT and if it hasn't already been used.
|
||||
//
|
||||
$fonts = array();
|
||||
$index = 6; // The first user defined FONT
|
||||
|
||||
$key = $format->get_font_key(); // The default font from _tmp_format
|
||||
$fonts[$key] = 0; // Index of the default font
|
||||
|
||||
for($i=0; $i < count($this->formats); $i++) {
|
||||
$key = $this->formats[$i]->get_font_key();
|
||||
if (isset($fonts[$key])) {
|
||||
// FONT has already been used
|
||||
$this->formats[$i]->font_index = $fonts[$key];
|
||||
}
|
||||
else {
|
||||
// Add a new FONT record
|
||||
$fonts[$key] = $index;
|
||||
$this->formats[$i]->font_index = $index;
|
||||
$index++;
|
||||
$font = $this->formats[$i]->get_font();
|
||||
$this->_append($font);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Store user defined numerical formats i.e. FORMAT records
|
||||
*/
|
||||
function _store_all_num_formats()
|
||||
{
|
||||
// Leaning num_format syndrome
|
||||
$hash_num_formats = array();
|
||||
$num_formats = array();
|
||||
$index = 164;
|
||||
|
||||
// Iterate through the XF objects and write a FORMAT record if it isn't a
|
||||
// built-in format type and if the FORMAT string hasn't already been used.
|
||||
//
|
||||
for($i=0; $i < count($this->formats); $i++)
|
||||
{
|
||||
$num_format = $this->formats[$i]->_num_format;
|
||||
|
||||
// Check if $num_format is an index to a built-in format.
|
||||
// Also check for a string of zeros, which is a valid format string
|
||||
// but would evaluate to zero.
|
||||
//
|
||||
if (!preg_match("/^0+\d/",$num_format))
|
||||
{
|
||||
if (preg_match("/^\d+$/",$num_format)) { // built-in format
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($hash_num_formats[$num_format])) {
|
||||
// FORMAT has already been used
|
||||
$this->formats[$i]->_num_format = $hash_num_formats[$num_format];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Add a new FORMAT
|
||||
$hash_num_formats[$num_format] = $index;
|
||||
$this->formats[$i]->_num_format = $index;
|
||||
array_push($num_formats,$num_format);
|
||||
$index++;
|
||||
}
|
||||
}
|
||||
|
||||
// Write the new FORMAT records starting from 0xA4
|
||||
$index = 164;
|
||||
foreach ($num_formats as $num_format)
|
||||
{
|
||||
$this->_store_num_format($num_format,$index);
|
||||
$index++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Write all XF records.
|
||||
*/
|
||||
function _store_all_xfs()
|
||||
{
|
||||
// tmp_format is added by the constructor. We use this to write the default XF's
|
||||
// The default font index is 0
|
||||
//
|
||||
$format = $this->tmp_format;
|
||||
for ($i=0; $i <= 14; $i++)
|
||||
{
|
||||
$xf = $format->get_xf('style'); // Style XF
|
||||
$this->_append($xf);
|
||||
}
|
||||
|
||||
$xf = $format->get_xf('cell'); // Cell XF
|
||||
$this->_append($xf);
|
||||
|
||||
// User defined XFs
|
||||
for($i=0; $i < count($this->formats); $i++)
|
||||
{
|
||||
$xf = $this->formats[$i]->get_xf('cell');
|
||||
$this->_append($xf);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Write all STYLE records.
|
||||
*/
|
||||
function _store_all_styles()
|
||||
{
|
||||
$this->_store_style();
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the EXTERNCOUNT and EXTERNSHEET records. These are used as indexes for
|
||||
* the NAME records.
|
||||
*/
|
||||
function _store_externs()
|
||||
{
|
||||
// Create EXTERNCOUNT with number of worksheets
|
||||
$this->_store_externcount(count($this->worksheets));
|
||||
|
||||
// Create EXTERNSHEET for each worksheet
|
||||
foreach ($this->sheetnames as $sheetname) {
|
||||
$this->_store_externsheet($sheetname);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the NAME record to define the print area and the repeat rows and cols.
|
||||
*/
|
||||
function _store_names()
|
||||
{
|
||||
// Create the print area NAME records
|
||||
foreach ($this->worksheets as $worksheet)
|
||||
{
|
||||
// Write a Name record if the print area has been defined
|
||||
if (isset($worksheet->_print_rowmin))
|
||||
{
|
||||
$this->store_name_short(
|
||||
$worksheet->index,
|
||||
0x06, // NAME type
|
||||
$worksheet->_print_rowmin,
|
||||
$worksheet->_print_rowmax,
|
||||
$worksheet->_print_colmin,
|
||||
$worksheet->_print_colmax
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Create the print title NAME records
|
||||
foreach ($this->worksheets as $worksheet)
|
||||
{
|
||||
$rowmin = $worksheet->_title_rowmin;
|
||||
$rowmax = $worksheet->_title_rowmax;
|
||||
$colmin = $worksheet->_title_colmin;
|
||||
$colmax = $worksheet->_title_colmax;
|
||||
|
||||
// Determine if row + col, row, col or nothing has been defined
|
||||
// and write the appropriate record
|
||||
//
|
||||
if (isset($rowmin) && isset($colmin))
|
||||
{
|
||||
// Row and column titles have been defined.
|
||||
// Row title has been defined.
|
||||
$this->store_name_long(
|
||||
$worksheet->index,
|
||||
0x07, // NAME type
|
||||
$rowmin,
|
||||
$rowmax,
|
||||
$colmin,
|
||||
$colmax
|
||||
);
|
||||
}
|
||||
elseif (isset($rowmin))
|
||||
{
|
||||
// Row title has been defined.
|
||||
$this->store_name_short(
|
||||
$worksheet->index,
|
||||
0x07, // NAME type
|
||||
$rowmin,
|
||||
$rowmax,
|
||||
0x00,
|
||||
0xff
|
||||
);
|
||||
}
|
||||
elseif (isset($colmin))
|
||||
{
|
||||
// Column title has been defined.
|
||||
$this->store_name_short(
|
||||
$worksheet->index,
|
||||
0x07, // NAME type
|
||||
0x0000,
|
||||
0x3fff,
|
||||
$colmin,
|
||||
$colmax
|
||||
);
|
||||
}
|
||||
else {
|
||||
// Print title hasn't been defined.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* BIFF RECORDS
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Write Excel BIFF WINDOW1 record.
|
||||
*/
|
||||
function _store_window1()
|
||||
{
|
||||
$record = 0x003D; // Record identifier
|
||||
$length = 0x0012; // Number of bytes to follow
|
||||
|
||||
$xWn = 0x0000; // Horizontal position of window
|
||||
$yWn = 0x0000; // Vertical position of window
|
||||
$dxWn = 0x25BC; // Width of window
|
||||
$dyWn = 0x1572; // Height of window
|
||||
|
||||
$grbit = 0x0038; // Option flags
|
||||
$ctabsel = $this->selected; // Number of workbook tabs selected
|
||||
$wTabRatio = 0x0258; // Tab to scrollbar ratio
|
||||
|
||||
$itabFirst = $this->firstsheet; // 1st displayed worksheet
|
||||
$itabCur = $this->activesheet; // Active worksheet
|
||||
|
||||
$header = pack("vv", $record, $length);
|
||||
$data = pack("vvvvvvvvv", $xWn, $yWn, $dxWn, $dyWn,
|
||||
$grbit,
|
||||
$itabCur, $itabFirst,
|
||||
$ctabsel, $wTabRatio);
|
||||
$this->_append($header.$data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes Excel BIFF BOUNDSHEET record.
|
||||
*
|
||||
* @param string $sheetname Worksheet name
|
||||
* @param integer $offset Location of worksheet BOF
|
||||
*/
|
||||
function _store_boundsheet($sheetname,$offset)
|
||||
{
|
||||
$record = 0x0085; // Record identifier
|
||||
$length = 0x07 + strlen($sheetname); // Number of bytes to follow
|
||||
|
||||
$grbit = 0x0000; // Sheet identifier
|
||||
$cch = strlen($sheetname); // Length of sheet name
|
||||
|
||||
$header = pack("vv", $record, $length);
|
||||
$data = pack("VvC", $offset, $grbit, $cch);
|
||||
$this->_append($header.$data.$sheetname);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write Excel BIFF STYLE records.
|
||||
*/
|
||||
function _store_style()
|
||||
{
|
||||
$record = 0x0293; // Record identifier
|
||||
$length = 0x0004; // Bytes to follow
|
||||
|
||||
$ixfe = 0x8000; // Index to style XF
|
||||
$BuiltIn = 0x00; // Built-in style
|
||||
$iLevel = 0xff; // Outline style level
|
||||
|
||||
$header = pack("vv", $record, $length);
|
||||
$data = pack("vCC", $ixfe, $BuiltIn, $iLevel);
|
||||
$this->_append($header.$data);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Writes Excel FORMAT record for non "built-in" numerical formats.
|
||||
*
|
||||
* @param string $format Custom format string
|
||||
* @param integer $ifmt Format index code
|
||||
*/
|
||||
function _store_num_format($format,$ifmt)
|
||||
{
|
||||
$record = 0x041E; // Record identifier
|
||||
$length = 0x03 + strlen($format); // Number of bytes to follow
|
||||
|
||||
$cch = strlen($format); // Length of format string
|
||||
|
||||
$header = pack("vv", $record, $length);
|
||||
$data = pack("vC", $ifmt, $cch);
|
||||
$this->_append($header.$data.$format);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write Excel 1904 record to indicate the date system in use.
|
||||
*/
|
||||
function _store_1904()
|
||||
{
|
||||
$record = 0x0022; // Record identifier
|
||||
$length = 0x0002; // Bytes to follow
|
||||
|
||||
$f1904 = $this->_1904; // Flag for 1904 date system
|
||||
|
||||
$header = pack("vv", $record, $length);
|
||||
$data = pack("v", $f1904);
|
||||
$this->_append($header.$data);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Write BIFF record EXTERNCOUNT to indicate the number of external sheet
|
||||
* references in the workbook.
|
||||
*
|
||||
* Excel only stores references to external sheets that are used in NAME.
|
||||
* The workbook NAME record is required to define the print area and the repeat
|
||||
* rows and columns.
|
||||
*
|
||||
* A similar method is used in Worksheet.php for a slightly different purpose.
|
||||
*
|
||||
* @param integer $cxals Number of external references
|
||||
*/
|
||||
function _store_externcount($cxals)
|
||||
{
|
||||
$record = 0x0016; // Record identifier
|
||||
$length = 0x0002; // Number of bytes to follow
|
||||
|
||||
$header = pack("vv", $record, $length);
|
||||
$data = pack("v", $cxals);
|
||||
$this->_append($header.$data);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Writes the Excel BIFF EXTERNSHEET record. These references are used by
|
||||
* formulas. NAME record is required to define the print area and the repeat
|
||||
* rows and columns.
|
||||
*
|
||||
* A similar method is used in Worksheet.php for a slightly different purpose.
|
||||
*
|
||||
* @param string $sheetname Worksheet name
|
||||
*/
|
||||
function _store_externsheet($sheetname)
|
||||
{
|
||||
$record = 0x0017; // Record identifier
|
||||
$length = 0x02 + strlen($sheetname); // Number of bytes to follow
|
||||
|
||||
$cch = strlen($sheetname); // Length of sheet name
|
||||
$rgch = 0x03; // Filename encoding
|
||||
|
||||
$header = pack("vv", $record, $length);
|
||||
$data = pack("CC", $cch, $rgch);
|
||||
$this->_append($header.$data.$sheetname);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Store the NAME record in the short format that is used for storing the print
|
||||
* area, repeat rows only and repeat columns only.
|
||||
*
|
||||
* @param integer $index Sheet index
|
||||
* @param integer $type Built-in name type
|
||||
* @param integer $rowmin Start row
|
||||
* @param integer $rowmax End row
|
||||
* @param integer $colmin Start colum
|
||||
* @param integer $colmax End column
|
||||
*/
|
||||
function store_name_short($index,$type,$rowmin,$rowmax,$colmin,$colmax)
|
||||
{
|
||||
$record = 0x0018; // Record identifier
|
||||
$length = 0x0024; // Number of bytes to follow
|
||||
|
||||
$grbit = 0x0020; // Option flags
|
||||
$chKey = 0x00; // Keyboard shortcut
|
||||
$cch = 0x01; // Length of text name
|
||||
$cce = 0x0015; // Length of text definition
|
||||
$ixals = $index + 1; // Sheet index
|
||||
$itab = $ixals; // Equal to ixals
|
||||
$cchCustMenu = 0x00; // Length of cust menu text
|
||||
$cchDescription = 0x00; // Length of description text
|
||||
$cchHelptopic = 0x00; // Length of help topic text
|
||||
$cchStatustext = 0x00; // Length of status bar text
|
||||
$rgch = $type; // Built-in name type
|
||||
|
||||
$unknown03 = 0x3b;
|
||||
$unknown04 = 0xffff-$index;
|
||||
$unknown05 = 0x0000;
|
||||
$unknown06 = 0x0000;
|
||||
$unknown07 = 0x1087;
|
||||
$unknown08 = 0x8005;
|
||||
|
||||
$header = pack("vv", $record, $length);
|
||||
$data = pack("v", $grbit);
|
||||
$data .= pack("C", $chKey);
|
||||
$data .= pack("C", $cch);
|
||||
$data .= pack("v", $cce);
|
||||
$data .= pack("v", $ixals);
|
||||
$data .= pack("v", $itab);
|
||||
$data .= pack("C", $cchCustMenu);
|
||||
$data .= pack("C", $cchDescription);
|
||||
$data .= pack("C", $cchHelptopic);
|
||||
$data .= pack("C", $cchStatustext);
|
||||
$data .= pack("C", $rgch);
|
||||
$data .= pack("C", $unknown03);
|
||||
$data .= pack("v", $unknown04);
|
||||
$data .= pack("v", $unknown05);
|
||||
$data .= pack("v", $unknown06);
|
||||
$data .= pack("v", $unknown07);
|
||||
$data .= pack("v", $unknown08);
|
||||
$data .= pack("v", $index);
|
||||
$data .= pack("v", $index);
|
||||
$data .= pack("v", $rowmin);
|
||||
$data .= pack("v", $rowmax);
|
||||
$data .= pack("C", $colmin);
|
||||
$data .= pack("C", $colmax);
|
||||
$this->_append($header.$data);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Store the NAME record in the long format that is used for storing the repeat
|
||||
* rows and columns when both are specified. This share a lot of code with
|
||||
* _store_name_short() but we use a separate method to keep the code clean.
|
||||
* Code abstraction for reuse can be carried too far, and I should know. ;-)
|
||||
*
|
||||
* @param integer $index Sheet index
|
||||
* @param integer $type Built-in name type
|
||||
* @param integer $rowmin Start row
|
||||
* @param integer $rowmax End row
|
||||
* @param integer $colmin Start colum
|
||||
* @param integer $colmax End column
|
||||
*/
|
||||
function store_name_long($index,$type,$rowmin,$rowmax,$colmin,$colmax)
|
||||
{
|
||||
$record = 0x0018; // Record identifier
|
||||
$length = 0x003d; // Number of bytes to follow
|
||||
$grbit = 0x0020; // Option flags
|
||||
$chKey = 0x00; // Keyboard shortcut
|
||||
$cch = 0x01; // Length of text name
|
||||
$cce = 0x002e; // Length of text definition
|
||||
$ixals = $index + 1; // Sheet index
|
||||
$itab = $ixals; // Equal to ixals
|
||||
$cchCustMenu = 0x00; // Length of cust menu text
|
||||
$cchDescription = 0x00; // Length of description text
|
||||
$cchHelptopic = 0x00; // Length of help topic text
|
||||
$cchStatustext = 0x00; // Length of status bar text
|
||||
$rgch = $type; // Built-in name type
|
||||
|
||||
$unknown01 = 0x29;
|
||||
$unknown02 = 0x002b;
|
||||
$unknown03 = 0x3b;
|
||||
$unknown04 = 0xffff-$index;
|
||||
$unknown05 = 0x0000;
|
||||
$unknown06 = 0x0000;
|
||||
$unknown07 = 0x1087;
|
||||
$unknown08 = 0x8008;
|
||||
|
||||
$header = pack("vv", $record, $length);
|
||||
$data = pack("v", $grbit);
|
||||
$data .= pack("C", $chKey);
|
||||
$data .= pack("C", $cch);
|
||||
$data .= pack("v", $cce);
|
||||
$data .= pack("v", $ixals);
|
||||
$data .= pack("v", $itab);
|
||||
$data .= pack("C", $cchCustMenu);
|
||||
$data .= pack("C", $cchDescription);
|
||||
$data .= pack("C", $cchHelptopic);
|
||||
$data .= pack("C", $cchStatustext);
|
||||
$data .= pack("C", $rgch);
|
||||
$data .= pack("C", $unknown01);
|
||||
$data .= pack("v", $unknown02);
|
||||
// Column definition
|
||||
$data .= pack("C", $unknown03);
|
||||
$data .= pack("v", $unknown04);
|
||||
$data .= pack("v", $unknown05);
|
||||
$data .= pack("v", $unknown06);
|
||||
$data .= pack("v", $unknown07);
|
||||
$data .= pack("v", $unknown08);
|
||||
$data .= pack("v", $index);
|
||||
$data .= pack("v", $index);
|
||||
$data .= pack("v", 0x0000);
|
||||
$data .= pack("v", 0x3fff);
|
||||
$data .= pack("C", $colmin);
|
||||
$data .= pack("C", $colmax);
|
||||
// Row definition
|
||||
$data .= pack("C", $unknown03);
|
||||
$data .= pack("v", $unknown04);
|
||||
$data .= pack("v", $unknown05);
|
||||
$data .= pack("v", $unknown06);
|
||||
$data .= pack("v", $unknown07);
|
||||
$data .= pack("v", $unknown08);
|
||||
$data .= pack("v", $index);
|
||||
$data .= pack("v", $index);
|
||||
$data .= pack("v", $rowmin);
|
||||
$data .= pack("v", $rowmax);
|
||||
$data .= pack("C", 0x00);
|
||||
$data .= pack("C", 0xff);
|
||||
// End of data
|
||||
$data .= pack("C", 0x10);
|
||||
$this->_append($header.$data);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Stores the PALETTE biff record.
|
||||
*/
|
||||
function _store_palette()
|
||||
{
|
||||
$aref = $this->palette;
|
||||
|
||||
$record = 0x0092; // Record identifier
|
||||
$length = 2 + 4 * count($aref); // Number of bytes to follow
|
||||
$ccv = count($aref); // Number of RGB values to follow
|
||||
$data = ''; // The RGB data
|
||||
|
||||
// Pack the RGB data
|
||||
foreach($aref as $color)
|
||||
{
|
||||
foreach($color as $byte) {
|
||||
$data .= pack("C",$byte);
|
||||
}
|
||||
}
|
||||
|
||||
$header = pack("vvv", $record, $length, $ccv);
|
||||
$this->_append($header.$data);
|
||||
}
|
||||
}
|
||||
?>
|
File diff suppressed because it is too large
Load Diff
@ -1 +0,0 @@
|
||||
|
@ -1,197 +0,0 @@
|
||||
20 Jul 2010
|
||||
MDL-20876 - replaced deprecated split() with explode() or str_split() where appropriate
|
||||
|
||||
diff --git a/lib/excel/Parser.php b/lib/excel/Parser.php
|
||||
index f91cf98..06b9e23 100644
|
||||
--- a/lib/excel/Parser.php
|
||||
+++ b/lib/excel/Parser.php
|
||||
@@ -538,10 +538,10 @@ class Parser
|
||||
|
||||
// Split the range into 2 cell refs
|
||||
if(preg_match("/^([A-I]?[A-Z])(\d+)\:([A-I]?[A-Z])(\d+)$/",$range)) {
|
||||
- list($cell1, $cell2) = split(':', $range);
|
||||
+ list($cell1, $cell2) = explode(':', $range);
|
||||
}
|
||||
elseif(preg_match("/^([A-I]?[A-Z])(\d+)\.\.([A-I]?[A-Z])(\d+)$/",$range)) {
|
||||
- list($cell1, $cell2) = split('\.\.', $range);
|
||||
+ list($cell1, $cell2) = explode('..', $range);
|
||||
}
|
||||
else {
|
||||
die("Unknown range separator");
|
||||
@@ -993,4 +993,4 @@ class Parser
|
||||
return $polish;
|
||||
}
|
||||
}
|
||||
-?>
|
||||
\ No newline at end of file
|
||||
+?>
|
||||
diff --git a/lib/excel/Worksheet.php b/lib/excel/Worksheet.php
|
||||
index 1eb7682..d7c5cfc 100644
|
||||
--- a/lib/excel/Worksheet.php
|
||||
+++ b/lib/excel/Worksheet.php
|
||||
@@ -909,7 +909,7 @@ class Worksheet extends BIFFwriter
|
||||
$row = $match[2];
|
||||
|
||||
// Convert base26 column string to number
|
||||
- $chars = split('', $col);
|
||||
+ $chars = str_split($col);
|
||||
$expn = 0;
|
||||
$col = 0;
|
||||
|
||||
@@ -1530,13 +1530,13 @@ class Worksheet extends BIFFwriter
|
||||
// Determine if the link contains a sheet reference and change some of the
|
||||
// parameters accordingly.
|
||||
// Split the dir name and sheet name (if it exists)
|
||||
- list($dir_long , $sheet) = split('/\#/', $url);
|
||||
+ list($dir_long , $sheet) = explode('/#/', $url);
|
||||
$link_type = 0x01 | $absolute;
|
||||
|
||||
if (isset($sheet)) {
|
||||
$link_type |= 0x08;
|
||||
$sheet_len = pack("V", strlen($sheet) + 0x01);
|
||||
- $sheet = join("\0", split('', $sheet));
|
||||
+ $sheet = join("\0", str_split($sheet));
|
||||
$sheet .= "\0\0\0";
|
||||
}
|
||||
else {
|
||||
@@ -1555,7 +1555,7 @@ class Worksheet extends BIFFwriter
|
||||
$dir_short = preg_replace('/\.\.\\/', '', $dir_long) . "\0";
|
||||
|
||||
// Store the long dir name as a wchar string (non-null terminated)
|
||||
- $dir_long = join("\0", split('', $dir_long));
|
||||
+ $dir_long = join("\0", str_split($dir_long));
|
||||
$dir_long = $dir_long . "\0";
|
||||
|
||||
// Pack the lengths of the dir strings
|
||||
@@ -1644,7 +1644,7 @@ class Worksheet extends BIFFwriter
|
||||
if (defined $sheet) {
|
||||
$link_type |= 0x08;
|
||||
$sheet_len = pack("V", length($sheet) + 0x01);
|
||||
- $sheet = join("\0", split('', $sheet));
|
||||
+ $sheet = join("\0", str_split($sheet));
|
||||
$sheet .= "\0\0\0";
|
||||
}
|
||||
else {
|
||||
@@ -1665,7 +1665,7 @@ class Worksheet extends BIFFwriter
|
||||
|
||||
|
||||
# Store the long dir name as a wchar string (non-null terminated)
|
||||
- $dir_long = join("\0", split('', $dir_long));
|
||||
+ $dir_long = join("\0", str_split($dir_long));
|
||||
$dir_long = $dir_long . "\0";
|
||||
|
||||
|
||||
@@ -2832,4 +2832,4 @@ class Worksheet extends BIFFwriter
|
||||
$this->_append($header.$data);
|
||||
}
|
||||
}
|
||||
-?>
|
||||
\ No newline at end of file
|
||||
+?>
|
||||
|
||||
|
||||
|
||||
18 Nov 2009
|
||||
Description of WriteExcel modifications to remove functions deprecated as of php 5.3
|
||||
|
||||
Index: Parser.php
|
||||
===================================================================
|
||||
RCS file: /cvsroot/moodle/moodle/lib/excel/Parser.php,v
|
||||
retrieving revision 1.1
|
||||
diff -u -r1.1 Parser.php
|
||||
--- Parser.php 26 Sep 2003 04:18:02 -0000 1.1
|
||||
+++ Parser.php 18 Nov 2009 03:58:49 -0000
|
||||
@@ -466,7 +466,7 @@
|
||||
{
|
||||
return(pack("C", $this->ptg[$token]));
|
||||
}
|
||||
- elseif(preg_match("/[A-Z0-9À-Ü\.]+/",$token))
|
||||
+ elseif(preg_match("/[A-Z0-9ᅵ-ᅵ\.]+/",$token))
|
||||
{
|
||||
return($this->_convert_function($token,$this->_func_args));
|
||||
}
|
||||
@@ -723,21 +723,21 @@
|
||||
break;
|
||||
default:
|
||||
// if it's a reference
|
||||
- if(eregi("^[A-I]?[A-Z][0-9]+$",$token) and
|
||||
- !ereg("[0-9]",$this->_lookahead) and
|
||||
+ if(preg_match("/^[A-I]?[A-Z][0-9]+$/i",$token) and
|
||||
+ !preg_match("/[0-9]/",$this->_lookahead) and
|
||||
($this->_lookahead != ':') and ($this->_lookahead != '.'))
|
||||
{
|
||||
return($token);
|
||||
}
|
||||
// if it's a range (A1:A2)
|
||||
- elseif(eregi("^[A-I]?[A-Z][0-9]+:[A-I]?[A-Z][0-9]+$",$token) and
|
||||
- !ereg("[0-9]",$this->_lookahead))
|
||||
+ elseif(preg_match("/^[A-I]?[A-Z][0-9]+:[A-I]?[A-Z][0-9]+$/i",$token) and
|
||||
+ !preg_match("/[0-9]/",$this->_lookahead))
|
||||
{
|
||||
return($token);
|
||||
}
|
||||
// if it's a range (A1..A2)
|
||||
- elseif(eregi("^[A-I]?[A-Z][0-9]+\.\.[A-I]?[A-Z][0-9]+$",$token) and
|
||||
- !ereg("[0-9]",$this->_lookahead))
|
||||
+ elseif(preg_match("/^[A-I]?[A-Z][0-9]+\.\.[A-I]?[A-Z][0-9]+$/i",$token) and
|
||||
+ !preg_match("/[0-9]/",$this->_lookahead))
|
||||
{
|
||||
return($token);
|
||||
}
|
||||
@@ -746,7 +746,7 @@
|
||||
return($token);
|
||||
}
|
||||
// if it's a function call
|
||||
- elseif(eregi("^[A-Z0-9À-Ü\.]+$",$token) and ($this->_lookahead == "("))
|
||||
+ elseif(preg_match("/^[A-Z0-9ᅵ-ᅵ\.]+$/i",$token) and ($this->_lookahead == "("))
|
||||
|
||||
{
|
||||
return($token);
|
||||
@@ -857,15 +857,15 @@
|
||||
return($result);
|
||||
}
|
||||
// if it's a reference
|
||||
- if (eregi("^[A-I]?[A-Z][0-9]+$",$this->_current_token))
|
||||
+ if (preg_match("/^[A-I]?[A-Z][0-9]+$/i",$this->_current_token))
|
||||
{
|
||||
$result = $this->_create_tree($this->_current_token, '', '');
|
||||
$this->_advance();
|
||||
return($result);
|
||||
}
|
||||
// if it's a range
|
||||
- elseif (eregi("^[A-I]?[A-Z][0-9]+:[A-I]?[A-Z][0-9]+$",$this->_current_token) or
|
||||
- eregi("^[A-I]?[A-Z][0-9]+\.\.[A-I]?[A-Z][0-9]+$",$this->_current_token))
|
||||
+ elseif (preg_match("/^[A-I]?[A-Z][0-9]+:[A-I]?[A-Z][0-9]+$/i",$this->_current_token) or
|
||||
+ preg_match("/^[A-I]?[A-Z][0-9]+\.\.[A-I]?[A-Z][0-9]+$/i",$this->_current_token))
|
||||
{
|
||||
$result = $this->_current_token;
|
||||
$this->_advance();
|
||||
@@ -878,7 +878,7 @@
|
||||
return($result);
|
||||
}
|
||||
// if it's a function call
|
||||
- elseif (eregi("^[A-Z0-9À-Ü\.]+$",$this->_current_token))
|
||||
+ elseif (preg_match("/^[A-Z0-9ᅵ-ᅵ\.]+$/i",$this->_current_token))
|
||||
{
|
||||
$result = $this->_func();
|
||||
return($result);
|
||||
Index: Worksheet.php
|
||||
===================================================================
|
||||
RCS file: /cvsroot/moodle/moodle/lib/excel/Worksheet.php,v
|
||||
retrieving revision 1.1
|
||||
diff -u -r1.1 Worksheet.php
|
||||
--- Worksheet.php 26 Sep 2003 04:18:02 -0000 1.1
|
||||
+++ Worksheet.php 18 Nov 2009 03:58:50 -0000
|
||||
@@ -1264,10 +1264,10 @@
|
||||
}
|
||||
|
||||
// Strip the '=' or '@' sign at the beginning of the formula string
|
||||
- if (ereg("^=",$formula)) {
|
||||
+ if (preg_match("/^=/",$formula)) {
|
||||
$formula = preg_replace("/(^=)/","",$formula);
|
||||
}
|
||||
- elseif(ereg("^@",$formula)) {
|
||||
+ elseif(preg_match("/^@/",$formula)) {
|
||||
$formula = preg_replace("/(^@)/","",$formula);
|
||||
}
|
||||
else {
|
@ -1,90 +0,0 @@
|
||||
<?php
|
||||
//require_once('OLEwriter.php');
|
||||
//require_once('BIFFwriter.php');
|
||||
require_once('Worksheet.php');
|
||||
require_once('Workbook.php');
|
||||
|
||||
function HeaderingExcel($filename) {
|
||||
header("Content-type: application/vnd.ms-excel");
|
||||
header("Content-Disposition: attachment; filename=\"$filename\"" );
|
||||
header("Expires: 0");
|
||||
header("Cache-Control: must-revalidate, post-check=0,pre-check=0");
|
||||
header("Pragma: public");
|
||||
}
|
||||
|
||||
// HTTP headers
|
||||
HeaderingExcel('test.xls');
|
||||
|
||||
// Creating a workbook
|
||||
$workbook = new Workbook("-");
|
||||
// Creating the first worksheet
|
||||
$worksheet1 =& $workbook->add_worksheet('First One');
|
||||
// set the column width
|
||||
$worksheet1->set_column(1, 1, 40);
|
||||
// set the row height
|
||||
$worksheet1->set_row(1, 20);
|
||||
$worksheet1->write_string(1, 1, "This worksheet's name is ".$worksheet1->get_name());
|
||||
$worksheet1->write(2,1,"http://www.phpclasses.org/browse.html/package/767.html");
|
||||
$worksheet1->write_number(3, 0, 11);
|
||||
$worksheet1->write_number(3, 1, 1);
|
||||
$worksheet1->write_string(3, 2, "by four is");
|
||||
$worksheet1->write_formula(3, 3, "=A4 * (2 + 2)");
|
||||
//$worksheet1->write_formula(3, 3, "= SUM(A4:B4)");
|
||||
$worksheet1->write(5, 4, "= POWER(2,3)");
|
||||
$worksheet1->write(4, 4, "= SUM(5, 5, 5)");
|
||||
//$worksheet1->write_formula(4, 4, "= LN(2.71428)");
|
||||
//$worksheet1->write_formula(5, 4, "= SIN(PI()/2)");
|
||||
|
||||
// Creating the second worksheet
|
||||
$worksheet2 =& $workbook->add_worksheet();
|
||||
|
||||
// Format for the headings
|
||||
$formatot =& $workbook->add_format();
|
||||
$formatot->set_size(10);
|
||||
$formatot->set_align('center');
|
||||
$formatot->set_color('white');
|
||||
$formatot->set_pattern();
|
||||
$formatot->set_fg_color('magenta');
|
||||
|
||||
$worksheet2->set_column(0,0,15);
|
||||
$worksheet2->set_column(1,2,30);
|
||||
$worksheet2->set_column(3,3,15);
|
||||
$worksheet2->set_column(4,4,10);
|
||||
|
||||
$worksheet2->write_string(1,0,"Id",$formatot);
|
||||
$worksheet2->write_string(1,1,"Name",$formatot);
|
||||
$worksheet2->write_string(1,2,"Adress",$formatot);
|
||||
$worksheet2->write_string(1,3,"Phone Number",$formatot);
|
||||
$worksheet2->write_string(1,4,"Salary",$formatot);
|
||||
|
||||
$worksheet2->write(3,0,"22222222-2");
|
||||
$worksheet2->write(3,1,"John Smith");
|
||||
$worksheet2->write(3,2,"Main Street 100");
|
||||
$worksheet2->write(3,3,"02-5551234");
|
||||
$worksheet2->write(3,4,100);
|
||||
$worksheet2->write(4,0,"11111111-1");
|
||||
$worksheet2->write(4,1,"Juan Perez");
|
||||
$worksheet2->write(4,2,"Los Paltos 200");
|
||||
$worksheet2->write(4,3,"03-5552345");
|
||||
$worksheet2->write(4,4,110);
|
||||
// if you are writing a very long worksheet, you may want to use
|
||||
// write_xxx() functions, instead of write() for performance reasons.
|
||||
$worksheet2->write_string(5,0,"11111111-1");
|
||||
$worksheet2->write_string(5,1,"Another Guy");
|
||||
$worksheet2->write_string(5,2,"Somewhere 300");
|
||||
$worksheet2->write_string(5,3,"03-5553456");
|
||||
$worksheet2->write(5,4,108);
|
||||
|
||||
|
||||
// Calculate some statistics
|
||||
$worksheet2->write(7, 0, "Average Salary:");
|
||||
$worksheet2->write_formula(7, 4, "= AVERAGE(E4:E6)");
|
||||
$worksheet2->write(8, 0, "Minimum Salary:");
|
||||
$worksheet2->write_formula(8, 4, "= MIN(E4:E6)");
|
||||
$worksheet2->write(9, 0, "Maximum Salary:");
|
||||
$worksheet2->write_formula(9, 4, "= MAX(E4:E6)");
|
||||
|
||||
//$worksheet2->insert_bitmap(0, 0, "some.bmp",10,10);
|
||||
|
||||
$workbook->close();
|
||||
?>
|
@ -15,8 +15,6 @@ and documented for Moodle at:
|
||||
http://tracker.moodle.org/browse/MDL-9911
|
||||
|
||||
2/ Changed ereg_ to preg_
|
||||
* http://cvs.moodle.org/moodle/lib/excel/Parser.php.diff?r1=1.1&r2=1.2
|
||||
* http://cvs.moodle.org/moodle/lib/excel/Worksheet.php.diff?r1=1.1&r2=1.2
|
||||
|
||||
3/ removed deprecated "=& new"
|
||||
|
||||
|
@ -320,6 +320,8 @@ function upgrade_stale_php_files_present() {
|
||||
global $CFG;
|
||||
|
||||
$someexamplesofremovedfiles = array(
|
||||
// removed in 2.5dev
|
||||
'/lib/excel/test.php',
|
||||
// removed in 2.4dev
|
||||
'/admin/tool/unittest/simpletestlib.php',
|
||||
// removed in 2.3dev
|
||||
|
Loading…
x
Reference in New Issue
Block a user