Compare commits

...

75 Commits
1.3.5 ... 1.3.9

Author SHA1 Message Date
Andy Miller
d4204f13f8 Merge branch 'release/1.3.9' 2017-12-05 17:16:13 -07:00
Andy Miller
0554b25c78 Prepare for release 2017-12-05 17:16:05 -07:00
Andy Miller
f4e7cbaa6e updated changelog 2017-12-05 17:15:28 -07:00
Andy Miller
83bfc1fd0f Added support for intl_enabled option 2017-12-05 17:03:05 -07:00
Andy Miller
30439b864d Added a quick type test for #1764 2017-12-05 11:04:59 -07:00
Andy Miller
80999121a9 Potential fix for #1764 2017-12-05 10:51:44 -07:00
Andy Miller
ca0d0bb373 Added a comment 2017-12-05 10:50:39 -07:00
Andy Miller
345578a05d Force field.multiple: true for checkboxes to use min/max rules 2017-12-04 22:32:26 -07:00
Andy Miller
1f0537124a Merge branch 'develop' of https://github.com/getgrav/grav into develop 2017-12-04 18:14:25 -07:00
Andy Miller
2a2b9a12a7 Fix for checkbox validation form#216 2017-12-04 18:14:20 -07:00
Iain Gillis
5a19e05931 Fix typo (#1770) 2017-12-02 22:08:55 -07:00
Andy Miller
6ae4680fcb Move system twig templates to last 2017-12-01 11:38:38 -07:00
Andy Miller
b4cf7899bb cleanup 2017-12-01 00:01:23 -07:00
Andy Miller
eac16911d0 Added new core twig templates 2017-11-30 18:31:13 -07:00
Andy Miller
21bef62b82 Added get and set FlashCookieObject() methods 2017-11-30 18:28:25 -07:00
Andy Miller
a1eccfdb61 Updated changelog 2017-11-28 12:58:04 -07:00
Matias Griese
90e05694d3 Merge remote-tracking branch 'origin/develop' into develop 2017-11-28 14:58:07 +02:00
Matias Griese
b97ac503a1 Add filter for item-list type (removes empty items from the list) 2017-11-28 14:57:53 +02:00
Agustin Villalba
2cc34151df Fixed issue #1742 where the creation of GPM object tried to connect to Remote repositories even if only Local package was needed (#1746)
All good, thanks!
2017-11-27 21:15:09 -07:00
Iain Gillis
4c160533c2 Add additional controls to HTML5 audio attributes (#1756)
Adds support for `autoplay`, `controls`, `loop`, and `preload` attributes, with rudimentary validation for preload.

Those for `autoplay`, `controls`, and `loop` are copied directly from pfcloutier-druide/aaa3f82

See also #1442.
2017-11-27 21:12:56 -07:00
Matias Griese
59dd0d1212 Fixed CSS Pipeline failing with Google remote fonts if the file was minified (#1261) (#1763)
* Fixed CSS Pipeline failing with Google remote fonts if the file was minified (#1261)

* Assets: Make tag check ungreedy again -- inline js may have tags in the content
2017-11-27 21:12:33 -07:00
Andy Miller
3bf7e38e52 Updated changelog 2017-11-27 18:30:10 -07:00
Andy Miller
362ee4c9eb Fix for URL encoding with Multibyte folders 2017-11-27 18:27:18 -07:00
Andy Miller
2462331884 Fix for MB Markdown links #1749 2017-11-27 18:21:08 -07:00
Matias Griese
cb4147a4bd Fixed token creation issue with Uri params like /id:3 2017-11-17 08:03:58 +02:00
Wensheng Yan
72f3a01abf Update Cache.php (#1745)
make sure find resource return valid path.
2017-11-15 18:35:44 -07:00
Matias Griese
31e3c1c295 Remove support for config.user, it was broken and bad practise 2017-11-10 22:07:29 +02:00
Andy Miller
37891a1032 Minor optimizations 2017-11-08 05:34:42 -07:00
Andy Miller
70284e1517 Sort using folder name #1740 2017-11-07 18:38:35 -07:00
Andy Miller
0bca1dcb48 Fix for custom_base_url issues #1736 2017-11-07 17:50:06 -07:00
Andy Miller
36f9865c0b Couple of utility functions 2017-11-07 17:44:40 -07:00
Matias Griese
cd48551630 Fix changelog 2017-11-07 17:00:34 +02:00
Matias Griese
0ff130650f Merge remote-tracking branch 'origin/develop' into develop 2017-11-07 16:57:59 +02:00
Matias Griese
9b445ac5b6 Fixed "Invalid AJAX response" When using Built-in PHP Webserver in Windows (#1258) 2017-11-07 16:57:52 +02:00
Andy Miller
c21248fcc2 Updated changelog 2017-11-06 19:52:05 -07:00
Andy Miller
88aa4c5ec9 Added ability to toggle lowercase urls 2017-11-06 19:50:59 -07:00
Matias Griese
0fd22ad933 Uri: Encode user and password to prevent issues in browsers 2017-11-06 10:26:17 +02:00
Andy Miller
00b56da220 Updated changelog 2017-11-02 14:51:13 -06:00
Andy Miller
fef6bdde5f Revert "Added system option to enable case insensitive urls. (#1638)"
This reverts commit 481fe1903e.
2017-11-02 14:48:42 -06:00
Sam
6f7938e939 Update README.md (#1705) 2017-11-01 17:21:14 -06:00
Viktor
2cd469cd7c Update CompiledFile.php (#1693)
const CACHE_DIR already defined with trailing slash

```php
define('CACHE_DIR', ROOT_DIR . 'cache/');
```
2017-11-01 17:20:38 -06:00
Andy Miller
0895b15489 Updated changelog 2017-10-31 16:38:16 -06:00
Andy Miller
d9062b60d6 Merge branch 'develop' of https://github.com/getgrav/grav into develop 2017-10-31 16:36:47 -06:00
Andy Miller
3f4049031d use Event object in Page/Pages events 2017-10-31 16:36:43 -06:00
Andy Miller
c81ce71074 Fix active() + activeChild() to work with UTF-8 #1727 2017-10-31 16:36:13 -06:00
cofunin
f84ffd235b Fix ignoring media in modular.yaml (#1725) 2017-10-30 18:15:39 -06:00
Andy Miller
1ca6181856 Added onPageProcessed for dynamic addPage() calls 2017-10-30 16:19:13 -06:00
Andy Miller
f17954a5db Added a copy method to Medium object 2017-10-30 15:36:52 -06:00
Andy Miller
acea401a3d Merge branch 'release/1.3.8' 2017-10-26 18:37:27 -06:00
Andy Miller
e9e4106d22 Merge tag '1.3.8' into develop
Release v1.3.8
2017-10-26 18:37:27 -06:00
Andy Miller
0ec7158102 Prepare for release 2017-10-26 18:37:17 -06:00
Andy Miller
d3695b2faa Fixed missing image file not throwing 404 p#1713 2017-10-23 16:19:08 -06:00
Andy Miller
0668a47758 Fixed GPM update issue with filtered slugs #1711 2017-10-23 16:13:22 -06:00
Andy Miller
ca645ef476 updated changelog 2017-10-19 22:13:36 -04:00
Andy Miller
3ff5f79561 Added manual order capability to Page media 2017-10-19 22:10:12 -04:00
Djamil Legato
b5c8b70163 More media order changes 2017-10-19 18:01:37 -04:00
Djamil Legato
173a70c017 Updated default yaml with media order 2017-10-19 17:39:10 -04:00
Benoît Rouleau
eb52f670b9 fix nonsense logic (#1709) 2017-10-19 16:53:31 -04:00
Sam
dd166ce25c Update CONTRIBUTING.md copywriting (#1706) 2017-10-19 09:19:03 -04:00
Andy Miller
ea6423226a Merge branch 'release/1.3.7' 2017-10-18 16:35:41 -04:00
Andy Miller
85bf4406ed Merge tag '1.3.7' into develop
Release v1.3.7
2017-10-18 16:35:41 -04:00
Andy Miller
0cb8e0664e Prepare for release 2017-10-18 16:35:27 -04:00
Matias Griese
2842b8fa39 Fixed routing paths with urlencoded spaces and non-latin letters (#1688) 2017-10-17 14:40:30 +03:00
Matias Griese
317615854a Uri: Prefer using REQUEST_SCHEME instead of HTTPS (#1698) 2017-10-17 13:34:25 +03:00
Matias Griese
a9c82710a6 Regression: base_url_absolute always has the port number (#1690) 2017-10-16 12:36:06 +03:00
Matias Griese
3856a2a719 Add unit test for #1688 2017-10-16 11:13:25 +03:00
Viktor
880128c339 Update Grav Console Cli InstallCommand.php (#1692)
why do I have to clone the entire history of the plugin?
2017-10-13 08:34:39 -06:00
Andy Miller
444b48f788 Merge branch 'release/1.3.6' 2017-10-12 12:26:29 -06:00
Andy Miller
cc69591799 Merge tag '1.3.6' into develop
Release v1.3.6
2017-10-12 12:26:29 -06:00
Andy Miller
0d6f774386 Prepare for release 2017-10-12 12:26:12 -06:00
Andy Miller
474ca513ae Fix for nginx and _url issue
[admin#1244](https://github.com/getgrav/grav-plugin-admin/issues/1244)
2017-10-12 12:23:49 -06:00
Matias Griese
f37c08f341 Regression: Ajax error in ngnix (#1244) 2017-10-12 21:18:34 +03:00
Matias Griese
92afba0e28 Add test case for #1244 2017-10-12 18:36:10 +03:00
Andy Miller
974fc552c5 Added another complex test 2017-10-11 19:24:16 -06:00
Andy Miller
9e1170bd50 Merge tag '1.3.5' into develop
Release v1.3.5
2017-10-11 14:49:28 -06:00
34 changed files with 748 additions and 162 deletions

View File

@@ -1,3 +1,57 @@
# v1.3.9
## 12/05/2017
1. [](#new)
* Added new core Twig templates for `partials/metadata.html.twig` and `partials/messages.html.twig`
* Added ability to work with GPM locally [#1742](https://github.com/getgrav/grav/issues/1742)
* Added new HTML5 audio controls [#1756](https://github.com/getgrav/grav/issues/1756)
* Added `Medium::copy()` method to create a copy of a medium object
* Added new `force_lowercase_urls` functionality on routes and slugs
* Added new `item-list` filter type to remove empty items
* Added new `setFlashCookieObject()` and `getFlashCookieObject()` methods to `Session` object
* Added new `intl_enabled` option to disable PHP intl module collation when not needed
1. [](#bugfix)
* Fixed an issue with checkbox field validation [form#216](https://github.com/getgrav/grav-plugin-form/issues/216)
* Fixed issue with multibyte Markdown link URLs [#1749](https://github.com/getgrav/grav/issues/1749)
* Fixed issue with multibyte folder names [#1751](https://github.com/getgrav/grav/issues/1751)
* Fixed several issues related to `system.custom_base_url` that were broken [#1736](https://github.com/getgrav/grav/issues/1736)
* Dynamically added pages via `Pages::addPage()` were not firing `onPageProcessed()` event causing forms not to be processed
* Fixed `Page::active()` and `Page::activeChild()` to work with UTF-8 characters in the URL [#1727](https://github.com/getgrav/grav/issues/1727)
* Fixed typo in `modular.yaml` causing media to be ignored [#1725](https://github.com/getgrav/grav/issues/1725)
* Reverted `case_insensitive_urls` option as it was causing issues with taxonomy [#1733](https://github.com/getgrav/grav/pull/1733)
* Removed an extra `/` in `CompileFile.php` [#1693](https://github.com/getgrav/grav/pull/1693)
* Uri::Encode user and password to prevent issues in browsers
* Fixed "Invalid AJAX response" When using Built-in PHP Webserver in Windows [#1258](https://github.com/getgrav/grav-plugin-admin/issues/1258)
* Remove support for `config.user`, it was broken and bad practise
* Make sure that `clean cache` uses valid path [#1745](https://github.com/getgrav/grav/pull/1745)
* Fixed token creation issue with `Uri` params like `/id:3`
* Fixed CSS Pipeline failing with Google remote fonts if the file was minified [#1261](https://github.com/getgrav/grav-plugin-admin/issues/1261)
* Forced `field.multiple: true` to allow use of min/max options in `checkboxes.validate`
# v1.3.8
## 10/26/2017
1. [](#new)
* Added Page `media_order` capability to manually order page media via a page header
1. [](#bugfix)
* Fixed GPM update issue with filtered slugs [#1711](https://github.com/getgrav/grav/issues/1711)
* Fixed issue with missing image file not throwing 404 properly [#1713](https://github.com/getgrav/grav/issues/1713)
# v1.3.7
## 10/18/2017
1. [](#bugfix)
* Regression Uri: `base_url_absolute` always has the port number [#1690](https://github.com/getgrav/grav-plugin-admin/issues/1690)
* Uri: Prefer using REQUEST_SCHEME instead of HTTPS [#1698](https://github.com/getgrav/grav-plugin-admin/issues/1698)
* Fixed routing paths with urlencoded spaces and non-latin letters [#1688](https://github.com/getgrav/grav-plugin-admin/issues/1688)
# v1.3.6
## 10/12/2017
1. [](#bugfix)
* Regression: Ajax error in Nginx [admin#1244](https://github.com/getgrav/grav-plugin-admin/issues/1244)
* Remove the `_url=$uri` portion of the the Nginx `try_files` command [admin#1244](https://github.com/getgrav/grav-plugin-admin/issues/1244)
# v1.3.5
## 10/11/2017

View File

@@ -12,7 +12,7 @@ patches and features.
## Grav, Plugins, Themes and Skeletons
Grav is a large open source projectit's made up of over 100 repositories. When you initially consider contributing to Grav, you might be unsure about which of those 200 repositories implements the functionality you want to change or report a bug for.
Grav is a large open source projectit's made up of over 100 repositories. When you initially consider contributing to Grav, you might be unsure about which of those 200 repositories implements the functionality you want to change or report a bug for.
[https://github.com/getgrav/grav](https://github.com/getgrav/grav) is the main Grav repository. The core of Grav is provided by this repo.
@@ -60,20 +60,20 @@ Guidelines for bug reports:
A good bug report shouldn't leave others needing to chase you up for more
information. Please try to be as detailed as possible in your report.
What is your environment? Is it localhost, OSX, Linux, on a remote server? Same happening locally and or the server, or just locally or just on Linux?
- What is your environment? Is it localhost, OSX, Linux, on a remote server? Same happening locally and or the server, or just locally or just on Linux?
What steps will reproduce the issue? What browser(s) and OS experience the problem?
- What steps will reproduce the issue? What browser(s) and OS experience the problem?
What would you expect to be the outcome?
- What would you expect to be the outcome?
Did the problem start happening recently (e.g. after updating to a new version of Grav) or was this always a problem?
- Did the problem start happening recently (e.g. after updating to a new version of Grav) or was this always a problem?
If the problem started happening recently, can you reproduce the problem in an older version of Grav? What's the most recent version in which the problem doesn't happen? You can download older versions of Grav from the releases page on Github.
- If the problem started happening recently, can you reproduce the problem in an older version of Grav? What's the most recent version in which the problem doesn't happen? You can download older versions of Grav from the releases page on Github.
Can you reliably reproduce the issue? If not, provide details about how often the problem happens and under which conditions it normally happens.
- Can you reliably reproduce the issue? If not, provide details about how often the problem happens and under which conditions it normally happens.
All these details will help people to fix any potential bugs.
All these details will help contributors to fix any potential bugs.
Important: [include Code Samples in triple backticks](https://help.github.com/articles/github-flavored-markdown/#fenced-code-blocks) so that Github will provide a proper indentation. [Add the language name after the backticks](https://help.github.com/articles/github-flavored-markdown/#syntax-highlighting) to add syntax highlighting to the code snippets.

View File

@@ -86,7 +86,7 @@ $ bin/gpm update
We appreciate any contribution to Grav, whether it is related to bugs, grammar, or simply a suggestion or improvement! Please refer to the [Contributing guide](CONTRIBUTING.md) for more guidance on this topic.
## Security issues
If you discover a possible security issue related to Grav or one of its plugins, please send an email to the core team at contact@getgrav.org and we'll address it as soon as possible.
If you discover a possible security issue related to Grav or one of its plugins, please email the core team at contact@getgrav.org and we'll address it as soon as possible.
# Getting Started
@@ -101,9 +101,11 @@ If you discover a possible security issue related to Grav or one of its plugins,
* Have a look at our [Basic Tutorial](https://learn.getgrav.org/basics/basic-tutorial)
* Dive into more [advanced](https://learn.getgrav.org/advanced) functions
* Learn about the [Grav CLI](https://learn.getgrav.org/cli-console/grav-cli)
* Review examples in the [Grav Cookbook](https://learn.getgrav.org/cookbook)
# Backers
Support us with a monthly donation and help us continue our activities. [[Become a backer](https://opencollective.com/grav#backer)]
Support Grav with a monthly donation to help us continue development. [[Become a backer](https://opencollective.com/grav#backer)]
<a href="https://opencollective.com/grav/backer/0/website" target="_blank"><img src="https://opencollective.com/grav/backer/0/avatar.svg"></a>
<a href="https://opencollective.com/grav/backer/1/website" target="_blank"><img src="https://opencollective.com/grav/backer/1/avatar.svg"></a>

View File

@@ -1131,6 +1131,16 @@ form:
label: PLUGIN_ADMIN.PWD_REGEX
help: PLUGIN_ADMIN.PWD_REGEX_HELP
intl_enabled:
type: toggle
label: PLUGIN_ADMIN.INTL_ENABLED
highlight: 1
help: PLUGIN_ADMIN.INTL_ENABLED_HELP
options:
1: PLUGIN_ADMIN.YES
0: PLUGIN_ADMIN.NO
validate:
type: bool
wrapped_site:
type: toggle
@@ -1154,17 +1164,6 @@ form:
validate:
type: bool
case_insensitive_urls:
type: toggle
label: PLUGIN_ADMIN.CASE_INSENSITIVE_URLS
highlight: 0
help: PLUGIN_ADMIN.CASE_INSENSITIVE_URLS_HELP
options:
1: PLUGIN_ADMIN.YES
0: PLUGIN_ADMIN.NO
validate:
type: bool
param_sep:
type: select
size: medium
@@ -1187,6 +1186,18 @@ form:
validate:
type: bool
force_lowercase_urls:
type: toggle
label: PLUGIN_ADMIN.FORCE_LOWERCASE_URLS
highlight: 1
default: 1
help: PLUGIN_ADMIN.FORCE_LOWERCASE_URLS_HELP
options:
1: PLUGIN_ADMIN.YES
0: PLUGIN_ADMIN.NO
validate:
type: bool
custom_base_url:
type: text
size: medium

View File

@@ -32,7 +32,7 @@ form:
validate:
type: textarea
uploads:
header.media_order:
type: pagemedia
label: PLUGIN_ADMIN.PAGE_MEDIA

View File

@@ -25,7 +25,7 @@ form:
content:
unset@: true
uploads:
header.media_order:
unset@: true
header.external_url:

View File

@@ -42,6 +42,6 @@ form:
type: ignore
content:
type: ignore
uploads:
header.media_order:
type: ignore

View File

@@ -5,9 +5,11 @@ param_sep: ':' # Parameter separator, use ';'
wrapped_site: false # For themes/plugins to know if Grav is wrapped by another platform
reverse_proxy_setup: false # Running in a reverse proxy scenario with different webserver ports than proxy
force_ssl: false # If enabled, Grav forces to be accessed via HTTPS (NOTE: Not an ideal solution)
force_lowercase_urls: true # If you want to support mixed cased URLs set this to false
custom_base_url: '' # Set the base_url manually, e.g. http://yoursite.com/yourpath
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
intl_enabled: true # Special logic for PHP International Extension (mod_intl)
languages:
supported: [] # List of languages supported. eg: [en, fr, de]

View File

@@ -8,7 +8,7 @@
// Some standard defines
define('GRAV', true);
define('GRAV_VERSION', '1.3.5');
define('GRAV_VERSION', '1.3.9');
//define('GRAV_TESTING', true);
define('DS', '/');

View File

@@ -35,11 +35,15 @@ class Assets
const CSS_URL_REGEX = '{url\(([\'\"]?)(.*?)\1\)}';
/** @const Regex to match CSS sourcemap comments */
const CSS_SOURCEMAP_REGEX = '{\/\*# (.*) \*\/}';
const CSS_SOURCEMAP_REGEX = '{\/\*# (.*?) \*\/}';
/** @const Regex to match CSS import content */
const CSS_IMPORT_REGEX = '{@import(.*);}';
const CSS_IMPORT_REGEX = '{@import(.*?);}';
/**
* @const Regex to match <script> or <style> tag when adding inline style/script. Note that this only supports a
* single tag, so the check is greedy to avoid issues in JS.
*/
const HTML_TAG_REGEX = '#(<([A-Z][A-Z0-9]*)>)+(.*)(<\/\2>)#is';

View File

@@ -390,6 +390,7 @@ class Cache extends Getters
// Convert stream to a real path
try {
$path = $locator->findResource($stream, true, true);
if($path === false) continue;
$anything = false;
$files = glob($path . '/*');

View File

@@ -28,9 +28,12 @@ class Validation
$messages = [];
$validate = isset($field['validate']) ? (array) $field['validate'] : [];
// Validate type with fallback type text.
$type = (string) isset($validate['type']) ? $validate['type'] : $field['type'];
$method = 'type'.strtr($type, '-', '_');
// If value isn't required, we will stop validation if empty value is given.
if (empty($validate['required']) && ($value === null || $value === '')) {
if ((empty($validate['required']) || (isset($validate['required']) && $validate['required'] !== true)) && ($value === null || $value === '' || ($field['type'] === 'checkbox' && $value == false))) {
return $messages;
}
@@ -46,10 +49,6 @@ class Validation
// Get language class.
$language = Grav::instance()['language'];
// Validate type with fallback type text.
$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'])
? $language->translate($field['validate']['message'])
@@ -161,7 +160,7 @@ class Validation
return is_array($value) ? $value : preg_split('/\s*,\s*/', $value, -1, PREG_SPLIT_NO_EMPTY);
}
protected static function typeCommaList($value, array $params, array $field)
public static function typeCommaList($value, array $params, array $field)
{
return is_array($value) ? true : self::typeText($value, $params, $field);
}
@@ -230,6 +229,8 @@ class Validation
*/
public static function typeCheckboxes($value, array $params, array $field)
{
// Set multiple: true so checkboxes can easily use min/max counts to control number of options required
$field['multiple'] = true;
return self::typeArray((array) $value, $params, $field);
}
@@ -253,7 +254,7 @@ class Validation
if (!isset($field['value'])) {
$field['value'] = 1;
}
if ($value && $value != $field['value']) {
if (isset($value) && $value != $field['value']) {
return false;
}
@@ -758,6 +759,11 @@ class Validation
&& $value instanceof \Countable);
}
public static function filterItem_List($value, $params)
{
return array_values(array_filter($value, function($v) { return !empty($v); } ));
}
public static function validateJson($value, $params)
{
return (bool) (@json_decode($value));

View File

@@ -27,7 +27,7 @@ trait CompiledFile
// If nothing has been loaded, attempt to get pre-compiled version of the file first.
if ($var === null && $this->raw === null && $this->content === null) {
$key = md5($this->filename);
$file = PhpFile::instance(CACHE_DIR . DS . "compiled/files/{$key}{$this->extension}.php");
$file = PhpFile::instance(CACHE_DIR . "compiled/files/{$key}{$this->extension}.php");
$modified = $this->modified();

View File

@@ -17,6 +17,9 @@ use Symfony\Component\Yaml\Yaml;
class GPM extends Iterator
{
/** @var callable */
private $callback;
/**
* Local installed Packages
* @var Local\Packages
@@ -29,6 +32,9 @@ class GPM extends Iterator
*/
private $repository;
/** @var bool */
private $shouldRefresh;
/**
* @var Remote\GravCore
*/
@@ -47,18 +53,33 @@ class GPM extends Iterator
];
/**
* Creates a new GPM instance with Local and Remote packages available
* Loads Remote Packages available
*/
private function retrieveRemoteRepository()
{
if (!$this->repository) {
$this->repository = new Remote\Packages($this->shouldRefresh, $this->callback);
}
}
/**
* Creates a new GPM instance with Local packages available
* @param boolean $refresh Applies to Remote Packages only and forces a refetch of data
* @param callable $callback Either a function or callback in array notation
*/
public function __construct($refresh = false, $callback = null)
{
$this->installed = new Local\Packages();
try {
$this->repository = new Remote\Packages($refresh, $callback);
$this->grav = new Remote\GravCore($refresh, $callback);
} catch (\Exception $e) {
}
$this->shouldRefresh = $refresh;
$this->callback = $callback;
}
/**
* Loads Remote Grav package available
*/
public function loadRemoteGrav()
{
$this->grav = new Remote\GravCore($this->refresh, $this->callback);
}
/**
@@ -268,6 +289,7 @@ class GPM extends Iterator
*/
public function getLatestVersionOfPackage($package_name)
{
$this->retrieveRemoteRepository();
$repository = $this->repository['plugins'];
if (isset($repository[$package_name])) {
return $repository[$package_name]->available ?: $repository[$package_name]->version;
@@ -310,6 +332,7 @@ class GPM extends Iterator
public function getUpdatableThemes()
{
$items = [];
$this->retrieveRemoteRepository();
$repository = $this->repository['themes'];
// local cache to speed things up
@@ -357,6 +380,7 @@ class GPM extends Iterator
*/
public function getReleaseType($package_name)
{
$this->retrieveRemoteRepository();
$repository = $this->repository['plugins'];
if (isset($repository[$package_name])) {
return $repository[$package_name]->release_type;
@@ -405,6 +429,7 @@ class GPM extends Iterator
*/
public function getRepositoryPlugin($slug)
{
$this->retrieveRemoteRepository();
return @$this->repository['plugins'][$slug];
}
@@ -443,6 +468,7 @@ class GPM extends Iterator
*/
public function getRepository()
{
$this->retrieveRemoteRepository();
return $this->repository;
}

View File

@@ -148,7 +148,7 @@ class Grav extends Container
// Initialize Locale if set and configured.
if ($this['language']->enabled() && $this['config']->get('system.languages.override_locale')) {
$language = $this['language']->getLanguage();
setlocale(LC_ALL, count($language < 3) ? ($language . '_' . strtoupper($language)) : $language);
setlocale(LC_ALL, strlen($language) < 3 ? ($language . '_' . strtoupper($language)) : $language);
} elseif ($this['config']->get('system.default_locale')) {
setlocale(LC_ALL, $this['config']->get('system.default_locale'));
}
@@ -499,6 +499,9 @@ class Grav extends Container
}
Utils::download($page->path() . DIRECTORY_SEPARATOR . $uri->basename(), $download);
}
// Nothing found
return false;
}
return $page;

View File

@@ -12,6 +12,7 @@ use Grav\Common\Grav;
use Grav\Common\Page\Page;
use Grav\Common\Uri;
use Grav\Common\Page\Medium\Medium;
use Grav\Common\Utils;
use RocketTheme\Toolbox\Event\Event;
use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
@@ -321,7 +322,7 @@ class Excerpts
*/
protected static function parseUrl($url)
{
$url_parts = parse_url($url);
$url_parts = Utils::multibyteParseUrl($url);
if (isset($url_parts['scheme'])) {
/** @var UniformResourceLocator $locator */

View File

@@ -9,6 +9,8 @@
namespace Grav\Common\Page\Medium;
use Grav\Common\Getters;
use Grav\Common\Grav;
use Grav\Common\Utils;
abstract class AbstractMedia extends Getters
{
@@ -49,7 +51,8 @@ abstract class AbstractMedia extends Getters
*/
public function all()
{
ksort($this->instances, SORT_NATURAL | SORT_FLAG_CASE);
$this->instances = $this->orderMedia($this->instances);
return $this->instances;
}
@@ -60,7 +63,7 @@ abstract class AbstractMedia extends Getters
*/
public function images()
{
ksort($this->images, SORT_NATURAL | SORT_FLAG_CASE);
$this->images = $this->orderMedia($this->images);
return $this->images;
}
@@ -71,7 +74,7 @@ abstract class AbstractMedia extends Getters
*/
public function videos()
{
ksort($this->videos, SORT_NATURAL | SORT_FLAG_CASE);
$this->videos = $this->orderMedia($this->videos);
return $this->videos;
}
@@ -82,7 +85,7 @@ abstract class AbstractMedia extends Getters
*/
public function audios()
{
ksort($this->audios, SORT_NATURAL | SORT_FLAG_CASE);
$this->audios = $this->orderMedia($this->audios);
return $this->audios;
}
@@ -93,7 +96,7 @@ abstract class AbstractMedia extends Getters
*/
public function files()
{
ksort($this->files, SORT_NATURAL | SORT_FLAG_CASE);
$this->files = $this->orderMedia($this->files);
return $this->files;
}
@@ -119,6 +122,25 @@ abstract class AbstractMedia extends Getters
}
}
/**
* Order the media based on the page's media_order
*
* @param $media
* @return array
*/
protected function orderMedia($media)
{
$page = Grav::instance()['pages']->get($this->path);
if ($page && isset($page->header()->media_order)) {
$media_order = array_map('trim', explode(',', $page->header()->media_order));
$media = Utils::sortArrayByArray($media, $media_order);
} else {
ksort($media, SORT_NATURAL | SORT_FLAG_CASE);
}
return $media;
}
/**
* Get filename, extension and meta part.
*

View File

@@ -30,6 +30,114 @@ class AudioMedium extends Medium
];
}
/**
* Allows to set or remove the HTML5 default controls
*
* @param bool $display
* @return $this
*/
public function controls($display = true)
{
if($display)
{
$this->attributes['controls'] = true;
}
else
{
unset($this->attributes['controls']);
}
return $this;
}
/**
* Allows to set the preload behaviour
*
* @param $preload
* @return $this
*/
public function preload($preload)
{
$validPreloadAttrs = array('auto','metadata','none');
if (in_array($preload, $validPreloadAttrs))
{
$this->attributes['preload'] = $preload;
}
return $this;
}
/**
* Allows to set the controlsList behaviour
* Separate multiple values with a hyphen
*
* @param $controlsList
* @return $this
*/
public function controlsList($controlsList)
{
$controlsList = str_replace('-', ' ', $controlsList);
$this->attributes['controlsList'] = $controlsList;
return $this;
}
/**
* Allows to set the muted attribute
*
* @param bool $status
* @return $this
*/
public function muted($status = false)
{
if($status)
{
$this->attributes['muted'] = true;
}
else
{
unset($this->attributes['muted']);
}
return $this;
}
/**
* Allows to set the loop attribute
*
* @param bool $status
* @return $this
*/
public function loop($status = false)
{
if($status)
{
$this->attributes['loop'] = true;
}
else
{
unset($this->attributes['loop']);
}
return $this;
}
/**
* Allows to set the autoplay attribute
*
* @param bool $status
* @return $this
*/
public function autoplay($status = false)
{
if($status)
{
$this->attributes['autoplay'] = true;
}
else
{
unset($this->attributes['autoplay']);
}
return $this;
}
/**
* Reset medium.
*

View File

@@ -72,6 +72,16 @@ class Medium extends Data implements RenderableInterface
$this->reset();
}
/**
* Create a copy of this media object
*
* @return Medium
*/
public function copy()
{
return clone($this);
}
/**
* Return just metadata from the Medium object
*

View File

@@ -125,7 +125,7 @@ class Page
$config = Grav::instance()['config'];
$this->hide_home_route = $config->get('system.home.hide_in_urls', false);
$this->home_route = $config->get('system.home.alias');
$this->home_route = $this->adjustRouteCase($config->get('system.home.alias'));
$this->filePath($file->getPathName());
$this->modified($file->getMTime());
$this->id($this->modified() . md5($this->filePath()));
@@ -135,7 +135,7 @@ class Page
$this->metadata();
$this->url();
$this->visible();
$this->modularTwig($this->slug[0] == '_');
$this->modularTwig($this->slug[0] === '_');
$this->setPublishState();
$this->published();
$this->urlExtension();
@@ -517,17 +517,18 @@ class Page
// Return entire page content on wrong/ unknown format
if (!in_array($format, ['short', 'long'])) {
return $content;
} elseif (($format === 'short') && isset($summary_size)) {
}
if (($format === 'short') && isset($summary_size)) {
// Use mb_strimwidth to slice the string
if (mb_strwidth($content, 'utf8') > $summary_size) {
return mb_substr($content, 0, $summary_size);
} else {
return $content;
}
return $content;
}
// Get summary size from site config's file
if (is_null($size)) {
if ($size === null) {
$size = $config['size'];
}
@@ -535,7 +536,8 @@ class Page
if ($size === 0) {
return $content;
// Return calculated summary based on defaults
} elseif (!is_numeric($size) || ($size < 0)) {
}
if (!is_numeric($size) || ($size < 0)) {
$size = 300;
}
@@ -726,10 +728,9 @@ class Page
if ($name) {
if (isset($this->content_meta[$name])) {
return $this->content_meta[$name];
} else {
return null;
}
return null;
}
return $this->content_meta;
@@ -825,27 +826,27 @@ class Page
*/
public function value($name, $default = null)
{
if ($name == 'content') {
if ($name === 'content') {
return $this->raw_content;
}
if ($name == 'route') {
if ($name === 'route') {
return $this->parent()->rawRoute();
}
if ($name == 'order') {
if ($name === 'order') {
$order = $this->order();
return $order ? (int)$this->order() : '';
}
if ($name == 'ordering') {
if ($name === 'ordering') {
return (bool)$this->order();
}
if ($name == 'folder') {
if ($name === 'folder') {
return preg_replace(PAGE_ORDER_PREFIX_REGEX, '', $this->folder);
}
if ($name == 'slug') {
if ($name === 'slug') {
return $this->slug();
}
if ($name == 'name') {
if ($name === 'name') {
$language = $this->language() ? '.' . $this->language() : '';
$name_val = str_replace($language . '.md', '', $this->name());
if ($this->modular()) {
@@ -854,30 +855,30 @@ class Page
return $name_val;
}
if ($name == 'media') {
if ($name === 'media') {
return $this->media()->all();
}
if ($name == 'media.file') {
if ($name === 'media.file') {
return $this->media()->files();
}
if ($name == 'media.video') {
if ($name === 'media.video') {
return $this->media()->videos();
}
if ($name == 'media.image') {
if ($name === 'media.image') {
return $this->media()->images();
}
if ($name == 'media.audio') {
if ($name === 'media.audio') {
return $this->media()->audios();
}
$path = explode('.', $name);
$scope = array_shift($path);
if ($name == 'frontmatter') {
if ($name === 'frontmatter') {
return $this->frontmatter;
}
if ($scope == 'header') {
if ($scope === 'header') {
$current = $this->header();
foreach ($path as $field) {
if (is_object($current) && isset($current->{$field})) {
@@ -969,7 +970,7 @@ class Page
$this->_action = 'move';
if ($this->route() == $parent->route()) {
if ($this->route() === $parent->route()) {
throw new Exception('Failed: Cannot set page parent to self');
}
if (Utils::startsWith($parent->rawRoute(), $this->rawRoute())) {
@@ -1029,12 +1030,12 @@ class Page
$edit_mode = isset($grav['admin']) ? $grav['config']->get('plugins.admin.edit_mode') : null;
// override if you only want 'normal' mode
if (empty($fields) && ($edit_mode == 'auto' || $edit_mode == 'normal')) {
if (empty($fields) && ($edit_mode === 'auto' || $edit_mode === 'normal')) {
$blueprint = $pages->blueprints('default');
}
// override if you only want 'expert' mode
if (!empty($fields) && $edit_mode == 'expert') {
if (!empty($fields) && $edit_mode === 'expert') {
$blueprint = $pages->blueprints('');
}
@@ -1459,9 +1460,9 @@ class Page
{
if (isset($this->debugger) && $this->debugger === false) {
return false;
} else {
return true;
}
return true;
}
/**
@@ -1502,7 +1503,7 @@ class Page
// Backward compatibility for nested arrays in metas
if (is_array($value)) {
foreach ($value as $property => $prop_value) {
$prop_key = $key . ":" . $property;
$prop_key = $key . ':' . $property;
$this->metadata[$prop_key] = [
'name' => $prop_key,
'property' => $prop_key,
@@ -1517,7 +1518,7 @@ class Page
'http_equiv' => $key,
'content' => htmlspecialchars($value, ENT_QUOTES, 'UTF-8')
];
} elseif ($key == 'charset') {
} elseif ($key === 'charset') {
$this->metadata[$key] = ['charset' => htmlspecialchars($value, ENT_QUOTES, 'UTF-8')];
} else {
// if it's a social metadata with separator, render as property
@@ -1552,12 +1553,12 @@ class Page
*/
public function slug($var = null)
{
if ($var !== null && $var !== "") {
if ($var !== null && $var !== '') {
$this->slug = $var;
}
if (empty($this->slug)) {
$this->slug = strtolower(preg_replace(PAGE_ORDER_PREFIX_REGEX, '', $this->folder));
$this->slug = $this->adjustRouteCase(preg_replace(PAGE_ORDER_PREFIX_REGEX, '', $this->folder));
}
@@ -1679,7 +1680,7 @@ class Page
$url = rtrim($url, '/');
}
return $url;
return Uri::filterPath($url);
}
/**
@@ -1702,7 +1703,7 @@ class Page
// calculate route based on parent slugs
$parent = $this->parent();
if (isset($parent)) {
if ($this->hide_home_route && $parent->route() == $this->home_route) {
if ($this->hide_home_route && $parent->route() === $this->home_route) {
$baseRoute = '';
} else {
$baseRoute = (string)$parent->route();
@@ -1747,7 +1748,7 @@ class Page
if (empty($this->raw_route)) {
$baseRoute = $this->parent ? (string)$this->parent()->rawRoute() : null;
$slug = preg_replace(PAGE_ORDER_PREFIX_REGEX, '', $this->folder);
$slug = $this->adjustRouteCase(preg_replace(PAGE_ORDER_PREFIX_REGEX, '', $this->folder));
$this->raw_route = isset($baseRoute) ? $baseRoute . '/' . $slug : null;
}
@@ -1770,9 +1771,9 @@ class Page
if (!empty($this->routes) && isset($this->routes['aliases'])) {
return $this->routes['aliases'];
} else {
return [];
}
return [];
}
/**
@@ -2294,11 +2295,11 @@ class Page
*/
public function active()
{
$uri_path = rtrim(Grav::instance()['uri']->path(), '/') ?: '/';
$uri_path = rtrim(urldecode(Grav::instance()['uri']->path()), '/') ?: '/';
$routes = Grav::instance()['pages']->routes();
if (isset($routes[$uri_path])) {
if ($routes[$uri_path] == $this->path()) {
if ($routes[$uri_path] === $this->path()) {
return true;
}
@@ -2317,7 +2318,7 @@ class Page
{
$uri = Grav::instance()['uri'];
$pages = Grav::instance()['pages'];
$uri_path = rtrim($uri->path(), '/');
$uri_path = rtrim(urldecode($uri->path()), '/');
$routes = Grav::instance()['pages']->routes();
if (isset($routes[$uri_path])) {
@@ -2325,7 +2326,7 @@ class Page
$child_page = $pages->dispatch($uri->route())->parent();
if ($child_page) {
while (!$child_page->root()) {
if ($this->path() == $child_page->path()) {
if ($this->path() === $child_page->path()) {
return true;
}
$child_page = $child_page->parent();
@@ -2344,7 +2345,7 @@ class Page
public function home()
{
$home = Grav::instance()['config']->get('system.home.alias');
$is_home = ($this->route() == $home || $this->rawRoute() == $home);
$is_home = ($this->route() === $home || $this->rawRoute() === $home);
return $is_home;
}
@@ -2358,9 +2359,9 @@ class Page
{
if (!$this->parent && !$this->name && !$this->visible) {
return true;
} else {
return false;
}
return false;
}
/**
@@ -2587,7 +2588,7 @@ class Page
}
/**
* @param string $value
* @param string|array $value
*
* @return mixed
* @internal
@@ -2605,7 +2606,7 @@ class Page
$params = (array)current($value);
} else {
$result = [];
foreach ($value as $key => $val) {
foreach ((array)$value as $key => $val) {
if (is_int($key)) {
$result = $result + $this->evaluate($val)->toArray();
} else {
@@ -2711,7 +2712,7 @@ class Page
case 'root@':
case '@root':
if (!empty($parts) && $parts[0] == 'descendants') {
if (!empty($parts) && $parts[0] === 'descendants') {
$results = $pages->all($pages->root())->nonModular()->published();
} else {
$results = $pages->root()->children()->nonModular()->published();
@@ -2824,11 +2825,11 @@ class Page
// Reorder all moved pages.
foreach ($siblings as $slug => $page) {
$order = intval(trim($page->order(), '.'));
$order = (int)trim($page->order(), '.');
$counter++;
if ($order) {
if ($page->path() == $this->path() && $this->folderExists()) {
if ($page->path() === $this->path() && $this->folderExists()) {
// Handle current page; we do want to change ordering number, but nothing else.
$this->order($counter);
$this->save(false);
@@ -2859,14 +2860,14 @@ class Page
}
if (is_dir($this->_original->path())) {
if ($this->_action == 'move') {
if ($this->_action === 'move') {
Folder::move($this->_original->path(), $this->path());
} elseif ($this->_action == 'copy') {
} elseif ($this->_action === 'copy') {
Folder::copy($this->_original->path(), $this->path());
}
}
if ($this->name() != $this->_original->name()) {
if ($this->name() !== $this->_original->name()) {
$path = $this->path();
if (is_file($path . '/' . $this->_original->name())) {
rename($path . '/' . $this->_original->name(), $path . '/' . $this->name());
@@ -2889,10 +2890,21 @@ class Page
}
}
// publish if required, if not clear cache right before page is published
if ($this->publishDate() && $this->publishDate() && $this->publishDate() > time()) {
if ($this->publishDate() && $this->publishDate() > time()) {
$this->published(false);
Grav::instance()['cache']->setLifeTime($this->publishDate());
}
}
}
protected function adjustRouteCase($route)
{
$case_insensitive = Grav::instance()['config']->get('system.force_lowercase_urls');
if ($case_insensitive) {
return mb_strtolower($route);
} else {
return $route;
}
}
}

View File

@@ -16,12 +16,13 @@ use Grav\Common\Filesystem\Folder;
use Grav\Common\Grav;
use Grav\Common\Language\Language;
use Grav\Common\Taxonomy;
use Grav\Common\Uri;
use Grav\Common\Utils;
use Grav\Plugin\Admin;
use RocketTheme\Toolbox\Event\Event;
use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
use Whoops\Exception\ErrorException;
use Collator as Collator;
use Collator;
class Pages
{
@@ -152,7 +153,7 @@ class Pages
}
$path_append = rtrim($this->grav['pages']->base(), '/');
if ($language->getDefault() != $lang || $config->get('system.languages.include_default_lang') === true) {
if ($language->getDefault() !== $lang || $config->get('system.languages.include_default_lang') === true) {
$path_append .= $lang ? '/' . $lang : '';
}
@@ -192,7 +193,7 @@ class Pages
return $this->homeUrl($lang, $absolute);
}
return $this->baseUrl($lang, $absolute) . $route;
return $this->baseUrl($lang, $absolute) . Uri::filterPath($route);
}
/**
@@ -264,6 +265,8 @@ class Pages
$this->children[$page->parent()->path()][$page->path()] = ['slug' => $page->slug()];
}
$this->routes[$route] = $page->path();
$this->grav->fireEvent('onPageProcessed', new Event(['page' => $page]));
}
/**
@@ -297,7 +300,7 @@ class Pages
$sort = $this->sort[$path][$order_by];
if ($order_dir != 'asc') {
if ($order_dir !== 'asc') {
$sort = array_reverse($sort);
}
@@ -327,7 +330,7 @@ class Pages
$sort = $this->sort[$lookup][$orderBy];
if ($orderDir != 'asc') {
if ($orderDir !== 'asc') {
$sort = array_reverse($sort);
}
@@ -345,10 +348,6 @@ class Pages
*/
public function get($path)
{
if (!is_null($path) && !is_string($path)) {
throw new \Exception();
}
return isset($this->instances[(string)$path]) ? $this->instances[(string)$path] : null;
}
@@ -376,13 +375,13 @@ class Pages
*/
public function ancestor($route, $path = null)
{
if (!is_null($path)) {
if ($path !== null) {
$page = $this->dispatch($route, true);
if ($page->path() == $path) {
if ($page && $page->path() === $path) {
return $page;
} elseif (!$page->parent()->root()) {
}
if ($page && !$page->parent()->root()) {
return $this->ancestor($page->parent()->route(), $path);
}
}
@@ -400,15 +399,14 @@ class Pages
*/
public function inherited($route, $field = null)
{
if (!is_null($field)) {
if ($field !== null) {
$page = $this->dispatch($route, true);
$ancestorField = $page->parent()->value('header.' . $field);
if ($ancestorField !== null) {
if ($page && $page->parent()->value('header.' . $field) !== null) {
return $page->parent();
} elseif (!$page->parent()->root()) {
}
if ($page && !$page->parent()->root()) {
return $this->inherited($page->parent()->route(), $field);
}
}
@@ -441,6 +439,8 @@ class Pages
*/
public function dispatch($route, $all = false, $redirect = true)
{
$route = urldecode($route);
// Fetch page if there's a defined route to it.
$page = isset($this->routes[$route]) ? $this->get($this->routes[$route]) : null;
// Try without trailing slash
@@ -499,7 +499,7 @@ class Pages
$pattern = '#^' . str_replace('/', '\/', ltrim($pattern, '^')) . '#';
try {
$found = preg_replace($pattern, $replace, $source_url);
if ($found != $source_url) {
if ($found !== $source_url) {
$page = $this->dispatch($found, $all);
}
} catch (ErrorException $e) {
@@ -535,7 +535,7 @@ class Pages
*/
public function blueprints($type)
{
if (!isset($this->blueprints)) {
if ($this->blueprints === null) {
$this->blueprints = new Blueprints(self::getTypes());
}
@@ -970,7 +970,7 @@ class Pages
* @throws \RuntimeException
* @internal
*/
protected function recurse($directory, Page &$parent = null)
protected function recurse($directory, Page $parent = null)
{
$directory = rtrim($directory, DS);
$page = new Page;
@@ -1023,7 +1023,7 @@ class Pages
if ($found->isDir()) {
continue;
}
$regex = '/^[^\.]*' . preg_quote($extension) . '$/';
$regex = '/^[^\.]*' . preg_quote($extension, '/') . '$/';
if (preg_match($regex, $found->getFilename())) {
$page_found = $found;
$page_extension = $extension;
@@ -1053,10 +1053,8 @@ class Pages
$name = $file->getFilename();
// Ignore all hidden files if set.
if ($this->ignore_hidden) {
if ($name && $name[0] == '.') {
continue;
}
if ($this->ignore_hidden && $name && $name[0] === '.') {
continue;
}
if ($file->isFile()) {
@@ -1096,7 +1094,7 @@ class Pages
}
// Override the modified time if modular
if ($page->template() == 'modular') {
if ($page->template() === 'modular') {
foreach ($page->collection() as $child) {
$modified = $child->modified();
@@ -1174,6 +1172,7 @@ class Pages
* @param array $pages
* @param string $order_by
* @param array $manual
* @param int $sort_flags
*
* @throws \RuntimeException
* @internal
@@ -1224,6 +1223,9 @@ class Pages
case 'basename':
$list[$key] = basename($key);
break;
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]);
@@ -1249,11 +1251,11 @@ class Pages
}
// handle special case when order_by is random
if ($order_by == 'random') {
if ($order_by === 'random') {
$list = $this->arrayShuffle($list);
} else {
// else just sort the list according to specified key
if (extension_loaded('intl')) {
if (extension_loaded('intl') && $this->grav['config']->get('system.intl_enabled')) {
$locale = setlocale(LC_COLLATE, 0); //`setlocale` with a 0 param returns the current locale set
$col = Collator::create($locale);
if ($col) {
@@ -1261,6 +1263,13 @@ class Pages
$list = preg_replace_callback('~([0-9]+)\.~', function($number) {
return sprintf('%032d.', $number[0]);
}, $list);
$list_vals = array_values($list);
if (is_numeric(array_shift($list_vals))) {
$sort_flags = Collator::SORT_REGULAR;
} else {
$sort_flags = Collator::SORT_STRING;
}
}
$col->asort($list, $sort_flags);

View File

@@ -9,6 +9,7 @@
namespace Grav\Common\Processors;
use Grav\Common\Page\Page;
use RocketTheme\Toolbox\Event\Event;
class PagesProcessor extends ProcessorBase implements ProcessorInterface
{
@@ -21,15 +22,15 @@ class PagesProcessor extends ProcessorBase implements ProcessorInterface
$this->container['debugger']->addMessage($this->container['cache']->getCacheStatus());
$this->container['pages']->init();
$this->container->fireEvent('onPagesInitialized');
$this->container->fireEvent('onPageInitialized');
$this->container->fireEvent('onPagesInitialized', new Event(['pages' => $this->container['pages']]));
$this->container->fireEvent('onPageInitialized', new Event(['page' => $this->container['page']]));
/** @var Page $page */
$page = $this->container['page'];
if (!$page->routable()) {
// If no page found, fire event
$event = $this->container->fireEvent('onPageNotFound');
$event = $this->container->fireEvent('onPageNotFound', new Event(['page' => $page]));
if (isset($event->page)) {
unset ($this->container['page']);

View File

@@ -105,4 +105,20 @@ class Session extends BaseSession
return $object;
}
// Store something in cookie temporarily
public function setFlashCookieObject($name, $object, $time = 60)
{
setcookie($name, json_encode($object), time() + $time, '/');
}
// Return object and remove it from the cookie
public function getFlashCookieObject($name)
{
if (isset($_COOKIE[$name])) {
$object = json_decode($_COOKIE[$name]);
setcookie($name, '', time() - 3600, '/');
return $object;
}
}
}

View File

@@ -97,6 +97,9 @@ class Twig
$this->grav->fireEvent('onTwigTemplatePaths');
// Add Grav core templates location
$this->twig_paths = array_merge($this->twig_paths, $locator->findResources('system://templates'));
$this->loader = new \Twig_Loader_Filesystem($this->twig_paths);
$this->grav->fireEvent('onTwigLoader');

View File

@@ -58,8 +58,12 @@ class Uri
protected function createFromEnvironment(array $env)
{
// Build scheme.
$https = isset($env['HTTPS']) ? $env['HTTPS'] : '';
$this->scheme = (empty($https) || strtolower($https) === 'off') ? 'http' : 'https';
if (isset($env['REQUEST_SCHEME'])) {
$this->scheme = $env['REQUEST_SCHEME'];
} else {
$https = isset($env['HTTPS']) ? $env['HTTPS'] : '';
$this->scheme = (empty($https) || strtolower($https) === 'off') ? 'http' : 'https';
}
// Build user and password.
$this->user = isset($env['PHP_AUTH_USER']) ? $env['PHP_AUTH_USER'] : null;
@@ -79,6 +83,9 @@ class Uri
// Build port.
$this->port = isset($env['SERVER_PORT']) ? (int)$env['SERVER_PORT'] : null;
if ($this->hasStandardPort()) {
$this->port = null;
}
// Build path.
$request_uri = isset($env['REQUEST_URI']) ? $env['REQUEST_URI'] : '';
@@ -90,16 +97,35 @@ class Uri
$this->query = parse_url('http://example.com' . $request_uri, PHP_URL_QUERY);
}
// Support ngnix routes.
if (strpos($this->query, '_url=') === 0) {
parse_str($this->query, $query);
unset($query['_url']);
$this->query = http_build_query($query);
}
// Build fragment.
$this->fragment = null;
// Filter path and query string.
// Filter userinfo, path and query string.
$this->user = $this->user !== null ? static::filterUserInfo($this->user) : null;
$this->password = $this->password !== null ? static::filterUserInfo($this->password) : null;
$this->path = empty($this->path) ? '/' : static::filterPath($this->path);
$this->query = static::filterQuery($this->query);
$this->reset();
}
/**
* Does this Uri use a standard port?
*
* @return bool
*/
protected function hasStandardPort()
{
return ($this->scheme === 'http' && $this->port === 80) || ($this->scheme === 'https' && $this->port === 443);
}
/**
* @param string $url
*/
@@ -124,7 +150,9 @@ class Uri
$this->host = $this->validateHostname($this->host) ? $this->host : 'unknown';
}
// Filter path, query string and fragment.
// Filter userinfo, path, query string and fragment.
$this->user = $this->user !== null ? static::filterUserInfo($this->user) : null;
$this->password = $this->password !== null ? static::filterUserInfo($this->password) : null;
$this->path = empty($this->path) ? '/' : static::filterPath($this->path);
$this->query = static::filterQuery($this->query);
$this->fragment = $this->fragment !== null ? static::filterQuery($this->fragment) : null;
@@ -221,7 +249,8 @@ class Uri
*/
private function buildRootPath()
{
$scriptPath = $_SERVER['PHP_SELF'];
// In Windows script path uses backslash, convert it:
$scriptPath = str_replace('\\', '/', $_SERVER['PHP_SELF']);
$rootPath = str_replace(' ', '%20', rtrim(substr($scriptPath, 0, strpos($scriptPath, 'index.php')), '/'));
// check if userdir in the path and workaround PHP bug with PHP_SELF
@@ -257,22 +286,21 @@ class Uri
$this->base .= ':' . (string)$this->port;
}
// Set some defaults
if ($grav['config']->get('system.custom_base_url')) {
$this->root_path = parse_url($grav['config']->get('system.custom_base_url'), PHP_URL_PATH);
$this->root = $grav['config']->get('system.custom_base_url');
// Handle custom base
$custom_base = rtrim($grav['config']->get('system.custom_base_url'), '/');
if ($custom_base) {
$custom_parts = parse_url($custom_base);
$orig_root_path = $this->root_path;
$this->root_path = isset($custom_parts['path']) ? rtrim($custom_parts['path'], '/') : '';
$this->root = isset($custom_parts['scheme']) ? $custom_base : $this->base . $this->root_path;
$this->uri = Utils::replaceFirstOccurrence($orig_root_path, $this->root_path, $this->uri);
} else {
$this->root = $this->base . $this->root_path;
}
$this->url = $this->base . $this->uri;
// if case insensitive urls is enabled, lowercase the url
if( $grav['config']->get('system.case_insensitive_urls') ){
$this->url = strtolower($this->url);
}
// get any params and remove them
$uri = str_replace($this->root, '', $this->url);
// remove the setup.php based base if set:
@@ -282,8 +310,9 @@ class Uri
}
// If configured to, redirect trailing slash URI's with a 302 redirect
if ($uri !== '/' && $config->get('system.pages.redirect_trailing_slash', false) && Utils::endsWith($uri, '/')) {
$grav->redirect(str_replace($this->root, '', rtrim($uri, '/')), 302);
$redirect = str_replace($this->root, '', rtrim($uri, '/'));
if ($redirect && $uri !== '/' && $redirect !== $this->base() && $config->get('system.pages.redirect_trailing_slash', false) && Utils::endsWith($uri, '/')) {
$grav->redirect($redirect, 302);
}
// process params
@@ -1114,11 +1143,20 @@ class Uri
*/
public static function addNonce($url, $action, $nonceParamName = 'nonce')
{
$fake = $url && $url[0] === '/';
if ($fake) {
$url = 'http://domain.com' . $url;
}
$uri = new static($url);
$parts = $uri->toArray();
$nonce = Utils::getNonce($action);
$parts['params'] = (isset($parts['params']) ? $parts['params'] : []) + [$nonceParamName => $nonce];
if ($fake) {
unset($parts['scheme'], $parts['host']);
}
return static::buildUrl($parts);
}
@@ -1153,6 +1191,23 @@ class Uri
return $path;
}
/**
* Filters the user info string.
*
* @param string $info The raw user or password.
* @return string The percent-encoded user or password string.
*/
public static function filterUserInfo($info)
{
return preg_replace_callback(
'/(?:[^a-zA-Z0-9_\-\.~!\$&\'\(\)\*\+,;=]+|%(?![A-Fa-f0-9]{2}))/u',
function ($match) {
return rawurlencode($match[0]);
},
$info
);
}
/**
* Filter Uri path.
*
@@ -1168,7 +1223,7 @@ class Uri
public static function filterPath($path)
{
return preg_replace_callback(
'/(?:[^a-zA-Z0-9_\-\.~:@&=\+\$,\/;%]+|%(?![A-Fa-f0-9]{2}))/',
'/(?:[^a-zA-Z0-9_\-\.~:@&=\+\$,\/;%]+|%(?![A-Fa-f0-9]{2}))/u',
function ($match) {
return rawurlencode($match[0]);
},
@@ -1185,7 +1240,7 @@ class Uri
public static function filterQuery($query)
{
return preg_replace_callback(
'/(?:[^a-zA-Z0-9_\-\.~!\$&\'\(\)\*\+,;=%:@\/\?]+|%(?![A-Fa-f0-9]{2}))/',
'/(?:[^a-zA-Z0-9_\-\.~!\$&\'\(\)\*\+,;=%:@\/\?]+|%(?![A-Fa-f0-9]{2}))/u',
function ($match) {
return rawurlencode($match[0]);
},

View File

@@ -29,7 +29,6 @@ class User extends Data
{
$grav = Grav::instance();
$locator = $grav['locator'];
$config = $grav['config'];
// force lowercase of username
$username = strtolower($username);
@@ -38,7 +37,7 @@ class User extends Data
$blueprint = $blueprints->get('user/account');
$file_path = $locator->findResource('account://' . $username . YAML_EXT);
$file = CompiledYamlFile::instance($file_path);
$content = $file->content();
$content = (array)$file->content();
if (!isset($content['username'])) {
$content['username'] = $username;
}
@@ -48,9 +47,6 @@ class User extends Data
$user = new User($content, $blueprint);
$user->file($file);
// add user to config
$config->set("user", $user);
return $user;
}

View File

@@ -80,7 +80,7 @@ abstract class Utils
}
/**
* Returns the substring of a string up to a specified needle. if not found, return the whole haytack
* Returns the substring of a string up to a specified needle. if not found, return the whole haystack
*
* @param $haystack
* @param $needle
@@ -96,6 +96,46 @@ abstract class Utils
return $haystack;
}
/**
* Utility method to replace only the first occurrence in a string
*
* @param $search
* @param $replace
* @param $subject
* @return mixed
*/
public static function replaceFirstOccurrence($search, $replace, $subject)
{
if (!$search) {
return $subject;
}
$pos = strpos($subject, $search);
if ($pos !== false) {
$subject = substr_replace($subject, $replace, $pos, strlen($search));
}
return $subject;
}
/**
* Utility method to replace only the last occurrence in a string
*
* @param $search
* @param $replace
* @param $subject
* @return mixed
*/
public static function replaceLastOccurrence($search, $replace, $subject)
{
$pos = strrpos($subject, $search);
if($pos !== false)
{
$subject = substr_replace($subject, $replace, $pos, strlen($search));
}
return $subject;
}
/**
* Merge two objects into one.
*
@@ -852,6 +892,24 @@ abstract class Utils
return strpos($_SERVER["SERVER_SOFTWARE"], 'Apache') !== false;
}
/**
* Sort a multidimensional array by another array of ordered keys
*
* @param array $array
* @param array $orderArray
* @return array
*/
public static function sortArrayByArray(array $array, array $orderArray) {
$ordered = array();
foreach ($orderArray as $key) {
if (array_key_exists($key, $array)) {
$ordered[$key] = $array[$key];
unset($array[$key]);
}
}
return $ordered + $array;
}
/**
* Get's path based on a token
*
@@ -939,4 +997,36 @@ abstract class Utils
return intval($size);
}
}
/**
* Multibyte-safe Parse URL function
*
* @param $url
* @return mixed
*/
public static function multibyteParseUrl($url)
{
$enc_url = preg_replace_callback(
'%[^:/@?&=#]+%usD',
function ($matches)
{
return urlencode($matches[0]);
},
$url
);
$parts = parse_url($enc_url);
if($parts === false)
{
throw new \InvalidArgumentException('Malformed URL: ' . $url);
}
foreach($parts as $name => $value)
{
$parts[$name] = urldecode($value);
}
return $parts;
}
}

View File

@@ -117,7 +117,7 @@ class InstallCommand extends ConsoleCommand
$this->destination = rtrim($this->destination, DS);
$path = $this->destination . DS . $data['path'];
if (!file_exists($path)) {
exec('cd "' . $this->destination . '" && git clone -b ' . $data['branch'] . ' ' . $data['url'] . ' ' . $data['path'], $output, $return);
exec('cd "' . $this->destination . '" && git clone -b ' . $data['branch'] . ' --depth 1 ' . $data['url'] . ' ' . $data['path'], $output, $return);
if (!$return) {
$this->output->writeln('<green>SUCCESS</green> cloned <magenta>' . $data['url'] . '</magenta> -> <cyan>' . $path . '</cyan>');

View File

@@ -182,7 +182,7 @@ class UpdateCommand extends ConsoleCommand
$index = 0;
foreach ($this->data as $packages) {
foreach ($packages as $slug => $package) {
if (count($limit_to) && !array_key_exists($slug, $limit_to)) {
if (count($only_packages) && !array_key_exists($slug, $limit_to)) {
continue;
}
@@ -276,6 +276,7 @@ class UpdateCommand extends ConsoleCommand
$this->output->writeln('');
$this->output->writeln("Packages not found or not requiring updates: <red>" . implode('</red>, <red>',
$ignore) . "</red>");
}
}

View File

@@ -0,0 +1,14 @@
{% set status_mapping = {'info':'green', 'error': 'red', 'warning': 'yellow'} %}
{% if grav.messages.all %}
<div id="messages">
{% for message in grav.messages.fetch %}
{% set scope = message.scope|e %}
{% set color = status_mapping[scope] %}
<div class="notices {{ scope }} {{ color }}"><p>{{ message.message|raw }}</p></div>
{% endfor %}
</div>
{% endif %}

View File

@@ -0,0 +1,3 @@
{% for meta in page.metadata %}
<meta {% if meta.name %}name="{{ meta.name }}" {% endif %}{% if meta.http_equiv %}http-equiv="{{ meta.http_equiv }}" {% endif %}{% if meta.charset %}charset="{{ meta.charset }}" {% endif %}{% if meta.property %}property="{{ meta.property }}" {% endif %}{% if meta.content %}content="{{ meta.content }}" {% endif %}/>
{% endfor %}

View File

@@ -320,4 +320,47 @@ class GpmTest extends \Codeception\TestCase\Test
$this->assertSame(null, $this->gpm->calculateVersionNumberFromDependencyVersion('*'));
$this->assertSame('2.0.2', $this->gpm->calculateVersionNumberFromDependencyVersion('2.0.2'));
}
public function testRemoteRepositoryIsEmptyAfterConstruct()
{
$gpm = new GPM();
$reflection = new \ReflectionClass(get_class($gpm));
$repository = $reflection->getProperty('repository');
$repository->setAccessible(true);
$this->assertSame(null, $repository->getValue($gpm));
}
public function testLocalRepositoryIsNotEmptyAfterConstruct()
{
$gpm = new GPM();
$reflection = new \ReflectionClass(get_class($gpm));
$repository = $reflection->getProperty('installed');
$repository->setAccessible(true);
$this->assertInstanceOf( '\Grav\Common\GPM\Local\Packages', $repository->getValue($gpm));
}
public function testGetRepository()
{
$this->assertInstanceOf('\Grav\Common\GPM\Remote\Packages', $this->gpm->getRepository());
}
public function testLatestVersionOfPackage()
{
$gpm = new GPM();
$this->assertNotNull($gpm->getLatestVersionOfPackage('admin'));
}
public function testReleaseType()
{
$gpm = new GPM();
$this->assertNotNull($gpm->getReleaseType('admin'));
}
public function testGetRepositoryPlugin()
{
$gpm = new GPM();
$this->assertNotNull($gpm->getRepositoryPlugin('admin'));
}
}

View File

@@ -371,6 +371,52 @@ class UriTest extends \Codeception\TestCase\Test
'extension' => null,
'addNonce' => 'http://localhost:8080/a/b/c/d/e/f/a/b/c/d/e/f/a/b/c/d/e/f/nonce:{{nonce}}',
],
'http://localhost/this is the path/my page' => [
'scheme' => 'http://',
'user' => null,
'password' => null,
'host' => 'localhost',
'port' => 80,
'path' => '/this%20is%20the%20path/my%20page',
'query' => '',
'fragment' => null,
'route' => '/this%20is%20the%20path/my%20page',
'paths' => ['this%20is%20the%20path', 'my%20page'],
'params' => null,
'url' => '/this%20is%20the%20path/my%20page',
'environment' => 'localhost',
'basename' => 'my%20page',
'base' => 'http://localhost',
'currentPage' => 1,
'rootUrl' => 'http://localhost',
'extension' => null,
'addNonce' => 'http://localhost/this%20is%20the%20path/my%20page/nonce:{{nonce}}',
'__toString' => 'http://localhost/this%20is%20the%20path/my%20page'
],
'http://localhost/pölöpölö/päläpälä' => [
'scheme' => 'http://',
'user' => null,
'password' => null,
'host' => 'localhost',
'port' => 80,
'path' => '/p%C3%B6l%C3%B6p%C3%B6l%C3%B6/p%C3%A4l%C3%A4p%C3%A4l%C3%A4',
'query' => '',
'fragment' => null,
'route' => '/p%C3%B6l%C3%B6p%C3%B6l%C3%B6/p%C3%A4l%C3%A4p%C3%A4l%C3%A4',
'paths' => ['p%C3%B6l%C3%B6p%C3%B6l%C3%B6', 'p%C3%A4l%C3%A4p%C3%A4l%C3%A4'],
'params' => null,
'url' => '/p%C3%B6l%C3%B6p%C3%B6l%C3%B6/p%C3%A4l%C3%A4p%C3%A4l%C3%A4',
'environment' => 'localhost',
'basename' => 'p%C3%A4l%C3%A4p%C3%A4l%C3%A4',
'base' => 'http://localhost',
'currentPage' => 1,
'rootUrl' => 'http://localhost',
'extension' => null,
'addNonce' => 'http://localhost/p%C3%B6l%C3%B6p%C3%B6l%C3%B6/p%C3%A4l%C3%A4p%C3%A4l%C3%A4/nonce:{{nonce}}',
'__toString' => 'http://localhost/p%C3%B6l%C3%B6p%C3%B6l%C3%B6/p%C3%A4l%C3%A4p%C3%A4l%C3%A4'
],
// Query params tests.
'http://localhost:8080/grav/it/ueper?test=x&test2=y' => [
'scheme' => 'http://',
@@ -550,7 +596,53 @@ class UriTest extends \Codeception\TestCase\Test
'rootUrl' => 'http://localhost',
'extension' => 'json',
'addNonce' => 'http://localhost/a-page.json/nonce:{{nonce}}',
'__toString' => 'http://localhost/a-page', // FIXME <-
'__toString' => 'http://localhost/a-page', // FIX ME <-
],
'http://localhost/admin/ajax.json/task:getnewsfeed' => [
'scheme' => 'http://',
'user' => null,
'password' => null,
'host' => 'localhost',
'port' => 80,
'path' => '/admin/ajax',
'query' => '',
'fragment' => null,
'route' => '/admin/ajax',
'paths' => ['admin', 'ajax'],
'params' => '/task:getnewsfeed',
'url' => '/admin/ajax',
'environment' => 'localhost',
'basename' => 'ajax.json',
'base' => 'http://localhost',
'currentPage' => 1,
'rootUrl' => 'http://localhost',
'extension' => 'json',
'addNonce' => 'http://localhost/admin/ajax.json/task:getnewsfeed/nonce:{{nonce}}',
'__toString' => 'http://localhost/admin/ajax/task:getnewsfeed',
],
'http://localhost/grav/admin/media.json/route:L1VzZXJzL3JodWsvd29ya3NwYWNlL2dyYXYtZGVtby1zYW1wbGVyL3VzZXIvYXNzZXRzL3FRMXB4Vk1ERTNJZzh5Ni5qcGc=/task:removeFileFromBlueprint/proute:/blueprint:Y29uZmlnL2RldGFpbHM=/type:config/field:deep.nested.custom_file/path:dXNlci9hc3NldHMvcVExcHhWTURFM0lnOHk2LmpwZw==' => [
'scheme' => 'http://',
'user' => null,
'password' => null,
'host' => 'localhost',
'port' => 80,
'path' => '/grav/admin/media',
'query' => '',
'fragment' => null,
'route' => '/grav/admin/media',
'paths' => ['grav','admin','media'],
'params' => '/route:L1VzZXJzL3JodWsvd29ya3NwYWNlL2dyYXYtZGVtby1zYW1wbGVyL3VzZXIvYXNzZXRzL3FRMXB4Vk1ERTNJZzh5Ni5qcGc=/task:removeFileFromBlueprint/proute:/blueprint:Y29uZmlnL2RldGFpbHM=/type:config/field:deep.nested.custom_file/path:dXNlci9hc3NldHMvcVExcHhWTURFM0lnOHk2LmpwZw==',
'url' => '/grav/admin/media',
'environment' => 'localhost',
'basename' => 'media.json',
'base' => 'http://localhost',
'currentPage' => 1,
'rootUrl' => 'http://localhost',
'extension' => 'json',
'addNonce' => 'http://localhost/grav/admin/media.json/route:L1VzZXJzL3JodWsvd29ya3NwYWNlL2dyYXYtZGVtby1zYW1wbGVyL3VzZXIvYXNzZXRzL3FRMXB4Vk1ERTNJZzh5Ni5qcGc=/task:removeFileFromBlueprint/proute:/blueprint:Y29uZmlnL2RldGFpbHM=/type:config/field:deep.nested.custom_file/path:dXNlci9hc3NldHMvcVExcHhWTURFM0lnOHk2LmpwZw==/nonce:{{nonce}}',
'__toString' => 'http://localhost/grav/admin/media/route:L1VzZXJzL3JodWsvd29ya3NwYWNlL2dyYXYtZGVtby1zYW1wbGVyL3VzZXIvYXNzZXRzL3FRMXB4Vk1ERTNJZzh5Ni5qcGc=/task:removeFileFromBlueprint/proute:/blueprint:Y29uZmlnL2RldGFpbHM=/type:config/field:deep.nested.custom_file/path:dXNlci9hc3NldHMvcVExcHhWTURFM0lnOHk2LmpwZw==', // FIXME <-
],
'http://localhost/a-page.foo' => [
'scheme' => 'http://',
@@ -573,6 +665,7 @@ class UriTest extends \Codeception\TestCase\Test
'rootUrl' => 'http://localhost',
'extension' => 'foo',
'addNonce' => 'http://localhost/a-page.foo/nonce:{{nonce}}',
'__toString' => 'http://localhost/a-page.foo'
],
// Fragment tests.
'http://localhost:8080/a/b/c#my-fragment' => [

View File

@@ -12,7 +12,7 @@ server {
# `location /subfolder {`
# and the rewrite to use `/subfolder/index.php`
location / {
try_files $uri $uri/ /index.php?_url=$uri&$query_string;
try_files $uri $uri/ /index.php?$query_string;
}
## End - Index