diff --git a/CHANGELOG.md b/CHANGELOG.md index 66fe0b0..5a6091c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,83 @@ +# v1.7.21 +## 09/14/2021 + +1. [](#new) + * Added `|yaml` filter to convert input to YAML + * Added `route` and `request` to `onPageNotFound` event + * Added file upload/remove support for `Flex Forms` + * Added support for `flex-required@: not exists` and `flex-required@: '!exists'` in blueprints + * Added `$object->getOriginalData()` to get flex objects data before it was modified with `update()` + * Throwing exceptions from Twig templates fires `onDisplayErrorPage.[code]` event allowing better error pages +2. [](#improved) + * Use a simplified text-based `cron` field for scheduler + * Add timestamp to logging output of scheduler jobs to see when they ran +3. [](#bugfix) + * Fixed escaping in PageIndex::getLevelListing() + * Fixed validation of `number` type [#3433](https://github.com/getgrav/grav/issues/3433) + * Fixed excessive `security.yaml` file creation [#3432](https://github.com/getgrav/grav/issues/3432) + * Fixed incorrect port :0 with nginx unix socket setup [#3439](https://github.com/getgrav/grav/issues/3439) + * Fixed `Session::setFlashCookieObject()` to use the same options as the main session cookie + +# v1.7.20 +## 09/01/2021 + +2. [](#improved) + * Added support for `task` and `action` inside JSON request body + +# v1.7.19 +## 08/31/2021 + +1. [](#new) + * Include active form and request in `onPageTask` and `onPageAction` events (defaults to `null`) + * Added `UserObject::$authorizeCallable` to allow `$user->authorize()` customization +2. [](#improved) + * Added meta support for `UploadedFile` class + * Added support for multiple mime-types per file extension [#3422](https://github.com/getgrav/grav/issues/3422) + * Added `setCurrent()` method to Page Collection [#3398](https://github.com/getgrav/grav/pull/3398) + * Initialize `$grav['uri']` before session +3. [](#bugfix) + * Fixed `Warning: Undefined array key "SERVER_SOFTWARE" in index.php` [#3408](https://github.com/getgrav/grav/issues/3408) + * Fixed error in `loadDirectoryConfig()` if configuration hasn't been saved [#3409](https://github.com/getgrav/grav/issues/3409) + * Fixed GPM not using non-standard cache path [#3410](https://github.com/getgrav/grav/issues/3410) + * Fixed broken `environment://` stream when it doesn't have configuration + * Fixed `Flex Object` missing key field value when using `FolderStorage` + * Fixed broken Twig try tag when catch has not been defined or is empty + * Fixed `FlexForm` serialization + * Fixed form validation for numeric values in PHP 8 + * Fixed `flex-options@` in blueprints duplicating items in array + * Fixed wrong form issue with flex objects after cache clear + * Fixed Flex object types not implementing `MediaInterface` + * Fixed issue with `svgImageFunction()` that was causing broken output + +# v1.7.18 +## 07/19/2021 + +1. [](#improved) + * Added support for loading Flex Directory configuration from main configuration + * Move SVGs that cannot be sanitized to quarantine folder under `log://quarantine` + * Added support for CloudFlare-forwarded client IP in the `URI::ip()` method +1. [](#bugfix) + * Fixed error when using Flex `SimpleStorage` with no entries + * Fixed page search to include slug field [#3316](https://github.com/getgrav/grav/issues/3316) + * Fixed Admin becoming unusable when GPM cannot be reached [#3383](https://github.com/getgrav/grav/issues/3383) + * Fixed `Failed to save entry: Forbidden` when moving a page to a visible page [#3389](https://github.com/getgrav/grav/issues/3389) + * Better support for Symfony local server on linux [#3400](https://github.com/getgrav/grav/pull/3400) + * Fixed `open_basedir()` error with some forms + +# v1.7.17 +## 06/15/2021 + +1. [](#new) + * Interface `FlexDirectoryInterface` now extends `FlexAuthorizeInterface` +1. [](#improved) + * Allow to unset an asset attribute by specifying null (ie, `'defer': null`) + * Support specifying custom attributes to assets in a collection [Read more](https://learn.getgrav.org/17/themes/asset-manager#collections-with-attributes?target=_blank) [#3358](https://github.com/getgrav/grav/issues/3358) + * File `frontmatter.yaml` isn't part of media, ignore it + * Switched default `JQuery` collection to use 3.x rather than 2.x +1. [](#bugfix) + * Fixed missing styles when CSS/JS Pipeline is used and `asset://` folder is missing + * Fixed permission check when moving a page [#3382](https://github.com/getgrav/grav/issues/3382) + # v1.7.16 ## 06/02/2021 diff --git a/README.md b/README.md index 562349f..31a4a7e 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,6 @@ # ![](https://avatars1.githubusercontent.com/u/8237355?v=2&s=50) Grav [![PHPStan](https://img.shields.io/badge/PHPStan-enabled-brightgreen.svg?style=flat)](https://github.com/phpstan/phpstan) -[![SensioLabsInsight](https://insight.sensiolabs.com/projects/cfd20465-d0f8-4a0a-8444-467f5b5f16ad/mini.png)](https://insight.sensiolabs.com/projects/cfd20465-d0f8-4a0a-8444-467f5b5f16ad) [![Discord](https://img.shields.io/discord/501836936584101899.svg?logo=discord&colorB=728ADA&label=Discord%20Chat)](https://chat.getgrav.org) [![PHP Tests](https://github.com/getgrav/grav/workflows/PHP%20Tests/badge.svg?branch=develop)](https://github.com/getgrav/grav/actions?query=workflow%3A%22PHP+Tests%22) [![OpenCollective](https://opencollective.com/grav/backers/badge.svg)](#backers) [![OpenCollective](https://opencollective.com/grav/sponsors/badge.svg)](#sponsors) diff --git a/composer.lock b/composer.lock index 1d51262..8d2907f 100644 --- a/composer.lock +++ b/composer.lock @@ -56,16 +56,16 @@ }, { "name": "composer/ca-bundle", - "version": "1.2.9", + "version": "1.2.10", "source": { "type": "git", "url": "https://github.com/composer/ca-bundle.git", - "reference": "78a0e288fdcebf92aa2318a8d3656168da6ac1a5" + "reference": "9fdb22c2e97a614657716178093cd1da90a64aa8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/ca-bundle/zipball/78a0e288fdcebf92aa2318a8d3656168da6ac1a5", - "reference": "78a0e288fdcebf92aa2318a8d3656168da6ac1a5", + "url": "https://api.github.com/repos/composer/ca-bundle/zipball/9fdb22c2e97a614657716178093cd1da90a64aa8", + "reference": "9fdb22c2e97a614657716178093cd1da90a64aa8", "shasum": "" }, "require": { @@ -112,7 +112,7 @@ "support": { "irc": "irc://irc.freenode.org/composer", "issues": "https://github.com/composer/ca-bundle/issues", - "source": "https://github.com/composer/ca-bundle/tree/1.2.9" + "source": "https://github.com/composer/ca-bundle/tree/1.2.10" }, "funding": [ { @@ -128,7 +128,7 @@ "type": "tidelift" } ], - "time": "2021-01-12T12:10:35+00:00" + "time": "2021-06-07T13:58:28+00:00" }, { "name": "composer/semver", @@ -212,24 +212,23 @@ }, { "name": "doctrine/cache", - "version": "1.11.0", + "version": "1.12.1", "source": { "type": "git", "url": "https://github.com/doctrine/cache.git", - "reference": "a9c1b59eba5a08ca2770a76eddb88922f504e8e0" + "reference": "4cf401d14df219fa6f38b671f5493449151c9ad8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/cache/zipball/a9c1b59eba5a08ca2770a76eddb88922f504e8e0", - "reference": "a9c1b59eba5a08ca2770a76eddb88922f504e8e0", + "url": "https://api.github.com/repos/doctrine/cache/zipball/4cf401d14df219fa6f38b671f5493449151c9ad8", + "reference": "4cf401d14df219fa6f38b671f5493449151c9ad8", "shasum": "" }, "require": { "php": "~7.1 || ^8.0" }, "conflict": { - "doctrine/common": ">2.2,<2.4", - "psr/cache": ">=3" + "doctrine/common": ">2.2,<2.4" }, "require-dev": { "alcaeus/mongo-php-adapter": "^1.1", @@ -238,8 +237,9 @@ "mongodb/mongodb": "^1.1", "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0", "predis/predis": "~1.0", - "psr/cache": "^1.0 || ^2.0", - "symfony/cache": "^4.4 || ^5.2" + "psr/cache": "^1.0 || ^2.0 || ^3.0", + "symfony/cache": "^4.4 || ^5.2 || ^6.0@dev", + "symfony/var-exporter": "^4.4 || ^5.2 || ^6.0@dev" }, "suggest": { "alcaeus/mongo-php-adapter": "Required to use legacy MongoDB driver" @@ -291,7 +291,7 @@ ], "support": { "issues": "https://github.com/doctrine/cache/issues", - "source": "https://github.com/doctrine/cache/tree/1.11.0" + "source": "https://github.com/doctrine/cache/tree/1.12.1" }, "funding": [ { @@ -307,30 +307,30 @@ "type": "tidelift" } ], - "time": "2021-04-13T14:46:17+00:00" + "time": "2021-07-17T14:39:21+00:00" }, { "name": "doctrine/collections", - "version": "1.6.7", + "version": "1.6.8", "source": { "type": "git", "url": "https://github.com/doctrine/collections.git", - "reference": "55f8b799269a1a472457bd1a41b4f379d4cfba4a" + "reference": "1958a744696c6bb3bb0d28db2611dc11610e78af" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/collections/zipball/55f8b799269a1a472457bd1a41b4f379d4cfba4a", - "reference": "55f8b799269a1a472457bd1a41b4f379d4cfba4a", + "url": "https://api.github.com/repos/doctrine/collections/zipball/1958a744696c6bb3bb0d28db2611dc11610e78af", + "reference": "1958a744696c6bb3bb0d28db2611dc11610e78af", "shasum": "" }, "require": { "php": "^7.1.3 || ^8.0" }, "require-dev": { - "doctrine/coding-standard": "^6.0", - "phpstan/phpstan-shim": "^0.9.2", - "phpunit/phpunit": "^7.0", - "vimeo/psalm": "^3.8.1" + "doctrine/coding-standard": "^9.0", + "phpstan/phpstan": "^0.12", + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.1.5", + "vimeo/psalm": "^4.2.1" }, "type": "library", "autoload": { @@ -374,9 +374,9 @@ ], "support": { "issues": "https://github.com/doctrine/collections/issues", - "source": "https://github.com/doctrine/collections/tree/1.6.7" + "source": "https://github.com/doctrine/collections/tree/1.6.8" }, - "time": "2020-07-27T17:53:49+00:00" + "time": "2021-08-10T18:51:53+00:00" }, { "name": "donatj/phpuseragentparser", @@ -495,25 +495,26 @@ }, { "name": "enshrined/svg-sanitize", - "version": "0.14.0", + "version": "0.14.1", "source": { "type": "git", "url": "https://github.com/darylldoyle/svg-sanitizer.git", - "reference": "beff89576a72540ee99476aeb9cfe98222e76fb8" + "reference": "307b42066fb0b76b5119f5e1f0826e18fefabe95" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/darylldoyle/svg-sanitizer/zipball/beff89576a72540ee99476aeb9cfe98222e76fb8", - "reference": "beff89576a72540ee99476aeb9cfe98222e76fb8", + "url": "https://api.github.com/repos/darylldoyle/svg-sanitizer/zipball/307b42066fb0b76b5119f5e1f0826e18fefabe95", + "reference": "307b42066fb0b76b5119f5e1f0826e18fefabe95", "shasum": "" }, "require": { "ext-dom": "*", - "ext-libxml": "*" + "ext-libxml": "*", + "php": "^7.0 || ^8.0" }, "require-dev": { "codeclimate/php-test-reporter": "^0.1.2", - "phpunit/phpunit": "^6" + "phpunit/phpunit": "^6.5 || ^8.5" }, "type": "library", "autoload": { @@ -534,9 +535,9 @@ "description": "An SVG sanitizer for PHP", "support": { "issues": "https://github.com/darylldoyle/svg-sanitizer/issues", - "source": "https://github.com/darylldoyle/svg-sanitizer/tree/0.14.0" + "source": "https://github.com/darylldoyle/svg-sanitizer/tree/0.14.1" }, - "time": "2021-01-21T10:13:20+00:00" + "time": "2021-08-09T23:46:54+00:00" }, { "name": "erusev/parsedown", @@ -641,16 +642,16 @@ }, { "name": "filp/whoops", - "version": "2.12.1", + "version": "2.14.1", "source": { "type": "git", "url": "https://github.com/filp/whoops.git", - "reference": "c13c0be93cff50f88bbd70827d993026821914dd" + "reference": "15ead64e9828f0fc90932114429c4f7923570cb1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/filp/whoops/zipball/c13c0be93cff50f88bbd70827d993026821914dd", - "reference": "c13c0be93cff50f88bbd70827d993026821914dd", + "url": "https://api.github.com/repos/filp/whoops/zipball/15ead64e9828f0fc90932114429c4f7923570cb1", + "reference": "15ead64e9828f0fc90932114429c4f7923570cb1", "shasum": "" }, "require": { @@ -700,7 +701,7 @@ ], "support": { "issues": "https://github.com/filp/whoops/issues", - "source": "https://github.com/filp/whoops/tree/2.12.1" + "source": "https://github.com/filp/whoops/tree/2.14.1" }, "funding": [ { @@ -708,7 +709,7 @@ "type": "github" } ], - "time": "2021-04-25T12:00:00+00:00" + "time": "2021-08-29T12:00:00+00:00" }, { "name": "getgrav/cache", @@ -823,16 +824,16 @@ }, { "name": "guzzlehttp/psr7", - "version": "1.8.1", + "version": "1.8.2", "source": { "type": "git", "url": "https://github.com/guzzle/psr7.git", - "reference": "35ea11d335fd638b5882ff1725228b3d35496ab1" + "reference": "dc960a912984efb74d0a90222870c72c87f10c91" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/psr7/zipball/35ea11d335fd638b5882ff1725228b3d35496ab1", - "reference": "35ea11d335fd638b5882ff1725228b3d35496ab1", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/dc960a912984efb74d0a90222870c72c87f10c91", + "reference": "dc960a912984efb74d0a90222870c72c87f10c91", "shasum": "" }, "require": { @@ -892,22 +893,22 @@ ], "support": { "issues": "https://github.com/guzzle/psr7/issues", - "source": "https://github.com/guzzle/psr7/tree/1.8.1" + "source": "https://github.com/guzzle/psr7/tree/1.8.2" }, - "time": "2021-03-21T16:25:00+00:00" + "time": "2021-04-26T09:17:50+00:00" }, { "name": "itsgoingd/clockwork", - "version": "v5.0.7", + "version": "v5.1.0", "source": { "type": "git", "url": "https://github.com/itsgoingd/clockwork.git", - "reference": "e41ee368ff4dcc30d3f4563fe8bd80ed72b293b4" + "reference": "b963dee47429a49c9669981cfa9a8362ce209278" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/itsgoingd/clockwork/zipball/e41ee368ff4dcc30d3f4563fe8bd80ed72b293b4", - "reference": "e41ee368ff4dcc30d3f4563fe8bd80ed72b293b4", + "url": "https://api.github.com/repos/itsgoingd/clockwork/zipball/b963dee47429a49c9669981cfa9a8362ce209278", + "reference": "b963dee47429a49c9669981cfa9a8362ce209278", "shasum": "" }, "require": { @@ -955,7 +956,7 @@ ], "support": { "issues": "https://github.com/itsgoingd/clockwork/issues", - "source": "https://github.com/itsgoingd/clockwork/tree/v5.0.7" + "source": "https://github.com/itsgoingd/clockwork/tree/v5.1.0" }, "funding": [ { @@ -963,7 +964,7 @@ "type": "github" } ], - "time": "2021-03-14T16:29:40+00:00" + "time": "2021-08-07T23:04:17+00:00" }, { "name": "league/climate", @@ -1163,16 +1164,16 @@ }, { "name": "maximebf/debugbar", - "version": "v1.16.5", + "version": "v1.17.1", "source": { "type": "git", "url": "https://github.com/maximebf/php-debugbar.git", - "reference": "6d51ee9e94cff14412783785e79a4e7ef97b9d62" + "reference": "0a3532556be0145603f8a9de23e76dc28eed7054" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/maximebf/php-debugbar/zipball/6d51ee9e94cff14412783785e79a4e7ef97b9d62", - "reference": "6d51ee9e94cff14412783785e79a4e7ef97b9d62", + "url": "https://api.github.com/repos/maximebf/php-debugbar/zipball/0a3532556be0145603f8a9de23e76dc28eed7054", + "reference": "0a3532556be0145603f8a9de23e76dc28eed7054", "shasum": "" }, "require": { @@ -1191,7 +1192,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.16-dev" + "dev-master": "1.17-dev" } }, "autoload": { @@ -1222,9 +1223,9 @@ ], "support": { "issues": "https://github.com/maximebf/php-debugbar/issues", - "source": "https://github.com/maximebf/php-debugbar/tree/v1.16.5" + "source": "https://github.com/maximebf/php-debugbar/tree/v1.17.1" }, - "time": "2020-12-07T11:07:24+00:00" + "time": "2021-08-01T09:19:02+00:00" }, { "name": "miljar/php-exif", @@ -1288,16 +1289,16 @@ }, { "name": "monolog/monolog", - "version": "1.26.0", + "version": "1.26.1", "source": { "type": "git", "url": "https://github.com/Seldaek/monolog.git", - "reference": "2209ddd84e7ef1256b7af205d0717fb62cfc9c33" + "reference": "c6b00f05152ae2c9b04a448f99c7590beb6042f5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Seldaek/monolog/zipball/2209ddd84e7ef1256b7af205d0717fb62cfc9c33", - "reference": "2209ddd84e7ef1256b7af205d0717fb62cfc9c33", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/c6b00f05152ae2c9b04a448f99c7590beb6042f5", + "reference": "c6b00f05152ae2c9b04a448f99c7590beb6042f5", "shasum": "" }, "require": { @@ -1358,7 +1359,7 @@ ], "support": { "issues": "https://github.com/Seldaek/monolog/issues", - "source": "https://github.com/Seldaek/monolog/tree/1.26.0" + "source": "https://github.com/Seldaek/monolog/tree/1.26.1" }, "funding": [ { @@ -1370,20 +1371,20 @@ "type": "tidelift" } ], - "time": "2020-12-14T12:56:38+00:00" + "time": "2021-05-28T08:32:12+00:00" }, { "name": "nyholm/psr7", - "version": "1.4.0", + "version": "1.4.1", "source": { "type": "git", "url": "https://github.com/Nyholm/psr7.git", - "reference": "23ae1f00fbc6a886cbe3062ca682391b9cc7c37b" + "reference": "2212385b47153ea71b1c1b1374f8cb5e4f7892ec" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Nyholm/psr7/zipball/23ae1f00fbc6a886cbe3062ca682391b9cc7c37b", - "reference": "23ae1f00fbc6a886cbe3062ca682391b9cc7c37b", + "url": "https://api.github.com/repos/Nyholm/psr7/zipball/2212385b47153ea71b1c1b1374f8cb5e4f7892ec", + "reference": "2212385b47153ea71b1c1b1374f8cb5e4f7892ec", "shasum": "" }, "require": { @@ -1397,7 +1398,7 @@ "psr/http-message-implementation": "1.0" }, "require-dev": { - "http-interop/http-factory-tests": "^0.8", + "http-interop/http-factory-tests": "^0.9", "php-http/psr7-integration-tests": "^1.0", "phpunit/phpunit": "^7.5 || 8.5 || 9.4", "symfony/error-handler": "^4.4" @@ -1435,7 +1436,7 @@ ], "support": { "issues": "https://github.com/Nyholm/psr7/issues", - "source": "https://github.com/Nyholm/psr7/tree/1.4.0" + "source": "https://github.com/Nyholm/psr7/tree/1.4.1" }, "funding": [ { @@ -1447,20 +1448,20 @@ "type": "github" } ], - "time": "2021-02-18T15:41:32+00:00" + "time": "2021-07-02T08:32:20+00:00" }, { "name": "nyholm/psr7-server", - "version": "1.0.1", + "version": "1.0.2", "source": { "type": "git", "url": "https://github.com/Nyholm/psr7-server.git", - "reference": "5c134aeb5dd6521c7978798663470dabf0528c96" + "reference": "b846a689844cef114e8079d8c80f0afd96745ae3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Nyholm/psr7-server/zipball/5c134aeb5dd6521c7978798663470dabf0528c96", - "reference": "5c134aeb5dd6521c7978798663470dabf0528c96", + "url": "https://api.github.com/repos/Nyholm/psr7-server/zipball/b846a689844cef114e8079d8c80f0afd96745ae3", + "reference": "b846a689844cef114e8079d8c80f0afd96745ae3", "shasum": "" }, "require": { @@ -1501,7 +1502,7 @@ ], "support": { "issues": "https://github.com/Nyholm/psr7-server/issues", - "source": "https://github.com/Nyholm/psr7-server/tree/1.0.1" + "source": "https://github.com/Nyholm/psr7-server/tree/1.0.2" }, "funding": [ { @@ -1513,7 +1514,7 @@ "type": "github" } ], - "time": "2020-11-15T15:26:20+00:00" + "time": "2021-05-12T11:11:27+00:00" }, { "name": "phive/twig-extensions-deferred", @@ -2001,16 +2002,16 @@ }, { "name": "psr/log", - "version": "1.1.3", + "version": "1.1.4", "source": { "type": "git", "url": "https://github.com/php-fig/log.git", - "reference": "0f73288fd15629204f9d42b7055f72dacbe811fc" + "reference": "d49695b909c3b7628b6289db5479a1c204601f11" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/log/zipball/0f73288fd15629204f9d42b7055f72dacbe811fc", - "reference": "0f73288fd15629204f9d42b7055f72dacbe811fc", + "url": "https://api.github.com/repos/php-fig/log/zipball/d49695b909c3b7628b6289db5479a1c204601f11", + "reference": "d49695b909c3b7628b6289db5479a1c204601f11", "shasum": "" }, "require": { @@ -2034,7 +2035,7 @@ "authors": [ { "name": "PHP-FIG", - "homepage": "http://www.php-fig.org/" + "homepage": "https://www.php-fig.org/" } ], "description": "Common interface for logging libraries", @@ -2045,9 +2046,9 @@ "psr-3" ], "support": { - "source": "https://github.com/php-fig/log/tree/1.1.3" + "source": "https://github.com/php-fig/log/tree/1.1.4" }, - "time": "2020-03-23T09:12:05+00:00" + "time": "2021-05-03T11:20:27+00:00" }, { "name": "psr/simple-cache", @@ -2257,36 +2258,37 @@ }, { "name": "symfony/console", - "version": "v4.4.21", + "version": "v4.4.30", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "1ba4560dbbb9fcf5ae28b61f71f49c678086cf23" + "reference": "a3f7189a0665ee33b50e9e228c46f50f5acbed22" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/1ba4560dbbb9fcf5ae28b61f71f49c678086cf23", - "reference": "1ba4560dbbb9fcf5ae28b61f71f49c678086cf23", + "url": "https://api.github.com/repos/symfony/console/zipball/a3f7189a0665ee33b50e9e228c46f50f5acbed22", + "reference": "a3f7189a0665ee33b50e9e228c46f50f5acbed22", "shasum": "" }, "require": { "php": ">=7.1.3", "symfony/polyfill-mbstring": "~1.0", "symfony/polyfill-php73": "^1.8", - "symfony/polyfill-php80": "^1.15", + "symfony/polyfill-php80": "^1.16", "symfony/service-contracts": "^1.1|^2" }, "conflict": { + "psr/log": ">=3", "symfony/dependency-injection": "<3.4", "symfony/event-dispatcher": "<4.3|>=5", "symfony/lock": "<4.4", "symfony/process": "<3.3" }, "provide": { - "psr/log-implementation": "1.0" + "psr/log-implementation": "1.0|2.0" }, "require-dev": { - "psr/log": "~1.0", + "psr/log": "^1|^2", "symfony/config": "^3.4|^4.0|^5.0", "symfony/dependency-injection": "^3.4|^4.0|^5.0", "symfony/event-dispatcher": "^4.3", @@ -2326,7 +2328,7 @@ "description": "Eases the creation of beautiful and testable command line interfaces", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/console/tree/v4.4.21" + "source": "https://github.com/symfony/console/tree/v4.4.30" }, "funding": [ { @@ -2342,7 +2344,7 @@ "type": "tidelift" } ], - "time": "2021-03-26T09:23:24+00:00" + "time": "2021-08-25T19:27:26+00:00" }, { "name": "symfony/contracts", @@ -2440,21 +2442,22 @@ }, { "name": "symfony/event-dispatcher", - "version": "v4.4.20", + "version": "v4.4.30", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "c352647244bd376bf7d31efbd5401f13f50dad0c" + "reference": "2fe81680070043c4c80e7cedceb797e34f377bac" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/c352647244bd376bf7d31efbd5401f13f50dad0c", - "reference": "c352647244bd376bf7d31efbd5401f13f50dad0c", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/2fe81680070043c4c80e7cedceb797e34f377bac", + "reference": "2fe81680070043c4c80e7cedceb797e34f377bac", "shasum": "" }, "require": { "php": ">=7.1.3", - "symfony/event-dispatcher-contracts": "^1.1" + "symfony/event-dispatcher-contracts": "^1.1", + "symfony/polyfill-php80": "^1.16" }, "conflict": { "symfony/dependency-injection": "<3.4" @@ -2464,7 +2467,7 @@ "symfony/event-dispatcher-implementation": "1.1" }, "require-dev": { - "psr/log": "~1.0", + "psr/log": "^1|^2|^3", "symfony/config": "^3.4|^4.0|^5.0", "symfony/dependency-injection": "^3.4|^4.0|^5.0", "symfony/error-handler": "~3.4|~4.4", @@ -2503,7 +2506,7 @@ "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/event-dispatcher/tree/v4.4.20" + "source": "https://github.com/symfony/event-dispatcher/tree/v4.4.30" }, "funding": [ { @@ -2519,27 +2522,28 @@ "type": "tidelift" } ], - "time": "2021-01-27T09:09:26+00:00" + "time": "2021-08-04T20:31:23+00:00" }, { "name": "symfony/http-client", - "version": "v4.4.21", + "version": "v4.4.27", "source": { "type": "git", "url": "https://github.com/symfony/http-client.git", - "reference": "911177e186b82e5b9a9f41c13af53699b6745657" + "reference": "ade6979785bb799e08912f3104959fb169739462" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-client/zipball/911177e186b82e5b9a9f41c13af53699b6745657", - "reference": "911177e186b82e5b9a9f41c13af53699b6745657", + "url": "https://api.github.com/repos/symfony/http-client/zipball/ade6979785bb799e08912f3104959fb169739462", + "reference": "ade6979785bb799e08912f3104959fb169739462", "shasum": "" }, "require": { "php": ">=7.1.3", - "psr/log": "^1.0", + "psr/log": "^1|^2|^3", "symfony/http-client-contracts": "^1.1.10|^2", "symfony/polyfill-php73": "^1.11", + "symfony/polyfill-php80": "^1.16", "symfony/service-contracts": "^1.0|^2" }, "provide": { @@ -2583,7 +2587,7 @@ "description": "Provides powerful methods to fetch HTTP resources synchronously or asynchronously", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-client/tree/v4.4.21" + "source": "https://github.com/symfony/http-client/tree/v4.4.27" }, "funding": [ { @@ -2599,20 +2603,20 @@ "type": "tidelift" } ], - "time": "2021-03-25T17:52:07+00:00" + "time": "2021-07-23T15:41:52+00:00" }, { "name": "symfony/polyfill-ctype", - "version": "v1.22.1", + "version": "v1.23.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "c6c942b1ac76c82448322025e084cadc56048b4e" + "reference": "46cd95797e9df938fdd2b03693b5fca5e64b01ce" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/c6c942b1ac76c82448322025e084cadc56048b4e", - "reference": "c6c942b1ac76c82448322025e084cadc56048b4e", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/46cd95797e9df938fdd2b03693b5fca5e64b01ce", + "reference": "46cd95797e9df938fdd2b03693b5fca5e64b01ce", "shasum": "" }, "require": { @@ -2624,7 +2628,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.22-dev" + "dev-main": "1.23-dev" }, "thanks": { "name": "symfony/polyfill", @@ -2662,7 +2666,7 @@ "portable" ], "support": { - "source": "https://github.com/symfony/polyfill-ctype/tree/v1.22.1" + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.23.0" }, "funding": [ { @@ -2678,20 +2682,20 @@ "type": "tidelift" } ], - "time": "2021-01-07T16:49:33+00:00" + "time": "2021-02-19T12:13:01+00:00" }, { "name": "symfony/polyfill-iconv", - "version": "v1.22.1", + "version": "v1.23.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-iconv.git", - "reference": "06fb361659649bcfd6a208a0f1fcaf4e827ad342" + "reference": "63b5bb7db83e5673936d6e3b8b3e022ff6474933" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-iconv/zipball/06fb361659649bcfd6a208a0f1fcaf4e827ad342", - "reference": "06fb361659649bcfd6a208a0f1fcaf4e827ad342", + "url": "https://api.github.com/repos/symfony/polyfill-iconv/zipball/63b5bb7db83e5673936d6e3b8b3e022ff6474933", + "reference": "63b5bb7db83e5673936d6e3b8b3e022ff6474933", "shasum": "" }, "require": { @@ -2703,7 +2707,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.22-dev" + "dev-main": "1.23-dev" }, "thanks": { "name": "symfony/polyfill", @@ -2742,7 +2746,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-iconv/tree/v1.22.1" + "source": "https://github.com/symfony/polyfill-iconv/tree/v1.23.0" }, "funding": [ { @@ -2758,20 +2762,20 @@ "type": "tidelift" } ], - "time": "2021-01-22T09:19:47+00:00" + "time": "2021-05-27T09:27:20+00:00" }, { "name": "symfony/polyfill-mbstring", - "version": "v1.22.1", + "version": "v1.23.1", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "5232de97ee3b75b0360528dae24e73db49566ab1" + "reference": "9174a3d80210dca8daa7f31fec659150bbeabfc6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/5232de97ee3b75b0360528dae24e73db49566ab1", - "reference": "5232de97ee3b75b0360528dae24e73db49566ab1", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/9174a3d80210dca8daa7f31fec659150bbeabfc6", + "reference": "9174a3d80210dca8daa7f31fec659150bbeabfc6", "shasum": "" }, "require": { @@ -2783,7 +2787,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.22-dev" + "dev-main": "1.23-dev" }, "thanks": { "name": "symfony/polyfill", @@ -2822,7 +2826,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.22.1" + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.23.1" }, "funding": [ { @@ -2838,20 +2842,20 @@ "type": "tidelift" } ], - "time": "2021-01-22T09:19:47+00:00" + "time": "2021-05-27T12:26:48+00:00" }, { "name": "symfony/polyfill-php74", - "version": "v1.22.1", + "version": "v1.23.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php74.git", - "reference": "577e147350331efeb816897e004d85e6e765daaf" + "reference": "a5d80cdf049bd3b0af6da91184a2cd37533c0fd8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php74/zipball/577e147350331efeb816897e004d85e6e765daaf", - "reference": "577e147350331efeb816897e004d85e6e765daaf", + "url": "https://api.github.com/repos/symfony/polyfill-php74/zipball/a5d80cdf049bd3b0af6da91184a2cd37533c0fd8", + "reference": "a5d80cdf049bd3b0af6da91184a2cd37533c0fd8", "shasum": "" }, "require": { @@ -2860,7 +2864,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.22-dev" + "dev-main": "1.23-dev" }, "thanks": { "name": "symfony/polyfill", @@ -2902,7 +2906,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php74/tree/v1.22.1" + "source": "https://github.com/symfony/polyfill-php74/tree/v1.23.0" }, "funding": [ { @@ -2918,20 +2922,20 @@ "type": "tidelift" } ], - "time": "2021-01-07T16:49:33+00:00" + "time": "2021-02-19T12:13:01+00:00" }, { "name": "symfony/polyfill-php80", - "version": "v1.22.1", + "version": "v1.23.1", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php80.git", - "reference": "dc3063ba22c2a1fd2f45ed856374d79114998f91" + "reference": "1100343ed1a92e3a38f9ae122fc0eb21602547be" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/dc3063ba22c2a1fd2f45ed856374d79114998f91", - "reference": "dc3063ba22c2a1fd2f45ed856374d79114998f91", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/1100343ed1a92e3a38f9ae122fc0eb21602547be", + "reference": "1100343ed1a92e3a38f9ae122fc0eb21602547be", "shasum": "" }, "require": { @@ -2940,7 +2944,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.22-dev" + "dev-main": "1.23-dev" }, "thanks": { "name": "symfony/polyfill", @@ -2985,7 +2989,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php80/tree/v1.22.1" + "source": "https://github.com/symfony/polyfill-php80/tree/v1.23.1" }, "funding": [ { @@ -3001,24 +3005,25 @@ "type": "tidelift" } ], - "time": "2021-01-07T16:49:33+00:00" + "time": "2021-07-28T13:41:28+00:00" }, { "name": "symfony/process", - "version": "v4.4.20", + "version": "v4.4.30", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "7e950b6366d4da90292c2e7fa820b3c1842b965a" + "reference": "13d3161ef63a8ec21eeccaaf9a4d7f784a87a97d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/7e950b6366d4da90292c2e7fa820b3c1842b965a", - "reference": "7e950b6366d4da90292c2e7fa820b3c1842b965a", + "url": "https://api.github.com/repos/symfony/process/zipball/13d3161ef63a8ec21eeccaaf9a4d7f784a87a97d", + "reference": "13d3161ef63a8ec21eeccaaf9a4d7f784a87a97d", "shasum": "" }, "require": { - "php": ">=7.1.3" + "php": ">=7.1.3", + "symfony/polyfill-php80": "^1.16" }, "type": "library", "autoload": { @@ -3046,7 +3051,7 @@ "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/process/tree/v4.4.20" + "source": "https://github.com/symfony/process/tree/v4.4.30" }, "funding": [ { @@ -3062,27 +3067,27 @@ "type": "tidelift" } ], - "time": "2021-01-27T09:09:26+00:00" + "time": "2021-08-04T20:31:23+00:00" }, { "name": "symfony/var-dumper", - "version": "v4.4.21", + "version": "v4.4.30", "source": { "type": "git", "url": "https://github.com/symfony/var-dumper.git", - "reference": "0da0e174f728996f5d5072d6a9f0a42259dbc806" + "reference": "7f65c44c2ce80d3a0fcdb6385ee0ad535e45660c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/0da0e174f728996f5d5072d6a9f0a42259dbc806", - "reference": "0da0e174f728996f5d5072d6a9f0a42259dbc806", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/7f65c44c2ce80d3a0fcdb6385ee0ad535e45660c", + "reference": "7f65c44c2ce80d3a0fcdb6385ee0ad535e45660c", "shasum": "" }, "require": { "php": ">=7.1.3", "symfony/polyfill-mbstring": "~1.0", "symfony/polyfill-php72": "~1.5", - "symfony/polyfill-php80": "^1.15" + "symfony/polyfill-php80": "^1.16" }, "conflict": { "phpunit/phpunit": "<4.8.35|<5.4.3,>=5.0", @@ -3135,7 +3140,7 @@ "dump" ], "support": { - "source": "https://github.com/symfony/var-dumper/tree/v4.4.21" + "source": "https://github.com/symfony/var-dumper/tree/v4.4.30" }, "funding": [ { @@ -3151,20 +3156,20 @@ "type": "tidelift" } ], - "time": "2021-03-27T19:49:03+00:00" + "time": "2021-08-04T20:31:23+00:00" }, { "name": "symfony/yaml", - "version": "v4.4.21", + "version": "v4.4.29", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "3871c720871029f008928244e56cf43497da7e9d" + "reference": "3abcc4db06d4e776825eaa3ed8ad924d5bc7432a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/3871c720871029f008928244e56cf43497da7e9d", - "reference": "3871c720871029f008928244e56cf43497da7e9d", + "url": "https://api.github.com/repos/symfony/yaml/zipball/3abcc4db06d4e776825eaa3ed8ad924d5bc7432a", + "reference": "3abcc4db06d4e776825eaa3ed8ad924d5bc7432a", "shasum": "" }, "require": { @@ -3206,7 +3211,7 @@ "description": "Loads and dumps YAML files", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/yaml/tree/v4.4.21" + "source": "https://github.com/symfony/yaml/tree/v4.4.29" }, "funding": [ { @@ -3222,20 +3227,20 @@ "type": "tidelift" } ], - "time": "2021-03-05T17:58:50+00:00" + "time": "2021-07-27T16:19:30+00:00" }, { "name": "twig/twig", - "version": "v1.44.2", + "version": "v1.44.4", "source": { "type": "git", "url": "https://github.com/twigphp/Twig.git", - "reference": "138c493c5b8ee7cff3821f80b8896d371366b5fe" + "reference": "4d400421528e9fa40caaffcf7824c172526dd99d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/twigphp/Twig/zipball/138c493c5b8ee7cff3821f80b8896d371366b5fe", - "reference": "138c493c5b8ee7cff3821f80b8896d371366b5fe", + "url": "https://api.github.com/repos/twigphp/Twig/zipball/4d400421528e9fa40caaffcf7824c172526dd99d", + "reference": "4d400421528e9fa40caaffcf7824c172526dd99d", "shasum": "" }, "require": { @@ -3288,7 +3293,7 @@ ], "support": { "issues": "https://github.com/twigphp/Twig/issues", - "source": "https://github.com/twigphp/Twig/tree/v1.44.2" + "source": "https://github.com/twigphp/Twig/tree/v1.44.4" }, "funding": [ { @@ -3300,7 +3305,7 @@ "type": "tidelift" } ], - "time": "2021-01-05T10:10:05+00:00" + "time": "2021-05-16T12:11:20+00:00" }, { "name": "willdurand/negotiation", @@ -3426,16 +3431,16 @@ }, { "name": "codeception/codeception", - "version": "4.1.20", + "version": "4.1.22", "source": { "type": "git", "url": "https://github.com/Codeception/Codeception.git", - "reference": "d8b16e13e1781dbc3a7ae8292117d520c89a9c5a" + "reference": "9777ec3690ceedc4bce2ed13af7af4ca4ee3088f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Codeception/Codeception/zipball/d8b16e13e1781dbc3a7ae8292117d520c89a9c5a", - "reference": "d8b16e13e1781dbc3a7ae8292117d520c89a9c5a", + "url": "https://api.github.com/repos/Codeception/Codeception/zipball/9777ec3690ceedc4bce2ed13af7af4ca4ee3088f", + "reference": "9777ec3690ceedc4bce2ed13af7af4ca4ee3088f", "shasum": "" }, "require": { @@ -3446,7 +3451,7 @@ "ext-curl": "*", "ext-json": "*", "ext-mbstring": "*", - "guzzlehttp/psr7": "~1.4", + "guzzlehttp/psr7": "^1.4 | ^2.0", "php": ">=5.6.0 <9.0", "symfony/console": ">=2.7 <6.0", "symfony/css-selector": ">=2.7 <6.0", @@ -3455,11 +3460,11 @@ "symfony/yaml": ">=2.7 <6.0" }, "require-dev": { - "codeception/module-asserts": "*@dev", - "codeception/module-cli": "*@dev", - "codeception/module-db": "*@dev", - "codeception/module-filesystem": "*@dev", - "codeception/module-phpbrowser": "*@dev", + "codeception/module-asserts": "1.*@dev", + "codeception/module-cli": "1.*@dev", + "codeception/module-db": "1.*@dev", + "codeception/module-filesystem": "1.*@dev", + "codeception/module-phpbrowser": "1.*@dev", "codeception/specify": "~0.3", "codeception/util-universalframework": "*@dev", "monolog/monolog": "~1.8", @@ -3509,7 +3514,7 @@ ], "support": { "issues": "https://github.com/Codeception/Codeception/issues", - "source": "https://github.com/Codeception/Codeception/tree/4.1.20" + "source": "https://github.com/Codeception/Codeception/tree/4.1.22" }, "funding": [ { @@ -3517,7 +3522,7 @@ "type": "open_collective" } ], - "time": "2021-04-02T16:41:51+00:00" + "time": "2021-08-06T17:15:34+00:00" }, { "name": "codeception/lib-asserts", @@ -3575,20 +3580,20 @@ }, { "name": "codeception/lib-innerbrowser", - "version": "1.5.0", + "version": "1.5.1", "source": { "type": "git", "url": "https://github.com/Codeception/lib-innerbrowser.git", - "reference": "4b0d89b37fe454e060a610a85280a87ab4f534f1" + "reference": "31b4b56ad53c3464fcb2c0a14d55a51a201bd3c2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Codeception/lib-innerbrowser/zipball/4b0d89b37fe454e060a610a85280a87ab4f534f1", - "reference": "4b0d89b37fe454e060a610a85280a87ab4f534f1", + "url": "https://api.github.com/repos/Codeception/lib-innerbrowser/zipball/31b4b56ad53c3464fcb2c0a14d55a51a201bd3c2", + "reference": "31b4b56ad53c3464fcb2c0a14d55a51a201bd3c2", "shasum": "" }, "require": { - "codeception/codeception": "*@dev", + "codeception/codeception": "4.*@dev", "ext-dom": "*", "ext-json": "*", "ext-mbstring": "*", @@ -3629,9 +3634,9 @@ ], "support": { "issues": "https://github.com/Codeception/lib-innerbrowser/issues", - "source": "https://github.com/Codeception/lib-innerbrowser/tree/1.5.0" + "source": "https://github.com/Codeception/lib-innerbrowser/tree/1.5.1" }, - "time": "2021-04-23T06:18:29+00:00" + "time": "2021-08-30T15:21:42+00:00" }, { "name": "codeception/module-asserts", @@ -4172,16 +4177,16 @@ }, { "name": "nikic/php-parser", - "version": "v4.10.4", + "version": "v4.12.0", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "c6d052fc58cb876152f89f532b95a8d7907e7f0e" + "reference": "6608f01670c3cc5079e18c1dab1104e002579143" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/c6d052fc58cb876152f89f532b95a8d7907e7f0e", - "reference": "c6d052fc58cb876152f89f532b95a8d7907e7f0e", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/6608f01670c3cc5079e18c1dab1104e002579143", + "reference": "6608f01670c3cc5079e18c1dab1104e002579143", "shasum": "" }, "require": { @@ -4222,22 +4227,22 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v4.10.4" + "source": "https://github.com/nikic/PHP-Parser/tree/v4.12.0" }, - "time": "2020-12-20T10:01:03+00:00" + "time": "2021-07-21T10:44:31+00:00" }, { "name": "phar-io/manifest", - "version": "2.0.1", + "version": "2.0.3", "source": { "type": "git", "url": "https://github.com/phar-io/manifest.git", - "reference": "85265efd3af7ba3ca4b2a2c34dbfc5788dd29133" + "reference": "97803eca37d319dfa7826cc2437fc020857acb53" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phar-io/manifest/zipball/85265efd3af7ba3ca4b2a2c34dbfc5788dd29133", - "reference": "85265efd3af7ba3ca4b2a2c34dbfc5788dd29133", + "url": "https://api.github.com/repos/phar-io/manifest/zipball/97803eca37d319dfa7826cc2437fc020857acb53", + "reference": "97803eca37d319dfa7826cc2437fc020857acb53", "shasum": "" }, "require": { @@ -4282,9 +4287,9 @@ "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", "support": { "issues": "https://github.com/phar-io/manifest/issues", - "source": "https://github.com/phar-io/manifest/tree/master" + "source": "https://github.com/phar-io/manifest/tree/2.0.3" }, - "time": "2020-06-27T14:33:11+00:00" + "time": "2021-07-20T11:28:43+00:00" }, { "name": "phar-io/version", @@ -4564,16 +4569,16 @@ }, { "name": "phpstan/phpstan", - "version": "0.12.84", + "version": "0.12.98", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "9c43f15da8798c8f30a4b099e6a94530a558cfd5" + "reference": "3bb7cc246c057405dd5e290c3ecc62ab51d57e00" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/9c43f15da8798c8f30a4b099e6a94530a558cfd5", - "reference": "9c43f15da8798c8f30a4b099e6a94530a558cfd5", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/3bb7cc246c057405dd5e290c3ecc62ab51d57e00", + "reference": "3bb7cc246c057405dd5e290c3ecc62ab51d57e00", "shasum": "" }, "require": { @@ -4604,13 +4609,17 @@ "description": "PHPStan - PHP Static Analysis Tool", "support": { "issues": "https://github.com/phpstan/phpstan/issues", - "source": "https://github.com/phpstan/phpstan/tree/0.12.84" + "source": "https://github.com/phpstan/phpstan/tree/0.12.98" }, "funding": [ { "url": "https://github.com/ondrejmirtes", "type": "github" }, + { + "url": "https://github.com/phpstan", + "type": "github" + }, { "url": "https://www.patreon.com/phpstan", "type": "patreon" @@ -4620,7 +4629,7 @@ "type": "tidelift" } ], - "time": "2021-04-19T17:10:54+00:00" + "time": "2021-09-02T12:33:01+00:00" }, { "name": "phpstan/phpstan-deprecation-rules", @@ -4993,16 +5002,16 @@ }, { "name": "phpunit/phpunit", - "version": "9.5.4", + "version": "9.5.9", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "c73c6737305e779771147af66c96ca6a7ed8a741" + "reference": "ea8c2dfb1065eb35a79b3681eee6e6fb0a6f273b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/c73c6737305e779771147af66c96ca6a7ed8a741", - "reference": "c73c6737305e779771147af66c96ca6a7ed8a741", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/ea8c2dfb1065eb35a79b3681eee6e6fb0a6f273b", + "reference": "ea8c2dfb1065eb35a79b3681eee6e6fb0a6f273b", "shasum": "" }, "require": { @@ -5014,7 +5023,7 @@ "ext-xml": "*", "ext-xmlwriter": "*", "myclabs/deep-copy": "^1.10.1", - "phar-io/manifest": "^2.0.1", + "phar-io/manifest": "^2.0.3", "phar-io/version": "^3.0.2", "php": ">=7.3", "phpspec/prophecy": "^1.12.1", @@ -5032,7 +5041,7 @@ "sebastian/global-state": "^5.0.1", "sebastian/object-enumerator": "^4.0.3", "sebastian/resource-operations": "^3.0.3", - "sebastian/type": "^2.3", + "sebastian/type": "^2.3.4", "sebastian/version": "^3.0.2" }, "require-dev": { @@ -5080,7 +5089,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", - "source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.4" + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.9" }, "funding": [ { @@ -5092,7 +5101,7 @@ "type": "github" } ], - "time": "2021-03-23T07:16:29+00:00" + "time": "2021-08-31T06:47:40+00:00" }, { "name": "psr/http-client", @@ -5652,16 +5661,16 @@ }, { "name": "sebastian/global-state", - "version": "5.0.2", + "version": "5.0.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/global-state.git", - "reference": "a90ccbddffa067b51f574dea6eb25d5680839455" + "reference": "23bd5951f7ff26f12d4e3242864df3e08dec4e49" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/a90ccbddffa067b51f574dea6eb25d5680839455", - "reference": "a90ccbddffa067b51f574dea6eb25d5680839455", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/23bd5951f7ff26f12d4e3242864df3e08dec4e49", + "reference": "23bd5951f7ff26f12d4e3242864df3e08dec4e49", "shasum": "" }, "require": { @@ -5704,7 +5713,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/global-state/issues", - "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.2" + "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.3" }, "funding": [ { @@ -5712,7 +5721,7 @@ "type": "github" } ], - "time": "2020-10-26T15:55:19+00:00" + "time": "2021-06-11T13:31:12+00:00" }, { "name": "sebastian/lines-of-code", @@ -5999,20 +6008,21 @@ "type": "github" } ], + "abandoned": true, "time": "2020-09-28T06:45:17+00:00" }, { "name": "sebastian/type", - "version": "2.3.1", + "version": "2.3.4", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/type.git", - "reference": "81cd61ab7bbf2de744aba0ea61fae32f721df3d2" + "reference": "b8cd8a1c753c90bc1a0f5372170e3e489136f914" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/81cd61ab7bbf2de744aba0ea61fae32f721df3d2", - "reference": "81cd61ab7bbf2de744aba0ea61fae32f721df3d2", + "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/b8cd8a1c753c90bc1a0f5372170e3e489136f914", + "reference": "b8cd8a1c753c90bc1a0f5372170e3e489136f914", "shasum": "" }, "require": { @@ -6047,7 +6057,7 @@ "homepage": "https://github.com/sebastianbergmann/type", "support": { "issues": "https://github.com/sebastianbergmann/type/issues", - "source": "https://github.com/sebastianbergmann/type/tree/2.3.1" + "source": "https://github.com/sebastianbergmann/type/tree/2.3.4" }, "funding": [ { @@ -6055,7 +6065,7 @@ "type": "github" } ], - "time": "2020-10-26T13:18:59+00:00" + "time": "2021-06-15T12:49:02+00:00" }, { "name": "sebastian/version", @@ -6112,21 +6122,22 @@ }, { "name": "symfony/browser-kit", - "version": "v5.2.4", + "version": "v5.3.4", "source": { "type": "git", "url": "https://github.com/symfony/browser-kit.git", - "reference": "3ca3a57ce9860318b20a924fec5daf5c6db44d93" + "reference": "c1e3f64fcc631c96e2c5843b666db66679ced11c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/browser-kit/zipball/3ca3a57ce9860318b20a924fec5daf5c6db44d93", - "reference": "3ca3a57ce9860318b20a924fec5daf5c6db44d93", + "url": "https://api.github.com/repos/symfony/browser-kit/zipball/c1e3f64fcc631c96e2c5843b666db66679ced11c", + "reference": "c1e3f64fcc631c96e2c5843b666db66679ced11c", "shasum": "" }, "require": { "php": ">=7.2.5", - "symfony/dom-crawler": "^4.4|^5.0" + "symfony/dom-crawler": "^4.4|^5.0", + "symfony/polyfill-php80": "^1.16" }, "require-dev": { "symfony/css-selector": "^4.4|^5.0", @@ -6163,7 +6174,7 @@ "description": "Simulates the behavior of a web browser, allowing you to make requests, click on links and submit forms programmatically", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/browser-kit/tree/v5.2.4" + "source": "https://github.com/symfony/browser-kit/tree/v5.3.4" }, "funding": [ { @@ -6179,24 +6190,25 @@ "type": "tidelift" } ], - "time": "2021-02-22T06:48:33+00:00" + "time": "2021-07-21T12:40:44+00:00" }, { "name": "symfony/css-selector", - "version": "v5.2.4", + "version": "v5.3.4", "source": { "type": "git", "url": "https://github.com/symfony/css-selector.git", - "reference": "f65f217b3314504a1ec99c2d6ef69016bb13490f" + "reference": "7fb120adc7f600a59027775b224c13a33530dd90" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/css-selector/zipball/f65f217b3314504a1ec99c2d6ef69016bb13490f", - "reference": "f65f217b3314504a1ec99c2d6ef69016bb13490f", + "url": "https://api.github.com/repos/symfony/css-selector/zipball/7fb120adc7f600a59027775b224c13a33530dd90", + "reference": "7fb120adc7f600a59027775b224c13a33530dd90", "shasum": "" }, "require": { - "php": ">=7.2.5" + "php": ">=7.2.5", + "symfony/polyfill-php80": "^1.16" }, "type": "library", "autoload": { @@ -6228,7 +6240,7 @@ "description": "Converts CSS selectors to XPath expressions", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/css-selector/tree/v5.2.4" + "source": "https://github.com/symfony/css-selector/tree/v5.3.4" }, "funding": [ { @@ -6244,27 +6256,95 @@ "type": "tidelift" } ], - "time": "2021-01-27T10:01:46+00:00" + "time": "2021-07-21T12:38:00+00:00" }, { - "name": "symfony/dom-crawler", - "version": "v5.2.4", + "name": "symfony/deprecation-contracts", + "version": "v2.4.0", "source": { "type": "git", - "url": "https://github.com/symfony/dom-crawler.git", - "reference": "400e265163f65aceee7e904ef532e15228de674b" + "url": "https://github.com/symfony/deprecation-contracts.git", + "reference": "5f38c8804a9e97d23e0c8d63341088cd8a22d627" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/400e265163f65aceee7e904ef532e15228de674b", - "reference": "400e265163f65aceee7e904ef532e15228de674b", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/5f38c8804a9e97d23e0c8d63341088cd8a22d627", + "reference": "5f38c8804a9e97d23e0c8d63341088cd8a22d627", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.4-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "files": [ + "function.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "A generic function and convention to trigger deprecation notices", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/deprecation-contracts/tree/v2.4.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2021-03-23T23:28:01+00:00" + }, + { + "name": "symfony/dom-crawler", + "version": "v5.3.7", + "source": { + "type": "git", + "url": "https://github.com/symfony/dom-crawler.git", + "reference": "c7eef3a60ccfdd8eafe07f81652e769ac9c7146c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/c7eef3a60ccfdd8eafe07f81652e769ac9c7146c", + "reference": "c7eef3a60ccfdd8eafe07f81652e769ac9c7146c", "shasum": "" }, "require": { "php": ">=7.2.5", + "symfony/deprecation-contracts": "^2.1", "symfony/polyfill-ctype": "~1.8", "symfony/polyfill-mbstring": "~1.0", - "symfony/polyfill-php80": "^1.15" + "symfony/polyfill-php80": "^1.16" }, "conflict": { "masterminds/html5": "<2.6" @@ -6302,7 +6382,7 @@ "description": "Eases DOM navigation for HTML and XML documents", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/dom-crawler/tree/v5.2.4" + "source": "https://github.com/symfony/dom-crawler/tree/v5.3.7" }, "funding": [ { @@ -6318,24 +6398,25 @@ "type": "tidelift" } ], - "time": "2021-02-15T18:55:04+00:00" + "time": "2021-08-29T19:32:13+00:00" }, { "name": "symfony/finder", - "version": "v5.2.4", + "version": "v5.3.7", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "0d639a0943822626290d169965804f79400e6a04" + "reference": "a10000ada1e600d109a6c7632e9ac42e8bf2fb93" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/0d639a0943822626290d169965804f79400e6a04", - "reference": "0d639a0943822626290d169965804f79400e6a04", + "url": "https://api.github.com/repos/symfony/finder/zipball/a10000ada1e600d109a6c7632e9ac42e8bf2fb93", + "reference": "a10000ada1e600d109a6c7632e9ac42e8bf2fb93", "shasum": "" }, "require": { - "php": ">=7.2.5" + "php": ">=7.2.5", + "symfony/polyfill-php80": "^1.16" }, "type": "library", "autoload": { @@ -6363,7 +6444,7 @@ "description": "Finds files and directories via an intuitive fluent interface", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/finder/tree/v5.2.4" + "source": "https://github.com/symfony/finder/tree/v5.3.7" }, "funding": [ { @@ -6379,20 +6460,20 @@ "type": "tidelift" } ], - "time": "2021-02-15T18:55:04+00:00" + "time": "2021-08-04T21:20:46+00:00" }, { "name": "theseer/tokenizer", - "version": "1.2.0", + "version": "1.2.1", "source": { "type": "git", "url": "https://github.com/theseer/tokenizer.git", - "reference": "75a63c33a8577608444246075ea0af0d052e452a" + "reference": "34a41e998c2183e22995f158c581e7b5e755ab9e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/theseer/tokenizer/zipball/75a63c33a8577608444246075ea0af0d052e452a", - "reference": "75a63c33a8577608444246075ea0af0d052e452a", + "url": "https://api.github.com/repos/theseer/tokenizer/zipball/34a41e998c2183e22995f158c581e7b5e755ab9e", + "reference": "34a41e998c2183e22995f158c581e7b5e755ab9e", "shasum": "" }, "require": { @@ -6421,7 +6502,7 @@ "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", "support": { "issues": "https://github.com/theseer/tokenizer/issues", - "source": "https://github.com/theseer/tokenizer/tree/master" + "source": "https://github.com/theseer/tokenizer/tree/1.2.1" }, "funding": [ { @@ -6429,7 +6510,7 @@ "type": "github" } ], - "time": "2020-07-12T23:59:07+00:00" + "time": "2021-07-28T10:34:58+00:00" }, { "name": "webmozart/assert", diff --git a/index.php b/index.php index 9842952..091e9a8 100644 --- a/index.php +++ b/index.php @@ -17,8 +17,8 @@ if (version_compare($ver = PHP_VERSION, $req = GRAV_PHP_MIN, '<')) { } if (PHP_SAPI === 'cli-server') { - $symfony_server = stripos(getenv('_'), 'symfony') !== false || stripos($_SERVER['SERVER_SOFTWARE'], 'symfony -') !== false; + $symfony_server = stripos(getenv('_'), 'symfony') !== false || stripos($_SERVER['SERVER_SOFTWARE'] ?? '', 'symfony') !== false || stripos($_ENV['SERVER_SOFTWARE'] ?? '', 'symfony') !== false; + if (!isset($_SERVER['PHP_CLI_ROUTER']) && !$symfony_server) { die("PHP webserver requires a router to run Grav, please use:
php -S {$_SERVER['SERVER_NAME']}:{$_SERVER['SERVER_PORT']} system/router.php
"); } diff --git a/system/blueprints/config/scheduler.yaml b/system/blueprints/config/scheduler.yaml index caa7711..a8dce31 100644 --- a/system/blueprints/config/scheduler.yaml +++ b/system/blueprints/config/scheduler.yaml @@ -47,7 +47,8 @@ form: label: PLUGIN_ADMIN.EXTRA_ARGUMENTS placeholder: '-lah' .at: - type: cron + type: text + wrapper_classes: cron-selector label: PLUGIN_ADMIN.SCHEDULER_RUNAT help: PLUGIN_ADMIN.SCHEDULER_RUNAT_HELP placeholder: '* * * * *' diff --git a/system/blueprints/flex/pages.yaml b/system/blueprints/flex/pages.yaml index ee2e7e5..5c6ed8e 100644 --- a/system/blueprints/flex/pages.yaml +++ b/system/blueprints/flex/pages.yaml @@ -184,9 +184,9 @@ config: # Fields to be searched fields: - key + - slug - menu - title - - name blueprints: configure: diff --git a/system/config/media.yaml b/system/config/media.yaml index e5439d6..b118a21 100644 --- a/system/config/media.yaml +++ b/system/config/media.yaml @@ -28,6 +28,10 @@ types: type: image thumb: media/thumb-webp.png mime: image/webp + avif: + type: image + thumb: media/thumb.png + mime: image/avif gif: type: animated thumb: media/thumb-gif.png @@ -91,7 +95,7 @@ types: aif: type: audio thumb: media/thumb-aif.png - mime: audio/aif + mime: audio/aiff txt: type: file thumb: media/thumb-txt.png @@ -207,7 +211,7 @@ types: js: type: file thumb: media/thumb-js.png - mime: application/javascript + mime: text/javascript json: type: file thumb: media/thumb-json.png diff --git a/system/config/mime.yaml b/system/config/mime.yaml new file mode 100644 index 0000000..3143c67 --- /dev/null +++ b/system/config/mime.yaml @@ -0,0 +1,1986 @@ +types: + '123': + - application/vnd.lotus-1-2-3 + wof: + - application/font-woff + php: + - application/php + - application/x-httpd-php + - application/x-httpd-php-source + - application/x-php + - text/php + - text/x-php + otf: + - application/x-font-otf + - font/otf + ttf: + - application/x-font-ttf + - font/ttf + ttc: + - application/x-font-ttf + - font/collection + zip: + - application/x-gzip + - application/zip + - application/x-zip-compressed + amr: + - audio/amr + mp3: + - audio/mpeg + mpga: + - audio/mpeg + mp2: + - audio/mpeg + mp2a: + - audio/mpeg + m2a: + - audio/mpeg + m3a: + - audio/mpeg + jpg: + - image/jpeg + jpeg: + - image/jpeg + jpe: + - image/jpeg + bmp: + - image/x-ms-bmp + - image/bmp + ez: + - application/andrew-inset + aw: + - application/applixware + atom: + - application/atom+xml + atomcat: + - application/atomcat+xml + atomsvc: + - application/atomsvc+xml + ccxml: + - application/ccxml+xml + cdmia: + - application/cdmi-capability + cdmic: + - application/cdmi-container + cdmid: + - application/cdmi-domain + cdmio: + - application/cdmi-object + cdmiq: + - application/cdmi-queue + cu: + - application/cu-seeme + davmount: + - application/davmount+xml + dbk: + - application/docbook+xml + dssc: + - application/dssc+der + xdssc: + - application/dssc+xml + ecma: + - application/ecmascript + emma: + - application/emma+xml + epub: + - application/epub+zip + exi: + - application/exi + pfr: + - application/font-tdpfr + gml: + - application/gml+xml + gpx: + - application/gpx+xml + gxf: + - application/gxf + stk: + - application/hyperstudio + ink: + - application/inkml+xml + inkml: + - application/inkml+xml + ipfix: + - application/ipfix + jar: + - application/java-archive + ser: + - application/java-serialized-object + class: + - application/java-vm + js: + - application/javascript + json: + - application/json + jsonml: + - application/jsonml+json + lostxml: + - application/lost+xml + hqx: + - application/mac-binhex40 + cpt: + - application/mac-compactpro + mads: + - application/mads+xml + mrc: + - application/marc + mrcx: + - application/marcxml+xml + ma: + - application/mathematica + nb: + - application/mathematica + mb: + - application/mathematica + mathml: + - application/mathml+xml + mbox: + - application/mbox + mscml: + - application/mediaservercontrol+xml + metalink: + - application/metalink+xml + meta4: + - application/metalink4+xml + mets: + - application/mets+xml + mods: + - application/mods+xml + m21: + - application/mp21 + mp21: + - application/mp21 + mp4s: + - application/mp4 + doc: + - application/msword + dot: + - application/msword + mxf: + - application/mxf + bin: + - application/octet-stream + dms: + - application/octet-stream + lrf: + - application/octet-stream + mar: + - application/octet-stream + so: + - application/octet-stream + dist: + - application/octet-stream + distz: + - application/octet-stream + pkg: + - application/octet-stream + bpk: + - application/octet-stream + dump: + - application/octet-stream + elc: + - application/octet-stream + deploy: + - application/octet-stream + oda: + - application/oda + opf: + - application/oebps-package+xml + ogx: + - application/ogg + omdoc: + - application/omdoc+xml + onetoc: + - application/onenote + onetoc2: + - application/onenote + onetmp: + - application/onenote + onepkg: + - application/onenote + oxps: + - application/oxps + xer: + - application/patch-ops-error+xml + pdf: + - application/pdf + pgp: + - application/pgp-encrypted + asc: + - application/pgp-signature + sig: + - application/pgp-signature + prf: + - application/pics-rules + p10: + - application/pkcs10 + p7m: + - application/pkcs7-mime + p7c: + - application/pkcs7-mime + p7s: + - application/pkcs7-signature + p8: + - application/pkcs8 + ac: + - application/pkix-attr-cert + cer: + - application/pkix-cert + crl: + - application/pkix-crl + pkipath: + - application/pkix-pkipath + pki: + - application/pkixcmp + pls: + - application/pls+xml + ai: + - application/postscript + eps: + - application/postscript + ps: + - application/postscript + cww: + - application/prs.cww + pskcxml: + - application/pskc+xml + rdf: + - application/rdf+xml + rif: + - application/reginfo+xml + rnc: + - application/relax-ng-compact-syntax + rl: + - application/resource-lists+xml + rld: + - application/resource-lists-diff+xml + rs: + - application/rls-services+xml + gbr: + - application/rpki-ghostbusters + mft: + - application/rpki-manifest + roa: + - application/rpki-roa + rsd: + - application/rsd+xml + rss: + - application/rss+xml + rtf: + - application/rtf + sbml: + - application/sbml+xml + scq: + - application/scvp-cv-request + scs: + - application/scvp-cv-response + spq: + - application/scvp-vp-request + spp: + - application/scvp-vp-response + sdp: + - application/sdp + setpay: + - application/set-payment-initiation + setreg: + - application/set-registration-initiation + shf: + - application/shf+xml + smi: + - application/smil+xml + smil: + - application/smil+xml + rq: + - application/sparql-query + srx: + - application/sparql-results+xml + gram: + - application/srgs + grxml: + - application/srgs+xml + sru: + - application/sru+xml + ssdl: + - application/ssdl+xml + ssml: + - application/ssml+xml + tei: + - application/tei+xml + teicorpus: + - application/tei+xml + tfi: + - application/thraud+xml + tsd: + - application/timestamped-data + plb: + - application/vnd.3gpp.pic-bw-large + psb: + - application/vnd.3gpp.pic-bw-small + pvb: + - application/vnd.3gpp.pic-bw-var + tcap: + - application/vnd.3gpp2.tcap + pwn: + - application/vnd.3m.post-it-notes + aso: + - application/vnd.accpac.simply.aso + imp: + - application/vnd.accpac.simply.imp + acu: + - application/vnd.acucobol + atc: + - application/vnd.acucorp + acutc: + - application/vnd.acucorp + air: + - application/vnd.adobe.air-application-installer-package+zip + fcdt: + - application/vnd.adobe.formscentral.fcdt + fxp: + - application/vnd.adobe.fxp + fxpl: + - application/vnd.adobe.fxp + xdp: + - application/vnd.adobe.xdp+xml + xfdf: + - application/vnd.adobe.xfdf + ahead: + - application/vnd.ahead.space + azf: + - application/vnd.airzip.filesecure.azf + azs: + - application/vnd.airzip.filesecure.azs + azw: + - application/vnd.amazon.ebook + acc: + - application/vnd.americandynamics.acc + ami: + - application/vnd.amiga.ami + apk: + - application/vnd.android.package-archive + cii: + - application/vnd.anser-web-certificate-issue-initiation + fti: + - application/vnd.anser-web-funds-transfer-initiation + atx: + - application/vnd.antix.game-component + mpkg: + - application/vnd.apple.installer+xml + m3u8: + - application/vnd.apple.mpegurl + swi: + - application/vnd.aristanetworks.swi + iota: + - application/vnd.astraea-software.iota + aep: + - application/vnd.audiograph + mpm: + - application/vnd.blueice.multipass + bmi: + - application/vnd.bmi + rep: + - application/vnd.businessobjects + cdxml: + - application/vnd.chemdraw+xml + mmd: + - application/vnd.chipnuts.karaoke-mmd + cdy: + - application/vnd.cinderella + cla: + - application/vnd.claymore + rp9: + - application/vnd.cloanto.rp9 + c4g: + - application/vnd.clonk.c4group + c4d: + - application/vnd.clonk.c4group + c4f: + - application/vnd.clonk.c4group + c4p: + - application/vnd.clonk.c4group + c4u: + - application/vnd.clonk.c4group + c11amc: + - application/vnd.cluetrust.cartomobile-config + c11amz: + - application/vnd.cluetrust.cartomobile-config-pkg + csp: + - application/vnd.commonspace + cdbcmsg: + - application/vnd.contact.cmsg + cmc: + - application/vnd.cosmocaller + clkx: + - application/vnd.crick.clicker + clkk: + - application/vnd.crick.clicker.keyboard + clkp: + - application/vnd.crick.clicker.palette + clkt: + - application/vnd.crick.clicker.template + clkw: + - application/vnd.crick.clicker.wordbank + wbs: + - application/vnd.criticaltools.wbs+xml + pml: + - application/vnd.ctc-posml + ppd: + - application/vnd.cups-ppd + car: + - application/vnd.curl.car + pcurl: + - application/vnd.curl.pcurl + dart: + - application/vnd.dart + rdz: + - application/vnd.data-vision.rdz + uvf: + - application/vnd.dece.data + uvvf: + - application/vnd.dece.data + uvd: + - application/vnd.dece.data + uvvd: + - application/vnd.dece.data + uvt: + - application/vnd.dece.ttml+xml + uvvt: + - application/vnd.dece.ttml+xml + uvx: + - application/vnd.dece.unspecified + uvvx: + - application/vnd.dece.unspecified + uvz: + - application/vnd.dece.zip + uvvz: + - application/vnd.dece.zip + fe_launch: + - application/vnd.denovo.fcselayout-link + dna: + - application/vnd.dna + mlp: + - application/vnd.dolby.mlp + dpg: + - application/vnd.dpgraph + dfac: + - application/vnd.dreamfactory + kpxx: + - application/vnd.ds-keypoint + ait: + - application/vnd.dvb.ait + svc: + - application/vnd.dvb.service + geo: + - application/vnd.dynageo + mag: + - application/vnd.ecowin.chart + nml: + - application/vnd.enliven + esf: + - application/vnd.epson.esf + msf: + - application/vnd.epson.msf + qam: + - application/vnd.epson.quickanime + slt: + - application/vnd.epson.salt + ssf: + - application/vnd.epson.ssf + es3: + - application/vnd.eszigno3+xml + et3: + - application/vnd.eszigno3+xml + ez2: + - application/vnd.ezpix-album + ez3: + - application/vnd.ezpix-package + fdf: + - application/vnd.fdf + mseed: + - application/vnd.fdsn.mseed + seed: + - application/vnd.fdsn.seed + dataless: + - application/vnd.fdsn.seed + gph: + - application/vnd.flographit + ftc: + - application/vnd.fluxtime.clip + fm: + - application/vnd.framemaker + frame: + - application/vnd.framemaker + maker: + - application/vnd.framemaker + book: + - application/vnd.framemaker + fnc: + - application/vnd.frogans.fnc + ltf: + - application/vnd.frogans.ltf + fsc: + - application/vnd.fsc.weblaunch + oas: + - application/vnd.fujitsu.oasys + oa2: + - application/vnd.fujitsu.oasys2 + oa3: + - application/vnd.fujitsu.oasys3 + fg5: + - application/vnd.fujitsu.oasysgp + bh2: + - application/vnd.fujitsu.oasysprs + ddd: + - application/vnd.fujixerox.ddd + xdw: + - application/vnd.fujixerox.docuworks + xbd: + - application/vnd.fujixerox.docuworks.binder + fzs: + - application/vnd.fuzzysheet + txd: + - application/vnd.genomatix.tuxedo + ggb: + - application/vnd.geogebra.file + ggt: + - application/vnd.geogebra.tool + gex: + - application/vnd.geometry-explorer + gre: + - application/vnd.geometry-explorer + gxt: + - application/vnd.geonext + g2w: + - application/vnd.geoplan + g3w: + - application/vnd.geospace + gmx: + - application/vnd.gmx + kml: + - application/vnd.google-earth.kml+xml + kmz: + - application/vnd.google-earth.kmz + gqf: + - application/vnd.grafeq + gqs: + - application/vnd.grafeq + gac: + - application/vnd.groove-account + ghf: + - application/vnd.groove-help + gim: + - application/vnd.groove-identity-message + grv: + - application/vnd.groove-injector + gtm: + - application/vnd.groove-tool-message + tpl: + - application/vnd.groove-tool-template + vcg: + - application/vnd.groove-vcard + hal: + - application/vnd.hal+xml + zmm: + - application/vnd.handheld-entertainment+xml + hbci: + - application/vnd.hbci + les: + - application/vnd.hhe.lesson-player + hpgl: + - application/vnd.hp-hpgl + hpid: + - application/vnd.hp-hpid + hps: + - application/vnd.hp-hps + jlt: + - application/vnd.hp-jlyt + pcl: + - application/vnd.hp-pcl + pclxl: + - application/vnd.hp-pclxl + sfd-hdstx: + - application/vnd.hydrostatix.sof-data + mpy: + - application/vnd.ibm.minipay + afp: + - application/vnd.ibm.modcap + listafp: + - application/vnd.ibm.modcap + list3820: + - application/vnd.ibm.modcap + irm: + - application/vnd.ibm.rights-management + sc: + - application/vnd.ibm.secure-container + icc: + - application/vnd.iccprofile + icm: + - application/vnd.iccprofile + igl: + - application/vnd.igloader + ivp: + - application/vnd.immervision-ivp + ivu: + - application/vnd.immervision-ivu + igm: + - application/vnd.insors.igm + xpw: + - application/vnd.intercon.formnet + xpx: + - application/vnd.intercon.formnet + i2g: + - application/vnd.intergeo + qbo: + - application/vnd.intu.qbo + qfx: + - application/vnd.intu.qfx + rcprofile: + - application/vnd.ipunplugged.rcprofile + irp: + - application/vnd.irepository.package+xml + xpr: + - application/vnd.is-xpr + fcs: + - application/vnd.isac.fcs + jam: + - application/vnd.jam + rms: + - application/vnd.jcp.javame.midlet-rms + jisp: + - application/vnd.jisp + joda: + - application/vnd.joost.joda-archive + ktz: + - application/vnd.kahootz + ktr: + - application/vnd.kahootz + karbon: + - application/vnd.kde.karbon + chrt: + - application/vnd.kde.kchart + kfo: + - application/vnd.kde.kformula + flw: + - application/vnd.kde.kivio + kon: + - application/vnd.kde.kontour + kpr: + - application/vnd.kde.kpresenter + kpt: + - application/vnd.kde.kpresenter + ksp: + - application/vnd.kde.kspread + kwd: + - application/vnd.kde.kword + kwt: + - application/vnd.kde.kword + htke: + - application/vnd.kenameaapp + kia: + - application/vnd.kidspiration + kne: + - application/vnd.kinar + knp: + - application/vnd.kinar + skp: + - application/vnd.koan + skd: + - application/vnd.koan + skt: + - application/vnd.koan + skm: + - application/vnd.koan + sse: + - application/vnd.kodak-descriptor + lasxml: + - application/vnd.las.las+xml + lbd: + - application/vnd.llamagraphics.life-balance.desktop + lbe: + - application/vnd.llamagraphics.life-balance.exchange+xml + apr: + - application/vnd.lotus-approach + pre: + - application/vnd.lotus-freelance + nsf: + - application/vnd.lotus-notes + org: + - application/vnd.lotus-organizer + scm: + - application/vnd.lotus-screencam + lwp: + - application/vnd.lotus-wordpro + portpkg: + - application/vnd.macports.portpkg + mcd: + - application/vnd.mcd + mc1: + - application/vnd.medcalcdata + cdkey: + - application/vnd.mediastation.cdkey + mwf: + - application/vnd.mfer + mfm: + - application/vnd.mfmp + flo: + - application/vnd.micrografx.flo + igx: + - application/vnd.micrografx.igx + mif: + - application/vnd.mif + daf: + - application/vnd.mobius.daf + dis: + - application/vnd.mobius.dis + mbk: + - application/vnd.mobius.mbk + mqy: + - application/vnd.mobius.mqy + msl: + - application/vnd.mobius.msl + plc: + - application/vnd.mobius.plc + txf: + - application/vnd.mobius.txf + mpn: + - application/vnd.mophun.application + mpc: + - application/vnd.mophun.certificate + xul: + - application/vnd.mozilla.xul+xml + cil: + - application/vnd.ms-artgalry + cab: + - application/vnd.ms-cab-compressed + xls: + - application/vnd.ms-excel + xlm: + - application/vnd.ms-excel + xla: + - application/vnd.ms-excel + xlc: + - application/vnd.ms-excel + xlt: + - application/vnd.ms-excel + xlw: + - application/vnd.ms-excel + xlam: + - application/vnd.ms-excel.addin.macroenabled.12 + xlsb: + - application/vnd.ms-excel.sheet.binary.macroenabled.12 + xlsm: + - application/vnd.ms-excel.sheet.macroenabled.12 + xltm: + - application/vnd.ms-excel.template.macroenabled.12 + eot: + - application/vnd.ms-fontobject + chm: + - application/vnd.ms-htmlhelp + ims: + - application/vnd.ms-ims + lrm: + - application/vnd.ms-lrm + thmx: + - application/vnd.ms-officetheme + cat: + - application/vnd.ms-pki.seccat + stl: + - application/vnd.ms-pki.stl + ppt: + - application/vnd.ms-powerpoint + pps: + - application/vnd.ms-powerpoint + pot: + - application/vnd.ms-powerpoint + ppam: + - application/vnd.ms-powerpoint.addin.macroenabled.12 + pptm: + - application/vnd.ms-powerpoint.presentation.macroenabled.12 + sldm: + - application/vnd.ms-powerpoint.slide.macroenabled.12 + ppsm: + - application/vnd.ms-powerpoint.slideshow.macroenabled.12 + potm: + - application/vnd.ms-powerpoint.template.macroenabled.12 + mpp: + - application/vnd.ms-project + mpt: + - application/vnd.ms-project + docm: + - application/vnd.ms-word.document.macroenabled.12 + dotm: + - application/vnd.ms-word.template.macroenabled.12 + wps: + - application/vnd.ms-works + wks: + - application/vnd.ms-works + wcm: + - application/vnd.ms-works + wdb: + - application/vnd.ms-works + wpl: + - application/vnd.ms-wpl + xps: + - application/vnd.ms-xpsdocument + mseq: + - application/vnd.mseq + mus: + - application/vnd.musician + msty: + - application/vnd.muvee.style + taglet: + - application/vnd.mynfc + nlu: + - application/vnd.neurolanguage.nlu + ntf: + - application/vnd.nitf + nitf: + - application/vnd.nitf + nnd: + - application/vnd.noblenet-directory + nns: + - application/vnd.noblenet-sealer + nnw: + - application/vnd.noblenet-web + ngdat: + - application/vnd.nokia.n-gage.data + n-gage: + - application/vnd.nokia.n-gage.symbian.install + rpst: + - application/vnd.nokia.radio-preset + rpss: + - application/vnd.nokia.radio-presets + edm: + - application/vnd.novadigm.edm + edx: + - application/vnd.novadigm.edx + ext: + - application/vnd.novadigm.ext + odc: + - application/vnd.oasis.opendocument.chart + otc: + - application/vnd.oasis.opendocument.chart-template + odb: + - application/vnd.oasis.opendocument.database + odf: + - application/vnd.oasis.opendocument.formula + odft: + - application/vnd.oasis.opendocument.formula-template + odg: + - application/vnd.oasis.opendocument.graphics + otg: + - application/vnd.oasis.opendocument.graphics-template + odi: + - application/vnd.oasis.opendocument.image + oti: + - application/vnd.oasis.opendocument.image-template + odp: + - application/vnd.oasis.opendocument.presentation + otp: + - application/vnd.oasis.opendocument.presentation-template + ods: + - application/vnd.oasis.opendocument.spreadsheet + ots: + - application/vnd.oasis.opendocument.spreadsheet-template + odt: + - application/vnd.oasis.opendocument.text + odm: + - application/vnd.oasis.opendocument.text-master + ott: + - application/vnd.oasis.opendocument.text-template + oth: + - application/vnd.oasis.opendocument.text-web + xo: + - application/vnd.olpc-sugar + dd2: + - application/vnd.oma.dd2+xml + oxt: + - application/vnd.openofficeorg.extension + pptx: + - application/vnd.openxmlformats-officedocument.presentationml.presentation + sldx: + - application/vnd.openxmlformats-officedocument.presentationml.slide + ppsx: + - application/vnd.openxmlformats-officedocument.presentationml.slideshow + potx: + - application/vnd.openxmlformats-officedocument.presentationml.template + xlsx: + - application/vnd.openxmlformats-officedocument.spreadsheetml.sheet + xltx: + - application/vnd.openxmlformats-officedocument.spreadsheetml.template + docx: + - application/vnd.openxmlformats-officedocument.wordprocessingml.document + dotx: + - application/vnd.openxmlformats-officedocument.wordprocessingml.template + mgp: + - application/vnd.osgeo.mapguide.package + dp: + - application/vnd.osgi.dp + esa: + - application/vnd.osgi.subsystem + pdb: + - application/vnd.palm + pqa: + - application/vnd.palm + oprc: + - application/vnd.palm + paw: + - application/vnd.pawaafile + str: + - application/vnd.pg.format + ei6: + - application/vnd.pg.osasli + efif: + - application/vnd.picsel + wg: + - application/vnd.pmi.widget + plf: + - application/vnd.pocketlearn + pbd: + - application/vnd.powerbuilder6 + box: + - application/vnd.previewsystems.box + mgz: + - application/vnd.proteus.magazine + qps: + - application/vnd.publishare-delta-tree + ptid: + - application/vnd.pvi.ptid1 + qxd: + - application/vnd.quark.quarkxpress + qxt: + - application/vnd.quark.quarkxpress + qwd: + - application/vnd.quark.quarkxpress + qwt: + - application/vnd.quark.quarkxpress + qxl: + - application/vnd.quark.quarkxpress + qxb: + - application/vnd.quark.quarkxpress + bed: + - application/vnd.realvnc.bed + mxl: + - application/vnd.recordare.musicxml + musicxml: + - application/vnd.recordare.musicxml+xml + cryptonote: + - application/vnd.rig.cryptonote + cod: + - application/vnd.rim.cod + rm: + - application/vnd.rn-realmedia + rmvb: + - application/vnd.rn-realmedia-vbr + link66: + - application/vnd.route66.link66+xml + st: + - application/vnd.sailingtracker.track + see: + - application/vnd.seemail + sema: + - application/vnd.sema + semd: + - application/vnd.semd + semf: + - application/vnd.semf + ifm: + - application/vnd.shana.informed.formdata + itp: + - application/vnd.shana.informed.formtemplate + iif: + - application/vnd.shana.informed.interchange + ipk: + - application/vnd.shana.informed.package + twd: + - application/vnd.simtech-mindmapper + twds: + - application/vnd.simtech-mindmapper + mmf: + - application/vnd.smaf + teacher: + - application/vnd.smart.teacher + sdkm: + - application/vnd.solent.sdkm+xml + sdkd: + - application/vnd.solent.sdkm+xml + dxp: + - application/vnd.spotfire.dxp + sfs: + - application/vnd.spotfire.sfs + sdc: + - application/vnd.stardivision.calc + sda: + - application/vnd.stardivision.draw + sdd: + - application/vnd.stardivision.impress + smf: + - application/vnd.stardivision.math + sdw: + - application/vnd.stardivision.writer + vor: + - application/vnd.stardivision.writer + sgl: + - application/vnd.stardivision.writer-global + smzip: + - application/vnd.stepmania.package + sm: + - application/vnd.stepmania.stepchart + sxc: + - application/vnd.sun.xml.calc + stc: + - application/vnd.sun.xml.calc.template + sxd: + - application/vnd.sun.xml.draw + std: + - application/vnd.sun.xml.draw.template + sxi: + - application/vnd.sun.xml.impress + sti: + - application/vnd.sun.xml.impress.template + sxm: + - application/vnd.sun.xml.math + sxw: + - application/vnd.sun.xml.writer + sxg: + - application/vnd.sun.xml.writer.global + stw: + - application/vnd.sun.xml.writer.template + sus: + - application/vnd.sus-calendar + susp: + - application/vnd.sus-calendar + svd: + - application/vnd.svd + sis: + - application/vnd.symbian.install + sisx: + - application/vnd.symbian.install + xsm: + - application/vnd.syncml+xml + bdm: + - application/vnd.syncml.dm+wbxml + xdm: + - application/vnd.syncml.dm+xml + tao: + - application/vnd.tao.intent-module-archive + pcap: + - application/vnd.tcpdump.pcap + cap: + - application/vnd.tcpdump.pcap + dmp: + - application/vnd.tcpdump.pcap + tmo: + - application/vnd.tmobile-livetv + tpt: + - application/vnd.trid.tpt + mxs: + - application/vnd.triscape.mxs + tra: + - application/vnd.trueapp + ufd: + - application/vnd.ufdl + ufdl: + - application/vnd.ufdl + utz: + - application/vnd.uiq.theme + umj: + - application/vnd.umajin + unityweb: + - application/vnd.unity + uoml: + - application/vnd.uoml+xml + vcx: + - application/vnd.vcx + vsd: + - application/vnd.visio + vst: + - application/vnd.visio + vss: + - application/vnd.visio + vsw: + - application/vnd.visio + vis: + - application/vnd.visionary + vsf: + - application/vnd.vsf + wbxml: + - application/vnd.wap.wbxml + wmlc: + - application/vnd.wap.wmlc + wmlsc: + - application/vnd.wap.wmlscriptc + wtb: + - application/vnd.webturbo + nbp: + - application/vnd.wolfram.player + wpd: + - application/vnd.wordperfect + wqd: + - application/vnd.wqd + stf: + - application/vnd.wt.stf + xar: + - application/vnd.xara + xfdl: + - application/vnd.xfdl + hvd: + - application/vnd.yamaha.hv-dic + hvs: + - application/vnd.yamaha.hv-script + hvp: + - application/vnd.yamaha.hv-voice + osf: + - application/vnd.yamaha.openscoreformat + osfpvg: + - application/vnd.yamaha.openscoreformat.osfpvg+xml + saf: + - application/vnd.yamaha.smaf-audio + spf: + - application/vnd.yamaha.smaf-phrase + cmp: + - application/vnd.yellowriver-custom-menu + zir: + - application/vnd.zul + zirz: + - application/vnd.zul + zaz: + - application/vnd.zzazz.deck+xml + vxml: + - application/voicexml+xml + wgt: + - application/widget + hlp: + - application/winhlp + wsdl: + - application/wsdl+xml + wspolicy: + - application/wspolicy+xml + 7z: + - application/x-7z-compressed + abw: + - application/x-abiword + ace: + - application/x-ace-compressed + dmg: + - application/x-apple-diskimage + aab: + - application/x-authorware-bin + x32: + - application/x-authorware-bin + u32: + - application/x-authorware-bin + vox: + - application/x-authorware-bin + aam: + - application/x-authorware-map + aas: + - application/x-authorware-seg + bcpio: + - application/x-bcpio + torrent: + - application/x-bittorrent + blb: + - application/x-blorb + blorb: + - application/x-blorb + bz: + - application/x-bzip + bz2: + - application/x-bzip2 + boz: + - application/x-bzip2 + cbr: + - application/x-cbr + cba: + - application/x-cbr + cbt: + - application/x-cbr + cbz: + - application/x-cbr + cb7: + - application/x-cbr + vcd: + - application/x-cdlink + cfs: + - application/x-cfs-compressed + chat: + - application/x-chat + pgn: + - application/x-chess-pgn + nsc: + - application/x-conference + cpio: + - application/x-cpio + csh: + - application/x-csh + deb: + - application/x-debian-package + udeb: + - application/x-debian-package + dgc: + - application/x-dgc-compressed + dir: + - application/x-director + dcr: + - application/x-director + dxr: + - application/x-director + cst: + - application/x-director + cct: + - application/x-director + cxt: + - application/x-director + w3d: + - application/x-director + fgd: + - application/x-director + swa: + - application/x-director + wad: + - application/x-doom + ncx: + - application/x-dtbncx+xml + dtb: + - application/x-dtbook+xml + res: + - application/x-dtbresource+xml + dvi: + - application/x-dvi + evy: + - application/x-envoy + eva: + - application/x-eva + bdf: + - application/x-font-bdf + gsf: + - application/x-font-ghostscript + psf: + - application/x-font-linux-psf + pcf: + - application/x-font-pcf + snf: + - application/x-font-snf + pfa: + - application/x-font-type1 + pfb: + - application/x-font-type1 + pfm: + - application/x-font-type1 + afm: + - application/x-font-type1 + arc: + - application/x-freearc + spl: + - application/x-futuresplash + gca: + - application/x-gca-compressed + ulx: + - application/x-glulx + gnumeric: + - application/x-gnumeric + gramps: + - application/x-gramps-xml + gtar: + - application/x-gtar + hdf: + - application/x-hdf + install: + - application/x-install-instructions + iso: + - application/x-iso9660-image + jnlp: + - application/x-java-jnlp-file + latex: + - application/x-latex + lzh: + - application/x-lzh-compressed + lha: + - application/x-lzh-compressed + mie: + - application/x-mie + prc: + - application/x-mobipocket-ebook + mobi: + - application/x-mobipocket-ebook + application: + - application/x-ms-application + lnk: + - application/x-ms-shortcut + wmd: + - application/x-ms-wmd + wmz: + - application/x-ms-wmz + - application/x-msmetafile + xbap: + - application/x-ms-xbap + mdb: + - application/x-msaccess + obd: + - application/x-msbinder + crd: + - application/x-mscardfile + clp: + - application/x-msclip + exe: + - application/x-msdownload + dll: + - application/x-msdownload + com: + - application/x-msdownload + bat: + - application/x-msdownload + msi: + - application/x-msdownload + mvb: + - application/x-msmediaview + m13: + - application/x-msmediaview + m14: + - application/x-msmediaview + wmf: + - application/x-msmetafile + emf: + - application/x-msmetafile + emz: + - application/x-msmetafile + mny: + - application/x-msmoney + pub: + - application/x-mspublisher + scd: + - application/x-msschedule + trm: + - application/x-msterminal + wri: + - application/x-mswrite + nc: + - application/x-netcdf + cdf: + - application/x-netcdf + nzb: + - application/x-nzb + p12: + - application/x-pkcs12 + pfx: + - application/x-pkcs12 + p7b: + - application/x-pkcs7-certificates + spc: + - application/x-pkcs7-certificates + p7r: + - application/x-pkcs7-certreqresp + rar: + - application/x-rar-compressed + ris: + - application/x-research-info-systems + sh: + - application/x-sh + shar: + - application/x-shar + swf: + - application/x-shockwave-flash + xap: + - application/x-silverlight-app + sql: + - application/x-sql + sit: + - application/x-stuffit + sitx: + - application/x-stuffitx + srt: + - application/x-subrip + sv4cpio: + - application/x-sv4cpio + sv4crc: + - application/x-sv4crc + t3: + - application/x-t3vm-image + gam: + - application/x-tads + tar: + - application/x-tar + tcl: + - application/x-tcl + tex: + - application/x-tex + tfm: + - application/x-tex-tfm + texinfo: + - application/x-texinfo + texi: + - application/x-texinfo + obj: + - application/x-tgif + ustar: + - application/x-ustar + src: + - application/x-wais-source + der: + - application/x-x509-ca-cert + crt: + - application/x-x509-ca-cert + fig: + - application/x-xfig + xlf: + - application/x-xliff+xml + xpi: + - application/x-xpinstall + xz: + - application/x-xz + z1: + - application/x-zmachine + z2: + - application/x-zmachine + z3: + - application/x-zmachine + z4: + - application/x-zmachine + z5: + - application/x-zmachine + z6: + - application/x-zmachine + z7: + - application/x-zmachine + z8: + - application/x-zmachine + xaml: + - application/xaml+xml + xdf: + - application/xcap-diff+xml + xenc: + - application/xenc+xml + xhtml: + - application/xhtml+xml + xht: + - application/xhtml+xml + xml: + - application/xml + xsl: + - application/xml + dtd: + - application/xml-dtd + xop: + - application/xop+xml + xpl: + - application/xproc+xml + xslt: + - application/xslt+xml + xspf: + - application/xspf+xml + mxml: + - application/xv+xml + xhvml: + - application/xv+xml + xvml: + - application/xv+xml + xvm: + - application/xv+xml + yang: + - application/yang + yin: + - application/yin+xml + adp: + - audio/adpcm + au: + - audio/basic + snd: + - audio/basic + mid: + - audio/midi + midi: + - audio/midi + kar: + - audio/midi + rmi: + - audio/midi + m4a: + - audio/mp4 + mp4a: + - audio/mp4 + oga: + - audio/ogg + ogg: + - audio/ogg + spx: + - audio/ogg + s3m: + - audio/s3m + sil: + - audio/silk + uva: + - audio/vnd.dece.audio + uvva: + - audio/vnd.dece.audio + eol: + - audio/vnd.digital-winds + dra: + - audio/vnd.dra + dts: + - audio/vnd.dts + dtshd: + - audio/vnd.dts.hd + lvp: + - audio/vnd.lucent.voice + pya: + - audio/vnd.ms-playready.media.pya + ecelp4800: + - audio/vnd.nuera.ecelp4800 + ecelp7470: + - audio/vnd.nuera.ecelp7470 + ecelp9600: + - audio/vnd.nuera.ecelp9600 + rip: + - audio/vnd.rip + weba: + - audio/webm + aac: + - audio/x-aac + aif: + - audio/x-aiff + aiff: + - audio/x-aiff + aifc: + - audio/x-aiff + caf: + - audio/x-caf + flac: + - audio/x-flac + mka: + - audio/x-matroska + m3u: + - audio/x-mpegurl + wax: + - audio/x-ms-wax + wma: + - audio/x-ms-wma + ram: + - audio/x-pn-realaudio + ra: + - audio/x-pn-realaudio + rmp: + - audio/x-pn-realaudio-plugin + wav: + - audio/x-wav + xm: + - audio/xm + cdx: + - chemical/x-cdx + cif: + - chemical/x-cif + cmdf: + - chemical/x-cmdf + cml: + - chemical/x-cml + csml: + - chemical/x-csml + xyz: + - chemical/x-xyz + woff: + - font/woff + woff2: + - font/woff2 + cgm: + - image/cgm + g3: + - image/g3fax + gif: + - image/gif + ief: + - image/ief + ktx: + - image/ktx + png: + - image/png + btif: + - image/prs.btif + sgi: + - image/sgi + svg: + - image/svg+xml + svgz: + - image/svg+xml + tiff: + - image/tiff + tif: + - image/tiff + psd: + - image/vnd.adobe.photoshop + uvi: + - image/vnd.dece.graphic + uvvi: + - image/vnd.dece.graphic + uvg: + - image/vnd.dece.graphic + uvvg: + - image/vnd.dece.graphic + djvu: + - image/vnd.djvu + djv: + - image/vnd.djvu + sub: + - image/vnd.dvb.subtitle + - text/vnd.dvb.subtitle + dwg: + - image/vnd.dwg + dxf: + - image/vnd.dxf + fbs: + - image/vnd.fastbidsheet + fpx: + - image/vnd.fpx + fst: + - image/vnd.fst + mmr: + - image/vnd.fujixerox.edmics-mmr + rlc: + - image/vnd.fujixerox.edmics-rlc + mdi: + - image/vnd.ms-modi + wdp: + - image/vnd.ms-photo + npx: + - image/vnd.net-fpx + wbmp: + - image/vnd.wap.wbmp + xif: + - image/vnd.xiff + webp: + - image/webp + 3ds: + - image/x-3ds + ras: + - image/x-cmu-raster + cmx: + - image/x-cmx + fh: + - image/x-freehand + fhc: + - image/x-freehand + fh4: + - image/x-freehand + fh5: + - image/x-freehand + fh7: + - image/x-freehand + ico: + - image/x-icon + sid: + - image/x-mrsid-image + pcx: + - image/x-pcx + pic: + - image/x-pict + pct: + - image/x-pict + pnm: + - image/x-portable-anymap + pbm: + - image/x-portable-bitmap + pgm: + - image/x-portable-graymap + ppm: + - image/x-portable-pixmap + rgb: + - image/x-rgb + tga: + - image/x-tga + xbm: + - image/x-xbitmap + xpm: + - image/x-xpixmap + xwd: + - image/x-xwindowdump + eml: + - message/rfc822 + mime: + - message/rfc822 + igs: + - model/iges + iges: + - model/iges + msh: + - model/mesh + mesh: + - model/mesh + silo: + - model/mesh + dae: + - model/vnd.collada+xml + dwf: + - model/vnd.dwf + gdl: + - model/vnd.gdl + gtw: + - model/vnd.gtw + mts: + - model/vnd.mts + vtu: + - model/vnd.vtu + wrl: + - model/vrml + vrml: + - model/vrml + x3db: + - model/x3d+binary + x3dbz: + - model/x3d+binary + x3dv: + - model/x3d+vrml + x3dvz: + - model/x3d+vrml + x3d: + - model/x3d+xml + x3dz: + - model/x3d+xml + appcache: + - text/cache-manifest + ics: + - text/calendar + ifb: + - text/calendar + css: + - text/css + csv: + - text/csv + html: + - text/html + htm: + - text/html + n3: + - text/n3 + txt: + - text/plain + text: + - text/plain + conf: + - text/plain + def: + - text/plain + list: + - text/plain + log: + - text/plain + in: + - text/plain + dsc: + - text/prs.lines.tag + rtx: + - text/richtext + sgml: + - text/sgml + sgm: + - text/sgml + tsv: + - text/tab-separated-values + t: + - text/troff + tr: + - text/troff + roff: + - text/troff + man: + - text/troff + me: + - text/troff + ms: + - text/troff + ttl: + - text/turtle + uri: + - text/uri-list + uris: + - text/uri-list + urls: + - text/uri-list + vcard: + - text/vcard + curl: + - text/vnd.curl + dcurl: + - text/vnd.curl.dcurl + mcurl: + - text/vnd.curl.mcurl + scurl: + - text/vnd.curl.scurl + fly: + - text/vnd.fly + flx: + - text/vnd.fmi.flexstor + gv: + - text/vnd.graphviz + 3dml: + - text/vnd.in3d.3dml + spot: + - text/vnd.in3d.spot + jad: + - text/vnd.sun.j2me.app-descriptor + wml: + - text/vnd.wap.wml + wmls: + - text/vnd.wap.wmlscript + s: + - text/x-asm + asm: + - text/x-asm + c: + - text/x-c + cc: + - text/x-c + cxx: + - text/x-c + cpp: + - text/x-c + h: + - text/x-c + hh: + - text/x-c + dic: + - text/x-c + f: + - text/x-fortran + for: + - text/x-fortran + f77: + - text/x-fortran + f90: + - text/x-fortran + java: + - text/x-java-source + nfo: + - text/x-nfo + opml: + - text/x-opml + p: + - text/x-pascal + pas: + - text/x-pascal + etx: + - text/x-setext + sfv: + - text/x-sfv + uu: + - text/x-uuencode + vcs: + - text/x-vcalendar + vcf: + - text/x-vcard + 3gp: + - video/3gpp + 3g2: + - video/3gpp2 + h261: + - video/h261 + h263: + - video/h263 + h264: + - video/h264 + jpgv: + - video/jpeg + jpm: + - video/jpm + jpgm: + - video/jpm + mj2: + - video/mj2 + mjp2: + - video/mj2 + mp4: + - video/mp4 + mp4v: + - video/mp4 + mpg4: + - video/mp4 + mpeg: + - video/mpeg + mpg: + - video/mpeg + mpe: + - video/mpeg + m1v: + - video/mpeg + m2v: + - video/mpeg + ogv: + - video/ogg + qt: + - video/quicktime + mov: + - video/quicktime + uvh: + - video/vnd.dece.hd + uvvh: + - video/vnd.dece.hd + uvm: + - video/vnd.dece.mobile + uvvm: + - video/vnd.dece.mobile + uvp: + - video/vnd.dece.pd + uvvp: + - video/vnd.dece.pd + uvs: + - video/vnd.dece.sd + uvvs: + - video/vnd.dece.sd + uvv: + - video/vnd.dece.video + uvvv: + - video/vnd.dece.video + dvb: + - video/vnd.dvb.file + fvt: + - video/vnd.fvt + mxu: + - video/vnd.mpegurl + m4u: + - video/vnd.mpegurl + pyv: + - video/vnd.ms-playready.media.pyv + uvu: + - video/vnd.uvvu.mp4 + uvvu: + - video/vnd.uvvu.mp4 + viv: + - video/vnd.vivo + webm: + - video/webm + f4v: + - video/x-f4v + fli: + - video/x-fli + flv: + - video/x-flv + m4v: + - video/x-m4v + mkv: + - video/x-matroska + mk3d: + - video/x-matroska + mks: + - video/x-matroska + mng: + - video/x-mng + asf: + - video/x-ms-asf + asx: + - video/x-ms-asf + vob: + - video/x-ms-vob + wm: + - video/x-ms-wm + wmv: + - video/x-ms-wmv + wmx: + - video/x-ms-wmx + wvx: + - video/x-ms-wvx + avi: + - video/x-msvideo + movie: + - video/x-sgi-movie + smv: + - video/x-smv + ice: + - x-conference/x-cooltalk diff --git a/system/config/system.yaml b/system/config/system.yaml index 8c14e5d..fb5f391 100644 --- a/system/config/system.yaml +++ b/system/config/system.yaml @@ -96,7 +96,7 @@ cache: purge_at: '0 4 * * *' # How often to purge old file cache (using new scheduler) clear_at: '0 3 * * *' # How often to clear cache (using new scheduler) clear_job_type: 'standard' # Type to clear when processing the scheduled clear job `standard`|`all` - clear_images_by_default: false # By default grav will include processed images in cache clear, this can be disabled + clear_images_by_default: false # By default grav does not include processed images in cache clear, this can be enabled cli_compatibility: false # Ensures only non-volatile drivers are used (file, redis, memcache, etc.) lifetime: 604800 # Lifetime of cached data in seconds (0 = infinite) gzip: false # GZip compress the page output @@ -131,7 +131,7 @@ assets: # Configuration for Assets Mana enable_asset_timestamp: false # Enable asset timestamps enable_asset_sri: false # Enable asset SRI collections: - jquery: system://assets/jquery/jquery-2.x.min.js + jquery: system://assets/jquery/jquery-3.x.min.js errors: display: 0 # Display either (1) Full backtrace | (0) Simple Error | (-1) System Error diff --git a/system/defines.php b/system/defines.php index f6b0958..9ab384f 100644 --- a/system/defines.php +++ b/system/defines.php @@ -9,7 +9,7 @@ // Some standard defines define('GRAV', true); -define('GRAV_VERSION', '1.7.16'); +define('GRAV_VERSION', '1.7.21'); define('GRAV_SCHEMA', '1.7.0_2020-11-20_1'); define('GRAV_TESTING', false); diff --git a/system/src/Grav/Common/Assets.php b/system/src/Grav/Common/Assets.php index 51a2531..a9b930b 100644 --- a/system/src/Grav/Common/Assets.php +++ b/system/src/Grav/Common/Assets.php @@ -110,7 +110,7 @@ class Assets extends PropertyObject /** @var UniformResourceLocator $locator */ $locator = $grav['locator']; - $this->assets_dir = $locator->findResource('asset://') . DS; + $this->assets_dir = $locator->findResource('asset://'); $this->assets_url = $locator->findResource('asset://', false); $this->config($asset_config); @@ -164,10 +164,19 @@ class Assets extends PropertyObject // More than one asset if (is_array($asset)) { - foreach ($asset as $a) { - array_shift($args); - $args = array_merge([$a], $args); - call_user_func_array([$this, 'add'], $args); + foreach ($asset as $index => $location) { + $params = array_slice($args, 1); + if (is_array($location)) { + $params = array_shift($params); + if (is_numeric($params)) { + $params = [ 'priority' => $params ]; + } + $params = [array_replace_recursive([], $location, $params)]; + $location = $index; + } + + $params = array_merge([$location], $params); + call_user_func_array([$this, 'add'], $params); } } elseif (isset($this->collections[$asset])) { array_shift($args); @@ -201,8 +210,13 @@ class Assets extends PropertyObject protected function addType($collection, $type, $asset, $options) { if (is_array($asset)) { - foreach ($asset as $a) { - $this->addType($collection, $type, $a, $options); + foreach ($asset as $index => $location) { + $assetOptions = $options; + if (is_array($location)) { + $assetOptions = array_replace_recursive([], $options, $location); + $location = $index; + } + $this->addType($collection, $type, $location, $assetOptions); } return $this; diff --git a/system/src/Grav/Common/Assets/Pipeline.php b/system/src/Grav/Common/Assets/Pipeline.php index 7aef0e1..2e499f9 100644 --- a/system/src/Grav/Common/Assets/Pipeline.php +++ b/system/src/Grav/Common/Assets/Pipeline.php @@ -9,9 +9,9 @@ namespace Grav\Common\Assets; -use Grav\Common\Assets\BaseAsset; use Grav\Common\Assets\Traits\AssetUtilsTrait; use Grav\Common\Config\Config; +use Grav\Common\Filesystem\Folder; use Grav\Common\Grav; use Grav\Common\Uri; use Grav\Common\Utils; @@ -88,7 +88,14 @@ class Pipeline extends PropertyObject $uri = Grav::instance()['uri']; $this->base_url = rtrim($uri->rootUrl($config->get('system.absolute_urls')), '/') . '/'; - $this->assets_dir = $locator->findResource('asset://') . DS; + $this->assets_dir = $locator->findResource('asset://'); + if (!$this->assets_dir) { + // Attempt to create assets folder if it doesn't exist yet. + $this->assets_dir = $locator->findResource('asset://', true, true); + Folder::mkdir($this->assets_dir); + $locator->clearCache(); + } + $this->assets_url = $locator->findResource('asset://', false); } @@ -119,10 +126,9 @@ class Pipeline extends PropertyObject $file = $uid . '.css'; $relative_path = "{$this->base_url}{$this->assets_url}/{$file}"; - $buffer = null; - - if (file_exists($this->assets_dir . $file)) { - $buffer = file_get_contents($this->assets_dir . $file) . "\n"; + $filepath = "{$this->assets_dir}/{$file}"; + if (file_exists($filepath)) { + $buffer = file_get_contents($filepath) . "\n"; } else { //if nothing found get out of here! if (empty($assets)) { @@ -141,7 +147,7 @@ class Pipeline extends PropertyObject // Write file if (trim($buffer) !== '') { - file_put_contents($this->assets_dir . $file, $buffer); + file_put_contents($filepath, $buffer); } } @@ -182,10 +188,9 @@ class Pipeline extends PropertyObject $file = $uid . '.js'; $relative_path = "{$this->base_url}{$this->assets_url}/{$file}"; - $buffer = null; - - if (file_exists($this->assets_dir . $file)) { - $buffer = file_get_contents($this->assets_dir . $file) . "\n"; + $filepath = "{$this->assets_dir}/{$file}"; + if (file_exists($filepath)) { + $buffer = file_get_contents($filepath) . "\n"; } else { //if nothing found get out of here! if (empty($assets)) { @@ -204,7 +209,7 @@ class Pipeline extends PropertyObject // Write file if (trim($buffer) !== '') { - file_put_contents($this->assets_dir . $file, $buffer); + file_put_contents($filepath, $buffer); } } diff --git a/system/src/Grav/Common/Assets/Traits/AssetUtilsTrait.php b/system/src/Grav/Common/Assets/Traits/AssetUtilsTrait.php index 902a7c5..ac6e55a 100644 --- a/system/src/Grav/Common/Assets/Traits/AssetUtilsTrait.php +++ b/system/src/Grav/Common/Assets/Traits/AssetUtilsTrait.php @@ -156,6 +156,10 @@ trait AssetUtilsTrait $no_key = ['loading']; foreach ($this->attributes as $key => $value) { + if ($value === null) { + continue; + } + if (is_numeric($key)) { $key = $value; } diff --git a/system/src/Grav/Common/Config/Setup.php b/system/src/Grav/Common/Config/Setup.php index 5693a92..6ff7372 100644 --- a/system/src/Grav/Common/Config/Setup.php +++ b/system/src/Grav/Common/Config/Setup.php @@ -41,6 +41,9 @@ class Setup extends Data */ public static $environment; + /** @var string */ + public static $securityFile = 'config://security.yaml'; + /** @var array */ protected $streams = [ 'user' => [ @@ -390,12 +393,19 @@ class Setup extends Data if (!$locator->findResource('environment://config', true)) { // If environment does not have its own directory, remove it from the lookup. - $this->set('streams.schemes.environment.prefixes', ['config' => []]); + $prefixes = $this->get('streams.schemes.environment.prefixes'); + $prefixes['config'] = []; + + $this->set('streams.schemes.environment.prefixes', $prefixes); $this->initializeLocator($locator); } - // Create security.yaml if it doesn't exist. - $filename = $locator->findResource('config://security.yaml', true, true); + // Create security.yaml salt if it doesn't exist into existing configuration environment if possible. + $securityFile = basename(static::$securityFile); + $securityFolder = substr(static::$securityFile, 0, -\strlen($securityFile)); + $securityFolder = $locator->findResource($securityFolder, true) ?: $locator->findResource($securityFolder, true, true); + $filename = "{$securityFolder}/{$securityFile}"; + $security_file = CompiledYamlFile::instance($filename); $security_content = (array)$security_file->content(); diff --git a/system/src/Grav/Common/Data/Validation.php b/system/src/Grav/Common/Data/Validation.php index bb3fdd1..7ee60e4 100644 --- a/system/src/Grav/Common/Data/Validation.php +++ b/system/src/Grav/Common/Data/Validation.php @@ -519,17 +519,32 @@ class Validation return false; } - if (isset($params['min']) && $value < $params['min']) { - return false; + $value = (float)$value; + + $min = 0; + if (isset($params['min'])) { + $min = (float)$params['min']; + if ($value < $min) { + return false; + } } - if (isset($params['max']) && $value > $params['max']) { - return false; + if (isset($params['max'])) { + $max = (float)$params['max']; + if ($value > $max) { + return false; + } } - $min = $params['min'] ?? 0; + if (isset($params['step'])) { + $step = (float)$params['step']; + // Count of how many steps we are above/below the minimum value. + $pos = ($value - $min) / $step; - return !(isset($params['step']) && fmod($value - $min, $params['step']) === 0); + return is_int(static::filterNumber($pos, $params, $field)); + } + + return true; } /** diff --git a/system/src/Grav/Common/Flex/FlexObject.php b/system/src/Grav/Common/Flex/FlexObject.php index 2a43eaa..66e5412 100644 --- a/system/src/Grav/Common/Flex/FlexObject.php +++ b/system/src/Grav/Common/Flex/FlexObject.php @@ -13,6 +13,7 @@ namespace Grav\Common\Flex; use Grav\Common\Flex\Traits\FlexGravTrait; use Grav\Common\Flex\Traits\FlexObjectTrait; +use Grav\Common\Media\Interfaces\MediaInterface; use Grav\Framework\Flex\Traits\FlexMediaTrait; use function is_array; @@ -21,7 +22,7 @@ use function is_array; * * @package Grav\Common\Flex */ -abstract class FlexObject extends \Grav\Framework\Flex\FlexObject +abstract class FlexObject extends \Grav\Framework\Flex\FlexObject implements MediaInterface { use FlexGravTrait; use FlexObjectTrait; diff --git a/system/src/Grav/Common/Flex/Types/Pages/PageCollection.php b/system/src/Grav/Common/Flex/Types/Pages/PageCollection.php index 0c23134..08f192f 100644 --- a/system/src/Grav/Common/Flex/Types/Pages/PageCollection.php +++ b/system/src/Grav/Common/Flex/Types/Pages/PageCollection.php @@ -192,6 +192,14 @@ class PageCollection extends FlexPageCollection implements PageCollectionInterfa throw new RuntimeException(__METHOD__ . '(): Not Implemented'); } + /** + * Set current page. + */ + public function setCurrent(string $path): void + { + throw new RuntimeException(__METHOD__ . '(): Not Implemented'); + } + /** * Return previous item. * diff --git a/system/src/Grav/Common/Flex/Types/Pages/PageIndex.php b/system/src/Grav/Common/Flex/Types/Pages/PageIndex.php index e2938ae..dd06f58 100644 --- a/system/src/Grav/Common/Flex/Types/Pages/PageIndex.php +++ b/system/src/Grav/Common/Flex/Types/Pages/PageIndex.php @@ -674,12 +674,12 @@ class PageIndex extends FlexPageIndex implements PageCollectionInterface $count = $filters ? $tmp->filterBy($filters, true)->count() : null; $route = $child->getRoute(); $payload = [ - 'item-key' => basename($child->rawRoute() ?? $child->getKey()), + 'item-key' => htmlspecialchars(basename($child->rawRoute() ?? $child->getKey())), 'icon' => $icon, 'title' => htmlspecialchars($child->menu()), 'route' => [ - 'display' => ($route ? ($route->toString(false) ?: '/') : null) ?? '', - 'raw' => $child->rawRoute(), + 'display' => htmlspecialchars(($route ? ($route->toString(false) ?: '/') : null) ?? ''), + 'raw' => htmlspecialchars($child->rawRoute()), ], 'modified' => $this->jsDate($child->modified()), 'child_count' => $child_count ?: null, diff --git a/system/src/Grav/Common/Flex/Types/Pages/PageObject.php b/system/src/Grav/Common/Flex/Types/Pages/PageObject.php index 914eb7f..21a03d3 100644 --- a/system/src/Grav/Common/Flex/Types/Pages/PageObject.php +++ b/system/src/Grav/Common/Flex/Types/Pages/PageObject.php @@ -262,6 +262,24 @@ class PageObject extends FlexPageObject $this->getFlexDirectory()->reloadIndex(); } + /** + * @param UserInterface|null $user + */ + public function check(UserInterface $user = null): void + { + parent::check($user); + + if ($user && $this->isMoved()) { + $parentKey = $this->getProperty('parent_key'); + + /** @var PageObject|null $parent */ + $parent = $this->getFlexDirectory()->getObject($parentKey, 'storage_key'); + if (!$parent || !$parent->isAuthorized('create', null, $user)) { + throw new \RuntimeException('Forbidden', 403); + } + } + } + /** * @param array|bool $reorder * @return FlexObject|FlexObjectInterface @@ -357,6 +375,19 @@ class PageObject extends FlexPageObject return parent::isAuthorizedOverride($user, $action, $scope, $isMe); } + /** + * @return bool + */ + protected function isMoved(): bool + { + $storageKey = $this->getMasterKey(); + $filesystem = Filesystem::getInstance(false); + $oldParentKey = ltrim($filesystem->dirname("/{$storageKey}"), '/'); + $newParentKey = $this->getProperty('parent_key'); + + return $this->exists() && $oldParentKey !== $newParentKey; + } + /** * @param array $ordering * @return PageCollection|null @@ -364,10 +395,7 @@ class PageObject extends FlexPageObject protected function reorderSiblings(array $ordering) { $storageKey = $this->getMasterKey(); - $filesystem = Filesystem::getInstance(false); - $oldParentKey = ltrim($filesystem->dirname("/{$storageKey}"), '/'); - $newParentKey = $this->getProperty('parent_key'); - $isMoved = $this->exists() && $oldParentKey !== $newParentKey; + $isMoved = $this->isMoved(); $order = !$isMoved ? $this->order() : false; if ($order !== false) { $order = (int)$order; diff --git a/system/src/Grav/Common/Flex/Types/UserGroups/UserGroupObject.php b/system/src/Grav/Common/Flex/Types/UserGroups/UserGroupObject.php index fb69eab..ea68fa1 100644 --- a/system/src/Grav/Common/Flex/Types/UserGroups/UserGroupObject.php +++ b/system/src/Grav/Common/Flex/Types/UserGroups/UserGroupObject.php @@ -41,6 +41,14 @@ class UserGroupObject extends FlexObject implements UserGroupInterface ] + parent::getCachedMethods(); } + /** + * @return string + */ + public function getTitle(): string + { + return $this->getProperty('readableName'); + } + /** * Checks user authorization to the action. * diff --git a/system/src/Grav/Common/Flex/Types/Users/UserObject.php b/system/src/Grav/Common/Flex/Types/Users/UserObject.php index 62305cd..310c313 100644 --- a/system/src/Grav/Common/Flex/Types/Users/UserObject.php +++ b/system/src/Grav/Common/Flex/Types/Users/UserObject.php @@ -11,6 +11,7 @@ declare(strict_types=1); namespace Grav\Common\Flex\Types\Users; +use Closure; use Countable; use Grav\Common\Config\Config; use Grav\Common\Data\Blueprint; @@ -31,6 +32,7 @@ use Grav\Common\User\Interfaces\UserInterface; use Grav\Common\User\Traits\UserTrait; use Grav\Framework\File\Formatter\JsonFormatter; use Grav\Framework\File\Formatter\YamlFormatter; +use Grav\Framework\Filesystem\Filesystem; use Grav\Framework\Flex\Flex; use Grav\Framework\Flex\FlexDirectory; use Grav\Framework\Flex\Storage\FileStorage; @@ -75,6 +77,9 @@ class UserObject extends FlexObject implements UserInterface, Countable use UserTrait; use UserObjectLegacyTrait; + /** @var Closure|null */ + static public $authorizeCallable; + /** @var array|null */ protected $_uploads_original; /** @var FileInterface|null */ @@ -259,6 +264,15 @@ class UserObject extends FlexObject implements UserInterface, Countable } } + $authorizeCallable = static::$authorizeCallable; + if ($authorizeCallable instanceof Closure) { + $authorizeCallable->bindTo($this); + $authorized = $authorizeCallable($action, $scope); + if (is_bool($authorized)) { + return $authorized; + } + } + // Check user access. $access = $this->getAccess(); $authorized = $access->authorize($action, $scope); @@ -292,6 +306,14 @@ class UserObject extends FlexObject implements UserInterface, Countable return $value; } + /** + * @return UserGroupIndex + */ + public function getRoles(): UserGroupIndex + { + return $this->getGroups(); + } + /** * Convert object into an array. * @@ -689,6 +711,7 @@ class UserObject extends FlexObject implements UserInterface, Countable /** * @param array $files + * @return void */ protected function setUpdatedMedia(array $files): void { @@ -700,9 +723,12 @@ class UserObject extends FlexObject implements UserInterface, Countable return; } + $filesystem = Filesystem::getInstance(false); + $list = []; $list_original = []; foreach ($files as $field => $group) { + // Ignore files without a field. if ($field === '') { continue; } @@ -724,7 +750,7 @@ class UserObject extends FlexObject implements UserInterface, Countable } if ($file) { - // Check file upload against media limits. + // Check file upload against media limits (except for max size). $filename = $media->checkUploadedFile($file, $filename, ['filesize' => 0] + $settings); } @@ -748,15 +774,19 @@ class UserObject extends FlexObject implements UserInterface, Countable continue; } + // Calculate path without the retina scaling factor. + $realpath = $filesystem->pathname($filepath) . str_replace(['@3x', '@2x'], '', basename($filepath)); + $list[$filename] = [$file, $settings]; + $path = str_replace('.', "\n", $field); if (null !== $data) { $data['name'] = $filename; $data['path'] = $filepath; - $this->setNestedProperty("{$field}\n{$filepath}", $data, "\n"); + $this->setNestedProperty("{$path}\n{$realpath}", $data, "\n"); } else { - $this->unsetNestedProperty("{$field}\n{$filepath}", "\n"); + $this->unsetNestedProperty("{$path}\n{$realpath}", "\n"); } } } diff --git a/system/src/Grav/Common/GPM/GPM.php b/system/src/Grav/Common/GPM/GPM.php index 222aa0a..4505696 100644 --- a/system/src/Grav/Common/GPM/GPM.php +++ b/system/src/Grav/Common/GPM/GPM.php @@ -35,7 +35,11 @@ class GPM extends Iterator /** @var Remote\Packages|null Remote available Packages */ private $repository; /** @var Remote\GravCore|null Remove Grav Packages */ - public $grav; + private $grav; + /** @var bool */ + private $refresh; + /** @var callable|null */ + private $callback; /** @var array Internal cache */ protected $cache; @@ -55,13 +59,45 @@ class GPM extends Iterator public function __construct($refresh = false, $callback = null) { parent::__construct(); + + Folder::create(CACHE_DIR . '/gpm'); + $this->cache = []; $this->installed = new Local\Packages(); - try { - $this->repository = new Remote\Packages($refresh, $callback); - $this->grav = new Remote\GravCore($refresh, $callback); - } catch (Exception $e) { + $this->refresh = $refresh; + $this->callback = $callback; + } + + /** + * Magic getter method + * + * @param string $offset Asset name value + * @return mixed Asset value + */ + public function __get($offset) + { + switch ($offset) { + case 'grav': + return $this->getGrav(); } + + return parent::__get($offset); + } + + /** + * Magic method to determine if the attribute is set + * + * @param string $offset Asset name value + * @return bool True if the value is set + */ + public function __isset($offset) + { + switch ($offset) { + case 'grav': + return $this->getGrav() !== null; + } + + return parent::__isset($offset); } /** @@ -266,11 +302,12 @@ class GPM extends Iterator { $items = []; - if (null === $this->repository) { + $repository = $this->getRepository(); + if (null === $repository) { return $items; } - $repository = $this->repository['plugins']; + $plugins = $repository['plugins']; // local cache to speed things up if (isset($this->cache[__METHOD__])) { @@ -278,18 +315,18 @@ class GPM extends Iterator } foreach ($this->installed['plugins'] as $slug => $plugin) { - if (!isset($repository[$slug]) || $plugin->symlink || !$plugin->version || $plugin->gpm === false) { + if (!isset($plugins[$slug]) || $plugin->symlink || !$plugin->version || $plugin->gpm === false) { continue; } $local_version = $plugin->version ?? 'Unknown'; - $remote_version = $repository[$slug]->version; + $remote_version = $plugins[$slug]->version; if (version_compare($local_version, $remote_version) < 0) { - $repository[$slug]->available = $remote_version; - $repository[$slug]->version = $local_version; - $repository[$slug]->type = $repository[$slug]->release_type; - $items[$slug] = $repository[$slug]; + $plugins[$slug]->available = $remote_version; + $plugins[$slug]->version = $local_version; + $plugins[$slug]->type = $plugins[$slug]->release_type; + $items[$slug] = $plugins[$slug]; } } @@ -306,19 +343,20 @@ class GPM extends Iterator */ public function getLatestVersionOfPackage($package_name) { - if (null === $this->repository) { + $repository = $this->getRepository(); + if (null === $repository) { return null; } - $repository = $this->repository['plugins']; - if (isset($repository[$package_name])) { - return $repository[$package_name]->available ?: $repository[$package_name]->version; + $plugins = $repository['plugins']; + if (isset($plugins[$package_name])) { + return $plugins[$package_name]->available ?: $plugins[$package_name]->version; } //Not a plugin, it's a theme? - $repository = $this->repository['themes']; - if (isset($repository[$package_name])) { - return $repository[$package_name]->available ?: $repository[$package_name]->version; + $themes = $repository['themes']; + if (isset($themes[$package_name])) { + return $themes[$package_name]->available ?: $themes[$package_name]->version; } return null; @@ -356,11 +394,12 @@ class GPM extends Iterator { $items = []; - if (null === $this->repository) { + $repository = $this->getRepository(); + if (null === $repository) { return $items; } - $repository = $this->repository['themes']; + $themes = $repository['themes']; // local cache to speed things up if (isset($this->cache[__METHOD__])) { @@ -368,18 +407,18 @@ class GPM extends Iterator } foreach ($this->installed['themes'] as $slug => $plugin) { - if (!isset($repository[$slug]) || $plugin->symlink || !$plugin->version || $plugin->gpm === false) { + if (!isset($themes[$slug]) || $plugin->symlink || !$plugin->version || $plugin->gpm === false) { continue; } $local_version = $plugin->version ?? 'Unknown'; - $remote_version = $repository[$slug]->version; + $remote_version = $themes[$slug]->version; if (version_compare($local_version, $remote_version) < 0) { - $repository[$slug]->available = $remote_version; - $repository[$slug]->version = $local_version; - $repository[$slug]->type = $repository[$slug]->release_type; - $items[$slug] = $repository[$slug]; + $themes[$slug]->available = $remote_version; + $themes[$slug]->version = $local_version; + $themes[$slug]->type = $themes[$slug]->release_type; + $items[$slug] = $themes[$slug]; } } @@ -407,19 +446,20 @@ class GPM extends Iterator */ public function getReleaseType($package_name) { - if (null === $this->repository) { + $repository = $this->getRepository(); + if (null === $repository) { return null; } - $repository = $this->repository['plugins']; - if (isset($repository[$package_name])) { - return $repository[$package_name]->release_type; + $plugins = $repository['plugins']; + if (isset($plugins[$package_name])) { + return $plugins[$package_name]->release_type; } //Not a plugin, it's a theme? - $repository = $this->repository['themes']; - if (isset($repository[$package_name])) { - return $repository[$package_name]->release_type; + $themes = $repository['themes']; + if (isset($themes[$package_name])) { + return $themes[$package_name]->release_type; } return null; @@ -470,7 +510,7 @@ class GPM extends Iterator */ public function getRepositoryPlugins() { - return $this->repository['plugins'] ?? null; + return $this->getRepository()['plugins'] ?? null; } /** @@ -493,7 +533,7 @@ class GPM extends Iterator */ public function getRepositoryThemes() { - return $this->repository['themes'] ?? null; + return $this->getRepository()['themes'] ?? null; } /** @@ -504,9 +544,31 @@ class GPM extends Iterator */ public function getRepository() { + if (null === $this->repository) { + try { + $this->repository = new Remote\Packages($this->refresh, $this->callback); + } catch (Exception $e) {} + } + return $this->repository; } + /** + * Returns Grav version available in the repository + * + * @return Remote\GravCore|null + */ + public function getGrav() + { + if (null === $this->grav) { + try { + $this->grav = new Remote\GravCore($this->refresh, $this->callback); + } catch (Exception $e) {} + } + + return $this->grav; + } + /** * Searches for a Package in the repository * diff --git a/system/src/Grav/Common/Grav.php b/system/src/Grav/Common/Grav.php index c9097ee..ffbb508 100644 --- a/system/src/Grav/Common/Grav.php +++ b/system/src/Grav/Common/Grav.php @@ -9,6 +9,7 @@ namespace Grav\Common; +use Composer\Autoload\ClassLoader; use Grav\Common\Config\Config; use Grav\Common\Config\Setup; use Grav\Common\Helpers\Exif; @@ -152,6 +153,13 @@ class Grav extends Container { if (null === self::$instance) { self::$instance = static::load($values); + + /** @var ClassLoader|null $loader */ + $loader = self::$instance['loader'] ?? null; + if ($loader) { + // Load fix for Deferred Twig Extension + $loader->addPsr4('Phive\\Twig\\Extensions\\Deferred\\', LIB_DIR . 'Phive/Twig/Extensions/Deferred/', true); + } } elseif ($values) { $instance = self::$instance; foreach ($values as $key => $value) { diff --git a/system/src/Grav/Common/Media/Traits/MediaUploadTrait.php b/system/src/Grav/Common/Media/Traits/MediaUploadTrait.php index 6da77ee..71431ed 100644 --- a/system/src/Grav/Common/Media/Traits/MediaUploadTrait.php +++ b/system/src/Grav/Common/Media/Traits/MediaUploadTrait.php @@ -20,11 +20,13 @@ use Grav\Common\Security; use Grav\Common\Utils; use Grav\Framework\Filesystem\Filesystem; use Grav\Framework\Form\FormFlashFile; +use Grav\Framework\Mime\MimeTypes; use Psr\Http\Message\UploadedFileInterface; use RocketTheme\Toolbox\File\YamlFile; use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator; use RuntimeException; use function dirname; +use function in_array; /** * Implements media upload and delete functionality. @@ -179,16 +181,20 @@ trait MediaUploadTrait } } + $grav = Grav::instance(); + /** @var MimeTypes $mimeChecker */ + $mimeChecker = $grav['mime']; + // Handle Accepted file types. Accept can only be mime types (image/png | image/*) or file extensions (.pdf | .jpg) - $accepted = false; - $errors = []; // Do not trust mime type sent by the browser. - $mime = Utils::getMimeByFilename($filename); - $mimeTest = $metadata['mime'] ?? $mime; - if ($mime !== $mimeTest) { + $mime = $metadata['mime'] ?? $mimeChecker->getMimeType($extension); + $validExtensions = $mimeChecker->getExtensions($mime); + if (!in_array($extension, $validExtensions, true)) { throw new RuntimeException('The mime type does not match to file extension', 400); } + $accepted = false; + $errors = []; foreach ((array)$settings['accept'] as $type) { // Force acceptance of any file when star notation if ($type === '*') { @@ -418,6 +424,17 @@ trait MediaUploadTrait $uploadedFile->moveTo($filepath); } + /** + * Get upload settings. + * + * @param array|null $settings Form field specific settings (override). + * @return array + */ + public function getUploadSettings(?array $settings = null): array + { + return null !== $settings ? $settings + $this->_upload_defaults : $this->_upload_defaults; + } + /** * Internal logic to copy file. * @@ -604,17 +621,6 @@ trait MediaUploadTrait } } - /** - * Get upload settings. - * - * @param array|null $settings Form field specific settings (override). - * @return array - */ - protected function getUploadSettings(?array $settings = null): array - { - return null !== $settings ? $settings + $this->_upload_defaults : $this->_upload_defaults; - } - /** * @param string $filename * @param string $path diff --git a/system/src/Grav/Common/Page/Collection.php b/system/src/Grav/Common/Page/Collection.php index 139a58b..c9a3cdb 100644 --- a/system/src/Grav/Common/Page/Collection.php +++ b/system/src/Grav/Common/Page/Collection.php @@ -145,6 +145,18 @@ class Collection extends Iterator implements PageCollectionInterface return $this; } + /** + * Set current page. + */ + public function setCurrent(string $path): void + { + reset($this->items); + + while (($key = key($this->items)) !== null && $key !== $path) { + next($this->items); + } + } + /** * Returns current page. * diff --git a/system/src/Grav/Common/Page/Media.php b/system/src/Grav/Common/Page/Media.php index 9201e66..94fd2c4 100644 --- a/system/src/Grav/Common/Page/Media.php +++ b/system/src/Grav/Common/Page/Media.php @@ -102,12 +102,13 @@ class Media extends AbstractMedia foreach ($iterator as $file => $info) { // Ignore folders and Markdown files. - if (!$info->isFile() || $info->getExtension() === 'md' || strpos($info->getFilename(), '.') === 0) { + $filename = $info->getFilename(); + if (!$info->isFile() || $info->getExtension() === 'md' || $filename === 'frontmatter.yaml' || strpos($filename, '.') === 0) { continue; } // Find out what type we're dealing with - [$basename, $ext, $type, $extra] = $this->getFileParts($info->getFilename()); + [$basename, $ext, $type, $extra] = $this->getFileParts($filename); if (!in_array(strtolower($ext), $media_types, true)) { continue; diff --git a/system/src/Grav/Common/Processors/InitializeProcessor.php b/system/src/Grav/Common/Processors/InitializeProcessor.php index cc8e4f2..6114464 100644 --- a/system/src/Grav/Common/Processors/InitializeProcessor.php +++ b/system/src/Grav/Common/Processors/InitializeProcessor.php @@ -105,12 +105,12 @@ class InitializeProcessor extends ProcessorBase // TODO: remove in 2.0. $this->container['accounts']; - // Initialize session. - $this->initializeSession($config); - // Initialize URI (uses session, see issue #3269). $this->initializeUri($config); + // Initialize session. + $this->initializeSession($config); + // Grav may return redirect response right away. $redirectCode = (int)$config->get('system.pages.redirect_trailing_slash', 1); if ($redirectCode) { diff --git a/system/src/Grav/Common/Processors/PagesProcessor.php b/system/src/Grav/Common/Processors/PagesProcessor.php index 33b483f..470ca90 100644 --- a/system/src/Grav/Common/Processors/PagesProcessor.php +++ b/system/src/Grav/Common/Processors/PagesProcessor.php @@ -10,6 +10,8 @@ namespace Grav\Common\Processors; use Grav\Common\Page\Interfaces\PageInterface; +use Grav\Framework\RequestHandler\Exception\RequestException; +use Grav\Plugin\Form\Forms; use RocketTheme\Toolbox\Event\Event; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; @@ -47,8 +49,17 @@ class PagesProcessor extends ProcessorBase $page = $this->container['page']; if (!$page->routable()) { + $exception = new RequestException($request, 'Page Not Found', 404); + $route = $this->container['route']; // If no page found, fire event - $event = new Event(['page' => $page]); + $event = new Event([ + 'page' => $page, + 'code' => $exception->getCode(), + 'message' => $exception->getMessage(), + 'exception' => $exception, + 'route' => $route, + 'request' => $request + ]); $event->page = null; $event = $this->container->fireEvent('onPageNotFound', $event); @@ -65,12 +76,18 @@ class PagesProcessor extends ProcessorBase $task = $this->container['task']; $action = $this->container['action']; + + /** @var Forms $forms */ + $forms = $this->container['forms'] ?? null; + $form = $forms ? $forms->getActiveForm() : null; + + $options = ['page' => $page, 'form' => $form, 'request' => $request]; if ($task) { - $event = new Event(['task' => $task, 'page' => $page]); + $event = new Event(['task' => $task] + $options); $this->container->fireEvent('onPageTask', $event); $this->container->fireEvent('onPageTask.' . $task, $event); } elseif ($action) { - $event = new Event(['action' => $action, 'page' => $page]); + $event = new Event(['action' => $action] + $options); $this->container->fireEvent('onPageAction', $event); $this->container->fireEvent('onPageAction.' . $action, $event); } diff --git a/system/src/Grav/Common/Scheduler/Job.php b/system/src/Grav/Common/Scheduler/Job.php index f21c26d..94fbaf1 100644 --- a/system/src/Grav/Common/Scheduler/Job.php +++ b/system/src/Grav/Common/Scheduler/Job.php @@ -390,7 +390,9 @@ class Job if (count($this->outputTo) > 0) { foreach ($this->outputTo as $file) { $output_mode = $this->outputMode === 'append' ? FILE_APPEND | LOCK_EX : LOCK_EX; - file_put_contents($file, $this->output, $output_mode); + $timestamp = (new DateTime('now'))->format('c'); + $output = $timestamp . "\n" . str_pad('', strlen($timestamp), '>') . "\n" . $this->output; + file_put_contents($file, $output, $output_mode); } } diff --git a/system/src/Grav/Common/Security.php b/system/src/Grav/Common/Security.php index fe33d79..c464e43 100644 --- a/system/src/Grav/Common/Security.php +++ b/system/src/Grav/Common/Security.php @@ -12,6 +12,7 @@ namespace Grav\Common; use enshrined\svgSanitize\Sanitizer; use Exception; use Grav\Common\Config\Config; +use Grav\Common\Filesystem\Folder; use Grav\Common\Page\Pages; use function chr; use function count; @@ -56,9 +57,16 @@ class Security $original_svg = file_get_contents($file); $clean_svg = $sanitizer->sanitize($original_svg); - // TODO: what to do with bad SVG files which return false? - if ($clean_svg !== false && $clean_svg !== $original_svg) { + // Quarantine bad SVG files and throw exception + if ($clean_svg !== false ) { file_put_contents($file, $clean_svg); + } else { + $quarantine_file = basename($file); + $quarantine_dir = 'log://quarantine'; + Folder::mkdir($quarantine_dir); + file_put_contents("$quarantine_dir/$quarantine_file", $original_svg); + unlink($file); + throw new Exception('SVG could not be sanitized, it has been moved to the logs/quarantine folder'); } } } diff --git a/system/src/Grav/Common/Service/ConfigServiceProvider.php b/system/src/Grav/Common/Service/ConfigServiceProvider.php index a423f6e..b56f62f 100644 --- a/system/src/Grav/Common/Service/ConfigServiceProvider.php +++ b/system/src/Grav/Common/Service/ConfigServiceProvider.php @@ -17,6 +17,7 @@ use Grav\Common\Config\Config; use Grav\Common\Config\ConfigFileFinder; use Grav\Common\Config\Setup; use Grav\Common\Language\Language; +use Grav\Framework\Mime\MimeTypes; use Pimple\Container; use Pimple\ServiceProviderInterface; use RocketTheme\Toolbox\File\YamlFile; @@ -56,6 +57,19 @@ class ConfigServiceProvider implements ServiceProviderInterface return $config; }; + $container['mime'] = function ($c) { + /** @var Config $config */ + $config = $c['config']; + $mimes = $config->get('mime.types', []); + foreach ($config->get('media.types', []) as $ext => $media) { + if (!empty($media['mime'])) { + $mimes[$ext] = array_unique(array_merge([$media['mime']], $mimes[$ext] ?? [])); + } + } + + return MimeTypes::createFromMimes($mimes); + }; + $container['languages'] = function ($c) { return static::languages($c); }; diff --git a/system/src/Grav/Common/Service/TaskServiceProvider.php b/system/src/Grav/Common/Service/TaskServiceProvider.php index 9afab59..49ce147 100644 --- a/system/src/Grav/Common/Service/TaskServiceProvider.php +++ b/system/src/Grav/Common/Service/TaskServiceProvider.php @@ -12,6 +12,7 @@ namespace Grav\Common\Service; use Grav\Common\Grav; use Pimple\Container; use Pimple\ServiceProviderInterface; +use Psr\Http\Message\ServerRequestInterface; /** * Class TaskServiceProvider @@ -26,7 +27,11 @@ class TaskServiceProvider implements ServiceProviderInterface public function register(Container $container) { $container['task'] = function (Grav $c) { - $task = $_POST['task'] ?? $c['uri']->param('task'); + /** @var ServerRequestInterface $request */ + $request = $c['request']; + $body = $request->getParsedBody(); + + $task = $body['task'] ?? $c['uri']->param('task'); if (null !== $task) { $task = filter_var($task, FILTER_SANITIZE_STRING); } @@ -35,7 +40,11 @@ class TaskServiceProvider implements ServiceProviderInterface }; $container['action'] = function (Grav $c) { - $action = $_POST['action'] ?? $c['uri']->param('action'); + /** @var ServerRequestInterface $request */ + $request = $c['request']; + $body = $request->getParsedBody(); + + $action = $body['action'] ?? $c['uri']->param('action'); if (null !== $action) { $action = filter_var($action, FILTER_SANITIZE_STRING); } diff --git a/system/src/Grav/Common/Session.php b/system/src/Grav/Common/Session.php index 8856e7a..2dbc307 100644 --- a/system/src/Grav/Common/Session.php +++ b/system/src/Grav/Common/Session.php @@ -12,6 +12,7 @@ namespace Grav\Common; use Grav\Common\Form\FormFlash; use Grav\Events\SessionStartEvent; use Grav\Plugin\Form\Forms; +use JsonException; use function is_string; /** @@ -148,10 +149,11 @@ class Session extends \Grav\Framework\Session\Session * @param mixed $object * @param int $time * @return $this + * @throws JsonException */ public function setFlashCookieObject($name, $object, $time = 60) { - setcookie($name, json_encode($object), time() + $time, '/'); + setcookie($name, json_encode($object, JSON_THROW_ON_ERROR), $this->getCookieOptions($time)); return $this; } @@ -161,13 +163,15 @@ class Session extends \Grav\Framework\Session\Session * * @param string $name * @return mixed|null + * @throws JsonException */ public function getFlashCookieObject($name) { if (isset($_COOKIE[$name])) { - $object = json_decode($_COOKIE[$name], false); - setcookie($name, '', time() - 3600, '/'); - return $object; + $cookie = $_COOKIE[$name]; + setcookie($name, '', $this->getCookieOptions(-42000)); + + return json_decode($cookie, false, 512, JSON_THROW_ON_ERROR); } return null; diff --git a/system/src/Grav/Common/Twig/Exception/TwigException.php b/system/src/Grav/Common/Twig/Exception/TwigException.php new file mode 100644 index 0000000..8f543dc --- /dev/null +++ b/system/src/Grav/Common/Twig/Exception/TwigException.php @@ -0,0 +1,19 @@ + ['all']]), new TwigFilter('array', [$this, 'arrayFilter']), + new TwigFilter('yaml', [$this, 'yamlFilter']), // Object Types new TwigFilter('get_type', [$this, 'getTypeFunc']), @@ -807,6 +808,17 @@ class GravExtension extends AbstractExtension implements GlobalsInterface return (array)$input; } + /** + * @param array|object $value + * @param int|null $inline + * @param int|null $indent + * @return string + */ + public function yamlFilter($value, $inline = null, $indent = null): string + { + return Yaml::dump($value, $inline, $indent); + } + /** * @param Environment $twig * @return string @@ -1499,7 +1511,7 @@ class GravExtension extends AbstractExtension implements GlobalsInterface } //Look for existing class - $svg = preg_replace_callback('/^]*(class=\")([^"]*)(\")[^>]*>/', function($matches) use ($classes, &$matched) { + $svg = preg_replace_callback('/^]*(class=\"([^"]*)\")[^>]*>/', function($matches) use ($classes, &$matched) { if (isset($matches[2])) { $new_classes = $matches[2] . $classes; $matched = true; diff --git a/system/src/Grav/Common/Twig/Node/TwigNodeThrow.php b/system/src/Grav/Common/Twig/Node/TwigNodeThrow.php index 1a32a91..3bfe612 100644 --- a/system/src/Grav/Common/Twig/Node/TwigNodeThrow.php +++ b/system/src/Grav/Common/Twig/Node/TwigNodeThrow.php @@ -43,7 +43,7 @@ class TwigNodeThrow extends Node $compiler->addDebugInfo($this); $compiler - ->write('throw new \RuntimeException(') + ->write('throw new \Grav\Common\Twig\Exception\TwigException(') ->subcompile($this->getNode('message')) ->write(', ') ->write($this->getAttribute('code') ?: 500) diff --git a/system/src/Grav/Common/Twig/Node/TwigNodeTryCatch.php b/system/src/Grav/Common/Twig/Node/TwigNodeTryCatch.php index da95a1d..40e9240 100644 --- a/system/src/Grav/Common/Twig/Node/TwigNodeTryCatch.php +++ b/system/src/Grav/Common/Twig/Node/TwigNodeTryCatch.php @@ -49,16 +49,15 @@ class TwigNodeTryCatch extends Node $compiler ->indent() - ->subcompile($this->getNode('try')); + ->subcompile($this->getNode('try')) + ->outdent() + ->write('} catch (\Exception $e) {' . "\n") + ->indent() + ->write('if (isset($context[\'grav\'][\'debugger\'])) $context[\'grav\'][\'debugger\']->addException($e);' . "\n") + ->write('$context[\'e\'] = $e;' . "\n"); if ($this->hasNode('catch')) { - $compiler - ->outdent() - ->write('} catch (\Exception $e) {' . "\n") - ->indent() - ->write('if (isset($context[\'grav\'][\'debugger\'])) $context[\'grav\'][\'debugger\']->addException($e);' . "\n") - ->write('$context[\'e\'] = $e;' . "\n") - ->subcompile($this->getNode('catch')); + $compiler->subcompile($this->getNode('catch')); } $compiler diff --git a/system/src/Grav/Common/Twig/Twig.php b/system/src/Grav/Common/Twig/Twig.php index 2796c0d..ef74ce7 100644 --- a/system/src/Grav/Common/Twig/Twig.php +++ b/system/src/Grav/Common/Twig/Twig.php @@ -16,6 +16,7 @@ use Grav\Common\Language\Language; use Grav\Common\Language\LanguageCodes; use Grav\Common\Page\Interfaces\PageInterface; use Grav\Common\Page\Pages; +use Grav\Common\Twig\Exception\TwigException; use Grav\Common\Twig\Extension\FilesystemExtension; use Grav\Common\Twig\Extension\GravExtension; use Grav\Common\Utils; @@ -26,6 +27,7 @@ use RuntimeException; use Twig\Cache\FilesystemCache; use Twig\Environment; use Twig\Error\LoaderError; +use Twig\Error\RuntimeError; use Twig\Extension\CoreExtension; use Twig\Extension\DebugExtension; use Twig\Extension\StringLoaderExtension; @@ -404,38 +406,63 @@ class Twig */ public function processSite($format = null, array $vars = []) { - // set the page now its been processed - $this->grav->fireEvent('onTwigSiteVariables'); - /** @var Pages $pages */ - $pages = $this->grav['pages']; - /** @var PageInterface $page */ - $page = $this->grav['page']; - $content = $page->content(); - - $twig_vars = $this->twig_vars; - - $twig_vars['theme'] = $this->grav['config']->get('theme'); - $twig_vars['pages'] = $pages->root(); - $twig_vars['page'] = $page; - $twig_vars['header'] = $page->header(); - $twig_vars['media'] = $page->media(); - $twig_vars['content'] = $content; - - // determine if params are set, if so disable twig cache - $params = $this->grav['uri']->params(null, true); - if (!empty($params)) { - $this->twig->setCache(false); - } - - // Get Twig template layout - $template = $this->getPageTwigTemplate($page, $format); - $page->templateFormat($format); - try { + $grav = $this->grav; + + // set the page now its been processed + $grav->fireEvent('onTwigSiteVariables'); + + /** @var Pages $pages */ + $pages = $grav['pages']; + + /** @var PageInterface $page */ + $page = $grav['page']; + + $twig_vars = $this->twig_vars; + $twig_vars['theme'] = $grav['config']->get('theme'); + $twig_vars['pages'] = $pages->root(); + $twig_vars['page'] = $page; + $twig_vars['header'] = $page->header(); + $twig_vars['media'] = $page->media(); + $twig_vars['content'] = $page->content(); + + // determine if params are set, if so disable twig cache + $params = $grav['uri']->params(null, true); + if (!empty($params)) { + $this->twig->setCache(false); + } + + // Get Twig template layout + $template = $this->getPageTwigTemplate($page, $format); + $page->templateFormat($format); + $output = $this->twig->render($template, $vars + $twig_vars); } catch (LoaderError $e) { - $error_msg = $e->getMessage(); - throw new RuntimeException($error_msg, 400, $e); + throw new RuntimeException($e->getMessage(), 400, $e); + } catch (RuntimeError $e) { + $prev = $e->getPrevious(); + if ($prev instanceof TwigException) { + $code = $prev->getCode() ?: 500; + // Fire onPageNotFound event. + $event = new Event([ + 'page' => $page, + 'code' => $code, + 'message' => $prev->getMessage(), + 'exception' => $prev, + 'route' => $grav['route'], + 'request' => $grav['request'] + ]); + $event = $grav->fireEvent("onDisplayErrorPage.{$code}", $event); + $newPage = $event['page']; + if ($newPage && $newPage !== $page) { + unset($grav['page']); + $grav['page'] = $newPage; + + return $this->processSite($newPage->templateFormat(), $vars); + } + } + + throw $e; } return $output; diff --git a/system/src/Grav/Common/Uri.php b/system/src/Grav/Common/Uri.php index 798176b..de325bb 100644 --- a/system/src/Grav/Common/Uri.php +++ b/system/src/Grav/Common/Uri.php @@ -675,10 +675,15 @@ class Uri */ public static function ip() { + $ip = 'UNKNOWN'; + if (getenv('HTTP_CLIENT_IP')) { $ip = getenv('HTTP_CLIENT_IP'); + } elseif (getenv('HTTP_CF_CONNECTING_IP')) { + $ip = getenv('HTTP_CF_CONNECTING_IP'); } elseif (getenv('HTTP_X_FORWARDED_FOR') && Grav::instance()['config']->get('system.http_x_forwarded.ip')) { - $ip = getenv('HTTP_X_FORWARDED_FOR'); + $ips = array_map('trim', explode(',', getenv('HTTP_X_FORWARDED_FOR'))); + $ip = array_shift($ips); } elseif (getenv('HTTP_X_FORWARDED') && Grav::instance()['config']->get('system.http_x_forwarded.ip')) { $ip = getenv('HTTP_X_FORWARDED'); } elseif (getenv('HTTP_FORWARDED_FOR')) { @@ -687,8 +692,6 @@ class Uri $ip = getenv('HTTP_FORWARDED'); } elseif (getenv('REMOTE_ADDR')) { $ip = getenv('REMOTE_ADDR'); - } else { - $ip = 'UNKNOWN'; } return $ip; @@ -1258,7 +1261,7 @@ class Uri $this->port = null; } - if ($this->hasStandardPort()) { + if ($this->port === 0 || $this->hasStandardPort()) { $this->port = null; } @@ -1311,11 +1314,13 @@ class Uri if ($parts === false) { throw new RuntimeException('Malformed URL: ' . $url); } + $port = (int)($parts['port'] ?? 0); + $this->scheme = $parts['scheme'] ?? null; $this->user = $parts['user'] ?? null; $this->password = $parts['pass'] ?? null; $this->host = $parts['host'] ?? null; - $this->port = isset($parts['port']) ? (int)$parts['port'] : null; + $this->port = $port ?: null; $this->path = $parts['path'] ?? ''; $this->query = $parts['query'] ?? ''; $this->fragment = $parts['fragment'] ?? null; diff --git a/system/src/Grav/Framework/Flex/FlexDirectory.php b/system/src/Grav/Framework/Flex/FlexDirectory.php index b9c9d54..29f1490 100644 --- a/system/src/Grav/Framework/Flex/FlexDirectory.php +++ b/system/src/Grav/Framework/Flex/FlexDirectory.php @@ -47,7 +47,7 @@ use function is_callable; * @package Grav\Framework\Flex * @template T */ -class FlexDirectory implements FlexDirectoryInterface, FlexAuthorizeInterface +class FlexDirectory implements FlexDirectoryInterface { use FlexAuthorizeTrait; @@ -235,7 +235,17 @@ class FlexDirectory implements FlexDirectoryInterface, FlexAuthorizeInterface /** @var UniformResourceLocator $locator */ $locator = $grav['locator']; - $filename = $locator->findResource($this->getDirectoryConfigUri($name), true); + $uri = $this->getDirectoryConfigUri($name); + + // If configuration is found in main configuration, use it. + if (str_starts_with($uri, 'config://')) { + $path = str_replace('/', '.', substr($uri, 9, -5)); + + return (array)$grav['config']->get($path); + } + + // Load the configuration file. + $filename = $locator->findResource($uri, true); if ($filename === false) { return []; } @@ -821,20 +831,46 @@ class FlexDirectory implements FlexDirectoryInterface, FlexAuthorizeInterface * @param array $call * @return void */ - protected function dynamicFlexField(array &$field, $property, array $call) + protected function dynamicFlexField(array &$field, $property, array $call): void { $params = (array)$call['params']; $object = $call['object'] ?? null; $method = array_shift($params); + $not = false; + if (str_starts_with($method, '!')) { + $method = substr($method, 1); + $not = true; + } elseif (str_starts_with($method, 'not ')) { + $method = substr($method, 4); + $not = true; + } + $method = trim($method); if ($object && method_exists($object, $method)) { $value = $object->{$method}(...$params); if (is_array($value) && isset($field[$property]) && is_array($field[$property])) { - $field[$property] = array_merge_recursive($field[$property], $value); + $value = $this->mergeArrays($field[$property], $value); + } + $field[$property] = $not ? !$value : $value; + } + } + + /** + * @param array $array1 + * @param array $array2 + * @return array + */ + protected function mergeArrays(array $array1, array $array2): array + { + foreach ($array2 as $key => $value) { + if (is_array($value) && isset($array1[$key]) && is_array($array1[$key])) { + $array1[$key] = $this->mergeArrays($array1[$key], $value); } else { - $field[$property] = $value; + $array1[$key] = $value; } } + + return $array1; } /** diff --git a/system/src/Grav/Framework/Flex/FlexDirectoryForm.php b/system/src/Grav/Framework/Flex/FlexDirectoryForm.php index ba26b63..dff0836 100644 --- a/system/src/Grav/Framework/Flex/FlexDirectoryForm.php +++ b/system/src/Grav/Framework/Flex/FlexDirectoryForm.php @@ -318,11 +318,11 @@ class FlexDirectoryForm implements FlexDirectoryFormInterface, JsonSerializable } /** - * @param string $field - * @param string $filename + * @param string|null $field + * @param string|null $filename * @return Route|null */ - public function getFileDeleteAjaxRoute($field, $filename): ?Route + public function getFileDeleteAjaxRoute($field = null, $filename = null): ?Route { return null; } @@ -453,7 +453,9 @@ class FlexDirectoryForm implements FlexDirectoryFormInterface, JsonSerializable protected function doSerialize(): array { return $this->doTraitSerialize() + [ + 'form' => $this->form, 'directory' => $this->directory, + 'flexName' => $this->flexName ]; } @@ -465,7 +467,9 @@ class FlexDirectoryForm implements FlexDirectoryFormInterface, JsonSerializable { $this->doTraitUnserialize($data); + $this->form = $data['form']; $this->directory = $data['directory']; + $this->flexName = $data['flexName']; } /** diff --git a/system/src/Grav/Framework/Flex/FlexForm.php b/system/src/Grav/Framework/Flex/FlexForm.php index 192f38f..aba0044 100644 --- a/system/src/Grav/Framework/Flex/FlexForm.php +++ b/system/src/Grav/Framework/Flex/FlexForm.php @@ -103,7 +103,14 @@ class FlexForm implements FlexObjectFormInterface, JsonSerializable { $this->name = $name; $this->setObject($object); - $this->setName($object->getFlexType(), $name); + + if (isset($options['form']['name'])) { + // Use custom form name. + $this->flexName = $options['form']['name']; + } else { + // Use standard form name. + $this->setName($object->getFlexType(), $name); + } $this->setId($this->getName()); $uniqueId = $options['unique_id'] ?? null; @@ -371,22 +378,28 @@ class FlexForm implements FlexObjectFormInterface, JsonSerializable { $object = $this->getObject(); if (!method_exists($object, 'route')) { - return null; + /** @var Route $route */ + $route = Grav::instance()['route']; + + return $route->withExtension('json')->withGravParam('task', 'media.upload'); } return $object->route('/edit.json/task:media.upload'); } /** - * @param string $field - * @param string $filename + * @param string|null $field + * @param string|null $filename * @return Route|null */ - public function getFileDeleteAjaxRoute($field, $filename): ?Route + public function getFileDeleteAjaxRoute($field = null, $filename = null): ?Route { $object = $this->getObject(); if (!method_exists($object, 'route')) { - return null; + /** @var Route $route */ + $route = Grav::instance()['route']; + + return $route->withExtension('json')->withGravParam('task', 'media.delete'); } return $object->route('/edit.json/task:media.delete'); @@ -536,7 +549,11 @@ class FlexForm implements FlexObjectFormInterface, JsonSerializable protected function doSerialize(): array { return $this->doTraitSerialize() + [ + 'items' => $this->items, + 'form' => $this->form, 'object' => $this->object, + 'flexName' => $this->flexName, + 'submitMethod' => $this->submitMethod, ]; } @@ -548,7 +565,11 @@ class FlexForm implements FlexObjectFormInterface, JsonSerializable { $this->doTraitUnserialize($data); - $this->object = $data['object']; + $this->items = $data['items'] ?? null; + $this->form = $data['form'] ?? null; + $this->object = $data['object'] ?? null; + $this->flexName = $data['flexName'] ?? null; + $this->submitMethod = $data['submitMethod'] ?? null; } /** diff --git a/system/src/Grav/Framework/Flex/FlexObject.php b/system/src/Grav/Framework/Flex/FlexObject.php index d505e56..945f5ad 100644 --- a/system/src/Grav/Framework/Flex/FlexObject.php +++ b/system/src/Grav/Framework/Flex/FlexObject.php @@ -44,6 +44,7 @@ use function is_array; use function is_object; use function is_scalar; use function is_string; +use function json_encode; /** * Class FlexObject @@ -70,6 +71,8 @@ class FlexObject implements FlexObjectInterface, FlexAuthorizeInterface /** @var array */ private $_meta; /** @var array */ + protected $_original; + /** @var array */ protected $_changes; /** @var string */ protected $storage_key; @@ -369,7 +372,7 @@ class FlexObject implements FlexObjectInterface, FlexAuthorizeInterface */ public function searchProperty(string $property, string $search, array $options = null): float { - $options = $options ?? $this->getFlexDirectory()->getConfig('data.search.options', []); + $options = $options ?? (array)$this->getFlexDirectory()->getConfig('data.search.options'); $value = $this->getProperty($property); return $this->searchValue($property, $value, $search, $options); @@ -383,7 +386,7 @@ class FlexObject implements FlexObjectInterface, FlexAuthorizeInterface */ public function searchNestedProperty(string $property, string $search, array $options = null): float { - $options = $options ?? $this->getFlexDirectory()->getConfig('data.search.options', []); + $options = $options ?? (array)$this->getFlexDirectory()->getConfig('data.search.options'); if ($property === 'key') { $value = $this->getKey(); } else { @@ -440,6 +443,16 @@ class FlexObject implements FlexObjectInterface, FlexAuthorizeInterface return 0; } + /** + * Get original data before update + * + * @return array + */ + public function getOriginalData(): array + { + return $this->_original ?? []; + } + /** * Get any changes based on data sent to update * @@ -653,7 +666,8 @@ class FlexObject implements FlexObjectInterface, FlexAuthorizeInterface } // Store the changes - $this->_changes = Utils::arrayDiffMultidimensional($this->getElements(), $elements); + $this->_original = $this->getElements(); + $this->_changes = Utils::arrayDiffMultidimensional($this->_original, $elements); } if ($files && method_exists($this, 'setUpdatedMedia')) { @@ -691,6 +705,17 @@ class FlexObject implements FlexObjectInterface, FlexAuthorizeInterface return $this->create($key); } + /** + * @param UserInterface|null $user + */ + public function check(UserInterface $user = null): void + { + // If user has been provided, check if the user has permissions to save this object. + if ($user && !$this->isAuthorized('save', null, $user)) { + throw new \RuntimeException('Forbidden', 403); + } + } + /** * {@inheritdoc} * @see FlexObjectInterface::save() @@ -809,11 +834,12 @@ class FlexObject implements FlexObjectInterface, FlexAuthorizeInterface */ public function getForm(string $name = '', array $options = null) { - if (!isset($this->_forms[$name])) { - $this->_forms[$name] = $this->createFormObject($name, $options); + $hash = $name . '-' . md5(json_encode($options, JSON_THROW_ON_ERROR)); + if (!isset($this->_forms[$hash])) { + $this->_forms[$hash] = $this->createFormObject($name, $options); } - return $this->_forms[$name]; + return $this->_forms[$hash]; } /** @@ -1063,6 +1089,17 @@ class FlexObject implements FlexObjectInterface, FlexAuthorizeInterface return $action; } + /** + * Method to reset blueprints if the type changes. + * + * @return void + * @since 1.7.18 + */ + protected function resetBlueprints(): void + { + $this->_blueprint = []; + } + // DEPRECATED METHODS /** diff --git a/system/src/Grav/Framework/Flex/Interfaces/FlexDirectoryInterface.php b/system/src/Grav/Framework/Flex/Interfaces/FlexDirectoryInterface.php index 7523241..07eab01 100644 --- a/system/src/Grav/Framework/Flex/Interfaces/FlexDirectoryInterface.php +++ b/system/src/Grav/Framework/Flex/Interfaces/FlexDirectoryInterface.php @@ -17,7 +17,7 @@ use Grav\Framework\Cache\CacheInterface; * Interface FlexDirectoryInterface * @package Grav\Framework\Flex\Interfaces */ -interface FlexDirectoryInterface +interface FlexDirectoryInterface extends FlexAuthorizeInterface { /** * @return bool diff --git a/system/src/Grav/Framework/Flex/Interfaces/FlexFormInterface.php b/system/src/Grav/Framework/Flex/Interfaces/FlexFormInterface.php index 9539a15..32dab19 100644 --- a/system/src/Grav/Framework/Flex/Interfaces/FlexFormInterface.php +++ b/system/src/Grav/Framework/Flex/Interfaces/FlexFormInterface.php @@ -38,8 +38,8 @@ interface FlexFormInterface extends Serializable, FormInterface /** * Get route for deleting files by AJAX. * - * @param string $field Field where the file is associated into. - * @param string $filename Filename for the file. + * @param string|null $field Field where the file is associated into. + * @param string|null $filename Filename for the file. * @return Route|null Returns Route object or null if file uploads are not enabled. */ public function getFileDeleteAjaxRoute($field, $filename); diff --git a/system/src/Grav/Framework/Flex/Storage/FolderStorage.php b/system/src/Grav/Framework/Flex/Storage/FolderStorage.php index 229194d..5b4f9f3 100644 --- a/system/src/Grav/Framework/Flex/Storage/FolderStorage.php +++ b/system/src/Grav/Framework/Flex/Storage/FolderStorage.php @@ -40,6 +40,8 @@ class FolderStorage extends AbstractFilesystemStorage protected $dataFolder; /** @var string Pattern to access an object. */ protected $dataPattern = '{FOLDER}/{KEY}/{FILE}{EXT}'; + /** @var string[] */ + protected $variables = ['FOLDER' => '%1$s', 'KEY' => '%2$s', 'KEY:2' => '%3$s', 'FILE' => '%4$s', 'EXT' => '%5$s']; /** @var string Filename for the object. */ protected $dataFile; /** @var string File extension for the object. */ @@ -380,6 +382,12 @@ class FolderStorage extends AbstractFilesystemStorage if (isset($data[0])) { throw new RuntimeException('Broken object file'); } + + // Add key field to the object. + $keyField = $this->keyField; + if ($keyField !== 'storage_key' && !isset($data[$keyField])) { + $data[$keyField] = $key; + } } catch (RuntimeException $e) { $data = ['__ERROR' => $e->getMessage()]; } finally { @@ -692,9 +700,7 @@ class FolderStorage extends AbstractFilesystemStorage $this->keyLen = (int)($options['key_len'] ?? 32); $this->caseSensitive = (bool)($options['case_sensitive'] ?? true); - $variables = ['FOLDER' => '%1$s', 'KEY' => '%2$s', 'KEY:2' => '%3$s', 'FILE' => '%4$s', 'EXT' => '%5$s']; - $pattern = Utils::simpleTemplate($pattern, $variables); - + $pattern = Utils::simpleTemplate($pattern, $this->variables); if (!$pattern) { throw new RuntimeException('Bad storage folder pattern'); } diff --git a/system/src/Grav/Framework/Flex/Storage/SimpleStorage.php b/system/src/Grav/Framework/Flex/Storage/SimpleStorage.php index 85c1429..6faac9d 100644 --- a/system/src/Grav/Framework/Flex/Storage/SimpleStorage.php +++ b/system/src/Grav/Framework/Flex/Storage/SimpleStorage.php @@ -455,7 +455,7 @@ class SimpleStorage extends AbstractFilesystemStorage $content = (array) $file->content(); if ($this->prefix) { $data = new Data($content); - $content = $data->get($this->prefix); + $content = $data->get($this->prefix, []); } $file->free(); diff --git a/system/src/Grav/Framework/Flex/Traits/FlexMediaTrait.php b/system/src/Grav/Framework/Flex/Traits/FlexMediaTrait.php index 197664a..dabfe17 100644 --- a/system/src/Grav/Framework/Flex/Traits/FlexMediaTrait.php +++ b/system/src/Grav/Framework/Flex/Traits/FlexMediaTrait.php @@ -120,7 +120,7 @@ trait FlexMediaTrait // Load settings for the field. $schema = $this->getBlueprint()->schema(); $settings = $field && is_object($schema) ? (array)$schema->getProperty($field) : null; - if (!isset($settings) || !is_array($settings)) { + if (!is_array($settings)) { return null; } diff --git a/system/src/Grav/Framework/Form/FormFlash.php b/system/src/Grav/Framework/Form/FormFlash.php index 00aab28..864e992 100644 --- a/system/src/Grav/Framework/Form/FormFlash.php +++ b/system/src/Grav/Framework/Form/FormFlash.php @@ -120,7 +120,7 @@ class FormFlash implements FormFlashInterface protected function loadStoredForm(): ?array { $file = $this->getTmpIndex(); - $exists = $file->exists(); + $exists = $file && $file->exists(); $data = null; if ($exists) { @@ -246,8 +246,10 @@ class FormFlash implements FormFlashInterface if ($force || $this->data || $this->files) { // Only save if there is data or files to be saved. $file = $this->getTmpIndex(); - $file->save($this->jsonSerialize()); - $this->exists = true; + if ($file) { + $file->save($this->jsonSerialize()); + $this->exists = true; + } } elseif ($this->exists) { // Delete empty form flash if it exists (it carries no information). return $this->delete(); @@ -476,12 +478,14 @@ class FormFlash implements FormFlashInterface } /** - * @return YamlFile + * @return ?YamlFile */ - protected function getTmpIndex(): YamlFile + protected function getTmpIndex(): ?YamlFile { + $tmpDir = $this->getTmpDir(); + // Do not use CompiledYamlFile as the file can change multiple times per second. - return YamlFile::instance($this->getTmpDir() . '/index.yaml'); + return $tmpDir ? YamlFile::instance($tmpDir . '/index.yaml') : null; } /** @@ -503,7 +507,9 @@ class FormFlash implements FormFlashInterface { // Make sure that index file cache gets always cleared. $file = $this->getTmpIndex(); - $file->free(); + if ($file) { + $file->free(); + } $tmpDir = $this->getTmpDir(); if ($tmpDir && file_exists($tmpDir)) { diff --git a/system/src/Grav/Framework/Mime/MimeTypes.php b/system/src/Grav/Framework/Mime/MimeTypes.php new file mode 100644 index 0000000..dadcddf --- /dev/null +++ b/system/src/Grav/Framework/Mime/MimeTypes.php @@ -0,0 +1,107 @@ + ['mime/type', 'mime/type2']] + */ + public static function createFromMimes(array $mimes): self + { + $extensions = []; + foreach ($mimes as $ext => $list) { + foreach ($list as $mime) { + $list = $extensions[$mime] ?? []; + if (!in_array($ext, $list, true)) { + $list[] = $ext; + $extensions[$mime] = $list; + } + } + } + + return new static($extensions, $mimes); + } + + /** + * @param string $extension + * @return string|null + */ + public function getMimeType(string $extension): ?string + { + $extension = $this->cleanInput($extension); + + return $this->mimes[$extension][0] ?? null; + } + + /** + * @param string $mime + * @return string|null + */ + public function getExtension(string $mime): ?string + { + $mime = $this->cleanInput($mime); + + return $this->extensions[$mime][0] ?? null; + } + + /** + * @param string $extension + * @return array + */ + public function getMimeTypes(string $extension): array + { + $extension = $this->cleanInput($extension); + + return $this->mimes[$extension] ?? []; + } + + /** + * @param string $mime + * @return array + */ + public function getExtensions(string $mime): array + { + $mime = $this->cleanInput($mime); + + return $this->extensions[$mime] ?? []; + } + + /** + * @param string $input + * @return string + */ + protected function cleanInput(string $input): string + { + return strtolower(trim($input)); + } + + /** + * @param array $extensions + * @param array $mimes + */ + protected function __construct(array $extensions, array $mimes) + { + $this->extensions = $extensions; + $this->mimes = $mimes; + } +} diff --git a/system/src/Grav/Framework/Object/ObjectCollection.php b/system/src/Grav/Framework/Object/ObjectCollection.php index 0d82434..3a51ec8 100644 --- a/system/src/Grav/Framework/Object/ObjectCollection.php +++ b/system/src/Grav/Framework/Object/ObjectCollection.php @@ -9,7 +9,6 @@ namespace Grav\Framework\Object; -use Doctrine\Common\Collections\Collection; use Doctrine\Common\Collections\Criteria; use Grav\Framework\Collection\ArrayCollection; use Grav\Framework\Object\Access\NestedPropertyCollectionTrait; diff --git a/system/src/Grav/Framework/Psr7/UploadedFile.php b/system/src/Grav/Framework/Psr7/UploadedFile.php index f136742..bfa63cd 100644 --- a/system/src/Grav/Framework/Psr7/UploadedFile.php +++ b/system/src/Grav/Framework/Psr7/UploadedFile.php @@ -23,6 +23,9 @@ class UploadedFile implements UploadedFileInterface { use UploadedFileDecoratorTrait; + /** @var array */ + private $meta = []; + /** * @param StreamInterface|string|resource $streamOrFile * @param int $size @@ -34,4 +37,34 @@ class UploadedFile implements UploadedFileInterface { $this->uploadedFile = new \Nyholm\Psr7\UploadedFile($streamOrFile, $size, $errorStatus, $clientFilename, $clientMediaType); } + + /** + * @param array $meta + * @return $this + */ + public function setMeta(array $meta) + { + $this->meta = $meta; + + return $this; + } + + /** + * @param array $meta + * @return $this + */ + public function addMeta(array $meta) + { + $this->meta = array_merge($this->meta, $meta); + + return $this; + } + + /** + * @return array + */ + public function getMeta(): array + { + return $this->meta; + } } diff --git a/system/src/Grav/Framework/Session/Session.php b/system/src/Grav/Framework/Session/Session.php index ddab08d..3feae5a 100644 --- a/system/src/Grav/Framework/Session/Session.php +++ b/system/src/Grav/Framework/Session/Session.php @@ -338,23 +338,12 @@ class Session implements SessionInterface { $name = $this->getName(); if (null !== $name) { - $params = session_get_cookie_params(); - - $cookie_options = array ( - 'expires' => time() - 42000, - 'path' => $params['path'], - 'domain' => $params['domain'], - 'secure' => $params['secure'], - 'httponly' => $params['httponly'], - 'samesite' => $params['samesite'] - ); - $this->removeCookie(); setcookie( session_name(), '', - $cookie_options + $this->getCookieOptions(-42000) ); } @@ -463,27 +452,36 @@ class Session implements SessionInterface } /** - * @return void + * Store something in cookie temporarily. + * + * @param int|null $lifetime + * @return array */ - protected function setCookie(): void + public function getCookieOptions(int $lifetime = null): array { $params = session_get_cookie_params(); - $cookie_options = array ( - 'expires' => time() + $params['lifetime'], + return [ + 'expires' => time() + ($lifetime ?? $params['lifetime']), 'path' => $params['path'], 'domain' => $params['domain'], 'secure' => $params['secure'], 'httponly' => $params['httponly'], 'samesite' => $params['samesite'] - ); + ]; + } + /** + * @return void + */ + protected function setCookie(): void + { $this->removeCookie(); setcookie( session_name(), session_id(), - $cookie_options + $this->getCookieOptions() ); } diff --git a/system/src/Phive/Twig/Extensions/Deferred/DeferredExtension.php b/system/src/Phive/Twig/Extensions/Deferred/DeferredExtension.php new file mode 100644 index 0000000..3a41e4a --- /dev/null +++ b/system/src/Phive/Twig/Extensions/Deferred/DeferredExtension.php @@ -0,0 +1,70 @@ +getTemplateName(); + $this->blocks[$templateName][] = [ob_get_level(), $blockName]; + } + + public function resolve(\Twig_Template $template, array $context, array $blocks) + { + $templateName = $template->getTemplateName(); + if (empty($this->blocks[$templateName])) { + return; + } + + while ($block = array_pop($this->blocks[$templateName])) { + [$level, $blockName] = $block; + if (ob_get_level() !== $level) { + continue; + } + + $buffer = ob_get_clean(); + + $blocks[$blockName] = array($template, 'block_'.$blockName.'_deferred'); + $template->displayBlock($blockName, $context, $blocks); + + echo $buffer; + } + + if ($parent = $template->getParent($context)) { + $this->resolve($parent, $context, $blocks); + } + } +} diff --git a/user/config/versions.yaml b/user/config/versions.yaml index 6fcafce..f9359e7 100644 --- a/user/config/versions.yaml +++ b/user/config/versions.yaml @@ -1,6 +1,7 @@ core: grav: - version: 1.7.16 + version: 1.7.21 schema: 1.7.0_2020-11-20_1 history: - { version: 1.7.16, date: '2021-06-10 14:03:35' } + - { version: 1.7.21, date: '2021-09-16 12:41:14' }