Upgrade to 3.4.1

This commit is contained in:
Bastian Allgeier
2020-08-04 15:56:15 +02:00
parent f2f3bb96c0
commit 68078dd107
33 changed files with 328 additions and 318 deletions

View File

@@ -75,14 +75,6 @@ class App
protected $users;
protected $visitor;
/**
* List of options that shouldn't be converted
* to a tree structure by dot syntax
*
* @var array
*/
public static $nestIgnoreOptions = ['hooks'];
/**
* Creates a new App instance
*
@@ -127,13 +119,8 @@ class App
$this->extensionsFromSystem();
$this->extensionsFromProps($props);
$this->extensionsFromPlugins();
$this->extensionsFromFolders();
// bake the options for the first time
$this->bakeOptions();
// register the extensions from the normalized options
$this->extensionsFromOptions();
$this->extensionsFromFolders();
// trigger hook for use in plugins
$this->trigger('system.loadPlugins:after');
@@ -141,7 +128,7 @@ class App
// execute a ready callback from the config
$this->optionsFromReadyCallback();
// bake the options again with those from the ready callback
// bake config
$this->bakeOptions();
}
@@ -238,7 +225,30 @@ class App
*/
protected function bakeOptions()
{
$this->options = A::nest($this->options, static::$nestIgnoreOptions);
// convert the old plugin option syntax to the new one
foreach ($this->options as $key => $value) {
// detect option keys with the `vendor.plugin.option` format
if (preg_match('/^([a-z0-9-]+\.[a-z0-9-]+)\.(.*)$/i', $key, $matches) === 1) {
list(, $plugin, $option) = $matches;
// verify that it's really a plugin option
if (isset(static::$plugins[str_replace('.', '/', $plugin)]) !== true) {
continue;
}
// ensure that the target option array exists
// (which it will if the plugin has any options)
if (isset($this->options[$plugin]) !== true) {
$this->options[$plugin] = []; // @codeCoverageIgnore
}
// move the option to the plugin option array
// don't overwrite nested arrays completely but merge them
$this->options[$plugin] = array_replace_recursive($this->options[$plugin], [$option => $value]);
unset($this->options[$key]);
}
}
Config::$data = $this->options;
return $this;
}

View File

@@ -292,19 +292,9 @@ trait AppPlugins
protected function extendOptions(array $options, Plugin $plugin = null): array
{
if ($plugin !== null) {
$prefixed = [];
foreach ($options as $key => $value) {
$prefixed[$plugin->prefix() . '.' . $key] = $value;
}
$options = $prefixed;
$options = [$plugin->prefix() => $options];
}
// register each option in the nesting blacklist;
// this prevents Kirby from nesting the array keys inside each option
static::$nestIgnoreOptions = array_merge(static::$nestIgnoreOptions, array_keys($options));
return $this->extensions['options'] = $this->options = A::merge($options, $this->options, A::MERGE_REPLACE);
}

View File

@@ -6,6 +6,7 @@ use Kirby\Data\Data;
use Kirby\Exception\InvalidArgumentException;
use Kirby\Exception\NotFoundException;
use Kirby\Exception\PermissionException;
use Kirby\Http\Idn;
use Kirby\Http\Request\Auth\BasicAuth;
use Kirby\Toolkit\F;
use Throwable;
@@ -256,6 +257,9 @@ class Auth
*/
public function validatePassword(string $email, string $password)
{
// ensure that email addresses with IDN domains are in Unicode format
$email = Idn::decodeEmail($email);
// check for blocked ips
if ($this->isBlocked($email) === true) {
if ($this->kirby->option('debug') === true) {

View File

@@ -95,7 +95,7 @@ class LanguageRoutes
}
}
return $kirby->defaultLanguage()->router()->call($path);
return $kirby->language()->router()->call($path);
}
];
}

View File

@@ -329,7 +329,7 @@ trait PageActions
if ($action === 'create') {
$argumentsAfter = ['page' => $result];
} elseif ($action === 'duplicate') {
$argumentsAfter = ['duplicatePage' => $result];
$argumentsAfter = ['duplicatePage' => $result, 'originalPage' => $old];
} elseif ($action === 'delete') {
$argumentsAfter = ['status' => $result, 'page' => $old];
} else {

View File

@@ -5,7 +5,6 @@ namespace Kirby\Cms;
use Exception;
use Kirby\Exception\InvalidArgumentException;
use Kirby\Exception\NotFoundException;
use Kirby\Session\Session;
use Kirby\Toolkit\F;
use Kirby\Toolkit\Str;
@@ -764,7 +763,7 @@ class User extends ModelWithContent
protected function setEmail(string $email = null)
{
if ($email !== null) {
$this->email = strtolower(trim($email));
$this->email = Str::lower(trim($email));
}
return $this;
}
@@ -825,7 +824,7 @@ class User extends ModelWithContent
*/
protected function setRole(string $role = null)
{
$this->role = $role !== null ? strtolower(trim($role)) : null;
$this->role = $role !== null ? Str::lower(trim($role)) : null;
return $this;
}

View File

@@ -6,6 +6,7 @@ use Closure;
use Kirby\Data\Data;
use Kirby\Exception\LogicException;
use Kirby\Exception\PermissionException;
use Kirby\Http\Idn;
use Kirby\Toolkit\Dir;
use Kirby\Toolkit\F;
use Kirby\Toolkit\Str;
@@ -29,7 +30,7 @@ trait UserActions
*/
public function changeEmail(string $email)
{
return $this->commit('changeEmail', ['user' => $this, 'email' => $email], function ($user, $email) {
return $this->commit('changeEmail', ['user' => $this, 'email' => Idn::decodeEmail($email)], function ($user, $email) {
$user = $user->clone([
'email' => $email
]);
@@ -176,6 +177,10 @@ trait UserActions
{
$data = $props;
if (isset($props['email']) === true) {
$data['email'] = Idn::decodeEmail($props['email']);
}
if (isset($props['password']) === true) {
$data['password'] = User::hashPassword($props['password']);
}

View File

@@ -87,7 +87,7 @@ class Users extends Collection
public function findByKey(string $key)
{
if (Str::contains($key, '@') === true) {
return parent::findBy('email', strtolower($key));
return parent::findBy('email', Str::lower($key));
}
return parent::findByKey($key);

View File

@@ -2,6 +2,7 @@
namespace Kirby\Email;
use Closure;
use Exception;
use Kirby\Toolkit\Properties;
use Kirby\Toolkit\V;
@@ -23,6 +24,7 @@ class Email
protected $attachments;
protected $body;
protected $bcc;
protected $beforeSend;
protected $cc;
protected $from;
protected $fromName;
@@ -60,6 +62,11 @@ class Email
return $this->bcc;
}
public function beforeSend(): ?Closure
{
return $this->beforeSend;
}
public function cc(): array
{
return $this->cc;
@@ -159,6 +166,12 @@ class Email
return $this;
}
protected function setBeforeSend(?Closure $beforeSend = null)
{
$this->beforeSend = $beforeSend;
return $this;
}
protected function setCc($cc = null)
{
$this->cc = $this->resolveEmail($cc);

View File

@@ -2,6 +2,7 @@
namespace Kirby\Email;
use Kirby\Exception\InvalidArgumentException;
use PHPMailer\PHPMailer\PHPMailer as Mailer;
/**
@@ -67,6 +68,17 @@ class PHPMailer extends Email
$mailer->Port = $this->transport()['port'] ?? null;
}
// accessible phpMailer instance
$beforeSend = $this->beforeSend();
if (empty($beforeSend) === false && is_a($beforeSend, 'Closure') === true) {
$mailer = $beforeSend->call($this, $mailer) ?? $mailer;
if (is_a($mailer, 'PHPMailer\PHPMailer\PHPMailer') === false) {
throw new InvalidArgumentException('"beforeSend" option return should be instance of PHPMailer\PHPMailer\PHPMailer class');
}
}
if ($debug === true) {
return $this->isSent = true;
}

View File

@@ -284,8 +284,9 @@ class Field extends Component
unset($array['model']);
$array['invalid'] = $this->isInvalid();
$array['errors'] = $this->errors();
$array['invalid'] = $this->isInvalid();
$array['saveable'] = $this->save();
$array['signature'] = md5(json_encode($array));
ksort($array);

View File

@@ -85,13 +85,22 @@ class Form
}
}
public function data($defaults = false): array
public function content(): array
{
return $this->data(false, false);
}
public function data($defaults = false, bool $includeNulls = true): array
{
$data = $this->values;
foreach ($this->fields as $field) {
if ($field->save() === false || $field->unset() === true) {
$data[$field->name()] = null;
if ($includeNulls === true) {
$data[$field->name()] = null;
} else {
unset($data[$field->name()]);
}
} else {
$data[$field->name()] = $field->data($defaults);
}

View File

@@ -2,6 +2,7 @@
namespace Kirby\Http;
use Kirby\Toolkit\Str;
use TrueBV\Punycode;
/**
@@ -24,4 +25,40 @@ class Idn
{
return (new Punycode())->encode($domain);
}
/**
* Decodes a email address to the Unicode format
*
* @param string $email
* @return string
*/
public static function decodeEmail(string $email): string
{
if (Str::contains($email, 'xn--') === true) {
$parts = Str::split($email, '@');
$address = $parts[0];
$domain = Idn::decode($parts[1] ?? '');
$email = $address . '@' . $domain;
}
return $email;
}
/**
* Encodes a email address to the Punycode format
*
* @param string $email
* @return string
*/
public static function encodeEmail(string $email): string
{
if (mb_detect_encoding($email, 'ASCII', true) === false) {
$parts = Str::split($email, '@');
$address = $parts[0];
$domain = Idn::encode($parts[1] ?? '');
$email = $address . '@' . $domain;
}
return $email;
}
}

View File

@@ -177,19 +177,25 @@ class Remote
];
// determine the TLS CA to use
if (is_file($this->options['ca']) === true) {
$this->curlopt[CURLOPT_SSL_VERIFYPEER] = true;
$this->curlopt[CURLOPT_CAINFO] = $this->options['ca'];
} elseif (is_dir($this->options['ca']) === true) {
$this->curlopt[CURLOPT_SSL_VERIFYPEER] = true;
$this->curlopt[CURLOPT_CAPATH] = $this->options['ca'];
} elseif ($this->options['ca'] === self::CA_INTERNAL) {
if ($this->options['ca'] === self::CA_INTERNAL) {
$this->curlopt[CURLOPT_SSL_VERIFYPEER] = true;
$this->curlopt[CURLOPT_CAINFO] = dirname(__DIR__, 2) . '/cacert.pem';
} elseif ($this->options['ca'] === self::CA_SYSTEM) {
$this->curlopt[CURLOPT_SSL_VERIFYPEER] = true;
} elseif ($this->options['ca'] === false) {
$this->curlopt[CURLOPT_SSL_VERIFYPEER] = false;
} elseif (
is_string($this->options['ca']) === true &&
is_file($this->options['ca']) === true
) {
$this->curlopt[CURLOPT_SSL_VERIFYPEER] = true;
$this->curlopt[CURLOPT_CAINFO] = $this->options['ca'];
} elseif (
is_string($this->options['ca']) === true &&
is_dir($this->options['ca']) === true
) {
$this->curlopt[CURLOPT_SSL_VERIFYPEER] = true;
$this->curlopt[CURLOPT_CAPATH] = $this->options['ca'];
} else {
throw new InvalidArgumentException('Invalid "ca" option for the Remote class');
}

View File

@@ -376,7 +376,7 @@ class Request
/**
* Returns the Query object
*
* @return \Kirby\Http\Query
* @return \Kirby\Http\Request\Query
*/
public function query()
{

View File

@@ -55,6 +55,26 @@ class Query
return $this->data;
}
/**
* Returns `true` if the request doesn't contain query variables
*
* @return bool
*/
public function isEmpty(): bool
{
return empty($this->data) === true;
}
/**
* Returns `true` if the request contains query variables
*
* @return bool
*/
public function isNotEmpty(): bool
{
return empty($this->data) === false;
}
/**
* Converts the query data array
* back to a query string

View File

@@ -185,7 +185,7 @@ class Exif
*
* @return bool|null
*/
public function isBW(): bool
public function isBW(): ?bool
{
return ($this->isColor !== null) ? $this->isColor === false : null;
}

View File

@@ -35,6 +35,30 @@ class Html extends Xml
*/
public static $void = '>';
/**
* List of HTML tags that are considered to be self-closing
*
* @var array
*/
public static $voidList = [
'area',
'base',
'br',
'col',
'command',
'embed',
'hr',
'img',
'input',
'keygen',
'link',
'meta',
'param',
'source',
'track',
'wbr'
];
/**
* Generic HTML tag generator
* Can be called like `Html::p('A paragraph', ['class' => 'text'])`
@@ -260,26 +284,7 @@ class Html extends Xml
*/
public static function isVoid(string $tag): bool
{
$void = [
'area',
'base',
'br',
'col',
'command',
'embed',
'hr',
'img',
'input',
'keygen',
'link',
'meta',
'param',
'source',
'track',
'wbr',
];
return in_array(strtolower($tag), $void);
return in_array(strtolower($tag), static::$voidList);
}
/**
@@ -334,8 +339,8 @@ class Html extends Xml
* Builds an HTML tag
*
* @param string $name Tag name
* @param array|string|null $content Scalar value or array with multiple lines of content or `null` to
* generate a self-closing tag; pass an empty string to generate empty content
* @param array|string $content Scalar value or array with multiple lines of content; self-closing
* tags are generated automatically based on the `Html::isVoid()` list
* @param array $attr An associative array with additional attributes for the tag
* @param string|null $indent Indentation string, defaults to two spaces or `null` for output on one line
* @param int $level Indentation level
@@ -343,6 +348,12 @@ class Html extends Xml
*/
public static function tag(string $name, $content = '', array $attr = null, string $indent = null, int $level = 0): string
{
// treat an explicit `null` value as an empty tag
// as void tags are already covered below
if ($content === null) {
$content = '';
}
// force void elements to be self-closing
if (static::isVoid($name) === true) {
$content = null;

View File

@@ -306,10 +306,7 @@ V::$validators = [
'email' => function ($value): bool {
if (filter_var($value, FILTER_VALIDATE_EMAIL) === false) {
try {
$parts = Str::split($value, '@');
$address = $parts[0] ?? null;
$domain = Idn::encode($parts[1] ?? '');
$email = $address . '@' . $domain;
$email = Idn::encodeEmail($value);
} catch (Throwable $e) {
return false;
}