1
0
Fork 0
mirror of synced 2024-06-02 19:04:49 +12:00

Merge branch 'feat-large-file' into feat-s3-integration

This commit is contained in:
Damodar Lohani 2021-12-10 16:22:35 +05:45
commit 037c0bfbd5
2 changed files with 177 additions and 85 deletions

View file

@ -493,7 +493,7 @@ App::delete('/v1/storage/buckets/:bucketId')
throw new Exception('Bucket not found', 404);
}
if(!$dbForInternal->deleteDocument('buckets', $bucketId)) {
if (!$dbForInternal->deleteDocument('buckets', $bucketId)) {
throw new Exception('Failed to remove project from DB', 500);
}
@ -557,7 +557,7 @@ App::post('/v1/storage/buckets/:bucketId/files')
$bucket = $dbForInternal->getDocument('buckets', $bucketId);
if($bucket->isEmpty()
if ($bucket->isEmpty()
|| (!$bucket->getAttribute('enabled') && $mode !== APP_MODE_ADMIN )) {
throw new Exception('Bucket not found', 404);
}
@ -597,7 +597,7 @@ App::post('/v1/storage/buckets/:bucketId/files')
$fileSize = (\is_array($file['size']) && isset($file['size'][0])) ? $file['size'][0] : $file['size'];
$contentRange = $request->getHeader('content-range');
$fileId = $fileId === 'unique()' ? $dbForInternal->getId() : $fileId;
$fileId = $fileId === 'unique()' ? $dbForExternal->getId() : $fileId;
$chunk = 1;
$chunks = 1;
@ -606,7 +606,7 @@ App::post('/v1/storage/buckets/:bucketId/files')
$end = $request->getContentRangeEnd();
$fileSize = $request->getContentRangeSize();
$fileId = $request->getHeader('x-appwrite-id', $fileId);
if(is_null($start) || is_null($end) || is_null($fileSize)) {
if (is_null($start) || is_null($end) || is_null($fileSize)) {
throw new Exception('Invalid content-range header', 400);
}
@ -694,7 +694,7 @@ App::post('/v1/storage/buckets/:bucketId/files')
$data = OpenSSL::encrypt($data, OpenSSL::CIPHER_AES_128_GCM, $key, 0, $iv, $tag);
}
if(!empty($data)) {
if (!empty($data)) {
if (!$device->write($path, $data, $mimeType)) {
throw new Exception('Failed to save file', 500);
}
@ -737,7 +737,7 @@ App::post('/v1/storage/buckets/:bucketId/files')
'search' => implode(' ', [$fileId, $fileName,]),
'metadata' => $metadata,
]);
if($permissionBucket) {
if ($permissionBucket) {
$file = Authorization::skip(function() use ($dbForExternal, $bucketId, $doc) {
return $dbForExternal->createDocument('bucket_' . $bucketId, $doc);
});
@ -756,9 +756,10 @@ App::post('/v1/storage/buckets/:bucketId/files')
->setAttribute('openSSLCipher', $openSSLCipher)
->setAttribute('openSSLTag', $openSSLTag)
->setAttribute('openSSLIV', $openSSLIV)
->setAttribute('metadata', $metadata);
->setAttribute('metadata', $metadata)
->setAttribute('chunksUploaded', $chunksUploaded);
if($permissionBucket) {
if ($permissionBucket) {
$file = Authorization::skip(function() use ($dbForExternal, $bucketId, $fileId, $file) {
return $dbForExternal->updateDocument('bucket_' . $bucketId, $fileId, $file);
});
@ -796,7 +797,7 @@ App::post('/v1/storage/buckets/:bucketId/files')
'search' => implode(' ', [$fileId, $fileName,]),
'metadata' => $metadata,
]);
if($permissionBucket) {
if ($permissionBucket) {
$file = Authorization::skip(function() use ($dbForExternal, $bucketId, $doc) {
return $dbForExternal->createDocument('bucket_' . $bucketId, $doc);
});
@ -808,7 +809,7 @@ App::post('/v1/storage/buckets/:bucketId/files')
->setAttribute('chunksUploaded', $chunksUploaded)
->setAttribute('metadata', $metadata);
if($permissionBucket) {
if ($permissionBucket) {
$file = Authorization::skip(function() use ($dbForExternal, $bucketId, $fileId, $file) {
return $dbForExternal->updateDocument('bucket_' . $bucketId, $fileId, $file);
});
@ -876,7 +877,7 @@ App::get('/v1/storage/buckets/:bucketId/files')
$bucket = $dbForInternal->getDocument('buckets', $bucketId);
if($bucket->isEmpty()
if ($bucket->isEmpty()
|| (!$bucket->getAttribute('enabled') && $mode !== APP_MODE_ADMIN )) {
throw new Exception('Bucket not found', 404);
}
@ -896,7 +897,7 @@ App::get('/v1/storage/buckets/:bucketId/files')
}
if (!empty($cursor)) {
if($bucket->getAttribute('permission') ==='bucket') {
if ($bucket->getAttribute('permission') ==='bucket') {
$cursorFile = Authorization::skip(function() use ($dbForExternal, $bucket, $cursor) {
return $dbForExternal->getDocument('bucket_' . $bucket->getId(), $cursor);
});
@ -915,7 +916,7 @@ App::get('/v1/storage/buckets/:bucketId/files')
$queries[] = new Query('search', Query::TYPE_SEARCH, [$search]);
}
if($bucket->getAttribute('permission') === 'bucket') {
if ($bucket->getAttribute('permission') === 'bucket') {
$files = Authorization::skip(function() use ($dbForExternal, $bucketId, $queries, $limit, $offset, $cursor, $cursorDirection, $orderType) {
return $dbForExternal->find('bucket_' . $bucketId, $queries, $limit, $offset, [], [$orderType], $cursorFile ?? null, $cursorDirection);
});
@ -962,7 +963,7 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId')
$bucket = $dbForInternal->getDocument('buckets', $bucketId);
if($bucket->isEmpty()
if ($bucket->isEmpty()
|| (!$bucket->getAttribute('enabled') && $mode !== APP_MODE_ADMIN )) {
throw new Exception('Bucket not found', 404);
}
@ -975,7 +976,7 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId')
}
}
if($bucket->getAttribute('permission') === 'bucket') {
if ($bucket->getAttribute('permission') === 'bucket') {
$file = Authorization::skip(function() use ($dbForExternal, $bucketId, $fileId) {
return $dbForExternal->getDocument('bucket_' . $bucketId, $fileId);
});
@ -1044,7 +1045,7 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview')
}
$bucket = $dbForInternal->getDocument('buckets', $bucketId);
if($bucket->isEmpty()
if ($bucket->isEmpty()
|| (!$bucket->getAttribute('enabled') && $mode !== APP_MODE_ADMIN )) {
throw new Exception('Bucket not found', 404);
}
@ -1068,7 +1069,7 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview')
$date = \date('D, d M Y H:i:s', \time() + (60 * 60 * 24 * 45)).' GMT'; // 45 days cache
$key = \md5($fileId.$width.$height.$gravity.$quality.$borderWidth.$borderColor.$borderRadius.$opacity.$rotation.$background.$storage.$output);
if($bucket->getAttribute('permission')==='bucket') {
if ($bucket->getAttribute('permission')==='bucket') {
// skip authorization
$file = Authorization::skip(function () use ($dbForExternal, $bucketId, $fileId) {
return $dbForExternal->getDocument('bucket_' . $bucketId, $fileId);
@ -1209,7 +1210,7 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/download')
$bucket = $dbForInternal->getDocument('buckets', $bucketId);
if($bucket->isEmpty()
if ($bucket->isEmpty()
|| (!$bucket->getAttribute('enabled') && $mode !== APP_MODE_ADMIN )) {
throw new Exception('Bucket not found', 404);
}
@ -1222,7 +1223,7 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/download')
}
}
if($bucket->getAttribute('permission') === 'bucket') {
if ($bucket->getAttribute('permission') === 'bucket') {
$file = Authorization::skip(function() use ($dbForExternal, $fileId, $bucketId) {
return $dbForExternal->getDocument('bucket_' . $bucketId, $fileId);
});
@ -1257,16 +1258,16 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/download')
$size = $file->getAttribute('sizeOriginal', 0);
$rangeHeader = $request->getHeader('range');
if(!empty($rangeHeader)) {
if (!empty($rangeHeader)) {
$start = $request->getRangeStart();
$end = $request->getRangeEnd();
$unit = $request->getRangeUnit();
if($end == null) {
$end = min(($start + 2000000-1), ($size - 1));
if ($end === null) {
$end = min(($start + MAX_OUTPUT_CHUNK_SIZE-1), ($size - 1));
}
if($unit != 'bytes' || $start >= $end || $end >= $size) {
if ($unit !== 'bytes' || $start >= $end || $end >= $size) {
throw new Exception('Invalid range', 416);
}
@ -1291,28 +1292,35 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/download')
}
if (!empty($file->getAttribute('algorithm', ''))) {
if(empty($source)) {
if (empty($source)) {
$source = $device->read($path);
}
$compressor = new GZIP();
$source = $compressor->decompress($source);
}
if(!empty($source)) {
if(!empty($rangeHeader)) {
if (!empty($source)) {
if (!empty($rangeHeader)) {
$response->send(substr($source, $start, ($end - $start + 1)));
}
$response->send($source);
}
if(!empty($rangeHeader)) {
if (!empty($rangeHeader)) {
$response->send($device->read($path, $start, ($end - $start + 1)));
}
if ($size > APP_STORAGE_READ_BUFFER) {
$response->addHeader('Content-Length', $device->getFileSize($path));
for ($i=0; $i < ceil($size / MAX_OUTPUT_CHUNK_SIZE); $i++) {
$response->chunk($device->read($path, ($i * MAX_OUTPUT_CHUNK_SIZE), min(MAX_OUTPUT_CHUNK_SIZE, $size - ($i * MAX_OUTPUT_CHUNK_SIZE))), (($i + 1) * MAX_OUTPUT_CHUNK_SIZE) >= $size);
$response->chunk(
$device->read(
$path,
($i * MAX_OUTPUT_CHUNK_SIZE),
min(MAX_OUTPUT_CHUNK_SIZE, $size - ($i * MAX_OUTPUT_CHUNK_SIZE))
),
(($i + 1) * MAX_OUTPUT_CHUNK_SIZE) >= $size
);
}
} else {
$response->send($device->read($path));
@ -1348,7 +1356,7 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/view')
$bucket = $dbForInternal->getDocument('buckets', $bucketId);
if($bucket->isEmpty()
if ($bucket->isEmpty()
|| (!$bucket->getAttribute('enabled') && $mode !== APP_MODE_ADMIN )) {
throw new Exception('Bucket not found', 404);
}
@ -1361,7 +1369,7 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/view')
}
}
if($bucket->getAttribute('permission') === 'bucket') {
if ($bucket->getAttribute('permission') === 'bucket') {
$file = Authorization::skip(function() use ($dbForExternal, $fileId, $bucketId) {
return $dbForExternal->getDocument('bucket_' . $bucketId, $fileId);
});
@ -1402,22 +1410,22 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/view')
$size = $file->getAttribute('sizeOriginal', 0);
$rangeHeader = $request->getHeader('range');
if(!empty($rangeHeader)) {
if (!empty($rangeHeader)) {
$start = $request->getRangeStart();
$end = $request->getRangeEnd();
$unit = $request->getRangeUnit();
if($end == null) {
if ($end === null) {
$end = min(($start + 2000000-1), ($size - 1));
}
if($unit != 'bytes' || $start >= $end || $end >= $size) {
if ($unit != 'bytes' || $start >= $end || $end >= $size) {
throw new Exception('Invalid range', 416);
}
$response
->addHeader('Accept-Ranges', 'bytes')
->addHeader('Content-Range', 'bytes ' . $start . '-' . $end . '/' . $size)
->addHeader('Content-Range', "bytes $start-$end/$size")
->addHeader('Content-Length', $end - $start + 1)
->setStatusCode(Response::STATUS_CODE_PARTIALCONTENT);
}
@ -1436,7 +1444,7 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/view')
}
if (!empty($file->getAttribute('algorithm', ''))) {
if(empty($source)) {
if (empty($source)) {
$source = $device->read($path);
}
$compressor = new GZIP();
@ -1448,23 +1456,29 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/view')
->setParam('bucketId', $bucketId)
;
if(!empty($source)) {
if(!empty($rangeHeader)) {
if (!empty($source)) {
if (!empty($rangeHeader)) {
$response->send(substr($source, $start, ($end - $start + 1)));
}
$response->send($source);
}
if(!empty($rangeHeader)) {
if (!empty($rangeHeader)) {
$response->send($device->read($path, $start, ($end - $start + 1)));
}
$size = $device->getFileSize($path);
if ($size > APP_STORAGE_READ_BUFFER) {
$response->addHeader('Content-Length', $device->getFileSize($path));
$chunk = 2000000; // Max chunk of 2 mb
for ($i=0; $i < ceil($size / $chunk); $i++) {
$response->chunk($device->read($path, ($i * $chunk), min($chunk, $size - ($i * $chunk))), (($i + 1) * $chunk) >= $size);
for ($i=0; $i < ceil($size / MAX_OUTPUT_CHUNK_SIZE); $i++) {
$response->chunk(
$device->read(
$path,
($i * MAX_OUTPUT_CHUNK_SIZE),
min(MAX_OUTPUT_CHUNK_SIZE, $size - ($i * MAX_OUTPUT_CHUNK_SIZE))
),
(($i + 1) * MAX_OUTPUT_CHUNK_SIZE) >= $size
);
}
} else {
$response->send($device->read($path));
@ -1503,7 +1517,7 @@ App::put('/v1/storage/buckets/:bucketId/files/:fileId')
$bucket = $dbForInternal->getDocument('buckets', $bucketId);
if($bucket->isEmpty()
if ($bucket->isEmpty()
|| (!$bucket->getAttribute('enabled') && $mode !== APP_MODE_ADMIN )) {
throw new Exception('Bucket not found', 404);
}
@ -1516,7 +1530,7 @@ App::put('/v1/storage/buckets/:bucketId/files/:fileId')
}
}
if($bucket->getAttribute('permission') === 'bucket') {
if ($bucket->getAttribute('permission') === 'bucket') {
$file = Authorization::skip(function() use ($dbForExternal, $fileId, $bucketId) {
return $dbForExternal->getDocument('bucket_' . $bucketId, $fileId);
});
@ -1528,7 +1542,7 @@ App::put('/v1/storage/buckets/:bucketId/files/:fileId')
throw new Exception('File not found', 404);
}
if($bucket->getAttribute('permission') === 'bucket') {
if ($bucket->getAttribute('permission') === 'bucket') {
$file = Authorization::skip(function() use ($dbForExternal, $fileId, $bucketId, $file, $read, $write) {
return $dbForExternal->updateDocument('bucket_' . $bucketId, $fileId, $file
->setAttribute('$read', $read)
@ -1587,7 +1601,7 @@ App::delete('/v1/storage/buckets/:bucketId/files/:fileId')
$bucket = $dbForInternal->getDocument('buckets', $bucketId);
if($bucket->isEmpty()
if ($bucket->isEmpty()
|| (!$bucket->getAttribute('enabled') && $mode !== APP_MODE_ADMIN )) {
throw new Exception('Bucket not found', 404);
}
@ -1600,7 +1614,7 @@ App::delete('/v1/storage/buckets/:bucketId/files/:fileId')
}
}
if($bucket->getAttribute('permission') === 'bucket') {
if ($bucket->getAttribute('permission') === 'bucket') {
$file = Authorization::skip(function() use ($dbForExternal, $fileId, $bucketId) {
return $dbForExternal->getDocument('bucket_' . $bucketId, $fileId);
});
@ -1615,7 +1629,7 @@ App::delete('/v1/storage/buckets/:bucketId/files/:fileId')
$device = Storage::getDevice('files');
if ($device->delete($file->getAttribute('path', ''))) {
if($bucket->getAttribute('permission') === 'bucket') {
if ($bucket->getAttribute('permission') === 'bucket') {
$deleted = Authorization::skip(function() use ($dbForExternal, $fileId, $bucketId) {
return $dbForExternal->deleteDocument('bucket_' . $bucketId, $fileId);
});
@ -1778,7 +1792,7 @@ App::get('/v1/storage/:bucketId/usage')
$bucket = $dbForInternal->getDocument('buckets', $bucketId);
if($bucket->isEmpty()) {
if ($bucket->isEmpty()) {
throw new Exception('Bucket not found', 404);
}

152
composer.lock generated
View file

@ -489,16 +489,16 @@
},
{
"name": "guzzlehttp/guzzle",
"version": "7.4.0",
"version": "7.4.1",
"source": {
"type": "git",
"url": "https://github.com/guzzle/guzzle.git",
"reference": "868b3571a039f0ebc11ac8f344f4080babe2cb94"
"reference": "ee0a041b1760e6a53d2a39c8c34115adc2af2c79"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/guzzle/guzzle/zipball/868b3571a039f0ebc11ac8f344f4080babe2cb94",
"reference": "868b3571a039f0ebc11ac8f344f4080babe2cb94",
"url": "https://api.github.com/repos/guzzle/guzzle/zipball/ee0a041b1760e6a53d2a39c8c34115adc2af2c79",
"reference": "ee0a041b1760e6a53d2a39c8c34115adc2af2c79",
"shasum": ""
},
"require": {
@ -507,7 +507,7 @@
"guzzlehttp/psr7": "^1.8.3 || ^2.1",
"php": "^7.2.5 || ^8.0",
"psr/http-client": "^1.0",
"symfony/deprecation-contracts": "^2.2"
"symfony/deprecation-contracts": "^2.2 || ^3.0"
},
"provide": {
"psr/http-client-implementation": "1.0"
@ -593,7 +593,7 @@
],
"support": {
"issues": "https://github.com/guzzle/guzzle/issues",
"source": "https://github.com/guzzle/guzzle/tree/7.4.0"
"source": "https://github.com/guzzle/guzzle/tree/7.4.1"
},
"funding": [
{
@ -609,7 +609,7 @@
"type": "tidelift"
}
],
"time": "2021-10-18T09:52:00+00:00"
"time": "2021-12-06T18:43:05+00:00"
},
{
"name": "guzzlehttp/promises",
@ -1591,25 +1591,25 @@
},
{
"name": "symfony/deprecation-contracts",
"version": "v2.5.0",
"version": "v3.0.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/deprecation-contracts.git",
"reference": "6f981ee24cf69ee7ce9736146d1c57c2780598a8"
"reference": "c726b64c1ccfe2896cb7df2e1331c357ad1c8ced"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/6f981ee24cf69ee7ce9736146d1c57c2780598a8",
"reference": "6f981ee24cf69ee7ce9736146d1c57c2780598a8",
"url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/c726b64c1ccfe2896cb7df2e1331c357ad1c8ced",
"reference": "c726b64c1ccfe2896cb7df2e1331c357ad1c8ced",
"shasum": ""
},
"require": {
"php": ">=7.1"
"php": ">=8.0.2"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "2.5-dev"
"dev-main": "3.0-dev"
},
"thanks": {
"name": "symfony/contracts",
@ -1638,7 +1638,7 @@
"description": "A generic function and convention to trigger deprecation notices",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/deprecation-contracts/tree/v2.5.0"
"source": "https://github.com/symfony/deprecation-contracts/tree/v3.0.0"
},
"funding": [
{
@ -1654,7 +1654,7 @@
"type": "tidelift"
}
],
"time": "2021-07-12T14:48:14+00:00"
"time": "2021-11-01T23:48:49+00:00"
},
{
"name": "symfony/polyfill-ctype",
@ -2554,7 +2554,7 @@
"source": {
"type": "git",
"url": "https://github.com/utopia-php/storage",
"reference": "88ed83274542ba3c9d34c5dabd17e0cfb480519d"
"reference": "c47611b3a4a36c674c16e9720e86187452eb1cc2"
},
"require": {
"php": ">=8.0",
@ -2570,6 +2570,11 @@
"Utopia\\Storage\\": "src/Storage"
}
},
"autoload-dev": {
"psr-4": {
"Utopia\\Tests\\": "tests/Storage"
}
},
"license": [
"MIT"
],
@ -2587,7 +2592,7 @@
"upf",
"utopia"
],
"time": "2021-12-03T04:31:08+00:00"
"time": "2021-12-09T07:34:55+00:00"
},
{
"name": "utopia-php/swoole",
@ -3033,6 +3038,77 @@
},
"time": "2021-11-12T11:09:38+00:00"
},
{
"name": "composer/pcre",
"version": "1.0.0",
"source": {
"type": "git",
"url": "https://github.com/composer/pcre.git",
"reference": "3d322d715c43a1ac36c7fe215fa59336265500f2"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/composer/pcre/zipball/3d322d715c43a1ac36c7fe215fa59336265500f2",
"reference": "3d322d715c43a1ac36c7fe215fa59336265500f2",
"shasum": ""
},
"require": {
"php": "^5.3.2 || ^7.0 || ^8.0"
},
"require-dev": {
"phpstan/phpstan": "^1",
"phpstan/phpstan-strict-rules": "^1.1",
"symfony/phpunit-bridge": "^4.2 || ^5"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "1.x-dev"
}
},
"autoload": {
"psr-4": {
"Composer\\Pcre\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Jordi Boggiano",
"email": "j.boggiano@seld.be",
"homepage": "http://seld.be"
}
],
"description": "PCRE wrapping library that offers type-safe preg_* replacements.",
"keywords": [
"PCRE",
"preg",
"regex",
"regular expression"
],
"support": {
"issues": "https://github.com/composer/pcre/issues",
"source": "https://github.com/composer/pcre/tree/1.0.0"
},
"funding": [
{
"url": "https://packagist.com",
"type": "custom"
},
{
"url": "https://github.com/composer",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/composer/composer",
"type": "tidelift"
}
],
"time": "2021-12-06T15:17:27+00:00"
},
{
"name": "composer/semver",
"version": "3.2.6",
@ -3116,25 +3192,27 @@
},
{
"name": "composer/xdebug-handler",
"version": "2.0.2",
"version": "2.0.3",
"source": {
"type": "git",
"url": "https://github.com/composer/xdebug-handler.git",
"reference": "84674dd3a7575ba617f5a76d7e9e29a7d3891339"
"reference": "6555461e76962fd0379c444c46fd558a0fcfb65e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/composer/xdebug-handler/zipball/84674dd3a7575ba617f5a76d7e9e29a7d3891339",
"reference": "84674dd3a7575ba617f5a76d7e9e29a7d3891339",
"url": "https://api.github.com/repos/composer/xdebug-handler/zipball/6555461e76962fd0379c444c46fd558a0fcfb65e",
"reference": "6555461e76962fd0379c444c46fd558a0fcfb65e",
"shasum": ""
},
"require": {
"composer/pcre": "^1",
"php": "^5.3.2 || ^7.0 || ^8.0",
"psr/log": "^1 || ^2 || ^3"
},
"require-dev": {
"phpstan/phpstan": "^0.12.55",
"symfony/phpunit-bridge": "^4.2 || ^5"
"phpstan/phpstan": "^1.0",
"phpstan/phpstan-strict-rules": "^1.1",
"symfony/phpunit-bridge": "^4.2 || ^5.0 || ^6.0"
},
"type": "library",
"autoload": {
@ -3160,7 +3238,7 @@
"support": {
"irc": "irc://irc.freenode.org/composer",
"issues": "https://github.com/composer/xdebug-handler/issues",
"source": "https://github.com/composer/xdebug-handler/tree/2.0.2"
"source": "https://github.com/composer/xdebug-handler/tree/2.0.3"
},
"funding": [
{
@ -3176,7 +3254,7 @@
"type": "tidelift"
}
],
"time": "2021-07-31T17:03:58+00:00"
"time": "2021-12-08T13:07:32+00:00"
},
{
"name": "dnoegel/php-xdg-base-dir",
@ -4007,16 +4085,16 @@
},
{
"name": "phpspec/prophecy",
"version": "1.14.0",
"version": "v1.15.0",
"source": {
"type": "git",
"url": "https://github.com/phpspec/prophecy.git",
"reference": "d86dfc2e2a3cd366cee475e52c6bb3bbc371aa0e"
"reference": "bbcd7380b0ebf3961ee21409db7b38bc31d69a13"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpspec/prophecy/zipball/d86dfc2e2a3cd366cee475e52c6bb3bbc371aa0e",
"reference": "d86dfc2e2a3cd366cee475e52c6bb3bbc371aa0e",
"url": "https://api.github.com/repos/phpspec/prophecy/zipball/bbcd7380b0ebf3961ee21409db7b38bc31d69a13",
"reference": "bbcd7380b0ebf3961ee21409db7b38bc31d69a13",
"shasum": ""
},
"require": {
@ -4068,22 +4146,22 @@
],
"support": {
"issues": "https://github.com/phpspec/prophecy/issues",
"source": "https://github.com/phpspec/prophecy/tree/1.14.0"
"source": "https://github.com/phpspec/prophecy/tree/v1.15.0"
},
"time": "2021-09-10T09:02:12+00:00"
"time": "2021-12-08T12:19:24+00:00"
},
{
"name": "phpunit/php-code-coverage",
"version": "9.2.9",
"version": "9.2.10",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
"reference": "f301eb1453c9e7a1bc912ee8b0ea9db22c60223b"
"reference": "d5850aaf931743067f4bfc1ae4cbd06468400687"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/f301eb1453c9e7a1bc912ee8b0ea9db22c60223b",
"reference": "f301eb1453c9e7a1bc912ee8b0ea9db22c60223b",
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/d5850aaf931743067f4bfc1ae4cbd06468400687",
"reference": "d5850aaf931743067f4bfc1ae4cbd06468400687",
"shasum": ""
},
"require": {
@ -4139,7 +4217,7 @@
],
"support": {
"issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
"source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.9"
"source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.10"
},
"funding": [
{
@ -4147,7 +4225,7 @@
"type": "github"
}
],
"time": "2021-11-19T15:21:02+00:00"
"time": "2021-12-05T09:12:13+00:00"
},
{
"name": "phpunit/php-file-iterator",