Skip to content
Snippets Groups Projects
Commit 7e7f9d55 authored by Carsten  Rose's avatar Carsten Rose
Browse files

Implements and fixes #7747. Import Excel: restrict reading to explicit named worksheets

parent fb907848
No related branches found
No related tags found
1 merge request!120F#7747: New options to import Excel files: importNamedSheetsOnly, importSetReadDataOnly, importListSheetNames
Pipeline #1408 passed
......@@ -2790,31 +2790,39 @@ See also at specific *FormElement* definitions.
+------------------------+--------+----------------------------------------------------------------------------------------------------------+
| autofocus | string | See `input-option-autofocus`_ |
+------------------------+--------+----------------------------------------------------------------------------------------------------------+
| capture | string | See `input-upload`_ |
| accept | string | |
| maxFileSize | string | |
| fileDestination | string | |
| fileReplace | string | |
| autoOrient | string | |
| autoOrientCmd | string | |
| autoOrientMimeType | string | |
| chmodFile / chmodDir | string | |
| slaveId | string | |
| sqlBefore | string | |
| sqlInsert | string | |
| sqlUpdate | string | |
| sqlDelete | string | |
| sqlAfter | string | |
| capture, | string | See `input-upload`_ |
| accept, | | |
| maxFileSize, | | |
| fileDestination, | | |
| fileReplace, | | |
| autoOrient, | | |
| autoOrientCmd, | | |
| autoOrientMimeType, | | |
| chmodFile, chmodDir, | | |
| slaveId, | | |
| sqlBefore, | | |
| sqlInsert, | | |
| sqlUpdate, | | |
| sqlDelete, | | |
| sqlAfter, | | |
| importToTable, | | |
| importToColumns, | | |
| importRegion, | | |
| importMode, | | |
| importType, | | |
| importNamedSheetsOnly, | | |
| importSetReadDataOnly, | | |
| importListSheetNames, | | |
+------------------------+--------+----------------------------------------------------------------------------------------------------------+
| checkBoxMode | string | See `input-checkbox`_, `input-radio`_, `input-select`_ |
| checked | string | |
| unchecked | string | |
| label2 | string | |
| itemList | string | |
| emptyHide | - | |
| emptyItemAtStart | - | |
| emptyItemAtEnd | - | |
| buttonClass | string | |
| checked | | |
| unchecked | | |
| label2 | | |
| itemList | | |
| emptyHide | | |
| emptyItemAtStart | | |
| emptyItemAtEnd | | |
| buttonClass | | |
+------------------------+--------+----------------------------------------------------------------------------------------------------------+
| dateFormat | string | yyyy-mm-dd / dd.mm.yyyy |
+------------------------+--------+----------------------------------------------------------------------------------------------------------+
......@@ -2841,20 +2849,20 @@ See also at specific *FormElement* definitions.
+------------------------+--------+----------------------------------------------------------------------------------------------------------+
| extraButtonInfoClass | string | By default empty. Specify any class to be assigned to wrap extraButtonInfo |
+------------------------+--------+----------------------------------------------------------------------------------------------------------+
| editor-plugins | string | See `input-editor`_ |
| editor-toolbar | string | |
| editor-statusbar | string | |
| editor-plugins, | string | See `input-editor`_ |
| editor-toolbar, | | |
| editor-statusbar, | | |
+------------------------+--------+----------------------------------------------------------------------------------------------------------+
| fileButtonText | string | Overwrite default 'Choose File' |
+------------------------+--------+----------------------------------------------------------------------------------------------------------+
| fillStoreVar | string | Fill the STORE_VAR with custom values. See `STORE_VARS`_. |
+------------------------+--------+----------------------------------------------------------------------------------------------------------+
| form | string | See `subrecord-option`_ |
| page | string | |
| title | string | |
| extraDeleteForm | string | |
| detail | string | |
| subrecordTableClass | string | |
| form, | string | See `subrecord-option`_ |
| page, | | |
| title, | | |
| extraDeleteForm, | | |
| detail, | | |
| subrecordTableClass, | | |
+------------------------+--------+----------------------------------------------------------------------------------------------------------+
| min | s/d/n | Minimum and/or maximum allowed values for input field. Can be used for numbers, dates, or strings. |
+------------------------+--------+ |
......@@ -2863,12 +2871,12 @@ See also at specific *FormElement* definitions.
| processReadOnly | [n] | [0|1] By default FE's with type='readonly' are not processed during 'save'. |
| | | This option forces to process them during 'save' as well. |
+------------------------+--------+----------------------------------------------------------------------------------------------------------+
| retype | string | See `input-text`_ |
| retypeLabel | string | |
| retypeNote | string | |
| characterCountWrap | string | |
| hideZero | string | |
| emptyMeansNull | string | |
| retype, | string | See `input-text`_ |
| retypeLabel, | | |
| retypeNote, | | |
| characterCountWrap, | | |
| hideZero, | | |
| emptyMeansNull, | | |
+------------------------+--------+----------------------------------------------------------------------------------------------------------+
| showSeconds | string | 0|1 - Shows the seconds on form load. Default: 0 |
+------------------------+--------+----------------------------------------------------------------------------------------------------------+
......@@ -2877,10 +2885,10 @@ See also at specific *FormElement* definitions.
| timeIsOptional | string | 0|1 - Used for datetime input. 0 (default): Time is required - 1: Entering a time is optional |
| | | (defaults to 00:00:00 if none entered). |
+------------------------+--------+----------------------------------------------------------------------------------------------------------+
| typeAheadLimit | string | See `input-typeahead`_ |
| typeAheadMinLength | string | |
| typeAheadSql | string | |
| typeAheadSqlPrefetch | string | |
| typeAheadLimit, | string | See `input-typeahead`_ |
| typeAheadMinLength, | | |
| typeAheadSql, | | |
| typeAheadSqlPrefetch, | | |
+------------------------+--------+----------------------------------------------------------------------------------------------------------+
| wrapRow | string | If specified, skip default wrapping (`<div class='col-md-?'>`). Instead the given string is used. |
+------------------------+--------+ |
......@@ -3606,16 +3614,22 @@ See also `downloadButton`_ to offer a download of an uploaded file.
(e.g. 43214), which is the serial value date in Excel. To convert such a number to a MariaDb date, use:
`DATE_ADD('1899-12-30', INTERVAL serialValue DAY)`.
* *importToTable*: <mariadb.tablename> - **Required**. Providing this parameter activates the import. If the table
* *importToTable* = <[db.]tablename> - **Required**. Providing this parameter activates the import. If the table
doesn't exist, it will be created.
* *importToColumns*: <col1>,<col2>,... - If none provided, the Excel column names A, B, ... are used. Note: These
* *importToColumns* = <col1>,<col2>,... - If none provided, the Excel column names A, B, ... are used. Note: These
have to match the table's column names if the table already exists.
* *importRegion*: [tab],[startColumn],[startRow],[endColumn],[endRow]|... - All parts are optional (default:
* *importRegion* = [tab],[startColumn],[startRow],[endColumn],[endRow]|... - All parts are optional (default:
entire 1st sheet). Tab can either be given as an index (1-based) or a name. start/endColumn can be given either
numerically (1, 2, ...) or by column name (A, B, ...). Note that you can specify several regions to import.
* *importMode*: `append` (default) | `replace` - The data is either appended or replace in the specified table.
* *importType*: `auto` (default) | `xls` | `xlsx` | `ods` | `csv` - Define what kind of data should be expected by the
Spreadsheet Reader. `auto` should work fine in most cases.
* *importMode* = `append` (default) | `replace` - The data is either appended or replace in the specified table.
* *importType* = `auto` (default) | `xls` | `xlsx` | `ods` | `csv` - Define what kind of data should be expected by the
Spreadsheet Reader.
* *importNamedSheetsOnly* = <comma separated list of sheet names>. Use this option if specific sheets cause problems
during import and should be skipped, by naming only those sheets, who will be read. This will also reduce the memory
usage.
* *importSetReadDataOnly* = 0|1. Read only cell data, not the cell formatting. Warning: cell types other than numerical
will be misinterpreted.
* *importListSheetNames* = 0|1. For debug use only. Will open a dialog and report all found worksheet names.
Immediately after the upload finished (before the user press save), the file will be checked on the server for it's
......
......@@ -337,6 +337,10 @@ const ERROR_DND_EMPTY_REORDER_SQL = 2700;
// Form
const ERROR_FORM_RESERVED_NAME = 2800;
// Import (Excel, ODS, ...)
const ERROR_IMPORT_MISSING_EXPLICIT_TYPE = 2900;
const ERROR_IMPORT_LIST_SHEET_NAMES = 2901;
//
// Store Names: Identifier
//
......@@ -1040,6 +1044,10 @@ const FE_IMPORT_TYPE_XLS = 'xls';
const FE_IMPORT_TYPE_XLSX = 'xlsx';
const FE_IMPORT_TYPE_ODS = 'ods';
const FE_IMPORT_TYPE_CSV = 'csv';
const FE_IMPORT_NAMED_SHEETS_ONLY = 'importNamedSheetsOnly';
const FE_IMPORT_READ_DATA_ONLY = 'importSetReadDataOnly';
const FE_IMPORT_LIST_SHEET_NAMES = 'importListSheetNames';
const FE_IMAGE_SOURCE = 'imageSource'; // Image source for a fabric element
const FE_DEFAULT_PEN_COLOR = 'defaultPenColor'; // Default pen color for a fabric element
......
......@@ -369,7 +369,7 @@ class Save {
}
$column = $formElement[FE_NAME];
$pathFileName = $this->doUpload($formElement, ($formValues[$column]??''), $sip, $modeUpload);
$pathFileName = $this->doUpload($formElement, ($formValues[$column] ?? ''), $sip, $modeUpload);
if ($modeUpload == UPLOAD_MODE_DELETEOLD && $pathFileName == '') {
$pathFileNameTmp = ''; // see '4'
......@@ -661,9 +661,25 @@ class Save {
* @throws \PhpOffice\PhpSpreadsheet\Reader\Exception
*/
private function doImport($formElement, $fileName) {
$importNamedSheetsOnly = array();
Support::setIfNotSet($formElement, FE_IMPORT_TYPE, FE_IMPORT_TYPE_AUTO);
if (!empty($formElement[FE_IMPORT_NAMED_SHEETS_ONLY])) {
$importNamedSheetsOnly = explode(',', $formElement[FE_IMPORT_NAMED_SHEETS_ONLY]);
}
if ($formElement[FE_IMPORT_TYPE] === FE_IMPORT_TYPE_AUTO) {
$list = [FE_IMPORT_LIST_SHEET_NAMES, FE_IMPORT_READ_DATA_ONLY, FE_IMPORT_LIST_SHEET_NAMES];
foreach ($list as $token) {
if (isset($formElement[$token])) {
throw new UserFormException('If ' . $token .
' is given, an explicit document type (like ' . FE_IMPORT_TYPE . '=xlsx) should be set.', ERROR_IMPORT_MISSING_EXPLICIT_TYPE);
}
}
}
switch ($formElement[FE_IMPORT_TYPE]) {
case FE_IMPORT_TYPE_AUTO:
$spreadsheet = \PhpOffice\PhpSpreadsheet\IOFactory::load($fileName);
......@@ -675,6 +691,23 @@ class Save {
case FE_IMPORT_TYPE_ODS:
$inputFileType = ucfirst($formElement[FE_IMPORT_TYPE]);
$reader = \PhpOffice\PhpSpreadsheet\IOFactory::createReader($inputFileType);
// setReadDataOnly
if (($formElement[FE_IMPORT_READ_DATA_ONLY] ?? '0') != '0') {
$reader->setReadDataOnly(true);
}
// setLoadSheetsOnly
if (!empty ($importNamedSheetsOnly)) {
$reader->setLoadSheetsOnly($importNamedSheetsOnly);
}
if (($formElement[FE_IMPORT_LIST_SHEET_NAMES] ?? '0') != '0') {
$sheetNames = $reader->listWorksheetNames($fileName);
throw new UserFormException("Worksheets: " . implode(', ', $sheetNames),
ERROR_IMPORT_LIST_SHEET_NAMES);
}
$spreadsheet = $reader->load($fileName);
break;
......@@ -685,7 +718,7 @@ class Save {
$tableName = $formElement[FE_IMPORT_TO_TABLE];
$regions = OnArray::trimArray(explode('|', $formElement[FE_IMPORT_REGION] ?? ''));
$columnNames = OnArray::trimArray(explode(',', $formElement[FE_IMPORT_TO_COLUMNS]));
$columnNames = OnArray::trimArray(explode(',', $formElement[FE_IMPORT_TO_COLUMNS] ?? ''));
$importMode = $formElement[FE_IMPORT_MODE] ?? FE_IMPORT_MODE_APPEND;
foreach ($regions as $region) {
......@@ -789,7 +822,8 @@ class Save {
* @throws UserFormException
* @throws UserReportException
*/
private function copyUploadFile(array $formElement, array $statusUpload) {
private
function copyUploadFile(array $formElement, array $statusUpload) {
$pathFileName = '';
if (!isset($statusUpload[FILES_TMP_NAME]) || $statusUpload[FILES_TMP_NAME] === '') {
......@@ -852,7 +886,8 @@ class Save {
* @throws UserFormException
* @throws UserReportException
*/
private function autoOrient(array $formElement, $pathFileName) {
private
function autoOrient(array $formElement, $pathFileName) {
// 'autoOrient' wished?
if (!isset($formElement[FE_FILE_AUTO_ORIENT]) || $formElement[FE_FILE_AUTO_ORIENT] == '0') {
......@@ -893,7 +928,8 @@ class Save {
* @throws UserFormException
* @throws UserReportException
*/
private function splitUpload(array $formElement, $pathFileName, $chmod, array $statusUpload) {
private
function splitUpload(array $formElement, $pathFileName, $chmod, array $statusUpload) {
if (empty($formElement[FE_FILE_SPLIT]) || $statusUpload[FILES_TYPE] != MIME_TYPE_SPLIT_CAPABLE) {
return;
......@@ -1016,7 +1052,8 @@ class Save {
* @throws UserFormException
* @throws UserReportException
*/
private function doUploadSlave(array $fe, $modeUpload) {
private
function doUploadSlave(array $fe, $modeUpload) {
$sql = '';
$flagUpdateSlaveId = false;
$flagSlaveDeleted = false;
......
File deleted
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment