diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml new file mode 100644 index 00000000..f02bcd69 --- /dev/null +++ b/.github/workflows/codeql-analysis.yml @@ -0,0 +1,20 @@ +name: "CodeQL" + +on: [pull_request] +jobs: + lint: + name: CodeQL + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + with: + fetch-depth: 2 + + - run: git checkout HEAD^2 + + - name: Run CodeQL + run: | + docker run --rm -v $PWD:/app composer sh -c \ + "composer install --profile --ignore-platform-reqs && composer check" diff --git a/composer.json b/composer.json index 667ecfbc..e864431a 100644 --- a/composer.json +++ b/composer.json @@ -4,7 +4,6 @@ "type": "library", "keywords": ["php","framework","upf","utopia","storage"], "license": "MIT", - "authors": [], "autoload": { "psr-4": {"Utopia\\Storage\\":"src/Storage"} }, @@ -13,7 +12,8 @@ }, "scripts": { "lint": "./vendor/bin/pint --test", - "format": "./vendor/bin/pint" + "format": "./vendor/bin/pint", + "check": "./vendor/bin/phpstan analyse --level 5 src tests" }, "require": { "ext-fileinfo": "*", @@ -28,6 +28,7 @@ "require-dev": { "phpunit/phpunit": "^9.3", "vimeo/psalm": "4.0.1", + "phpstan/phpstan": "1.9.x-dev", "laravel/pint": "1.2.*" }, "minimum-stability": "dev" diff --git a/composer.lock b/composer.lock index 56f1adf2..4a2baa8c 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "0e15ac0ae89a77c7420f825af10e33fc", + "content-hash": "1259284323e29983e5aa6073843ff4f4", "packages": [ { "name": "utopia-php/framework", @@ -1274,18 +1274,77 @@ }, "time": "2023-02-07T18:11:17+00:00" }, + { + "name": "phpstan/phpstan", + "version": "1.9.x-dev", + "source": { + "type": "git", + "url": "https://github.com/phpstan/phpstan.git", + "reference": "6c0217aa2b146c3e28474e8be3e87188fac55dac" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/6c0217aa2b146c3e28474e8be3e87188fac55dac", + "reference": "6c0217aa2b146c3e28474e8be3e87188fac55dac", + "shasum": "" + }, + "require": { + "php": "^7.2|^8.0" + }, + "conflict": { + "phpstan/phpstan-shim": "*" + }, + "bin": [ + "phpstan", + "phpstan.phar" + ], + "type": "library", + "autoload": { + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "PHPStan - PHP Static Analysis Tool", + "keywords": [ + "dev", + "static analysis" + ], + "support": { + "issues": "https://github.com/phpstan/phpstan/issues", + "source": "https://github.com/phpstan/phpstan/tree/1.9.x" + }, + "funding": [ + { + "url": "https://github.com/ondrejmirtes", + "type": "github" + }, + { + "url": "https://github.com/phpstan", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpstan/phpstan", + "type": "tidelift" + } + ], + "time": "2023-02-18T15:01:46+00:00" + }, { "name": "phpunit/php-code-coverage", "version": "9.2.x-dev", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "b5f3416da036fb951a557518e8304b3595ff966a" + "reference": "87b660f75adb677ea503dd0b999dc90a999ad720" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/b5f3416da036fb951a557518e8304b3595ff966a", - "reference": "b5f3416da036fb951a557518e8304b3595ff966a", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/87b660f75adb677ea503dd0b999dc90a999ad720", + "reference": "87b660f75adb677ea503dd0b999dc90a999ad720", "shasum": "" }, "require": { @@ -1349,7 +1408,7 @@ "type": "github" } ], - "time": "2023-02-18T16:27:54+00:00" + "time": "2023-02-20T06:08:06+00:00" }, { "name": "phpunit/php-file-iterator", @@ -1598,12 +1657,12 @@ "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "c1bf2dd252dec994ee27d804c038a98fd0d1d940" + "reference": "ada16b71314bc852f7b199856bd2e12930951d24" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/c1bf2dd252dec994ee27d804c038a98fd0d1d940", - "reference": "c1bf2dd252dec994ee27d804c038a98fd0d1d940", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/ada16b71314bc852f7b199856bd2e12930951d24", + "reference": "ada16b71314bc852f7b199856bd2e12930951d24", "shasum": "" }, "require": { @@ -1692,7 +1751,7 @@ "type": "tidelift" } ], - "time": "2023-02-18T16:26:49+00:00" + "time": "2023-02-20T06:03:35+00:00" }, { "name": "psr/container", @@ -3912,7 +3971,9 @@ ], "aliases": [], "minimum-stability": "dev", - "stability-flags": [], + "stability-flags": { + "phpstan/phpstan": 20 + }, "prefer-stable": false, "prefer-lowest": false, "platform": { diff --git a/src/Storage/Device/Local.php b/src/Storage/Device/Local.php index 1f44a668..9e4553d4 100644 --- a/src/Storage/Device/Local.php +++ b/src/Storage/Device/Local.php @@ -170,8 +170,8 @@ public function abort(string $path, string $extra = ''): bool * Read file by given path. * * @param string $path - * @param int offset - * @param int|null $length + * @param int $offset + * @param int $length * @return string * * @throws Exception diff --git a/src/Storage/Device/S3.php b/src/Storage/Device/S3.php index 7b6161c7..6df5c5cc 100644 --- a/src/Storage/Device/S3.php +++ b/src/Storage/Device/S3.php @@ -214,10 +214,9 @@ public function getPath(string $filename, string $prefix = null): string * * @param string $source * @param string $path - * @param int chunk - * @param int chunks + * @param int $chunk + * @param int $chunks * @param array $metadata - * @return int * * @throws \Exception */ @@ -347,11 +346,12 @@ public function abort(string $path, string $extra = ''): bool * Read file or part of file by given path, offset and length. * * @param string $path - * @param int offset - * @param int length + * @param int $offset + * @param int $length * @return string * * @throws \Exception + * @throws \Exception */ public function read(string $path, int $offset = 0, int $length = null): string { @@ -441,10 +441,13 @@ public function delete(string $path, bool $recursive = false): bool /** * Get list of objects in the given path. * - * @param string $path + * @param string $prefix + * @param int $maxKeys + * @param string $continuationToken * @return array * * @throws \Exception + * @throws \Exception */ private function listObjects($prefix = '', $maxKeys = 1000, $continuationToken = '') { @@ -642,7 +645,7 @@ private function getInfo(string $path): array * * @param string $method * @param string $uri - * @param array parameters + * @param array $parameters * @return string */ private function getSignatureV4(string $method, string $uri, array $parameters = []): string @@ -769,7 +772,7 @@ private function call(string $method, string $uri, string $data = '', array $par return \strlen($data); }); - curl_setopt($curl, CURLOPT_HEADERFUNCTION, function ($curl, string $header) use (&$response) { + \curl_setopt($curl, CURLOPT_HEADERFUNCTION, function ($curl, string $header) use (&$response) { $len = strlen($header); $header = explode(':', $header, 2); @@ -810,7 +813,9 @@ private function call(string $method, string $uri, string $data = '', array $par \curl_close($curl); // Parse body into XML - if ((isset($response->headers['content-type']) && $response->headers['content-type'] == 'application/xml') || (str_starts_with($response->body, 'headers['content-type'] ?? '') !== 'image/svg+xml')) { + if (array_key_exists('content-type', $response->headers) + && ($response->headers['content-type'] == 'application/xml' + || (str_starts_with($response->body, 'headers['content-type'] == 'image/svg+xml'))) { $response->body = \simplexml_load_string($response->body); $response->body = json_decode(json_encode($response->body), true); } diff --git a/tests/Storage/Compression/Algorithms/GZIPTest.php b/tests/Storage/Compression/Algorithms/GZIPTest.php index 1f5a8446..2c14e956 100644 --- a/tests/Storage/Compression/Algorithms/GZIPTest.php +++ b/tests/Storage/Compression/Algorithms/GZIPTest.php @@ -21,7 +21,7 @@ public function tearDown(): void { } - public function testName() + public function testName(): void { $this->assertEquals($this->object->getName(), 'gzip'); } diff --git a/tests/Storage/Compression/Algorithms/ZstdTest.php b/tests/Storage/Compression/Algorithms/ZstdTest.php index 488cd290..aab3025e 100644 --- a/tests/Storage/Compression/Algorithms/ZstdTest.php +++ b/tests/Storage/Compression/Algorithms/ZstdTest.php @@ -18,7 +18,7 @@ public function tearDown(): void { } - public function testName() + public function testName(): void { $this->assertEquals($this->object->getName(), 'zstd'); } diff --git a/tests/Storage/Device/LocalTest.php b/tests/Storage/Device/LocalTest.php index ebaed963..c4342c13 100644 --- a/tests/Storage/Device/LocalTest.php +++ b/tests/Storage/Device/LocalTest.php @@ -47,17 +47,17 @@ public function testDescription() $this->assertEquals($this->object->getDescription(), 'Adapter for Local storage that is in the physical or virtual machine or mounted to it.'); } - public function testRoot() + public function testRoot(): void { $this->assertEquals($this->object->getRoot(), $this->object->getAbsolutePath(__DIR__.'/../../resources/disk-a')); } - public function testPath() + public function testPath(): void { $this->assertEquals($this->object->getPath('image.png'), $this->object->getAbsolutePath(__DIR__.'/../../resources/disk-a').'/image.png'); } - public function testWrite() + public function testWrite(): void { $this->assertEquals($this->object->write($this->object->getPath('text.txt'), 'Hello World'), true); $this->assertEquals(file_exists($this->object->getPath('text.txt')), true); @@ -66,7 +66,7 @@ public function testWrite() $this->object->delete($this->object->getPath('text.txt')); } - public function testRead() + public function testRead(): void { $this->assertEquals($this->object->write($this->object->getPath('text-for-read.txt'), 'Hello World'), true); $this->assertEquals($this->object->read($this->object->getPath('text-for-read.txt')), 'Hello World'); @@ -74,7 +74,7 @@ public function testRead() $this->object->delete($this->object->getPath('text-for-read.txt')); } - public function testFileExists() + public function testFileExists(): void { $this->assertEquals($this->object->write($this->object->getPath('text-for-test-exists.txt'), 'Hello World'), true); $this->assertEquals($this->object->exists($this->object->getPath('text-for-test-exists.txt')), true); @@ -83,7 +83,7 @@ public function testFileExists() $this->object->delete($this->object->getPath('text-for-test-exists.txt')); } - public function testMove() + public function testMove(): void { $this->assertEquals($this->object->write($this->object->getPath('text-for-move.txt'), 'Hello World'), true); $this->assertEquals($this->object->read($this->object->getPath('text-for-move.txt')), 'Hello World'); @@ -97,7 +97,7 @@ public function testMove() $this->object->delete($this->object->getPath('text-for-move-new.txt')); } - public function testDelete() + public function testDelete(): void { $this->assertEquals($this->object->write($this->object->getPath('text-for-delete.txt'), 'Hello World'), true); $this->assertEquals($this->object->read($this->object->getPath('text-for-delete.txt')), 'Hello World'); @@ -148,7 +148,7 @@ public function testPartUpload() $totalSize = $this->object->getFileSize($source); $chunkSize = 2097152; - $chunks = ceil($totalSize / $chunkSize); + $chunks = intval(ceil($totalSize / $chunkSize)); $chunk = 1; $start = 0; @@ -178,7 +178,7 @@ public function testAbort() $dest = $this->object->getPath('abcduploaded.mp4'); $totalSize = $this->object->getFileSize($source); $chunkSize = 2097152; - $chunks = ceil($totalSize / $chunkSize); + $chunks = intval(ceil($totalSize / $chunkSize)); $chunk = 1; $start = 0; @@ -202,7 +202,7 @@ public function testAbort() $dest1 = $this->object->getPath('abcduploaded2.mp4'); $totalSize = $this->object->getFileSize($source); $chunkSize = 2097152; - $chunks = ceil($totalSize / $chunkSize); + $chunks = intval(ceil($totalSize / $chunkSize)); $chunk = 1; $start = 0; diff --git a/tests/Storage/S3Base.php b/tests/Storage/S3Base.php index dd82daea..416dd574 100644 --- a/tests/Storage/S3Base.php +++ b/tests/Storage/S3Base.php @@ -35,7 +35,7 @@ public function setUp(): void $this->uploadTestFiles(); } - private function uploadTestFiles() + private function uploadTestFiles(): void { $this->object->upload(__DIR__.'/../resources/disk-a/kitten-1.jpg', $this->object->getPath('testing/kitten-1.jpg')); $this->object->upload(__DIR__.'/../resources/disk-a/kitten-2.jpg', $this->object->getPath('testing/kitten-2.jpg')); @@ -43,7 +43,7 @@ private function uploadTestFiles() $this->object->upload(__DIR__.'/../resources/disk-b/kitten-2.png', $this->object->getPath('testing/kitten-2.png')); } - private function removeTestFiles() + private function removeTestFiles(): void { $this->object->delete($this->object->getPath('testing/kitten-1.jpg')); $this->object->delete($this->object->getPath('testing/kitten-2.jpg')); @@ -56,7 +56,7 @@ public function tearDown(): void $this->removeTestFiles(); } - public function testName() + public function testName(): void { $this->assertEquals($this->getAdapterName(), $this->object->getName()); } @@ -66,29 +66,29 @@ public function testType() $this->assertEquals($this->getAdapterType(), $this->object->getType()); } - public function testDescription() + public function testDescription(): void { $this->assertEquals($this->getAdapterDescription(), $this->object->getDescription()); } - public function testRoot() + public function testRoot(): void { $this->assertEquals($this->root, $this->object->getRoot()); } - public function testPath() + public function testPath(): void { $this->assertEquals($this->root.'/image.png', $this->object->getPath('image.png')); } - public function testWrite() + public function testWrite(): void { $this->assertEquals(true, $this->object->write($this->object->getPath('text.txt'), 'Hello World', 'text/plain')); $this->object->delete($this->object->getPath('text.txt')); } - public function testRead() + public function testRead(): void { $this->assertEquals(true, $this->object->write($this->object->getPath('text-for-read.txt'), 'Hello World', 'text/plain')); $this->assertEquals('Hello World', $this->object->read($this->object->getPath('text-for-read.txt'))); @@ -96,13 +96,13 @@ public function testRead() $this->object->delete($this->object->getPath('text-for-read.txt')); } - public function testFileExists() + public function testFileExists(): void { $this->assertEquals(true, $this->object->exists($this->object->getPath('testing/kitten-1.jpg'))); $this->assertEquals(false, $this->object->exists($this->object->getPath('testing/kitten-5.jpg'))); } - public function testMove() + public function testMove(): void { $this->assertEquals(true, $this->object->write($this->object->getPath('text-for-move.txt'), 'Hello World', 'text/plain')); $this->assertEquals(true, $this->object->exists($this->object->getPath('text-for-move.txt'))); @@ -113,7 +113,7 @@ public function testMove() $this->object->delete($this->object->getPath('text-for-move-new.txt')); } - public function testDelete() + public function testDelete(): void { $this->assertEquals(true, $this->object->write($this->object->getPath('text-for-delete.txt'), 'Hello World', 'text/plain')); $this->assertEquals(true, $this->object->exists($this->object->getPath('text-for-delete.txt'))); @@ -128,7 +128,7 @@ public function testSVGUpload() $this->assertEquals(true, $this->object->delete($this->object->getPath('testing/appwrite.svg'))); } - public function testDeletePath() + public function testDeletePath(): void { // Test Single Object $path = $this->object->getPath('text-for-delete-path.txt'); @@ -154,13 +154,13 @@ public function testDeletePath() $this->assertEquals(false, $this->object->exists($path2)); } - public function testFileSize() + public function testFileSize(): void { $this->assertEquals(599639, $this->object->getFileSize($this->object->getPath('testing/kitten-1.jpg'))); $this->assertEquals(131958, $this->object->getFileSize($this->object->getPath('testing/kitten-2.jpg'))); } - public function testFileMimeType() + public function testFileMimeType(): void { $this->assertEquals('image/jpeg', $this->object->getFileMimeType($this->object->getPath('testing/kitten-1.jpg'))); $this->assertEquals('image/jpeg', $this->object->getFileMimeType($this->object->getPath('testing/kitten-2.jpg'))); @@ -168,7 +168,7 @@ public function testFileMimeType() $this->assertEquals('image/png', $this->object->getFileMimeType($this->object->getPath('testing/kitten-2.png'))); } - public function testFileHash() + public function testFileHash(): void { $this->assertEquals('7551f343143d2e24ab4aaf4624996b6a', $this->object->getFileHash($this->object->getPath('testing/kitten-1.jpg'))); $this->assertEquals('81702fdeef2e55b1a22617bce4951cb5', $this->object->getFileHash($this->object->getPath('testing/kitten-2.jpg'))); @@ -186,12 +186,12 @@ public function testDirectorySize() $this->assertEquals(-1, $this->object->getDirectorySize('resources/disk-a/')); } - public function testPartitionFreeSpace() + public function testPartitionFreeSpace(): void { $this->assertEquals(-1, $this->object->getPartitionFreeSpace()); } - public function testPartitionTotalSpace() + public function testPartitionTotalSpace(): void { $this->assertEquals(-1, $this->object->getPartitionTotalSpace()); } @@ -204,7 +204,7 @@ public function testPartUpload() // AWS S3 requires each part to be at least 5MB except for last part $chunkSize = 5 * 1024 * 1024; - $chunks = ceil($totalSize / $chunkSize); + $chunks = intval(ceil($totalSize / $chunkSize)); $chunk = 1; $start = 0; diff --git a/tests/Storage/StorageTest.php b/tests/Storage/StorageTest.php index 3f04feb8..1fadd343 100644 --- a/tests/Storage/StorageTest.php +++ b/tests/Storage/StorageTest.php @@ -20,7 +20,7 @@ public function tearDown(): void { } - public function testGetters() + public function testGetters(): void { $this->assertEquals(get_class(Storage::getDevice('disk-a')), 'Utopia\Storage\Device\Local'); $this->assertEquals(get_class(Storage::getDevice('disk-b')), 'Utopia\Storage\Device\Local'); @@ -33,7 +33,7 @@ public function testGetters() } } - public function testExists() + public function testExists(): void { $this->assertEquals(Storage::exists('disk-a'), true); $this->assertEquals(Storage::exists('disk-b'), true); diff --git a/tests/Storage/Validator/FileExtTest.php b/tests/Storage/Validator/FileExtTest.php index b3b6a69a..90c0fe3c 100644 --- a/tests/Storage/Validator/FileExtTest.php +++ b/tests/Storage/Validator/FileExtTest.php @@ -21,7 +21,7 @@ public function tearDown(): void { } - public function testValues() + public function testValues(): void { $this->assertEquals($this->object->isValid(''), false); $this->assertEquals($this->object->isValid(null), false); diff --git a/tests/Storage/Validator/FileNameTest.php b/tests/Storage/Validator/FileNameTest.php index f3358bfe..f9776b1e 100644 --- a/tests/Storage/Validator/FileNameTest.php +++ b/tests/Storage/Validator/FileNameTest.php @@ -21,7 +21,7 @@ public function tearDown(): void { } - public function testValues() + public function testValues(): void { $this->assertEquals($this->object->isValid(''), false); $this->assertEquals($this->object->isValid(null), false); diff --git a/tests/Storage/Validator/FileSizeTest.php b/tests/Storage/Validator/FileSizeTest.php index 20deee4c..b254a571 100644 --- a/tests/Storage/Validator/FileSizeTest.php +++ b/tests/Storage/Validator/FileSizeTest.php @@ -21,7 +21,7 @@ public function tearDown(): void { } - public function testValues() + public function testValues(): void { $this->assertEquals($this->object->isValid(1001), false); $this->assertEquals($this->object->isValid(1000), true); diff --git a/tests/Storage/Validator/FileTypeTest.php b/tests/Storage/Validator/FileTypeTest.php index c246c06d..1aee5146 100644 --- a/tests/Storage/Validator/FileTypeTest.php +++ b/tests/Storage/Validator/FileTypeTest.php @@ -21,7 +21,7 @@ public function tearDown(): void { } - public function testValues() + public function testValues(): void { $this->assertEquals($this->object->isValid(__DIR__.'/../../resources/disk-a/kitten-1.jpg'), true); $this->assertEquals($this->object->isValid(__DIR__.'/../../resources/disk-a/kitten-2.jpg'), true); diff --git a/tests/Storage/Validator/UploadTest.php b/tests/Storage/Validator/UploadTest.php index 35de5cbb..139c334d 100644 --- a/tests/Storage/Validator/UploadTest.php +++ b/tests/Storage/Validator/UploadTest.php @@ -21,7 +21,7 @@ public function tearDown(): void { } - public function testValues() + public function testValues(): void { $this->assertEquals($this->object->isValid(__DIR__.'/../../resources/disk-a/kitten-1.jpg'), false); $this->assertEquals($this->object->isValid(__DIR__.'/../../resources/disk-a/kitten-2.jpg'), false);