Merge branch 'develop' of github.com:getgrav/grav into feature/media

 Conflicts:
	CHANGELOG.md
	composer.lock
This commit is contained in:
Matias Griese
2022-03-23 16:06:39 +02:00
10 changed files with 131 additions and 32 deletions

View File

@@ -6,16 +6,33 @@
2. [](#improved)
* By default, add media to only pages which have been initialized in pages loop
# v1.7.31
# v1.7.32
## mm/dd/2022
1. [](#new)
* Added `|replace_last(search, replace)` filter
* Added `parseurl` Twig function to expose PHP's `parse_url` function
2. [](#improved)
* Added multi-language support for page routes in `Utils::url()`
* Set default maximum length for text fields
- `password`: 256
- `email`: 320
- `text`, `url`, `hidden`, `commalist`: 2048
- `text` (multiline), `textarea`: 65536
3. [](#bugfix)
* Fixed issue with `system.cache.gzip: true` resulted in "Fetch Failed" for PHP 8.0.17 and PHP 8.1.4 [PHP issue #8218](https://github.com/php/php-src/issues/8218).
* Fix for multi-lang issues with Security Report
# v1.7.31
## 03/14/2022
1. [](#new)
* Added new local Multiavatar (local generation). **This will be default in Grav 1.8**
* Added support to get image size for SVG vector images [#3533](https://github.com/getgrav/grav/pull/3533)
* Added XSS check for uploaded SVG files before they get stored
* Fixed phpstan issues (All level 2, Framework level 5)
2. [](#improved)
* Moved Accounts out of Experimental section of System configuration
* Moved Accounts out of Experimental section of System configuration to new "Accounts" tab
3. [](#bugfix)
* Fixed `'mbstring' extension is not loaded` error, use Polyfill instead [#3504](https://github.com/getgrav/grav/pull/3504)
* Fixed new `Utils::pathinfo()` and `Utils::basename()` being too strict for legacy use [#3542](https://github.com/getgrav/grav/issues/3542)

View File

@@ -9,7 +9,7 @@
// Some standard defines
define('GRAV', true);
define('GRAV_VERSION', '1.7.30');
define('GRAV_VERSION', '1.7.31');
define('GRAV_SCHEMA', '1.7.0_2020-11-20_1');
define('GRAV_TESTING', false);

View File

@@ -246,7 +246,9 @@ class Validation
return false;
}
$max = (int)($params['max'] ?? 0);
$multiline = isset($params['multiline']) && $params['multiline'];
$max = (int)($params['max'] ?? ($multiline ? 65536 : 2048));
if ($max && $len > $max) {
return false;
}
@@ -256,7 +258,7 @@ class Validation
return false;
}
if ((!isset($params['multiline']) || !$params['multiline']) && preg_match('/\R/um', $value)) {
if (!$multiline && preg_match('/\R/um', $value)) {
return false;
}
@@ -317,6 +319,10 @@ class Validation
*/
public static function typeCommaList($value, array $params, array $field)
{
if (!isset($params['max'])) {
$params['max'] = 2048;
}
return is_array($value) ? true : self::typeText($value, $params, $field);
}
@@ -379,6 +385,10 @@ class Validation
*/
public static function typePassword($value, array $params, array $field)
{
if (!isset($params['max'])) {
$params['max'] = 256;
}
return self::typeText($value, $params, $field);
}
@@ -621,6 +631,10 @@ class Validation
*/
public static function typeEmail($value, array $params, array $field)
{
if (!isset($params['max'])) {
$params['max'] = 320;
}
$values = !is_array($value) ? explode(',', preg_replace('/\s+/', '', $value)) : $value;
foreach ($values as $val) {
@@ -642,6 +656,10 @@ class Validation
*/
public static function typeUrl($value, array $params, array $field)
{
if (!isset($params['max'])) {
$params['max'] = 2048;
}
return self::typeText($value, $params, $field) && filter_var($value, FILTER_VALIDATE_URL);
}

View File

@@ -43,4 +43,25 @@ class SystemFacade extends \Whoops\Util\SystemFacade
$handler();
}
}
/**
* @param int $httpCode
*
* @return int
*/
public function setHttpResponseCode($httpCode)
{
if (!headers_sent()) {
// Ensure that no 'location' header is present as otherwise this
// will override the HTTP code being set here, and mask the
// expected error page.
header_remove('location');
// Work around PHP bug #8218 (8.0.17 & 8.1.4).
header_remove('Content-Encoding');
}
return http_response_code($httpCode);
}
}

View File

@@ -242,6 +242,7 @@ class PageObject extends FlexPageObject
{
/** @var PageCollection $siblings */
$siblings = $variables['siblings'];
/** @var PageObject $sibling */
foreach ($siblings as $sibling) {
$sibling->save(false);
}

View File

@@ -341,6 +341,23 @@ class Grav extends Container
}
}
/**
* Clean any output buffers. Useful when exiting from the application.
*
* Please use $grav->close() and $grav->redirect() instead of calling this one!
*
* @return void
*/
public function cleanOutputBuffers(): void
{
// Make sure nothing extra gets written to the response.
while (ob_get_level()) {
ob_end_clean();
}
// Work around PHP bug #8218 (8.0.17 & 8.1.4).
header_remove('Content-Encoding');
}
/**
* Terminates Grav request with a response.
*
@@ -351,10 +368,7 @@ class Grav extends Container
*/
public function close(ResponseInterface $response): void
{
// Make sure nothing extra gets written to the response.
while (ob_get_level()) {
ob_end_clean();
}
$this->cleanOutputBuffers();
// Close the session.
if (isset($this['session'])) {
@@ -400,7 +414,7 @@ class Grav extends Container
/**
* @param ResponseInterface $response
* @return never-return
* @deprecated 1.7 Do not use
* @deprecated 1.7 Use $grav->close() instead.
*/
public function exit(ResponseInterface $response): void
{

View File

@@ -97,7 +97,7 @@ class Security
*/
public static function detectXssFromPages(Pages $pages, $route = true, callable $status = null)
{
$routes = $pages->routes();
$routes = $pages->getList(null, 0, true);
// Remove duplicate for homepage
unset($routes['/']);
@@ -110,26 +110,23 @@ class Security
'steps' => count($routes),
]);
foreach ($routes as $path) {
foreach (array_keys($routes) as $route) {
$status && $status([
'type' => 'progress',
]);
try {
$page = $pages->get($path);
$page = $pages->find($route);
if ($page->exists()) {
// call the content to load/cache it
$header = (array) $page->header();
$content = $page->value('content');
// call the content to load/cache it
$header = (array) $page->header();
$content = $page->value('content');
$data = ['header' => $header, 'content' => $content];
$results = static::detectXssFromArray($data);
$data = ['header' => $header, 'content' => $content];
$results = static::detectXssFromArray($data);
if (!empty($results)) {
if ($route) {
$list[$page->route()] = $results;
} else {
$list[$page->filePathClean()] = $results;
if (!empty($results)) {
$list[$page->rawRoute()] = $results;
}
}
} catch (Exception $e) {

View File

@@ -145,6 +145,7 @@ class GravExtension extends AbstractExtension implements GlobalsInterface
new TwigFilter('yaml_encode', [$this, 'yamlEncodeFilter']),
new TwigFilter('yaml_decode', [$this, 'yamlDecodeFilter']),
new TwigFilter('nicecron', [$this, 'niceCronFilter']),
new TwigFilter('replace_last', [$this, 'replaceLastFilter']),
// Translations
new TwigFilter('t', [$this, 'translate'], ['needs_environment' => true]),
@@ -194,6 +195,7 @@ class GravExtension extends AbstractExtension implements GlobalsInterface
new TwigFunction('gist', [$this, 'gistFunc']),
new TwigFunction('nonce_field', [$this, 'nonceFieldFunc']),
new TwigFunction('pathinfo', 'pathinfo'),
new TwigFunction('parseurl', 'parse_url'),
new TwigFunction('random_string', [$this, 'randomStringFunc']),
new TwigFunction('repeat', [$this, 'repeatFunc']),
new TwigFunction('regex_replace', [$this, 'regexReplace']),
@@ -547,6 +549,21 @@ class GravExtension extends AbstractExtension implements GlobalsInterface
return $cron->getText('en');
}
/**
* @param string|mixed $str
* @param string $search
* @param string $replace
* @return string|mixed
*/
public function replaceLastFilter($str, $search, $replace)
{
if (is_string($str) && ($pos = mb_strrpos($str, $search)) !== false) {
$str = mb_substr($str, 0, $pos) . $replace . mb_substr($str, $pos + mb_strlen($search));
}
return $str;
}
/**
* Get Cron object for a crontab 'at' format
*

View File

@@ -83,6 +83,7 @@ abstract class Utils
$resource = false;
if (static::contains((string)$input, '://')) {
// Url contains a scheme (https:// , user:// etc).
/** @var UniformResourceLocator $locator */
$locator = $grav['locator'];
@@ -134,6 +135,16 @@ abstract class Utils
$resource = $locator->findResource($input, false);
}
} else {
// Just a path.
/** @var Pages $pages */
$pages = $grav['pages'];
// Is this a page?
$page = $pages->find($input, true);
if ($page && $page->routable()) {
return $page->url($domain);
}
$root = preg_quote($uri->rootUrl(), '#');
$pattern = '#(' . $root . '$|' . $root . '/)#';
if (!empty($root) && preg_match($pattern, $input, $matches)) {
@@ -657,18 +668,17 @@ abstract class Utils
*/
public static function download($file, $force_download = true, $sec = 0, $bytes = 1024, array $options = [])
{
$grav = Grav::instance();
if (file_exists($file)) {
// fire download event
Grav::instance()->fireEvent('onBeforeDownload', new Event(['file' => $file, 'options' => &$options]));
$grav->fireEvent('onBeforeDownload', new Event(['file' => $file, 'options' => &$options]));
$file_parts = static::pathinfo($file);
$mimetype = $options['mime'] ?? static::getMimeByExtension($file_parts['extension']);
$size = filesize($file); // File size
// clean all buffers
while (ob_get_level()) {
ob_end_clean();
}
$grav->cleanOutputBuffers();
// required for IE, otherwise Content-Disposition may be ignored
if (ini_get('zlib.output_compression')) {
@@ -703,8 +713,8 @@ abstract class Utils
$new_length = $size;
header('Content-Length: ' . $size);
if (Grav::instance()['config']->get('system.cache.enabled')) {
$expires = $options['expires'] ?? Grav::instance()['config']->get('system.pages.expires');
if ($grav['config']->get('system.cache.enabled')) {
$expires = $options['expires'] ?? $grav['config']->get('system.pages.expires');
if ($expires > 0) {
$expires_date = gmdate('D, d M Y H:i:s T', time() + $expires);
header('Cache-Control: max-age=' . $expires);

View File

@@ -23,6 +23,7 @@ use Grav\Common\User\Interfaces\UserInterface;
use Grav\Common\Utils;
use Grav\Framework\Compat\Serializable;
use Grav\Framework\ContentBlock\HtmlBlock;
use Grav\Framework\Form\FormFlashFile;
use Grav\Framework\Form\Interfaces\FormFlashInterface;
use Grav\Framework\Form\Interfaces\FormInterface;
use Grav\Framework\Session\SessionInterface;
@@ -775,13 +776,16 @@ trait FormTrait
{
// Handle bad filenames.
$filename = $file->getClientFilename();
if ($filename && !Utils::checkFilename($filename)) {
$grav = Grav::instance();
throw new RuntimeException(
sprintf($grav['language']->translate('PLUGIN_FORM.FILEUPLOAD_UNABLE_TO_UPLOAD', null, true), $filename, 'Bad filename')
);
}
if ($file instanceof FormFlashFile) {
$file->checkXss();
}
}
/**