mirror of
https://github.com/getgrav/grav.git
synced 2026-03-05 20:11:50 +01:00
Merge branches 'develop' and 'feature/refactor' of https://github.com/getgrav/grav into feature/refactor
This commit is contained in:
@@ -12,6 +12,7 @@
|
||||
|
||||
1. [](#bugfix)
|
||||
* Fixed a fatal error if you have a collection with missing or invalid `@page: /route`
|
||||
* Fixed gzip compression making it to work correctly with all servers and browsers
|
||||
|
||||
# v1.0.0-rc.3
|
||||
## 10/29/2015
|
||||
|
||||
@@ -73,7 +73,7 @@ form:
|
||||
options:
|
||||
"F jS \\a\\t g:ia": Date1
|
||||
"l jS \\of F g:i A": Date2
|
||||
"D, m M Y G:i:s": Date3
|
||||
"D, d M Y G:i:s": Date3
|
||||
"d-m-y G:i": Date4
|
||||
"jS M Y": Date5
|
||||
|
||||
@@ -86,7 +86,7 @@ form:
|
||||
options:
|
||||
"F jS \\a\\t g:ia": Date1
|
||||
"l jS \\of F g:i A": Date2
|
||||
"D, m M Y G:i:s": Date3
|
||||
"D, d M Y G:i:s": Date3
|
||||
"d-m-y G:i": Date4
|
||||
"jS M Y": Date5
|
||||
|
||||
|
||||
@@ -1,113 +1,114 @@
|
||||
absolute_urls: false # Absolute or relative URLs for `base_url`
|
||||
timezone: '' # Valid values: http://php.net/manual/en/timezones.php
|
||||
default_locale: # Default locale (defaults to system)
|
||||
param_sep: ':' # Parameter separator, use ';' for Apache on windows
|
||||
wrapped_site: false # For themes/plugins to know if Grav is wrapped by another platform
|
||||
absolute_urls: false # Absolute or relative URLs for `base_url`
|
||||
timezone: '' # Valid values: http://php.net/manual/en/timezones.php
|
||||
default_locale: # Default locale (defaults to system)
|
||||
param_sep: ':' # Parameter separator, use ';' for Apache on windows
|
||||
wrapped_site: false # For themes/plugins to know if Grav is wrapped by another platform
|
||||
|
||||
languages:
|
||||
supported: [] # List of languages supported. eg: [en, fr, de]
|
||||
include_default_lang: true # Include the default lang prefix in all URLs
|
||||
translations: true # Enable translations by default
|
||||
translations_fallback: true # Fallback through supported translations if active lang doesn't exist
|
||||
session_store_active: false # Store active language in session
|
||||
http_accept_language: false # Attempt to set the language based on http_accept_language header in the browser
|
||||
override_locale: false # Override the default or system locale with language specific one
|
||||
supported: [] # List of languages supported. eg: [en, fr, de]
|
||||
include_default_lang: true # Include the default lang prefix in all URLs
|
||||
translations: true # Enable translations by default
|
||||
translations_fallback: true # Fallback through supported translations if active lang doesn't exist
|
||||
session_store_active: false # Store active language in session
|
||||
http_accept_language: false # Attempt to set the language based on http_accept_language header in the browser
|
||||
override_locale: false # Override the default or system locale with language specific one
|
||||
|
||||
home:
|
||||
alias: '/home' # Default path for home, ie /
|
||||
alias: '/home' # Default path for home, ie /
|
||||
|
||||
pages:
|
||||
theme: antimatter # Default theme (defaults to "antimatter" theme)
|
||||
theme: antimatter # Default theme (defaults to "antimatter" theme)
|
||||
order:
|
||||
by: default # Order pages by "default", "alpha" or "date"
|
||||
dir: asc # Default ordering direction, "asc" or "desc"
|
||||
by: default # Order pages by "default", "alpha" or "date"
|
||||
dir: asc # Default ordering direction, "asc" or "desc"
|
||||
list:
|
||||
count: 20 # Default item count per page
|
||||
count: 20 # Default item count per page
|
||||
dateformat:
|
||||
default: # The default date format Grav expects in the `date: ` field
|
||||
short: 'jS M Y' # Short date format
|
||||
long: 'F jS \a\t g:ia' # Long date format
|
||||
publish_dates: true # automatically publish/unpublish based on dates
|
||||
default: # The default date format Grav expects in the `date: ` field
|
||||
short: 'jS M Y' # Short date format
|
||||
long: 'F jS \a\t g:ia' # Long date format
|
||||
publish_dates: true # automatically publish/unpublish based on dates
|
||||
process:
|
||||
markdown: true # Process Markdown
|
||||
twig: false # Process Twig
|
||||
markdown: true # Process Markdown
|
||||
twig: false # Process Twig
|
||||
events:
|
||||
page: true # Enable page level events
|
||||
twig: true # Enable twig level events
|
||||
page: true # Enable page level events
|
||||
twig: true # Enable twig level events
|
||||
markdown:
|
||||
extra: false # Enable support for Markdown Extra support (GFM by default)
|
||||
auto_line_breaks: false # Enable automatic line breaks
|
||||
auto_url_links: false # Enable automatic HTML links
|
||||
escape_markup: false # Escape markup tags into entities
|
||||
special_chars: # List of special characters to automatically convert to entities
|
||||
extra: false # Enable support for Markdown Extra support (GFM by default)
|
||||
auto_line_breaks: false # Enable automatic line breaks
|
||||
auto_url_links: false # Enable automatic HTML links
|
||||
escape_markup: false # Escape markup tags into entities
|
||||
special_chars: # List of special characters to automatically convert to entities
|
||||
'>': 'gt'
|
||||
'<': 'lt'
|
||||
types: [txt,xml,html,json,rss,atom] # list of valid page types
|
||||
expires: 604800 # Page expires time in seconds (604800 seconds = 7 days)
|
||||
last_modified: false # Set the last modified date header based on file modifcation timestamp
|
||||
etag: false # Set the etag header tag
|
||||
vary_accept_encoding: false # Add `Vary: Accept-Encoding` header
|
||||
redirect_default_route: false # Automatically redirect to a page's default route
|
||||
redirect_default_code: 301 # Default code to use for redirects
|
||||
redirect_trailing_slash: true # Handle automatically or 301 redirect a trailing / URL
|
||||
ignore_files: [.DS_Store] # Files to ignore in Pages
|
||||
ignore_folders: [.git, .idea] # Folders to ignore in Pages
|
||||
ignore_hidden: true # Ignore all Hidden files and folders
|
||||
url_taxonomy_filters: true # Enable auto-magic URL-based taxonomy filters for page collections
|
||||
fallback_types: [png,jpg,jpeg,gif] # Allowed types of files found if accessed via Page route
|
||||
types: [txt,xml,html,htm,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)
|
||||
expires: 604800 # Page expires time in seconds (604800 seconds = 7 days)
|
||||
last_modified: false # Set the last modified date header based on file modifcation timestamp
|
||||
etag: false # Set the etag header tag
|
||||
vary_accept_encoding: false # Add `Vary: Accept-Encoding` header
|
||||
redirect_default_route: false # Automatically redirect to a page's default route
|
||||
redirect_default_code: 301 # Default code to use for redirects
|
||||
redirect_trailing_slash: true # Handle automatically or 301 redirect a trailing / URL
|
||||
ignore_files: [.DS_Store] # Files to ignore in Pages
|
||||
ignore_folders: [.git, .idea] # Folders to ignore in Pages
|
||||
ignore_hidden: true # Ignore all Hidden files and folders
|
||||
url_taxonomy_filters: true # Enable auto-magic URL-based taxonomy filters for page collections
|
||||
fallback_types: [png,jpg,jpeg,gif] # Allowed types of files found if accessed via Page route
|
||||
|
||||
cache:
|
||||
enabled: true # Set to true to enable caching
|
||||
enabled: true # Set to true to enable caching
|
||||
check:
|
||||
method: file # Method to check for updates in pages: file|folder|none
|
||||
driver: auto # One of: auto|file|apc|xcache|memcache|wincache
|
||||
prefix: 'g' # Cache prefix string (prevents cache conflicts)
|
||||
lifetime: 604800 # Lifetime of cached data in seconds (0 = infinite)
|
||||
gzip: false # GZip compress the page output
|
||||
method: file # Method to check for updates in pages: file|folder|none
|
||||
driver: auto # One of: auto|file|apc|xcache|memcache|wincache
|
||||
prefix: 'g' # Cache prefix string (prevents cache conflicts)
|
||||
lifetime: 604800 # Lifetime of cached data in seconds (0 = infinite)
|
||||
gzip: false # GZip compress the page output
|
||||
|
||||
twig:
|
||||
cache: true # Set to true to enable twig caching
|
||||
debug: false # Enable Twig debug
|
||||
auto_reload: true # Refresh cache on changes
|
||||
autoescape: false # Autoescape Twig vars
|
||||
undefined_functions: true # Allow undefined functions
|
||||
undefined_filters: true # Allow undefined filters
|
||||
umask_fix: false # By default Twig creates cached files as 755, fix switches this to 775
|
||||
cache: true # Set to true to enable twig caching
|
||||
debug: false # Enable Twig debug
|
||||
auto_reload: true # Refresh cache on changes
|
||||
autoescape: false # Autoescape Twig vars
|
||||
undefined_functions: true # Allow undefined functions
|
||||
undefined_filters: true # Allow undefined filters
|
||||
umask_fix: false # By default Twig creates cached files as 755, fix switches this to 775
|
||||
|
||||
assets: # Configuration for Assets Manager (JS, CSS)
|
||||
css_pipeline: false # The CSS pipeline is the unification of multiple CSS resources into one file
|
||||
css_minify: true # Minify the CSS during pipelining
|
||||
css_minify_windows: false # Minify Override for Windows platforms. False by default due to ThreadStackSize
|
||||
css_rewrite: true # Rewrite any CSS relative URLs during pipelining
|
||||
js_pipeline: false # The JS pipeline is the unification of multiple JS resources into one file
|
||||
js_minify: true # Minify the JS during pipelining
|
||||
enable_asset_timestamp: false # Enable asset timestamps
|
||||
assets: # Configuration for Assets Manager (JS, CSS)
|
||||
css_pipeline: false # The CSS pipeline is the unification of multiple CSS resources into one file
|
||||
css_minify: true # Minify the CSS during pipelining
|
||||
css_minify_windows: false # Minify Override for Windows platforms. False by default due to ThreadStackSize
|
||||
css_rewrite: true # Rewrite any CSS relative URLs during pipelining
|
||||
js_pipeline: false # The JS pipeline is the unification of multiple JS resources into one file
|
||||
js_minify: true # Minify the JS during pipelining
|
||||
enable_asset_timestamp: false # Enable asset timestamps
|
||||
collections:
|
||||
jquery: system://assets/jquery/jquery-2.1.4.min.js
|
||||
|
||||
errors:
|
||||
display: false # Display full backtrace-style error page
|
||||
log: true # Log errors to /logs folder
|
||||
display: false # Display full backtrace-style error page
|
||||
log: true # Log errors to /logs folder
|
||||
|
||||
debugger:
|
||||
enabled: false # Enable Grav debugger and following settings
|
||||
enabled: false # Enable Grav debugger and following settings
|
||||
shutdown:
|
||||
close_connection: true # Close the connection before calling onShutdown(). false for debugging
|
||||
close_connection: true # Close the connection before calling onShutdown(). false for debugging
|
||||
|
||||
images:
|
||||
default_image_quality: 85 # Default image quality to use when resampling images (85%)
|
||||
cache_all: false # Cache all image by default
|
||||
debug: false # Show an overlay over images indicating the pixel depth of the image when working with retina for example
|
||||
default_image_quality: 85 # Default image quality to use when resampling images (85%)
|
||||
cache_all: false # Cache all image by default
|
||||
debug: false # Show an overlay over images indicating the pixel depth of the image when working with retina for example
|
||||
|
||||
media:
|
||||
enable_media_timestamp: false # Enable media timetsamps
|
||||
upload_limit: 0 # Set maximum upload size in bytes (0 is unlimited)
|
||||
unsupported_inline_types: [] # Array of unsupported media file types to try to display inline
|
||||
enable_media_timestamp: false # Enable media timetsamps
|
||||
upload_limit: 0 # Set maximum upload size in bytes (0 is unlimited)
|
||||
unsupported_inline_types: [] # Array of unsupported media file types to try to display inline
|
||||
|
||||
session:
|
||||
enabled: true # Enable Session support
|
||||
timeout: 1800 # Timeout in seconds
|
||||
name: grav-site # Name prefix of the session cookie
|
||||
enabled: true # Enable Session support
|
||||
timeout: 1800 # Timeout in seconds
|
||||
name: grav-site # Name prefix of the session cookie
|
||||
|
||||
security:
|
||||
default_hash: $2y$10$kwsyMVwM8/7j0K/6LHT.g.Fs49xOCTp2b8hh/S5.dPJuJcJB6T.UK
|
||||
|
||||
@@ -92,3 +92,6 @@ NICETIME:
|
||||
MO_PLURAL: mos
|
||||
YR_PLURAL: yrs
|
||||
DEC_PLURAL: decs
|
||||
FORM:
|
||||
VALIDATION_FAIL: <b>Validation failed:</b>
|
||||
INVALID_INPUT: Invalid input in
|
||||
|
||||
@@ -79,7 +79,8 @@ class Blueprint implements \ArrayAccess, ExportInterface
|
||||
$this->validateArray($data, $this->nested);
|
||||
} catch (\RuntimeException $e) {
|
||||
$language = self::getGrav()['language'];
|
||||
throw new \RuntimeException(sprintf('<b>Validation failed:</b> %s', $language->translate($e->getMessage())));
|
||||
$message = sprintf($language->translate('FORM.VALIDATION_FAIL', null, true) . ' %s', $e->getMessage());
|
||||
throw new \RuntimeException($message);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -452,7 +453,8 @@ class Blueprint implements \ArrayAccess, ExportInterface
|
||||
if (isset($field['validate']['required'])
|
||||
&& $field['validate']['required'] === true
|
||||
&& empty($data[$name])) {
|
||||
throw new \RuntimeException("Missing required field: {$field['label']}");
|
||||
$value = isset($field['label']) ? $field['label'] : $field['name'];
|
||||
throw new \RuntimeException("Missing required field: {$value}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ class Validation
|
||||
$type = (string) isset($field['validate']['type']) ? $field['validate']['type'] : $field['type'];
|
||||
$method = 'type'.strtr($type, '-', '_');
|
||||
$name = ucfirst(isset($field['label']) ? $field['label'] : $field['name']);
|
||||
$message = (string) isset($field['validate']['message']) ? $field['validate']['message'] : 'Invalid input in "' . $language->translate($name) . '""';
|
||||
$message = (string) isset($field['validate']['message']) ? $field['validate']['message'] : $language->translate('FORM.INVALID_INPUT', null, true) . ' "' . $language->translate($name) . '"';
|
||||
|
||||
if (method_exists(__CLASS__, $method)) {
|
||||
$success = self::$method($value, $validate, $field);
|
||||
|
||||
@@ -64,8 +64,8 @@ abstract class Folder
|
||||
/**
|
||||
* Get relative path between target and base path. If path isn't relative, return full path.
|
||||
*
|
||||
* @param string $path
|
||||
* @param string $base
|
||||
* @param string $path
|
||||
* @param mixed|string $base
|
||||
* @return string
|
||||
*/
|
||||
public static function getRelativePath($path, $base = GRAV_ROOT)
|
||||
|
||||
@@ -1,58 +0,0 @@
|
||||
<?php
|
||||
namespace Grav\Common\GPM;
|
||||
|
||||
use Grav\Common\Data\Data;
|
||||
|
||||
/**
|
||||
* Interface Package
|
||||
* @package Grav\Common\GPM
|
||||
*/
|
||||
class Package
|
||||
{
|
||||
/**
|
||||
* @var Data
|
||||
*/
|
||||
protected $data;
|
||||
|
||||
/**
|
||||
* @var \Grav\Common\Data\Blueprint
|
||||
*/
|
||||
protected $blueprints;
|
||||
|
||||
/**
|
||||
* @param Data $package
|
||||
* @param bool $package_type
|
||||
*/
|
||||
public function __construct(Data $package, $package_type = false);
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function isEnabled();
|
||||
|
||||
/**
|
||||
* @return Data
|
||||
*/
|
||||
public function getData();
|
||||
|
||||
/**
|
||||
* @param $key
|
||||
* @return mixed
|
||||
*/
|
||||
public function __get($key);
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function __toString();
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function toJson();
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function toArray();
|
||||
}
|
||||
@@ -16,6 +16,8 @@ class Plugins extends AbstractPackageCollection
|
||||
|
||||
/**
|
||||
* Local Plugins Constructor
|
||||
* @param bool $refresh
|
||||
* @param callable $callback Either a function or callback in array notation
|
||||
*/
|
||||
public function __construct($refresh = false, $callback = null)
|
||||
{
|
||||
|
||||
@@ -16,6 +16,8 @@ class Themes extends AbstractPackageCollection
|
||||
|
||||
/**
|
||||
* Local Themes Constructor
|
||||
* @param bool $refresh
|
||||
* @param callable $callback Either a function or callback in array notation
|
||||
*/
|
||||
public function __construct($refresh = false, $callback = null)
|
||||
{
|
||||
|
||||
@@ -50,6 +50,7 @@ class Response
|
||||
/**
|
||||
* Sets the preferred method to use for making HTTP calls.
|
||||
* @param string $method Default is `auto`
|
||||
* @return Response
|
||||
*/
|
||||
public static function setMethod($method = 'auto')
|
||||
{
|
||||
@@ -64,8 +65,9 @@ class Response
|
||||
|
||||
/**
|
||||
* Makes a request to the URL by using the preferred method
|
||||
* @param string $uri URL to call
|
||||
* @param array $options An array of parameters for both `curl` and `fopen`
|
||||
* @param string $uri URL to call
|
||||
* @param array $options An array of parameters for both `curl` and `fopen`
|
||||
* @param callable $callback Either a function or callback in array notation
|
||||
* @return string The response of the request
|
||||
*/
|
||||
public static function get($uri = '', $options = [], $callback = null)
|
||||
|
||||
@@ -201,7 +201,10 @@ class Grav extends Container
|
||||
// Use output buffering to prevent headers from being sent too early.
|
||||
ob_start();
|
||||
if ($this['config']->get('system.cache.gzip')) {
|
||||
ob_start('ob_gzhandler');
|
||||
// Enable zip/deflate with a fallback in case of if browser does not support compressing.
|
||||
if(!ob_start("ob_gzhandler")) {
|
||||
ob_start();
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize the timezone
|
||||
@@ -416,22 +419,25 @@ class Grav extends Container
|
||||
public function shutdown()
|
||||
{
|
||||
if ($this['config']->get('system.debugger.shutdown.close_connection')) {
|
||||
//stop user abort
|
||||
// Prevent user abort.
|
||||
if (function_exists('ignore_user_abort')) {
|
||||
@ignore_user_abort(true);
|
||||
}
|
||||
|
||||
// close the session
|
||||
// Close the session.
|
||||
if (isset($this['session'])) {
|
||||
$this['session']->close();
|
||||
}
|
||||
|
||||
// flush buffer if gzip buffer was started
|
||||
if ($this['config']->get('system.cache.gzip')) {
|
||||
ob_end_flush(); // gzhandler buffer
|
||||
// Flush gzhandler buffer if gzip was enabled.
|
||||
ob_end_flush();
|
||||
} else {
|
||||
// Otherwise prevent server from compressing the output.
|
||||
header('Content-Encoding: none');
|
||||
}
|
||||
|
||||
// get lengh and close the connection
|
||||
// Get length and close the connection.
|
||||
header('Content-Length: ' . ob_get_length());
|
||||
header("Connection: close");
|
||||
|
||||
@@ -440,7 +446,7 @@ class Grav extends Container
|
||||
@ob_flush();
|
||||
flush();
|
||||
|
||||
// fix for fastcgi close connection issue
|
||||
// Fix for fastcgi close connection issue.
|
||||
if (function_exists('fastcgi_finish_request')) {
|
||||
@fastcgi_finish_request();
|
||||
}
|
||||
|
||||
@@ -41,6 +41,7 @@ class Page
|
||||
protected $folder;
|
||||
protected $path;
|
||||
protected $extension;
|
||||
protected $url_extension;
|
||||
|
||||
protected $id;
|
||||
protected $parent;
|
||||
@@ -128,6 +129,7 @@ class Page
|
||||
$this->modularTwig($this->slug[0] == '_');
|
||||
$this->setPublishState();
|
||||
$this->published();
|
||||
$this->urlExtension();
|
||||
|
||||
// some extension logic
|
||||
if (empty($extension)) {
|
||||
@@ -136,6 +138,7 @@ class Page
|
||||
$this->extension($extension);
|
||||
}
|
||||
|
||||
|
||||
// extract page language from page extension
|
||||
$language = trim(basename($this->extension(), 'md'), '.') ?: null;
|
||||
$this->language($language);
|
||||
@@ -349,7 +352,6 @@ class Page
|
||||
if (isset($this->header->last_modified)) {
|
||||
$this->last_modified = (bool) $this->header->last_modified;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return $this->header;
|
||||
@@ -957,6 +959,17 @@ class Page
|
||||
return $this->extension;
|
||||
}
|
||||
|
||||
public function urlExtension()
|
||||
{
|
||||
// if not set in the page get the value from system config
|
||||
if (empty($this->url_extension)) {
|
||||
$this->url_extension = trim(isset($this->header->append_url_extension) ? $this->header->append_url_extension : self::getGrav()['config']->get('system.pages.append_url_extension', false));
|
||||
}
|
||||
|
||||
return $this->url_extension;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets and sets the expires field. If not set will return the default
|
||||
*
|
||||
@@ -1262,7 +1275,7 @@ class Page
|
||||
|
||||
$rootUrl = $uri->rootUrl($include_host) . $pages->base();
|
||||
|
||||
$url = $rootUrl.'/'.trim($route, '/');
|
||||
$url = $rootUrl.'/'.trim($route, '/') . $this->urlExtension();
|
||||
|
||||
// trim trailing / if not root
|
||||
if ($url !== '/') {
|
||||
|
||||
@@ -94,14 +94,17 @@ class TwigExtension extends \Twig_Extension
|
||||
new \Twig_simpleFunction('authorize', [$this, 'authorize']),
|
||||
new \Twig_SimpleFunction('debug', [$this, 'dump'], ['needs_context' => true, 'needs_environment' => true]),
|
||||
new \Twig_SimpleFunction('dump', [$this, 'dump'], ['needs_context' => true, 'needs_environment' => true]),
|
||||
new \Twig_SimpleFunction('evaluate', [$this, 'evaluateFunc']),
|
||||
new \Twig_SimpleFunction('gist', [$this, 'gistFunc']),
|
||||
new \Twig_SimpleFunction('nonce_field', [$this, 'nonceFieldFunc']),
|
||||
new \Twig_simpleFunction('random_string', [$this, 'randomStringFunc']),
|
||||
new \Twig_SimpleFunction('repeat', [$this, 'repeatFunc']),
|
||||
new \Twig_SimpleFunction('string', [$this, 'stringFunc']),
|
||||
new \Twig_simpleFunction('t', [$this, 'translate']),
|
||||
new \Twig_simpleFunction('ta', [$this, 'translateArray']),
|
||||
new \Twig_SimpleFunction('url', [$this, 'urlFunc']),
|
||||
new \Twig_SimpleFunction('evaluate', [$this, 'evaluateFunc']),
|
||||
|
||||
|
||||
];
|
||||
}
|
||||
|
||||
@@ -595,4 +598,22 @@ class TwigExtension extends \Twig_Extension
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to add a nonce to a form. Call {{ nonce_field('action') }} specifying a string representing the action.
|
||||
*
|
||||
* For maximum protection, ensure that the string representing the action is as specific as possible.
|
||||
*
|
||||
* @todo evaluate if adding referrer or not
|
||||
*
|
||||
* @param string action the action
|
||||
* @param string nonceParamName a custom nonce param name
|
||||
*
|
||||
* @return string the nonce input field
|
||||
*/
|
||||
public function nonceFieldFunc($action, $nonceParamName = 'nonce')
|
||||
{
|
||||
$string = '<input type="hidden" id="' . $nonceParamName . '" name="' . $nonceParamName . '" value="' . Utils::getNonce($action) .'" />';
|
||||
return $string;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -139,6 +139,7 @@ class Uri
|
||||
|
||||
$valid_page_types = implode('|', $config->get('system.pages.types'));
|
||||
|
||||
// Strip the file extension for valid page types
|
||||
if (preg_match("/\.(".$valid_page_types.")$/", $parts['basename'])) {
|
||||
$uri = rtrim(str_replace(DIRECTORY_SEPARATOR, DS, $parts['dirname']), DS). '/' .$parts['filename'];
|
||||
}
|
||||
@@ -571,4 +572,21 @@ class Uri
|
||||
return $normalized_url;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the nonce to a URL for a specific action
|
||||
*
|
||||
* @param string $url the url
|
||||
* @param string $action the action
|
||||
* @param string $nonceParamName the param name to use
|
||||
*
|
||||
* @return string the url with the nonce
|
||||
*/
|
||||
public static function addNonce($url, $action, $nonceParamName = 'nonce')
|
||||
{
|
||||
$nonce = Utils::getNonce($action);
|
||||
$nonce = str_replace('/', 'SLASH', $nonce);
|
||||
$urlWithNonce = $url . '/' . $nonceParamName . Grav::instance()['config']->get('system.param_sep', ':') . $nonce;
|
||||
return $urlWithNonce;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -384,7 +384,109 @@ abstract class Utils
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public static function isPositive($value) {
|
||||
public static function isPositive($value)
|
||||
{
|
||||
return in_array($value, [true, 1, '1', 'yes', 'on', 'true'], true);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Generates a nonce string to be hashed. Called by self::getNonce()
|
||||
*
|
||||
* @param string $action
|
||||
* @param bool $plusOneTick if true, generates the token for the next tick (the next 12 hours)
|
||||
*
|
||||
* @return string the nonce string
|
||||
*/
|
||||
private static function generateNonceString($action, $plusOneTick = false)
|
||||
{
|
||||
if (isset(self::getGrav()['user'])) {
|
||||
$user = self::getGrav()['user'];
|
||||
$username = $user->username;
|
||||
} else {
|
||||
$username = false;
|
||||
}
|
||||
|
||||
if (!$username) {
|
||||
$username = isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : '';
|
||||
}
|
||||
|
||||
$token = session_id();
|
||||
$i = self::nonceTick();
|
||||
|
||||
if ($plusOneTick) {
|
||||
$i++;
|
||||
}
|
||||
|
||||
return ( $i . '|' . $action . '|' . $username . '|' . $token );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the time-dependent variable for nonce creation.
|
||||
*
|
||||
* @todo now a tick lasts a day. Once the day is passed, the nonce is not valid any more. Find a better way
|
||||
* to ensure nonces issued near the end of the day do not expire in that small amount of time
|
||||
*
|
||||
* @return int the time part of the nonce. Changes once every 24 hours
|
||||
*/
|
||||
private static function nonceTick()
|
||||
{
|
||||
$secondsInHalfADay = 60 * 60 * 12;
|
||||
return (int)ceil(time() / ( $secondsInHalfADay ));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get hash of given string
|
||||
*
|
||||
* @param string $data string to hash
|
||||
*
|
||||
* @return string hashed value of $data, cut to 10 characters
|
||||
*/
|
||||
private static function hash($data)
|
||||
{
|
||||
$hash = password_hash($data, PASSWORD_DEFAULT);
|
||||
return $hash;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a hashed nonce tied to the passed action. Tied to the current user and time. The nonce for a given
|
||||
* action is the same for 12 hours.
|
||||
*
|
||||
* @param string $action the action the nonce is tied to (e.g. save-user-admin or move-page-homepage)
|
||||
* @param bool $plusOneTick if true, generates the token for the next tick (the next 12 hours)
|
||||
*
|
||||
* @return string the nonce
|
||||
*/
|
||||
public static function getNonce($action, $plusOneTick = false)
|
||||
{
|
||||
$nonce = self::hash(self::generateNonceString($action, $plusOneTick));
|
||||
return $nonce;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify the passed nonce for the give action
|
||||
*
|
||||
* @param string $nonce the nonce to verify
|
||||
* @param string $action the action to verify the nonce to
|
||||
*
|
||||
* @return boolean verified or not
|
||||
*/
|
||||
public static function verifyNonce($nonce, $action)
|
||||
{
|
||||
$nonce = str_replace('SLASH', '/', $nonce);
|
||||
|
||||
//Nonce generated 0-12 hours ago
|
||||
if (password_verify(self::generateNonceString($action), $nonce)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
//Nonce generated 12-24 hours ago
|
||||
$plusOneTick = true;
|
||||
if (password_verify(self::generateNonceString($action, $plusOneTick), $nonce)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
//Invalid nonce
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user