ILIAS  release_5-4 Revision v5.4.26-12-gabc799a52e6
class.ilExcel.php
Go to the documentation of this file.
1 <?php
2 /* Copyright (c) 1998-2009 ILIAS open source, Extended GPL, see docs/LICENSE */
3 
4 include_once './libs/composer/vendor/autoload.php';
5 
15 
16 /*
17  * Wrapper for Microsoft Excel Import/Export (based on PHPSpreadsheet, formerPHPExcel which is deprecated)
18  *
19  * @author Jörg Lützenkirchen <luetzenkirchen@leifos.com>
20  * @ingroup ServicesExcel
21  */
22 class ilExcel
23 {
27  protected $lng;
28 
32  protected $workbook; // [PhpSpreadsheet]
33 
37  protected $type; // [string]
38 
39  const FORMAT_XML = "Xlsx";
40  const FORMAT_BIFF = "Xls";
41 
47  public function __construct()
48  {
49  global $DIC;
50 
51  $this->lng = $DIC->language();
52  $this->setFormat(self::FORMAT_XML);
53  $this->workbook = new Spreadsheet();
54  $this->workbook->removeSheetByIndex(0);
55  }
56 
57  //
58  // loading files
59  //
60 
65  public function loadFromFile($filename)
66  {
67  $this->workbook = IOFactory::load($filename);
68  }
69 
70  //
71  // type/format
72  //
73 
79  public function getValidFormats()
80  {
81  return array(self::FORMAT_XML, self::FORMAT_BIFF);
82  }
83 
89  public function setFormat($a_format)
90  {
91  if (in_array($a_format, $this->getValidFormats())) {
92  $this->format = $a_format;
93  }
94  }
95 
96 
97  //
98  // sheets
99  //
100 
108  public function addSheet($a_name, $a_activate = true)
109  {
110  #20749
111  // see Worksheet::$_invalidCharacters;
112  $invalid = array('*', ':', '/', '\\', '?', '[', ']', '\'-','\'');
113 
114  $a_name = str_replace($invalid, "", $a_name);
115 
116  // #19056 - phpExcel only allows 31 chars
117  // see https://github.com/PHPOffice/PHPExcel/issues/79
118  $a_name = ilUtil::shortenText($a_name, 31);
119 
120  $sheet = new Worksheet($this->workbook, $a_name);
121  $this->workbook->addSheet($sheet);
122  $new_index = $this->workbook->getSheetCount() - 1;
123 
124  if ((bool) $a_activate) {
125  $this->setActiveSheet($new_index);
126  }
127 
128  return $new_index;
129  }
130 
136  public function setActiveSheet($a_index)
137  {
138  $this->workbook->setActiveSheetIndex($a_index);
139  }
140 
141 
147  public function getSheetCount()
148  {
149  return $this->workbook->getSheetCount();
150  }
151 
152 
158  public function getSheetTitle()
159  {
160  return $this->workbook->getActiveSheet()->getTitle();
161  }
162 
163 
164  //
165  // cells
166  //
167 
174  protected function prepareValue($a_value)
175  {
176  $lng = $this->lng;
177 
178  // :TODO: does this make sense?
179  if (is_bool($a_value)) {
180  $a_value = $this->prepareBooleanValue($a_value);
181  } elseif ($a_value instanceof ilDateTime) {
182  $a_value = $this->prepareDateValue($a_value);
183  } elseif (is_string($a_value)) {
184  $a_value = $this->prepareString($a_value);
185  }
186 
187  return $a_value;
188  }
189 
194  protected function prepareDateValue(ilDateTime $a_value)
195  {
196  switch (true) {
197  case $a_value instanceof ilDate:
198  $a_value = Date::stringToExcel($a_value->get(IL_CAL_DATE));
199  break;
200 
201  default:
202  $a_value = Date::stringToExcel($a_value->get(IL_CAL_DATETIME));
203  break;
204  }
205 
206  return $a_value;
207  }
208 
213  protected function prepareBooleanValue($a_value)
214  {
215  $lng = $this->lng;
216 
217  return $a_value ? $lng->txt('yes') : $lng->txt('no');
218  }
219 
224  protected function prepareString($a_value)
225  {
226  return strip_tags($a_value); // #14542
227  }
228 
235  protected function setDateFormat(Cell $a_cell, $a_value)
236  {
237  if ($a_value instanceof ilDate) {
238  // :TODO: i18n?
239  $a_cell->getStyle()->getNumberFormat()->setFormatCode("dd.mm.yyyy");
240  } elseif ($a_value instanceof ilDateTime) {
241  // :TODO: i18n?
242  $a_cell->getStyle()->getNumberFormat()->setFormatCode("dd.mm.yyyy hh:mm:ss");
243  }
244  }
245 
252  public function setCellByCoordinates($a_coords, $a_value)
253  {
254  if ($a_value instanceof ilDateTime) {
255  $wb = $this->workbook->getActiveSheet()->setCellValue(
256  $a_coords,
257  $this->prepareValue($a_value)
258  );
259  $cell = $wb->getCell($a_coords);
260  $this->setDateFormat($cell, $a_value);
261  } elseif (is_numeric($a_value)) {
262  $this->workbook->getActiveSheet()->setCellValueExplicit(
263  $a_coords,
264  $this->prepareValue($a_value),
265  DataType::TYPE_NUMERIC
266  );
267  } else {
268  $this->workbook->getActiveSheet()->setCellValueExplicit(
269  $a_coords,
270  $this->prepareValue($a_value),
271  DataType::TYPE_STRING
272  );
273  }
274  }
275 
284  public function setCell($a_row, $a_col, $a_value, $a_datatype = null)
285  {
286  $col = $this->columnIndexAdjustment($a_col);
287 
288  if (!is_null($a_datatype)) {
289  $this->workbook->getActiveSheet()->setCellValueExplicitByColumnAndRow(
290  $col,
291  $a_row,
292  $this->prepareValue($a_value),
293  $a_datatype
294  );
295  } elseif ($a_value instanceof ilDateTime) {
296  $wb = $this->workbook->getActiveSheet()->setCellValueByColumnAndRow(
297  $col,
298  $a_row,
299  $this->prepareValue($a_value)
300  );
301  $this->setDateFormat($wb->getCellByColumnAndRow($col, $a_row), $a_value);
302  } elseif (is_numeric($a_value)) {
303  $wb = $this->workbook->getActiveSheet()->setCellValueExplicitByColumnAndRow(
304  $col,
305  $a_row,
306  $this->prepareValue($a_value),
307  DataType::TYPE_NUMERIC
308  );
309  } else {
310  $wb = $this->workbook->getActiveSheet()->setCellValueExplicitByColumnAndRow(
311  $col,
312  $a_row,
313  $this->prepareValue($a_value),
314  DataType::TYPE_STRING
315  );
316  }
317  }
318 
326  public function setCellArray(array $a_values, $a_top_left = "A1", $a_null_value = null)
327  {
328  foreach ($a_values as $row_idx => $cols) {
329  if (is_array($cols)) {
330  foreach ($cols as $col_idx => $col_value) {
331  $a_values[$row_idx][$col_idx] = $this->prepareValue($col_value);
332  }
333  } else {
334  $a_values[$row_idx] = $this->prepareValue($cols);
335  }
336  }
337 
338  $this->workbook->getActiveSheet()->fromArray($a_values, $a_null_value, $a_top_left);
339  }
340 
341 
350  public function getCell($a_row, $a_col)
351  {
352  $col = $this->columnIndexAdjustment($a_col);
353 
354  return $this->workbook->getActiveSheet()->getCellByColumnAndRow($col, $a_row)->getValue();
355  }
356 
357 
363  public function getSheetAsArray()
364  {
365  return $this->workbook->getActiveSheet()->toArray();
366  }
367 
368 
374  public function getColumnCount()
375  {
376  return Coordinate::columnIndexFromString($this->workbook->getActiveSheet()->getHighestDataColumn());
377  }
378 
385  public function getColumnCoord($a_col)
386  {
387  $col = $this->columnIndexAdjustment($a_col);
388 
389  return Coordinate::stringFromColumnIndex($col);
390  }
391 
395  protected function setGlobalAutoSize()
396  {
397  // this may change the active sheet
398  foreach ($this->workbook->getWorksheetIterator() as $worksheet) {
399  $this->workbook->setActiveSheetIndex($this->workbook->getIndex($worksheet));
400  $sheet = $this->workbook->getActiveSheet();
401  $cellIterator = $sheet->getRowIterator()->current()->getCellIterator();
402  $cellIterator->setIterateOnlyExistingCells(true);
403  foreach ($cellIterator as $cell) {
404  $sheet->getColumnDimension($cell->getColumn())->setAutoSize(true);
405  }
406  }
407  }
408 
409  //
410  // deliver/save
411  //
412 
416  protected function prepareStorage($a_file_name)
417  {
418  $this->setGlobalAutoSize();
419  $this->workbook->setActiveSheetIndex(0);
420 
421  switch ($this->format) {
422  case self::FORMAT_BIFF:
423  if (!stristr($a_file_name, ".xls")) {
424  $a_file_name .= ".xls";
425  }
426  break;
427 
428  case self::FORMAT_XML:
429  if (!stristr($a_file_name, ".xlsx")) {
430  $a_file_name .= ".xlsx";
431  }
432  break;
433  }
434 
435  return $a_file_name;
436  }
437 
443  public function sendToClient($a_file_name)
444  {
445  require_once('./Services/FileDelivery/classes/class.ilPHPOutputDelivery.php');
446 
447  $a_file_name = $this->prepareStorage($a_file_name);
448  switch ($this->format) {
449  case self::FORMAT_BIFF:
451  break;
452 
453  case self::FORMAT_XML:
455  break;
456  default:
458  break;
459  }
460  $tmp_name = ilUtil::ilTempnam();
461 
462  $writer = IOFactory::createWriter($this->workbook, $this->format);
463  $writer->save($tmp_name);
464 
465  ilFileDelivery::deliverFileAttached($tmp_name, $a_file_name, $a_mime_type, true);
466  }
467 
473  public function writeToFile($a_file)
474  {
475  $a_file = $this->prepareStorage($a_file);
476 
477  $writer = IOFactory::createWriter($this->workbook, $this->format);
478  $writer->save($a_file);
479  }
480 
481 
486  public function writeToTmpFile()
487  {
488  $writer = IOFactory::createWriter($this->workbook, $this->format);
490  $writer->save($filename);
491 
492  return $filename;
493  }
494 
495  //
496  // style (:TODO: more options?)
497  //
498 
504  public function setBold($a_coords)
505  {
506  $this->workbook->getActiveSheet()->getStyle($a_coords)->getFont()->setBold(true);
507  }
508 
516  public function setColors($a_coords, $a_background, $a_font = null)
517  {
518  $opts = array(
519  'fill' => array(
520  'fillType' => Fill::FILL_SOLID,
521  'color' => array('rgb' => $a_background)
522  )
523  );
524 
525  if ($a_font) {
526  $opts['font'] = array(
527  'color' => array('rgb' => $a_font)
528  );
529  }
530 
531  $this->workbook->getActiveSheet()->getStyle($a_coords)->applyFromArray($opts);
532  }
533 
543  public function setBorders($a_coords, $a_top, $a_right = false, $a_bottom = false, $a_left = false)
544  {
545  $style = $this->workbook->getActiveSheet()->getStyle($a_coords);
546 
547  // :TODO: border styles?
548  if ($a_top) {
549  $style->getBorders()->getTop()->setBorderStyle(Border::BORDER_THIN);
550  }
551  if ($a_right) {
552  $style->getBorders()->getRight()->setBorderStyle(Border::BORDER_THIN);
553  }
554  if ($a_bottom) {
555  $style->getBorders()->getBottom()->setBorderStyle(Border::BORDER_THIN);
556  }
557  if ($a_left) {
558  $style->getBorders()->getLeft()->setBorderStyle(Border::BORDER_THIN);
559  }
560  }
561 
569  public function getCoordByColumnAndRow($pColumn = 1, $pRow = 1)
570  {
571  $col = $this->columnIndexAdjustment($pColumn);
572  $columnLetter = Coordinate::stringFromColumnIndex($col);
573 
574  return $columnLetter . $pRow;
575  }
576 
582  public function addLink($a_row, $a_column, $a_path)
583  {
584  $column = $this->columnIndexAdjustment($a_column);
585 
586  $this->workbook->getActiveSheet()->getCellByColumnAndRow($column, $a_row)->getHyperlink()->setUrl($a_path);
587  }
588 
595  public function columnIndexAdjustment(int $column) : int
596  {
597  return ++$column;
598  }
599 }
getSheetAsArray()
Returns the active sheet as an array.
const FORMAT_BIFF
$style
Definition: example_012.php:70
static shortenText( $a_str, $a_len, $a_dots=false, $a_next_blank=false, $a_keep_extension=false)
shorten a string to given length.
const IL_CAL_DATETIME
global $DIC
Definition: saml.php:7
setActiveSheet($a_index)
Set active sheet.
setDateFormat(Cell $a_cell, $a_value)
Set date format.
prepareString($a_value)
getColumnCount()
Returns the number of columns the sheet contains.
__construct()
Constructor.
prepareBooleanValue($a_value)
setGlobalAutoSize()
Set all existing columns on all sheets to autosize.
prepareStorage($a_file_name)
Prepare workbook for storage/delivery.
getValidFormats()
Get valid file formats.
getCell($a_row, $a_col)
Returns the value of a cell.
Class for single dates.
getColumnCoord($a_col)
Get column "name" from number.
static deliverFileAttached($path_to_file, $download_file_name='', $mime_type='', $delete_file=false)
void
addSheet($a_name, $a_activate=true)
Add sheet.
setBold($a_coords)
Set cell(s) to bold.
writeToFile($a_file)
Save workbook to file.
getSheetTitle()
Return the current sheet title.
Date and time handling
getCoordByColumnAndRow($pColumn=1, $pRow=1)
Get cell coordinate (e.g.
getSheetCount()
Returns number of sheets.
setCell($a_row, $a_col, $a_value, $a_datatype=null)
Set cell value.
get($a_format, $a_format_str='', $a_tz='')
get formatted date
setCellByCoordinates($a_coords, $a_value)
Set cell value by coordinates.
addLink($a_row, $a_column, $a_path)
$filename
Definition: buildRTE.php:89
columnIndexAdjustment(int $column)
Adjustment needed because of migration PHPExcel to PhpSpreadsheet.
static ilTempnam($a_temp_path=null)
Returns a unique and non existing Path for e temporary file or directory.
setFormat($a_format)
Set file format.
const IL_CAL_DATE
setColors($a_coords, $a_background, $a_font=null)
Set cell(s) colors.
prepareDateValue(ilDateTime $a_value)
const FORMAT_XML
setBorders($a_coords, $a_top, $a_right=false, $a_bottom=false, $a_left=false)
Toggle cell(s) borders.
const APPLICATION__VND_OPENXMLFORMATS_OFFICEDOCUMENT_SPREADSHEETML_SHEET
sendToClient($a_file_name)
Send workbook to client.
getStyle()
Get cell style.
Definition: Cell.php:533
$cols
Definition: xhr_table.php:11
setCellArray(array $a_values, $a_top_left="A1", $a_null_value=null)
Set cell values from array.
prepareValue($a_value)
Prepare value for cell.
loadFromFile($filename)
Loads a spreadsheet from file.