diff --git a/Controller/AiScanInvoice.php b/Controller/AiScanInvoice.php
index 2863833..2a2d227 100644
--- a/Controller/AiScanInvoice.php
+++ b/Controller/AiScanInvoice.php
@@ -27,6 +27,7 @@
use FacturaScripts\Plugins\AiScan\Lib\ExtractionService;
use FacturaScripts\Plugins\AiScan\Lib\HistoricalContextService;
use FacturaScripts\Plugins\AiScan\Lib\InvoiceMapper;
+use FacturaScripts\Plugins\AiScan\Lib\StoragePathHelper;
use FacturaScripts\Plugins\AiScan\Lib\SupplierMatcher;
use FacturaScripts\Plugins\AiScan\Model\AiScanImportBatch;
use FacturaScripts\Plugins\AiScan\Model\AiScanImportDocument;
@@ -259,7 +260,7 @@ private function storeUploadedFile(array $file, int $clientIndex): array
);
}
- $tmpDir = FS_FOLDER . '/MyFiles/aiscan_tmp';
+ $tmpDir = StoragePathHelper::absoluteDirectory();
if (!is_dir($tmpDir)) {
mkdir($tmpDir, 0700, true);
}
@@ -341,7 +342,7 @@ private function handleAnalyze(): void
echo json_encode(['error' => Tools::lang()->trans('aiscan-invalid-file-name')]);
return;
}
- $tmpPath = FS_FOLDER . '/MyFiles/aiscan_tmp/' . $tmpFile;
+ $tmpPath = StoragePathHelper::absoluteFile($tmpFile);
if (!file_exists($tmpPath)) {
http_response_code(404);
@@ -631,7 +632,7 @@ private function handleGetText(): void
echo json_encode(['error' => Tools::lang()->trans('aiscan-invalid-file-name')]);
return;
}
- $tmpPath = FS_FOLDER . '/MyFiles/aiscan_tmp/' . $tmpFile;
+ $tmpPath = StoragePathHelper::absoluteFile($tmpFile);
if (!file_exists($tmpPath)) {
http_response_code(404);
diff --git a/Lib/AttachmentService.php b/Lib/AttachmentService.php
index fa974ce..eb9365a 100644
--- a/Lib/AttachmentService.php
+++ b/Lib/AttachmentService.php
@@ -35,8 +35,8 @@ public function attachTemporaryFile(FacturaProveedor $invoice, array $uploadData
return;
}
- $tmpDir = realpath(FS_FOLDER . '/MyFiles/aiscan_tmp');
- $tmpPath = realpath(FS_FOLDER . '/MyFiles/aiscan_tmp/' . $tmpFile);
+ $tmpDir = realpath(StoragePathHelper::absoluteDirectory());
+ $tmpPath = realpath(StoragePathHelper::absoluteFile($tmpFile));
$prefix = false === $tmpDir ? '' : rtrim($tmpDir, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR;
if (
false === $tmpDir
@@ -58,7 +58,7 @@ public function attachTemporaryFile(FacturaProveedor $invoice, array $uploadData
}
$attachedFile = new AttachedFile();
- $attachedFile->path = 'aiscan_tmp/' . $tmpFile;
+ $attachedFile->path = StoragePathHelper::relativeFile($tmpFile);
if (false === $attachedFile->save()) {
return;
}
diff --git a/Lib/ExtractionService.php b/Lib/ExtractionService.php
index a5f3252..62003b5 100644
--- a/Lib/ExtractionService.php
+++ b/Lib/ExtractionService.php
@@ -638,7 +638,7 @@ public static function extractPdfText(string $filePath): string
}
$realPath = realpath($filePath);
- $expectedDir = realpath(FS_FOLDER . '/MyFiles/aiscan_tmp');
+ $expectedDir = realpath(StoragePathHelper::absoluteDirectory());
if ($realPath === false || $expectedDir === false || strpos($realPath, $expectedDir) !== 0) {
return '';
}
diff --git a/Lib/StoragePathHelper.php b/Lib/StoragePathHelper.php
new file mode 100644
index 0000000..3f5fb8c
--- /dev/null
+++ b/Lib/StoragePathHelper.php
@@ -0,0 +1,41 @@
+
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see .
+ */
+
+namespace FacturaScripts\Plugins\AiScan\Lib;
+
+final class StoragePathHelper
+{
+ private const DIRECTORY = 'aiscan';
+
+ public static function absoluteDirectory(): string
+ {
+ return FS_FOLDER . '/MyFiles/' . self::DIRECTORY;
+ }
+
+ public static function absoluteFile(string $filename): string
+ {
+ return self::absoluteDirectory() . '/' . basename($filename);
+ }
+
+ public static function relativeFile(string $filename): string
+ {
+ return self::DIRECTORY . '/' . basename($filename);
+ }
+}
diff --git a/Test/main/AiScanInvoiceControllerTest.php b/Test/main/AiScanInvoiceControllerTest.php
index 2823597..77f54d7 100644
--- a/Test/main/AiScanInvoiceControllerTest.php
+++ b/Test/main/AiScanInvoiceControllerTest.php
@@ -50,15 +50,15 @@ public function testNormalizeUploadedFilesExpandsMultipleUploadShape(): void
$this->assertSame('image/png', $result[1]['type']);
}
- public function testResolveMimeTypeFallsBackToExtensionForOctetStream(): void
+ public function testResolveMimeTypeFallsBackToExtensionForGenericMimeTypes(): void
{
$controller = $this->buildController();
- $tmpFile = tempnam(sys_get_temp_dir(), 'aiscan-octet-');
+ $tmpFile = tempnam(sys_get_temp_dir(), 'aiscan-generic-');
if (false === $tmpFile) {
self::fail('Failed to create temporary file for MIME fallback test.');
}
- file_put_contents($tmpFile, random_bytes(32));
+ file_put_contents($tmpFile, 'This is plain text content without PDF structure.');
try {
$result = $this->callResolveMimeType($controller, $tmpFile, 'pdf');
diff --git a/Test/main/StoragePathHelperTest.php b/Test/main/StoragePathHelperTest.php
new file mode 100644
index 0000000..bb16212
--- /dev/null
+++ b/Test/main/StoragePathHelperTest.php
@@ -0,0 +1,41 @@
+
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see .
+ */
+
+namespace FacturaScripts\Test\Plugins;
+
+use FacturaScripts\Plugins\AiScan\Lib\StoragePathHelper;
+use PHPUnit\Framework\TestCase;
+
+final class StoragePathHelperTest extends TestCase
+{
+ public function testAbsoluteDirectoryUsesCleanAiScanFolder(): void
+ {
+ $this->assertSame(FS_FOLDER . '/MyFiles/aiscan', StoragePathHelper::absoluteDirectory());
+ }
+
+ public function testAbsoluteAndRelativeFileSanitizeNestedInput(): void
+ {
+ $this->assertSame(
+ FS_FOLDER . '/MyFiles/aiscan/invoice.pdf',
+ StoragePathHelper::absoluteFile('../nested/invoice.pdf')
+ );
+ $this->assertSame('aiscan/invoice.pdf', StoragePathHelper::relativeFile('../nested/invoice.pdf'));
+ }
+}