Fix #116: Beleg-Uploads aus dem Web-Root entfernt (nach data/uploads verschoben)
This commit is contained in:
parent
2012f228c4
commit
649684a77b
13 changed files with 56 additions and 32 deletions
10
Changes.md
10
Changes.md
|
|
@ -2,6 +2,16 @@
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## 2026-07-08 – Fix: Unauthentifizierter Direktzugriff auf Belege/Rechnungs-PDFs (Issue #116)
|
||||||
|
|
||||||
|
- **Kritisch:** Hochgeladene Belege und Rechnungs-PDFs lagen unter `public/static/uploads/...` im Web-Root und wurden von Apache direkt ausgeliefert, bevor der Request `index.php`/`Auth::require()` erreichte – ein Angreifer konnte Belege ohne Anmeldung per URL abrufen.
|
||||||
|
- **`src/Config.php`:** `upload_dir` zeigt jetzt auf `data/uploads` (außerhalb des Web-Roots, analog zum bereits per Apache gesperrten `/data`-Verzeichnis)
|
||||||
|
- **`src/Models/Beleg.php`:** Neue Methode `absolutePath()` als einzige Quelle für die Pfad-Auflösung; unterstützt weiterhin Bestandsdaten mit dem alten Präfix `static/uploads/` in `storage_path`
|
||||||
|
- **`src/Controllers/BelegController.php`, `InvoiceController.php`, `BankController.php`, `src/Services/NextcloudImportService.php`, `KontierungsvorschlagService.php`:** Alle Stellen, die Beleg-Dateien schreiben oder lesen, nutzen jetzt `Config::get('upload_dir')` bzw. `Beleg::absolutePath()` statt eigener `public/static/uploads`-Pfade
|
||||||
|
- **`docker-compose.yml`, `Dockerfile`, `docker-entrypoint.sh`:** Upload-Verzeichnis wird nach `/var/www/html/data/uploads` gemountet/angelegt (bestehender Host-Ordner `./uploads` bleibt unverändert)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## 2026-07-06 – Fix: Fehlermeldung beim Beleg-Löschen, falls Datei nicht löschbar ist (Issue #114)
|
## 2026-07-06 – Fix: Fehlermeldung beim Beleg-Löschen, falls Datei nicht löschbar ist (Issue #114)
|
||||||
|
|
||||||
- **`src/Models/Beleg.php`:** `delete()` nutzte ein ungeschütztes `unlink()`; schlug dieses auf dem Server mit „Permission denied" fehl, wurde eine PHP-Warning ausgegeben, die den nachfolgenden Redirect-Header zerstörte („headers already sent"). Der Datensatz wurde dabei trotzdem gelöscht, was zu Verwirrung führte. Fehler beim Datei-Löschen wird jetzt abgefangen und nur noch geloggt (`error_log`), die Löschung des Datensatzes läuft unverändert durch.
|
- **`src/Models/Beleg.php`:** `delete()` nutzte ein ungeschütztes `unlink()`; schlug dieses auf dem Server mit „Permission denied" fehl, wurde eine PHP-Warning ausgegeben, die den nachfolgenden Redirect-Header zerstörte („headers already sent"). Der Datensatz wurde dabei trotzdem gelöscht, was zu Verwirrung führte. Fehler beim Datei-Löschen wird jetzt abgefangen und nur noch geloggt (`error_log`), die Löschung des Datensatzes läuft unverändert durch.
|
||||||
|
|
|
||||||
|
|
@ -36,9 +36,8 @@ COPY apache/steuerkram.conf /etc/apache2/sites-available/000-default.conf
|
||||||
RUN a2enmod rewrite headers
|
RUN a2enmod rewrite headers
|
||||||
|
|
||||||
# Permissions
|
# Permissions
|
||||||
RUN mkdir -p /var/www/html/public/static/uploads /var/www/html/data \
|
RUN mkdir -p /var/www/html/data/uploads \
|
||||||
&& chown -R www-data:www-data /var/www/html \
|
&& chown -R www-data:www-data /var/www/html \
|
||||||
&& chmod -R 755 /var/www/html/public/static/uploads \
|
|
||||||
&& chmod -R 755 /var/www/html/data
|
&& chmod -R 755 /var/www/html/data
|
||||||
|
|
||||||
EXPOSE 80
|
EXPOSE 80
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ services:
|
||||||
- ./public:/var/www/html/public
|
- ./public:/var/www/html/public
|
||||||
- ./src:/var/www/html/src
|
- ./src:/var/www/html/src
|
||||||
- ./migrations:/var/www/html/migrations
|
- ./migrations:/var/www/html/migrations
|
||||||
- ./uploads:/var/www/html/public/static/uploads
|
- ./uploads:/var/www/html/data/uploads
|
||||||
- ./data:/var/www/html/data
|
- ./data:/var/www/html/data
|
||||||
- ./tests:/var/www/html/tests
|
- ./tests:/var/www/html/tests
|
||||||
- ./scripts:/var/www/html/scripts
|
- ./scripts:/var/www/html/scripts
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
# Fix ownership of volume-mounted upload directory at container start
|
# Fix ownership of volume-mounted upload directory at container start
|
||||||
chown -R www-data:www-data /var/www/html/public/static/uploads 2>/dev/null || true
|
chown -R www-data:www-data /var/www/html/data/uploads 2>/dev/null || true
|
||||||
|
|
||||||
# Datenbank-Migrationen automatisch einspielen
|
# Datenbank-Migrationen automatisch einspielen
|
||||||
php /var/www/html/scripts/migrate.php
|
php /var/www/html/scripts/migrate.php
|
||||||
|
|
|
||||||
|
|
@ -116,7 +116,7 @@ MariaDB 11, Engine InnoDB, Zeichensatz `utf8mb4_unicode_ci`. Das Schema wird dur
|
||||||
| `id` | INT UNSIGNED PK | |
|
| `id` | INT UNSIGNED PK | |
|
||||||
| `beleg_nr` | VARCHAR(30) UNIQUE | Automatisch vergeben (z.B. `BLG-2026-0001`) |
|
| `beleg_nr` | VARCHAR(30) UNIQUE | Automatisch vergeben (z.B. `BLG-2026-0001`) |
|
||||||
| `filename` | VARCHAR(500) | Originaldateiname |
|
| `filename` | VARCHAR(500) | Originaldateiname |
|
||||||
| `storage_path` | VARCHAR(500) | Pfad unter `public/static/uploads/` |
|
| `storage_path` | VARCHAR(500) | Relativer Pfad unter `data/uploads/` (außerhalb des Web-Roots, Bestandsdaten mit altem Präfix `static/uploads/` werden von `Beleg::absolutePath()` weiter unterstützt) |
|
||||||
| `mime_type` | VARCHAR(100) | MIME-Typ der Datei |
|
| `mime_type` | VARCHAR(100) | MIME-Typ der Datei |
|
||||||
| `file_hash` | VARCHAR(64) | SHA-256 für GoBD-Integritätsprüfung |
|
| `file_hash` | VARCHAR(64) | SHA-256 für GoBD-Integritätsprüfung |
|
||||||
| `beleg_datum` | DATE | Datum auf dem Dokument |
|
| `beleg_datum` | DATE | Datum auf dem Dokument |
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ class Config
|
||||||
'db_pass' => $_ENV['DB_PASS'] ?? getenv('DB_PASS') ?: 'steuerkram',
|
'db_pass' => $_ENV['DB_PASS'] ?? getenv('DB_PASS') ?: 'steuerkram',
|
||||||
'app_key' => $_ENV['APP_KEY'] ?? getenv('APP_KEY') ?: '',
|
'app_key' => $_ENV['APP_KEY'] ?? getenv('APP_KEY') ?: '',
|
||||||
'sidebar_bg_color' => $_ENV['SIDEBAR_BG_COLOR'] ?? getenv('SIDEBAR_BG_COLOR') ?: '#1e293b',
|
'sidebar_bg_color' => $_ENV['SIDEBAR_BG_COLOR'] ?? getenv('SIDEBAR_BG_COLOR') ?: '#1e293b',
|
||||||
'upload_dir' => dirname(__DIR__) . '/public/static/uploads',
|
'upload_dir' => dirname(__DIR__) . '/data/uploads',
|
||||||
'base_url' => '',
|
'base_url' => '',
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ declare(strict_types=1);
|
||||||
|
|
||||||
namespace Steuerkram\Controllers;
|
namespace Steuerkram\Controllers;
|
||||||
|
|
||||||
|
use Steuerkram\Config;
|
||||||
use Steuerkram\Models\BankProvider;
|
use Steuerkram\Models\BankProvider;
|
||||||
use Steuerkram\Models\BankSource;
|
use Steuerkram\Models\BankSource;
|
||||||
use Steuerkram\Models\BankTransaction;
|
use Steuerkram\Models\BankTransaction;
|
||||||
|
|
@ -350,12 +351,12 @@ class BankController extends BaseController
|
||||||
$ext = $allowedMime[$mime];
|
$ext = $allowedMime[$mime];
|
||||||
$belegNr = Beleg::generateBelegNr();
|
$belegNr = Beleg::generateBelegNr();
|
||||||
$year = date('Y', strtotime($transaction['wertstellung']));
|
$year = date('Y', strtotime($transaction['wertstellung']));
|
||||||
$relDir = "static/uploads/{$year}/{$belegNr}";
|
$relDir = "{$year}/{$belegNr}";
|
||||||
$absDir = dirname(__DIR__, 2) . "/public/{$relDir}";
|
$absDir = Config::get('upload_dir') . "/{$relDir}";
|
||||||
if (!is_dir($absDir)) mkdir($absDir, 0755, true);
|
if (!is_dir($absDir)) mkdir($absDir, 0755, true);
|
||||||
|
|
||||||
$storagePath = "{$relDir}/original.{$ext}";
|
$storagePath = "{$relDir}/original.{$ext}";
|
||||||
$absPath = dirname(__DIR__, 2) . "/public/{$storagePath}";
|
$absPath = Config::get('upload_dir') . "/{$storagePath}";
|
||||||
move_uploaded_file($file['tmp_name'], $absPath);
|
move_uploaded_file($file['tmp_name'], $absPath);
|
||||||
$hash = hash_file('sha256', $absPath);
|
$hash = hash_file('sha256', $absPath);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ declare(strict_types=1);
|
||||||
|
|
||||||
namespace Steuerkram\Controllers;
|
namespace Steuerkram\Controllers;
|
||||||
|
|
||||||
|
use Steuerkram\Config;
|
||||||
use Steuerkram\Models\Beleg;
|
use Steuerkram\Models\Beleg;
|
||||||
use Steuerkram\Models\Booking;
|
use Steuerkram\Models\Booking;
|
||||||
use Steuerkram\Models\Account;
|
use Steuerkram\Models\Account;
|
||||||
|
|
@ -159,14 +160,14 @@ class BelegController extends BaseController
|
||||||
: date('Y');
|
: date('Y');
|
||||||
|
|
||||||
// Store under uploads/{year}/{belegNr}/original.{ext}
|
// Store under uploads/{year}/{belegNr}/original.{ext}
|
||||||
$relDir = "static/uploads/{$year}/{$belegNr}";
|
$relDir = "{$year}/{$belegNr}";
|
||||||
$absDir = dirname(__DIR__, 2) . "/public/{$relDir}";
|
$absDir = Config::get('upload_dir') . "/{$relDir}";
|
||||||
if (!is_dir($absDir)) mkdir($absDir, 0755, true);
|
if (!is_dir($absDir)) mkdir($absDir, 0755, true);
|
||||||
|
|
||||||
$filename = pathinfo($file['name'], PATHINFO_BASENAME);
|
$filename = pathinfo($file['name'], PATHINFO_BASENAME);
|
||||||
$filenameWithoutExt = pathinfo($file['name'], PATHINFO_FILENAME);
|
$filenameWithoutExt = pathinfo($file['name'], PATHINFO_FILENAME);
|
||||||
$storagePath = "{$relDir}/original.{$ext}";
|
$storagePath = "{$relDir}/original.{$ext}";
|
||||||
$absPath = dirname(__DIR__, 2) . "/public/{$storagePath}";
|
$absPath = Config::get('upload_dir') . "/{$storagePath}";
|
||||||
|
|
||||||
move_uploaded_file($file['tmp_name'], $absPath);
|
move_uploaded_file($file['tmp_name'], $absPath);
|
||||||
|
|
||||||
|
|
@ -311,8 +312,8 @@ class BelegController extends BaseController
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
$basePath = (string)realpath(dirname(__DIR__, 2) . '/public/static/uploads');
|
$basePath = (string)realpath(Config::get('upload_dir'));
|
||||||
$absPath = dirname(__DIR__, 2) . '/public/' . $beleg['storage_path'];
|
$absPath = Beleg::absolutePath($beleg);
|
||||||
$realPath = realpath($absPath);
|
$realPath = realpath($absPath);
|
||||||
|
|
||||||
if ($realPath === false || !str_starts_with($realPath, $basePath)) {
|
if ($realPath === false || !str_starts_with($realPath, $basePath)) {
|
||||||
|
|
@ -466,7 +467,7 @@ class BelegController extends BaseController
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$absPath = dirname(__DIR__, 2) . '/public/' . $beleg['storage_path'];
|
$absPath = Beleg::absolutePath($beleg);
|
||||||
if (!file_exists($absPath)) {
|
if (!file_exists($absPath)) {
|
||||||
http_response_code(404);
|
http_response_code(404);
|
||||||
echo json_encode(['error' => 'Datei nicht gefunden.']);
|
echo json_encode(['error' => 'Datei nicht gefunden.']);
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ declare(strict_types=1);
|
||||||
|
|
||||||
namespace Steuerkram\Controllers;
|
namespace Steuerkram\Controllers;
|
||||||
|
|
||||||
|
use Steuerkram\Config;
|
||||||
use Steuerkram\Models\Invoice;
|
use Steuerkram\Models\Invoice;
|
||||||
use Steuerkram\Models\Customer;
|
use Steuerkram\Models\Customer;
|
||||||
use Steuerkram\Models\Beleg;
|
use Steuerkram\Models\Beleg;
|
||||||
|
|
@ -291,8 +292,8 @@ class InvoiceController extends BaseController
|
||||||
$beleg = null;
|
$beleg = null;
|
||||||
if (!empty($invoice['beleg_id'])) {
|
if (!empty($invoice['beleg_id'])) {
|
||||||
$beleg = Beleg::find((int)$invoice['beleg_id']);
|
$beleg = Beleg::find((int)$invoice['beleg_id']);
|
||||||
$absPath = $beleg
|
$absPath = ($beleg && !empty($beleg['storage_path']))
|
||||||
? dirname(__DIR__, 2) . '/public/' . $beleg['storage_path']
|
? Beleg::absolutePath($beleg)
|
||||||
: '';
|
: '';
|
||||||
if ($absPath && is_file($absPath)) {
|
if ($absPath && is_file($absPath)) {
|
||||||
header('Content-Type: application/pdf');
|
header('Content-Type: application/pdf');
|
||||||
|
|
@ -322,17 +323,17 @@ class InvoiceController extends BaseController
|
||||||
if ($invoice['status'] !== 'Entwurf' && $beleg !== null) {
|
if ($invoice['status'] !== 'Entwurf' && $beleg !== null) {
|
||||||
if (!empty($beleg['storage_path'])) {
|
if (!empty($beleg['storage_path'])) {
|
||||||
$relPath = $beleg['storage_path'];
|
$relPath = $beleg['storage_path'];
|
||||||
$absDir = dirname(dirname(__DIR__, 2) . '/public/' . $relPath);
|
$absDir = dirname(Beleg::absolutePath($beleg));
|
||||||
} else {
|
} else {
|
||||||
$year = date('Y', strtotime($invoice['rechnungs_datum']));
|
$year = date('Y', strtotime($invoice['rechnungs_datum']));
|
||||||
$relDir = 'static/uploads/' . $year . '/' . $beleg['beleg_nr'];
|
$relDir = $year . '/' . $beleg['beleg_nr'];
|
||||||
$relPath = $relDir . '/original.pdf';
|
$relPath = $relDir . '/original.pdf';
|
||||||
$absDir = dirname(__DIR__, 2) . '/public/' . $relDir;
|
$absDir = Config::get('upload_dir') . '/' . $relDir;
|
||||||
}
|
}
|
||||||
if (!is_dir($absDir)) {
|
if (!is_dir($absDir)) {
|
||||||
mkdir($absDir, 0755, true);
|
mkdir($absDir, 0755, true);
|
||||||
}
|
}
|
||||||
$absFilePath = dirname(__DIR__, 2) . '/public/' . $relPath;
|
$absFilePath = Beleg::absolutePath(['storage_path' => $relPath]);
|
||||||
file_put_contents($absFilePath, $pdf);
|
file_put_contents($absFilePath, $pdf);
|
||||||
\Steuerkram\Database::execute(
|
\Steuerkram\Database::execute(
|
||||||
'UPDATE belege SET storage_path=?, filename=?, file_hash=?, updated_at=NOW() WHERE id=?',
|
'UPDATE belege SET storage_path=?, filename=?, file_hash=?, updated_at=NOW() WHERE id=?',
|
||||||
|
|
@ -512,13 +513,13 @@ class InvoiceController extends BaseController
|
||||||
|
|
||||||
$belegNr = Beleg::generateBelegNr();
|
$belegNr = Beleg::generateBelegNr();
|
||||||
$year = date('Y', strtotime($invoice['rechnungs_datum']));
|
$year = date('Y', strtotime($invoice['rechnungs_datum']));
|
||||||
$relDir = "static/uploads/{$year}/{$belegNr}";
|
$relDir = "{$year}/{$belegNr}";
|
||||||
$absDir = dirname(__DIR__, 2) . "/public/{$relDir}";
|
$absDir = Config::get('upload_dir') . "/{$relDir}";
|
||||||
if (!is_dir($absDir)) mkdir($absDir, 0755, true);
|
if (!is_dir($absDir)) mkdir($absDir, 0755, true);
|
||||||
|
|
||||||
$filename = $invoice['rechnungs_nr'] . '.pdf';
|
$filename = $invoice['rechnungs_nr'] . '.pdf';
|
||||||
$storagePath = "{$relDir}/original.pdf";
|
$storagePath = "{$relDir}/original.pdf";
|
||||||
file_put_contents(dirname(__DIR__, 2) . "/public/{$storagePath}", $pdf);
|
file_put_contents(Config::get('upload_dir') . "/{$storagePath}", $pdf);
|
||||||
|
|
||||||
$belegId = Beleg::create([
|
$belegId = Beleg::create([
|
||||||
'invoice_id' => $id,
|
'invoice_id' => $id,
|
||||||
|
|
|
||||||
|
|
@ -4,10 +4,21 @@ declare(strict_types=1);
|
||||||
|
|
||||||
namespace Steuerkram\Models;
|
namespace Steuerkram\Models;
|
||||||
|
|
||||||
|
use Steuerkram\Config;
|
||||||
use Steuerkram\Database;
|
use Steuerkram\Database;
|
||||||
|
|
||||||
class Beleg
|
class Beleg
|
||||||
{
|
{
|
||||||
|
// Bestandsdaten mit altem, webroot-relativem Präfix "static/uploads/" bleiben lesbar.
|
||||||
|
public static function absolutePath(array $beleg): string
|
||||||
|
{
|
||||||
|
$relPath = (string)($beleg['storage_path'] ?? '');
|
||||||
|
if (str_starts_with($relPath, 'static/uploads/')) {
|
||||||
|
$relPath = substr($relPath, strlen('static/uploads/'));
|
||||||
|
}
|
||||||
|
return Config::get('upload_dir') . '/' . $relPath;
|
||||||
|
}
|
||||||
|
|
||||||
public static function all(array $filter = [], int $page = 1, int $perPage = 30): array
|
public static function all(array $filter = [], int $page = 1, int $perPage = 30): array
|
||||||
{
|
{
|
||||||
$where = ['1=1'];
|
$where = ['1=1'];
|
||||||
|
|
@ -250,7 +261,7 @@ class Beleg
|
||||||
if ($cnt && $cnt['cnt'] > 0) return false;
|
if ($cnt && $cnt['cnt'] > 0) return false;
|
||||||
|
|
||||||
// Delete file (Datei-Löschung darf DB-Löschung nicht durch Warnings/Header-Fehler stören)
|
// Delete file (Datei-Löschung darf DB-Löschung nicht durch Warnings/Header-Fehler stören)
|
||||||
$fullPath = dirname(__DIR__, 2) . '/public/' . $beleg['storage_path'];
|
$fullPath = self::absolutePath($beleg);
|
||||||
if (file_exists($fullPath) && !@unlink($fullPath)) {
|
if (file_exists($fullPath) && !@unlink($fullPath)) {
|
||||||
error_log('Beleg::delete: Datei konnte nicht gelöscht werden: ' . $fullPath);
|
error_log('Beleg::delete: Datei konnte nicht gelöscht werden: ' . $fullPath);
|
||||||
}
|
}
|
||||||
|
|
@ -300,7 +311,7 @@ class Beleg
|
||||||
$beleg = self::find($id);
|
$beleg = self::find($id);
|
||||||
if (!$beleg) return false;
|
if (!$beleg) return false;
|
||||||
|
|
||||||
$fullPath = dirname(__DIR__, 2) . '/public/' . $beleg['storage_path'];
|
$fullPath = self::absolutePath($beleg);
|
||||||
if (!file_exists($fullPath)) return false;
|
if (!file_exists($fullPath)) return false;
|
||||||
|
|
||||||
return hash_file('sha256', $fullPath) === $beleg['file_hash'];
|
return hash_file('sha256', $fullPath) === $beleg['file_hash'];
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ class KontierungsvorschlagService
|
||||||
|
|
||||||
public function extractText(array $beleg): string
|
public function extractText(array $beleg): string
|
||||||
{
|
{
|
||||||
$absPath = dirname(__DIR__, 2) . '/public/' . $beleg['storage_path'];
|
$absPath = Beleg::absolutePath($beleg);
|
||||||
if (!file_exists($absPath)) return '';
|
if (!file_exists($absPath)) return '';
|
||||||
|
|
||||||
$mime = strtolower($beleg['mime_type'] ?? '');
|
$mime = strtolower($beleg['mime_type'] ?? '');
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ declare(strict_types=1);
|
||||||
|
|
||||||
namespace Steuerkram\Services;
|
namespace Steuerkram\Services;
|
||||||
|
|
||||||
|
use Steuerkram\Config;
|
||||||
use Steuerkram\Database;
|
use Steuerkram\Database;
|
||||||
use Steuerkram\Models\Beleg;
|
use Steuerkram\Models\Beleg;
|
||||||
use Steuerkram\Models\EventLog;
|
use Steuerkram\Models\EventLog;
|
||||||
|
|
@ -260,8 +261,8 @@ class NextcloudImportService
|
||||||
// In Upload-Verzeichnis ablegen
|
// In Upload-Verzeichnis ablegen
|
||||||
$belegNr = Beleg::generateBelegNr();
|
$belegNr = Beleg::generateBelegNr();
|
||||||
$year = date('Y');
|
$year = date('Y');
|
||||||
$relDir = "static/uploads/{$year}/{$belegNr}";
|
$relDir = "{$year}/{$belegNr}";
|
||||||
$absDir = dirname(__DIR__, 2) . "/public/{$relDir}";
|
$absDir = Config::get('upload_dir') . "/{$relDir}";
|
||||||
|
|
||||||
if (!is_dir($absDir) && !mkdir($absDir, 0755, true)) {
|
if (!is_dir($absDir) && !mkdir($absDir, 0755, true)) {
|
||||||
$msg = "FEHLER: Verzeichnis konnte nicht erstellt werden: {$absDir}";
|
$msg = "FEHLER: Verzeichnis konnte nicht erstellt werden: {$absDir}";
|
||||||
|
|
@ -273,7 +274,7 @@ class NextcloudImportService
|
||||||
}
|
}
|
||||||
|
|
||||||
$storagePath = "{$relDir}/original.{$ext}";
|
$storagePath = "{$relDir}/original.{$ext}";
|
||||||
$absPath = dirname(__DIR__, 2) . "/public/{$storagePath}";
|
$absPath = Config::get('upload_dir') . "/{$storagePath}";
|
||||||
|
|
||||||
if (!rename($tmpPath, $absPath)) {
|
if (!rename($tmpPath, $absPath)) {
|
||||||
$msg = "FEHLER: Datei konnte nicht verschoben werden: {$filename}";
|
$msg = "FEHLER: Datei konnte nicht verschoben werden: {$filename}";
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ class BelegDeleteUnlinkFailTest extends TestCase
|
||||||
|
|
||||||
public function run(): void
|
public function run(): void
|
||||||
{
|
{
|
||||||
$dir = dirname(__DIR__) . '/public/static/uploads/test_49_unlink_fail';
|
$dir = \Steuerkram\Config::get('upload_dir') . '/test_49_unlink_fail';
|
||||||
$file = $dir . '/original.pdf';
|
$file = $dir . '/original.pdf';
|
||||||
|
|
||||||
mkdir($dir, 0755, true);
|
mkdir($dir, 0755, true);
|
||||||
|
|
@ -23,7 +23,7 @@ class BelegDeleteUnlinkFailTest extends TestCase
|
||||||
$id = Beleg::create([
|
$id = Beleg::create([
|
||||||
'beleg_nr' => 'BLG-TEST-49',
|
'beleg_nr' => 'BLG-TEST-49',
|
||||||
'filename' => 'original.pdf',
|
'filename' => 'original.pdf',
|
||||||
'storage_path' => 'static/uploads/test_49_unlink_fail/original.pdf',
|
'storage_path' => 'test_49_unlink_fail/original.pdf',
|
||||||
'mime_type' => 'application/pdf',
|
'mime_type' => 'application/pdf',
|
||||||
'file_hash' => 'testhash49',
|
'file_hash' => 'testhash49',
|
||||||
'beleg_datum' => '2026-01-01',
|
'beleg_datum' => '2026-01-01',
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue