diff --git a/Admin/Installer.php b/Admin/Installer.php index 39a864f..679f265 100755 --- a/Admin/Installer.php +++ b/Admin/Installer.php @@ -58,6 +58,10 @@ final class Installer extends InstallerAbstract */ public static function install(DatabasePool $dbPool, ModuleInfo $info, SettingsInterface $cfgHandler) : void { + if (!\is_dir(__DIR__ . '/../Files')) { + \mkdir(__DIR__ . '/../Files'); + } + parent::install($dbPool, $info, $cfgHandler); // Create directory for admin account @@ -255,12 +259,13 @@ final class Installer extends InstallerAbstract } } - $upload = new UploadFile(); - $upload->outputDir = empty($data['path'] ?? '') + $upload = new UploadFile(); + $upload->preserveFileName = $data['fixed_names'] ?? true; + $upload->outputDir = empty($data['path'] ?? '') ? ApiController::createMediaPath() : __DIR__ . '/../../..' . $data['path']; - $status = $upload->upload($files, [$data['name']], true); + $status = $upload->upload($files, ($data['fixed_names'] ?? true) ? [] : [$data['name']], true); $mediaFiles = []; foreach ($status as $uFile) { diff --git a/Controller/ApiController.php b/Controller/ApiController.php index ac7f964..5b17204 100755 --- a/Controller/ApiController.php +++ b/Controller/ApiController.php @@ -70,7 +70,8 @@ final class ApiController extends Controller public function apiMediaUpload(RequestAbstract $request, ResponseAbstract $response, $data = null) : void { $uploads = $this->uploadFiles( - [$request->getData('name') === null ? '' : $request->getData('name')], + $request->getDataList('names') ?? [], + $request->getDataList('filenames') ?? [], $request->getFiles(), $request->header->account, __DIR__ . '/../../../Modules/Media/Files' . \urldecode((string) ($request->getData('path') ?? '')), @@ -119,7 +120,8 @@ final class ApiController extends Controller /** * Upload a media file * - * @param array $names Name + * @param array $names Database names + * @param array $fileNames FileNames * @param array $files Files * @param int $account Uploader * @param string $basePath Base path. The path which is used for the upload. @@ -138,6 +140,7 @@ final class ApiController extends Controller */ public function uploadFiles( array $names, + array $fileNames, array $files, int $account, string $basePath = '/Modules/Media/Files', @@ -164,10 +167,17 @@ final class ApiController extends Controller return []; } - $upload = new UploadFile(); - $upload->outputDir = $outputDir; + $upload = new UploadFile(); + $upload->outputDir = $outputDir; - $status = $upload->upload($files, $names, $absolute, $encryptionKey); + $status = $upload->upload($files, $fileNames, $absolute, $encryptionKey); + + $sameLength = \count($names) === \count($status); + $nCounter = -1; + foreach ($status as &$stat) { + ++$nCounter; + $stat['name'] = $sameLength ? $names[$nCounter] : $stat['filename']; + } return $this->createDbEntries($status, $account, $virtualPath, $type); } @@ -175,9 +185,9 @@ final class ApiController extends Controller /** * Uploads a file to a destination * - * @param array $files Files to upload - * @param array $names Name of the file (only if a single file is provided) - * @param string $path Upload path + * @param array $files Files to upload + * @param array $fileNames Names on the directory + * @param string $path Upload path * * @return array * @@ -185,14 +195,14 @@ final class ApiController extends Controller */ public static function uploadFilesToDestination( array $files, - array $names = [], + array $fileNames = [], string $path = '', ) : array { - $upload = new UploadFile(); - $upload->outputDir = $path; + $upload = new UploadFile(); + $upload->outputDir = $path; - $status = $upload->upload($files, $names, true, ''); + $status = $upload->upload($files, $fileNames, true, ''); return $status; } diff --git a/Models/UploadFile.php b/Models/UploadFile.php index d054389..5d58eea 100755 --- a/Models/UploadFile.php +++ b/Models/UploadFile.php @@ -83,7 +83,7 @@ class UploadFile * Upload file to server. * * @param array $files File data ($_FILE) - * @param string[] $names File name + * @param string[] $fileNames File name * @param bool $absolute Use absolute path * @param string $encryptionKey Encryption key * @param string $encoding Encoding used for uploaded file. Empty string will not convert file content. @@ -96,13 +96,14 @@ class UploadFile */ public function upload( array $files, - array $names = [], + array $fileNames = [], bool $absolute = false, string $encryptionKey = '', string $encoding = 'UTF-8' ) : array { - $result = []; + $result = []; + $fileNames = $this->preserveFileName || \count($files) !== \count($fileNames) ? [] : $fileNames; if (\count($files) === \count($files, \COUNT_RECURSIVE)) { $files = [$files]; @@ -114,11 +115,9 @@ class UploadFile $path = $this->outputDir; $fCounter = -1; - $areNamed = \count($files) === \count($names); foreach ($files as $key => $f) { ++$fCounter; - $name = $areNamed ? $names[$fCounter] : ''; if ($path === '') { $path = File::dirpath($f['tmp_name']); @@ -151,15 +150,17 @@ class UploadFile return $result; } - $split = \explode('.', $f['name']); - $result[$key]['filename'] = !empty($name) && !$this->preserveFileName ? $name : $f['name']; - - $extension = \count($split) > 1 ? $split[\count($split) - 1] : ''; - $result[$key]['extension'] = $extension; + $split = \explode('.', $f['name']); + $result[$key]['filename'] = !empty($fileNames) ? $fileNames[$fCounter] : $f['name']; + $result[$key]['extension'] = ($c = \count($split)) > 1 ? $split[$c - 1] : ''; if (!$this->preserveFileName || \is_file($path . '/' . $result[$key]['filename'])) { try { - $result[$key]['filename'] = $this->createFileName($path, $f['tmp_name'], $extension); + $result[$key]['filename'] = $this->createFileName( + $path, + $this->preserveFileName ? $result[$key]['filename'] : '', + $result[$key]['extension'] + ); } catch (\Exception $e) { $result[$key]['filename'] = $f['name']; $result[$key]['status'] = UploadStatus::FAILED_HASHING; @@ -168,12 +169,8 @@ class UploadFile } } - $result[$key]['name'] = empty($name) ? $result[$key]['filename'] : $name; - if (!\is_dir($path)) { - $created = Directory::create($path, 0755, true); - - if (!$created) { + if (!Directory::create($path, 0755, true)) { FileLogger::getInstance()->error('Couldn\t upload media file. There maybe is a problem with your permission or uploaded file.'); } } @@ -244,10 +241,13 @@ class UploadFile private function createFileName(string $path, string $tempName, string $extension) : string { $rnd = ''; - $limit = 0; + $limit = -1; + + $nameWithoutExtension = empty($tempName) ? '' : \substr($tempName, 0, -\strlen($extension) - 1); do { - $sha = \sha1($tempName . $rnd); + ++$limit; + $sha = empty($nameWithoutExtension) ? \sha1($tempName . $rnd) : $nameWithoutExtension . '_' . $rnd; if ($sha === false) { throw new \Exception('No file path could be found. Potential attack!'); @@ -256,7 +256,6 @@ class UploadFile $sha .= '.' . $extension; $fileName = $sha; $rnd = \mt_rand(); - ++$limit; } while (\is_file($path . '/' . $fileName) && $limit < self::PATH_GENERATION_LIMIT); if ($limit >= self::PATH_GENERATION_LIMIT) { diff --git a/tests/Bootstrap.php b/tests/Bootstrap.php index 051ac7e..f5fc99c 100755 --- a/tests/Bootstrap.php +++ b/tests/Bootstrap.php @@ -392,4 +392,4 @@ function phpServe() : void }); } -phpServe(); +\phpServe(); diff --git a/tests/Controller/Api/ApiControllerMediaTrait.php b/tests/Controller/Api/ApiControllerMediaTrait.php index 2f4cf9a..1e33f5f 100755 --- a/tests/Controller/Api/ApiControllerMediaTrait.php +++ b/tests/Controller/Api/ApiControllerMediaTrait.php @@ -172,7 +172,7 @@ trait ApiControllerMediaTrait { self::assertEquals( [], - $this->module->uploadFiles(['test'], ['test'], 1, '/test', '', null, '', '', 99) + $this->module->uploadFiles(['test'], ['test'], ['test'], 1, '/test', '', null, '', '', 99) ); }