Commit 5ac6d94c authored by Administrator's avatar Administrator 💬

Upgrade to Grav `1.6.23`.

parent c2b2656a
Pipeline #1742 passed with stage
in 1 minute and 5 seconds
# 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
......
......@@ -28,6 +28,13 @@ 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');
if (!file_exists(GRAV_ROOT . '/index.php')) {
exit('FATAL: Must be run from ROOT directory of Grav!');
}
......@@ -55,7 +62,7 @@ $grav->setup($environment);
$grav['config']->init();
$grav['uri']->init();
$grav['users'];
$grav['accounts'];
$app = new Application('Grav Package Manager', GRAV_VERSION);
$app->addCommands(array(
......
......@@ -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));
}
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->arguments->add([
'environment' => [
......@@ -42,10 +53,6 @@ $environment = $climate->arguments->get('environment');
$grav = Grav::instance(array('loader' => $autoload));
$grav->setup($environment);
if (!ini_get('date.timezone')) {
date_default_timezone_set('UTC');
}
if (!file_exists(GRAV_ROOT . '/index.php')) {
exit('FATAL: Must be run from ROOT directory of Grav!');
}
......
......@@ -32,6 +32,13 @@ 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');
if (!file_exists(GRAV_ROOT . '/index.php')) {
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->setup($environment);
$grav['config']->init();
$grav['uri']->init();
$grav['users'];
$grav['plugins']->init();
$grav['themes']->init();
$grav->initializeCli();
$app = new Application('Grav Plugins Commands', GRAV_VERSION);
$pattern = '([A-Z]\w+Command\.php)';
......
......@@ -28,8 +28,6 @@
"kodus/psr7-server": "*",
"nyholm/psr7": "^1.0",
"twig/twig": "~1.40",
"erusev/parsedown": "1.6.4",
"erusev/parsedown-extra": "~0.7",
"symfony/yaml": "~4.2.0",
"symfony/console": "~4.2.0",
"symfony/event-dispatcher": "~4.2.0",
......@@ -44,7 +42,7 @@
"gregwar/image": "2.*",
"donatj/phpuseragentparser": "~0.10",
"pimple/pimple": "~3.2",
"rockettheme/toolbox": "~1.4",
"rockettheme/toolbox": "~1.4.0",
"maximebf/debugbar": "~1.15",
"league/climate": "^3.4",
"antoligy/dom-string-iterators": "^1.0",
......@@ -52,7 +50,7 @@
"composer/ca-bundle": "^1.0",
"dragonmantank/cron-expression": "^1.2",
"phive/twig-extensions-deferred": "^1.0",
"willdurand/negotiation": "^2.3"
"willdurand/negotiation": "2.x-dev"
},
"require-dev": {
"codeception/codeception": "^2.4",
......@@ -86,7 +84,8 @@
"Grav\\": "system/src/Grav"
},
"files": [
"system/defines.php"
"system/defines.php",
"system/aliases.php"
]
},
"archive": {
......
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -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>");
}
// 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
$autoload = __DIR__ . '/vendor/autoload.php';
if (!is_file($autoload)) {
......@@ -32,15 +42,6 @@ $loader = require $autoload;
use Grav\Common\Grav;
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
$grav = Grav::instance(
array(
......
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -8,7 +8,7 @@
// Some standard defines
define('GRAV', true);
define('GRAV_VERSION', '1.6.17');
define('GRAV_VERSION', '1.6.23');
define('GRAV_TESTING', false);
define('DS', '/');
......
......@@ -51,7 +51,11 @@ trait LegacyAssetsTrait
// special case to handle old attributes being passed in
if (isset($arguments['attributes'])) {
$old_attributes = $arguments['attributes'];
if (is_array($old_attributes)) {
$arguments = array_merge($arguments, $old_attributes);
} else {
$arguments['type'] = $old_attributes;
}
}
unset($arguments['attributes']);
......
......@@ -136,7 +136,7 @@ class BlueprintSchema extends BlueprintSchemaBase implements ExportInterface
{
$messages = $this->checkRequired($data, $rules);
foreach ($data as $key => $field) {
foreach ($data as $key => $child) {
$val = $rules[$key] ?? $rules['*'] ?? null;
$rule = \is_string($val) ? $this->items[$val] : null;
......@@ -147,10 +147,10 @@ class BlueprintSchema extends BlueprintSchemaBase implements ExportInterface
continue;
}
$messages += Validation::validate($field, $rule);
} elseif (\is_array($field) && \is_array($val)) {
$messages += Validation::validate($child, $rule);
} elseif (\is_array($child) && \is_array($val)) {
// Array has been defined in blueprints.
$messages += $this->validateArray($field, $val);
$messages += $this->validateArray($child, $val);
} elseif (isset($rules['validation']) && $rules['validation'] === 'strict') {
// Undefined/extra item.
throw new \RuntimeException(sprintf('%s is not defined in blueprints', $key));
......
......@@ -32,6 +32,12 @@ class Data implements DataInterface, \ArrayAccess, \Countable, \JsonSerializable
/** @var File */
protected $storage;
/** @var bool */
private $missingValuesAsNull = false;
/** @var bool */
private $keepEmptyValues = true;
/**
* @param array $items
* @param Blueprint|callable $blueprints
......@@ -42,6 +48,28 @@ class Data implements DataInterface, \ArrayAccess, \Countable, \JsonSerializable
$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.
*
......@@ -202,8 +230,8 @@ class Data implements DataInterface, \ArrayAccess, \Countable, \JsonSerializable
public function filter()
{
$args = func_get_args();
$missingValuesAsNull = (bool)(array_shift($args) ?: false);
$keepEmptyValues = (bool)(array_shift($args) ?: false);
$missingValuesAsNull = (bool)(array_shift($args) ?? $this->missingValuesAsNull);
$keepEmptyValues = (bool)(array_shift($args) ?? $this->keepEmptyValues);
$this->items = $this->blueprints()->filter($this->items, $missingValuesAsNull, $keepEmptyValues);
......
......@@ -166,9 +166,18 @@ class Validation
return (string) $value;
}
/**
* @param mixed $value
* @param array $params
* @param array $field
* @return string|null
*/
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)
......
......@@ -347,7 +347,7 @@ class Debugger
*/
public function deprecatedErrorHandler($errno, $errstr, $errfile, $errline)
{
if ($errno !== E_USER_DEPRECATED) {
if ($errno !== E_USER_DEPRECATED && $errno !== E_DEPRECATED) {
if ($this->errorHandler) {
return \call_user_func($this->errorHandler, $errno, $errstr, $errfile, $errline);
}
......
......@@ -22,6 +22,10 @@ abstract class Folder
*/
public static function lastModifiedFolder($path)
{
if (!file_exists($path)) {
return 0;
}
$last_modified = 0;
/** @var UniformResourceLocator $locator */
......@@ -56,6 +60,10 @@ abstract class Folder
*/
public static function lastModifiedFile($path, $extensions = 'md|yaml')
{
if (!file_exists($path)) {
return 0;
}
$last_modified = 0;
/** @var UniformResourceLocator $locator */
......@@ -92,9 +100,11 @@ abstract class Folder
*/
public static function hashAllFiles($path)
{
$flags = \RecursiveDirectoryIterator::SKIP_DOTS;
$files = [];
if (file_exists($path)) {
$flags = \RecursiveDirectoryIterator::SKIP_DOTS;
/** @var UniformResourceLocator $locator */
$locator = Grav::instance()['locator'];
if ($locator->isStream($path)) {
......@@ -108,6 +118,7 @@ abstract class Folder
foreach ($iterator as $file) {
$files[] = $file->getPathname() . '?'. $file->getMTime();
}
}
return md5(serialize($files));
}
......@@ -199,6 +210,9 @@ abstract class Folder
if ($path === false) {
throw new \RuntimeException("Path doesn't exist.");
}
if (!file_exists($path)) {
return [];
}
$compare = isset($params['compare']) ? 'get' . $params['compare'] : null;
$pattern = $params['pattern'] ?? null;
......
......@@ -11,6 +11,7 @@ namespace Grav\Common\GPM\Local;
use Grav\Common\Data\Data;
use Grav\Common\GPM\Common\Package as BasePackage;
use Grav\Framework\Parsedown\Parsedown;
class Package extends BasePackage
{
......@@ -23,7 +24,7 @@ class Package extends BasePackage
$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('description_html', $html_description);
$this->data->set('description_plain', strip_tags($html_description));
......
......@@ -170,6 +170,29 @@ class Grav extends Container
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
*/
......@@ -293,7 +316,10 @@ class Grav extends Container
/** @var Uri $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])\])$/';
preg_match($regex, $route, $matches);
if ($matches) {
......@@ -439,11 +465,16 @@ class Grav extends Container
* Used to call closures.
*
* Source: http://stackoverflow.com/questions/419804/closures-as-class-members
*
* @param string $method
* @param array $args
* @return
*/
public function __call($method, $args)
{
$closure = $this->{$method};
\call_user_func_array($closure, $args);
$closure = $this->{$method} ?? null;
return is_callable($closure) ? $closure(...$args) : null;
}
/**
......
......@@ -11,8 +11,9 @@ namespace Grav\Common\Markdown;
use Grav\Common\Page\Interfaces\PageInterface;
use Grav\Common\Page\Markdown\Excerpts;
use Grav\Framework\Parsedown\Parsedown as ParsedownLib;
class Parsedown extends \Parsedown
class Parsedown extends ParsedownLib
{
use ParsedownGravTrait;
......
......@@ -11,8 +11,9 @@ namespace Grav\Common\Markdown;
use Grav\Common\Page\Interfaces\PageInterface;
use Grav\Common\Page\Markdown\Excerpts;
use Grav\Framework\Parsedown\ParsedownExtra as ParsedownExtraLib;
class ParsedownExtra extends \ParsedownExtra
class ParsedownExtra extends ParsedownExtraLib
{
use ParsedownGravTrait;
......
......@@ -608,12 +608,12 @@ class Page implements PageInterface
return $content;
}
return mb_strimwidth($content, 0, $size, '...', 'utf-8');
return mb_strimwidth($content, 0, $size, '...', 'UTF-8');
}
$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
/** @var Cache $cache */
$cache = Grav::instance()['cache'];
$cache_id = md5('page' . $this->id());
$cache_id = md5('page' . $this->getCacheKey());
$content_obj = $cache->fetch($cache_id);
if (is_array($content_obj)) {
......@@ -865,7 +865,7 @@ class Page implements PageInterface
public function cachePageContent()
{
$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]);
}
......@@ -1200,7 +1200,7 @@ class Page implements PageInterface
/**
* @return string
*/
protected function getCacheKey(): string
public function getCacheKey(): string
{
return $this->id();
}
......@@ -1694,7 +1694,7 @@ class Page implements PageInterface
$metadata['generator'] = 'GravCMS';
// 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) && is_array($this->header->metadata)) {
// Merge any site.metadata settings in with page metadata
......@@ -2009,6 +2009,10 @@ class Page implements PageInterface
*/
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) {
// store unique per language
$active_lang = Grav::instance()['language']->getLanguage() ?: '';
......@@ -2824,7 +2828,7 @@ class Page implements PageInterface
if ($pagination) {
$params = $collection->params();
$limit = $params['limit'] ?? 0;
$limit = (int)($params['limit'] ?? 0);
$start = !empty($params['pagination']) ? ($uri->currentPage() - 1) * $limit : 0;
if ($limit && $collection->count() > $limit) {
......
......@@ -95,6 +95,8 @@ class Pages
protected $initialized = false;
protected $active_lang;
/**
* @var Types
*/
......@@ -143,7 +145,7 @@ class Pages
*/
public function baseRoute($lang = null)
{
$key = $lang ?: 'default';
$key = $lang ?: $this->active_lang ?: 'default';
if (!isset($this->baseRoute[$key])) {
/** @var Language $language */
......@@ -236,6 +238,16 @@ class Pages
$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.
*/
......@@ -958,6 +970,9 @@ class Pages
$pages_dir = $locator->findResource('page://');
// Set active language
$this->active_lang = $language->getActive();
if ($config->get('system.cache.enabled')) {
/** @var Cache $cache */
$cache = $this->grav['cache'];
......@@ -982,17 +997,19 @@ class Pages
$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);
if (!$this->instances) {
$this->grav['debugger']->addMessage('Page cache missed, rebuilding pages..');
$cached = $cache->fetch($this->pages_cache_id);
if ($cached) {
$this->grav['debugger']->addMessage('Page cache hit.');
// recurse pages and cache result
$this->resetPages($pages_dir);
list($this->instances, $this->routes, $this->children, $taxonomy_map, $this->sort) = $cached;
} else {
// If pages was found in cache, set the taxonomy
$this->grav['debugger']->addMessage('Page cache hit.');
$taxonomy->taxonomy($taxonomy_map);
} else {
$this->grav['debugger']->addMessage('Page cache missed, rebuilding pages..');
// recurse pages and cache result
$this->resetPages($pages_dir);
}
} else {
$this->recurse($pages_dir);
......@@ -1261,14 +1278,13 @@ class Pages
{
$list = [];
$header_default = null;
$header_query = null;
$header_query = [];
// do this header query work only once
if (strpos($order_by, 'header.') === 0) {
$header_query = explode('|', str_replace('header.', '', $order_by));
if (isset($header_query[1])) {
$header_default = $header_query[1];
}
$query = explode('|', str_replace('header.', '', $order_by), 2);
$header_query = array_shift($query) ?? '';
$header_default = array_shift($query);
}
foreach ($pages as $key => $info) {
......@@ -1306,11 +1322,17 @@ class Pages
case 'folder':
$list[$key] = $child->folder();
break;
case (is_string($header_query[0])):
$child_header = new Header((array)$child->header());
$header_value = $child_header->get($header_query[0]);
case 'manual':
case 'default':
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)) {
$list[$key] = implode(',',$header_value);
$list[$key] = implode(',', $header_value);
} elseif ($header_value) {
$list[$key] = $header_value;
} else {
......@@ -1318,9 +1340,7 @@ class Pages
}
$sort_flags = $sort_flags ?: SORT_REGULAR;
break;
case 'manual':
case 'default':
default:
}
$list[$key] = $key;
$sort_flags = $sort_flags ?: SORT_REGULAR;
}
......
......@@ -10,6 +10,7 @@
namespace Grav\Common\Processors;
use Grav\Common\Config\Config;
use Grav\Common\Grav;
use Grav\Common\Uri;
use Grav\Common\Utils;
use Grav\Framework\Session\Exceptions\SessionException;
......@@ -22,6 +23,22 @@ class InitializeProcessor extends ProcessorBase
public $id = 'init';
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
{
$this->startTimer();
......@@ -77,4 +94,35 @@ class InitializeProcessor extends ProcessorBase
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'];
}
}
......@@ -26,6 +26,19 @@ class PagesServiceProvider implements ServiceProviderInterface
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) {
/** @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)
{
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);
}
/**
......
......@@ -151,7 +151,7 @@ class 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:
$setup_base = $grav['pages']->base();
......@@ -195,7 +195,7 @@ class Uri
// set the new url
$this->url = $this->root . $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 !== '') {
$this->paths = explode('/', $this->content_path);
}
......@@ -306,7 +306,7 @@ class Uri
public function param($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;
......@@ -340,7 +340,7 @@ class Uri
return $this->url;
}
$url = str_replace($this->base, '', rtrim($this->url, '/'));
$url = Utils::replaceFirstOccurrence($this->base, '', rtrim($this->url, '/'));
return $url ?: '/';
}
......@@ -489,7 +489,7 @@ class 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 str_replace($this->base, '', $this->root);
return Utils::replaceFirstOccurrence($this->base, '', $this->root);
}
/**
......@@ -541,7 +541,9 @@ class Uri
*/
public function currentPage()
{
return $this->params['page'] ?? 1;
$page = (int)($this->params['page'] ?? 1);
return max(1, $page);
}
/**
......@@ -783,7 +785,7 @@ class Uri
}
// 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()) {
$url_path = $normalized_url;
} else {
......@@ -852,7 +854,7 @@ class Uri
}
// 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
if (empty($target_path)) {
......@@ -877,7 +879,7 @@ class Uri
// Handle 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
......@@ -998,7 +1000,7 @@ class Uri
}
// 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()) {
return $normalized_url;
}
......
......@@ -10,6 +10,10 @@
namespace Grav\Console;
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\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
......@@ -18,6 +22,13 @@ class ConsoleCommand extends Command
{
use ConsoleTrait;
/** @var bool */
private $plugins_initialized = false;
/** @var bool */
private $themes_initialized = false;
/** @var bool */
private $pages_initialized = false;
/**
* @param InputInterface $input
* @param OutputInterface $output
......@@ -31,12 +42,140 @@ class ConsoleCommand extends Command
}
/**
*
* Override with your implementation.
*/
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()
{
$this->output->writeln('');
......
......@@ -177,7 +177,7 @@ class SelfupgradeCommand extends ConsoleCommand
}
/**
* @param Package $package
* @param array $package
*
* @return string
*/
......
......@@ -92,7 +92,7 @@ class CsvFormatter extends AbstractFormatter
if ($null_replace) {
array_walk($csv_line, function(&$el) use ($null_replace) {
$el = str_replace($null_replace, null, $el);
$el = str_replace($null_replace, "\0", $el);
});
}
......
......@@ -9,6 +9,7 @@
namespace Grav\Framework\Session;
use Grav\Common\User\Interfaces\UserInterface;
use Grav\Framework\Session\Exceptions\SessionException;
/**
......@@ -17,16 +18,13 @@ use Grav\Framework\Session\Exceptions\SessionException;
*/
class Session implements SessionInterface
{
protected $options;
/** @var array */
protected $options = [];
/**
* @var bool
*/
/** @var bool */
protected $started = false;
/**
* @var Session
*/
/** @var Session */
protected static $instance;
/**
......@@ -178,9 +176,13 @@ class Session implements SessionInterface
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
if (isset($_COOKIE[session_name()]) && !preg_match('/^[-,a-zA-Z0-9]{1,128}$/', $_COOKIE[session_name()])) {
unset($_COOKIE[session_name()]);
if ($sessionExists && !preg_match('/^[-,a-zA-Z0-9]{1,128}$/', $_COOKIE[$sessionName])) {
unset($_COOKIE[$sessionName]);
$sessionExists = false;
}
$options = $this->options;
......@@ -197,15 +199,20 @@ class Session implements SessionInterface
throw new SessionException('Failed to start session: ' . $error, 500);
}
if ($user && !$user->isValid()) {
$this->clear();
throw new SessionException('User Invalid', 500);
$this->started = true;
if ($user && (!$user instanceof UserInterface || !$user->isValid())) {
$this->invalidate();
throw new SessionException('Invalid User object, session destroyed.', 500);
}
// Extend the lifetime of the session.
if ($sessionExists) {
$params = session_get_cookie_params();
setcookie(
session_name(),
$sessionName,
session_id(),
time() + $params['lifetime'],
$params['path'],
......@@ -213,8 +220,7 @@ class Session implements SessionInterface
$params['secure'],
$params['httponly']
);
$this->started = true;
}
return $this;
}
......
......@@ -23,7 +23,7 @@ $HTTP["querystring"] =~ "_REQUEST(=|\[|\%[0-9A-Z])" {
#REROUTING TO THE INDEX PAGE
url.rewrite-if-not-file = (
"^/grav_path/(.*)$" => "/grav_path/index.php$1"
"^/grav_path/(.*)$" => "/grav_path/index.php?$1"
)
#IMPROVING SECURITY
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment