update grav et plugin

This commit is contained in:
2020-09-08 11:32:48 +02:00
parent 7435174adc
commit 72aae1eb2d
274 changed files with 11935 additions and 4906 deletions
+124
View File
@@ -1,3 +1,127 @@
# v1.6.27
## 09/01/2020
1. [](#improved)
* Right trim route for safety
* Use the proper ellipsis for summary [#2939](https://github.com/getgrav/grav/pull/2939)
* Left pad schedule times with zeros [#2921](https://github.com/getgrav/grav/pull/2921)
# v1.6.26
## 06/08/2020
1. [](#improved)
* Added new configuration option to control the supported attributes in markdown links [#2882](https://github.com/getgrav/grav/issues/2882)
1. [](#bugfix)
* Fixed blueprint for `system.pages.hide_empty_folders` [#1925](https://github.com/getgrav/grav/issues/2925)
* JSON Route of homepage with no route set is valid
* Fix case-insensitive search of location header [form#425](https://github.com/getgrav/grav-plugin-form/issues/425)
# v1.6.25
## 05/14/2020
1. [](#improved)
* Added system configuration support for `HTTP_X_Forwarded` headers (host disabled by default)
* Updated `PHPUserAgentParser` to 1.0.0
* Bump `Go` to version 1.13 in `travis.yaml`
# v1.6.24
## 04/27/2020
1. [](#improved)
* Added support for `X-Forwarded-Host` [#2891](https://github.com/getgrav/grav/pull/2891)
* Disable XDebug in Travis builds
# v1.6.23
## 03/19/2020
1. [](#new)
* Moved `Parsedown` 1.6 and `ParsedownExtra` 0.7 into `Grav\Framework\Parsedown` to allow fixes
* Added `aliases.php` with references to direct `\Parsedown` and `\ParsedownExtra` references
1. [](#improved)
* Upgraded `jQuery` to latest 3.4.1 version [#2859](https://github.com/getgrav/grav/issues/2859)
1. [](#bugfix)
* Fixed PHP 7.4 issue in ParsedownExtra [#2832](https://github.com/getgrav/grav/issues/2832)
* Fix for [user reported](https://twitter.com/OriginalSicksec) CVE path-based open redirect
* Fix for `stream_set_option` error with PHP 7.4 via Toolbox#28 [#2850](https://github.com/getgrav/grav/issues/2850)
# v1.6.22
## 03/05/2020
1. [](#new)
* Added `Pages::reset()` method
1. [](#improved)
* Updated Negotiation library to address issues [#2513](https://github.com/getgrav/grav/issues/2513)
1. [](#bugfix)
* Fixed issue with search plugins not being able to switch between page translations
* Fixed issues with `Pages::baseRoute()` not picking up active language reliably
* Reverted `validation: strict` fix as it breaks sites, see [#1273](https://github.com/getgrav/grav/issues/1273)
# v1.6.21
## 02/11/2020
1. [](#new)
* Added `ConsoleCommand::setLanguage()` method to set language to be used from CLI
* Added `ConsoleCommand::initializeGrav()` method to properly set up Grav instance to be used from CLI
* Added `ConsoleCommand::initializePlugins()`method to properly set up all plugins to be used from CLI
* Added `ConsoleCommand::initializeThemes()`method to properly set up current theme to be used from CLI
* Added `ConsoleCommand::initializePages()` method to properly set up pages to be used from CLI
1. [](#improved)
* Vendor updates
1. [](#bugfix)
* Fixed `bin/plugin` CLI calling `$themes->init()` way too early (removed it, use above methods instead)
* Fixed call to `$grav['page']` crashing CLI
* Fixed encoding problems when PHP INI setting `default_charset` is not `utf-8` [#2154](https://github.com/getgrav/grav/issues/2154)
# v1.6.20
## 02/03/2020
1. [](#bugfix)
* Fixed incorrect routing caused by `str_replace()` in `Uri::init()` [#2754](https://github.com/getgrav/grav/issues/2754)
* Fixed session cookie is being set twice in the HTTP header [#2745](https://github.com/getgrav/grav/issues/2745)
* Fixed session not restarting if user was invalid (downgrading from Grav 1.7)
* Fixed filesystem iterator calls with non-existing folders
* Fixed `checkbox` field not being saved, requires also Form v4.0.2 [#1225](https://github.com/getgrav/grav/issues/1225)
* Fixed `validation: strict` not working in blueprints [#1273](https://github.com/getgrav/grav/issues/1273)
* Fixed `Data::filter()` removing empty fields (such as empty list) by default [#2805](https://github.com/getgrav/grav/issues/2805)
* Fixed fatal error with non-integer page param value [#2803](https://github.com/getgrav/grav/issues/2803)
* Fixed `Assets::addInlineJs()` parameter type mismatch between v1.5 and v1.6 [#2659](https://github.com/getgrav/grav/issues/2659)
* Fixed `site.metadata` saving issues [#2615](https://github.com/getgrav/grav/issues/2615)
# v1.6.19
## 12/04/2019
1. [](#new)
* Catch PHP 7.4 deprecation messages and report them in debugbar instead of throwing fatal error
1. [](#bugfix)
* Fixed fatal error when calling `{{ grav.undefined }}`
* Fixed multiple issues when there are no pages in the site
* PHP 7.4 fix for [#2750](https://github.com/getgrav/grav/issues/2750)
# v1.6.18
## 12/02/2019
1. [](#bugfix)
* PHP 7.4 fix in `Pages::buildSort()`
* Updated vendor libraries for PHP 7.4 fixes in Twig and other libraries
* Fixed fatal error when `$page->id()` is null [#2731](https://github.com/getgrav/grav/pull/2731)
* Fixed cache conflicts on pages with no set id
* Fix rewrite rule for for `lighttpd` default config [#721](https://github.com/getgrav/grav/pull/2721)
# v1.6.17
## 11/06/2019
1. [](#new)
* Added working ETag (304 Not Modified) support based on the final rendered HTML
1. [](#improved)
* Safer file handling + customizable null char replacement in `CsvFormatter::decode()`
* Change of Behavior: `Inflector::hyphenize` will now automatically trim dashes at beginning and end of a string.
* Change in Behavior for `Folder::all()` so no longer fails if trying to copy non-existent dot file [#2581](https://github.com/getgrav/grav/pull/2581)
* renamed composer `test-plugins` script to `phpstan-plugins` to be more explicit [#2637](https://github.com/getgrav/grav/pull/2637)
1. [](#bugfix)
* Fixed PHP 7.1 bug in FlexMedia
* Fix cache image generation when using cropResize [#2639](https://github.com/getgrav/grav/pull/2639)
* Fix `array_merge()` exception with non-array page header metadata [#2701](https://github.com/getgrav/grav/pull/2701)
# v1.6.16 # v1.6.16
## 09/19/2019 ## 09/19/2019
+8 -1
View File
@@ -28,6 +28,13 @@ if (!ini_get('date.timezone')) {
date_default_timezone_set('UTC'); date_default_timezone_set('UTC');
} }
// Set internal encoding.
if (!\extension_loaded('mbstring')) {
die("'mbstring' extension is not loaded. This is required for Grav to run correctly");
}
@ini_set('default_charset', 'UTF-8');
mb_internal_encoding('UTF-8');
if (!file_exists(GRAV_ROOT . '/index.php')) { if (!file_exists(GRAV_ROOT . '/index.php')) {
exit('FATAL: Must be run from ROOT directory of Grav!'); exit('FATAL: Must be run from ROOT directory of Grav!');
} }
@@ -55,7 +62,7 @@ $grav->setup($environment);
$grav['config']->init(); $grav['config']->init();
$grav['uri']->init(); $grav['uri']->init();
$grav['users']; $grav['accounts'];
$app = new Application('Grav Package Manager', GRAV_VERSION); $app = new Application('Grav Package Manager', GRAV_VERSION);
$app->addCommands(array( $app->addCommands(array(
+11 -4
View File
@@ -25,6 +25,17 @@ if (version_compare($ver = PHP_VERSION, $req = GRAV_PHP_MIN, '<')) {
exit(sprintf("You are running PHP %s, but Grav needs at least PHP %s to run.\n", $ver, $req)); exit(sprintf("You are running PHP %s, but Grav needs at least PHP %s to run.\n", $ver, $req));
} }
if (!ini_get('date.timezone')) {
date_default_timezone_set('UTC');
}
// Set internal encoding.
if (!\extension_loaded('mbstring')) {
die("'mbstring' extension is not loaded. This is required for Grav to run correctly");
}
@ini_set('default_charset', 'UTF-8');
mb_internal_encoding('UTF-8');
$climate = new League\CLImate\CLImate; $climate = new League\CLImate\CLImate;
$climate->arguments->add([ $climate->arguments->add([
'environment' => [ 'environment' => [
@@ -42,10 +53,6 @@ $environment = $climate->arguments->get('environment');
$grav = Grav::instance(array('loader' => $autoload)); $grav = Grav::instance(array('loader' => $autoload));
$grav->setup($environment); $grav->setup($environment);
if (!ini_get('date.timezone')) {
date_default_timezone_set('UTC');
}
if (!file_exists(GRAV_ROOT . '/index.php')) { if (!file_exists(GRAV_ROOT . '/index.php')) {
exit('FATAL: Must be run from ROOT directory of Grav!'); exit('FATAL: Must be run from ROOT directory of Grav!');
} }
+8 -6
View File
@@ -32,6 +32,13 @@ if (!ini_get('date.timezone')) {
date_default_timezone_set('UTC'); date_default_timezone_set('UTC');
} }
// Set internal encoding.
if (!\extension_loaded('mbstring')) {
die("'mbstring' extension is not loaded. This is required for Grav to run correctly");
}
@ini_set('default_charset', 'UTF-8');
mb_internal_encoding('UTF-8');
if (!file_exists(GRAV_ROOT . '/index.php')) { if (!file_exists(GRAV_ROOT . '/index.php')) {
exit('FATAL: Must be run from ROOT directory of Grav!'); exit('FATAL: Must be run from ROOT directory of Grav!');
} }
@@ -51,12 +58,7 @@ $environment = $climate->arguments->get('environment');
$grav = Grav::instance(array('loader' => $autoload)); $grav = Grav::instance(array('loader' => $autoload));
$grav->setup($environment); $grav->setup($environment);
$grav->initializeCli();
$grav['config']->init();
$grav['uri']->init();
$grav['users'];
$grav['plugins']->init();
$grav['themes']->init();
$app = new Application('Grav Plugins Commands', GRAV_VERSION); $app = new Application('Grav Plugins Commands', GRAV_VERSION);
$pattern = '([A-Z]\w+Command\.php)'; $pattern = '([A-Z]\w+Command\.php)';
+18 -13
View File
@@ -2,7 +2,13 @@
"name": "getgrav/grav", "name": "getgrav/grav",
"type": "project", "type": "project",
"description": "Modern, Crazy Fast, Ridiculously Easy and Amazingly Powerful Flat-File CMS", "description": "Modern, Crazy Fast, Ridiculously Easy and Amazingly Powerful Flat-File CMS",
"keywords": ["cms","flat-file cms","flat cms","flatfile cms","php"], "keywords": [
"cms",
"flat-file cms",
"flat cms",
"flatfile cms",
"php"
],
"homepage": "https://getgrav.org", "homepage": "https://getgrav.org",
"license": "MIT", "license": "MIT",
"require": { "require": {
@@ -16,17 +22,12 @@
"symfony/polyfill-iconv": "^1.9", "symfony/polyfill-iconv": "^1.9",
"symfony/polyfill-php72": "^1.9", "symfony/polyfill-php72": "^1.9",
"symfony/polyfill-php73": "^1.9", "symfony/polyfill-php73": "^1.9",
"psr/simple-cache": "^1.0", "psr/simple-cache": "^1.0",
"psr/http-message": "^1.0", "psr/http-message": "^1.0",
"psr/http-server-middleware": "^1.0", "psr/http-server-middleware": "^1.0",
"kodus/psr7-server": "*", "kodus/psr7-server": "*",
"nyholm/psr7": "^1.0", "nyholm/psr7": "^1.0",
"twig/twig": "~1.40", "twig/twig": "~1.40",
"erusev/parsedown": "1.6.4",
"erusev/parsedown-extra": "~0.7",
"symfony/yaml": "~4.2.0", "symfony/yaml": "~4.2.0",
"symfony/console": "~4.2.0", "symfony/console": "~4.2.0",
"symfony/event-dispatcher": "~4.2.0", "symfony/event-dispatcher": "~4.2.0",
@@ -36,13 +37,12 @@
"doctrine/collections": "^1.5", "doctrine/collections": "^1.5",
"guzzlehttp/psr7": "^1.4", "guzzlehttp/psr7": "^1.4",
"filp/whoops": "~2.2", "filp/whoops": "~2.2",
"matthiasmullie/minify": "^1.3", "matthiasmullie/minify": "^1.3",
"monolog/monolog": "~1.0", "monolog/monolog": "~1.0",
"gregwar/image": "2.*", "gregwar/image": "2.*",
"donatj/phpuseragentparser": "~0.10", "donatj/phpuseragentparser": "~1.0",
"pimple/pimple": "~3.2", "pimple/pimple": "~3.2",
"rockettheme/toolbox": "~1.4", "rockettheme/toolbox": "~1.4.0",
"maximebf/debugbar": "~1.15", "maximebf/debugbar": "~1.15",
"league/climate": "^3.4", "league/climate": "^3.4",
"antoligy/dom-string-iterators": "^1.0", "antoligy/dom-string-iterators": "^1.0",
@@ -50,7 +50,7 @@
"composer/ca-bundle": "^1.0", "composer/ca-bundle": "^1.0",
"dragonmantank/cron-expression": "^1.2", "dragonmantank/cron-expression": "^1.2",
"phive/twig-extensions-deferred": "^1.0", "phive/twig-extensions-deferred": "^1.0",
"willdurand/negotiation": "^2.3" "willdurand/negotiation": "2.x-dev"
}, },
"require-dev": { "require-dev": {
"codeception/codeception": "^2.4", "codeception/codeception": "^2.4",
@@ -83,10 +83,15 @@
"psr-4": { "psr-4": {
"Grav\\": "system/src/Grav" "Grav\\": "system/src/Grav"
}, },
"files": ["system/defines.php"] "files": [
"system/defines.php",
"system/aliases.php"
]
}, },
"archive": { "archive": {
"exclude": ["VERSION"] "exclude": [
"VERSION"
]
}, },
"scripts": { "scripts": {
"api-16": "vendor/bin/phpdoc-md generate system/src > user/pages/14.api/default.16.md", "api-16": "vendor/bin/phpdoc-md generate system/src > user/pages/14.api/default.16.md",
@@ -94,7 +99,7 @@
"post-create-project-cmd": "bin/grav install", "post-create-project-cmd": "bin/grav install",
"phpstan": "vendor/bin/phpstan analyse -l 2 -c ./tests/phpstan/phpstan.neon system/src --memory-limit=256M", "phpstan": "vendor/bin/phpstan analyse -l 2 -c ./tests/phpstan/phpstan.neon system/src --memory-limit=256M",
"phpstan-framework": "vendor/bin/phpstan analyse -l 5 -c ./tests/phpstan/phpstan.neon system/src/Grav/Framework --memory-limit=256M", "phpstan-framework": "vendor/bin/phpstan analyse -l 5 -c ./tests/phpstan/phpstan.neon system/src/Grav/Framework --memory-limit=256M",
"test-plugins": "vendor/bin/phpstan analyse -l 0 -c ./tests/phpstan/plugins.neon user/plugins --memory-limit=256M", "phpstan-plugins": "vendor/bin/phpstan analyse -l 0 -c ./tests/phpstan/plugins.neon user/plugins --memory-limit=256M",
"test": "vendor/bin/codecept run unit", "test": "vendor/bin/codecept run unit",
"test-windows": "vendor\\bin\\codecept run unit" "test-windows": "vendor\\bin\\codecept run unit"
}, },
Generated
+500 -529
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -1,5 +1,5 @@
#!/bin/sh #!/bin/sh
chown -R 1000:www-data . chown -R 1000:http .
find . -type f -exec chmod 664 {} \; find . -type f -exec chmod 664 {} \;
find ./bin -type f -exec chmod 775 {} \; find ./bin -type f -exec chmod 775 {} \;
find . -type d -exec chmod 775 {} \; find . -type d -exec chmod 775 {} \;
+10 -9
View File
@@ -20,6 +20,16 @@ if (PHP_SAPI === 'cli-server' && !isset($_SERVER['PHP_CLI_ROUTER'])) {
die("PHP webserver requires a router to run Grav, please use: <pre>php -S {$_SERVER['SERVER_NAME']}:{$_SERVER['SERVER_PORT']} system/router.php</pre>"); die("PHP webserver requires a router to run Grav, please use: <pre>php -S {$_SERVER['SERVER_NAME']}:{$_SERVER['SERVER_PORT']} system/router.php</pre>");
} }
// Set timezone to default, falls back to system if php.ini not set
date_default_timezone_set(@date_default_timezone_get());
// Set internal encoding.
if (!\extension_loaded('mbstring')) {
die("'mbstring' extension is not loaded. This is required for Grav to run correctly");
}
@ini_set('default_charset', 'UTF-8');
mb_internal_encoding('UTF-8');
// Ensure vendor libraries exist // Ensure vendor libraries exist
$autoload = __DIR__ . '/vendor/autoload.php'; $autoload = __DIR__ . '/vendor/autoload.php';
if (!is_file($autoload)) { if (!is_file($autoload)) {
@@ -32,15 +42,6 @@ $loader = require $autoload;
use Grav\Common\Grav; use Grav\Common\Grav;
use RocketTheme\Toolbox\Event\Event; use RocketTheme\Toolbox\Event\Event;
// Set timezone to default, falls back to system if php.ini not set
date_default_timezone_set(@date_default_timezone_get());
// Set internal encoding if mbstring loaded
if (!\extension_loaded('mbstring')) {
die("'mbstring' extension is not loaded. This is required for Grav to run correctly");
}
mb_internal_encoding('UTF-8');
// Get the Grav instance // Get the Grav instance
$grav = Grav::instance( $grav = Grav::instance(
array( array(
+5
View File
@@ -0,0 +1,5 @@
<?php
/** Moved from non-namespaced classes to Grav Framework */
class_alias(Grav\Framework\Parsedown\Parsedown::class, '\Parsedown');
class_alias(Grav\Framework\Parsedown\ParsedownExtra::class, '\ParsedownExtra');
File diff suppressed because one or more lines are too long
+64 -7
View File
@@ -241,13 +241,15 @@ form:
type: commalist type: commalist
pages.hide_empty_folders: pages.hide_empty_folders:
type: selectize type: toggle
size: large label: PLUGIN_ADMIN.HIDE_EMPTY_FOLDERS
label: PLUGIN_ADMIN.HIDE_EMPTY_FOLDERS help: PLUGIN_ADMIN.HIDE_EMPTY_FOLDERS_HELP
help: PLUGIN_ADMIN.HIDE_EMPTY_FOLDERS_HELP highlight: 0
classes: fancy options:
validate: 1: PLUGIN_ADMIN.YES
type: commalist 0: PLUGIN_ADMIN.NO
validate:
type: bool
pages.url_taxonomy_filters: pages.url_taxonomy_filters:
type: toggle type: toggle
@@ -513,6 +515,16 @@ form:
validate: validate:
type: bool type: bool
pages.markdown.valid_link_attributes:
type: selectize
size: large
label: PLUGIN_ADMIN.VALID_LINK_ATTRIBUTES
help: PLUGIN_ADMIN.VALID_LINK_ATTRIBUTES_HELP
placeholder: "rel, target, id, class, classes"
classes: fancy
validate:
type: commalist
caching: caching:
type: tab type: tab
title: PLUGIN_ADMIN.CACHING title: PLUGIN_ADMIN.CACHING
@@ -1379,6 +1391,51 @@ form:
label: PLUGIN_ADMIN.CUSTOM_BASE_URL label: PLUGIN_ADMIN.CUSTOM_BASE_URL
help: PLUGIN_ADMIN.CUSTOM_BASE_URL_HELP help: PLUGIN_ADMIN.CUSTOM_BASE_URL_HELP
http_x_forwarded.protocol:
type: toggle
label: HTTP_X_FORWARDED_PROTO Enabled
highlight: 1
default: 1
options:
1: PLUGIN_ADMIN.YES
0: PLUGIN_ADMIN.NO
validate:
type: bool
http_x_forwarded.host:
type: toggle
label: HTTP_X_FORWARDED_HOST Enabled
highlight: 0
default: 0
options:
1: PLUGIN_ADMIN.YES
0: PLUGIN_ADMIN.NO
validate:
type: bool
http_x_forwarded.port:
type: toggle
label: HTTP_X_FORWARDED_PORT Enabled
highlight: 1
default: 1
options:
1: PLUGIN_ADMIN.YES
0: PLUGIN_ADMIN.NO
validate:
type: bool
http_x_forwarded.ip:
type: toggle
label: HTTP_X_FORWARDED IP Enabled
highlight: 1
default: 1
options:
1: PLUGIN_ADMIN.YES
0: PLUGIN_ADMIN.NO
validate:
type: bool
accounts.type: accounts.type:
type: hidden type: hidden
+11
View File
@@ -10,6 +10,11 @@ custom_base_url: '' # Set the base_url manually, e.
username_regex: '^[a-z0-9_-]{3,16}$' # Only lowercase chars, digits, dashes, underscores. 3 - 16 chars username_regex: '^[a-z0-9_-]{3,16}$' # Only lowercase chars, digits, dashes, underscores. 3 - 16 chars
pwd_regex: '(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,}' # At least one number, one uppercase and lowercase letter, and be at least 8+ chars pwd_regex: '(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,}' # At least one number, one uppercase and lowercase letter, and be at least 8+ chars
intl_enabled: true # Special logic for PHP International Extension (mod_intl) intl_enabled: true # Special logic for PHP International Extension (mod_intl)
http_x_forwarded: # Configuration options for the various HTTP_X_FORWARD headers
protocol: true
host: false
port: true
ip: true
languages: languages:
supported: [] # List of languages supported. eg: [en, fr, de] supported: [] # List of languages supported. eg: [en, fr, de]
@@ -54,6 +59,12 @@ pages:
special_chars: # List of special characters to automatically convert to entities special_chars: # List of special characters to automatically convert to entities
'>': 'gt' '>': 'gt'
'<': 'lt' '<': 'lt'
valid_link_attributes: # Valid attributes to pass through via markdown links
- rel
- target
- id
- class
- classes
types: [html,htm,xml,txt,json,rss,atom] # list of valid page types types: [html,htm,xml,txt,json,rss,atom] # list of valid page types
append_url_extension: '' # Append page's extension in Page urls (e.g. '.html' results in /path/page.html) append_url_extension: '' # Append page's extension in Page urls (e.g. '.html' results in /path/page.html)
expires: 604800 # Page expires time in seconds (604800 seconds = 7 days) expires: 604800 # Page expires time in seconds (604800 seconds = 7 days)
+1 -1
View File
@@ -8,7 +8,7 @@
// Some standard defines // Some standard defines
define('GRAV', true); define('GRAV', true);
define('GRAV_VERSION', '1.6.16'); define('GRAV_VERSION', '1.6.27');
define('GRAV_TESTING', false); define('GRAV_TESTING', false);
define('DS', '/'); define('DS', '/');
@@ -51,7 +51,11 @@ trait LegacyAssetsTrait
// special case to handle old attributes being passed in // special case to handle old attributes being passed in
if (isset($arguments['attributes'])) { if (isset($arguments['attributes'])) {
$old_attributes = $arguments['attributes']; $old_attributes = $arguments['attributes'];
$arguments = array_merge($arguments, $old_attributes); if (is_array($old_attributes)) {
$arguments = array_merge($arguments, $old_attributes);
} else {
$arguments['type'] = $old_attributes;
}
} }
unset($arguments['attributes']); unset($arguments['attributes']);
+2
View File
@@ -9,6 +9,8 @@
namespace Grav\Common; namespace Grav\Common;
use function donatj\UserAgent\parse_user_agent;
/** /**
* Internally uses the PhpUserAgent package https://github.com/donatj/PhpUserAgent * Internally uses the PhpUserAgent package https://github.com/donatj/PhpUserAgent
*/ */
@@ -136,7 +136,7 @@ class BlueprintSchema extends BlueprintSchemaBase implements ExportInterface
{ {
$messages = $this->checkRequired($data, $rules); $messages = $this->checkRequired($data, $rules);
foreach ($data as $key => $field) { foreach ($data as $key => $child) {
$val = $rules[$key] ?? $rules['*'] ?? null; $val = $rules[$key] ?? $rules['*'] ?? null;
$rule = \is_string($val) ? $this->items[$val] : null; $rule = \is_string($val) ? $this->items[$val] : null;
@@ -147,10 +147,10 @@ class BlueprintSchema extends BlueprintSchemaBase implements ExportInterface
continue; continue;
} }
$messages += Validation::validate($field, $rule); $messages += Validation::validate($child, $rule);
} elseif (\is_array($field) && \is_array($val)) { } elseif (\is_array($child) && \is_array($val)) {
// Array has been defined in blueprints. // Array has been defined in blueprints.
$messages += $this->validateArray($field, $val); $messages += $this->validateArray($child, $val);
} elseif (isset($rules['validation']) && $rules['validation'] === 'strict') { } elseif (isset($rules['validation']) && $rules['validation'] === 'strict') {
// Undefined/extra item. // Undefined/extra item.
throw new \RuntimeException(sprintf('%s is not defined in blueprints', $key)); throw new \RuntimeException(sprintf('%s is not defined in blueprints', $key));
+30 -2
View File
@@ -32,6 +32,12 @@ class Data implements DataInterface, \ArrayAccess, \Countable, \JsonSerializable
/** @var File */ /** @var File */
protected $storage; protected $storage;
/** @var bool */
private $missingValuesAsNull = false;
/** @var bool */
private $keepEmptyValues = true;
/** /**
* @param array $items * @param array $items
* @param Blueprint|callable $blueprints * @param Blueprint|callable $blueprints
@@ -42,6 +48,28 @@ class Data implements DataInterface, \ArrayAccess, \Countable, \JsonSerializable
$this->blueprints = $blueprints; $this->blueprints = $blueprints;
} }
/**
* @param bool $value
* @return $this
*/
public function setKeepEmptyValues(bool $value)
{
$this->keepEmptyValues = $value;
return $this;
}
/**
* @param bool $value
* @return $this
*/
public function setMissingValuesAsNull(bool $value)
{
$this->missingValuesAsNull = $value;
return $this;
}
/** /**
* Get value by using dot notation for nested arrays/objects. * Get value by using dot notation for nested arrays/objects.
* *
@@ -202,8 +230,8 @@ class Data implements DataInterface, \ArrayAccess, \Countable, \JsonSerializable
public function filter() public function filter()
{ {
$args = func_get_args(); $args = func_get_args();
$missingValuesAsNull = (bool)(array_shift($args) ?: false); $missingValuesAsNull = (bool)(array_shift($args) ?? $this->missingValuesAsNull);
$keepEmptyValues = (bool)(array_shift($args) ?: false); $keepEmptyValues = (bool)(array_shift($args) ?? $this->keepEmptyValues);
$this->items = $this->blueprints()->filter($this->items, $missingValuesAsNull, $keepEmptyValues); $this->items = $this->blueprints()->filter($this->items, $missingValuesAsNull, $keepEmptyValues);
+10 -1
View File
@@ -166,9 +166,18 @@ class Validation
return (string) $value; return (string) $value;
} }
/**
* @param mixed $value
* @param array $params
* @param array $field
* @return string|null
*/
protected static function filterCheckbox($value, array $params, array $field) protected static function filterCheckbox($value, array $params, array $field)
{ {
return (bool) $value; $value = (string)$value;
$field_value = (string)($field['value'] ?? '1');
return $value === $field_value ? $value : null;
} }
protected static function filterCommaList($value, array $params, array $field) protected static function filterCommaList($value, array $params, array $field)
+1 -1
View File
@@ -347,7 +347,7 @@ class Debugger
*/ */
public function deprecatedErrorHandler($errno, $errstr, $errfile, $errline) public function deprecatedErrorHandler($errno, $errstr, $errfile, $errline)
{ {
if ($errno !== E_USER_DEPRECATED) { if ($errno !== E_USER_DEPRECATED && $errno !== E_DEPRECATED) {
if ($this->errorHandler) { if ($this->errorHandler) {
return \call_user_func($this->errorHandler, $errno, $errstr, $errfile, $errline); return \call_user_func($this->errorHandler, $errno, $errstr, $errfile, $errline);
} }
+26 -12
View File
@@ -22,6 +22,10 @@ abstract class Folder
*/ */
public static function lastModifiedFolder($path) public static function lastModifiedFolder($path)
{ {
if (!file_exists($path)) {
return 0;
}
$last_modified = 0; $last_modified = 0;
/** @var UniformResourceLocator $locator */ /** @var UniformResourceLocator $locator */
@@ -56,6 +60,10 @@ abstract class Folder
*/ */
public static function lastModifiedFile($path, $extensions = 'md|yaml') public static function lastModifiedFile($path, $extensions = 'md|yaml')
{ {
if (!file_exists($path)) {
return 0;
}
$last_modified = 0; $last_modified = 0;
/** @var UniformResourceLocator $locator */ /** @var UniformResourceLocator $locator */
@@ -92,21 +100,24 @@ abstract class Folder
*/ */
public static function hashAllFiles($path) public static function hashAllFiles($path)
{ {
$flags = \RecursiveDirectoryIterator::SKIP_DOTS;
$files = []; $files = [];
/** @var UniformResourceLocator $locator */ if (file_exists($path)) {
$locator = Grav::instance()['locator']; $flags = \RecursiveDirectoryIterator::SKIP_DOTS;
if ($locator->isStream($path)) {
$directory = $locator->getRecursiveIterator($path, $flags);
} else {
$directory = new \RecursiveDirectoryIterator($path, $flags);
}
$iterator = new \RecursiveIteratorIterator($directory, \RecursiveIteratorIterator::SELF_FIRST); /** @var UniformResourceLocator $locator */
$locator = Grav::instance()['locator'];
if ($locator->isStream($path)) {
$directory = $locator->getRecursiveIterator($path, $flags);
} else {
$directory = new \RecursiveDirectoryIterator($path, $flags);
}
foreach ($iterator as $file) { $iterator = new \RecursiveIteratorIterator($directory, \RecursiveIteratorIterator::SELF_FIRST);
$files[] = $file->getPathname() . '?'. $file->getMTime();
foreach ($iterator as $file) {
$files[] = $file->getPathname() . '?'. $file->getMTime();
}
} }
return md5(serialize($files)); return md5(serialize($files));
@@ -199,6 +210,9 @@ abstract class Folder
if ($path === false) { if ($path === false) {
throw new \RuntimeException("Path doesn't exist."); throw new \RuntimeException("Path doesn't exist.");
} }
if (!file_exists($path)) {
return [];
}
$compare = isset($params['compare']) ? 'get' . $params['compare'] : null; $compare = isset($params['compare']) ? 'get' . $params['compare'] : null;
$pattern = $params['pattern'] ?? null; $pattern = $params['pattern'] ?? null;
@@ -235,7 +249,7 @@ abstract class Folder
/** @var \RecursiveDirectoryIterator $file */ /** @var \RecursiveDirectoryIterator $file */
foreach ($iterator as $file) { foreach ($iterator as $file) {
// Ignore hidden files. // Ignore hidden files.
if (strpos($file->getFilename(), '.') === 0) { if (strpos($file->getFilename(), '.') === 0 && $file->isFile()) {
continue; continue;
} }
if (!$folders && $file->isDir()) { if (!$folders && $file->isDir()) {
+2 -1
View File
@@ -11,6 +11,7 @@ namespace Grav\Common\GPM\Local;
use Grav\Common\Data\Data; use Grav\Common\Data\Data;
use Grav\Common\GPM\Common\Package as BasePackage; use Grav\Common\GPM\Common\Package as BasePackage;
use Grav\Framework\Parsedown\Parsedown;
class Package extends BasePackage class Package extends BasePackage
{ {
@@ -23,7 +24,7 @@ class Package extends BasePackage
$this->settings = $package->toArray(); $this->settings = $package->toArray();
$html_description = \Parsedown::instance()->line($this->__get('description')); $html_description = Parsedown::instance()->line($this->__get('description'));
$this->data->set('slug', $package->__get('slug')); $this->data->set('slug', $package->__get('slug'));
$this->data->set('description_html', $html_description); $this->data->set('description_html', $html_description);
$this->data->set('description_plain', strip_tags($html_description)); $this->data->set('description_plain', strip_tags($html_description));
+1 -1
View File
@@ -409,7 +409,7 @@ class Response
} else { } else {
$code = (int)curl_getinfo($rch, CURLINFO_HTTP_CODE); $code = (int)curl_getinfo($rch, CURLINFO_HTTP_CODE);
if ($code === 301 || $code === 302 || $code === 303) { if ($code === 301 || $code === 302 || $code === 303) {
preg_match('/Location:(.*?)\n/', $header, $matches); preg_match('/(?:^|\n)Location:(.*?)\n/i', $header, $matches);
$uri = trim(array_pop($matches)); $uri = trim(array_pop($matches));
} else { } else {
$code = 0; $code = 0;
+47 -4
View File
@@ -170,6 +170,29 @@ class Grav extends Container
return $this; return $this;
} }
/**
* Initialize CLI environment.
*
* Call after `$grav->setup($environment)`
*
* - Load configuration
* - Disable debugger
* - Set timezone, locale
* - Load plugins
* - Set Users type to be used in the site
*
* This method WILL NOT initialize assets, twig or pages.
*
* @param string|null $environment
* @return $this
*/
public function initializeCli()
{
InitializeProcessor::initializeCli($this);
return $this;
}
/** /**
* Process a request * Process a request
*/ */
@@ -247,9 +270,21 @@ class Grav extends Container
$collection = new RequestHandler($this->middleware, $default, $container); $collection = new RequestHandler($this->middleware, $default, $container);
$response = $collection->handle($this['request']); $response = $collection->handle($this['request']);
$body = $response->getBody();
// Handle ETag and If-None-Match headers.
if ($response->getHeaderLine('ETag') === '1') {
$etag = md5($body);
$response = $response->withHeader('ETag', $etag);
if ($this['request']->getHeaderLine('If-None-Match') === $etag) {
$response = $response->withStatus(304);
$body = '';
}
}
$this->header($response); $this->header($response);
echo $response->getBody(); echo $body;
$debugger->render(); $debugger->render();
@@ -281,7 +316,10 @@ class Grav extends Container
/** @var Uri $uri */ /** @var Uri $uri */
$uri = $this['uri']; $uri = $this['uri'];
//Check for code in route // Clean route for redirect
$route = preg_replace("#^\/[\\\/]+\/#", '/', $route);
// Check for code in route
$regex = '/.*(\[(30[1-7])\])$/'; $regex = '/.*(\[(30[1-7])\])$/';
preg_match($regex, $route, $matches); preg_match($regex, $route, $matches);
if ($matches) { if ($matches) {
@@ -427,11 +465,16 @@ class Grav extends Container
* Used to call closures. * Used to call closures.
* *
* Source: http://stackoverflow.com/questions/419804/closures-as-class-members * Source: http://stackoverflow.com/questions/419804/closures-as-class-members
*
* @param string $method
* @param array $args
* @return
*/ */
public function __call($method, $args) public function __call($method, $args)
{ {
$closure = $this->{$method}; $closure = $this->{$method} ?? null;
\call_user_func_array($closure, $args);
return is_callable($closure) ? $closure(...$args) : null;
} }
/** /**
+2
View File
@@ -193,6 +193,8 @@ class Inflector
$regex3 = preg_replace('/([0-9])([A-Z])/', '\1-\2', $regex2); $regex3 = preg_replace('/([0-9])([A-Z])/', '\1-\2', $regex2);
$regex4 = preg_replace('/[^A-Z^a-z^0-9]+/', '-', $regex3); $regex4 = preg_replace('/[^A-Z^a-z^0-9]+/', '-', $regex3);
$regex4 = trim($regex4, '-');
return strtolower($regex4); return strtolower($regex4);
} }
@@ -11,8 +11,9 @@ namespace Grav\Common\Markdown;
use Grav\Common\Page\Interfaces\PageInterface; use Grav\Common\Page\Interfaces\PageInterface;
use Grav\Common\Page\Markdown\Excerpts; use Grav\Common\Page\Markdown\Excerpts;
use Grav\Framework\Parsedown\Parsedown as ParsedownLib;
class Parsedown extends \Parsedown class Parsedown extends ParsedownLib
{ {
use ParsedownGravTrait; use ParsedownGravTrait;
@@ -11,8 +11,9 @@ namespace Grav\Common\Markdown;
use Grav\Common\Page\Interfaces\PageInterface; use Grav\Common\Page\Interfaces\PageInterface;
use Grav\Common\Page\Markdown\Excerpts; use Grav\Common\Page\Markdown\Excerpts;
use Grav\Framework\Parsedown\ParsedownExtra as ParsedownExtraLib;
class ParsedownExtra extends \ParsedownExtra class ParsedownExtra extends ParsedownExtraLib
{ {
use ParsedownGravTrait; use ParsedownGravTrait;
@@ -125,5 +125,5 @@ trait MediaTrait
/** /**
* @return string * @return string
*/ */
abstract protected function getCacheKey(); abstract protected function getCacheKey(): string;
} }
@@ -87,7 +87,7 @@ class Excerpts
); );
// Valid attributes supported. // Valid attributes supported.
$valid_attributes = ['rel', 'target', 'id', 'class', 'classes']; $valid_attributes = Grav::instance()['config']->get('system.pages.markdown.valid_link_attributes');
// Unless told to not process, go through actions. // Unless told to not process, go through actions.
if (array_key_exists('noprocess', $actions)) { if (array_key_exists('noprocess', $actions)) {
@@ -232,6 +232,7 @@ class Excerpts
$url_parts = is_string($url) ? $this->parseUrl($url) : $url; $url_parts = is_string($url) ? $this->parseUrl($url) : $url;
$actions = []; $actions = [];
// if there is a query, then parse it and build action calls // if there is a query, then parse it and build action calls
if (isset($url_parts['query'])) { if (isset($url_parts['query'])) {
$actions = array_reduce( $actions = array_reduce(
@@ -516,6 +516,15 @@ class ImageMedium extends Medium
return $this; return $this;
} }
/**
* Handle this commonly used variant
*/
public function cropZoom()
{
$this->__call('zoomCrop', func_get_args());
return $this;
}
/** /**
* Forward the call to the image processing method. * Forward the call to the image processing method.
* *
@@ -525,10 +534,6 @@ class ImageMedium extends Medium
*/ */
public function __call($method, $args) public function __call($method, $args)
{ {
if ($method === 'cropZoom') {
$method = 'zoomCrop';
}
if (!\in_array($method, self::$magic_actions, true)) { if (!\in_array($method, self::$magic_actions, true)) {
return parent::__call($method, $args); return parent::__call($method, $args);
} }
+14 -10
View File
@@ -529,9 +529,9 @@ class Page implements PageInterface
$headers['Last-Modified'] = $last_modified_date; $headers['Last-Modified'] = $last_modified_date;
} }
// Calculate ETag based on the raw file // Ask Grav to calculate ETag from the final content.
if ($this->eTag()) { if ($this->eTag()) {
$headers['ETag'] = '"' . md5($this->raw() . $this->modified()).'"'; $headers['ETag'] = '1';
} }
// Set Vary: Accept-Encoding header // Set Vary: Accept-Encoding header
@@ -608,12 +608,12 @@ class Page implements PageInterface
return $content; return $content;
} }
return mb_strimwidth($content, 0, $size, '...', 'utf-8'); return mb_strimwidth($content, 0, $size, '', 'UTF-8');
} }
$summary = Utils::truncateHtml($content, $size); $summary = Utils::truncateHtml($content, $size);
return html_entity_decode($summary); return html_entity_decode($summary, ENT_COMPAT | ENT_HTML401, 'UTF-8');
} }
/** /**
@@ -659,7 +659,7 @@ class Page implements PageInterface
// Load cached content // Load cached content
/** @var Cache $cache */ /** @var Cache $cache */
$cache = Grav::instance()['cache']; $cache = Grav::instance()['cache'];
$cache_id = md5('page' . $this->id()); $cache_id = md5('page' . $this->getCacheKey());
$content_obj = $cache->fetch($cache_id); $content_obj = $cache->fetch($cache_id);
if (is_array($content_obj)) { if (is_array($content_obj)) {
@@ -865,7 +865,7 @@ class Page implements PageInterface
public function cachePageContent() public function cachePageContent()
{ {
$cache = Grav::instance()['cache']; $cache = Grav::instance()['cache'];
$cache_id = md5('page' . $this->id()); $cache_id = md5('page' . $this->getCacheKey());
$cache->save($cache_id, ['content' => $this->content, 'content_meta' => $this->content_meta]); $cache->save($cache_id, ['content' => $this->content, 'content_meta' => $this->content_meta]);
} }
@@ -1200,7 +1200,7 @@ class Page implements PageInterface
/** /**
* @return string * @return string
*/ */
protected function getCacheKey() public function getCacheKey(): string
{ {
return $this->id(); return $this->id();
} }
@@ -1694,9 +1694,9 @@ class Page implements PageInterface
$metadata['generator'] = 'GravCMS'; $metadata['generator'] = 'GravCMS';
// Get initial metadata for the page // Get initial metadata for the page
$metadata = array_merge($metadata, Grav::instance()['config']->get('site.metadata')); $metadata = array_merge($metadata, Grav::instance()['config']->get('site.metadata', []));
if (isset($this->header->metadata)) { if (isset($this->header->metadata) && is_array($this->header->metadata)) {
// Merge any site.metadata settings in with page metadata // Merge any site.metadata settings in with page metadata
$metadata = array_merge($metadata, $this->header->metadata); $metadata = array_merge($metadata, $this->header->metadata);
} }
@@ -2009,6 +2009,10 @@ class Page implements PageInterface
*/ */
public function id($var = null) public function id($var = null)
{ {
if (null === $this->id) {
// We need to set unique id to avoid potential cache conflicts between pages.
$var = time() . md5($this->filePath());
}
if ($var !== null) { if ($var !== null) {
// store unique per language // store unique per language
$active_lang = Grav::instance()['language']->getLanguage() ?: ''; $active_lang = Grav::instance()['language']->getLanguage() ?: '';
@@ -2824,7 +2828,7 @@ class Page implements PageInterface
if ($pagination) { if ($pagination) {
$params = $collection->params(); $params = $collection->params();
$limit = $params['limit'] ?? 0; $limit = (int)($params['limit'] ?? 0);
$start = !empty($params['pagination']) ? ($uri->currentPage() - 1) * $limit : 0; $start = !empty($params['pagination']) ? ($uri->currentPage() - 1) * $limit : 0;
if ($limit && $collection->count() > $limit) { if ($limit && $collection->count() > $limit) {
+42 -22
View File
@@ -95,6 +95,8 @@ class Pages
protected $initialized = false; protected $initialized = false;
protected $active_lang;
/** /**
* @var Types * @var Types
*/ */
@@ -143,7 +145,7 @@ class Pages
*/ */
public function baseRoute($lang = null) public function baseRoute($lang = null)
{ {
$key = $lang ?: 'default'; $key = $lang ?: $this->active_lang ?: 'default';
if (!isset($this->baseRoute[$key])) { if (!isset($this->baseRoute[$key])) {
/** @var Language $language */ /** @var Language $language */
@@ -236,6 +238,16 @@ class Pages
$this->check_method = strtolower($method); $this->check_method = strtolower($method);
} }
/**
* Reset pages (used in search indexing etc).
*/
public function reset()
{
$this->initialized = false;
$this->init();
}
/** /**
* Class initialization. Must be called before using this class. * Class initialization. Must be called before using this class.
*/ */
@@ -958,6 +970,9 @@ class Pages
$pages_dir = $locator->findResource('page://'); $pages_dir = $locator->findResource('page://');
// Set active language
$this->active_lang = $language->getActive();
if ($config->get('system.cache.enabled')) { if ($config->get('system.cache.enabled')) {
/** @var Cache $cache */ /** @var Cache $cache */
$cache = $this->grav['cache']; $cache = $this->grav['cache'];
@@ -982,17 +997,19 @@ class Pages
$this->pages_cache_id = md5($pages_dir . $hash . $language->getActive() . $config->checksum()); $this->pages_cache_id = md5($pages_dir . $hash . $language->getActive() . $config->checksum());
list($this->instances, $this->routes, $this->children, $taxonomy_map, $this->sort) = $cache->fetch($this->pages_cache_id); $cached = $cache->fetch($this->pages_cache_id);
if (!$this->instances) { if ($cached) {
$this->grav['debugger']->addMessage('Page cache hit.');
list($this->instances, $this->routes, $this->children, $taxonomy_map, $this->sort) = $cached;
// If pages was found in cache, set the taxonomy
$taxonomy->taxonomy($taxonomy_map);
} else {
$this->grav['debugger']->addMessage('Page cache missed, rebuilding pages..'); $this->grav['debugger']->addMessage('Page cache missed, rebuilding pages..');
// recurse pages and cache result // recurse pages and cache result
$this->resetPages($pages_dir); $this->resetPages($pages_dir);
} else {
// If pages was found in cache, set the taxonomy
$this->grav['debugger']->addMessage('Page cache hit.');
$taxonomy->taxonomy($taxonomy_map);
} }
} else { } else {
$this->recurse($pages_dir); $this->recurse($pages_dir);
@@ -1261,14 +1278,13 @@ class Pages
{ {
$list = []; $list = [];
$header_default = null; $header_default = null;
$header_query = null; $header_query = [];
// do this header query work only once // do this header query work only once
if (strpos($order_by, 'header.') === 0) { if (strpos($order_by, 'header.') === 0) {
$header_query = explode('|', str_replace('header.', '', $order_by)); $query = explode('|', str_replace('header.', '', $order_by), 2);
if (isset($header_query[1])) { $header_query = array_shift($query) ?? '';
$header_default = $header_query[1]; $header_default = array_shift($query);
}
} }
foreach ($pages as $key => $info) { foreach ($pages as $key => $info) {
@@ -1306,11 +1322,17 @@ class Pages
case 'folder': case 'folder':
$list[$key] = $child->folder(); $list[$key] = $child->folder();
break; break;
case (is_string($header_query[0])): case 'manual':
$child_header = new Header((array)$child->header()); case 'default':
$header_value = $child_header->get($header_query[0]); default:
if (is_string($header_query)) {
$child_header = $child->header();
if (!$child_header instanceof Header) {
$child_header = new Header((array)$child_header);
}
$header_value = $child_header->get($header_query);
if (is_array($header_value)) { if (is_array($header_value)) {
$list[$key] = implode(',',$header_value); $list[$key] = implode(',', $header_value);
} elseif ($header_value) { } elseif ($header_value) {
$list[$key] = $header_value; $list[$key] = $header_value;
} else { } else {
@@ -1318,11 +1340,9 @@ class Pages
} }
$sort_flags = $sort_flags ?: SORT_REGULAR; $sort_flags = $sort_flags ?: SORT_REGULAR;
break; break;
case 'manual': }
case 'default': $list[$key] = $key;
default: $sort_flags = $sort_flags ?: SORT_REGULAR;
$list[$key] = $key;
$sort_flags = $sort_flags ?: SORT_REGULAR;
} }
} }
+1 -1
View File
@@ -305,7 +305,7 @@ class Plugin implements EventSubscriberInterface, \ArrayAccess
// Create new config object and set it on the page object so it's cached for next time // Create new config object and set it on the page object so it's cached for next time
$page->modifyHeader($class_name_merged, new Data($header)); $page->modifyHeader($class_name_merged, new Data($header));
} else if (isset($page_header->{$class_name_merged})) { } elseif (isset($page_header->{$class_name_merged})) {
$merged = $page_header->{$class_name_merged}; $merged = $page_header->{$class_name_merged};
$header = $merged->toArray(); $header = $merged->toArray();
} }
@@ -10,6 +10,7 @@
namespace Grav\Common\Processors; namespace Grav\Common\Processors;
use Grav\Common\Config\Config; use Grav\Common\Config\Config;
use Grav\Common\Grav;
use Grav\Common\Uri; use Grav\Common\Uri;
use Grav\Common\Utils; use Grav\Common\Utils;
use Grav\Framework\Session\Exceptions\SessionException; use Grav\Framework\Session\Exceptions\SessionException;
@@ -22,6 +23,22 @@ class InitializeProcessor extends ProcessorBase
public $id = 'init'; public $id = 'init';
public $title = 'Initialize'; public $title = 'Initialize';
/** @var bool */
private static $cli_initialized = false;
/**
* @param Grav $grav
*/
public static function initializeCli(Grav $grav)
{
if (!static::$cli_initialized) {
static::$cli_initialized = true;
$instance = new static($grav);
$instance->processCli();
}
}
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler) : ResponseInterface public function process(ServerRequestInterface $request, RequestHandlerInterface $handler) : ResponseInterface
{ {
$this->startTimer(); $this->startTimer();
@@ -77,4 +94,35 @@ class InitializeProcessor extends ProcessorBase
return $handler->handle($request); return $handler->handle($request);
} }
public function processCli(): void
{
// Load configuration.
$this->container['config']->init();
$this->container['plugins']->setup();
// Disable debugger.
$this->container['debugger']->enabled(false);
// Set timezone, locale.
/** @var Config $config */
$config = $this->container['config'];
$timezone = $config->get('system.timezone');
if ($timezone) {
date_default_timezone_set($timezone);
}
$this->container->setLocale();
// Load plugins.
$this->container['plugins']->init();
// Initialize URI.
/** @var Uri $uri */
$uri = $this->container['uri'];
$uri->init();
// Load accounts.
// TODO: remove in 2.0.
$this->container['accounts'];
}
} }
+2 -2
View File
@@ -69,7 +69,7 @@ class Cron
'name_year' => 'année', 'name_year' => 'année',
'text_period' => 'Chaque %s', 'text_period' => 'Chaque %s',
'text_mins' => 'à %s minutes', 'text_mins' => 'à %s minutes',
'text_time' => 'à %s:%s', 'text_time' => 'à %02s:%02s',
'text_dow' => 'le %s', 'text_dow' => 'le %s',
'text_month' => 'de %s', 'text_month' => 'de %s',
'text_dom' => 'le %s', 'text_dom' => 'le %s',
@@ -86,7 +86,7 @@ class Cron
'name_year' => 'year', 'name_year' => 'year',
'text_period' => 'Every %s', 'text_period' => 'Every %s',
'text_mins' => 'at %s minutes past the hour', 'text_mins' => 'at %s minutes past the hour',
'text_time' => 'at %s:%s', 'text_time' => 'at %02s:%02s',
'text_dow' => 'on %s', 'text_dow' => 'on %s',
'text_month' => 'of %s', 'text_month' => 'of %s',
'text_dom' => 'on the %s', 'text_dom' => 'on the %s',
@@ -26,6 +26,19 @@ class PagesServiceProvider implements ServiceProviderInterface
return new Pages($c); return new Pages($c);
}; };
if (\defined('GRAV_CLI')) {
$container['page'] = static function ($c) {
$path = $c['locator']->findResource('system://pages/notfound.md');
$page = new Page();
$page->init(new \SplFileInfo($path));
$page->routable(false);
return $page;
};
return;
}
$container['page'] = function ($c) { $container['page'] = function ($c) {
/** @var Grav $c */ /** @var Grav $c */
@@ -1055,7 +1055,7 @@ class TwigExtension extends \Twig_Extension implements \Twig_Extension_GlobalsIn
*/ */
public function jsonDecodeFilter($str, $assoc = false, $depth = 512, $options = 0) public function jsonDecodeFilter($str, $assoc = false, $depth = 512, $options = 0)
{ {
return json_decode(html_entity_decode($str), $assoc, $depth, $options); return json_decode(html_entity_decode($str, ENT_COMPAT | ENT_HTML401, 'UTF-8'), $assoc, $depth, $options);
} }
/** /**
+22 -17
View File
@@ -151,7 +151,7 @@ class Uri
$this->url = $this->base . $this->uri; $this->url = $this->base . $this->uri;
$uri = str_replace(static::filterPath($this->root), '', $this->url); $uri = Utils::replaceFirstOccurrence(static::filterPath($this->root), '', $this->url);
// remove the setup.php based base if set: // remove the setup.php based base if set:
$setup_base = $grav['pages']->base(); $setup_base = $grav['pages']->base();
@@ -195,7 +195,7 @@ class Uri
// set the new url // set the new url
$this->url = $this->root . $path; $this->url = $this->root . $path;
$this->path = static::cleanPath($path); $this->path = static::cleanPath($path);
$this->content_path = trim(str_replace($this->base, '', $this->path), '/'); $this->content_path = trim(Utils::replaceFirstOccurrence($this->base, '', $this->path), '/');
if ($this->content_path !== '') { if ($this->content_path !== '') {
$this->paths = explode('/', $this->content_path); $this->paths = explode('/', $this->content_path);
} }
@@ -306,7 +306,7 @@ class Uri
public function param($id) public function param($id)
{ {
if (isset($this->params[$id])) { if (isset($this->params[$id])) {
return html_entity_decode(rawurldecode($this->params[$id])); return html_entity_decode(rawurldecode($this->params[$id]), ENT_COMPAT | ENT_HTML401, 'UTF-8');
} }
return false; return false;
@@ -340,7 +340,7 @@ class Uri
return $this->url; return $this->url;
} }
$url = str_replace($this->base, '', rtrim($this->url, '/')); $url = Utils::replaceFirstOccurrence($this->base, '', rtrim($this->url, '/'));
return $url ?: '/'; return $url ?: '/';
} }
@@ -489,7 +489,7 @@ class Uri
return $this->uri; return $this->uri;
} }
return str_replace($this->root_path, '', $this->uri); return Utils::replaceFirstOccurrence($this->root_path, '', $this->uri);
} }
/** /**
@@ -531,7 +531,7 @@ class Uri
return $this->root; return $this->root;
} }
return str_replace($this->base, '', $this->root); return Utils::replaceFirstOccurrence($this->base, '', $this->root);
} }
/** /**
@@ -541,7 +541,9 @@ class Uri
*/ */
public function currentPage() public function currentPage()
{ {
return $this->params['page'] ?? 1; $page = (int)($this->params['page'] ?? 1);
return max(1, $page);
} }
/** /**
@@ -629,9 +631,9 @@ class Uri
{ {
if (getenv('HTTP_CLIENT_IP')) { if (getenv('HTTP_CLIENT_IP')) {
$ip = getenv('HTTP_CLIENT_IP'); $ip = getenv('HTTP_CLIENT_IP');
} elseif (getenv('HTTP_X_FORWARDED_FOR')) { } elseif (getenv('HTTP_X_FORWARDED_FOR') && Grav::instance()['config']->get('system.http_x_forwarded.ip')) {
$ip = getenv('HTTP_X_FORWARDED_FOR'); $ip = getenv('HTTP_X_FORWARDED_FOR');
} elseif (getenv('HTTP_X_FORWARDED')) { } elseif (getenv('HTTP_X_FORWARDED') && Grav::instance()['config']->get('system.http_x_forwarded.ip')) {
$ip = getenv('HTTP_X_FORWARDED'); $ip = getenv('HTTP_X_FORWARDED');
} elseif (getenv('HTTP_FORWARDED_FOR')) { } elseif (getenv('HTTP_FORWARDED_FOR')) {
$ip = getenv('HTTP_FORWARDED_FOR'); $ip = getenv('HTTP_FORWARDED_FOR');
@@ -783,7 +785,7 @@ class Uri
} }
// special check to see if path checking is required. // special check to see if path checking is required.
$just_path = str_replace($normalized_url, '', $normalized_path); $just_path = Utils::replaceFirstOccurrence($normalized_url, '', $normalized_path);
if ($normalized_url === '/' || $just_path === $page->path()) { if ($normalized_url === '/' || $just_path === $page->path()) {
$url_path = $normalized_url; $url_path = $normalized_url;
} else { } else {
@@ -852,7 +854,7 @@ class Uri
} }
// strip base from this path // strip base from this path
$target_path = str_replace($uri->rootUrl(), '', $target_path); $target_path = Utils::replaceFirstOccurrence($uri->rootUrl(), '', $target_path);
// set to / if root // set to / if root
if (empty($target_path)) { if (empty($target_path)) {
@@ -877,7 +879,7 @@ class Uri
// Handle route only // Handle route only
if ($route_only) { if ($route_only) {
$url_path = str_replace(static::filterPath($base_url), '', $url_path); $url_path = Utils::replaceFirstOccurrence(static::filterPath($base_url), '', $url_path);
} }
// transform back to string/array as needed // transform back to string/array as needed
@@ -998,7 +1000,7 @@ class Uri
} }
// special check to see if path checking is required. // special check to see if path checking is required.
$just_path = str_replace($normalized_url, '', $normalized_path); $just_path = Utils::replaceFirstOccurrence($normalized_url, '', $normalized_path);
if ($just_path === $page->path()) { if ($just_path === $page->path()) {
return $normalized_url; return $normalized_url;
} }
@@ -1148,7 +1150,7 @@ class Uri
protected function createFromEnvironment(array $env) protected function createFromEnvironment(array $env)
{ {
// Build scheme. // Build scheme.
if (isset($env['HTTP_X_FORWARDED_PROTO'])) { if (isset($env['HTTP_X_FORWARDED_PROTO']) && Grav::instance()['config']->get('system.http_x_forwarded.protocol')) {
$this->scheme = $env['HTTP_X_FORWARDED_PROTO']; $this->scheme = $env['HTTP_X_FORWARDED_PROTO'];
} elseif (isset($env['X-FORWARDED-PROTO'])) { } elseif (isset($env['X-FORWARDED-PROTO'])) {
$this->scheme = $env['X-FORWARDED-PROTO']; $this->scheme = $env['X-FORWARDED-PROTO'];
@@ -1166,11 +1168,14 @@ class Uri
$this->password = $env['PHP_AUTH_PW'] ?? null; $this->password = $env['PHP_AUTH_PW'] ?? null;
// Build host. // Build host.
$hostname = 'localhost'; if (isset($env['HTTP_X_FORWARDED_HOST']) && Grav::instance()['config']->get('system.http_x_forwarded.host')) {
if (isset($env['HTTP_HOST'])) { $hostname = $env['HTTP_X_FORWARDED_HOST'];
} else if (isset($env['HTTP_HOST'])) {
$hostname = $env['HTTP_HOST']; $hostname = $env['HTTP_HOST'];
} elseif (isset($env['SERVER_NAME'])) { } elseif (isset($env['SERVER_NAME'])) {
$hostname = $env['SERVER_NAME']; $hostname = $env['SERVER_NAME'];
} else {
$hostname = 'localhost';
} }
// Remove port from HTTP_HOST generated $hostname // Remove port from HTTP_HOST generated $hostname
$hostname = Utils::substrToString($hostname, ':'); $hostname = Utils::substrToString($hostname, ':');
@@ -1178,7 +1183,7 @@ class Uri
$this->host = $this->validateHostname($hostname) ? $hostname : 'unknown'; $this->host = $this->validateHostname($hostname) ? $hostname : 'unknown';
// Build port. // Build port.
if (isset($env['HTTP_X_FORWARDED_PORT'])) { if (isset($env['HTTP_X_FORWARDED_PORT']) && Grav::instance()['config']->get('system.http_x_forwarded.port')) {
$this->port = (int)$env['HTTP_X_FORWARDED_PORT']; $this->port = (int)$env['HTTP_X_FORWARDED_PORT'];
} elseif (isset($env['X-FORWARDED-PORT'])) { } elseif (isset($env['X-FORWARDED-PORT'])) {
$this->port = (int)$env['X-FORWARDED-PORT']; $this->port = (int)$env['X-FORWARDED-PORT'];
+140 -1
View File
@@ -10,6 +10,10 @@
namespace Grav\Console; namespace Grav\Console;
use Grav\Common\Grav; use Grav\Common\Grav;
use Grav\Common\Language\Language;
use Grav\Common\Page\Page;
use Grav\Common\Processors\InitializeProcessor;
use RocketTheme\Toolbox\Event\Event;
use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Output\OutputInterface;
@@ -18,6 +22,13 @@ class ConsoleCommand extends Command
{ {
use ConsoleTrait; use ConsoleTrait;
/** @var bool */
private $plugins_initialized = false;
/** @var bool */
private $themes_initialized = false;
/** @var bool */
private $pages_initialized = false;
/** /**
* @param InputInterface $input * @param InputInterface $input
* @param OutputInterface $output * @param OutputInterface $output
@@ -31,12 +42,140 @@ class ConsoleCommand extends Command
} }
/** /**
* * Override with your implementation.
*/ */
protected function serve() protected function serve()
{ {
} }
/**
* Initialize Grav.
*
* - Load configuration
* - Disable debugger
* - Set timezone, locale
* - Load plugins
* - Set Users type to be used in the site
*
* Safe to be called multiple times.
*
* @return $this
*/
final protected function initializeGrav()
{
InitializeProcessor::initializeCli(Grav::instance());
return $this;
}
/**
* Set language to be used in CLI.
*
* @param string|null $code
*/
final protected function setLanguage(string $code = null)
{
$this->initializeGrav();
$grav = Grav::instance();
/** @var Language $language */
$language = $grav['language'];
if ($language->enabled()) {
if ($code && $language->validate($code)) {
$language->setActive($code);
} else {
$language->setActive($language->getDefault());
}
}
}
/**
* Properly initialize plugins.
*
* - call $this->initializeGrav()
* - call onPluginsInitialized event
*
* Safe to be called multiple times.
*
* @return $this
*/
final protected function initializePlugins()
{
if (!$this->plugins_initialized) {
$this->plugins_initialized = true;
$this->initializeGrav();
// Initialize plugins.
$grav = Grav::instance();
$grav->fireEvent('onPluginsInitialized');
}
return $this;
}
/**
* Properly initialize themes.
*
* - call $this->initializePlugins()
* - initialize theme (call onThemeInitialized event)
*
* Safe to be called multiple times.
*
* @return $this
*/
final protected function initializeThemes()
{
if (!$this->themes_initialized) {
$this->themes_initialized = true;
$this->initializePlugins();
// Initialize themes.
$grav = Grav::instance();
$grav['themes']->init();
}
return $this;
}
/**
* Properly initialize pages.
*
* - call $this->initializeThemes()
* - initialize assets (call onAssetsInitialized event)
* - initialize twig (calls the twig events)
* - initialize pages (calls onPagesInitialized event)
*
* Safe to be called multiple times.
*
* @return $this
*/
final protected function initializePages()
{
if (!$this->pages_initialized) {
$this->pages_initialized = true;
$this->initializeThemes();
$grav = Grav::instance();
// Initialize assets.
$grav['assets']->init();
$grav->fireEvent('onAssetsInitialized');
// Initialize twig.
$grav['twig']->init();
// Initialize pages.
$pages = $grav['pages'];
$pages->init();
$grav->fireEvent('onPagesInitialized', new Event(['pages' => $pages]));
}
return $this;
}
protected function displayGPMRelease() protected function displayGPMRelease()
{ {
$this->output->writeln(''); $this->output->writeln('');
@@ -177,7 +177,7 @@ class SelfupgradeCommand extends ConsoleCommand
} }
/** /**
* @param Package $package * @param array $package
* *
* @return string * @return string
*/ */
@@ -79,10 +79,28 @@ class CsvFormatter extends AbstractFormatter
// Get the field names // Get the field names
$header = str_getcsv(array_shift($lines), $delimiter); $header = str_getcsv(array_shift($lines), $delimiter);
// Allow for replacing a null string with null/empty value
$null_replace = $this->getConfig('null');
// Get the data // Get the data
$list = []; $list = [];
foreach ($lines as $line) { $line = null;
$list[] = array_combine($header, str_getcsv($line, $delimiter)); try {
foreach ($lines as $line) {
if (!empty($line)) {
$csv_line = str_getcsv($line, $delimiter);
if ($null_replace) {
array_walk($csv_line, function(&$el) use ($null_replace) {
$el = str_replace($null_replace, "\0", $el);
});
}
$list[] = array_combine($header, $csv_line);
}
}
} catch (\Exception $e) {
throw new \Exception('Badly formatted CSV line: ' . $line);
} }
return $list; return $list;
@@ -342,5 +342,5 @@ trait FlexMediaTrait
abstract public function getFlexDirectory(): FlexDirectory; abstract public function getFlexDirectory(): FlexDirectory;
abstract public function getStorageKey(); abstract public function getStorageKey(): string;
} }
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,532 @@
<?php
/**
* @package Grav\Framework\Parsedown
*
* @copyright Copyright (C) 2015 - 2019 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/
namespace Grav\Framework\Parsedown;
/*
* Parsedown Extra
* http://parsedown.org
*
* (c) Emanuil Rusev
* http://erusev.com
*
* This file ported from officiall ParsedownExtra repo and kept for compatibility.
*/
class ParsedownExtra extends Parsedown
{
# ~
const version = '0.7.0';
# ~
function __construct()
{
if (parent::version < '1.5.0')
{
throw new Exception('ParsedownExtra requires a later version of Parsedown');
}
$this->BlockTypes[':'] []= 'DefinitionList';
$this->BlockTypes['*'] []= 'Abbreviation';
# identify footnote definitions before reference definitions
array_unshift($this->BlockTypes['['], 'Footnote');
# identify footnote markers before before links
array_unshift($this->InlineTypes['['], 'FootnoteMarker');
}
#
# ~
function text($text)
{
$markup = parent::text($text);
# merge consecutive dl elements
$markup = preg_replace('/<\/dl>\s+<dl>\s+/', '', $markup);
# add footnotes
if (isset($this->DefinitionData['Footnote']))
{
$Element = $this->buildFootnoteElement();
$markup .= "\n" . $this->element($Element);
}
return $markup;
}
#
# Blocks
#
#
# Abbreviation
protected function blockAbbreviation($Line)
{
if (preg_match('/^\*\[(.+?)\]:[ ]*(.+?)[ ]*$/', $Line['text'], $matches))
{
$this->DefinitionData['Abbreviation'][$matches[1]] = $matches[2];
$Block = array(
'hidden' => true,
);
return $Block;
}
}
#
# Footnote
protected function blockFootnote($Line)
{
if (preg_match('/^\[\^(.+?)\]:[ ]?(.*)$/', $Line['text'], $matches))
{
$Block = array(
'label' => $matches[1],
'text' => $matches[2],
'hidden' => true,
);
return $Block;
}
}
protected function blockFootnoteContinue($Line, $Block)
{
if ($Line['text'][0] === '[' and preg_match('/^\[\^(.+?)\]:/', $Line['text']))
{
return;
}
if (isset($Block['interrupted']))
{
if ($Line['indent'] >= 4)
{
$Block['text'] .= "\n\n" . $Line['text'];
return $Block;
}
}
else
{
$Block['text'] .= "\n" . $Line['text'];
return $Block;
}
}
protected function blockFootnoteComplete($Block)
{
$this->DefinitionData['Footnote'][$Block['label']] = array(
'text' => $Block['text'],
'count' => null,
'number' => null,
);
return $Block;
}
#
# Definition List
protected function blockDefinitionList($Line, $Block)
{
if ( ! isset($Block) or isset($Block['type']))
{
return;
}
$Element = array(
'name' => 'dl',
'handler' => 'elements',
'text' => array(),
);
$terms = explode("\n", $Block['element']['text']);
foreach ($terms as $term)
{
$Element['text'] []= array(
'name' => 'dt',
'handler' => 'line',
'text' => $term,
);
}
$Block['element'] = $Element;
$Block = $this->addDdElement($Line, $Block);
return $Block;
}
protected function blockDefinitionListContinue($Line, array $Block)
{
if ($Line['text'][0] === ':')
{
$Block = $this->addDdElement($Line, $Block);
return $Block;
}
else
{
if (isset($Block['interrupted']) and $Line['indent'] === 0)
{
return;
}
if (isset($Block['interrupted']))
{
$Block['dd']['handler'] = 'text';
$Block['dd']['text'] .= "\n\n";
unset($Block['interrupted']);
}
$text = substr($Line['body'], min($Line['indent'], 4));
$Block['dd']['text'] .= "\n" . $text;
return $Block;
}
}
#
# Header
protected function blockHeader($Line)
{
$Block = parent::blockHeader($Line);
if ($Block !== null && preg_match('/[ #]*{('.$this->regexAttribute.'+)}[ ]*$/', $Block['element']['text'], $matches, PREG_OFFSET_CAPTURE))
{
$attributeString = $matches[1][0];
$Block['element']['attributes'] = $this->parseAttributeData($attributeString);
$Block['element']['text'] = substr($Block['element']['text'], 0, $matches[0][1]);
}
return $Block;
}
#
# Markup
protected function blockMarkupComplete($Block)
{
if ( ! isset($Block['void']))
{
$Block['markup'] = $this->processTag($Block['markup']);
}
return $Block;
}
#
# Setext
protected function blockSetextHeader($Line, array $Block = null)
{
$Block = parent::blockSetextHeader($Line, $Block);
if ($Block !== null && preg_match('/[ ]*{('.$this->regexAttribute.'+)}[ ]*$/', $Block['element']['text'], $matches, PREG_OFFSET_CAPTURE))
{
$attributeString = $matches[1][0];
$Block['element']['attributes'] = $this->parseAttributeData($attributeString);
$Block['element']['text'] = substr($Block['element']['text'], 0, $matches[0][1]);
}
return $Block;
}
#
# Inline Elements
#
#
# Footnote Marker
protected function inlineFootnoteMarker($Excerpt)
{
if (preg_match('/^\[\^(.+?)\]/', $Excerpt['text'], $matches))
{
$name = $matches[1];
if ( ! isset($this->DefinitionData['Footnote'][$name]))
{
return;
}
$this->DefinitionData['Footnote'][$name]['count'] ++;
if ( ! isset($this->DefinitionData['Footnote'][$name]['number']))
{
$this->DefinitionData['Footnote'][$name]['number'] = ++ $this->footnoteCount; # » &
}
$Element = array(
'name' => 'sup',
'attributes' => array('id' => 'fnref'.$this->DefinitionData['Footnote'][$name]['count'].':'.$name),
'handler' => 'element',
'text' => array(
'name' => 'a',
'attributes' => array('href' => '#fn:'.$name, 'class' => 'footnote-ref'),
'text' => $this->DefinitionData['Footnote'][$name]['number'],
),
);
return array(
'extent' => strlen($matches[0]),
'element' => $Element,
);
}
}
private $footnoteCount = 0;
#
# Link
protected function inlineLink($Excerpt)
{
$Link = parent::inlineLink($Excerpt);
$remainder = $Link !== null ? substr($Excerpt['text'], $Link['extent']) : '';
if (preg_match('/^[ ]*{('.$this->regexAttribute.'+)}/', $remainder, $matches))
{
$Link['element']['attributes'] += $this->parseAttributeData($matches[1]);
$Link['extent'] += strlen($matches[0]);
}
return $Link;
}
#
# ~
#
protected function unmarkedText($text)
{
$text = parent::unmarkedText($text);
if (isset($this->DefinitionData['Abbreviation']))
{
foreach ($this->DefinitionData['Abbreviation'] as $abbreviation => $meaning)
{
$pattern = '/\b'.preg_quote($abbreviation, '/').'\b/';
$text = preg_replace($pattern, '<abbr title="'.$meaning.'">'.$abbreviation.'</abbr>', $text);
}
}
return $text;
}
#
# Util Methods
#
protected function addDdElement(array $Line, array $Block)
{
$text = substr($Line['text'], 1);
$text = trim($text);
unset($Block['dd']);
$Block['dd'] = array(
'name' => 'dd',
'handler' => 'line',
'text' => $text,
);
if (isset($Block['interrupted']))
{
$Block['dd']['handler'] = 'text';
unset($Block['interrupted']);
}
$Block['element']['text'] []= & $Block['dd'];
return $Block;
}
protected function buildFootnoteElement()
{
$Element = array(
'name' => 'div',
'attributes' => array('class' => 'footnotes'),
'handler' => 'elements',
'text' => array(
array(
'name' => 'hr',
),
array(
'name' => 'ol',
'handler' => 'elements',
'text' => array(),
),
),
);
uasort($this->DefinitionData['Footnote'], 'self::sortFootnotes');
foreach ($this->DefinitionData['Footnote'] as $definitionId => $DefinitionData)
{
if ( ! isset($DefinitionData['number']))
{
continue;
}
$text = $DefinitionData['text'];
$text = parent::text($text);
$numbers = range(1, $DefinitionData['count']);
$backLinksMarkup = '';
foreach ($numbers as $number)
{
$backLinksMarkup .= ' <a href="#fnref'.$number.':'.$definitionId.'" rev="footnote" class="footnote-backref">&#8617;</a>';
}
$backLinksMarkup = substr($backLinksMarkup, 1);
if (substr($text, - 4) === '</p>')
{
$backLinksMarkup = '&#160;'.$backLinksMarkup;
$text = substr_replace($text, $backLinksMarkup.'</p>', - 4);
}
else
{
$text .= "\n".'<p>'.$backLinksMarkup.'</p>';
}
$Element['text'][1]['text'] []= array(
'name' => 'li',
'attributes' => array('id' => 'fn:'.$definitionId),
'text' => "\n".$text."\n",
);
}
return $Element;
}
# ~
protected function parseAttributeData($attributeString)
{
$Data = array();
$attributes = preg_split('/[ ]+/', $attributeString, - 1, PREG_SPLIT_NO_EMPTY);
foreach ($attributes as $attribute)
{
if ($attribute[0] === '#')
{
$Data['id'] = substr($attribute, 1);
}
else # "."
{
$classes []= substr($attribute, 1);
}
}
if (isset($classes))
{
$Data['class'] = implode(' ', $classes);
}
return $Data;
}
# ~
protected function processTag($elementMarkup) # recursive
{
# http://stackoverflow.com/q/1148928/200145
libxml_use_internal_errors(true);
$DOMDocument = new \DOMDocument;
# http://stackoverflow.com/q/11309194/200145
$elementMarkup = mb_convert_encoding($elementMarkup, 'HTML-ENTITIES', 'UTF-8');
# http://stackoverflow.com/q/4879946/200145
$DOMDocument->loadHTML($elementMarkup);
$DOMDocument->removeChild($DOMDocument->doctype);
$DOMDocument->replaceChild($DOMDocument->firstChild->firstChild->firstChild, $DOMDocument->firstChild);
$elementText = '';
if ($DOMDocument->documentElement->getAttribute('markdown') === '1')
{
foreach ($DOMDocument->documentElement->childNodes as $Node)
{
$elementText .= $DOMDocument->saveHTML($Node);
}
$DOMDocument->documentElement->removeAttribute('markdown');
$elementText = "\n".$this->text($elementText)."\n";
}
else
{
foreach ($DOMDocument->documentElement->childNodes as $Node)
{
$nodeMarkup = $DOMDocument->saveHTML($Node);
if ($Node instanceof \DOMElement and ! in_array($Node->nodeName, $this->textLevelElements))
{
$elementText .= $this->processTag($nodeMarkup);
}
else
{
$elementText .= $nodeMarkup;
}
}
}
# because we don't want for markup to get encoded
$DOMDocument->documentElement->nodeValue = 'placeholder\x1A';
$markup = $DOMDocument->saveHTML($DOMDocument->documentElement);
$markup = str_replace('placeholder\x1A', $elementText, $markup);
return $markup;
}
# ~
protected function sortFootnotes($A, $B) # callback
{
return $A['number'] - $B['number'];
}
#
# Fields
#
protected $regexAttribute = '(?:[#.][-\w]+[ ]*)';
}
+3 -4
View File
@@ -286,7 +286,7 @@ class Route
$url .= '?' . $this->getUriQuery(); $url .= '?' . $this->getUriQuery();
} }
return $url; return rtrim($url,'/');
} }
/** /**
@@ -344,9 +344,8 @@ class Route
$parts[] = $this->language; $parts[] = $this->language;
} }
if ($this->route !== '') { $parts[] = $this->extension ? $this->route . '.' . $this->extension : $this->route;
$parts[] = $this->extension ? $this->route . '.' . $this->extension : $this->route;
}
if ($this->gravParams) { if ($this->gravParams) {
$parts[] = RouteFactory::buildParams($this->gravParams); $parts[] = RouteFactory::buildParams($this->gravParams);
+30 -24
View File
@@ -9,6 +9,7 @@
namespace Grav\Framework\Session; namespace Grav\Framework\Session;
use Grav\Common\User\Interfaces\UserInterface;
use Grav\Framework\Session\Exceptions\SessionException; use Grav\Framework\Session\Exceptions\SessionException;
/** /**
@@ -17,16 +18,13 @@ use Grav\Framework\Session\Exceptions\SessionException;
*/ */
class Session implements SessionInterface class Session implements SessionInterface
{ {
protected $options; /** @var array */
protected $options = [];
/** /** @var bool */
* @var bool
*/
protected $started = false; protected $started = false;
/** /** @var Session */
* @var Session
*/
protected static $instance; protected static $instance;
/** /**
@@ -178,9 +176,13 @@ class Session implements SessionInterface
return $this; return $this;
} }
$sessionName = session_name();
$sessionExists = isset($_COOKIE[$sessionName]);
// Protection against invalid session cookie names throwing exception: http://php.net/manual/en/function.session-id.php#116836 // Protection against invalid session cookie names throwing exception: http://php.net/manual/en/function.session-id.php#116836
if (isset($_COOKIE[session_name()]) && !preg_match('/^[-,a-zA-Z0-9]{1,128}$/', $_COOKIE[session_name()])) { if ($sessionExists && !preg_match('/^[-,a-zA-Z0-9]{1,128}$/', $_COOKIE[$sessionName])) {
unset($_COOKIE[session_name()]); unset($_COOKIE[$sessionName]);
$sessionExists = false;
} }
$options = $this->options; $options = $this->options;
@@ -197,24 +199,28 @@ class Session implements SessionInterface
throw new SessionException('Failed to start session: ' . $error, 500); throw new SessionException('Failed to start session: ' . $error, 500);
} }
if ($user && !$user->isValid()) { $this->started = true;
$this->clear();
throw new SessionException('User Invalid', 500); if ($user && (!$user instanceof UserInterface || !$user->isValid())) {
$this->invalidate();
throw new SessionException('Invalid User object, session destroyed.', 500);
} }
$params = session_get_cookie_params(); // Extend the lifetime of the session.
if ($sessionExists) {
$params = session_get_cookie_params();
setcookie( setcookie(
session_name(), $sessionName,
session_id(), session_id(),
time() + $params['lifetime'], time() + $params['lifetime'],
$params['path'], $params['path'],
$params['domain'], $params['domain'],
$params['secure'], $params['secure'],
$params['httponly'] $params['httponly']
); );
}
$this->started = true;
return $this; return $this;
} }
+1
View File
@@ -1,5 +1,6 @@
themes/grav/.sass-cache themes/grav/.sass-cache
.DS_Store .DS_Store
crowdin.yaml
# Node Modules # Node Modules
**/node_modules/** **/node_modules/**
+50
View File
@@ -1,3 +1,53 @@
# v1.9.16
## 09/01/2020
1. [](#bugfix)
* Fixed a glitch which allows user to delete entire pages directory [#1941](https://github.com/getgrav/grav-plugin-admin/issues/1941)
* Fixed the hidden login plugin toggle
# v1.9.15
## 06/08/2020
1. [](#bugfix)
* Support markdown in `fieldset.text` [#2934](https://github.com/getgrav/grav/issues/2934)
* Fix data URLs in avatar images [#1889](https://github.com/getgrav/grav/issues/1889)
* Fix for deleting files in plugin configurations
# v1.9.14
## 04/27/2020
1. [](#improved)
* Added `slug` and `type` to blueprints
1. [](#bugfix)
* Support markdown in `fieldset.text` [#2934](https://github.com/getgrav/grav/issues/2934)
# v1.9.13
## 03/05/2020
1. [](#improved)
* Updated vendor libs
1. [](#bugfix)
* Fixed toggleable buttons no longer holding false state [form#406](ttps://github.com/getgrav/grav-plugin-form/issues/406)
# v1.9.12
## 12/04/2019
1. [](#bugfix)
* Fixed saving configuration in PHP 7.4
# v1.9.11
## 11/06/2019
1. [](#improved)
* Added new "secure delete" functionality [#1752](https://github.com/getgrav/grav-plugin-admin/issues/1752)
* Center text logo [#1751](https://github.com/getgrav/grav-plugin-admin/issues/1751)
* Added required span to editor field [#1748](https://github.com/getgrav/grav-plugin-admin/issues/1748)
* Warn users if JS is disabled [#1722](https://github.com/getgrav/grav-plugin-admin/issues/1722)
* Added target rule to quick links [#1518](https://github.com/getgrav/grav-plugin-admin/issues/1518)
1. [](#bugfix)
* Fixed `Badly encoded JSON data` warning when uploading files [grav#2663](https://github.com/getgrav/grav/issues/2663)
* Fixed `accept` for SVG in `file` uploaders [#1732](https://github.com/getgrav/grav-plugin-admin/issues/1732)
# v1.9.10 # v1.9.10
## 09/19/2019 ## 09/19/2019
+1
View File
@@ -26,6 +26,7 @@ session:
timeout: 1800 timeout: 1800
warnings: warnings:
delete_page: true delete_page: true
secure_delete: false
edit_mode: normal edit_mode: normal
frontend_preview_target: inline frontend_preview_target: inline
show_github_msg: true show_github_msg: true
+16 -2
View File
@@ -1,5 +1,7 @@
name: Admin Panel name: Admin Panel
version: 1.9.10 slug: admin
type: plugin
version: 1.9.16
testing: false testing: false
description: Adds an advanced administration panel to manage your site description: Adds an advanced administration panel to manage your site
icon: empire icon: empire
@@ -14,7 +16,7 @@ docs: https://github.com/getgrav/grav-plugin-admin/blob/develop/README.md
license: MIT license: MIT
dependencies: dependencies:
- { name: grav, version: '>=1.6.8' } - { name: grav, version: '>=1.6.22' }
- { name: form, version: '>=3.0.0' } - { name: form, version: '>=3.0.0' }
- { name: login, version: '>=3.0.0' } - { name: login, version: '>=3.0.0' }
- { name: email, version: '>=3.0.0' } - { name: email, version: '>=3.0.0' }
@@ -243,6 +245,18 @@ form:
type: bool type: bool
help: Ask the user confirmation when deleting a page help: Ask the user confirmation when deleting a page
warnings.secure_delete:
type: toggle
label: Secure Delete
highlight: 1
default: 1
options:
1: PLUGIN_ADMIN.ENABLED
0: PLUGIN_ADMIN.DISABLED
validate:
type: bool
help: Shows the user a field to enter the word DELETE and enable the confirm delete button.
hide_page_types: hide_page_types:
type: array type: array
label: Hide page types in Admin label: Hide page types in Admin
+4 -1
View File
@@ -1671,8 +1671,11 @@ class Admin
{ {
$reports = new ArrayCollection(); $reports = new ArrayCollection();
/** @var Pages $pages */
$pages = $this->grav['pages'];
// Default to XSS Security Report // Default to XSS Security Report
$result = Security::detectXssFromPages($this->grav['pages'], true); $result = Security::detectXssFromPages($pages, true);
$reports['Grav Security Check'] = $this->grav['twig']->processTemplate('reports/security.html.twig', [ $reports['Grav Security Check'] = $this->grav['twig']->processTemplate('reports/security.html.twig', [
'result' => $result, 'result' => $result,
@@ -325,7 +325,7 @@ class AdminBaseController
} }
$isMime = strstr($type, '/'); $isMime = strstr($type, '/');
$find = str_replace(['.', '*'], ['\.', '.*'], $type); $find = str_replace(['.', '*', '+'], ['\.', '.*', '\+'], $type);
if ($isMime) { if ($isMime) {
$match = preg_match('#' . $find . '$#', $mime); $match = preg_match('#' . $find . '$#', $mime);
@@ -737,8 +737,8 @@ class AdminBaseController
// Process previously uploaded files for the current URI // Process previously uploaded files for the current URI
// and finally store them. Everything else will get discarded // and finally store them. Everything else will get discarded
$queue = $this->admin->session()->getFlashObject('files-upload'); $queue = $this->admin->session()->getFlashObject('files-upload');
$queue = $queue[base64_encode($this->grav['uri']->url())];
if (is_array($queue)) { if (is_array($queue)) {
$queue = $queue[base64_encode($this->grav['uri']->url())];
foreach ($queue as $key => $files) { foreach ($queue as $key => $files) {
foreach ($files as $destination => $file) { foreach ($files as $destination => $file) {
if (!rename($file['tmp_name'], $destination)) { if (!rename($file['tmp_name'], $destination)) {
@@ -943,7 +943,7 @@ class AdminBaseController
$settings = (object)$blueprints->schema()->getProperty($field); $settings = (object)$blueprints->schema()->getProperty($field);
} else { } else {
$page = null; $page = null;
if ($type === 'themes') { if ($type === 'themes' || $type === 'plugins') {
$obj = $this->grav[$type]->get(Utils::substrToString($blueprint, '/')); //here $obj = $this->grav[$type]->get(Utils::substrToString($blueprint, '/')); //here
$settings = (object) $obj->blueprints()->schema()->getProperty($field); $settings = (object) $obj->blueprints()->schema()->getProperty($field);
} else { } else {
+15 -1
View File
@@ -487,6 +487,11 @@ class AdminController extends AdminBaseController
$data = (array)$this->data; $data = (array)$this->data;
$folder = $data['folder'] ?? '';
if ($folder === '' || mb_strpos($folder, '/') !== false) {
throw new \RuntimeException('Creating folder failed, bad folder name', 400);
}
if ($data['route'] === '/') { if ($data['route'] === '/') {
$path = $this->grav['locator']->findResource('page://'); $path = $this->grav['locator']->findResource('page://');
} else { } else {
@@ -494,7 +499,7 @@ class AdminController extends AdminBaseController
} }
$orderOfNewFolder = static::getNextOrderInFolder($path); $orderOfNewFolder = static::getNextOrderInFolder($path);
$new_path = $path . '/' . $orderOfNewFolder . '.' . $data['folder']; $new_path = $path . '/' . $orderOfNewFolder . '.' . $folder;
Folder::create($new_path); Folder::create($new_path);
Cache::clearCache('invalidate'); Cache::clearCache('invalidate');
@@ -585,6 +590,11 @@ class AdminController extends AdminBaseController
/** @var PageInterface $obj */ /** @var PageInterface $obj */
$obj = $this->admin->page(true); $obj = $this->admin->page(true);
$folder = $data['folder'] ?? null;
if ($folder === '' || mb_strpos($folder, '/') !== false) {
throw new \RuntimeException('Saving page failed: bad folder name', 400);
}
if (!isset($data['folder']) || !$data['folder']) { if (!isset($data['folder']) || !$data['folder']) {
$data['folder'] = $obj->slug(); $data['folder'] = $obj->slug();
$this->data['folder'] = $obj->slug(); $this->data['folder'] = $obj->slug();
@@ -814,6 +824,10 @@ class AdminController extends AdminBaseController
$folder = \Grav\Plugin\Admin\Utils::slug($data[substr($folder, 9)]); $folder = \Grav\Plugin\Admin\Utils::slug($data[substr($folder, 9)]);
} }
$folder = ltrim($folder, '_'); $folder = ltrim($folder, '_');
if ($folder === '' || mb_strpos($folder, '/') !== false) {
throw new \RuntimeException('Creating page failed: bad folder name', 400);
}
if (!empty($data['modular'])) { if (!empty($data['modular'])) {
$folder = '_' . $folder; $folder = '_' . $folder;
} }
+517 -341
View File
File diff suppressed because it is too large Load Diff
+6
View File
@@ -1,4 +1,5 @@
PLUGIN_ADMIN: PLUGIN_ADMIN:
ADMIN_NOSCRIPT_MSG: "Please enable JavaScript in your browser."
ADMIN_BETA_MSG: "This is a Beta release! Use this in production at your own risk..." ADMIN_BETA_MSG: "This is a Beta release! Use this in production at your own risk..."
ADMIN_REPORT_ISSUE: "Found an issue? Please report it on GitHub." ADMIN_REPORT_ISSUE: "Found an issue? Please report it on GitHub."
EMAIL_FOOTER: "<a href=\"http://getgrav.org\">Powered by Grav</a> - The Modern Flat File CMS" EMAIL_FOOTER: "<a href=\"http://getgrav.org\">Powered by Grav</a> - The Modern Flat File CMS"
@@ -43,10 +44,12 @@ PLUGIN_ADMIN:
EXPERT: "Expert" EXPERT: "Expert"
EXPAND_ALL: "Expand All" EXPAND_ALL: "Expand All"
COLLAPSE_ALL: "Collapse All" COLLAPSE_ALL: "Collapse All"
SECURE_DELETE_DESC: "Type DELETE and confirm"
ERROR: "Error" ERROR: "Error"
CLOSE: "Close" CLOSE: "Close"
CANCEL: "Cancel" CANCEL: "Cancel"
CONTINUE: "Continue" CONTINUE: "Continue"
CONFIRM: "Confirm"
MODAL_DELETE_PAGE_CONFIRMATION_REQUIRED_TITLE: "Confirmation Required" MODAL_DELETE_PAGE_CONFIRMATION_REQUIRED_TITLE: "Confirmation Required"
MODAL_CHANGED_DETECTED_TITLE: "Changes Detected" MODAL_CHANGED_DETECTED_TITLE: "Changes Detected"
MODAL_CHANGED_DETECTED_DESC: "You have unsaved changes. Are you sure you want to leave without saving?" MODAL_CHANGED_DETECTED_DESC: "You have unsaved changes. Are you sure you want to leave without saving?"
@@ -825,3 +828,6 @@ PLUGIN_ADMIN:
DEBUGGER_CLOCKWORK: "Clockwork Browser Extension" DEBUGGER_CLOCKWORK: "Clockwork Browser Extension"
SHOW_SENSITIVE: "Show Sensitive Data" SHOW_SENSITIVE: "Show Sensitive Data"
SHOW_SENSITIVE_HELP: "Clockwork Provider ONLY: Censor potentially sensitive information (POST parameters, cookies, files, configuration and most array/object data in log messages)" SHOW_SENSITIVE_HELP: "Clockwork Provider ONLY: Censor potentially sensitive information (POST parameters, cookies, files, configuration and most array/object data in log messages)"
VALID_LINK_ATTRIBUTES: "Valid Link Attributes"
VALID_LINK_ATTRIBUTES_HELP: "Attributes that will be automatically added to the media HTML element"
+2
View File
@@ -43,10 +43,12 @@ PLUGIN_ADMIN:
EXPERT: "Esperto" EXPERT: "Esperto"
EXPAND_ALL: "Expandir Tudo" EXPAND_ALL: "Expandir Tudo"
COLLAPSE_ALL: "Recolher Tudo" COLLAPSE_ALL: "Recolher Tudo"
SECURE_DELETE_DESC: "Digite DELETE e confirme"
ERROR: "Erro" ERROR: "Erro"
CLOSE: "Fechar" CLOSE: "Fechar"
CANCEL: "Cancelar" CANCEL: "Cancelar"
CONTINUE: "Continuar" CONTINUE: "Continuar"
CONFIRM: "Confirmar"
MODAL_DELETE_PAGE_CONFIRMATION_REQUIRED_TITLE: "Confirmação Requerida" MODAL_DELETE_PAGE_CONFIRMATION_REQUIRED_TITLE: "Confirmação Requerida"
MODAL_CHANGED_DETECTED_TITLE: "Alterações Detectadas" MODAL_CHANGED_DETECTED_TITLE: "Alterações Detectadas"
MODAL_CHANGED_DETECTED_DESC: "Você tem alterações não salvas. Tem certeza que deseja sair sem salvar?" MODAL_CHANGED_DETECTED_DESC: "Você tem alterações não salvas. Tem certeza que deseja sair sem salvar?"
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -3,7 +3,7 @@ $fonts-default: 'Roboto' !default;
$fonts-mono: 'Inconsolata' !default; $fonts-mono: 'Inconsolata' !default;
$font-definitions: ( $font-definitions: (
Josefin+Slab: 400, 'Josefin Slab': '400',
Roboto: '300,400,500', Roboto: '300,400,500',
Inconsolata: '400,700' Inconsolata: '400,700'
); );
@@ -798,6 +798,7 @@ body.sidebar-quickopen #admin-main {
.button { .button {
margin: 0; margin: 0;
height: 37px;
&.dropdown-toggle { &.dropdown-toggle {
margin-left: -4px; margin-left: -4px;
@@ -103,6 +103,7 @@
justify-content: center; justify-content: center;
&.text-logo { &.text-logo {
text-align: center;
font-size: 4rem; font-size: 4rem;
} }
@@ -24,7 +24,10 @@
font-size: 90%; font-size: 90%;
} }
&:disabled {
opacity: .6;
cursor: no-drop;
}
} }
@@ -2,9 +2,9 @@
{% if not blueprints or (blueprints.schema.type(field.type)['input@'] ?? true) is same as(true) %} {% if not blueprints or (blueprints.schema.type(field.type)['input@'] ?? true) is same as(true) %}
{% set originalValue = originalValue is defined ? originalValue : value %} {% set originalValue = originalValue is defined ? originalValue : value %}
{% set toggleableChecked = field.toggleable and (originalValue is not null and originalValue is not empty) %} {% set toggleableChecked = field.toggleable and originalValue is not null %}
{% set isDisabledToggleable = field.toggleable and not toggleableChecked %} {% set isDisabledToggleable = field.toggleable and not toggleableChecked %}
{% set value = (value is null ? field.default : value) %} {% set value = value ?? field.default %}
{% if (field.yaml or field.validate.type == 'yaml') and value is iterable%} {% if (field.yaml or field.validate.type == 'yaml') and value is iterable%}
{% set value = value|toYaml %} {% set value = value|toYaml %}
@@ -11,7 +11,10 @@
{% if field.help %} {% if field.help %}
{% set hint = 'data-hint="' ~ field.help|tu|raw ~ '"' %} {% set hint = 'data-hint="' ~ field.help|tu|raw ~ '"' %}
{% endif %} {% endif %}
<div class="form-label form-field hint--bottom" {{ hint|raw }}>{{ field.label|tu|raw }}</div> <div class="form-label form-field hint--bottom" {{ hint|raw }}>
{{ field.label|tu|raw }}
{{ field.validate.required in ['on', 'true', 1] ? '<span class="required">*</span>' }}
</div>
{% endif %} {% endif %}
{% endblock %} {% endblock %}
<div class="form-field {{ field.classes|default('') }}"> <div class="form-field {{ field.classes|default('') }}">
@@ -48,9 +48,12 @@
> >
{% block group %} {% block group %}
{% if field.text %} {% if field.text %}
<p>{% if grav.twig.twig.filters['tu'] is defined %}{{ field.text|tu }}{% else %}{{ field.text|t }}{% endif %} {% if grav.twig.twig.filters['tu'] is defined %}
<p> {{ field.markdown ? field.text|tu|markdown : '<p>' ~ field.text|tu ~ '</p>' }}
{% else %}
{{ field.markdown ? field.text|t|markdown : '<p>' ~ field.t ~ '</p>' }}
{% endif %}
{% endif %} {% endif %}
{% if field.fields %} {% if field.fields %}
@@ -107,6 +107,7 @@
{% set modular = context.modular ? 'modular_' : '' %} {% set modular = context.modular ? 'modular_' : '' %}
{% set warn = config.plugins.admin.warnings.delete_page %} {% set warn = config.plugins.admin.warnings.delete_page %}
{% set secure_delete = config.plugins.admin.warnings.secure_delete %}
{% set admin_lang = admin.session.admin_lang ?: 'en' %} {% set admin_lang = admin.session.admin_lang ?: 'en' %}
{% set page_lang = context.language %} {% set page_lang = context.language %}
{% set type = 'page' %} {% set type = 'page' %}
@@ -405,10 +406,19 @@
<p class="bigger"> <p class="bigger">
{{ "PLUGIN_ADMIN.MODAL_DELETE_PAGE_CONFIRMATION_REQUIRED_DESC"|tu }} {{ "PLUGIN_ADMIN.MODAL_DELETE_PAGE_CONFIRMATION_REQUIRED_DESC"|tu }}
</p> </p>
{% if secure_delete %}
<p class="form-secure-delete">
<input id="secure-delete-field" autofocus type="text" placeholder="{{ "PLUGIN_ADMIN.SECURE_DELETE_DESC"|tu }}" />
</p>
{% endif %}
<br> <br>
<div class="button-bar"> <div class="button-bar">
<button data-remodal-action="cancel" class="button secondary remodal-cancel"><i class="fa fa-fw fa-close"></i> {{ "PLUGIN_ADMIN.CANCEL"|tu }}</button> <button data-remodal-action="cancel" class="button secondary remodal-cancel"><i class="fa fa-fw fa-close"></i> {{ "PLUGIN_ADMIN.CANCEL"|tu }}</button>
<a class="button disable-after-click" data-delete-action href="#"><i class="fa fa-fw fa-check"></i> {{ "PLUGIN_ADMIN.CONTINUE"|tu }}</a> {% if secure_delete %}
<button id="secure-delete-btn" disabled="true" class="button danger disable-after-click" data-delete-action><i class="fa fa-fw fa-check"></i> {{ "PLUGIN_ADMIN.CONFIRM"|tu }}</button>
{% else %}
<a class="button danger disable-after-click" data-delete-action href="#"><i class="fa fa-fw fa-check"></i> {{ "PLUGIN_ADMIN.CONTINUE"|tu }}</a>
{% endif %}
</div> </div>
</form> </form>
</div> </div>
@@ -421,5 +431,18 @@
{{ parent() }} {{ parent() }}
<script> <script>
$('.admin-pages .form-tabs .tabs-nav').css('margin-right', ($('#admin-topbar').width() + 20) + 'px'); $('.admin-pages .form-tabs .tabs-nav').css('margin-right', ($('#admin-topbar').width() + 20) + 'px');
{% if secure_delete %}
$('#secure-delete-field').keyup(function () {
var inputValue = $(this).val();
if (inputValue == 'DELETE') {
$('#secure-delete-btn').attr('disabled', false);
}else{
$('#secure-delete-btn').attr('disabled', true);
}
});
$(document).on('closing', '.remodal', function () {
$('#secure-delete-field').val('');
});
{% endif %}
</script> </script>
{% endblock %} {% endblock %}
@@ -40,6 +40,10 @@
{% include 'partials/messages.html.twig' %} {% include 'partials/messages.html.twig' %}
{% else %} {% else %}
{% block noscript %}
{% include 'partials/noscript.html.twig' %}
{% endblock noscript %}
{% block page %} {% block page %}
<div class="remodal-bg"> <div class="remodal-bg">
@@ -18,7 +18,7 @@
{% endif %} {% endif %}
<li class="{{ item.class }} hint--bottom" data-hint="{{ item.hint }}" {{ data_tags|raw }}> <li class="{{ item.class }} hint--bottom" data-hint="{{ item.hint }}" {{ data_tags|raw }}>
{% if item.route %} {% if item.route %}
<a href="{{ url(item.route) }}"> <a href="{{ url(item.route) }}" {% if item.target %}target="{{ item.target }}"{% endif %}>
<i class="fa fa-fw {{ item.icon }}"></i> <i class="fa fa-fw {{ item.icon }}"></i>
</a> </a>
{% else %} {% else %}
@@ -1,2 +1,2 @@
{% set user_avatar = admin.user.getAvatarUrl() %} {% set user_avatar = admin.user.getAvatarUrl() %}
<img src="{{ '?' not in user_avatar ? user_avatar ~ '?s=80' : user_avatar }}" /> <img src="{{ ('?' not in user_avatar) and (not user_avatar starts with 'data:') ? user_avatar ~ '?s=80' : user_avatar }}" />
@@ -0,0 +1,42 @@
<style>
.error-message {
background-color: #fce4e4;
border: 1px solid #fcc2c3;
width: 100%;
padding: 20px 30px;
}
.error-text {
color: #cc0033;
font-family: Helvetica, Arial, sans-serif;
width: 100%;
font-weight: bold;
line-height: 20px;
text-shadow: 1px 1px rgba(250,250,250,.3);
}
.full-height {
display: block;
width: 100%;
height: 100%;
}
</style>
<div id="noscript" class="full-height">
<main id="admin-main" class="full-height">
<div id="titlebar" class="titlebar">
<h1><i class="fa fa-fw fa-exclamation-triangle"></i>{{ "PLUGIN_ADMIN.ERROR"|tu }}</h1>
</div>
<div class="full-height">
<div class="error-message {% if config.plugins.admin.content_padding %}content-padding{% endif %}">
<span class="error-text">{{ "PLUGIN_ADMIN.ADMIN_NOSCRIPT_MSG"|tu }}</span>
</div>
</div>
</main>
</div>
<script type="text/javascript">
function checkjs() {
var element = document.getElementById("noscript");
element.style.display = 'none';
}
checkjs();
</script>
@@ -42,7 +42,7 @@
{% if isTestingRelease %}<span class="gpm-testing">test release</span>{% endif %} {% if isTestingRelease %}<span class="gpm-testing">test release</span>{% endif %}
</td> </td>
<td class="gpm-actions"> <td class="gpm-actions">
{% if (not installing and (plugin.form.fields.enabled.type != 'hidden' and plugin.form.fields.tabs.fields.login.fields.enabled.type != 'hidden')) %} {% if (not installing and (plugin.form.fields.enabled.type != 'hidden' and plugin.form.fields.tabs.fields.options.fields.enabled.type != 'hidden')) %}
<a class="{{ data.get('enabled') ? 'enabled' : 'disabled' }}" href="{{ uri.addNonce(base_url_relative ~ '/plugins/' ~ slug ~ '/task' ~ config.system.param_sep ~ (data.get('enabled') ? 'disable' : 'enable'), 'admin-form', 'admin-nonce') }}"> <a class="{{ data.get('enabled') ? 'enabled' : 'disabled' }}" href="{{ uri.addNonce(base_url_relative ~ '/plugins/' ~ slug ~ '/task' ~ config.system.param_sep ~ (data.get('enabled') ? 'disable' : 'enable'), 'admin-form', 'admin-nonce') }}">
<i class="fa fa-fw fa-toggle-{{ data.get('enabled') ? 'on' : 'off' }}"></i> <i class="fa fa-fw fa-toggle-{{ data.get('enabled') ? 'on' : 'off' }}"></i>
</a> </a>
+2 -2
View File
@@ -279,7 +279,7 @@ class ClassLoader
*/ */
public function setApcuPrefix($apcuPrefix) public function setApcuPrefix($apcuPrefix)
{ {
$this->apcuPrefix = function_exists('apcu_fetch') && ini_get('apc.enabled') ? $apcuPrefix : null; $this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null;
} }
/** /**
@@ -377,7 +377,7 @@ class ClassLoader
$subPath = $class; $subPath = $class;
while (false !== $lastPos = strrpos($subPath, '\\')) { while (false !== $lastPos = strrpos($subPath, '\\')) {
$subPath = substr($subPath, 0, $lastPos); $subPath = substr($subPath, 0, $lastPos);
$search = $subPath.'\\'; $search = $subPath . '\\';
if (isset($this->prefixDirsPsr4[$search])) { if (isset($this->prefixDirsPsr4[$search])) {
$pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1); $pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1);
foreach ($this->prefixDirsPsr4[$search] as $dir) { foreach ($this->prefixDirsPsr4[$search] as $dir) {
+9 -9
View File
@@ -1,27 +1,26 @@
[ [
{ {
"name": "composer/semver", "name": "composer/semver",
"version": "1.4.2", "version": "1.5.1",
"version_normalized": "1.4.2.0", "version_normalized": "1.5.1.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/composer/semver.git", "url": "https://github.com/composer/semver.git",
"reference": "c7cb9a2095a074d131b65a8a0cd294479d785573" "reference": "c6bea70230ef4dd483e6bbcab6005f682ed3a8de"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/composer/semver/zipball/c7cb9a2095a074d131b65a8a0cd294479d785573", "url": "https://api.github.com/repos/composer/semver/zipball/c6bea70230ef4dd483e6bbcab6005f682ed3a8de",
"reference": "c7cb9a2095a074d131b65a8a0cd294479d785573", "reference": "c6bea70230ef4dd483e6bbcab6005f682ed3a8de",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"php": "^5.3.2 || ^7.0" "php": "^5.3.2 || ^7.0"
}, },
"require-dev": { "require-dev": {
"phpunit/phpunit": "^4.5 || ^5.0.5", "phpunit/phpunit": "^4.5 || ^5.0.5"
"phpunit/phpunit-mock-objects": "2.3.0 || ^3.0"
}, },
"time": "2016-08-30T16:08:34+00:00", "time": "2020-01-13T12:06:48+00:00",
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
@@ -164,6 +163,7 @@
"security", "security",
"xml", "xml",
"zf" "zf"
] ],
"abandoned": "laminas/laminas-xml"
} }
] ]
+12
View File
@@ -3,6 +3,15 @@
All notable changes to this project will be documented in this file. All notable changes to this project will be documented in this file.
This project adheres to [Semantic Versioning](http://semver.org/). This project adheres to [Semantic Versioning](http://semver.org/).
### [1.5.1] 2020-01-13
* Fixed: Parsing of aliased version was not validating the alias to be a valid version
### [1.5.0] 2019-03-19
* Added: some support for date versions (e.g. 201903) in `~` operator
* Fixed: support for stabilities in `~` operator was inconsistent
### [1.4.2] 2016-08-30 ### [1.4.2] 2016-08-30
* Fixed: collapsing of complex constraints lead to buggy constraints * Fixed: collapsing of complex constraints lead to buggy constraints
@@ -57,6 +66,9 @@ This project adheres to [Semantic Versioning](http://semver.org/).
- Namespace: `Composer\Test\Package\LinkConstraint` -> `Composer\Test\Semver\Constraint` - Namespace: `Composer\Test\Package\LinkConstraint` -> `Composer\Test\Semver\Constraint`
* Changed: code style using php-cs-fixer. * Changed: code style using php-cs-fixer.
[1.5.1]: https://github.com/composer/semver/compare/1.5.0...1.5.1
[1.5.0]: https://github.com/composer/semver/compare/1.4.2...1.5.0
[1.4.2]: https://github.com/composer/semver/compare/1.4.1...1.4.2
[1.4.1]: https://github.com/composer/semver/compare/1.4.0...1.4.1 [1.4.1]: https://github.com/composer/semver/compare/1.4.0...1.4.1
[1.4.0]: https://github.com/composer/semver/compare/1.3.0...1.4.0 [1.4.0]: https://github.com/composer/semver/compare/1.3.0...1.4.0
[1.3.0]: https://github.com/composer/semver/compare/1.2.0...1.3.0 [1.3.0]: https://github.com/composer/semver/compare/1.2.0...1.3.0
+1 -2
View File
@@ -34,8 +34,7 @@
"php": "^5.3.2 || ^7.0" "php": "^5.3.2 || ^7.0"
}, },
"require-dev": { "require-dev": {
"phpunit/phpunit": "^4.5 || ^5.0.5", "phpunit/phpunit": "^4.5 || ^5.0.5"
"phpunit/phpunit-mock-objects": "2.3.0 || ^3.0"
}, },
"autoload": { "autoload": {
"psr-4": { "psr-4": {
@@ -11,7 +11,7 @@
namespace Composer\Semver\Constraint; namespace Composer\Semver\Constraint;
trigger_error('The ' . __CLASS__ . ' abstract class is deprecated, there is no replacement for it, it will be removed in the next major version.', E_USER_DEPRECATED); trigger_error('The ' . __NAMESPACE__ . '\AbstractConstraint abstract class is deprecated, there is no replacement for it, it will be removed in the next major version.', E_USER_DEPRECATED);
/** /**
* Base constraint class. * Base constraint class.
@@ -184,7 +184,7 @@ class Constraint implements ConstraintInterface
// '!=' operator is match when other operator is not '==' operator or version is not match // '!=' operator is match when other operator is not '==' operator or version is not match
// these kinds of comparisons always have a solution // these kinds of comparisons always have a solution
if ($isNonEqualOp || $isProviderNonEqualOp) { if ($isNonEqualOp || $isProviderNonEqualOp) {
return !$isEqualOp && !$isProviderEqualOp return (!$isEqualOp && !$isProviderEqualOp)
|| $this->versionCompare($provider->version, $this->version, '!=', $compareBranches); || $this->versionCompare($provider->version, $this->version, '!=', $compareBranches);
} }
@@ -197,13 +197,9 @@ class Constraint implements ConstraintInterface
if ($this->versionCompare($provider->version, $this->version, self::$transOpInt[$this->operator], $compareBranches)) { if ($this->versionCompare($provider->version, $this->version, self::$transOpInt[$this->operator], $compareBranches)) {
// special case, e.g. require >= 1.0 and provide < 1.0 // special case, e.g. require >= 1.0 and provide < 1.0
// 1.0 >= 1.0 but 1.0 is outside of the provided interval // 1.0 >= 1.0 but 1.0 is outside of the provided interval
if ($provider->version === $this->version return !($provider->version === $this->version
&& self::$transOpInt[$provider->operator] === $providerNoEqualOp && self::$transOpInt[$provider->operator] === $providerNoEqualOp
&& self::$transOpInt[$this->operator] !== $noEqualOp) { && self::$transOpInt[$this->operator] !== $noEqualOp);
return false;
}
return true;
} }
return false; return false;
@@ -46,7 +46,7 @@ class EmptyConstraint implements ConstraintInterface
return $this->prettyString; return $this->prettyString;
} }
return $this->__toString(); return (string) $this;
} }
/** /**
@@ -102,7 +102,7 @@ class MultiConstraint implements ConstraintInterface
return $this->prettyString; return $this->prettyString;
} }
return $this->__toString(); return (string) $this;
} }
/** /**
+2 -2
View File
@@ -37,9 +37,9 @@ class Semver
$versionParser = self::$versionParser; $versionParser = self::$versionParser;
$provider = new Constraint('==', $versionParser->normalize($version)); $provider = new Constraint('==', $versionParser->normalize($version));
$constraints = $versionParser->parseConstraints($constraints); $parsedConstraints = $versionParser->parseConstraints($constraints);
return $constraints->matches($provider); return $parsedConstraints->matches($provider);
} }
/** /**
@@ -52,11 +52,12 @@ class VersionParser
{ {
$version = preg_replace('{#.+$}i', '', $version); $version = preg_replace('{#.+$}i', '', $version);
if ('dev-' === substr($version, 0, 4) || '-dev' === substr($version, -4)) { if (strpos($version, 'dev-') === 0 || '-dev' === substr($version, -4)) {
return 'dev'; return 'dev';
} }
preg_match('{' . self::$modifierRegex . '(?:\+.*)?$}i', strtolower($version), $match); preg_match('{' . self::$modifierRegex . '(?:\+.*)?$}i', strtolower($version), $match);
if (!empty($match[3])) { if (!empty($match[3])) {
return 'dev'; return 'dev';
} }
@@ -107,6 +108,9 @@ class VersionParser
// strip off aliasing // strip off aliasing
if (preg_match('{^([^,\s]++) ++as ++([^,\s]++)$}', $version, $match)) { if (preg_match('{^([^,\s]++) ++as ++([^,\s]++)$}', $version, $match)) {
// verify that the alias is a version without constraint
$this->normalize($match[2]);
$version = $match[1]; $version = $match[1];
} }
@@ -116,7 +120,7 @@ class VersionParser
} }
// if requirement is branch-like, use full name // if requirement is branch-like, use full name
if ('dev-' === strtolower(substr($version, 0, 4))) { if (stripos($version, 'dev-') === 0) {
return 'dev-' . substr($version, 4); return 'dev-' . substr($version, 4);
} }
@@ -236,6 +240,7 @@ class VersionParser
$orConstraints = preg_split('{\s*\|\|?\s*}', trim($constraints)); $orConstraints = preg_split('{\s*\|\|?\s*}', trim($constraints));
$orGroups = array(); $orGroups = array();
foreach ($orConstraints as $constraints) { foreach ($orConstraints as $constraints) {
$andConstraints = preg_split('{(?<!^|as|[=>< ,]) *(?<!-)[, ](?!-) *(?!,|as|$)}', $constraints); $andConstraints = preg_split('{(?<!^|as|[=>< ,]) *(?<!-)[, ](?!-) *(?!,|as|$)}', $constraints);
if (count($andConstraints) > 1) { if (count($andConstraints) > 1) {
@@ -268,9 +273,9 @@ class VersionParser
&& 2 === count($orGroups[0]->getConstraints()) && 2 === count($orGroups[0]->getConstraints())
&& 2 === count($orGroups[1]->getConstraints()) && 2 === count($orGroups[1]->getConstraints())
&& ($a = (string) $orGroups[0]) && ($a = (string) $orGroups[0])
&& substr($a, 0, 3) === '[>=' && (false !== ($posA = strpos($a, '<', 4))) && strpos($a, '[>=') === 0 && (false !== ($posA = strpos($a, '<', 4)))
&& ($b = (string) $orGroups[1]) && ($b = (string) $orGroups[1])
&& substr($b, 0, 3) === '[>=' && (false !== ($posB = strpos($b, '<', 4))) && strpos($b, '[>=') === 0 && (false !== ($posB = strpos($b, '<', 4)))
&& substr($a, $posA + 2, -1) === substr($b, 4, $posB - 5) && substr($a, $posA + 2, -1) === substr($b, 4, $posB - 5)
) { ) {
$constraint = new MultiConstraint(array( $constraint = new MultiConstraint(array(
@@ -314,7 +319,7 @@ class VersionParser
// version, to ensure that unstable instances of the current version are allowed. However, if a stability // version, to ensure that unstable instances of the current version are allowed. However, if a stability
// suffix is added to the constraint, then a >= match on the current version is used instead. // suffix is added to the constraint, then a >= match on the current version is used instead.
if (preg_match('{^~>?' . $versionRegex . '$}i', $constraint, $matches)) { if (preg_match('{^~>?' . $versionRegex . '$}i', $constraint, $matches)) {
if (substr($constraint, 0, 2) === '~>') { if (strpos($constraint, '~>') === 0) {
throw new \UnexpectedValueException( throw new \UnexpectedValueException(
'Could not parse version constraint ' . $constraint . ': ' . 'Could not parse version constraint ' . $constraint . ': ' .
'Invalid operator "~>", you probably meant to use the "~" operator' 'Invalid operator "~>", you probably meant to use the "~" operator'
@@ -322,11 +327,11 @@ class VersionParser
} }
// Work out which position in the version we are operating at // Work out which position in the version we are operating at
if (isset($matches[4]) && '' !== $matches[4]) { if (isset($matches[4]) && '' !== $matches[4] && null !== $matches[4]) {
$position = 4; $position = 4;
} elseif (isset($matches[3]) && '' !== $matches[3]) { } elseif (isset($matches[3]) && '' !== $matches[3] && null !== $matches[3]) {
$position = 3; $position = 3;
} elseif (isset($matches[2]) && '' !== $matches[2]) { } elseif (isset($matches[2]) && '' !== $matches[2] && null !== $matches[2]) {
$position = 2; $position = 2;
} else { } else {
$position = 1; $position = 1;
@@ -334,19 +339,11 @@ class VersionParser
// Calculate the stability suffix // Calculate the stability suffix
$stabilitySuffix = ''; $stabilitySuffix = '';
if (!empty($matches[5])) { if (empty($matches[5]) && empty($matches[7])) {
$stabilitySuffix .= '-' . $this->expandStability($matches[5]) . (!empty($matches[6]) ? $matches[6] : '');
}
if (!empty($matches[7])) {
$stabilitySuffix .= '-dev'; $stabilitySuffix .= '-dev';
} }
if (!$stabilitySuffix) { $lowVersion = $this->normalize(substr($constraint . $stabilitySuffix, 1));
$stabilitySuffix = '-dev';
}
$lowVersion = $this->manipulateVersionString($matches, $position, 0) . $stabilitySuffix;
$lowerBound = new Constraint('>=', $lowVersion); $lowerBound = new Constraint('>=', $lowVersion);
// For upper bound, we increment the position of one more significance, // For upper bound, we increment the position of one more significance,
@@ -368,9 +365,9 @@ class VersionParser
// versions 0.X >=0.1.0, and no updates for versions 0.0.X // versions 0.X >=0.1.0, and no updates for versions 0.0.X
if (preg_match('{^\^' . $versionRegex . '($)}i', $constraint, $matches)) { if (preg_match('{^\^' . $versionRegex . '($)}i', $constraint, $matches)) {
// Work out which position in the version we are operating at // Work out which position in the version we are operating at
if ('0' !== $matches[1] || '' === $matches[2]) { if ('0' !== $matches[1] || '' === $matches[2] || null === $matches[2]) {
$position = 1; $position = 1;
} elseif ('0' !== $matches[2] || '' === $matches[3]) { } elseif ('0' !== $matches[2] || '' === $matches[3] || null === $matches[3]) {
$position = 2; $position = 2;
} else { } else {
$position = 3; $position = 3;
@@ -401,9 +398,9 @@ class VersionParser
// Any of X, x, or * may be used to "stand in" for one of the numeric values in the [major, minor, patch] tuple. // Any of X, x, or * may be used to "stand in" for one of the numeric values in the [major, minor, patch] tuple.
// A partial version range is treated as an X-Range, so the special character is in fact optional. // A partial version range is treated as an X-Range, so the special character is in fact optional.
if (preg_match('{^v?(\d++)(?:\.(\d++))?(?:\.(\d++))?(?:\.[xX*])++$}', $constraint, $matches)) { if (preg_match('{^v?(\d++)(?:\.(\d++))?(?:\.(\d++))?(?:\.[xX*])++$}', $constraint, $matches)) {
if (isset($matches[3]) && '' !== $matches[3]) { if (isset($matches[3]) && '' !== $matches[3] && null !== $matches[3]) {
$position = 3; $position = 3;
} elseif (isset($matches[2]) && '' !== $matches[2]) { } elseif (isset($matches[2]) && '' !== $matches[2] && null !== $matches[2]) {
$position = 2; $position = 2;
} else { } else {
$position = 1; $position = 1;
@@ -462,11 +459,11 @@ class VersionParser
try { try {
$version = $this->normalize($matches[2]); $version = $this->normalize($matches[2]);
if (!empty($stabilityModifier) && $this->parseStability($version) === 'stable') { if (!empty($stabilityModifier) && self::parseStability($version) === 'stable') {
$version .= '-' . $stabilityModifier; $version .= '-' . $stabilityModifier;
} elseif ('<' === $matches[1] || '>=' === $matches[1]) { } elseif ('<' === $matches[1] || '>=' === $matches[1]) {
if (!preg_match('/-' . self::$modifierRegex . '$/', strtolower($matches[2]))) { if (!preg_match('/-' . self::$modifierRegex . '$/', strtolower($matches[2]))) {
if (substr($matches[2], 0, 4) !== 'dev-') { if (strpos($matches[2], 'dev-') !== 0) {
$version .= '-dev'; $version .= '-dev';
} }
} }
@@ -511,7 +508,7 @@ class VersionParser
// Return null on a carry overflow // Return null on a carry overflow
if ($i === 1) { if ($i === 1) {
return; return null;
} }
} }
} }
+41
View File
@@ -1,3 +1,44 @@
# v3.0.9
## 06/08/2020
1. [](#improved)
* Disable password autocomplete in password field
* Don't save empty string in password field [#134](https://github.com/getgrav/grav-plugin-email/issues/134)
# v3.0.8
## 04/27/2020
1. [](#improved)
* Updated vendor library files
* Use Grav's Parsedown class
# v3.0.7
## 03/05/2020
1. [](#improved)
* Updated email validator library
1. [](#bugfix)
* Fixed `Invalid resource theme://` on CLI command `test-email` on Grav 1.6.21 and later versions [#128](https://github.com/getgrav/grav-plugin-email/issues/128)
# v3.0.6
## 02/11/2020
1. [](#improved)
* Updated email validator library
# v3.0.5
## 02/03/2020
1. [](#bugfix)
* Fixed a date in changelog (no other changes)
# v3.0.4
## 01/17/2020
1. [](#improved)
* Added ZOHO configuration example
* Updated SwiftMailer library for PHP 7.4 support
# v3.0.3 # v3.0.3
## 08/16/2019 ## 08/16/2019
+19
View File
@@ -159,6 +159,25 @@ mailer:
It's that easy! It's that easy!
#### ZOHO
ZOHO is a popular solution for hosted email due to it's great 'FREE' tier. It's paid options are also very reasonable and combined with the latest UI updates and outstanding security features, it's a solid email option.
In order to get ZOHO working with Grav, you need to send email via a user account. You can either use your users' password or generate an **App Password** via your ZOHO account (clicking on your avatar once logged in), then navigating to `Two Factor Authentication -> App Passwords -> Generate`. Just enter a unique app name (i.e. `Grav Website`).
NOTE: The SMTP host required can be found in `Settings -> Mail - > Mail Accounts -> POP/IMAP -> SMTP`. This will provide the SMTP server for this account (it may not be `imap.zoho.com` depending on what region you are in)
```
mailer:
engine: smtp
smtp:
server: smtp.zoho.com
port: 587
encryption: tls
user: 'ZOHO_EMAIL_ADDRESS'
password: 'ZOHO_EMAIL_PASSWORD'
```
#### Sendmail #### Sendmail
Although not as reliable as SMTP not providing as much debug information, sendmail is a simple option as long as your hosting provider is not blocking the default SMTP port `25`: Although not as reliable as SMTP not providing as much debug information, sendmail is a simple option as long as your hosting provider is not blocking the default SMTP port `25`:
+6 -3
View File
@@ -1,5 +1,7 @@
name: Email name: Email
version: 3.0.3 slug: email
type: plugin
version: 3.0.9
testing: false testing: false
description: Enables the emailing system for Grav description: Enables the emailing system for Grav
icon: envelope icon: envelope
@@ -18,6 +20,7 @@ dependencies:
form: form:
validation: loose validation: loose
fields: fields:
enabled: enabled:
type: hidden type: hidden
@@ -168,13 +171,13 @@ form:
mailer.smtp.user: mailer.smtp.user:
type: text type: text
size: medium size: medium
autocomplete: nope autocomplete: 'off'
label: PLUGIN_EMAIL.SMTP_LOGIN_NAME label: PLUGIN_EMAIL.SMTP_LOGIN_NAME
mailer.smtp.password: mailer.smtp.password:
type: password type: password
size: medium size: medium
autocomplete: nope autocomplete: 'new-password'
label: PLUGIN_EMAIL.SMTP_PASSWORD label: PLUGIN_EMAIL.SMTP_PASSWORD
sendmail_config: sendmail_config:
+3 -2
View File
@@ -4,6 +4,7 @@ namespace Grav\Plugin\Email;
use Grav\Common\Config\Config; use Grav\Common\Config\Config;
use Grav\Common\Grav; use Grav\Common\Grav;
use Grav\Common\Language\Language; use Grav\Common\Language\Language;
use Grav\Common\Markdown\Parsedown;
use Grav\Common\Twig\Twig; use Grav\Common\Twig\Twig;
use Grav\Framework\Form\Interfaces\FormInterface; use Grav\Framework\Form\Interfaces\FormInterface;
use \Monolog\Logger; use \Monolog\Logger;
@@ -178,7 +179,7 @@ class Email
$body = $twig->processString($value, $vars); $body = $twig->processString($value, $vars);
if ($params['process_markdown']) { if ($params['process_markdown']) {
$parsedown = new \Parsedown(); $parsedown = new Parsedown();
$body = $parsedown->text($body); $body = $parsedown->text($body);
} }
@@ -202,7 +203,7 @@ class Email
$body = !empty($body_part['body']) ? $twig->processString($body_part['body'], $vars) : null; $body = !empty($body_part['body']) ? $twig->processString($body_part['body'], $vars) : null;
if ($params['process_markdown']) { if ($params['process_markdown']) {
$parsedown = new \Parsedown(); $parsedown = new Parsedown();
$body = $parsedown->text($body); $body = $parsedown->text($body);
} }
@@ -40,6 +40,11 @@ class ClearQueueFailuresCommand extends ConsoleCommand
*/ */
protected function serve() protected function serve()
{ {
// TODO: remove when requiring Grav 1.7+
if (method_exists($this, 'initializeGrav')) {
$this->initializeGrav();
}
$grav = Grav::instance(); $grav = Grav::instance();
$this->output->writeln(''); $this->output->writeln('');
@@ -40,6 +40,11 @@ class FlushQueueCommand extends ConsoleCommand
*/ */
protected function serve() protected function serve()
{ {
// TODO: remove when requiring Grav 1.7+
if (method_exists($this, 'initializeGrav')) {
$this->initializeGrav();
}
$grav = Grav::instance(); $grav = Grav::instance();
$this->output->writeln(''); $this->output->writeln('');
+5 -4
View File
@@ -59,6 +59,11 @@ class TestEmailCommand extends ConsoleCommand
*/ */
protected function serve() protected function serve()
{ {
// TODO: remove when requiring Grav 1.7+
if (method_exists($this, 'initializeGrav')) {
$this->initializeThemes();
}
$grav = Grav::instance(); $grav = Grav::instance();
$this->output->writeln(''); $this->output->writeln('');
@@ -69,8 +74,6 @@ class TestEmailCommand extends ConsoleCommand
$this->output->writeln(''); $this->output->writeln('');
require_once __DIR__ . '/../vendor/autoload.php';
$grav['Email'] = new Email(); $grav['Email'] = new Email();
$to = $this->input->getOption('to') ?: $grav['config']->get('plugins.email.to'); $to = $this->input->getOption('to') ?: $grav['config']->get('plugins.email.to');
@@ -86,8 +89,6 @@ class TestEmailCommand extends ConsoleCommand
$body = $grav['language']->translate(['PLUGIN_EMAIL.TEST_EMAIL_BODY', $configuration]); $body = $grav['language']->translate(['PLUGIN_EMAIL.TEST_EMAIL_BODY', $configuration]);
} }
// This is the old way....
// $sent = EmailUtils::sendEmail($subject, $body, $email_to);
$sent = EmailUtils::sendEmail(['subject'=>$subject, 'body'=>$body, 'to'=>$to]); $sent = EmailUtils::sendEmail(['subject'=>$subject, 'body'=>$body, 'to'=>$to]);
if ($sent) { if ($sent) {
+126 -60
View File
@@ -8,30 +8,35 @@
"packages": [ "packages": [
{ {
"name": "doctrine/lexer", "name": "doctrine/lexer",
"version": "v1.0.1", "version": "1.2.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/doctrine/lexer.git", "url": "https://github.com/doctrine/lexer.git",
"reference": "83893c552fd2045dd78aef794c31e694c37c0b8c" "reference": "5242d66dbeb21a30dd8a3e66bf7a73b66e05e1f6"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/doctrine/lexer/zipball/83893c552fd2045dd78aef794c31e694c37c0b8c", "url": "https://api.github.com/repos/doctrine/lexer/zipball/5242d66dbeb21a30dd8a3e66bf7a73b66e05e1f6",
"reference": "83893c552fd2045dd78aef794c31e694c37c0b8c", "reference": "5242d66dbeb21a30dd8a3e66bf7a73b66e05e1f6",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"php": ">=5.3.2" "php": "^7.2"
},
"require-dev": {
"doctrine/coding-standard": "^6.0",
"phpstan/phpstan": "^0.11.8",
"phpunit/phpunit": "^8.2"
}, },
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-master": "1.0.x-dev" "dev-master": "1.2.x-dev"
} }
}, },
"autoload": { "autoload": {
"psr-0": { "psr-4": {
"Doctrine\\Common\\Lexer\\": "lib/" "Doctrine\\Common\\Lexer\\": "lib/Doctrine/Common/Lexer"
} }
}, },
"notification-url": "https://packagist.org/downloads/", "notification-url": "https://packagist.org/downloads/",
@@ -39,48 +44,52 @@
"MIT" "MIT"
], ],
"authors": [ "authors": [
{
"name": "Roman Borschel",
"email": "roman@code-factory.org"
},
{ {
"name": "Guilherme Blanco", "name": "Guilherme Blanco",
"email": "guilhermeblanco@gmail.com" "email": "guilhermeblanco@gmail.com"
}, },
{
"name": "Roman Borschel",
"email": "roman@code-factory.org"
},
{ {
"name": "Johannes Schmitt", "name": "Johannes Schmitt",
"email": "schmittjoh@gmail.com" "email": "schmittjoh@gmail.com"
} }
], ],
"description": "Base library for a lexer that can be used in Top-Down, Recursive Descent Parsers.", "description": "PHP Doctrine Lexer parser library that can be used in Top-Down, Recursive Descent Parsers.",
"homepage": "http://www.doctrine-project.org", "homepage": "https://www.doctrine-project.org/projects/lexer.html",
"keywords": [ "keywords": [
"annotations",
"docblock",
"lexer", "lexer",
"parser" "parser",
"php"
], ],
"time": "2014-09-09T13:34:57+00:00" "time": "2019-10-30T14:39:59+00:00"
}, },
{ {
"name": "egulias/email-validator", "name": "egulias/email-validator",
"version": "2.1.7", "version": "2.1.17",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/egulias/EmailValidator.git", "url": "https://github.com/egulias/EmailValidator.git",
"reference": "709f21f92707308cdf8f9bcfa1af4cb26586521e" "reference": "ade6887fd9bd74177769645ab5c474824f8a418a"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/egulias/EmailValidator/zipball/709f21f92707308cdf8f9bcfa1af4cb26586521e", "url": "https://api.github.com/repos/egulias/EmailValidator/zipball/ade6887fd9bd74177769645ab5c474824f8a418a",
"reference": "709f21f92707308cdf8f9bcfa1af4cb26586521e", "reference": "ade6887fd9bd74177769645ab5c474824f8a418a",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"doctrine/lexer": "^1.0.1", "doctrine/lexer": "^1.0.1",
"php": ">= 5.5" "php": ">=5.5",
"symfony/polyfill-intl-idn": "^1.10"
}, },
"require-dev": { "require-dev": {
"dominicsayers/isemail": "dev-master", "dominicsayers/isemail": "^3.0.7",
"phpunit/phpunit": "^4.8.35||^5.7||^6.0", "phpunit/phpunit": "^4.8.36|^7.5.15",
"satooshi/php-coveralls": "^1.0.1" "satooshi/php-coveralls": "^1.0.1"
}, },
"suggest": { "suggest": {
@@ -89,7 +98,7 @@
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-master": "2.0.x-dev" "dev-master": "2.1.x-dev"
} }
}, },
"autoload": { "autoload": {
@@ -115,20 +124,20 @@
"validation", "validation",
"validator" "validator"
], ],
"time": "2018-12-04T22:38:24+00:00" "time": "2020-02-13T22:36:52+00:00"
}, },
{ {
"name": "swiftmailer/swiftmailer", "name": "swiftmailer/swiftmailer",
"version": "v6.2.0", "version": "v6.2.3",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/swiftmailer/swiftmailer.git", "url": "https://github.com/swiftmailer/swiftmailer.git",
"reference": "6fa3232ff9d3f8237c0fae4b7ff05e1baa4cd707" "reference": "149cfdf118b169f7840bbe3ef0d4bc795d1780c9"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/swiftmailer/swiftmailer/zipball/6fa3232ff9d3f8237c0fae4b7ff05e1baa4cd707", "url": "https://api.github.com/repos/swiftmailer/swiftmailer/zipball/149cfdf118b169f7840bbe3ef0d4bc795d1780c9",
"reference": "6fa3232ff9d3f8237c0fae4b7ff05e1baa4cd707", "reference": "149cfdf118b169f7840bbe3ef0d4bc795d1780c9",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -177,20 +186,20 @@
"mail", "mail",
"mailer" "mailer"
], ],
"time": "2019-03-10T07:52:41+00:00" "time": "2019-11-12T09:31:26+00:00"
}, },
{ {
"name": "symfony/polyfill-iconv", "name": "symfony/polyfill-iconv",
"version": "v1.10.0", "version": "v1.15.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/polyfill-iconv.git", "url": "https://github.com/symfony/polyfill-iconv.git",
"reference": "97001cfc283484c9691769f51cdf25259037eba2" "reference": "ad6d62792bfbcfc385dd34b424d4fcf9712a32c8"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-iconv/zipball/97001cfc283484c9691769f51cdf25259037eba2", "url": "https://api.github.com/repos/symfony/polyfill-iconv/zipball/ad6d62792bfbcfc385dd34b424d4fcf9712a32c8",
"reference": "97001cfc283484c9691769f51cdf25259037eba2", "reference": "ad6d62792bfbcfc385dd34b424d4fcf9712a32c8",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -202,7 +211,7 @@
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-master": "1.9-dev" "dev-master": "1.15-dev"
} }
}, },
"autoload": { "autoload": {
@@ -236,26 +245,40 @@
"portable", "portable",
"shim" "shim"
], ],
"time": "2018-09-21T06:26:08+00:00" "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": "2020-03-09T19:04:49+00:00"
}, },
{ {
"name": "symfony/polyfill-intl-idn", "name": "symfony/polyfill-intl-idn",
"version": "v1.10.0", "version": "v1.15.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/polyfill-intl-idn.git", "url": "https://github.com/symfony/polyfill-intl-idn.git",
"reference": "89de1d44f2c059b266f22c9cc9124ddc4cd0987a" "reference": "47bd6aa45beb1cd7c6a16b7d1810133b728bdfcf"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/89de1d44f2c059b266f22c9cc9124ddc4cd0987a", "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/47bd6aa45beb1cd7c6a16b7d1810133b728bdfcf",
"reference": "89de1d44f2c059b266f22c9cc9124ddc4cd0987a", "reference": "47bd6aa45beb1cd7c6a16b7d1810133b728bdfcf",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"php": ">=5.3.3", "php": ">=5.3.3",
"symfony/polyfill-mbstring": "^1.3", "symfony/polyfill-mbstring": "^1.3",
"symfony/polyfill-php72": "^1.9" "symfony/polyfill-php72": "^1.10"
}, },
"suggest": { "suggest": {
"ext-intl": "For best performance" "ext-intl": "For best performance"
@@ -263,7 +286,7 @@
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-master": "1.9-dev" "dev-master": "1.15-dev"
} }
}, },
"autoload": { "autoload": {
@@ -279,13 +302,13 @@
"MIT" "MIT"
], ],
"authors": [ "authors": [
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
},
{ {
"name": "Laurent Bassin", "name": "Laurent Bassin",
"email": "laurent@bassin.info" "email": "laurent@bassin.info"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
} }
], ],
"description": "Symfony polyfill for intl's idn_to_ascii and idn_to_utf8 functions", "description": "Symfony polyfill for intl's idn_to_ascii and idn_to_utf8 functions",
@@ -298,20 +321,34 @@
"portable", "portable",
"shim" "shim"
], ],
"time": "2018-09-30T16:36:12+00:00" "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": "2020-03-09T19:04:49+00:00"
}, },
{ {
"name": "symfony/polyfill-mbstring", "name": "symfony/polyfill-mbstring",
"version": "v1.10.0", "version": "v1.15.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/polyfill-mbstring.git", "url": "https://github.com/symfony/polyfill-mbstring.git",
"reference": "c79c051f5b3a46be09205c73b80b346e4153e494" "reference": "81ffd3a9c6d707be22e3012b827de1c9775fc5ac"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/c79c051f5b3a46be09205c73b80b346e4153e494", "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/81ffd3a9c6d707be22e3012b827de1c9775fc5ac",
"reference": "c79c051f5b3a46be09205c73b80b346e4153e494", "reference": "81ffd3a9c6d707be22e3012b827de1c9775fc5ac",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -323,7 +360,7 @@
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-master": "1.9-dev" "dev-master": "1.15-dev"
} }
}, },
"autoload": { "autoload": {
@@ -357,20 +394,34 @@
"portable", "portable",
"shim" "shim"
], ],
"time": "2018-09-21T13:07:52+00:00" "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": "2020-03-09T19:04:49+00:00"
}, },
{ {
"name": "symfony/polyfill-php72", "name": "symfony/polyfill-php72",
"version": "v1.10.0", "version": "v1.15.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/polyfill-php72.git", "url": "https://github.com/symfony/polyfill-php72.git",
"reference": "9050816e2ca34a8e916c3a0ae8b9c2fccf68b631" "reference": "37b0976c78b94856543260ce09b460a7bc852747"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/9050816e2ca34a8e916c3a0ae8b9c2fccf68b631", "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/37b0976c78b94856543260ce09b460a7bc852747",
"reference": "9050816e2ca34a8e916c3a0ae8b9c2fccf68b631", "reference": "37b0976c78b94856543260ce09b460a7bc852747",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -379,7 +430,7 @@
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-master": "1.9-dev" "dev-master": "1.15-dev"
} }
}, },
"autoload": { "autoload": {
@@ -412,7 +463,21 @@
"portable", "portable",
"shim" "shim"
], ],
"time": "2018-09-21T13:07:52+00:00" "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": "2020-02-27T09:26:54+00:00"
} }
], ],
"packages-dev": [], "packages-dev": [],
@@ -424,5 +489,6 @@
"platform": { "platform": {
"php": ">=7.1.3" "php": ">=7.1.3"
}, },
"platform-dev": [] "platform-dev": [],
"plugin-api-version": "1.1.0"
} }
+24
View File
@@ -1,6 +1,7 @@
<?php <?php
namespace Grav\Plugin; namespace Grav\Plugin;
use Grav\Common\Data\Data;
use Grav\Common\Plugin; use Grav\Common\Plugin;
use Grav\Plugin\Email\Email; use Grav\Plugin\Email\Email;
use RocketTheme\Toolbox\Event\Event; use RocketTheme\Toolbox\Event\Event;
@@ -22,6 +23,7 @@ class EmailPlugin extends Plugin
'onFormProcessed' => ['onFormProcessed', 0], 'onFormProcessed' => ['onFormProcessed', 0],
'onTwigTemplatePaths' => ['onTwigTemplatePaths', 0], 'onTwigTemplatePaths' => ['onTwigTemplatePaths', 0],
'onSchedulerInitialized' => ['onSchedulerInitialized', 0], 'onSchedulerInitialized' => ['onSchedulerInitialized', 0],
'onAdminSave' => ['onAdminSave', 0],
]; ];
} }
@@ -48,6 +50,28 @@ class EmailPlugin extends Plugin
$twig->twig_paths[] = __DIR__ . '/templates'; $twig->twig_paths[] = __DIR__ . '/templates';
} }
/**
* Force compile during save if admin plugin save
*
* @param Event $event
*/
public function onAdminSave(Event $event)
{
/** @var Data $obj */
$obj = $event['object'];
if ($obj instanceof Data && $obj->blueprints()->getFilename() === 'email/blueprints') {
$current_pw = $this->grav['config']->get('plugins.email.mailer.smtp.password');
$new_pw = $obj->get('mailer.smtp.password');
if (!empty($current_pw) && empty($new_pw)) {
$obj->set('mailer.smtp.password', $current_pw);
}
}
}
/** /**
* Send email when processing the form data. * Send email when processing the form data.
* *
+2 -2
View File
@@ -279,7 +279,7 @@ class ClassLoader
*/ */
public function setApcuPrefix($apcuPrefix) public function setApcuPrefix($apcuPrefix)
{ {
$this->apcuPrefix = function_exists('apcu_fetch') && ini_get('apc.enabled') ? $apcuPrefix : null; $this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null;
} }
/** /**
@@ -377,7 +377,7 @@ class ClassLoader
$subPath = $class; $subPath = $class;
while (false !== $lastPos = strrpos($subPath, '\\')) { while (false !== $lastPos = strrpos($subPath, '\\')) {
$subPath = substr($subPath, 0, $lastPos); $subPath = substr($subPath, 0, $lastPos);
$search = $subPath.'\\'; $search = $subPath . '\\';
if (isset($this->prefixDirsPsr4[$search])) { if (isset($this->prefixDirsPsr4[$search])) {
$pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1); $pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1);
foreach ($this->prefixDirsPsr4[$search] as $dir) { foreach ($this->prefixDirsPsr4[$search] as $dir) {
+1 -1
View File
@@ -8,7 +8,7 @@ $baseDir = dirname($vendorDir);
return array( return array(
'0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => $vendorDir . '/symfony/polyfill-mbstring/bootstrap.php', '0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => $vendorDir . '/symfony/polyfill-mbstring/bootstrap.php',
'25072dd6e2470089de65ae7bf11d3109' => $vendorDir . '/symfony/polyfill-php72/bootstrap.php', '25072dd6e2470089de65ae7bf11d3109' => $vendorDir . '/symfony/polyfill-php72/bootstrap.php',
'def43f6c87e4f8dfd0c9e1b1bab14fe8' => $vendorDir . '/symfony/polyfill-iconv/bootstrap.php',
'f598d06aa772fa33d905e87be6398fb1' => $vendorDir . '/symfony/polyfill-intl-idn/bootstrap.php', 'f598d06aa772fa33d905e87be6398fb1' => $vendorDir . '/symfony/polyfill-intl-idn/bootstrap.php',
'def43f6c87e4f8dfd0c9e1b1bab14fe8' => $vendorDir . '/symfony/polyfill-iconv/bootstrap.php',
'2c102faa651ef8ea5874edb585946bce' => $vendorDir . '/swiftmailer/swiftmailer/lib/swift_required.php', '2c102faa651ef8ea5874edb585946bce' => $vendorDir . '/swiftmailer/swiftmailer/lib/swift_required.php',
); );
@@ -6,5 +6,4 @@ $vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir); $baseDir = dirname($vendorDir);
return array( return array(
'Doctrine\\Common\\Lexer\\' => array($vendorDir . '/doctrine/lexer/lib'),
); );
+1
View File
@@ -13,4 +13,5 @@ return array(
'Grav\\Plugin\\Email\\' => array($baseDir . '/classes'), 'Grav\\Plugin\\Email\\' => array($baseDir . '/classes'),
'Grav\\Plugin\\Console\\' => array($baseDir . '/cli'), 'Grav\\Plugin\\Console\\' => array($baseDir . '/cli'),
'Egulias\\EmailValidator\\' => array($vendorDir . '/egulias/email-validator/EmailValidator'), 'Egulias\\EmailValidator\\' => array($vendorDir . '/egulias/email-validator/EmailValidator'),
'Doctrine\\Common\\Lexer\\' => array($vendorDir . '/doctrine/lexer/lib/Doctrine/Common/Lexer'),
); );
+3
View File
@@ -13,6 +13,9 @@ class ComposerAutoloaderInitdec5d78def1384d1f20996ded9d7efbf
} }
} }
/**
* @return \Composer\Autoload\ClassLoader
*/
public static function getLoader() public static function getLoader()
{ {
if (null !== self::$loader) { if (null !== self::$loader) {
+7 -10
View File
@@ -9,8 +9,8 @@ class ComposerStaticInitdec5d78def1384d1f20996ded9d7efbf
public static $files = array ( public static $files = array (
'0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => __DIR__ . '/..' . '/symfony/polyfill-mbstring/bootstrap.php', '0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => __DIR__ . '/..' . '/symfony/polyfill-mbstring/bootstrap.php',
'25072dd6e2470089de65ae7bf11d3109' => __DIR__ . '/..' . '/symfony/polyfill-php72/bootstrap.php', '25072dd6e2470089de65ae7bf11d3109' => __DIR__ . '/..' . '/symfony/polyfill-php72/bootstrap.php',
'def43f6c87e4f8dfd0c9e1b1bab14fe8' => __DIR__ . '/..' . '/symfony/polyfill-iconv/bootstrap.php',
'f598d06aa772fa33d905e87be6398fb1' => __DIR__ . '/..' . '/symfony/polyfill-intl-idn/bootstrap.php', 'f598d06aa772fa33d905e87be6398fb1' => __DIR__ . '/..' . '/symfony/polyfill-intl-idn/bootstrap.php',
'def43f6c87e4f8dfd0c9e1b1bab14fe8' => __DIR__ . '/..' . '/symfony/polyfill-iconv/bootstrap.php',
'2c102faa651ef8ea5874edb585946bce' => __DIR__ . '/..' . '/swiftmailer/swiftmailer/lib/swift_required.php', '2c102faa651ef8ea5874edb585946bce' => __DIR__ . '/..' . '/swiftmailer/swiftmailer/lib/swift_required.php',
); );
@@ -31,6 +31,10 @@ class ComposerStaticInitdec5d78def1384d1f20996ded9d7efbf
array ( array (
'Egulias\\EmailValidator\\' => 23, 'Egulias\\EmailValidator\\' => 23,
), ),
'D' =>
array (
'Doctrine\\Common\\Lexer\\' => 22,
),
); );
public static $prefixDirsPsr4 = array ( public static $prefixDirsPsr4 = array (
@@ -62,15 +66,9 @@ class ComposerStaticInitdec5d78def1384d1f20996ded9d7efbf
array ( array (
0 => __DIR__ . '/..' . '/egulias/email-validator/EmailValidator', 0 => __DIR__ . '/..' . '/egulias/email-validator/EmailValidator',
), ),
); 'Doctrine\\Common\\Lexer\\' =>
public static $prefixesPsr0 = array (
'D' =>
array ( array (
'Doctrine\\Common\\Lexer\\' => 0 => __DIR__ . '/..' . '/doctrine/lexer/lib/Doctrine/Common/Lexer',
array (
0 => __DIR__ . '/..' . '/doctrine/lexer/lib',
),
), ),
); );
@@ -83,7 +81,6 @@ class ComposerStaticInitdec5d78def1384d1f20996ded9d7efbf
return \Closure::bind(function () use ($loader) { return \Closure::bind(function () use ($loader) {
$loader->prefixLengthsPsr4 = ComposerStaticInitdec5d78def1384d1f20996ded9d7efbf::$prefixLengthsPsr4; $loader->prefixLengthsPsr4 = ComposerStaticInitdec5d78def1384d1f20996ded9d7efbf::$prefixLengthsPsr4;
$loader->prefixDirsPsr4 = ComposerStaticInitdec5d78def1384d1f20996ded9d7efbf::$prefixDirsPsr4; $loader->prefixDirsPsr4 = ComposerStaticInitdec5d78def1384d1f20996ded9d7efbf::$prefixDirsPsr4;
$loader->prefixesPsr0 = ComposerStaticInitdec5d78def1384d1f20996ded9d7efbf::$prefixesPsr0;
$loader->classMap = ComposerStaticInitdec5d78def1384d1f20996ded9d7efbf::$classMap; $loader->classMap = ComposerStaticInitdec5d78def1384d1f20996ded9d7efbf::$classMap;
}, null, ClassLoader::class); }, null, ClassLoader::class);
+131 -66
View File
@@ -1,33 +1,38 @@
[ [
{ {
"name": "doctrine/lexer", "name": "doctrine/lexer",
"version": "v1.0.1", "version": "1.2.0",
"version_normalized": "1.0.1.0", "version_normalized": "1.2.0.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/doctrine/lexer.git", "url": "https://github.com/doctrine/lexer.git",
"reference": "83893c552fd2045dd78aef794c31e694c37c0b8c" "reference": "5242d66dbeb21a30dd8a3e66bf7a73b66e05e1f6"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/doctrine/lexer/zipball/83893c552fd2045dd78aef794c31e694c37c0b8c", "url": "https://api.github.com/repos/doctrine/lexer/zipball/5242d66dbeb21a30dd8a3e66bf7a73b66e05e1f6",
"reference": "83893c552fd2045dd78aef794c31e694c37c0b8c", "reference": "5242d66dbeb21a30dd8a3e66bf7a73b66e05e1f6",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"php": ">=5.3.2" "php": "^7.2"
}, },
"time": "2014-09-09T13:34:57+00:00", "require-dev": {
"doctrine/coding-standard": "^6.0",
"phpstan/phpstan": "^0.11.8",
"phpunit/phpunit": "^8.2"
},
"time": "2019-10-30T14:39:59+00:00",
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-master": "1.0.x-dev" "dev-master": "1.2.x-dev"
} }
}, },
"installation-source": "dist", "installation-source": "dist",
"autoload": { "autoload": {
"psr-0": { "psr-4": {
"Doctrine\\Common\\Lexer\\": "lib/" "Doctrine\\Common\\Lexer\\": "lib/Doctrine/Common/Lexer"
} }
}, },
"notification-url": "https://packagist.org/downloads/", "notification-url": "https://packagist.org/downloads/",
@@ -35,58 +40,62 @@
"MIT" "MIT"
], ],
"authors": [ "authors": [
{
"name": "Roman Borschel",
"email": "roman@code-factory.org"
},
{ {
"name": "Guilherme Blanco", "name": "Guilherme Blanco",
"email": "guilhermeblanco@gmail.com" "email": "guilhermeblanco@gmail.com"
}, },
{
"name": "Roman Borschel",
"email": "roman@code-factory.org"
},
{ {
"name": "Johannes Schmitt", "name": "Johannes Schmitt",
"email": "schmittjoh@gmail.com" "email": "schmittjoh@gmail.com"
} }
], ],
"description": "Base library for a lexer that can be used in Top-Down, Recursive Descent Parsers.", "description": "PHP Doctrine Lexer parser library that can be used in Top-Down, Recursive Descent Parsers.",
"homepage": "http://www.doctrine-project.org", "homepage": "https://www.doctrine-project.org/projects/lexer.html",
"keywords": [ "keywords": [
"annotations",
"docblock",
"lexer", "lexer",
"parser" "parser",
"php"
] ]
}, },
{ {
"name": "egulias/email-validator", "name": "egulias/email-validator",
"version": "2.1.7", "version": "2.1.17",
"version_normalized": "2.1.7.0", "version_normalized": "2.1.17.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/egulias/EmailValidator.git", "url": "https://github.com/egulias/EmailValidator.git",
"reference": "709f21f92707308cdf8f9bcfa1af4cb26586521e" "reference": "ade6887fd9bd74177769645ab5c474824f8a418a"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/egulias/EmailValidator/zipball/709f21f92707308cdf8f9bcfa1af4cb26586521e", "url": "https://api.github.com/repos/egulias/EmailValidator/zipball/ade6887fd9bd74177769645ab5c474824f8a418a",
"reference": "709f21f92707308cdf8f9bcfa1af4cb26586521e", "reference": "ade6887fd9bd74177769645ab5c474824f8a418a",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"doctrine/lexer": "^1.0.1", "doctrine/lexer": "^1.0.1",
"php": ">= 5.5" "php": ">=5.5",
"symfony/polyfill-intl-idn": "^1.10"
}, },
"require-dev": { "require-dev": {
"dominicsayers/isemail": "dev-master", "dominicsayers/isemail": "^3.0.7",
"phpunit/phpunit": "^4.8.35||^5.7||^6.0", "phpunit/phpunit": "^4.8.36|^7.5.15",
"satooshi/php-coveralls": "^1.0.1" "satooshi/php-coveralls": "^1.0.1"
}, },
"suggest": { "suggest": {
"ext-intl": "PHP Internationalization Libraries are required to use the SpoofChecking validation" "ext-intl": "PHP Internationalization Libraries are required to use the SpoofChecking validation"
}, },
"time": "2018-12-04T22:38:24+00:00", "time": "2020-02-13T22:36:52+00:00",
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-master": "2.0.x-dev" "dev-master": "2.1.x-dev"
} }
}, },
"installation-source": "dist", "installation-source": "dist",
@@ -116,17 +125,17 @@
}, },
{ {
"name": "swiftmailer/swiftmailer", "name": "swiftmailer/swiftmailer",
"version": "v6.2.0", "version": "v6.2.3",
"version_normalized": "6.2.0.0", "version_normalized": "6.2.3.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/swiftmailer/swiftmailer.git", "url": "https://github.com/swiftmailer/swiftmailer.git",
"reference": "6fa3232ff9d3f8237c0fae4b7ff05e1baa4cd707" "reference": "149cfdf118b169f7840bbe3ef0d4bc795d1780c9"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/swiftmailer/swiftmailer/zipball/6fa3232ff9d3f8237c0fae4b7ff05e1baa4cd707", "url": "https://api.github.com/repos/swiftmailer/swiftmailer/zipball/149cfdf118b169f7840bbe3ef0d4bc795d1780c9",
"reference": "6fa3232ff9d3f8237c0fae4b7ff05e1baa4cd707", "reference": "149cfdf118b169f7840bbe3ef0d4bc795d1780c9",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -144,7 +153,7 @@
"ext-intl": "Needed to support internationalized email addresses", "ext-intl": "Needed to support internationalized email addresses",
"true/punycode": "Needed to support internationalized email addresses, if ext-intl is not installed" "true/punycode": "Needed to support internationalized email addresses, if ext-intl is not installed"
}, },
"time": "2019-03-10T07:52:41+00:00", "time": "2019-11-12T09:31:26+00:00",
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
@@ -180,17 +189,17 @@
}, },
{ {
"name": "symfony/polyfill-iconv", "name": "symfony/polyfill-iconv",
"version": "v1.10.0", "version": "v1.15.0",
"version_normalized": "1.10.0.0", "version_normalized": "1.15.0.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/polyfill-iconv.git", "url": "https://github.com/symfony/polyfill-iconv.git",
"reference": "97001cfc283484c9691769f51cdf25259037eba2" "reference": "ad6d62792bfbcfc385dd34b424d4fcf9712a32c8"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-iconv/zipball/97001cfc283484c9691769f51cdf25259037eba2", "url": "https://api.github.com/repos/symfony/polyfill-iconv/zipball/ad6d62792bfbcfc385dd34b424d4fcf9712a32c8",
"reference": "97001cfc283484c9691769f51cdf25259037eba2", "reference": "ad6d62792bfbcfc385dd34b424d4fcf9712a32c8",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -199,11 +208,11 @@
"suggest": { "suggest": {
"ext-iconv": "For best performance" "ext-iconv": "For best performance"
}, },
"time": "2018-09-21T06:26:08+00:00", "time": "2020-03-09T19:04:49+00:00",
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-master": "1.9-dev" "dev-master": "1.15-dev"
} }
}, },
"installation-source": "dist", "installation-source": "dist",
@@ -237,36 +246,50 @@
"polyfill", "polyfill",
"portable", "portable",
"shim" "shim"
],
"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"
}
] ]
}, },
{ {
"name": "symfony/polyfill-intl-idn", "name": "symfony/polyfill-intl-idn",
"version": "v1.10.0", "version": "v1.15.0",
"version_normalized": "1.10.0.0", "version_normalized": "1.15.0.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/polyfill-intl-idn.git", "url": "https://github.com/symfony/polyfill-intl-idn.git",
"reference": "89de1d44f2c059b266f22c9cc9124ddc4cd0987a" "reference": "47bd6aa45beb1cd7c6a16b7d1810133b728bdfcf"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/89de1d44f2c059b266f22c9cc9124ddc4cd0987a", "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/47bd6aa45beb1cd7c6a16b7d1810133b728bdfcf",
"reference": "89de1d44f2c059b266f22c9cc9124ddc4cd0987a", "reference": "47bd6aa45beb1cd7c6a16b7d1810133b728bdfcf",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"php": ">=5.3.3", "php": ">=5.3.3",
"symfony/polyfill-mbstring": "^1.3", "symfony/polyfill-mbstring": "^1.3",
"symfony/polyfill-php72": "^1.9" "symfony/polyfill-php72": "^1.10"
}, },
"suggest": { "suggest": {
"ext-intl": "For best performance" "ext-intl": "For best performance"
}, },
"time": "2018-09-30T16:36:12+00:00", "time": "2020-03-09T19:04:49+00:00",
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-master": "1.9-dev" "dev-master": "1.15-dev"
} }
}, },
"installation-source": "dist", "installation-source": "dist",
@@ -283,13 +306,13 @@
"MIT" "MIT"
], ],
"authors": [ "authors": [
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
},
{ {
"name": "Laurent Bassin", "name": "Laurent Bassin",
"email": "laurent@bassin.info" "email": "laurent@bassin.info"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
} }
], ],
"description": "Symfony polyfill for intl's idn_to_ascii and idn_to_utf8 functions", "description": "Symfony polyfill for intl's idn_to_ascii and idn_to_utf8 functions",
@@ -301,21 +324,35 @@
"polyfill", "polyfill",
"portable", "portable",
"shim" "shim"
],
"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"
}
] ]
}, },
{ {
"name": "symfony/polyfill-mbstring", "name": "symfony/polyfill-mbstring",
"version": "v1.10.0", "version": "v1.15.0",
"version_normalized": "1.10.0.0", "version_normalized": "1.15.0.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/polyfill-mbstring.git", "url": "https://github.com/symfony/polyfill-mbstring.git",
"reference": "c79c051f5b3a46be09205c73b80b346e4153e494" "reference": "81ffd3a9c6d707be22e3012b827de1c9775fc5ac"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/c79c051f5b3a46be09205c73b80b346e4153e494", "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/81ffd3a9c6d707be22e3012b827de1c9775fc5ac",
"reference": "c79c051f5b3a46be09205c73b80b346e4153e494", "reference": "81ffd3a9c6d707be22e3012b827de1c9775fc5ac",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -324,11 +361,11 @@
"suggest": { "suggest": {
"ext-mbstring": "For best performance" "ext-mbstring": "For best performance"
}, },
"time": "2018-09-21T13:07:52+00:00", "time": "2020-03-09T19:04:49+00:00",
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-master": "1.9-dev" "dev-master": "1.15-dev"
} }
}, },
"installation-source": "dist", "installation-source": "dist",
@@ -362,31 +399,45 @@
"polyfill", "polyfill",
"portable", "portable",
"shim" "shim"
],
"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"
}
] ]
}, },
{ {
"name": "symfony/polyfill-php72", "name": "symfony/polyfill-php72",
"version": "v1.10.0", "version": "v1.15.0",
"version_normalized": "1.10.0.0", "version_normalized": "1.15.0.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/polyfill-php72.git", "url": "https://github.com/symfony/polyfill-php72.git",
"reference": "9050816e2ca34a8e916c3a0ae8b9c2fccf68b631" "reference": "37b0976c78b94856543260ce09b460a7bc852747"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/9050816e2ca34a8e916c3a0ae8b9c2fccf68b631", "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/37b0976c78b94856543260ce09b460a7bc852747",
"reference": "9050816e2ca34a8e916c3a0ae8b9c2fccf68b631", "reference": "37b0976c78b94856543260ce09b460a7bc852747",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"php": ">=5.3.3" "php": ">=5.3.3"
}, },
"time": "2018-09-21T13:07:52+00:00", "time": "2020-02-27T09:26:54+00:00",
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-master": "1.9-dev" "dev-master": "1.15-dev"
} }
}, },
"installation-source": "dist", "installation-source": "dist",
@@ -419,6 +470,20 @@
"polyfill", "polyfill",
"portable", "portable",
"shim" "shim"
],
"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"
}
] ]
} }
] ]
+1 -1
View File
@@ -1,4 +1,4 @@
Copyright (c) 2006-2013 Doctrine Project Copyright (c) 2006-2018 Doctrine Project
Permission is hereby granted, free of charge, to any person obtaining a copy of Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in this software and associated documentation files (the "Software"), to deal in
+4
View File
@@ -1,5 +1,9 @@
# Doctrine Lexer # Doctrine Lexer
Build Status: [![Build Status](https://travis-ci.org/doctrine/lexer.svg?branch=master)](https://travis-ci.org/doctrine/lexer)
Base library for a lexer that can be used in Top-Down, Recursive Descent Parsers. Base library for a lexer that can be used in Top-Down, Recursive Descent Parsers.
This lexer is used in Doctrine Annotations and in Doctrine ORM (DQL). This lexer is used in Doctrine Annotations and in Doctrine ORM (DQL).
https://www.doctrine-project.org/projects/lexer.html
+23 -6
View File
@@ -1,9 +1,15 @@
{ {
"name": "doctrine/lexer", "name": "doctrine/lexer",
"type": "library", "type": "library",
"description": "Base library for a lexer that can be used in Top-Down, Recursive Descent Parsers.", "description": "PHP Doctrine Lexer parser library that can be used in Top-Down, Recursive Descent Parsers.",
"keywords": ["lexer", "parser"], "keywords": [
"homepage": "http://www.doctrine-project.org", "php",
"parser",
"lexer",
"annotations",
"docblock"
],
"homepage": "https://www.doctrine-project.org/projects/lexer.html",
"license": "MIT", "license": "MIT",
"authors": [ "authors": [
{"name": "Guilherme Blanco", "email": "guilhermeblanco@gmail.com"}, {"name": "Guilherme Blanco", "email": "guilhermeblanco@gmail.com"},
@@ -11,14 +17,25 @@
{"name": "Johannes Schmitt", "email": "schmittjoh@gmail.com"} {"name": "Johannes Schmitt", "email": "schmittjoh@gmail.com"}
], ],
"require": { "require": {
"php": ">=5.3.2" "php": "^7.2"
},
"require-dev": {
"doctrine/coding-standard": "^6.0",
"phpstan/phpstan": "^0.11.8",
"phpunit/phpunit": "^8.2"
}, },
"autoload": { "autoload": {
"psr-0": { "Doctrine\\Common\\Lexer\\": "lib/" } "psr-4": { "Doctrine\\Common\\Lexer\\": "lib/Doctrine/Common/Lexer" }
},
"autoload-dev": {
"psr-4": { "Doctrine\\Tests\\": "tests/Doctrine" }
}, },
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-master": "1.0.x-dev" "dev-master": "1.2.x-dev"
} }
},
"config": {
"sort-packages": true
} }
} }

Some files were not shown because too many files have changed in this diff Show More