diff --git a/public/userarea/edit_template_xls.php b/public/userarea/edit_template_xls.php
index 9677ba6..1ac0d71 100644
--- a/public/userarea/edit_template_xls.php
+++ b/public/userarea/edit_template_xls.php
@@ -207,6 +207,21 @@ if (!array_key_exists($currentButtonTextColor, array_change_key_case($buttonText
+
+
+
+
+ Attention: if left empty, the system will read the entire XLS/XLSX sheet.
+ Dirty Excel files may cause memory errors or timeout.
+
+
+
fetchAll(PDO::FETCH_ASSOC);
+
+
+
+
+ Attention: if left empty, the system will read the entire XLS/XLSX sheet.
+ Dirty Excel files may cause memory errors or timeout.
+
+
+
fetchAll(PDO::FETCH_ASSOC);
const headerRowWrapper = document.getElementById("headerRowWrapper");
const startColumnWrapper = document.getElementById("startColumnWrapper");
+ const xlsEndColumnWrapper = document.getElementById("xlsEndColumnWrapper");
const xlsSheetNumberWrapper = document.getElementById("xlsSheetNumberWrapper");
const apiConfigWrapper = document.getElementById("apiConfigWrapper");
const headerRow = document.getElementById("headerRow");
const startColumn = document.getElementById("startColumn");
+ const xlsEndColumn = document.getElementById("xlsEndColumn");
const xlsSheetIndex = document.getElementById("xlsSheetIndex");
const apiConfigSelect = document.getElementById("apiConfigSelect");
@@ -295,14 +312,20 @@ $apiConfigurations = $stmt->fetchAll(PDO::FETCH_ASSOC);
if (isXls) {
headerRowWrapper.style.display = 'block';
startColumnWrapper.style.display = 'block';
+ xlsEndColumnWrapper.style.display = 'block';
xlsSheetNumberWrapper.style.display = 'block';
headerRow.required = true;
startColumn.required = true;
xlsSheetIndex.required = true;
+ // Last Column is optional.
+ // If empty, the import will read the entire sheet.
+ xlsEndColumn.required = false;
+
headerRow.disabled = false;
startColumn.disabled = false;
+ xlsEndColumn.disabled = false;
xlsSheetIndex.disabled = false;
apiConfigWrapper.style.display = 'none';
@@ -312,16 +335,21 @@ $apiConfigurations = $stmt->fetchAll(PDO::FETCH_ASSOC);
} else {
headerRowWrapper.style.display = 'none';
startColumnWrapper.style.display = 'none';
+ xlsEndColumnWrapper.style.display = 'none';
xlsSheetNumberWrapper.style.display = 'none';
headerRow.required = false;
startColumn.required = false;
+ xlsEndColumn.required = false;
xlsSheetIndex.required = false;
headerRow.disabled = true;
startColumn.disabled = true;
+ xlsEndColumn.disabled = true;
xlsSheetIndex.disabled = true;
+ xlsEndColumn.value = '';
+
if (isApiJson) {
apiConfigWrapper.style.display = 'block';
apiConfigSelect.required = true;
diff --git a/public/userarea/process_edit_template_xls.php b/public/userarea/process_edit_template_xls.php
index e333d9a..8f3a654 100644
--- a/public/userarea/process_edit_template_xls.php
+++ b/public/userarea/process_edit_template_xls.php
@@ -4,6 +4,35 @@ require_once 'class/db-functions.php';
$response = ["success" => false, "message" => ""];
+function excelColumnToIndex($column)
+{
+ $column = strtoupper(trim((string)$column));
+
+ if ($column === '') {
+ return null;
+ }
+
+ // Numeric column index, example: 40
+ if (ctype_digit($column)) {
+ $index = (int)$column;
+ return $index > 0 ? $index : null;
+ }
+
+ // Excel column letters, example: A, AN, XFC
+ if (!preg_match('/^[A-Z]+$/', $column)) {
+ return null;
+ }
+
+ $index = 0;
+ $length = strlen($column);
+
+ for ($i = 0; $i < $length; $i++) {
+ $index = ($index * 26) + (ord($column[$i]) - ord('A') + 1);
+ }
+
+ return $index;
+}
+
try {
if ($_SERVER["REQUEST_METHOD"] !== "POST") {
throw new Exception("Invalid request method.");
@@ -19,6 +48,8 @@ try {
: null;
$start_column = trim($_POST['start_column'] ?? '');
+ $xls_end_column = strtoupper(trim($_POST['xls_end_column'] ?? ''));
+ $xls_end_column = $xls_end_column !== '' ? $xls_end_column : null;
$xls_sheet_index = isset($_POST['xls_sheet_index']) && $_POST['xls_sheet_index'] !== ''
? intval($_POST['xls_sheet_index'])
@@ -60,6 +91,24 @@ try {
throw new Exception("XLS Sheet Number cannot be negative.");
}
+ $startColumnIndex = excelColumnToIndex($start_column);
+
+ if ($startColumnIndex === null) {
+ throw new Exception("Start Column is not valid. Use Excel column letters like A, AN or a positive number.");
+ }
+
+ if ($xls_end_column !== null) {
+ $endColumnIndex = excelColumnToIndex($xls_end_column);
+
+ if ($endColumnIndex === null) {
+ throw new Exception("Last Column is not valid. Use Excel column letters like AN or a positive number.");
+ }
+
+ if ($endColumnIndex < $startColumnIndex) {
+ throw new Exception("Last Column cannot be before Start Column.");
+ }
+ }
+
$api_config_id = null;
}
@@ -71,6 +120,7 @@ try {
$header_row = null;
$start_column = null;
+ $xls_end_column = null;
$xls_sheet_index = null;
}
@@ -78,6 +128,7 @@ try {
if ($source_type === 'PDF') {
$header_row = null;
$start_column = null;
+ $xls_end_column = null;
$xls_sheet_index = null;
$api_config_id = null;
}
@@ -109,6 +160,7 @@ try {
source_type = ?,
header_row = ?,
start_column = ?,
+ xls_end_column = ?,
xls_sheet_index = ?,
api_config_id = ?,
description = ?,
@@ -131,6 +183,7 @@ try {
$source_type,
$header_row,
$start_column,
+ $xls_end_column,
$xls_sheet_index,
$api_config_id,
$description,
diff --git a/public/userarea/process_import_xls2.php b/public/userarea/process_import_xls2.php
index 407ea08..71c19b6 100644
--- a/public/userarea/process_import_xls2.php
+++ b/public/userarea/process_import_xls2.php
@@ -74,6 +74,7 @@ try {
id,
header_row,
start_column,
+ xls_end_column,
xls_sheet_index,
idroutine,
idclient
@@ -93,6 +94,12 @@ try {
$start_column_raw = $template['start_column'] ?? 'A';
$start_column = normalizeColumnIndex($start_column_raw);
+ $xls_end_column_raw = trim((string)($template['xls_end_column'] ?? ''));
+ $xls_end_column = $xls_end_column_raw !== '' ? normalizeColumnIndex($xls_end_column_raw) : 0;
+
+ if ($xls_end_column > 0 && $xls_end_column < $start_column) {
+ throw new Exception("Last Column cannot be before Start Column.");
+ }
$xlsSheetIndex = isset($template['xls_sheet_index']) && $template['xls_sheet_index'] !== null
? (int)$template['xls_sheet_index']
@@ -109,7 +116,15 @@ try {
// Debug del template_id ricevuto
error_log("Received template_id from POST: " . print_r($_POST['template_id'], true));
error_log("Converted template_id: $template_id");
- error_log("Template XLS settings - header_row: $header_row, start_column_raw: $start_column_raw, start_column_index: $start_column, xls_sheet_index: $xlsSheetIndex");
+ error_log(
+ "Template XLS settings - " .
+ "header_row: $header_row, " .
+ "start_column_raw: $start_column_raw, " .
+ "start_column_index: $start_column, " .
+ "xls_end_column_raw: " . ($xls_end_column_raw !== '' ? $xls_end_column_raw : '[empty = read all]') . ", " .
+ "xls_end_column_index: " . ($xls_end_column > 0 ? $xls_end_column : '[no limit]') . ", " .
+ "xls_sheet_index: $xlsSheetIndex"
+ );
$file = $_FILES['excel_file'];
$fileError = $file['error'];
@@ -161,8 +176,33 @@ try {
if (empty($mappings)) {
$response['error'] = "Nessun mapping trovato per il template con ID $template_id";
} else {
- // Carica il file rinominato con PHPSpreadsheet
- $spreadsheet = IOFactory::load($destination);
+ // Load the XLS/XLSX file.
+ // If Last Column is configured in the template, load only the configured column range.
+ // If Last Column is empty, keep the original behavior and read the entire sheet.
+ $reader = IOFactory::createReaderForFile($destination);
+ $reader->setReadDataOnly(true);
+
+ if ($xls_end_column > 0) {
+ $reader->setReadFilter(new class($start_column, $xls_end_column) implements \PhpOffice\PhpSpreadsheet\Reader\IReadFilter {
+ private int $startColumn;
+ private int $endColumn;
+
+ public function __construct(int $startColumn, int $endColumn)
+ {
+ $this->startColumn = $startColumn;
+ $this->endColumn = $endColumn;
+ }
+
+ public function readCell($columnAddress, $row, $worksheetName = ''): bool
+ {
+ $columnIndex = \PhpOffice\PhpSpreadsheet\Cell\Coordinate::columnIndexFromString($columnAddress);
+
+ return $columnIndex >= $this->startColumn && $columnIndex <= $this->endColumn;
+ }
+ });
+ }
+
+ $spreadsheet = $reader->load($destination);
$sheetCount = $spreadsheet->getSheetCount();
$sheetNames = $spreadsheet->getSheetNames();
@@ -193,6 +233,12 @@ try {
$highestColumn = $worksheet->getHighestColumn();
$highestColumnIndex = Coordinate::columnIndexFromString($highestColumn);
+ // Force the effective highest column to Last Column, if configured.
+ if ($xls_end_column > 0) {
+ $highestColumnIndex = $xls_end_column;
+ $highestColumn = Coordinate::stringFromColumnIndex($highestColumnIndex);
+ }
+
$startRow = max(1, $header_row);
$startColumn = max(1, $start_column);
diff --git a/public/userarea/process_insert_template_xls.php b/public/userarea/process_insert_template_xls.php
index e257656..389d76a 100644
--- a/public/userarea/process_insert_template_xls.php
+++ b/public/userarea/process_insert_template_xls.php
@@ -4,6 +4,35 @@ require_once 'class/db-functions.php';
$response = ["success" => false, "message" => ""];
+function excelColumnToIndex($column)
+{
+ $column = strtoupper(trim((string)$column));
+
+ if ($column === '') {
+ return null;
+ }
+
+ // Numeric column index, example: 40
+ if (ctype_digit($column)) {
+ $index = (int)$column;
+ return $index > 0 ? $index : null;
+ }
+
+ // Excel column letters, example: A, AN, XFC
+ if (!preg_match('/^[A-Z]+$/', $column)) {
+ return null;
+ }
+
+ $index = 0;
+ $length = strlen($column);
+
+ for ($i = 0; $i < $length; $i++) {
+ $index = ($index * 26) + (ord($column[$i]) - ord('A') + 1);
+ }
+
+ return $index;
+}
+
try {
if ($_SERVER["REQUEST_METHOD"] !== "POST") {
throw new Exception("Invalid request method.");
@@ -18,6 +47,8 @@ try {
: null;
$start_column = trim($_POST['start_column'] ?? '');
+ $xls_end_column = strtoupper(trim($_POST['xls_end_column'] ?? ''));
+ $xls_end_column = $xls_end_column !== '' ? $xls_end_column : null;
$xls_sheet_index = isset($_POST['xls_sheet_index']) && $_POST['xls_sheet_index'] !== ''
? intval($_POST['xls_sheet_index'])
@@ -63,6 +94,24 @@ try {
throw new Exception("XLS Sheet Number cannot be negative.");
}
+ $startColumnIndex = excelColumnToIndex($start_column);
+
+ if ($startColumnIndex === null) {
+ throw new Exception("Start Column is not valid. Use Excel column letters like A, AN or a positive number.");
+ }
+
+ if ($xls_end_column !== null) {
+ $endColumnIndex = excelColumnToIndex($xls_end_column);
+
+ if ($endColumnIndex === null) {
+ throw new Exception("Last Column is not valid. Use Excel column letters like AN or a positive number.");
+ }
+
+ if ($endColumnIndex < $startColumnIndex) {
+ throw new Exception("Last Column cannot be before Start Column.");
+ }
+ }
+
$api_config_id = null;
}
@@ -75,6 +124,7 @@ try {
$header_row = null;
$start_column = null;
$xls_sheet_index = null;
+ $xls_end_column = null;
}
// PDF currently does not require XLS coordinates or API configuration
@@ -82,6 +132,7 @@ try {
$header_row = null;
$start_column = null;
$xls_sheet_index = null;
+ $xls_end_column = null;
$api_config_id = null;
}
@@ -112,6 +163,7 @@ try {
source_type,
header_row,
start_column,
+ xls_end_column,
xls_sheet_index,
api_config_id,
description,
@@ -130,7 +182,7 @@ try {
)
VALUES
(
- ?, ?, ?, ?, ?, ?,
+ ?, ?, ?, ?, ?, ?,?,
?, ?, ?, ?, ?, ?,
?, ?, ?, ?, ?,
NOW(), NOW()
@@ -142,6 +194,7 @@ try {
$source_type,
$header_row,
$start_column,
+ $xls_end_column,
$xls_sheet_index,
$api_config_id,
$description,
diff --git a/public/userarea/schemi_base_response.json b/public/userarea/schemi_base_response.json
index 4e39ea7..b7dd566 100644
--- a/public/userarea/schemi_base_response.json
+++ b/public/userarea/schemi_base_response.json
@@ -730,8 +730,8 @@
{
"IdSchemaCustomFields": 177,
"ConteggioClienti": 0,
- "Nome": "Phoebe philo ACC",
- "Descrizione": "(scarpe, borse, cinture, occhiali, gioielleria)\r\n"
+ "Nome": "Phoebe Philo ",
+ "Descrizione": "\r\n\r\n"
},
{
"IdSchemaCustomFields": 178,