.
/**
* Major Contributors:
* - Eloy Lafuente (stronk7) {@link http://contiento.com}
* - Petr Skoda (skodak)
*
* @package core
* @subpackage lib
* @copyright (C) 2001-3001 Eloy Lafuente (stronk7) {@link http://contiento.com}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
/**
* The xml used here is derived from output of KSpread 1.6.1
*
* Known problems:
* - missing formatting
* - write_date() works fine in OOo, but it does not work in KOffice - it knows only date or time but not both :-(
*
* @package moodlecore
* @copyright 1999 onwards Martin Dougiamas {@link http://moodle.com}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class MoodleODSWorkbook {
var $worksheets = array();
var $filename;
function MoodleODSWorkbook($filename) {
$this->filename = $filename;
}
/* Create one Moodle Worksheet
* @param string $name Name of the sheet
*/
function &add_worksheet($name = '') {
/// Create the Moodle Worksheet. Returns one pointer to it
$ws = new MoodleODSWorksheet($name);
$this->worksheets[] =& $ws;
return $ws;
}
/* Create one Moodle Format
* @param array $properties array of properties [name]=value;
* valid names are set_XXXX existing
* functions without the set_ part
* i.e: [bold]=1 for set_bold(1)...Optional!
*/
function &add_format($properties = array()) {
$format = new MoodleODSFormat($properties);
return $format;;
}
/* Close the Moodle Workbook
*/
function close() {
global $CFG;
require_once($CFG->libdir.'/filelib.php');
$dir = 'ods/'.time();
make_temp_directory($dir);
make_temp_directory($dir.'/META-INF');
$dir = "$CFG->tempdir/$dir";
$files = array();
$handle = fopen("$dir/mimetype", 'w');
fwrite($handle, get_ods_mimetype());
$files[] = "$dir/mimetype";
$handle = fopen("$dir/content.xml", 'w');
fwrite($handle, get_ods_content($this->worksheets));
$files[] = "$dir/content.xml";
$handle = fopen("$dir/meta.xml", 'w');
fwrite($handle, get_ods_meta());
$files[] = "$dir/meta.xml";
$handle = fopen("$dir/styles.xml", 'w');
fwrite($handle, get_ods_styles());
$files[] = "$dir/styles.xml";
$handle = fopen("$dir/META-INF/manifest.xml", 'w');
fwrite($handle, get_ods_manifest());
$files[] = "$dir/META-INF";
$filename = "$dir/result.ods";
zip_files($files, $filename);
$handle = fopen($filename, 'rb');
$contents = fread($handle, filesize($filename));
fclose($handle);
remove_dir($dir); // cleanup the temp directory
send_file($contents, $this->filename, 0, 0, true, true, 'application/vnd.oasis.opendocument.spreadsheet');
}
/* Not required to use
* @param string $name Name of the downloaded file
*/
function send($filename) {
$this->filename = $filename;
}
}
/**
*
* @package moodlecore
* @copyright 1999 onwards Martin Dougiamas {@link http://moodle.com}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class MoodleODSWorksheet {
var $data = array();
var $columns = array();
var $rows = array();
var $name;
/* Constructs one Moodle Worksheet.
* @param string $filename The name of the file
*/
function MoodleODSWorksheet($name) {
$this->name = $name;
}
/* Write one string somewhere in the worksheet
* @param integer $row Zero indexed row
* @param integer $col Zero indexed column
* @param string $str The string to write
* @param mixed $format The XF format for the cell
*/
function write_string($row, $col, $str, $format=0) {
if (!array_key_exists($row, $this->data)) {
$this->data[$row] = array();
}
$this->data[$row][$col] = new stdClass();
$this->data[$row][$col]->value = $str;
$this->data[$row][$col]->type = 'string';
$this->data[$row][$col]->format = $format;
}
/* Write one number somewhere in the worksheet
* @param integer $row Zero indexed row
* @param integer $col Zero indexed column
* @param float $num The number to write
* @param mixed $format The XF format for the cell
*/
function write_number($row, $col, $num, $format=0) {
if (!array_key_exists($row, $this->data)) {
$this->data[$row] = array();
}
$this->data[$row][$col] = new stdClass();
$this->data[$row][$col]->value = $num;
$this->data[$row][$col]->type = 'float';
$this->data[$row][$col]->format = $format;
}
/* Write one url somewhere in the worksheet
* @param integer $row Zero indexed row
* @param integer $col Zero indexed column
* @param string $url The url to write
* @param mixed $format The XF format for the cell
*/
function write_url($row, $col, $url, $format=0) {
if (!array_key_exists($row, $this->data)) {
$this->data[$row] = array();
}
$this->data[$row][$col] = new stdClass();
$this->data[$row][$col]->value = $url;
$this->data[$row][$col]->type = 'string';
$this->data[$row][$col]->format = $format;
}
/* Write one date somewhere in the worksheet
* @param integer $row Zero indexed row
* @param integer $col Zero indexed column
* @param string $url The url to write
* @param mixed $format The XF format for the cell
*/
function write_date($row, $col, $date, $format=0) {
if (!array_key_exists($row, $this->data)) {
$this->data[$row] = array();
}
$this->data[$row][$col] = new stdClass();
$this->data[$row][$col]->value = $date;
$this->data[$row][$col]->type = 'date';
$this->data[$row][$col]->format = $format;
}
/**
* Write one formula somewhere in the worksheet
*
* @param integer $row Zero indexed row
* @param integer $col Zero indexed column
* @param string $formula The formula to write
* @param mixed $format The XF format for the cell
*/
function write_formula($row, $col, $formula, $format=null) {
// not implement
}
/* Write one blanck somewhere in the worksheet
* @param integer $row Zero indexed row
* @param integer $col Zero indexed column
* @param mixed $format The XF format for the cell
*/
function write_blank($row, $col, $format=0) {
if (array_key_exists($row, $this->data)) {
unset($this->data[$row][$col]);
}
}
/* Write anything somewhere in the worksheet
* Type will be automatically detected
* @param integer $row Zero indexed row
* @param integer $col Zero indexed column
* @param mixed $token What we are writing
* @param mixed $format The XF format for the cell
*/
function write($row, $col, $token, $format=0) {
/// Analyse what are we trying to send
if (preg_match("/^([+-]?)(?=\d|\.\d)\d*(\.\d*)?([Ee]([+-]?\d+))?$/", $token)) {
/// Match number
return $this->write_number($row, $col, $token, $format);
} elseif (preg_match("/^[fh]tt?p:\/\//", $token)) {
/// Match http or ftp URL
return $this->write_url($row, $col, $token, '', $format);
} elseif (preg_match("/^mailto:/", $token)) {
/// Match mailto:
return $this->write_url($row, $col, $token, '', $format);
} elseif (preg_match("/^(?:in|ex)ternal:/", $token)) {
/// Match internal or external sheet link
return $this->write_url($row, $col, $token, '', $format);
} elseif (preg_match("/^=/", $token)) {
/// Match formula
return $this->write_formula($row, $col, $token, $format);
} elseif (preg_match("/^@/", $token)) {
/// Match formula
return $this->write_formula($row, $col, $token, $format);
} elseif ($token == '') {
/// Match blank
return $this->write_blank($row, $col, $format);
} else {
/// Default: match string
return $this->write_string($row, $col, $token, $format);
}
}
/* Sets the height (and other settings) of one row
* @param integer $row The row to set
* @param integer $height Height we are giving to the row (null to set just format withouth setting the height)
* @param mixed $format The optional XF format we are giving to the row
* @param bool $hidden The optional hidden attribute
* @param integer $level The optional outline level (0-7)
*/
function set_row($row, $height, $format = 0, $hidden = false, $level = 0) {
$this->rows[$row] = new stdClass();
$this->rows[$row]->height = $height;
//$this->rows[$row]->format = $format; // TODO: fix and enable
$this->rows[$row]->hidden = $hidden;
}
/* Sets the width (and other settings) of one column
* @param integer $firstcol first column on the range
* @param integer $lastcol last column on the range
* @param integer $width width to set
* @param mixed $format The optional XF format to apply to the columns
* @param integer $hidden The optional hidden atribute
* @param integer $level The optional outline level (0-7)
*/
function set_column($firstcol, $lastcol, $width, $format = 0, $hidden = false, $level = 0) {
for($i=$firstcol; $i<=$lastcol; $i++) {
$this->columns[$i] = new stdClass();
$this->columns[$i]->width = $width;
//$this->columns[$i]->format = $format; // TODO: fix and enable
$this->columns[$i]->hidden = $hidden;
}
}
/**
* Set the option to hide gridlines on the printed page.
*
* @access public
*/
function hide_gridlines() {
// not implement
}
/**
* Set the option to hide gridlines on the worksheet (as seen on the screen).
*
* @access public
*/
function hide_screen_gridlines() {
// not implement
}
/**
* Insert a 24bit bitmap image in a worksheet.
*
* @access public
* @param integer $row The row we are going to insert the bitmap into
* @param integer $col The column we are going to insert the bitmap into
* @param string $bitmap The bitmap filename
* @param integer $x The horizontal position (offset) of the image inside the cell.
* @param integer $y The vertical position (offset) of the image inside the cell.
* @param integer $scale_x The horizontal scale
* @param integer $scale_y The vertical scale
*/
function insert_bitmap($row, $col, $bitmap, $x = 0, $y = 0, $scale_x = 1, $scale_y = 1) {
// not implement
}
/**
* Merges the area given by its arguments.
* merging than the normal setAlign('merge').
*
* @access public
* @param integer $first_row First row of the area to merge
* @param integer $first_col First column of the area to merge
* @param integer $last_row Last row of the area to merge
* @param integer $last_col Last column of the area to merge
*/
function merge_cells($first_row, $first_col, $last_row, $last_col) {
// not implement
}
}
/**
* Define and operate over one Format.
*
* @package moodlecore
* @copyright 1999 onwards Martin Dougiamas {@link http://moodle.com}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class MoodleODSFormat {
var $id;
var $properties;
/* Constructs one Moodle Format.
* @param object $workbook The internal PEAR Workbook onject we are creating
*/
function MoodleODSFormat($properties = array()) {
static $fid = 1;
$this->id = $fid++;
foreach($properties as $property => $value) {
if(method_exists($this,"set_$property")) {
$aux = 'set_'.$property;
$this->$aux($value);
}
}
}
/* Set weight of the format
* @param integer $weight Weight for the text, 0 maps to 400 (normal text),
* 1 maps to 700 (bold text). Valid range is: 100-1000.
* It's Optional, default is 1 (bold).
*/
function set_bold($weight = 1) {
$this->properties['bold'] = $weight;
}
/* Set underline of the format
* @param integer $underline The value for underline. Possible values are:
* 1 => underline, 2 => double underline
*/
function set_underline($underline = 1) {
$this->properties['underline'] = $underline;
}
/* Set italic of the format
*/
function set_italic() {
$this->properties['italic'] = true;
}
/* Set strikeout of the format
*/
function set_strikeout() {
$this->properties['strikeout'] = true;
}
/* Set outlining of the format
*/
function set_outline() {
}
/* Set shadow of the format
*/
function set_shadow() {
}
/* Set the script of the text
* @param integer $script The value for script type. Possible values are:
* 1 => superscript, 2 => subscript
*/
function set_script($script) {
}
/* Set color of the format
* @param mixed $color either a string (like 'blue'), or an integer (range is [8...63])
*/
function set_color($color) {
$this->properties['color'] = $this->_get_color($color);
}
/* Set foreground color of the format
* @param mixed $color either a string (like 'blue'), or an integer (range is [8...63])
*/
function set_fg_color($color) {
}
/* Set background color of the format
* @param mixed $color either a string (like 'blue'), or an integer (range is [8...63])
*/
function set_bg_color($color) {
$this->properties['bg_color'] = $this->_get_color($color);
}
/* Set the fill pattern of the format
* @param integer Optional. Defaults to 1. Meaningful values are: 0-18
* 0 meaning no background.
*/
function set_pattern($pattern=1) {
}
/* Set text wrap of the format
*/
function set_text_wrap() {
}
/* Set the cell alignment of the format
* @param string $location alignment for the cell ('left', 'right', etc...)
*/
function set_align($location) {
switch ($location) {
case 'start':
case 'left':
$this->properties['align'] = 'start';
break;
case 'center':
$this->properties['align'] = 'center';
break;
case 'end':
case 'right':
$this->properties['align'] = 'end';
break;
default:
//ignore the rest == start
}
}
/* Set the cell horizontal alignment of the format
* @param string $location alignment for the cell ('left', 'right', etc...)
*/
function set_h_align($location) {
$this->set_align($location);
}
/* Set the cell vertical alignment of the format
* @param string $location alignment for the cell ('top', 'vleft', etc...)
*/
function set_v_align($location) {
switch ($location) {
case 'top':
$this->properties['v_align'] = 'top';
break;
case 'bottom':
$this->properties['v_align'] = 'bottom';
break;
default:
//ignore the rest == middle
}
}
/* Set the top border of the format
* @param integer $style style for the cell. 1 => thin, 2 => thick
*/
function set_top($style) {
}
/* Set the bottom border of the format
* @param integer $style style for the cell. 1 => thin, 2 => thick
*/
function set_bottom($style) {
}
/* Set the left border of the format
* @param integer $style style for the cell. 1 => thin, 2 => thick
*/
function set_left($style) {
}
/* Set the right border of the format
* @param integer $style style for the cell. 1 => thin, 2 => thick
*/
function set_right($style) {
}
/**
* Set cells borders to the same style
* @param integer $style style to apply for all cell borders. 1 => thin, 2 => thick.
*/
function set_border($style) {
}
/* Set the numerical format of the format
* It can be date, time, currency, etc...
/* Set the numerical format of the format
* It can be date, time, currency, etc...
* @param integer $num_format The numeric format
*/
function set_num_format($num_format) {
}
function _get_color($name_color = '') {
if (strpos($name_color, '#') === 0) {
return $name_color; // no conversion needed
}
$colors = array('aqua' => '#00FFFF',
'cyan' => '#00FFFF',
'black' => '#FFFFFF',
'blue' => '#0000FF',
'brown' => '#A52A2A',
'magenta' => '#FF00FF',
'fuchsia' => '#FF00FF',
'gray' => '#A0A0A0',
'grey' => '#A0A0A0',
'green' => '#00FF00',
'lime' => '#00FF00',
'navy' => '#000080',
'orange' => '#FF8000',
'purple' => '#800080',
'red' => '#FF0000',
'silver' => '#DCDCDC',
'white' => '#FFFFFF',
'yellow' => '#FFFF00');
if(array_key_exists($name_color, $colors)) {
return $colors[$name_color];
} else {
return false;
}
}
}
//=============================
// OpenDocument XML functions
//=============================
function get_ods_content(&$worksheets) {
// find out the size of worksheets and used styles
$formats = array();
$formatstyles = '';
$rowstyles = '';
$colstyles = '';
foreach($worksheets as $wsnum=>$ws) {
$worksheets[$wsnum]->maxr = 0;
$worksheets[$wsnum]->maxc = 0;
foreach($ws->data as $rnum=>$row) {
if ($rnum > $worksheets[$wsnum]->maxr) {
$worksheets[$wsnum]->maxr = $rnum;
}
foreach($row as $cnum=>$cell) {
if ($cnum > $worksheets[$wsnum]->maxc) {
$worksheets[$wsnum]->maxc = $cnum;
}
if (!empty($cell->format)) {
if (!array_key_exists($cell->format->id, $formats)) {
$formats[$cell->format->id] = $cell->format;
}
}
}
}
foreach($ws->rows as $rnum=>$row) {
if (!empty($row->format)) {
if (!array_key_exists($row->format->id, $formats)) {
$formats[$row->format->id] = $row->format;
}
}
if ($rnum > $worksheets[$wsnum]->maxr) {
$worksheets[$wsnum]->maxr = $rnum;
}
//define all column styles
if (!empty($ws->rows[$rnum])) {
$rowstyles .= '
';
}
}
foreach($ws->columns as $cnum=>$col) {
if (!empty($col->format)) {
if (!array_key_exists($col->format->id, $formats)) {
$formats[$col->format->id] = $col->format;
}
}
if ($cnum > $worksheets[$wsnum]->maxc) {
$worksheets[$wsnum]->maxc = $cnum;
}
//define all column styles
if (!empty($ws->columns[$cnum])) {
$colstyles .= '
';
}
}
}
foreach($formats as $format) {
$textprop = '';
$cellprop = '';
$parprop = '';
foreach($format->properties as $pname=>$pvalue) {
switch ($pname) {
case 'bold':
if (!empty($pvalue)) {
$textprop .= ' fo:font-weight="bold"';
}
break;
case 'italic':
if (!empty($pvalue)) {
$textprop .= ' fo:font-style="italic"';
}
break;
case 'underline':
if (!empty($pvalue)) {
$textprop .= ' style:text-underline-color="font-color" style:text-underline-style="solid" style:text-underline-width="auto"';
}
break;
case 'strikeout':
if (!empty($pvalue)) {
$textprop .= ' style:text-line-through-style="solid"';
}
break;
case 'color':
if ($pvalue !== false) {
$textprop .= ' fo:color="'.$pvalue.'"';
}
break;
case 'bg_color':
if ($pvalue !== false) {
$cellprop .= ' fo:background-color="'.$pvalue.'"';
}
break;
case 'align':
$parprop .= ' fo:text-align="'.$pvalue.'"';
break;
case 'v_align':
$cellprop .= ' style:vertical-align="'.$pvalue.'"';
break;
}
}
if (!empty($textprop)) {
$textprop = '
';
}
if (!empty($cellprop)) {
$cellprop = '
';
}
if (!empty($parprop)) {
$parprop = '
';
}
$formatstyles .= '
'.$textprop.$cellprop.$parprop.'
';
}
/// header
$buffer =
'
';
$buffer .= $formatstyles;
$buffer .= $rowstyles;
$buffer .= $colstyles;
$buffer .= '
';
foreach($worksheets as $wsnum=>$ws) {
/// worksheet header
$buffer .= ''."\n";
// define column properties
for($c=0; $c<=$ws->maxc; $c++) {
if (array_key_exists($c, $ws->columns)) {
$extra = '';
if (!empty($ws->columns[$c]->format)) {
$extra .= ' table:default-cell-style-name="format'.$ws->columns[$c]->format->id.'"';
}
if ($ws->columns[$c]->hidden) {
$extra .= ' table:visibility="collapse"';
}
$buffer .= ''."\n";
} else {
$buffer .= ''."\n";
}
}
// print all rows
for($r=0; $r<=$ws->maxr; $r++) {
if (array_key_exists($r, $ws->rows)) {
$extra = '';
if (!empty($ws->rows[$r]->format)) {
$extra .= ' table:default-cell-style-name="format'.$ws->rows[$r]->format->id.'"';
}
if ($ws->rows[$r]->hidden) {
$extra .= ' table:visibility="collapse"';
}
$buffer .= ''."\n";
} else {
$buffer .= ''."\n";
}
for($c=0; $c<=$ws->maxc; $c++) {
if (isset($ws->data[$r][$c])) {
$cell = $ws->data[$r][$c];
$extra = ' ';
if (!empty($cell->format)) {
$extra = ' table:style-name="format'.$cell->format->id.'"';
}
if ($cell->type == 'date') {
$buffer .= ''
. '' . strftime('%Y-%m-%dT%H:%M:%S', $cell->value) . ''
. ''."\n";
} else if ($cell->type == 'float') {
$buffer .= ''
. '' . htmlspecialchars($cell->value) . ''
. ''."\n";
} else if ($cell->type == 'string') {
$buffer .= ''
. '' . htmlspecialchars($cell->value) . ''
. ''."\n";
} else {
$buffer .= ''
. '!!Error - unknown type!!'
. ''."\n";
}
} else {
$buffer .= ''."\n";
}
}
$buffer .= ''."\n";
}
/// worksheet footer
$buffer .= ''."\n";
}
/// footer
$buffer .=
'
';
return $buffer;
}
function get_ods_mimetype() {
return 'application/vnd.oasis.opendocument.spreadsheet';
}
function get_ods_meta() {
global $CFG, $USER;
return
'
Moodle '.$CFG->version.'
'.fullname($USER, true).'
1
'.strftime('%Y-%m-%dT%H:%M:%S').'
'.strftime('%Y-%m-%dT%H:%M:%S').'
'.fullname($USER, true).'
';
}
function get_ods_styles() {
return
'
???
Page
1
';
}
function get_ods_manifest() {
return
'
';
}