add composer-unused, comprehensive docs, and project restructure
- Add icanhazstring/composer-unused as dev dependency for dependency hygiene checks
- Add German documentation (docs/) covering architecture, conventions, workflows, and developer checklists
- Add API layer (ApiAuth, ApiBootstrap, ApiResponse), audit, scheduler, custom fields, and SSO services
- Add Microsoft OIDC SSO, API token management, and user lifecycle features
- Add swagger-ui vendor integration and OpenAPI spec
- Add production Docker setup and bin/ scripts
- Update composer dependencies, config, templates, and frontend assets throughout
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-22 15:27:35 +01:00
|
|
|
<?php
|
|
|
|
|
|
|
|
|
|
namespace MintyPHP\Service\Import;
|
|
|
|
|
|
|
|
|
|
class CsvReaderService
|
|
|
|
|
{
|
|
|
|
|
private const DELIMITERS = [',', ';'];
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @return array{ok:bool, delimiter?:string, headers?:array<int,string>, rows_total?:int, code?:string}
|
|
|
|
|
*/
|
2026-02-23 12:58:19 +01:00
|
|
|
public function analyze(string $path, int $maxRows): array
|
add composer-unused, comprehensive docs, and project restructure
- Add icanhazstring/composer-unused as dev dependency for dependency hygiene checks
- Add German documentation (docs/) covering architecture, conventions, workflows, and developer checklists
- Add API layer (ApiAuth, ApiBootstrap, ApiResponse), audit, scheduler, custom fields, and SSO services
- Add Microsoft OIDC SSO, API token management, and user lifecycle features
- Add swagger-ui vendor integration and OpenAPI spec
- Add production Docker setup and bin/ scripts
- Update composer dependencies, config, templates, and frontend assets throughout
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-22 15:27:35 +01:00
|
|
|
{
|
|
|
|
|
if (!is_file($path) || !is_readable($path)) {
|
|
|
|
|
return ['ok' => false, 'code' => 'invalid_file_type'];
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-23 12:58:19 +01:00
|
|
|
$delimiter = $this->detectDelimiter($path);
|
|
|
|
|
$headerMeta = $this->readHeader($path, $delimiter);
|
add composer-unused, comprehensive docs, and project restructure
- Add icanhazstring/composer-unused as dev dependency for dependency hygiene checks
- Add German documentation (docs/) covering architecture, conventions, workflows, and developer checklists
- Add API layer (ApiAuth, ApiBootstrap, ApiResponse), audit, scheduler, custom fields, and SSO services
- Add Microsoft OIDC SSO, API token management, and user lifecycle features
- Add swagger-ui vendor integration and OpenAPI spec
- Add production Docker setup and bin/ scripts
- Update composer dependencies, config, templates, and frontend assets throughout
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-22 15:27:35 +01:00
|
|
|
if (!$headerMeta['ok']) {
|
|
|
|
|
$code = isset($headerMeta['code']) ? (string) $headerMeta['code'] : 'invalid_csv_header';
|
|
|
|
|
return ['ok' => false, 'code' => $code];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$headers = $headerMeta['headers'] ?? [];
|
|
|
|
|
$headerLine = (int) ($headerMeta['header_line'] ?? 1);
|
|
|
|
|
if (!$headers) {
|
|
|
|
|
return ['ok' => false, 'code' => 'invalid_csv_header'];
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-23 12:58:19 +01:00
|
|
|
$rowsTotal = $this->countRows($path, $delimiter, $headers, $headerLine);
|
add composer-unused, comprehensive docs, and project restructure
- Add icanhazstring/composer-unused as dev dependency for dependency hygiene checks
- Add German documentation (docs/) covering architecture, conventions, workflows, and developer checklists
- Add API layer (ApiAuth, ApiBootstrap, ApiResponse), audit, scheduler, custom fields, and SSO services
- Add Microsoft OIDC SSO, API token management, and user lifecycle features
- Add swagger-ui vendor integration and OpenAPI spec
- Add production Docker setup and bin/ scripts
- Update composer dependencies, config, templates, and frontend assets throughout
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-22 15:27:35 +01:00
|
|
|
if ($rowsTotal <= 0) {
|
|
|
|
|
return ['ok' => false, 'code' => 'empty_csv'];
|
|
|
|
|
}
|
|
|
|
|
if ($rowsTotal > $maxRows) {
|
|
|
|
|
return ['ok' => false, 'code' => 'max_rows_exceeded'];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return [
|
|
|
|
|
'ok' => true,
|
|
|
|
|
'delimiter' => $delimiter,
|
|
|
|
|
'headers' => $headers,
|
|
|
|
|
'rows_total' => $rowsTotal,
|
|
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @param array<int, string> $headers
|
|
|
|
|
*/
|
2026-02-23 12:58:19 +01:00
|
|
|
public function streamRows(string $path, string $delimiter, array $headers, callable $callback): void
|
add composer-unused, comprehensive docs, and project restructure
- Add icanhazstring/composer-unused as dev dependency for dependency hygiene checks
- Add German documentation (docs/) covering architecture, conventions, workflows, and developer checklists
- Add API layer (ApiAuth, ApiBootstrap, ApiResponse), audit, scheduler, custom fields, and SSO services
- Add Microsoft OIDC SSO, API token management, and user lifecycle features
- Add swagger-ui vendor integration and OpenAPI spec
- Add production Docker setup and bin/ scripts
- Update composer dependencies, config, templates, and frontend assets throughout
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-22 15:27:35 +01:00
|
|
|
{
|
2026-02-23 12:58:19 +01:00
|
|
|
$headerMeta = $this->readHeader($path, $delimiter);
|
add composer-unused, comprehensive docs, and project restructure
- Add icanhazstring/composer-unused as dev dependency for dependency hygiene checks
- Add German documentation (docs/) covering architecture, conventions, workflows, and developer checklists
- Add API layer (ApiAuth, ApiBootstrap, ApiResponse), audit, scheduler, custom fields, and SSO services
- Add Microsoft OIDC SSO, API token management, and user lifecycle features
- Add swagger-ui vendor integration and OpenAPI spec
- Add production Docker setup and bin/ scripts
- Update composer dependencies, config, templates, and frontend assets throughout
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-22 15:27:35 +01:00
|
|
|
if (!$headerMeta['ok']) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
$headerLine = (int) ($headerMeta['header_line'] ?? 1);
|
|
|
|
|
|
|
|
|
|
$handle = @fopen($path, 'rb');
|
|
|
|
|
if (!$handle) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$lineNumber = 0;
|
|
|
|
|
$rowIndex = 0;
|
|
|
|
|
while (($row = fgetcsv($handle, 0, $delimiter, '"', '\\')) !== false) {
|
|
|
|
|
$lineNumber++;
|
|
|
|
|
if ($lineNumber <= $headerLine) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-23 12:58:19 +01:00
|
|
|
$row = $this->normalizeRowColumns($row, count($headers));
|
|
|
|
|
if ($this->isEmptyRow($row)) {
|
add composer-unused, comprehensive docs, and project restructure
- Add icanhazstring/composer-unused as dev dependency for dependency hygiene checks
- Add German documentation (docs/) covering architecture, conventions, workflows, and developer checklists
- Add API layer (ApiAuth, ApiBootstrap, ApiResponse), audit, scheduler, custom fields, and SSO services
- Add Microsoft OIDC SSO, API token management, and user lifecycle features
- Add swagger-ui vendor integration and OpenAPI spec
- Add production Docker setup and bin/ scripts
- Update composer dependencies, config, templates, and frontend assets throughout
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-22 15:27:35 +01:00
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$rowIndex++;
|
|
|
|
|
$assoc = [];
|
|
|
|
|
foreach ($headers as $index => $header) {
|
2026-02-23 12:58:19 +01:00
|
|
|
$assoc[$header] = $this->cleanCell($row[$index] ?? '');
|
add composer-unused, comprehensive docs, and project restructure
- Add icanhazstring/composer-unused as dev dependency for dependency hygiene checks
- Add German documentation (docs/) covering architecture, conventions, workflows, and developer checklists
- Add API layer (ApiAuth, ApiBootstrap, ApiResponse), audit, scheduler, custom fields, and SSO services
- Add Microsoft OIDC SSO, API token management, and user lifecycle features
- Add swagger-ui vendor integration and OpenAPI spec
- Add production Docker setup and bin/ scripts
- Update composer dependencies, config, templates, and frontend assets throughout
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-22 15:27:35 +01:00
|
|
|
}
|
|
|
|
|
$callback($assoc, $lineNumber, $rowIndex);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fclose($handle);
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-06 00:44:52 +01:00
|
|
|
// Sample-based detection — reading 5 lines is enough to identify the delimiter without scanning the full file.
|
2026-02-23 12:58:19 +01:00
|
|
|
private function detectDelimiter(string $path): string
|
add composer-unused, comprehensive docs, and project restructure
- Add icanhazstring/composer-unused as dev dependency for dependency hygiene checks
- Add German documentation (docs/) covering architecture, conventions, workflows, and developer checklists
- Add API layer (ApiAuth, ApiBootstrap, ApiResponse), audit, scheduler, custom fields, and SSO services
- Add Microsoft OIDC SSO, API token management, and user lifecycle features
- Add swagger-ui vendor integration and OpenAPI spec
- Add production Docker setup and bin/ scripts
- Update composer dependencies, config, templates, and frontend assets throughout
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-22 15:27:35 +01:00
|
|
|
{
|
|
|
|
|
$sample = '';
|
|
|
|
|
$handle = @fopen($path, 'rb');
|
|
|
|
|
if ($handle) {
|
|
|
|
|
for ($i = 0; $i < 5; $i++) {
|
|
|
|
|
$line = fgets($handle);
|
|
|
|
|
if ($line === false) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
$sample .= $line;
|
|
|
|
|
}
|
|
|
|
|
fclose($handle);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$bestDelimiter = ',';
|
|
|
|
|
$bestScore = -1;
|
|
|
|
|
foreach (self::DELIMITERS as $delimiter) {
|
|
|
|
|
$score = substr_count($sample, $delimiter);
|
|
|
|
|
if ($score > $bestScore) {
|
|
|
|
|
$bestScore = $score;
|
|
|
|
|
$bestDelimiter = $delimiter;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return $bestDelimiter;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @return array{ok:bool, headers?:array<int,string>, header_line?:int, code?:string}
|
|
|
|
|
*/
|
2026-02-23 12:58:19 +01:00
|
|
|
private function readHeader(string $path, string $delimiter): array
|
add composer-unused, comprehensive docs, and project restructure
- Add icanhazstring/composer-unused as dev dependency for dependency hygiene checks
- Add German documentation (docs/) covering architecture, conventions, workflows, and developer checklists
- Add API layer (ApiAuth, ApiBootstrap, ApiResponse), audit, scheduler, custom fields, and SSO services
- Add Microsoft OIDC SSO, API token management, and user lifecycle features
- Add swagger-ui vendor integration and OpenAPI spec
- Add production Docker setup and bin/ scripts
- Update composer dependencies, config, templates, and frontend assets throughout
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-22 15:27:35 +01:00
|
|
|
{
|
|
|
|
|
$handle = @fopen($path, 'rb');
|
|
|
|
|
if (!$handle) {
|
|
|
|
|
return ['ok' => false, 'code' => 'invalid_csv_header'];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$lineNumber = 0;
|
|
|
|
|
while (($row = fgetcsv($handle, 0, $delimiter, '"', '\\')) !== false) {
|
|
|
|
|
$lineNumber++;
|
|
|
|
|
if (!is_array($row)) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2026-02-23 12:58:19 +01:00
|
|
|
$row = $this->normalizeRowColumns($row, count($row));
|
|
|
|
|
if ($this->isEmptyRow($row)) {
|
add composer-unused, comprehensive docs, and project restructure
- Add icanhazstring/composer-unused as dev dependency for dependency hygiene checks
- Add German documentation (docs/) covering architecture, conventions, workflows, and developer checklists
- Add API layer (ApiAuth, ApiBootstrap, ApiResponse), audit, scheduler, custom fields, and SSO services
- Add Microsoft OIDC SSO, API token management, and user lifecycle features
- Add swagger-ui vendor integration and OpenAPI spec
- Add production Docker setup and bin/ scripts
- Update composer dependencies, config, templates, and frontend assets throughout
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-22 15:27:35 +01:00
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$headers = [];
|
|
|
|
|
foreach ($row as $index => $cell) {
|
2026-02-23 12:58:19 +01:00
|
|
|
$value = $this->cleanCell((string) $cell);
|
add composer-unused, comprehensive docs, and project restructure
- Add icanhazstring/composer-unused as dev dependency for dependency hygiene checks
- Add German documentation (docs/) covering architecture, conventions, workflows, and developer checklists
- Add API layer (ApiAuth, ApiBootstrap, ApiResponse), audit, scheduler, custom fields, and SSO services
- Add Microsoft OIDC SSO, API token management, and user lifecycle features
- Add swagger-ui vendor integration and OpenAPI spec
- Add production Docker setup and bin/ scripts
- Update composer dependencies, config, templates, and frontend assets throughout
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-22 15:27:35 +01:00
|
|
|
if ($index === 0) {
|
2026-02-23 12:58:19 +01:00
|
|
|
$value = $this->stripBom($value);
|
add composer-unused, comprehensive docs, and project restructure
- Add icanhazstring/composer-unused as dev dependency for dependency hygiene checks
- Add German documentation (docs/) covering architecture, conventions, workflows, and developer checklists
- Add API layer (ApiAuth, ApiBootstrap, ApiResponse), audit, scheduler, custom fields, and SSO services
- Add Microsoft OIDC SSO, API token management, and user lifecycle features
- Add swagger-ui vendor integration and OpenAPI spec
- Add production Docker setup and bin/ scripts
- Update composer dependencies, config, templates, and frontend assets throughout
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-22 15:27:35 +01:00
|
|
|
}
|
|
|
|
|
$headers[] = trim($value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fclose($handle);
|
|
|
|
|
|
|
|
|
|
if (!$headers) {
|
|
|
|
|
return ['ok' => false, 'code' => 'invalid_csv_header'];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
foreach ($headers as $headerValue) {
|
|
|
|
|
if ($headerValue === '') {
|
|
|
|
|
return ['ok' => false, 'code' => 'invalid_csv_header'];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-06 00:44:52 +01:00
|
|
|
// Case-insensitive duplicate check — "Email" and "email" in the same header row are ambiguous.
|
2026-02-23 12:58:19 +01:00
|
|
|
$normalizedKeys = array_map([$this, 'lower'], $headers);
|
add composer-unused, comprehensive docs, and project restructure
- Add icanhazstring/composer-unused as dev dependency for dependency hygiene checks
- Add German documentation (docs/) covering architecture, conventions, workflows, and developer checklists
- Add API layer (ApiAuth, ApiBootstrap, ApiResponse), audit, scheduler, custom fields, and SSO services
- Add Microsoft OIDC SSO, API token management, and user lifecycle features
- Add swagger-ui vendor integration and OpenAPI spec
- Add production Docker setup and bin/ scripts
- Update composer dependencies, config, templates, and frontend assets throughout
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-22 15:27:35 +01:00
|
|
|
if (count(array_unique($normalizedKeys)) !== count($normalizedKeys)) {
|
|
|
|
|
return ['ok' => false, 'code' => 'invalid_csv_header'];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ['ok' => true, 'headers' => $headers, 'header_line' => $lineNumber];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fclose($handle);
|
|
|
|
|
return ['ok' => false, 'code' => 'empty_csv'];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @param array<int, mixed> $row
|
|
|
|
|
* @return array<int, string>
|
|
|
|
|
*/
|
2026-02-23 12:58:19 +01:00
|
|
|
private function normalizeRowColumns(array $row, int $size): array
|
add composer-unused, comprehensive docs, and project restructure
- Add icanhazstring/composer-unused as dev dependency for dependency hygiene checks
- Add German documentation (docs/) covering architecture, conventions, workflows, and developer checklists
- Add API layer (ApiAuth, ApiBootstrap, ApiResponse), audit, scheduler, custom fields, and SSO services
- Add Microsoft OIDC SSO, API token management, and user lifecycle features
- Add swagger-ui vendor integration and OpenAPI spec
- Add production Docker setup and bin/ scripts
- Update composer dependencies, config, templates, and frontend assets throughout
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-22 15:27:35 +01:00
|
|
|
{
|
|
|
|
|
$normalized = [];
|
|
|
|
|
foreach ($row as $cell) {
|
2026-02-23 12:58:19 +01:00
|
|
|
$normalized[] = $this->cleanCell((string) $cell);
|
add composer-unused, comprehensive docs, and project restructure
- Add icanhazstring/composer-unused as dev dependency for dependency hygiene checks
- Add German documentation (docs/) covering architecture, conventions, workflows, and developer checklists
- Add API layer (ApiAuth, ApiBootstrap, ApiResponse), audit, scheduler, custom fields, and SSO services
- Add Microsoft OIDC SSO, API token management, and user lifecycle features
- Add swagger-ui vendor integration and OpenAPI spec
- Add production Docker setup and bin/ scripts
- Update composer dependencies, config, templates, and frontend assets throughout
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-22 15:27:35 +01:00
|
|
|
}
|
|
|
|
|
|
2026-03-06 00:44:52 +01:00
|
|
|
// Pad short rows and trim over-long rows so every row has exactly as many cells as headers.
|
add composer-unused, comprehensive docs, and project restructure
- Add icanhazstring/composer-unused as dev dependency for dependency hygiene checks
- Add German documentation (docs/) covering architecture, conventions, workflows, and developer checklists
- Add API layer (ApiAuth, ApiBootstrap, ApiResponse), audit, scheduler, custom fields, and SSO services
- Add Microsoft OIDC SSO, API token management, and user lifecycle features
- Add swagger-ui vendor integration and OpenAPI spec
- Add production Docker setup and bin/ scripts
- Update composer dependencies, config, templates, and frontend assets throughout
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-22 15:27:35 +01:00
|
|
|
$current = count($normalized);
|
|
|
|
|
if ($current < $size) {
|
|
|
|
|
$normalized = array_pad($normalized, $size, '');
|
|
|
|
|
} elseif ($current > $size) {
|
|
|
|
|
$normalized = array_slice($normalized, 0, $size);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return $normalized;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @param array<int, string> $headers
|
|
|
|
|
*/
|
2026-02-23 12:58:19 +01:00
|
|
|
private function countRows(string $path, string $delimiter, array $headers, int $headerLine): int
|
add composer-unused, comprehensive docs, and project restructure
- Add icanhazstring/composer-unused as dev dependency for dependency hygiene checks
- Add German documentation (docs/) covering architecture, conventions, workflows, and developer checklists
- Add API layer (ApiAuth, ApiBootstrap, ApiResponse), audit, scheduler, custom fields, and SSO services
- Add Microsoft OIDC SSO, API token management, and user lifecycle features
- Add swagger-ui vendor integration and OpenAPI spec
- Add production Docker setup and bin/ scripts
- Update composer dependencies, config, templates, and frontend assets throughout
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-22 15:27:35 +01:00
|
|
|
{
|
|
|
|
|
$count = 0;
|
|
|
|
|
$handle = @fopen($path, 'rb');
|
|
|
|
|
if (!$handle) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$lineNumber = 0;
|
|
|
|
|
while (($row = fgetcsv($handle, 0, $delimiter, '"', '\\')) !== false) {
|
|
|
|
|
$lineNumber++;
|
|
|
|
|
if ($lineNumber <= $headerLine) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if (!is_array($row)) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2026-02-23 12:58:19 +01:00
|
|
|
$row = $this->normalizeRowColumns($row, count($headers));
|
|
|
|
|
if ($this->isEmptyRow($row)) {
|
add composer-unused, comprehensive docs, and project restructure
- Add icanhazstring/composer-unused as dev dependency for dependency hygiene checks
- Add German documentation (docs/) covering architecture, conventions, workflows, and developer checklists
- Add API layer (ApiAuth, ApiBootstrap, ApiResponse), audit, scheduler, custom fields, and SSO services
- Add Microsoft OIDC SSO, API token management, and user lifecycle features
- Add swagger-ui vendor integration and OpenAPI spec
- Add production Docker setup and bin/ scripts
- Update composer dependencies, config, templates, and frontend assets throughout
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-22 15:27:35 +01:00
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
$count++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fclose($handle);
|
|
|
|
|
return $count;
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-23 12:58:19 +01:00
|
|
|
private function isEmptyRow(array $row): bool
|
add composer-unused, comprehensive docs, and project restructure
- Add icanhazstring/composer-unused as dev dependency for dependency hygiene checks
- Add German documentation (docs/) covering architecture, conventions, workflows, and developer checklists
- Add API layer (ApiAuth, ApiBootstrap, ApiResponse), audit, scheduler, custom fields, and SSO services
- Add Microsoft OIDC SSO, API token management, and user lifecycle features
- Add swagger-ui vendor integration and OpenAPI spec
- Add production Docker setup and bin/ scripts
- Update composer dependencies, config, templates, and frontend assets throughout
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-22 15:27:35 +01:00
|
|
|
{
|
|
|
|
|
foreach ($row as $cell) {
|
|
|
|
|
if (trim((string) $cell) !== '') {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-23 12:58:19 +01:00
|
|
|
private function stripBom(string $value): string
|
add composer-unused, comprehensive docs, and project restructure
- Add icanhazstring/composer-unused as dev dependency for dependency hygiene checks
- Add German documentation (docs/) covering architecture, conventions, workflows, and developer checklists
- Add API layer (ApiAuth, ApiBootstrap, ApiResponse), audit, scheduler, custom fields, and SSO services
- Add Microsoft OIDC SSO, API token management, and user lifecycle features
- Add swagger-ui vendor integration and OpenAPI spec
- Add production Docker setup and bin/ scripts
- Update composer dependencies, config, templates, and frontend assets throughout
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-22 15:27:35 +01:00
|
|
|
{
|
|
|
|
|
if (str_starts_with($value, "\xEF\xBB\xBF")) {
|
|
|
|
|
return substr($value, 3);
|
|
|
|
|
}
|
|
|
|
|
return $value;
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-06 00:44:52 +01:00
|
|
|
// Remove null bytes (defense against null byte injection) and UTF-8 BOM from each cell.
|
2026-02-23 12:58:19 +01:00
|
|
|
private function cleanCell(string $value): string
|
add composer-unused, comprehensive docs, and project restructure
- Add icanhazstring/composer-unused as dev dependency for dependency hygiene checks
- Add German documentation (docs/) covering architecture, conventions, workflows, and developer checklists
- Add API layer (ApiAuth, ApiBootstrap, ApiResponse), audit, scheduler, custom fields, and SSO services
- Add Microsoft OIDC SSO, API token management, and user lifecycle features
- Add swagger-ui vendor integration and OpenAPI spec
- Add production Docker setup and bin/ scripts
- Update composer dependencies, config, templates, and frontend assets throughout
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-22 15:27:35 +01:00
|
|
|
{
|
|
|
|
|
$value = str_replace("\0", '', $value);
|
2026-02-23 12:58:19 +01:00
|
|
|
$value = $this->stripBom($value);
|
add composer-unused, comprehensive docs, and project restructure
- Add icanhazstring/composer-unused as dev dependency for dependency hygiene checks
- Add German documentation (docs/) covering architecture, conventions, workflows, and developer checklists
- Add API layer (ApiAuth, ApiBootstrap, ApiResponse), audit, scheduler, custom fields, and SSO services
- Add Microsoft OIDC SSO, API token management, and user lifecycle features
- Add swagger-ui vendor integration and OpenAPI spec
- Add production Docker setup and bin/ scripts
- Update composer dependencies, config, templates, and frontend assets throughout
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-22 15:27:35 +01:00
|
|
|
return trim($value);
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-23 12:58:19 +01:00
|
|
|
private function lower(string $value): string
|
add composer-unused, comprehensive docs, and project restructure
- Add icanhazstring/composer-unused as dev dependency for dependency hygiene checks
- Add German documentation (docs/) covering architecture, conventions, workflows, and developer checklists
- Add API layer (ApiAuth, ApiBootstrap, ApiResponse), audit, scheduler, custom fields, and SSO services
- Add Microsoft OIDC SSO, API token management, and user lifecycle features
- Add swagger-ui vendor integration and OpenAPI spec
- Add production Docker setup and bin/ scripts
- Update composer dependencies, config, templates, and frontend assets throughout
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-22 15:27:35 +01:00
|
|
|
{
|
|
|
|
|
if (function_exists('mb_strtolower')) {
|
|
|
|
|
return mb_strtolower($value, 'UTF-8');
|
|
|
|
|
}
|
|
|
|
|
return strtolower($value);
|
|
|
|
|
}
|
|
|
|
|
}
|