Upgrade to Kirby 3.3.2
This commit is contained in:
@@ -69,6 +69,13 @@ trait AppPlugins
|
||||
'validators' => []
|
||||
];
|
||||
|
||||
/**
|
||||
* Cache for system extensions
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected static $systemExtensions = null;
|
||||
|
||||
/**
|
||||
* Flag when plugins have been loaded
|
||||
* to not load them again
|
||||
@@ -570,37 +577,69 @@ trait AppPlugins
|
||||
*/
|
||||
protected function extensionsFromSystem()
|
||||
{
|
||||
// Form Field Mixins
|
||||
FormField::$mixins['filepicker'] = include static::$root . '/config/fields/mixins/filepicker.php';
|
||||
FormField::$mixins['min'] = include static::$root . '/config/fields/mixins/min.php';
|
||||
FormField::$mixins['options'] = include static::$root . '/config/fields/mixins/options.php';
|
||||
FormField::$mixins['pagepicker'] = include static::$root . '/config/fields/mixins/pagepicker.php';
|
||||
FormField::$mixins['picker'] = include static::$root . '/config/fields/mixins/picker.php';
|
||||
FormField::$mixins['upload'] = include static::$root . '/config/fields/mixins/upload.php';
|
||||
FormField::$mixins['userpicker'] = include static::$root . '/config/fields/mixins/userpicker.php';
|
||||
// load static extensions only once
|
||||
if (static::$systemExtensions === null) {
|
||||
// Form Field Mixins
|
||||
FormField::$mixins['filepicker'] = include static::$root . '/config/fields/mixins/filepicker.php';
|
||||
FormField::$mixins['min'] = include static::$root . '/config/fields/mixins/min.php';
|
||||
FormField::$mixins['options'] = include static::$root . '/config/fields/mixins/options.php';
|
||||
FormField::$mixins['pagepicker'] = include static::$root . '/config/fields/mixins/pagepicker.php';
|
||||
FormField::$mixins['picker'] = include static::$root . '/config/fields/mixins/picker.php';
|
||||
FormField::$mixins['upload'] = include static::$root . '/config/fields/mixins/upload.php';
|
||||
FormField::$mixins['userpicker'] = include static::$root . '/config/fields/mixins/userpicker.php';
|
||||
|
||||
// Tag Aliases
|
||||
KirbyTag::$aliases = [
|
||||
'youtube' => 'video',
|
||||
'vimeo' => 'video'
|
||||
];
|
||||
// Tag Aliases
|
||||
KirbyTag::$aliases = [
|
||||
'youtube' => 'video',
|
||||
'vimeo' => 'video'
|
||||
];
|
||||
|
||||
// Field method aliases
|
||||
Field::$aliases = [
|
||||
'bool' => 'toBool',
|
||||
'esc' => 'escape',
|
||||
'excerpt' => 'toExcerpt',
|
||||
'float' => 'toFloat',
|
||||
'h' => 'html',
|
||||
'int' => 'toInt',
|
||||
'kt' => 'kirbytext',
|
||||
'kti' => 'kirbytextinline',
|
||||
'link' => 'toLink',
|
||||
'md' => 'markdown',
|
||||
'sp' => 'smartypants',
|
||||
'v' => 'isValid',
|
||||
'x' => 'xml'
|
||||
];
|
||||
// Field method aliases
|
||||
Field::$aliases = [
|
||||
'bool' => 'toBool',
|
||||
'esc' => 'escape',
|
||||
'excerpt' => 'toExcerpt',
|
||||
'float' => 'toFloat',
|
||||
'h' => 'html',
|
||||
'int' => 'toInt',
|
||||
'kt' => 'kirbytext',
|
||||
'kti' => 'kirbytextinline',
|
||||
'link' => 'toLink',
|
||||
'md' => 'markdown',
|
||||
'sp' => 'smartypants',
|
||||
'v' => 'isValid',
|
||||
'x' => 'xml'
|
||||
];
|
||||
|
||||
// blueprint presets
|
||||
PageBlueprint::$presets['pages'] = include static::$root . '/config/presets/pages.php';
|
||||
PageBlueprint::$presets['page'] = include static::$root . '/config/presets/page.php';
|
||||
PageBlueprint::$presets['files'] = include static::$root . '/config/presets/files.php';
|
||||
|
||||
// section mixins
|
||||
Section::$mixins['empty'] = include static::$root . '/config/sections/mixins/empty.php';
|
||||
Section::$mixins['headline'] = include static::$root . '/config/sections/mixins/headline.php';
|
||||
Section::$mixins['help'] = include static::$root . '/config/sections/mixins/help.php';
|
||||
Section::$mixins['layout'] = include static::$root . '/config/sections/mixins/layout.php';
|
||||
Section::$mixins['max'] = include static::$root . '/config/sections/mixins/max.php';
|
||||
Section::$mixins['min'] = include static::$root . '/config/sections/mixins/min.php';
|
||||
Section::$mixins['pagination'] = include static::$root . '/config/sections/mixins/pagination.php';
|
||||
Section::$mixins['parent'] = include static::$root . '/config/sections/mixins/parent.php';
|
||||
|
||||
// section types
|
||||
Section::$types['info'] = include static::$root . '/config/sections/info.php';
|
||||
Section::$types['pages'] = include static::$root . '/config/sections/pages.php';
|
||||
Section::$types['files'] = include static::$root . '/config/sections/files.php';
|
||||
Section::$types['fields'] = include static::$root . '/config/sections/fields.php';
|
||||
|
||||
static::$systemExtensions = [
|
||||
'components' => include static::$root . '/config/components.php',
|
||||
'blueprints' => include static::$root . '/config/blueprints.php',
|
||||
'fields' => include static::$root . '/config/fields.php',
|
||||
'fieldMethods' => include static::$root . '/config/methods.php',
|
||||
'tags' => include static::$root . '/config/tags.php'
|
||||
];
|
||||
}
|
||||
|
||||
// default cache types
|
||||
$this->extendCacheTypes([
|
||||
@@ -610,32 +649,11 @@ trait AppPlugins
|
||||
'memory' => 'Kirby\Cache\MemoryCache',
|
||||
]);
|
||||
|
||||
$this->extendComponents(include static::$root . '/config/components.php');
|
||||
$this->extendBlueprints(include static::$root . '/config/blueprints.php');
|
||||
$this->extendFields(include static::$root . '/config/fields.php');
|
||||
$this->extendFieldMethods((include static::$root . '/config/methods.php')($this));
|
||||
$this->extendTags(include static::$root . '/config/tags.php');
|
||||
|
||||
// blueprint presets
|
||||
PageBlueprint::$presets['pages'] = include static::$root . '/config/presets/pages.php';
|
||||
PageBlueprint::$presets['page'] = include static::$root . '/config/presets/page.php';
|
||||
PageBlueprint::$presets['files'] = include static::$root . '/config/presets/files.php';
|
||||
|
||||
// section mixins
|
||||
Section::$mixins['empty'] = include static::$root . '/config/sections/mixins/empty.php';
|
||||
Section::$mixins['headline'] = include static::$root . '/config/sections/mixins/headline.php';
|
||||
Section::$mixins['help'] = include static::$root . '/config/sections/mixins/help.php';
|
||||
Section::$mixins['layout'] = include static::$root . '/config/sections/mixins/layout.php';
|
||||
Section::$mixins['max'] = include static::$root . '/config/sections/mixins/max.php';
|
||||
Section::$mixins['min'] = include static::$root . '/config/sections/mixins/min.php';
|
||||
Section::$mixins['pagination'] = include static::$root . '/config/sections/mixins/pagination.php';
|
||||
Section::$mixins['parent'] = include static::$root . '/config/sections/mixins/parent.php';
|
||||
|
||||
// section types
|
||||
Section::$types['info'] = include static::$root . '/config/sections/info.php';
|
||||
Section::$types['pages'] = include static::$root . '/config/sections/pages.php';
|
||||
Section::$types['files'] = include static::$root . '/config/sections/files.php';
|
||||
Section::$types['fields'] = include static::$root . '/config/sections/fields.php';
|
||||
$this->extendComponents(static::$systemExtensions['components']);
|
||||
$this->extendBlueprints(static::$systemExtensions['blueprints']);
|
||||
$this->extendFields(static::$systemExtensions['fields']);
|
||||
$this->extendFieldMethods((static::$systemExtensions['fieldMethods'])($this));
|
||||
$this->extendTags(static::$systemExtensions['tags']);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -319,6 +319,9 @@ class Auth
|
||||
$log['by-ip'] = $log['by-ip'] ?? [];
|
||||
$log['by-email'] = $log['by-email'] ?? [];
|
||||
|
||||
// remove all elements on the top level with different keys (old structure)
|
||||
$log = array_intersect_key($log, array_flip(['by-ip', 'by-email']));
|
||||
|
||||
// remove entries that are no longer needed
|
||||
$originalLog = $log;
|
||||
$time = time() - $this->kirby->option('auth.timeout', 3600);
|
||||
@@ -328,9 +331,6 @@ class Auth
|
||||
});
|
||||
}
|
||||
|
||||
// remove all elements on the top level with different keys (old structure)
|
||||
$log = array_intersect_key($log, array_flip(['by-ip', 'by-email']));
|
||||
|
||||
// write new log to the file system if it changed
|
||||
if ($read === false || $log !== $originalLog) {
|
||||
if (count($log['by-ip']) === 0 && count($log['by-email']) === 0) {
|
||||
|
@@ -2,10 +2,11 @@
|
||||
|
||||
namespace Kirby\Cms;
|
||||
|
||||
use Kirby\Exception\InvalidArgumentException;
|
||||
use Kirby\Exception\NotFoundException;
|
||||
|
||||
/**
|
||||
* Wrapper around our PHPMailer package, which
|
||||
* Wrapper around our Email package, which
|
||||
* handles all the magic connections between Kirby
|
||||
* and sending emails, like email templates, file
|
||||
* attachments, etc.
|
||||
@@ -18,26 +19,34 @@ use Kirby\Exception\NotFoundException;
|
||||
*/
|
||||
class Email
|
||||
{
|
||||
/**
|
||||
* Options configured through the `email` CMS option
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $options;
|
||||
protected $preset;
|
||||
|
||||
/**
|
||||
* Props for the email object; will be passed to the
|
||||
* Kirby\Email\Email class
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $props;
|
||||
|
||||
protected static $transform = [
|
||||
'from' => 'user',
|
||||
'replyTo' => 'user',
|
||||
'to' => 'user',
|
||||
'cc' => 'user',
|
||||
'bcc' => 'user',
|
||||
'attachments' => 'file'
|
||||
];
|
||||
|
||||
/**
|
||||
* Class constructor
|
||||
*
|
||||
* @param string|array $preset Preset name from the config or a simple props array
|
||||
* @param array $props Props array to override the $preset
|
||||
*/
|
||||
public function __construct($preset = [], array $props = [])
|
||||
{
|
||||
$this->options = App::instance()->option('email');
|
||||
|
||||
// load presets from options
|
||||
$this->preset = $this->preset($preset);
|
||||
$this->props = array_merge($this->preset, $props);
|
||||
// build a prop array based on preset and props
|
||||
$preset = $this->preset($preset);
|
||||
$this->props = array_merge($preset, $props);
|
||||
|
||||
// add transport settings
|
||||
if (isset($this->props['transport']) === false) {
|
||||
@@ -45,27 +54,33 @@ class Email
|
||||
}
|
||||
|
||||
// transform model objects to values
|
||||
foreach (static::$transform as $prop => $model) {
|
||||
$this->transformProp($prop, $model);
|
||||
}
|
||||
$this->transformUserSingle('from', 'fromName');
|
||||
$this->transformUserSingle('replyTo', 'replyToName');
|
||||
$this->transformUserMultiple('to');
|
||||
$this->transformUserMultiple('cc');
|
||||
$this->transformUserMultiple('bcc');
|
||||
$this->transformFile('attachments');
|
||||
|
||||
// load template for body text
|
||||
$this->template();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string|array $preset
|
||||
* Grabs a preset from the options; supports fixed
|
||||
* prop arrays in case a preset is not needed
|
||||
*
|
||||
* @param string|array $preset Preset name or simple prop array
|
||||
* @return array
|
||||
*/
|
||||
protected function preset($preset): array
|
||||
{
|
||||
// only passed props, not preset name
|
||||
if (is_string($preset) !== true) {
|
||||
if (is_array($preset) === true) {
|
||||
return $preset;
|
||||
}
|
||||
|
||||
// preset does not exist
|
||||
if (isset($this->options['presets'][$preset]) === false) {
|
||||
if (isset($this->options['presets'][$preset]) !== true) {
|
||||
throw new NotFoundException([
|
||||
'key' => 'email.preset.notFound',
|
||||
'data' => ['name' => $preset]
|
||||
@@ -75,6 +90,12 @@ class Email
|
||||
return $this->options['presets'][$preset];
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the email template(s) and sets the body props
|
||||
* to the result
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function template(): void
|
||||
{
|
||||
if (isset($this->props['template']) === true) {
|
||||
@@ -105,10 +126,10 @@ class Email
|
||||
}
|
||||
|
||||
/**
|
||||
* Undocumented function
|
||||
* Returns an email template by name and type
|
||||
*
|
||||
* @param string $name
|
||||
* @param string|null $type
|
||||
* @param string $name Template name
|
||||
* @param string|null $type `html` or `text`
|
||||
* @return \Kirby\Cms\Template
|
||||
*/
|
||||
protected function getTemplate(string $name, string $type = null)
|
||||
@@ -116,47 +137,112 @@ class Email
|
||||
return App::instance()->template('emails/' . $name, $type, 'text');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the prop array
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function toArray(): array
|
||||
{
|
||||
return $this->props;
|
||||
}
|
||||
|
||||
protected function transformFile($file)
|
||||
/**
|
||||
* Transforms file object(s) to an array of file roots;
|
||||
* supports simple strings, file objects or collections/arrays of either
|
||||
*
|
||||
* @param string $prop Prop to transform
|
||||
* @return void
|
||||
*/
|
||||
protected function transformFile(string $prop): void
|
||||
{
|
||||
return $this->transformModel($file, 'Kirby\Cms\File', 'root');
|
||||
$this->props[$prop] = $this->transformModel($prop, 'Kirby\Cms\File', 'root');
|
||||
}
|
||||
|
||||
protected function transformModel($value, $class, $content)
|
||||
/**
|
||||
* Transforms Kirby models to a simplified collection
|
||||
*
|
||||
* @param string $prop Prop to transform
|
||||
* @param string $class Fully qualified class name of the supported model
|
||||
* @param string $contentValue Model method that returns the array value
|
||||
* @param string|null $contentKey Optional model method that returns the array key;
|
||||
* returns a simple value-only array if not given
|
||||
* @return array Simple key-value or just value array with the transformed prop data
|
||||
*/
|
||||
protected function transformModel(string $prop, string $class, string $contentValue, string $contentKey = null): array
|
||||
{
|
||||
// value is already a string
|
||||
if (is_string($value) === true) {
|
||||
return $value;
|
||||
$value = $this->props[$prop] ?? [];
|
||||
|
||||
// ensure consistent input by making everything an iterable value
|
||||
if (is_iterable($value) !== true) {
|
||||
$value = [$value];
|
||||
}
|
||||
|
||||
// value is a model object, get value through content method
|
||||
if (is_a($value, $class) === true) {
|
||||
return $value->$content();
|
||||
}
|
||||
|
||||
// value is an array or collection, call transform on each item
|
||||
if (is_array($value) === true || is_a($value, 'Kirby\Cms\Collection') === true) {
|
||||
$models = [];
|
||||
foreach ($value as $model) {
|
||||
$models[] = $this->transformModel($model, $class, $content);
|
||||
$result = [];
|
||||
foreach ($value as $key => $item) {
|
||||
if (is_string($item) === true) {
|
||||
// value is already a string
|
||||
if ($contentKey !== null && is_string($key) === true) {
|
||||
$result[$key] = $item;
|
||||
} else {
|
||||
$result[] = $item;
|
||||
}
|
||||
} elseif (is_a($item, $class) === true) {
|
||||
// value is a model object, get value through content method(s)
|
||||
if ($contentKey !== null) {
|
||||
$result[(string)$item->$contentKey()] = (string)$item->$contentValue();
|
||||
} else {
|
||||
$result[] = (string)$item->$contentValue();
|
||||
}
|
||||
} else {
|
||||
// invalid input
|
||||
throw new InvalidArgumentException('Invalid input for prop "' . $prop . '", expected string or "' . $class . '" object or collection');
|
||||
}
|
||||
return $models;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms an user object to the email address and name;
|
||||
* supports simple strings, user objects or collections/arrays of either
|
||||
* (note: only the first item in a collection/array will be used)
|
||||
*
|
||||
* @param string $addressProp Prop with the email address
|
||||
* @param string $nameProp Prop with the name corresponding to the $addressProp
|
||||
* @return void
|
||||
*/
|
||||
protected function transformUserSingle(string $addressProp, string $nameProp): void
|
||||
{
|
||||
$result = $this->transformModel($addressProp, 'Kirby\Cms\User', 'name', 'email');
|
||||
|
||||
$address = array_keys($result)[0] ?? null;
|
||||
$name = $result[$address] ?? null;
|
||||
|
||||
// if the array is non-associative, the value is the address
|
||||
if (is_int($address) === true) {
|
||||
$address = $name;
|
||||
$name = null;
|
||||
}
|
||||
|
||||
// always use the address as we have transformed that prop above
|
||||
$this->props[$addressProp] = $address;
|
||||
|
||||
// only use the name from the user if no custom name was set
|
||||
if (isset($this->props[$nameProp]) === false || $this->props[$nameProp] === null) {
|
||||
$this->props[$nameProp] = $name;
|
||||
}
|
||||
}
|
||||
|
||||
protected function transformProp(string $prop, string $model): void
|
||||
/**
|
||||
* Transforms user object(s) to the email address(es) and name(s);
|
||||
* supports simple strings, user objects or collections/arrays of either
|
||||
*
|
||||
* @param string $prop Prop to transform
|
||||
* @return void
|
||||
*/
|
||||
protected function transformUserMultiple(string $prop): void
|
||||
{
|
||||
if (isset($this->props[$prop]) === true) {
|
||||
$this->props[$prop] = $this->{'transform' . ucfirst($model)}($this->props[$prop]);
|
||||
}
|
||||
}
|
||||
|
||||
protected function transformUser($user)
|
||||
{
|
||||
return $this->transformModel($user, 'Kirby\Cms\User', 'email');
|
||||
$this->props[$prop] = $this->transformModel($prop, 'Kirby\Cms\User', 'name', 'email');
|
||||
}
|
||||
}
|
||||
|
@@ -15,7 +15,9 @@ use Kirby\Toolkit\Properties;
|
||||
*/
|
||||
class FileVersion
|
||||
{
|
||||
use FileFoundation;
|
||||
use FileFoundation {
|
||||
toArray as parentToArray;
|
||||
}
|
||||
use Properties;
|
||||
|
||||
protected $modifications;
|
||||
@@ -89,7 +91,7 @@ class FileVersion
|
||||
*/
|
||||
public function toArray(): array
|
||||
{
|
||||
$array = array_merge(parent::toArray(), [
|
||||
$array = array_merge($this->parentToArray(), [
|
||||
'modifications' => $this->modifications(),
|
||||
]);
|
||||
|
||||
|
@@ -51,7 +51,13 @@ trait PageActions
|
||||
|
||||
// actually move the page on disk
|
||||
if ($oldPage->exists() === true) {
|
||||
Dir::move($oldPage->root(), $newPage->root());
|
||||
if (Dir::move($oldPage->root(), $newPage->root()) === true) {
|
||||
// Updates the root path of the old page with the root path
|
||||
// of the moved new page to use fly actions on old page in loop
|
||||
$oldPage->setRoot($newPage->root());
|
||||
} else {
|
||||
throw new LogicException('The page directory cannot be moved');
|
||||
}
|
||||
}
|
||||
|
||||
// overwrite the child in the parent page
|
||||
@@ -506,10 +512,14 @@ trait PageActions
|
||||
|
||||
return $num;
|
||||
default:
|
||||
// get instance with default language
|
||||
$app = $this->kirby()->clone();
|
||||
$app->setCurrentLanguage();
|
||||
|
||||
$template = Str::template($mode, [
|
||||
'kirby' => $this->kirby(),
|
||||
'page' => $this,
|
||||
'site' => $this->site(),
|
||||
'kirby' => $app,
|
||||
'page' => $app->page($this->id()),
|
||||
'site' => $app->site(),
|
||||
]);
|
||||
|
||||
return (int)$template;
|
||||
@@ -706,7 +716,7 @@ trait PageActions
|
||||
$sibling->changeNum($index);
|
||||
}
|
||||
|
||||
$parent->children = $siblings->sortBy('num', 'desc');
|
||||
$parent->children = $siblings->sortBy('num', 'asc');
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@@ -272,7 +272,8 @@ class User extends ModelWithContent
|
||||
}
|
||||
|
||||
/**
|
||||
* Hashes user password
|
||||
* Hashes the user's password unless it is `null`,
|
||||
* which will leave it as `null`
|
||||
*
|
||||
* @internal
|
||||
* @param string|null $password
|
||||
@@ -281,11 +282,7 @@ class User extends ModelWithContent
|
||||
public static function hashPassword($password): ?string
|
||||
{
|
||||
if ($password !== null) {
|
||||
$info = password_get_info($password);
|
||||
|
||||
if ($info['algo'] === 0) {
|
||||
$password = password_hash($password, PASSWORD_DEFAULT);
|
||||
}
|
||||
$password = password_hash($password, PASSWORD_DEFAULT);
|
||||
}
|
||||
|
||||
return $password;
|
||||
@@ -773,7 +770,7 @@ class User extends ModelWithContent
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets and hashes a new user password
|
||||
* Sets the user's password hash
|
||||
*
|
||||
* @param string $password
|
||||
* @return self
|
||||
|
@@ -94,7 +94,7 @@ trait UserActions
|
||||
{
|
||||
return $this->commit('changePassword', [$this, $password], function ($user, $password) {
|
||||
$user = $user->clone([
|
||||
'password' => $password = $user->hashPassword($password)
|
||||
'password' => $password = User::hashPassword($password)
|
||||
]);
|
||||
|
||||
$user->writePassword($password);
|
||||
@@ -165,7 +165,7 @@ trait UserActions
|
||||
$data = $props;
|
||||
|
||||
if (isset($props['password']) === true) {
|
||||
$data['password'] = static::hashPassword($props['password']);
|
||||
$data['password'] = User::hashPassword($props['password']);
|
||||
}
|
||||
|
||||
$props['role'] = $props['model'] = strtolower($props['role'] ?? 'default');
|
||||
|
@@ -25,7 +25,9 @@ class Email
|
||||
protected $bcc;
|
||||
protected $cc;
|
||||
protected $from;
|
||||
protected $fromName;
|
||||
protected $replyTo;
|
||||
protected $replyToName;
|
||||
protected $isSent = false;
|
||||
protected $subject;
|
||||
protected $to;
|
||||
@@ -75,6 +77,11 @@ class Email
|
||||
return $this->from;
|
||||
}
|
||||
|
||||
public function fromName(): ?string
|
||||
{
|
||||
return $this->fromName;
|
||||
}
|
||||
|
||||
public function isHtml()
|
||||
{
|
||||
return $this->body()->html() !== null;
|
||||
@@ -90,6 +97,11 @@ class Email
|
||||
return $this->replyTo;
|
||||
}
|
||||
|
||||
public function replyToName(): ?string
|
||||
{
|
||||
return $this->replyToName;
|
||||
}
|
||||
|
||||
protected function resolveEmail($email = null, bool $multiple = true)
|
||||
{
|
||||
if ($email === null) {
|
||||
@@ -97,16 +109,27 @@ class Email
|
||||
}
|
||||
|
||||
if (is_array($email) === false) {
|
||||
$email = [$email];
|
||||
$email = [$email => null];
|
||||
}
|
||||
|
||||
foreach ($email as $address) {
|
||||
$result = [];
|
||||
foreach ($email as $address => $name) {
|
||||
// convert simple email arrays to associative arrays
|
||||
if (is_int($address) === true) {
|
||||
// the value is the address, there is no name
|
||||
$address = $name;
|
||||
$result[$address] = null;
|
||||
} else {
|
||||
$result[$address] = $name;
|
||||
}
|
||||
|
||||
// ensure that the address is valid
|
||||
if (V::email($address) === false) {
|
||||
throw new Exception(sprintf('"%s" is not a valid email address', $address));
|
||||
}
|
||||
}
|
||||
|
||||
return $multiple === true ? $email : $email[0];
|
||||
return $multiple === true ? $result : array_keys($result)[0];
|
||||
}
|
||||
|
||||
public function send(): bool
|
||||
@@ -148,12 +171,24 @@ class Email
|
||||
return $this;
|
||||
}
|
||||
|
||||
protected function setFromName(string $fromName = null)
|
||||
{
|
||||
$this->fromName = $fromName;
|
||||
return $this;
|
||||
}
|
||||
|
||||
protected function setReplyTo(string $replyTo = null)
|
||||
{
|
||||
$this->replyTo = $this->resolveEmail($replyTo, false);
|
||||
return $this;
|
||||
}
|
||||
|
||||
protected function setReplyToName(string $replyToName = null)
|
||||
{
|
||||
$this->replyToName = $replyToName;
|
||||
return $this;
|
||||
}
|
||||
|
||||
protected function setSubject(string $subject)
|
||||
{
|
||||
$this->subject = $subject;
|
||||
|
@@ -21,22 +21,22 @@ class PHPMailer extends Email
|
||||
$mailer = new Mailer(true);
|
||||
|
||||
// set sender's address
|
||||
$mailer->setFrom($this->from());
|
||||
$mailer->setFrom($this->from(), $this->fromName() ?? '');
|
||||
|
||||
// optional reply-to address
|
||||
if ($replyTo = $this->replyTo()) {
|
||||
$mailer->addReplyTo($replyTo);
|
||||
$mailer->addReplyTo($replyTo, $this->replyToName() ?? '');
|
||||
}
|
||||
|
||||
// add (multiple) recepient, CC & BCC addresses
|
||||
foreach ($this->to() as $to) {
|
||||
$mailer->addAddress($to);
|
||||
foreach ($this->to() as $email => $name) {
|
||||
$mailer->addAddress($email, $name ?? '');
|
||||
}
|
||||
foreach ($this->cc() as $cc) {
|
||||
$mailer->addCC($cc);
|
||||
foreach ($this->cc() as $email => $name) {
|
||||
$mailer->addCC($email, $name ?? '');
|
||||
}
|
||||
foreach ($this->bcc() as $bcc) {
|
||||
$mailer->addBCC($bcc);
|
||||
foreach ($this->bcc() as $email => $name) {
|
||||
$mailer->addBCC($email, $name ?? '');
|
||||
}
|
||||
|
||||
$mailer->Subject = $this->subject();
|
||||
|
@@ -22,16 +22,17 @@ class Remote
|
||||
* @var array
|
||||
*/
|
||||
public static $defaults = [
|
||||
'agent' => null,
|
||||
'body' => true,
|
||||
'data' => [],
|
||||
'encoding' => 'utf-8',
|
||||
'file' => null,
|
||||
'headers' => [],
|
||||
'method' => 'GET',
|
||||
'progress' => null,
|
||||
'test' => false,
|
||||
'timeout' => 10,
|
||||
'agent' => null,
|
||||
'basicAuth' => null,
|
||||
'body' => true,
|
||||
'data' => [],
|
||||
'encoding' => 'utf-8',
|
||||
'file' => null,
|
||||
'headers' => [],
|
||||
'method' => 'GET',
|
||||
'progress' => null,
|
||||
'test' => false,
|
||||
'timeout' => 10,
|
||||
];
|
||||
|
||||
/**
|
||||
@@ -170,7 +171,22 @@ class Remote
|
||||
|
||||
// add all headers
|
||||
if (empty($this->options['headers']) === false) {
|
||||
$this->curlopt[CURLOPT_HTTPHEADER] = $this->options['headers'];
|
||||
// convert associative arrays to strings
|
||||
$headers = [];
|
||||
foreach ($this->options['headers'] as $key => $value) {
|
||||
if (is_string($key) === true) {
|
||||
$headers[] = $key . ': ' . $value;
|
||||
} else {
|
||||
$headers[] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
$this->curlopt[CURLOPT_HTTPHEADER] = $headers;
|
||||
}
|
||||
|
||||
// add HTTP Basic authentication
|
||||
if (empty($this->options['basicAuth']) === false) {
|
||||
$this->curlopt[CURLOPT_USERPWD] = $this->options['basicAuth'];
|
||||
}
|
||||
|
||||
// add the user agent
|
||||
|
@@ -72,11 +72,16 @@ class File
|
||||
/**
|
||||
* Returns the file as data uri
|
||||
*
|
||||
* @param bool $base64 Whether the data should be base64 encoded or not
|
||||
* @return string
|
||||
*/
|
||||
public function dataUri(): string
|
||||
public function dataUri(bool $base64 = true): string
|
||||
{
|
||||
return 'data:' . $this->mime() . ';base64,' . $this->base64();
|
||||
if ($base64 === true) {
|
||||
return 'data:' . $this->mime() . ';base64,' . $this->base64();
|
||||
}
|
||||
|
||||
return 'data:' . $this->mime() . ',' . Escape::url($this->read());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -31,7 +31,7 @@ class Mime
|
||||
'avi' => 'video/x-msvideo',
|
||||
'bmp' => 'image/bmp',
|
||||
'css' => 'text/css',
|
||||
'csv' => ['text/x-comma-separated-values', 'text/comma-separated-values', 'application/octet-stream'],
|
||||
'csv' => ['text/csv', 'text/x-comma-separated-values', 'text/comma-separated-values', 'application/octet-stream'],
|
||||
'doc' => 'application/msword',
|
||||
'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
|
||||
'dotx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.template',
|
||||
|
Reference in New Issue
Block a user