a1a2b5adba919c6c91ea3a4274f9e70f55786d51
[moodle.git] / lib / excellib.class.php
1 <?php
3 // This file is part of Moodle - http://moodle.org/
4 //
5 // Moodle is free software: you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation, either version 3 of the License, or
8 // (at your option) any later version.
9 //
10 // Moodle is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
18 /**
19  * excellib.class.php
20  *
21  * @copyright  (C) 2001-3001 Eloy Lafuente (stronk7) {@link http://contiento.com}
22  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23  * @package    core
24  * @subpackage lib
25  */
27 defined('MOODLE_INTERNAL') || die();
29 /** setup.php includes our hacked pear libs first */
30 require_once 'Spreadsheet/Excel/Writer.php';
32 /**
33  * Define and operate over one Moodle Workbook.
34  *
35  * A big part of this class acts as a wrapper over the PEAR
36  * Spreadsheet_Excel_Writer_Workbook and OLE libraries
37  * maintaining Moodle functions isolated from underlying code.
38  *
39  * @copyright 1999 onwards Martin Dougiamas  {@link http://moodle.com}
40  * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
41  * @package moodlecore
42  */
43 class MoodleExcelWorkbook {
44     /** @var object */
45     var $pear_excel_workbook;
46     /** @var bool */
47     var $latin_output;
49     /**
50      * Constructs one Moodle Workbook.
51      *
52      * @global object
53      * @param string $filename The name of the file
54      */
55     function MoodleExcelWorkbook($filename) {
56         global $CFG;
57     /// Internally, create one PEAR Spreadsheet_Excel_Writer_Workbook class
58         $this->pear_excel_workbook = new Spreadsheet_Excel_Writer($filename);
59     /// Prepare it to accept UTF-16LE data and to encode it properly
60         if (empty($CFG->latinexcelexport)) { /// Only if don't want to use latin (win1252) stronger output
61             $this->pear_excel_workbook->setVersion(8);
62             $this->latin_output = false;
63         } else { /// We want latin (win1252) output
64             $this->latin_output = true;
65         }
66     /// Choose our temporary directory - see MDL-7176, found by paulo.matos
67         make_upload_directory('temp/excel');
68         $this->pear_excel_workbook->setTempDir($CFG->dataroot.'/temp/excel');
69     }
71     /**
72      * Create one Moodle Worksheet
73      *
74      * @param string $name Name of the sheet
75      * @return object MoodleExcelWorksheet
76      */
77     function &add_worksheet($name = '') {
78     /// Create the Moodle Worksheet. Returns one pointer to it
79         $ws = new MoodleExcelWorksheet ($name, $this->pear_excel_workbook, $this->latin_output);
80         return $ws;
81     }
83     /**
84      * Create one Moodle Format
85      *
86      * @param array $properties array of properties [name]=value;
87      *                          valid names are set_XXXX existing
88      *                          functions without the set_ part
89      *                          i.e: [bold]=1 for set_bold(1)...Optional!
90      * @return object MoodleExcelFormat
91      */
92     function &add_format($properties = array()) {
93     /// Create the Moodle Format. Returns one pointer to it
94         $ft = new MoodleExcelFormat ($this->pear_excel_workbook, $properties);
95         return $ft;
96     }
98     /**
99      * Close the Moodle Workbook
100      */
101     function close() {
102         $this->pear_excel_workbook->close();
103     }
105     /**
106      * Write the correct HTTP headers
107      *
108      * @param string $filename Name of the downloaded file
109      */
110     function send($filename) {
111         $this->pear_excel_workbook->send($filename);
112     }
115 /**
116  * Define and operate over one Worksheet.
117  *
118  * A big part of this class acts as a wrapper over the PEAR
119  * Spreadsheet_Excel_Writer_Workbook and OLE libraries
120  * maintaining Moodle functions isolated from underlying code.
121  *
122  * @copyright 1999 onwards Martin Dougiamas  {@link http://moodle.com}
123  * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
124  * @package moodlecore
125  */
126 class MoodleExcelWorksheet {
127     /** @var object */
128     var $pear_excel_worksheet;
129     /** @var bool Only if don't want to use latin (win1252) stronger output */
130     var $latin_output;
132     /**
133      * Constructs one Moodle Worksheet.
134      *
135      * @param string $filename The name of the file
136      * @param object $workbook The internal PEAR Workbook onject we are creating
137      * @param bool $latin_output Only if don't want to use latin (win1252) stronger output
138      */
139     function MoodleExcelWorksheet($name, &$workbook, $latin_output=false) {
141     /// Internally, add one sheet to the workbook
142         $this->pear_excel_worksheet =& $workbook->addWorksheet($name);
143         $this->latin_output = $latin_output;
144     /// Set encoding to UTF-16LE
145         if (!$this->latin_output) { /// Only if don't want to use latin (win1252) stronger output
146             $this->pear_excel_worksheet->setInputEncoding('UTF-16LE');
147         }
148     }
150     /**
151      * Write one string somewhere in the worksheet
152      *
153      * @param integer $row    Zero indexed row
154      * @param integer $col    Zero indexed column
155      * @param string  $str    The string to write
156      * @param mixed   $format The XF format for the cell
157      */
158     function write_string($row, $col, $str, $format=null) {
159     /// Calculate the internal PEAR format
160         $format = $this->MoodleExcelFormat2PearExcelFormat($format);
161     /// Loading the textlib singleton instance. We are going to need it.
162         $textlib = textlib_get_instance();
163     /// Convert the text from its original encoding to UTF-16LE
164         if (!$this->latin_output) { /// Only if don't want to use latin (win1252) stronger output
165             $str = $textlib->convert($str, 'utf-8', 'utf-16le');
166         } else { /// else, convert to latin (win1252)
167             $str = $textlib->convert($str, 'utf-8', 'windows-1252');
168         }
169     /// Add the string safely to the PEAR Worksheet
170         $this->pear_excel_worksheet->writeString($row, $col, $str, $format);
171     }
173     /**
174      * Write one number somewhere in the worksheet
175      *
176      * @param integer $row    Zero indexed row
177      * @param integer $col    Zero indexed column
178      * @param float   $num    The number to write
179      * @param mixed   $format The XF format for the cell
180      */
181     function write_number($row, $col, $num, $format=null) {
182     /// Calculate the internal PEAR format
183         $format = $this->MoodleExcelFormat2PearExcelFormat($format);
184     /// Add  the number safely to the PEAR Worksheet
185         $this->pear_excel_worksheet->writeNumber($row, $col, $num, $format);
186     }
188     /**
189      * Write one url somewhere in the worksheet
190      *
191      * @param integer $row    Zero indexed row
192      * @param integer $col    Zero indexed column
193      * @param string  $url    The url to write
194      * @param mixed   $format The XF format for the cell
195      */
196     function write_url($row, $col, $url, $format=null) {
197     /// Calculate the internal PEAR format
198         $format = $this->MoodleExcelFormat2PearExcelFormat($format);
199     /// Add  the url safely to the PEAR Worksheet
200         $this->pear_excel_worksheet->writeUrl($row, $col, $url, $format);
201     }
203     /**
204      * Write one date somewhere in the worksheet
205      * @param integer $row    Zero indexed row
206      * @param integer $col    Zero indexed column
207      * @param string  $date   The date to write in UNIX timestamp format
208      * @param mixed   $format The XF format for the cell
209      */
210     function write_date($row, $col, $date, $format=null) {
211     /// Calculate the internal PEAR format
212         $format = $this->MoodleExcelFormat2PearExcelFormat($format);
213     /// Convert the date to Excel format
214         $timezone = get_user_timezone_offset();
215         $value =  ((usertime($date) + (int)($timezone * HOURSECS * 2)) / 86400) + 25569;
216     /// Add  the date safely to the PEAR Worksheet
217         $this->pear_excel_worksheet->writeNumber($row, $col, $value, $format);
218     }
220     /**
221      * Write one formula somewhere in the worksheet
222      *
223      * @param integer $row    Zero indexed row
224      * @param integer $col    Zero indexed column
225      * @param string  $formula The formula to write
226      * @param mixed   $format The XF format for the cell
227      */
228     function write_formula($row, $col, $formula, $format=null) {
229     /// Calculate the internal PEAR format
230         $format = $this->MoodleExcelFormat2PearExcelFormat($format);
231     /// Add  the formula safely to the PEAR Worksheet
232         $this->pear_excel_worksheet->writeFormula($row, $col, $formula, $format);
233     }
235     /**
236      * Write one blanck somewhere in the worksheet
237      *
238      * @param integer $row    Zero indexed row
239      * @param integer $col    Zero indexed column
240      * @param mixed   $format The XF format for the cell
241      */
242     function write_blank($row, $col, $format=null) {
243     /// Calculate the internal PEAR format
244         $format = $this->MoodleExcelFormat2PearExcelFormat($format);
245     /// Add  the blank safely to the PEAR Worksheet
246         $this->pear_excel_worksheet->writeBlank($row, $col, $format);
247     }
249     /**
250      * Write anything somewhere in the worksheet
251      * Type will be automatically detected
252      *
253      * @param integer $row    Zero indexed row
254      * @param integer $col    Zero indexed column
255      * @param mixed   $token  What we are writing
256      * @param mixed   $format The XF format for the cell
257      * @return void
258      */
259     function write($row, $col, $token, $format=null) {
261     /// Analyse what are we trying to send
262         if (preg_match("/^([+-]?)(?=\d|\.\d)\d*(\.\d*)?([Ee]([+-]?\d+))?$/", $token)) {
263         /// Match number
264             return $this->write_number($row, $col, $token, $format);
265         } elseif (preg_match("/^[fh]tt?p:\/\//", $token)) {
266         /// Match http or ftp URL
267             return $this->write_url($row, $col, $token, '', $format);
268         } elseif (preg_match("/^mailto:/", $token)) {
269         /// Match mailto:
270             return $this->write_url($row, $col, $token, '', $format);
271         } elseif (preg_match("/^(?:in|ex)ternal:/", $token)) {
272         /// Match internal or external sheet link
273             return $this->write_url($row, $col, $token, '', $format);
274         } elseif (preg_match("/^=/", $token)) {
275         /// Match formula
276             return $this->write_formula($row, $col, $token, $format);
277         } elseif (preg_match("/^@/", $token)) {
278         /// Match formula
279             return $this->write_formula($row, $col, $token, $format);
280         } elseif ($token == '') {
281         /// Match blank
282             return $this->write_blank($row, $col, $format);
283         } else {
284         /// Default: match string
285             return $this->write_string($row, $col, $token, $format);
286         }
287     }
289     /**
290      * Sets the height (and other settings) of one row
291      *
292      * @param integer $row    The row to set
293      * @param integer $height Height we are giving to the row (null to set just format withouth setting the height)
294      * @param mixed   $format The optional XF format we are giving to the row
295      * @param bool    $hidden The optional hidden attribute
296      * @param integer $level  The optional outline level (0-7)
297      */
298     function set_row ($row, $height, $format = null, $hidden = false, $level = 0) {
299     /// Calculate the internal PEAR format
300         $format = $this->MoodleExcelFormat2PearExcelFormat($format);
301     /// Set the row safely to the PEAR Worksheet
302         $this->pear_excel_worksheet->setRow($row, $height, $format, $hidden, $level);
303     }
305     /**
306      * Sets the width (and other settings) of one column
307      *
308      * @param integer $firstcol first column on the range
309      * @param integer $lastcol  last column on the range
310      * @param integer $width    width to set
311      * @param mixed   $format   The optional XF format to apply to the columns
312      * @param integer $hidden   The optional hidden atribute
313      * @param integer $level    The optional outline level (0-7)
314      */
315     function set_column ($firstcol, $lastcol, $width, $format = null, $hidden = false, $level = 0) {
316     /// Calculate the internal PEAR format
317         $format = $this->MoodleExcelFormat2PearExcelFormat($format);
318     /// Set the column safely to the PEAR Worksheet
319         $this->pear_excel_worksheet->setColumn($firstcol, $lastcol, $width, $format, $hidden, $level);
320     }
322     /**
323     * Set the option to hide gridlines on the printed page.
324     *
325     * @access public
326     */
327     function hide_gridlines() {
328         $this->pear_excel_worksheet->hideGridLines();
329     }
331     /**
332     * Set the option to hide gridlines on the worksheet (as seen on the screen).
333     *
334     * @access public
335     */
336     function hide_screen_gridlines() {
337         $this->pear_excel_worksheet->hideScreenGridlines();
338     }
340     /**
341     * Insert a 24bit bitmap image in a worksheet.
342     *
343     * @access public
344     * @param integer $row     The row we are going to insert the bitmap into
345     * @param integer $col     The column we are going to insert the bitmap into
346     * @param string  $bitmap  The bitmap filename
347     * @param integer $x       The horizontal position (offset) of the image inside the cell.
348     * @param integer $y       The vertical position (offset) of the image inside the cell.
349     * @param integer $scale_x The horizontal scale
350     * @param integer $scale_y The vertical scale
351     */
352     function insert_bitmap($row, $col, $bitmap, $x = 0, $y = 0, $scale_x = 1, $scale_y = 1) {
353     /// Add the bitmap safely to the PEAR Worksheet
354         $this->pear_excel_worksheet->insertBitmap($row, $col, $bitmap, $x, $y, $scale_x, $scale_y);
355     }
357     /**
358     * Merges the area given by its arguments.
359     * This is an Excel97/2000 method. It is required to perform more complicated
360     * merging than the normal setAlign('merge').
361     *
362     * @access public
363     * @param integer $first_row First row of the area to merge
364     * @param integer $first_col First column of the area to merge
365     * @param integer $last_row  Last row of the area to merge
366     * @param integer $last_col  Last column of the area to merge
367     */
368     function merge_cells($first_row, $first_col, $last_row, $last_col) {
369         /// Merge cells safely to the PEAR Worksheet
370         $this->pear_excel_worksheet->mergeCells($first_row, $first_col, $last_row, $last_col);
371     }
373     /**
374      * Returns the PEAR Excel Format for one Moodle Excel Format
375      *
376      * @param mixed $format MoodleExcelFormat object
377      * @return mixed PEAR Excel Format object
378      */
379     function MoodleExcelFormat2PearExcelFormat($format) {
380         if ($format) {
381             return $format->pear_excel_format;
382         } else {
383             return null;
384         }
385     }
389 /**
390  * Define and operate over one Format.
391  *
392  * A big part of this class acts as a wrapper over the PEAR
393  * Spreadsheet_Excel_Writer_Workbook and OLE libraries
394  * maintaining Moodle functions isolated from underlying code.
395  *
396  * @copyright 1999 onwards Martin Dougiamas  {@link http://moodle.com}
397  * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
398  * @package moodlecore
399  */
400 class MoodleExcelFormat {
401     /** @var object */
402     var $pear_excel_format;
404     /**
405      * Constructs one Moodle Format.
406      *
407      * @param object $workbook The internal PEAR Workbook onject we are creating
408      * @param array $properties
409      */
410     function MoodleExcelFormat(&$workbook, $properties = array()) {
411     /// Internally, add one sheet to the workbook
412         $this->pear_excel_format =& $workbook->addFormat();
413     /// If we have something in the array of properties, compute them
414         foreach($properties as $property => $value) {
415             if(method_exists($this,"set_$property")) {
416                 $aux = 'set_'.$property;
417                 $this->$aux($value);
418             }
419         }
420     }
422     /**
423      * Set the size of the text in the format (in pixels).
424      * By default all texts in generated sheets are 10px.
425      *
426      * @param integer $size Size of the text (in pixels)
427      */
428     function set_size($size) {
429     /// Set the size safely to the PEAR Format
430         $this->pear_excel_format->setSize($size);
431     }
433     /**
434      * Set weight of the format
435      *
436      * @param integer $weight Weight for the text, 0 maps to 400 (normal text),
437      *                        1 maps to 700 (bold text). Valid range is: 100-1000.
438      *                        It's Optional, default is 1 (bold).
439      */
440     function set_bold($weight = 1) {
441     /// Set the bold safely to the PEAR Format
442         $this->pear_excel_format->setBold($weight);
443     }
445     /**
446      * Set underline of the format
447      *
448      * @param integer $underline The value for underline. Possible values are:
449      *                           1 => underline, 2 => double underline
450      */
451     function set_underline($underline) {
452     /// Set the underline safely to the PEAR Format
453         $this->pear_excel_format->setUnderline($underline);
454     }
456     /**
457      * Set italic of the format
458      */
459     function set_italic() {
460     /// Set the italic safely to the PEAR Format
461         $this->pear_excel_format->setItalic();
462     }
464     /**
465      * Set strikeout of the format
466      */
467     function set_strikeout() {
468     /// Set the strikeout safely to the PEAR Format
469         $this->pear_excel_format->setStrikeOut();
470     }
472     /**
473      * Set outlining of the format
474      */
475     function set_outline() {
476     /// Set the outlining safely to the PEAR Format
477         $this->pear_excel_format->setOutLine();
478     }
480     /**
481      * Set shadow of the format
482      */
483     function set_shadow() {
484     /// Set the shadow safely to the PEAR Format
485         $this->pear_excel_format->setShadow();
486     }
488     /**
489      * Set the script of the text
490      *
491      * @param integer $script The value for script type. Possible values are:
492      *                        1 => superscript, 2 => subscript
493      */
494     function set_script($script) {
495     /// Set the script safely to the PEAR Format
496         $this->pear_excel_format->setScript($script);
497     }
499     /**
500      * Set color of the format. Used to specify the color of the text to be formatted.
501      *
502      * @param mixed $color either a string (like 'blue'), or an integer (range is [8...63])
503      */
504     function set_color($color) {
505     /// Set the background color safely to the PEAR Format
506         $this->pear_excel_format->setColor($color);
507     }
509     /**
510      * Set foreground color (top layer) of the format. About formatting colors note that cells backgrounds
511      * have TWO layers, in order to support patterns and paint them with two diferent colors.
512      * This method set the color of the TOP layer of the background format. So, when filling
513      * cells with plain colors (no patterns) this is the method to use.
514      *
515      * @param mixed $color either a string (like 'blue'), or an integer (range is [8...63])
516      */
517     function set_fg_color($color) {
518     /// Set the foreground color safely to the PEAR Format
519         $this->pear_excel_format->setFgColor($color);
520     }
522     /**
523      * Set background color (bottom layer) of the format. About formatting colors note that cells backgrounds
524      * have TWO layers, in order to support patterns and paint them with two diferent colors.
525      * This method set the color of the BOTTOM layer of the background format. So, the color
526      * specified here only will be visible if using patterns. Use set_fg_color() to fill
527      * cells with plain colors (no patterns).
528      *
529      * @param mixed $color either a string (like 'blue'), or an integer (range is [8...63])
530      */
531     function set_bg_color($color) {
532     /// Set the background color safely to the PEAR Format
533         $this->pear_excel_format->setBgColor($color);
534     }
536     /**
537      * Set the fill pattern of the format
538      * @param integer Optional. Defaults to 1. Meaningful values are: 0-18
539      *                0 meaning no background.
540      */
541     function set_pattern($pattern=1) {
542     /// Set the fill pattern safely to the PEAR Format
543         $this->pear_excel_format->setPattern($pattern);
544     }
546     /**
547      * Set text wrap of the format
548      */
549     function set_text_wrap() {
550     /// Set the shadow safely to the PEAR Format
551         $this->pear_excel_format->setTextWrap();
552     }
554     /**
555      * Set the cell alignment of the format
556      *
557      * @param string $location alignment for the cell ('left', 'right', etc...)
558      */
559     function set_align($location) {
560     /// Set the alignment of the cell safely to the PEAR Format
561         $this->pear_excel_format->setAlign($location);
562     }
564     /**
565      * Set the cell horizontal alignment of the format
566      *
567      * @param string $location alignment for the cell ('left', 'right', etc...)
568      */
569     function set_h_align($location) {
570     /// Set the alignment of the cell safely to the PEAR Format
571         $this->pear_excel_format->setHAlign($location);
572     }
574     /**
575      * Set the cell vertical alignment of the format
576      *
577      * @param string $location alignment for the cell ('top', 'vleft', etc...)
578      */
579     function set_v_align($location) {
580     /// Set the alignment of the cell safely to the PEAR Format
581         $this->pear_excel_format->setVAlign($location);
582     }
584     /**
585      * Set the top border of the format
586      *
587      * @param integer $style style for the cell. 1 => thin, 2 => thick
588      */
589     function set_top($style) {
590     /// Set the top border of the cell safely to the PEAR Format
591         $this->pear_excel_format->setTop($style);
592     }
594     /**
595      * Set the bottom border of the format
596      *
597      * @param integer $style style for the cell. 1 => thin, 2 => thick
598      */
599     function set_bottom($style) {
600     /// Set the bottom border of the cell safely to the PEAR Format
601         $this->pear_excel_format->setBottom($style);
602     }
604     /**
605      * Set the left border of the format
606      *
607      * @param integer $style style for the cell. 1 => thin, 2 => thick
608      */
609     function set_left($style) {
610     /// Set the left border of the cell safely to the PEAR Format
611         $this->pear_excel_format->setLeft($style);
612     }
614     /**
615      * Set the right border of the format
616      *
617      * @param integer $style style for the cell. 1 => thin, 2 => thick
618      */
619     function set_right($style) {
620     /// Set the right border of the cell safely to the PEAR Format
621         $this->pear_excel_format->setRight($style);
622     }
624     /**
625      * Set cells borders to the same style
626      *
627      * @param integer $style style to apply for all cell borders. 1 => thin, 2 => thick.
628      */
629     function set_border($style) {
630     /// Set all the borders of the cell safely to the PEAR Format
631         $this->pear_excel_format->setBorder($style);
632     }
634     /**
635      * Set the numerical format of the format
636      * It can be date, time, currency, etc...
637      *
638      * @param integer $num_format The numeric format
639      */
640     function set_num_format($num_format) {
641     /// Set the numerical format safely to the PEAR Format
642         $this->pear_excel_format->setNumFormat($num_format);
643     }