mirror of
https://github.com/getgrav/grav.git
synced 2026-07-07 17:53:02 +02:00
Merge branch 'release/1.7.18'
This commit is contained in:
15
CHANGELOG.md
15
CHANGELOG.md
@@ -1,3 +1,18 @@
|
||||
# v1.7.18
|
||||
## 07/19/2021
|
||||
|
||||
1. [](#improved)
|
||||
* Added support for loading Flex Directory configuration from main configuration
|
||||
* Move SVGs that cannot be sanitized to quarantine folder under `log://quarantine`
|
||||
* Added support for CloudFlare-forwarded client IP in the `URI::ip()` method
|
||||
1. [](#bugfix)
|
||||
* Fixed error when using Flex `SimpleStorage` with no entries
|
||||
* Fixed page search to include slug field [#3316](https://github.com/getgrav/grav/issues/3316)
|
||||
* Fixed Admin becoming unusable when GPM cannot be reached [#3383](https://github.com/getgrav/grav/issues/3383)
|
||||
* Fixed `Failed to save entry: Forbidden` when moving a page to a visible page [#3389](https://github.com/getgrav/grav/issues/3389)
|
||||
* Better support for Symfony local server on linux [#3400](https://github.com/getgrav/grav/pull/3400)
|
||||
* Fixed `open_basedir()` error with some forms
|
||||
|
||||
# v1.7.17
|
||||
## 06/15/2021
|
||||
|
||||
|
||||
@@ -17,8 +17,8 @@ if (version_compare($ver = PHP_VERSION, $req = GRAV_PHP_MIN, '<')) {
|
||||
}
|
||||
|
||||
if (PHP_SAPI === 'cli-server') {
|
||||
$symfony_server = stripos(getenv('_'), 'symfony') !== false || stripos($_SERVER['SERVER_SOFTWARE'], 'symfony
|
||||
') !== false;
|
||||
$symfony_server = stripos(getenv('_'), 'symfony') !== false || stripos($_SERVER['SERVER_SOFTWARE'], 'symfony') !== false || stripos($_ENV['SERVER_SOFTWARE'], 'symfony') !== false;
|
||||
|
||||
if (!isset($_SERVER['PHP_CLI_ROUTER']) && !$symfony_server) {
|
||||
die("PHP webserver requires a router to run Grav, please use: <pre>php -S {$_SERVER['SERVER_NAME']}:{$_SERVER['SERVER_PORT']} system/router.php</pre>");
|
||||
}
|
||||
|
||||
@@ -184,9 +184,9 @@ config:
|
||||
# Fields to be searched
|
||||
fields:
|
||||
- key
|
||||
- slug
|
||||
- menu
|
||||
- title
|
||||
- name
|
||||
|
||||
blueprints:
|
||||
configure:
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
// Some standard defines
|
||||
define('GRAV', true);
|
||||
define('GRAV_VERSION', '1.7.17');
|
||||
define('GRAV_VERSION', '1.7.18');
|
||||
define('GRAV_SCHEMA', '1.7.0_2020-11-20_1');
|
||||
define('GRAV_TESTING', false);
|
||||
|
||||
|
||||
@@ -273,7 +273,7 @@ class PageObject extends FlexPageObject
|
||||
$parentKey = $this->getProperty('parent_key');
|
||||
|
||||
/** @var PageObject|null $parent */
|
||||
$parent = $this->getFlexDirectory()->getObject($parentKey);
|
||||
$parent = $this->getFlexDirectory()->getObject($parentKey, 'storage_key');
|
||||
if (!$parent || !$parent->isAuthorized('create', null, $user)) {
|
||||
throw new \RuntimeException('Forbidden', 403);
|
||||
}
|
||||
|
||||
@@ -35,7 +35,11 @@ class GPM extends Iterator
|
||||
/** @var Remote\Packages|null Remote available Packages */
|
||||
private $repository;
|
||||
/** @var Remote\GravCore|null Remove Grav Packages */
|
||||
public $grav;
|
||||
private $grav;
|
||||
/** @var bool */
|
||||
private $refresh;
|
||||
/** @var callable|null */
|
||||
private $callback;
|
||||
|
||||
/** @var array Internal cache */
|
||||
protected $cache;
|
||||
@@ -55,13 +59,45 @@ class GPM extends Iterator
|
||||
public function __construct($refresh = false, $callback = null)
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
Folder::create(GRAV_ROOT . '/cache/gpm');
|
||||
|
||||
$this->cache = [];
|
||||
$this->installed = new Local\Packages();
|
||||
try {
|
||||
$this->repository = new Remote\Packages($refresh, $callback);
|
||||
$this->grav = new Remote\GravCore($refresh, $callback);
|
||||
} catch (Exception $e) {
|
||||
$this->refresh = $refresh;
|
||||
$this->callback = $callback;
|
||||
}
|
||||
|
||||
/**
|
||||
* Magic getter method
|
||||
*
|
||||
* @param string $offset Asset name value
|
||||
* @return mixed Asset value
|
||||
*/
|
||||
public function __get($offset)
|
||||
{
|
||||
switch ($offset) {
|
||||
case 'grav':
|
||||
return $this->getGrav();
|
||||
}
|
||||
|
||||
return parent::__get($offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Magic method to determine if the attribute is set
|
||||
*
|
||||
* @param string $offset Asset name value
|
||||
* @return bool True if the value is set
|
||||
*/
|
||||
public function __isset($offset)
|
||||
{
|
||||
switch ($offset) {
|
||||
case 'grav':
|
||||
return $this->getGrav() !== null;
|
||||
}
|
||||
|
||||
return parent::__isset($offset);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -266,11 +302,12 @@ class GPM extends Iterator
|
||||
{
|
||||
$items = [];
|
||||
|
||||
if (null === $this->repository) {
|
||||
$repository = $this->getRepository();
|
||||
if (null === $repository) {
|
||||
return $items;
|
||||
}
|
||||
|
||||
$repository = $this->repository['plugins'];
|
||||
$plugins = $repository['plugins'];
|
||||
|
||||
// local cache to speed things up
|
||||
if (isset($this->cache[__METHOD__])) {
|
||||
@@ -278,18 +315,18 @@ class GPM extends Iterator
|
||||
}
|
||||
|
||||
foreach ($this->installed['plugins'] as $slug => $plugin) {
|
||||
if (!isset($repository[$slug]) || $plugin->symlink || !$plugin->version || $plugin->gpm === false) {
|
||||
if (!isset($plugins[$slug]) || $plugin->symlink || !$plugin->version || $plugin->gpm === false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$local_version = $plugin->version ?? 'Unknown';
|
||||
$remote_version = $repository[$slug]->version;
|
||||
$remote_version = $plugins[$slug]->version;
|
||||
|
||||
if (version_compare($local_version, $remote_version) < 0) {
|
||||
$repository[$slug]->available = $remote_version;
|
||||
$repository[$slug]->version = $local_version;
|
||||
$repository[$slug]->type = $repository[$slug]->release_type;
|
||||
$items[$slug] = $repository[$slug];
|
||||
$plugins[$slug]->available = $remote_version;
|
||||
$plugins[$slug]->version = $local_version;
|
||||
$plugins[$slug]->type = $plugins[$slug]->release_type;
|
||||
$items[$slug] = $plugins[$slug];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -306,19 +343,20 @@ class GPM extends Iterator
|
||||
*/
|
||||
public function getLatestVersionOfPackage($package_name)
|
||||
{
|
||||
if (null === $this->repository) {
|
||||
$repository = $this->getRepository();
|
||||
if (null === $repository) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$repository = $this->repository['plugins'];
|
||||
if (isset($repository[$package_name])) {
|
||||
return $repository[$package_name]->available ?: $repository[$package_name]->version;
|
||||
$plugins = $repository['plugins'];
|
||||
if (isset($plugins[$package_name])) {
|
||||
return $plugins[$package_name]->available ?: $plugins[$package_name]->version;
|
||||
}
|
||||
|
||||
//Not a plugin, it's a theme?
|
||||
$repository = $this->repository['themes'];
|
||||
if (isset($repository[$package_name])) {
|
||||
return $repository[$package_name]->available ?: $repository[$package_name]->version;
|
||||
$themes = $repository['themes'];
|
||||
if (isset($themes[$package_name])) {
|
||||
return $themes[$package_name]->available ?: $themes[$package_name]->version;
|
||||
}
|
||||
|
||||
return null;
|
||||
@@ -356,11 +394,12 @@ class GPM extends Iterator
|
||||
{
|
||||
$items = [];
|
||||
|
||||
if (null === $this->repository) {
|
||||
$repository = $this->getRepository();
|
||||
if (null === $repository) {
|
||||
return $items;
|
||||
}
|
||||
|
||||
$repository = $this->repository['themes'];
|
||||
$themes = $repository['themes'];
|
||||
|
||||
// local cache to speed things up
|
||||
if (isset($this->cache[__METHOD__])) {
|
||||
@@ -368,18 +407,18 @@ class GPM extends Iterator
|
||||
}
|
||||
|
||||
foreach ($this->installed['themes'] as $slug => $plugin) {
|
||||
if (!isset($repository[$slug]) || $plugin->symlink || !$plugin->version || $plugin->gpm === false) {
|
||||
if (!isset($themes[$slug]) || $plugin->symlink || !$plugin->version || $plugin->gpm === false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$local_version = $plugin->version ?? 'Unknown';
|
||||
$remote_version = $repository[$slug]->version;
|
||||
$remote_version = $themes[$slug]->version;
|
||||
|
||||
if (version_compare($local_version, $remote_version) < 0) {
|
||||
$repository[$slug]->available = $remote_version;
|
||||
$repository[$slug]->version = $local_version;
|
||||
$repository[$slug]->type = $repository[$slug]->release_type;
|
||||
$items[$slug] = $repository[$slug];
|
||||
$themes[$slug]->available = $remote_version;
|
||||
$themes[$slug]->version = $local_version;
|
||||
$themes[$slug]->type = $themes[$slug]->release_type;
|
||||
$items[$slug] = $themes[$slug];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -407,19 +446,20 @@ class GPM extends Iterator
|
||||
*/
|
||||
public function getReleaseType($package_name)
|
||||
{
|
||||
if (null === $this->repository) {
|
||||
$repository = $this->getRepository();
|
||||
if (null === $repository) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$repository = $this->repository['plugins'];
|
||||
if (isset($repository[$package_name])) {
|
||||
return $repository[$package_name]->release_type;
|
||||
$plugins = $repository['plugins'];
|
||||
if (isset($plugins[$package_name])) {
|
||||
return $plugins[$package_name]->release_type;
|
||||
}
|
||||
|
||||
//Not a plugin, it's a theme?
|
||||
$repository = $this->repository['themes'];
|
||||
if (isset($repository[$package_name])) {
|
||||
return $repository[$package_name]->release_type;
|
||||
$themes = $repository['themes'];
|
||||
if (isset($themes[$package_name])) {
|
||||
return $themes[$package_name]->release_type;
|
||||
}
|
||||
|
||||
return null;
|
||||
@@ -470,7 +510,7 @@ class GPM extends Iterator
|
||||
*/
|
||||
public function getRepositoryPlugins()
|
||||
{
|
||||
return $this->repository['plugins'] ?? null;
|
||||
return $this->getRepository()['plugins'] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -493,7 +533,7 @@ class GPM extends Iterator
|
||||
*/
|
||||
public function getRepositoryThemes()
|
||||
{
|
||||
return $this->repository['themes'] ?? null;
|
||||
return $this->getRepository()['themes'] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -504,9 +544,31 @@ class GPM extends Iterator
|
||||
*/
|
||||
public function getRepository()
|
||||
{
|
||||
if (null === $this->repository) {
|
||||
try {
|
||||
$this->repository = new Remote\Packages($this->refresh, $this->callback);
|
||||
} catch (Exception $e) {}
|
||||
}
|
||||
|
||||
return $this->repository;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns Grav version available in the repository
|
||||
*
|
||||
* @return Remote\GravCore|null
|
||||
*/
|
||||
public function getGrav()
|
||||
{
|
||||
if (null === $this->grav) {
|
||||
try {
|
||||
$this->grav = new Remote\GravCore($this->refresh, $this->callback);
|
||||
} catch (Exception $e) {}
|
||||
}
|
||||
|
||||
return $this->grav;
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches for a Package in the repository
|
||||
*
|
||||
|
||||
@@ -12,6 +12,7 @@ namespace Grav\Common;
|
||||
use enshrined\svgSanitize\Sanitizer;
|
||||
use Exception;
|
||||
use Grav\Common\Config\Config;
|
||||
use Grav\Common\Filesystem\Folder;
|
||||
use Grav\Common\Page\Pages;
|
||||
use function chr;
|
||||
use function count;
|
||||
@@ -56,9 +57,16 @@ class Security
|
||||
$original_svg = file_get_contents($file);
|
||||
$clean_svg = $sanitizer->sanitize($original_svg);
|
||||
|
||||
// TODO: what to do with bad SVG files which return false?
|
||||
if ($clean_svg !== false && $clean_svg !== $original_svg) {
|
||||
// Quarantine bad SVG files and throw exception
|
||||
if ($clean_svg !== false ) {
|
||||
file_put_contents($file, $clean_svg);
|
||||
} else {
|
||||
$quarantine_file = basename($file);
|
||||
$quarantine_dir = 'log://quarantine';
|
||||
Folder::mkdir($quarantine_dir);
|
||||
file_put_contents("$quarantine_dir/$quarantine_file", $original_svg);
|
||||
unlink($file);
|
||||
throw new Exception('SVG could not be sanitized, it has been moved to the logs/quarantine folder');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -675,10 +675,15 @@ class Uri
|
||||
*/
|
||||
public static function ip()
|
||||
{
|
||||
$ip = 'UNKNOWN';
|
||||
|
||||
if (getenv('HTTP_CLIENT_IP')) {
|
||||
$ip = getenv('HTTP_CLIENT_IP');
|
||||
} elseif (getenv('HTTP_CF_CONNECTING_IP')) {
|
||||
$ip = getenv('HTTP_CF_CONNECTING_IP');
|
||||
} elseif (getenv('HTTP_X_FORWARDED_FOR') && Grav::instance()['config']->get('system.http_x_forwarded.ip')) {
|
||||
$ip = getenv('HTTP_X_FORWARDED_FOR');
|
||||
$ips = array_map('trim', explode(',', getenv('HTTP_X_FORWARDED_FOR')));
|
||||
$ip = array_shift($ips);
|
||||
} elseif (getenv('HTTP_X_FORWARDED') && Grav::instance()['config']->get('system.http_x_forwarded.ip')) {
|
||||
$ip = getenv('HTTP_X_FORWARDED');
|
||||
} elseif (getenv('HTTP_FORWARDED_FOR')) {
|
||||
@@ -687,8 +692,6 @@ class Uri
|
||||
$ip = getenv('HTTP_FORWARDED');
|
||||
} elseif (getenv('REMOTE_ADDR')) {
|
||||
$ip = getenv('REMOTE_ADDR');
|
||||
} else {
|
||||
$ip = 'UNKNOWN';
|
||||
}
|
||||
|
||||
return $ip;
|
||||
|
||||
@@ -235,7 +235,17 @@ class FlexDirectory implements FlexDirectoryInterface
|
||||
|
||||
/** @var UniformResourceLocator $locator */
|
||||
$locator = $grav['locator'];
|
||||
$filename = $locator->findResource($this->getDirectoryConfigUri($name), true);
|
||||
$uri = $this->getDirectoryConfigUri($name);
|
||||
|
||||
// If configuration is found in main configuration, use it.
|
||||
if (str_starts_with($uri, 'config://')) {
|
||||
$path = strtr(substr($uri, 9, -5), '/', '.');
|
||||
|
||||
return $grav['config']->get($path);
|
||||
}
|
||||
|
||||
// Load the configuration file.
|
||||
$filename = $locator->findResource($uri, true);
|
||||
if ($filename === false) {
|
||||
return [];
|
||||
}
|
||||
|
||||
@@ -1074,6 +1074,17 @@ class FlexObject implements FlexObjectInterface, FlexAuthorizeInterface
|
||||
return $action;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to reset blueprints if the type changes.
|
||||
*
|
||||
* @return void
|
||||
* @since 1.7.18
|
||||
*/
|
||||
protected function resetBlueprints(): void
|
||||
{
|
||||
$this->_blueprint = [];
|
||||
}
|
||||
|
||||
// DEPRECATED METHODS
|
||||
|
||||
/**
|
||||
|
||||
@@ -455,7 +455,7 @@ class SimpleStorage extends AbstractFilesystemStorage
|
||||
$content = (array) $file->content();
|
||||
if ($this->prefix) {
|
||||
$data = new Data($content);
|
||||
$content = $data->get($this->prefix);
|
||||
$content = $data->get($this->prefix, []);
|
||||
}
|
||||
|
||||
$file->free();
|
||||
|
||||
@@ -120,7 +120,7 @@ class FormFlash implements FormFlashInterface
|
||||
protected function loadStoredForm(): ?array
|
||||
{
|
||||
$file = $this->getTmpIndex();
|
||||
$exists = $file->exists();
|
||||
$exists = $file && $file->exists();
|
||||
|
||||
$data = null;
|
||||
if ($exists) {
|
||||
@@ -246,8 +246,10 @@ class FormFlash implements FormFlashInterface
|
||||
if ($force || $this->data || $this->files) {
|
||||
// Only save if there is data or files to be saved.
|
||||
$file = $this->getTmpIndex();
|
||||
$file->save($this->jsonSerialize());
|
||||
$this->exists = true;
|
||||
if ($file) {
|
||||
$file->save($this->jsonSerialize());
|
||||
$this->exists = true;
|
||||
}
|
||||
} elseif ($this->exists) {
|
||||
// Delete empty form flash if it exists (it carries no information).
|
||||
return $this->delete();
|
||||
@@ -476,12 +478,14 @@ class FormFlash implements FormFlashInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* @return YamlFile
|
||||
* @return ?YamlFile
|
||||
*/
|
||||
protected function getTmpIndex(): YamlFile
|
||||
protected function getTmpIndex(): ?YamlFile
|
||||
{
|
||||
$tmpDir = $this->getTmpDir();
|
||||
|
||||
// Do not use CompiledYamlFile as the file can change multiple times per second.
|
||||
return YamlFile::instance($this->getTmpDir() . '/index.yaml');
|
||||
return $tmpDir ? YamlFile::instance($tmpDir . '/index.yaml') : null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -503,7 +507,9 @@ class FormFlash implements FormFlashInterface
|
||||
{
|
||||
// Make sure that index file cache gets always cleared.
|
||||
$file = $this->getTmpIndex();
|
||||
$file->free();
|
||||
if ($file) {
|
||||
$file->free();
|
||||
}
|
||||
|
||||
$tmpDir = $this->getTmpDir();
|
||||
if ($tmpDir && file_exists($tmpDir)) {
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
|
||||
namespace Grav\Framework\Object;
|
||||
|
||||
use Doctrine\Common\Collections\Collection;
|
||||
use Doctrine\Common\Collections\Criteria;
|
||||
use Grav\Framework\Collection\ArrayCollection;
|
||||
use Grav\Framework\Object\Access\NestedPropertyCollectionTrait;
|
||||
|
||||
Reference in New Issue
Block a user