chapter hgroup + calming decor

This commit is contained in:
Julie Blanc 2026-04-07 18:09:15 +02:00
parent 0545b131de
commit 94d14d70c1
370 changed files with 9583 additions and 1566 deletions

View file

@ -3,7 +3,7 @@
"description": "The Kirby core",
"license": "proprietary",
"type": "kirby-cms",
"version": "5.2.1",
"version": "5.3.1",
"keywords": [
"kirby",
"cms",
@ -43,7 +43,7 @@
"getkirby/composer-installer": "^1.2.1",
"laminas/laminas-escaper": "2.18.0",
"michelf/php-smartypants": "1.8.1",
"phpmailer/phpmailer": "7.0.1",
"phpmailer/phpmailer": "7.0.2",
"symfony/polyfill-intl-idn": "1.33.0",
"symfony/polyfill-mbstring": "1.33.0",
"symfony/yaml": "7.4.1"

14
kirby/composer.lock generated
View file

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "fe434f2b1c0af831ff7f35c58f3584ea",
"content-hash": "a1686fb2832c359a095c842b56c7b086",
"packages": [
{
"name": "christian-riesen/base32",
@ -491,16 +491,16 @@
},
{
"name": "phpmailer/phpmailer",
"version": "v7.0.1",
"version": "v7.0.2",
"source": {
"type": "git",
"url": "https://github.com/PHPMailer/PHPMailer.git",
"reference": "360ae911ce62e25e11249f6140fa58939f556ebe"
"reference": "ebf1655bd5b99b3f97e1a3ec0a69e5f4cd7ea088"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/360ae911ce62e25e11249f6140fa58939f556ebe",
"reference": "360ae911ce62e25e11249f6140fa58939f556ebe",
"url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/ebf1655bd5b99b3f97e1a3ec0a69e5f4cd7ea088",
"reference": "ebf1655bd5b99b3f97e1a3ec0a69e5f4cd7ea088",
"shasum": ""
},
"require": {
@ -561,7 +561,7 @@
"description": "PHPMailer is a full-featured email creation and transfer class for PHP",
"support": {
"issues": "https://github.com/PHPMailer/PHPMailer/issues",
"source": "https://github.com/PHPMailer/PHPMailer/tree/v7.0.1"
"source": "https://github.com/PHPMailer/PHPMailer/tree/v7.0.2"
},
"funding": [
{
@ -569,7 +569,7 @@
"type": "github"
}
],
"time": "2025-11-25T07:18:09+00:00"
"time": "2026-01-09T18:02:33+00:00"
},
{
"name": "psr/log",

View file

@ -59,7 +59,7 @@ return [
'submit' => fn () => (new UserTotpEnableDialog())->submit()
],
'account.totp.disable' => [
'pattern' => '(account)/totp/disable',
...$dialogs['user.totp.disable'],
'pattern' => '(account)/totp/disable',
],
];

View file

@ -180,44 +180,57 @@ return [
$kirby = App::instance();
$user = Find::user($id);
$fields = [
'currentPassword' => Field::password([
'label' => I18n::translate('user.changePassword.' . ($kirby->user()->is($user) ? 'current' : 'own')),
'autocomplete' => 'current-password',
'help' => I18n::translate('account') . ': ' . App::instance()->user()->email(),
]),
'line' => [
'type' => 'line',
],
'password' => Field::password([
'label' => I18n::translate('user.changePassword.new'),
'autocomplete' => 'new-password',
'help' => I18n::translate('account') . ': ' . $user->email(),
]),
'passwordConfirmation' => Field::password([
'label' => I18n::translate('user.changePassword.new.confirm'),
'autocomplete' => 'new-password'
])
];
// if the currently logged in user tries to change their own password
// and has no password so far, password confirmation can be skipped
if ($user->isLoggedIn() === true && $user->hasPassword() === false) {
unset($fields['currentPassword'], $fields['line']);
}
return [
'component' => 'k-form-dialog',
'props' => [
'fields' => [
'currentPassword' => Field::password([
'label' => I18n::translate('user.changePassword.' . ($kirby->user()->is($user) ? 'current' : 'own')),
'autocomplete' => 'current-password',
'help' => I18n::translate('account') . ': ' . App::instance()->user()->email(),
]),
'line' => [
'type' => 'line',
],
'password' => Field::password([
'label' => I18n::translate('user.changePassword.new'),
'autocomplete' => 'new-password',
'help' => I18n::translate('account') . ': ' . $user->email(),
]),
'passwordConfirmation' => Field::password([
'label' => I18n::translate('user.changePassword.new.confirm'),
'autocomplete' => 'new-password'
])
],
'fields' => $fields,
'submitButton' => I18n::translate('change'),
]
];
},
'submit' => function (string $id) {
$kirby = App::instance();
$request = $kirby->request();
$kirby = App::instance();
$request = $kirby->request();
$user = Find::user($id);
$currentPassword = $request->get('currentPassword');
$password = $request->get('password');
$passwordConfirmation = $request->get('passwordConfirmation');
// if the currently logged in user tries to change their own password
// and has no password so far, password confirmation can be skipped
$canSkipConfirmation = $user->isLoggedIn() === true && $user->hasPassword() === false;
// validate the current password of the acting user
try {
$kirby->user()->validatePassword($currentPassword);
if ($canSkipConfirmation === false) {
$kirby->user()->validatePassword($currentPassword);
}
} catch (Exception) {
// catching and re-throwing exception to avoid automatic
// sign-out of current user from the Panel

View file

@ -80,12 +80,14 @@ return [
$template = $mediaRoot . '/{{ name }}{{ attributes }}.{{ extension }}';
$thumbRoot = (new Filename($file->root(), $template, $options))->toString();
$thumbName = basename($thumbRoot);
$job = $mediaRoot . '/.jobs/' . $thumbName . '.json';
// check if the thumb already exists
if (file_exists($thumbRoot) === false) {
// check if the thumb or job file already exists
if (
file_exists($thumbRoot) === false &&
file_exists($job) === false
) {
// if not, create job file
$job = $mediaRoot . '/.jobs/' . $thumbName . '.json';
try {
Data::write(
$job,

View file

@ -251,6 +251,9 @@ return function (App $app) {
Field $field,
string $separator = 'yaml'
) use ($app): Pages {
// always pass at least two arguments even if the
// data is empty so that `$site->find()` always
// returns a collection, not a single page
return $app->site()->find(
false,
false,
@ -320,6 +323,9 @@ return function (App $app) {
Field $field,
string $separator = 'yaml'
) use ($app): Users {
// always pass at least two arguments even if the
// data is empty so that `$users->find()` always
// returns a collection, not a single user
return $app->users()->find(
false,
false,

View file

@ -298,6 +298,10 @@
"error.validation.uuid": "Please enter a valid UUID",
"error.validation.url": "Моля въведете валиден URL",
"error.version.discard.permission": "You are not allowed to discard this version",
"error.version.publish.permission": "You are not allowed to publish this version",
"error.version.save.permission": "You are not allowed to change this version",
"expand": "Expand",
"expand.all": "Expand all",
@ -631,7 +635,9 @@
"plugin": "Plugin",
"plugins": "Plugins",
"prev": "Previous",
"preview": "Preview",
"preview.browser.scroll": "Sync scroll",
"publish": "Publish",
"published": "Published",
@ -782,6 +788,7 @@
"user.create": "Добавете нов потребител",
"user.delete": "Изтрийте потребителя",
"user.delete.confirm": "Сигурни ли сте, че искате да изтриете <br><strong>{email}</strong>?",
"user.setPassword": "Set password",
"users": "Потребители",

View file

@ -298,6 +298,10 @@
"error.validation.uuid": "Unesite važeći UUID",
"error.validation.url": "Unesi važeći URL",
"error.version.discard.permission": "You are not allowed to discard this version",
"error.version.publish.permission": "You are not allowed to publish this version",
"error.version.save.permission": "You are not allowed to change this version",
"expand": "Proširi",
"expand.all": "Expand all",
@ -631,7 +635,9 @@
"plugin": "Plugin",
"plugins": "Plugini",
"prev": "Previous",
"preview": "Pregled",
"preview.browser.scroll": "Sync scroll",
"publish": "Objavi",
"published": "Javno",
@ -782,6 +788,7 @@
"user.create": "Dodaj novog korisnika",
"user.delete": "Obriši ovog korisnika",
"user.delete.confirm": "Da li stvarno želite obrisati <br><strong>{email}</strong>?",
"user.setPassword": "Set password",
"users": "Korisnici",

View file

@ -298,6 +298,10 @@
"error.validation.uuid": "Please enter a valid UUID",
"error.validation.url": "Si us plau, introduïu una URL vàlida",
"error.version.discard.permission": "You are not allowed to discard this version",
"error.version.publish.permission": "You are not allowed to publish this version",
"error.version.save.permission": "You are not allowed to change this version",
"expand": "Expandir",
"expand.all": "Expand all",
@ -631,7 +635,9 @@
"plugin": "Plugin",
"plugins": "Plugins",
"prev": "Anterior",
"preview": "Preview",
"preview.browser.scroll": "Sync scroll",
"publish": "Publish",
"published": "Publicat",
@ -782,6 +788,7 @@
"user.create": "Afegir un nou usuari",
"user.delete": "Eliminar aquest usuari",
"user.delete.confirm": "Segur que voleu eliminar <br> <strong>{email}</strong>?",
"user.setPassword": "Set password",
"users": "Usuaris",

View file

@ -298,6 +298,10 @@
"error.validation.uuid": "Zadejte platné UUID",
"error.validation.url": "Zadejte prosím platnou adresu URL",
"error.version.discard.permission": "You are not allowed to discard this version",
"error.version.publish.permission": "You are not allowed to publish this version",
"error.version.save.permission": "You are not allowed to change this version",
"expand": "Rozbalit",
"expand.all": "Rozbalit vše",
@ -631,7 +635,9 @@
"plugin": "Doplněk",
"plugins": "Doplňky",
"prev": "Předchozí",
"preview": "Náhled",
"preview.browser.scroll": "Sync scroll",
"publish": "Zveřejnit",
"published": "Zveřejněno",
@ -782,6 +788,7 @@
"user.create": "Přidat nového uživatele",
"user.delete": "Smazat tohoto uživatele",
"user.delete.confirm": "Opravdu chcete smazat tohoto u\u017eivatele?",
"user.setPassword": "Set password",
"users": "Uživatelé",

View file

@ -298,6 +298,10 @@
"error.validation.uuid": "Please enter a valid UUID",
"error.validation.url": "Indtast venligst en gyldig URL",
"error.version.discard.permission": "You are not allowed to discard this version",
"error.version.publish.permission": "You are not allowed to publish this version",
"error.version.save.permission": "You are not allowed to change this version",
"expand": "Fold ud",
"expand.all": "Expand all",
@ -631,7 +635,9 @@
"plugin": "Plugin",
"plugins": "Plugins",
"prev": "Forrige",
"preview": "Forhåndsvisning",
"preview.browser.scroll": "Sync scroll",
"publish": "Publish",
"published": "Udgivede",
@ -782,6 +788,7 @@
"user.create": "Tilføj en ny bruger",
"user.delete": "Slet denne bruger",
"user.delete.confirm": "\u00d8nsker du virkelig at slette denne bruger?",
"user.setPassword": "Set password",
"users": "Brugere",

View file

@ -16,7 +16,7 @@
"changes": "Änderungen",
"confirm": "OK",
"collapse": "Zusammenklappen",
"collapse.all": "Collapse all",
"collapse.all": "Alle zusammenklappen",
"color": "Farbe",
"coordinates": "Koordinaten",
"copy": "Kopieren",
@ -44,8 +44,8 @@
"delete": "L\u00f6schen",
"delete.all": "Alle löschen",
"deselect": "Deselect",
"deselect.all": "Deselect all",
"deselect": "Abwählen",
"deselect.all": "Alles abwählen",
"dialog.fields.empty": "Der Dialog hat keine Felder",
"dialog.files.empty": "Keine verfügbaren Dateien",
@ -298,8 +298,12 @@
"error.validation.uuid": "Bitte gib eine gültige UUID an",
"error.validation.url": "Bitte gib eine gültige URL ein",
"error.version.discard.permission": "Du darfst diese Version nicht verwerfen",
"error.version.publish.permission": "Du darfst diese Version nicht veröffentlichen",
"error.version.save.permission": "Du darfst diese Version nicht ändern",
"expand": "Aufklappen",
"expand.all": "Expand all",
"expand.all": "Alle aufklappen",
"field.invalid": "Das Feld ist ungültig",
"field.required": "Das Feld ist Pflicht",
@ -380,7 +384,7 @@
"field.structure.delete.confirm": "Willst du diesen Eintrag wirklich l\u00f6schen?",
"field.structure.delete.confirm.all": "Möchtest du wirklich alle Einträge löschen?",
"field.structure.delete.confirm.selected": "Do you really want to delete the selected entries?",
"field.structure.delete.confirm.selected": "Willst du die ausgewählten Einträge wirklich löschen?",
"field.structure.empty": "Es bestehen keine Eintr\u00e4ge.",
"field.users.empty": "Keine Accounts ausgewählt",
@ -479,7 +483,7 @@
"license.code": "Code",
"license.code.help": "Du hast deinen Lizenz Code nach dem Kauf per Email bekommen. Bitte kopiere sie aus der Email und füge sie hier ein. ",
"license.code.label": "Bitte gib deinen Lizenzcode ein",
"license.remove.text": "<p>Removing the license will irreversibly delete the license file from this site. You can then activate this site with a different license key or re-register the same license key if the domain remains the same.</p><p>To change the domain associated with the license, please contact the Kirby team. <a href='https://getkirby.com/license'>Read more &rarr;</a></p>",
"license.remove.text": "<p>Durch das Entfernen der Lizenz wird die Lizenzdatei unwiderruflich von dieser Website gelöscht. Du kannst diese Website dann mit einem anderen Lizenzschlüssel aktivieren oder denselben Lizenzschlüssel erneut registrieren, wenn die Domain unverändert bleibt.</p> <p>Um die mit der Lizenz verknüpfte Domain zu ändern, wende dich bitte an das Kirby-Team. <a href='https://getkirby.com/license'>Weiterlesen &rarr;</a></p>",
"license.status.active.info": "Beinhaltet neue Major Versionen bis {date}",
"license.status.active.label": "Gültige Lizenz",
"license.status.demo.info": "Dies ist eine Demo Installation",
@ -631,7 +635,9 @@
"plugin": "Plugin",
"plugins": "Plugins",
"prev": "Vorheriger Eintrag",
"preview": "Vorschau",
"preview.browser.scroll": "Scrollen synchronisieren",
"publish": "Veröffentlichen",
"published": "Veröffentlicht",
@ -667,7 +673,7 @@
"security": "Sicherheit",
"select": "Auswählen",
"select.all": "Select all",
"select.all": "Alles auswählen",
"server": "Server",
"settings": "Einstellungen",
"show": "Anzeigen",
@ -776,12 +782,13 @@
"user.changePassword.current": "Dein aktuelles Passwort",
"user.changePassword.new": "Neues Passwort",
"user.changePassword.new.confirm": "Wiederhole das Passwort …",
"user.changePassword.own": "Your own password",
"user.changePassword.own": "Dein eigenes Passwort",
"user.changeRole": "Rolle ändern",
"user.changeRole.select": "Neue Rolle auswählen",
"user.create": "Neuen Account anlegen",
"user.delete": "Account löschen",
"user.delete.confirm": "Willst du den Account <br><strong>{email}</strong> wirklich löschen?",
"user.setPassword": "Passwort anlegen",
"users": "Accounts",

View file

@ -298,6 +298,10 @@
"error.validation.uuid": "Please enter a valid UUID",
"error.validation.url": "Παρακαλώ εισάγετε μια έγκυρη διεύθυνση URL",
"error.version.discard.permission": "You are not allowed to discard this version",
"error.version.publish.permission": "You are not allowed to publish this version",
"error.version.save.permission": "You are not allowed to change this version",
"expand": "Expand",
"expand.all": "Expand all",
@ -631,7 +635,9 @@
"plugin": "Plugin",
"plugins": "Plugins",
"prev": "Προηγούμενο",
"preview": "Preview",
"preview.browser.scroll": "Sync scroll",
"publish": "Publish",
"published": "Δημοσιευμένο",
@ -782,6 +788,7 @@
"user.create": "Προσθήκη νέου χρήστη",
"user.delete": "Διαγραφή χρήστη",
"user.delete.confirm": "\u0398\u03ad\u03bb\u03b5\u03c4\u03b5 \u03c3\u03af\u03b3\u03bf\u03c5\u03c1\u03b1 \u03bd\u03b1 \u03b4\u03b9\u03b1\u03b3\u03c1\u03ac\u03c8\u03b5\u03c4\u03b5 \u03b1\u03c5\u03c4\u03cc\u03bd \u03c4\u03bf\u03bd \u03c7\u03c1\u03ae\u03c3\u03c4\u03b7;",
"user.setPassword": "Set password",
"users": "Χρήστες",

View file

@ -298,6 +298,10 @@
"error.validation.uuid": "Please enter a valid UUID",
"error.validation.url": "Please enter a valid URL",
"error.version.discard.permission": "You are not allowed to discard this version",
"error.version.publish.permission": "You are not allowed to publish this version",
"error.version.save.permission": "You are not allowed to change this version",
"expand": "Expand",
"expand.all": "Expand all",
@ -631,7 +635,9 @@
"plugin": "Plugin",
"plugins": "Plugins",
"prev": "Previous",
"preview": "Preview",
"preview.browser.scroll": "Sync scroll",
"publish": "Publish",
"published": "Published",
@ -782,6 +788,7 @@
"user.create": "Add a new user",
"user.delete": "Delete this user",
"user.delete.confirm": "Do you really want to delete <br><strong>{email}</strong>?",
"user.setPassword": "Set password",
"users": "Users",

View file

@ -298,6 +298,10 @@
"error.validation.uuid": "Please enter a valid UUID",
"error.validation.url": "Bonvolu entajpi validan URL",
"error.version.discard.permission": "You are not allowed to discard this version",
"error.version.publish.permission": "You are not allowed to publish this version",
"error.version.save.permission": "You are not allowed to change this version",
"expand": "Etendi",
"expand.all": "Expand all",
@ -631,7 +635,9 @@
"plugin": "Plugin",
"plugins": "Kromprogramoj",
"prev": "Antaŭe",
"preview": "Antaŭrigardi",
"preview.browser.scroll": "Sync scroll",
"publish": "Publish",
"published": "Publikigita",
@ -782,6 +788,7 @@
"user.create": "Aldoni novan uzanton",
"user.delete": "Forigi ĉi tiun uzanton",
"user.delete.confirm": "Ĉu vi certe volas forigi <br><strong>{email}</strong>?",
"user.setPassword": "Set password",
"users": "Uzantoj",

View file

@ -298,6 +298,10 @@
"error.validation.uuid": "Please enter a valid UUID",
"error.validation.url": "Por favor ingresa un URL válido",
"error.version.discard.permission": "You are not allowed to discard this version",
"error.version.publish.permission": "You are not allowed to publish this version",
"error.version.save.permission": "You are not allowed to change this version",
"expand": "Expandir",
"expand.all": "Expand all",
@ -631,7 +635,9 @@
"plugin": "Plugin",
"plugins": "Plugins",
"prev": "Anterior",
"preview": "Previsualizar",
"preview.browser.scroll": "Sync scroll",
"publish": "Publish",
"published": "Publicado",
@ -782,6 +788,7 @@
"user.create": "Agregar un nuevo usuario",
"user.delete": "Eliminar este usuario",
"user.delete.confirm": "¿Estás seguro que deseas eliminar <br><strong>{email}</strong>?",
"user.setPassword": "Set password",
"users": "Usuarios",

View file

@ -298,6 +298,10 @@
"error.validation.uuid": "Please enter a valid UUID",
"error.validation.url": "Por favor, introduce un URL válido",
"error.version.discard.permission": "You are not allowed to discard this version",
"error.version.publish.permission": "You are not allowed to publish this version",
"error.version.save.permission": "You are not allowed to change this version",
"expand": "Expandir",
"expand.all": "Expand all",
@ -631,7 +635,9 @@
"plugin": "Plugin",
"plugins": "Plugins",
"prev": "Anterior",
"preview": "Previsualizar",
"preview.browser.scroll": "Sync scroll",
"publish": "Publish",
"published": "Publicadas",
@ -782,6 +788,7 @@
"user.create": "Añadir un nuevo usuario",
"user.delete": "Eliminar este usuario",
"user.delete.confirm": "¿Realmente quieres eliminar <br><strong>{email}</strong>?",
"user.setPassword": "Set password",
"users": "Usuarios",

View file

@ -298,6 +298,10 @@
"error.validation.uuid": "Please enter a valid UUID",
"error.validation.url": "لطفا آدرس URL صحیح وارد کنید",
"error.version.discard.permission": "You are not allowed to discard this version",
"error.version.publish.permission": "You are not allowed to publish this version",
"error.version.save.permission": "You are not allowed to change this version",
"expand": "Expand",
"expand.all": "Expand all",
@ -631,7 +635,9 @@
"plugin": "Plugin",
"plugins": "Plugins",
"prev": "قبلی",
"preview": "Preview",
"preview.browser.scroll": "Sync scroll",
"publish": "Publish",
"published": "منتشر شده",
@ -782,6 +788,7 @@
"user.create": "افزودن کاربر جدید",
"user.delete": "حذف کاربر جاری",
"user.delete.confirm": "آیا واقعا میخواهید<strong> {email}</strong> را حذف کنید؟",
"user.setPassword": "Set password",
"users": "کاربران",

View file

@ -298,6 +298,10 @@
"error.validation.uuid": "Please enter a valid UUID",
"error.validation.url": "Anna kelpaava URL",
"error.version.discard.permission": "You are not allowed to discard this version",
"error.version.publish.permission": "You are not allowed to publish this version",
"error.version.save.permission": "You are not allowed to change this version",
"expand": "Laajenna",
"expand.all": "Expand all",
@ -631,7 +635,9 @@
"plugin": "Liitännäinen",
"plugins": "Liitännäiset",
"prev": "Edellinen",
"preview": "Esikatselu",
"preview.browser.scroll": "Sync scroll",
"publish": "Publish",
"published": "Julkaistut",
@ -782,6 +788,7 @@
"user.create": "Lisää uusi käyttäjä",
"user.delete": "Poista tämä käyttäjä",
"user.delete.confirm": "Haluatko varmsti poistaa käyttäjän <br><strong>{email}</strong>?",
"user.setPassword": "Set password",
"users": "Käyttäjät",

View file

@ -298,6 +298,10 @@
"error.validation.uuid": "Veuillez saisir un UUID valide",
"error.validation.url": "Veuillez saisir une URL valide",
"error.version.discard.permission": "Vous nêtes pas autorisé à supprimer cette version",
"error.version.publish.permission": "Vous nêtes pas autorisé à publier cette version",
"error.version.save.permission": "Vous nêtes pas autorisé à modifier cette version",
"expand": "Déplier",
"expand.all": "Tout déplier",
@ -311,7 +315,7 @@
"field.blocks.delete.confirm.all": "Voulez-vous vraiment supprimer tous les blocs ?",
"field.blocks.delete.confirm.selected": "Voulez-vous vraiment supprimer les blocs sélectionnés ?",
"field.blocks.empty": "Pas encore de blocs",
"field.blocks.fieldsets.empty": "Pas encore densembles de champs",
"field.blocks.fieldsets.empty": "Pas encore densembles de champs",
"field.blocks.fieldsets.label": "Veuillez sélectionner un type de bloc…",
"field.blocks.fieldsets.paste": "Pressez <kbd>{{ shortcut }}</kbd> pour importer des dispositions ou blocs depuis votre presse-papier <small>Seuls ceux autorisés dans le champ actuel seront insérés.</small>",
"field.blocks.gallery.name": "Galerie",
@ -631,7 +635,9 @@
"plugin": "Plugin",
"plugins": "Plugins",
"prev": "Précédent",
"preview": "Prévisualiser",
"preview.browser.scroll": "Synchroniser le défilement",
"publish": "Publier",
"published": "Publié",
@ -782,6 +788,7 @@
"user.create": "Ajouter un nouvel utilisateur",
"user.delete": "Supprimer cet utilisateur",
"user.delete.confirm": "Voulez-vous vraiment supprimer <br><strong>{email}</strong> ?",
"user.setPassword": "Définir un mot de passe",
"users": "Utilisateurs",

View file

@ -298,6 +298,10 @@
"error.validation.uuid": "Please enter a valid UUID",
"error.validation.url": "Kérlek megfelelő URL-t adj meg",
"error.version.discard.permission": "You are not allowed to discard this version",
"error.version.publish.permission": "You are not allowed to publish this version",
"error.version.save.permission": "You are not allowed to change this version",
"expand": "Kinyitás",
"expand.all": "Expand all",
@ -631,7 +635,9 @@
"plugin": "Plugin",
"plugins": "Pluginek",
"prev": "Előző",
"preview": "Előnézet",
"preview.browser.scroll": "Sync scroll",
"publish": "Publish",
"published": "Publikálva",
@ -782,6 +788,7 @@
"user.create": "Új felhasználó hozzáadása",
"user.delete": "Felhasználó törlése",
"user.delete.confirm": "Biztos törlöd ezt a felhasználót: <br><strong>{email}</strong>?",
"user.setPassword": "Set password",
"users": "Felhasználók",

View file

@ -298,6 +298,10 @@
"error.validation.uuid": "Masukkan UUID yang valid",
"error.validation.url": "Masukkan URL yang valid",
"error.version.discard.permission": "You are not allowed to discard this version",
"error.version.publish.permission": "You are not allowed to publish this version",
"error.version.save.permission": "You are not allowed to change this version",
"expand": "Luaskan",
"expand.all": "Expand all",
@ -631,7 +635,9 @@
"plugin": "Plugin",
"plugins": "Plugins",
"prev": "Sebelumnya",
"preview": "Pratinjau",
"preview.browser.scroll": "Sync scroll",
"publish": "Publish",
"published": "Dipublikasikan",
@ -782,6 +788,7 @@
"user.create": "Tambah pengguna baru",
"user.delete": "Hapus pengguna ini",
"user.delete.confirm": "Anda yakin menghapus <br><strong>{email}</strong>?",
"user.setPassword": "Set password",
"users": "Pengguna",

View file

@ -1,5 +1,5 @@
{
"account": "Account",
"account": "Reikningur",
"account.changeName": "Breyta nafninu þínu",
"account.delete": "Eyða notandareikning þínum",
"account.delete.confirm": "Ertu alveg viss um að þú viljir endanlega eyða reikningnum þínum? Þú munt verða útskráð/ur án tafar. Ómögulegt verður að endurheimta reikninginn þinn.",
@ -16,7 +16,7 @@
"changes": "Breytingar",
"confirm": "OK",
"collapse": "Fella",
"collapse.all": "Collapse all",
"collapse.all": "Fella allt",
"color": "Litur",
"coordinates": "Hnit",
"copy": "Afrita",
@ -44,8 +44,8 @@
"delete": "Eyða",
"delete.all": "Eyða hreint öllu",
"deselect": "Deselect",
"deselect.all": "Deselect all",
"deselect": "Afvelja",
"deselect.all": "Afvelja allt",
"dialog.fields.empty": "Þessi valmynd hefur engin svið",
"dialog.files.empty": "Engar skrár til að velja úr",
@ -298,8 +298,12 @@
"error.validation.uuid": "Vinsamlegast gillt UUID (Notandakenni)",
"error.validation.url": "Ákjósanleg vefslóð",
"error.version.discard.permission": "Þú mátt ekki hunsa þessa útgáfu",
"error.version.publish.permission": "Þú mátt ekki gefa út þessa útgáfu",
"error.version.save.permission": "Þú mátt ekki breyta þessari útgáfu",
"expand": "Þenja út",
"expand.all": "Expand all",
"expand.all": "Sýna allt",
"field.invalid": "Þetta svið er bara ógillt sem stendur.",
"field.required": "Þetta svið er nauðsynlegt",
@ -380,7 +384,7 @@
"field.structure.delete.confirm": "Viltu virkilega eyða þessari röð?",
"field.structure.delete.confirm.all": "Ætlar þú virkilega að eyða öllum færslum?",
"field.structure.delete.confirm.selected": "Do you really want to delete the selected entries?",
"field.structure.delete.confirm.selected": "Viltu virkilega eyða völdum færslum?",
"field.structure.empty": "Engar færslur enn",
"field.users.empty": "Engir notendur valdir enn",
@ -479,7 +483,7 @@
"license.code": "Kóðasnið",
"license.code.help": "Þú fékkst leyfiskóðan sendan í tölvupósti eftir að þú borgaðir fyrir leyfið. Vinsamlegast afritaðu hann hingað.",
"license.code.label": "Vinsamlegast settu inn leyfiskóðan",
"license.remove.text": "<p>Removing the license will irreversibly delete the license file from this site. You can then activate this site with a different license key or re-register the same license key if the domain remains the same.</p><p>To change the domain associated with the license, please contact the Kirby team. <a href='https://getkirby.com/license'>Read more &rarr;</a></p>",
"license.remove.text": "<p>Að fjarlægja leyfið mun eyða leyfisskránni varanlega af þessu vefsvæði. Þú getur síðan virkjað vefsvæðið með öðrum leyfislykli eða skráð sama leyfislykil aftur, svo framarlega sem lénið helst óbreytt. </p><p> Til að breyta léninu sem leyfið er tengt við, vinsamlegast hafðu samband við Kirby-teymið.<a href='https://getkirby.com/license'>Lesa nánar &rarr;</a></p>",
"license.status.active.info": "Felur í sér allar útgáfur þar til {date}",
"license.status.active.label": "Gilt skráningarleyfi",
"license.status.demo.info": "Þessi uppsetning er til prófunar.",
@ -631,7 +635,9 @@
"plugin": "Viðbót",
"plugins": "Viðbætur",
"prev": "Fyrri",
"preview": "Forskoða",
"preview.browser.scroll": "Skruna í takt",
"publish": "Útgefa",
"published": "Útgefnar og listaðar",
@ -667,7 +673,7 @@
"security": "Öryggi",
"select": "Velja",
"select.all": "Select all",
"select.all": "Velja allt",
"server": "Vefþjónn",
"settings": "Stillingar",
"show": "Sýna",
@ -776,12 +782,13 @@
"user.changePassword.current": "Þitt núverandi lykilorð",
"user.changePassword.new": "Nýtt lykilorð",
"user.changePassword.new.confirm": "Staðfestu nýtt lykilorð…",
"user.changePassword.own": "Your own password",
"user.changePassword.own": "Þitt eigið lykilorð",
"user.changeRole": "Breyta hlutverki",
"user.changeRole.select": "Veldu nýtt hlutverk",
"user.create": "Bæta við nýjum notenda",
"user.delete": "Farga þessum notenda",
"user.delete.confirm": "Viltu virkilega eyða <br><strong>{email}</strong>?",
"user.setPassword": "Setja lykilorð",
"users": "Notendur",

View file

@ -298,6 +298,10 @@
"error.validation.uuid": "Please enter a valid UUID",
"error.validation.url": "Inserisci un URL valido",
"error.version.discard.permission": "You are not allowed to discard this version",
"error.version.publish.permission": "You are not allowed to publish this version",
"error.version.save.permission": "You are not allowed to change this version",
"expand": "Espandi",
"expand.all": "Expand all",
@ -631,7 +635,9 @@
"plugin": "Plugin",
"plugins": "Plugins",
"prev": "Precedente",
"preview": "Anteprima",
"preview.browser.scroll": "Sync scroll",
"publish": "Pubblica",
"published": "Pubblicato",
@ -782,6 +788,7 @@
"user.create": "Aggiungi nuovo utente",
"user.delete": "Elimina questo utente",
"user.delete.confirm": "Sei sicuro di voler eliminare l'utente <br><strong>{email}</strong>?",
"user.setPassword": "Set password",
"users": "Utenti",

View file

@ -298,6 +298,10 @@
"error.validation.uuid": "올바른 UUID를 입력하세요.",
"error.validation.url": "올바른 URL을 입력하세요.",
"error.version.discard.permission": "You are not allowed to discard this version",
"error.version.publish.permission": "You are not allowed to publish this version",
"error.version.save.permission": "You are not allowed to change this version",
"expand": "열기",
"expand.all": "Expand all",
@ -631,7 +635,9 @@
"plugin": "플러그인",
"plugins": "플러그인",
"prev": "이전",
"preview": "미리 보기",
"preview.browser.scroll": "Sync scroll",
"publish": "발행",
"published": "발행",
@ -782,6 +788,7 @@
"user.create": "사용자 추가",
"user.delete": "사용자 삭제",
"user.delete.confirm": "사용자(<strong>{email}</strong>)를 삭제할까요?",
"user.setPassword": "Set password",
"users": "사용자",

View file

@ -298,6 +298,10 @@
"error.validation.uuid": "Please enter a valid UUID",
"error.validation.url": "Prašome įrašyti teisingą URL",
"error.version.discard.permission": "You are not allowed to discard this version",
"error.version.publish.permission": "You are not allowed to publish this version",
"error.version.save.permission": "You are not allowed to change this version",
"expand": "Išskleisti",
"expand.all": "Expand all",
@ -631,7 +635,9 @@
"plugin": "Įskiepas",
"plugins": "Įskiepai",
"prev": "Ankstesnis",
"preview": "Peržiūra",
"preview.browser.scroll": "Sync scroll",
"publish": "Publish",
"published": "Paskelbti",
@ -782,6 +788,7 @@
"user.create": "Pridėti naują vartotoją",
"user.delete": "Pašalinti šį vartotoją",
"user.delete.confirm": "Ar tikrai norite pašalinti vartotoją <br><strong>{email}</strong>?",
"user.setPassword": "Set password",
"users": "Vartotojai",

View file

@ -298,6 +298,10 @@
"error.validation.uuid": "Please enter a valid UUID",
"error.validation.url": "Vennligst skriv inn en gyldig URL",
"error.version.discard.permission": "You are not allowed to discard this version",
"error.version.publish.permission": "You are not allowed to publish this version",
"error.version.save.permission": "You are not allowed to change this version",
"expand": "Utvid",
"expand.all": "Expand all",
@ -631,7 +635,9 @@
"plugin": "Utvidelse",
"plugins": "Plugins",
"prev": "Forrige",
"preview": "Forhåndsvisning",
"preview.browser.scroll": "Sync scroll",
"publish": "Publish",
"published": "Publisert",
@ -782,6 +788,7 @@
"user.create": "Legg til ny bruker",
"user.delete": "Slett denne brukeren",
"user.delete.confirm": "Vil du virkelig slette denne konten?",
"user.setPassword": "Set password",
"users": "Brukere",

View file

@ -298,6 +298,10 @@
"error.validation.uuid": "Vul een geldige UUID in",
"error.validation.url": "Vul een geldige URL in",
"error.version.discard.permission": "You are not allowed to discard this version",
"error.version.publish.permission": "You are not allowed to publish this version",
"error.version.save.permission": "You are not allowed to change this version",
"expand": "Open",
"expand.all": "Expand all",
@ -631,7 +635,9 @@
"plugin": "Plugin",
"plugins": "Plugins",
"prev": "Vorige",
"preview": "Voorbeeld",
"preview.browser.scroll": "Sync scroll",
"publish": "Publiceren",
"published": "Gepubliceerd",
@ -782,6 +788,7 @@
"user.create": "Voeg een nieuwe gebruiker toe",
"user.delete": "Verwijder deze gebruiker",
"user.delete.confirm": "Weet je zeker dat je <br><strong>{email}</strong> wil verwijderen?",
"user.setPassword": "Set password",
"users": "Gebruikers",

View file

@ -298,6 +298,10 @@
"error.validation.uuid": "Wprowadź prawidłowy identyfikator UUID",
"error.validation.url": "Wprowadź poprawny adres URL",
"error.version.discard.permission": "You are not allowed to discard this version",
"error.version.publish.permission": "You are not allowed to publish this version",
"error.version.save.permission": "You are not allowed to change this version",
"expand": "Rozwiń",
"expand.all": "Expand all",
@ -631,7 +635,9 @@
"plugin": "Wtyczka",
"plugins": "Wtyczki",
"prev": "Poprzednie",
"preview": "Podgląd",
"preview.browser.scroll": "Sync scroll",
"publish": "Opublikuj",
"published": "Opublikowane",
@ -782,6 +788,7 @@
"user.create": "Dodaj nowego użytkownika",
"user.delete": "Usuń tego użytkownika",
"user.delete.confirm": "Czy na pewno chcesz usunąć <br><strong>{email}</strong>?",
"user.setPassword": "Set password",
"users": "Użytkownicy",

View file

@ -298,6 +298,10 @@
"error.validation.uuid": "Por favor, insira um UUID válido",
"error.validation.url": "Digite uma URL válida",
"error.version.discard.permission": "You are not allowed to discard this version",
"error.version.publish.permission": "You are not allowed to publish this version",
"error.version.save.permission": "You are not allowed to change this version",
"expand": "Expandir",
"expand.all": "Expandir todos",
@ -631,7 +635,9 @@
"plugin": "Plugin",
"plugins": "Plugins",
"prev": "Anterior",
"preview": "Visualizar",
"preview.browser.scroll": "Sync scroll",
"publish": "Publicar",
"published": "Publicadas",
@ -782,6 +788,7 @@
"user.create": "Adicionar novo usuário",
"user.delete": "Deletar este usuário",
"user.delete.confirm": "Deseja realmente deletar <br><strong>{email}</strong>?",
"user.setPassword": "Set password",
"users": "Usuários",

View file

@ -298,6 +298,10 @@
"error.validation.uuid": "Por favor, insira um UUID válido",
"error.validation.url": "Por favor, insira um URL válido",
"error.version.discard.permission": "You are not allowed to discard this version",
"error.version.publish.permission": "You are not allowed to publish this version",
"error.version.save.permission": "You are not allowed to change this version",
"expand": "Expandir",
"expand.all": "Expandir todos",
@ -631,7 +635,9 @@
"plugin": "Plugin",
"plugins": "Plugins",
"prev": "Anterior",
"preview": "Pré-visualizar",
"preview.browser.scroll": "Sync scroll",
"publish": "Publicar",
"published": "Publicadas",
@ -782,6 +788,7 @@
"user.create": "Adicionar um novo utilizador",
"user.delete": "Eliminar este utilizador",
"user.delete.confirm": "Tem a certeza que pretende eliminar <br><strong>{email}</strong>?",
"user.setPassword": "Set password",
"users": "Utilizadores",

View file

@ -1,5 +1,5 @@
{
"account": "Account",
"account": "Cont",
"account.changeName": "Schimbă-ți numele",
"account.delete": "Șterge-ți contul",
"account.delete.confirm": "Chiar vrei să îți ștergi contul? Vei fi deconectat imediat. Contul nu poate fi recuperat.",
@ -16,7 +16,7 @@
"changes": "Schimbări",
"confirm": "Ok",
"collapse": "Pliază",
"collapse.all": "Collapse all",
"collapse.all": "Închide toate",
"color": "Culoare",
"coordinates": "Coordonate",
"copy": "Copiază",
@ -44,8 +44,8 @@
"delete": "\u0218terge",
"delete.all": "Șterge toate",
"deselect": "Deselect",
"deselect.all": "Deselect all",
"deselect": "Deselectează",
"deselect.all": "Deselectează toate",
"dialog.fields.empty": "Acest dialog nu are niciun câmp",
"dialog.files.empty": "Nu există fișiere de selectat",
@ -298,8 +298,12 @@
"error.validation.uuid": "Te rog introdu un UUID valid",
"error.validation.url": "Te rog introdu un URL valid",
"error.version.discard.permission": "Nu ai voie să înlături această versiune",
"error.version.publish.permission": "Nu ai voie să publici această versiune",
"error.version.save.permission": "Nu ai voie să modifici această versiune",
"expand": "Extinde",
"expand.all": "Expand all",
"expand.all": "Deschide toate",
"field.invalid": "Câmpul este nevalid",
"field.required": "Acest câmp este necesar",
@ -380,7 +384,7 @@
"field.structure.delete.confirm": "Chiar vrei să ștergi acest rând?",
"field.structure.delete.confirm.all": "Chiar vrei să ștergi toate înregistrările?",
"field.structure.delete.confirm.selected": "Do you really want to delete the selected entries?",
"field.structure.delete.confirm.selected": "Chiar vrei să ștergi toate intrările alese?",
"field.structure.empty": "Nicio înregistrare deocamdată",
"field.users.empty": "Niciun utilizator ales deocamdată",
@ -479,7 +483,7 @@
"license.code": "Cod",
"license.code.help": "Ați primit codul de licență după achiziție prin e-mail. Vă rugăm să-l copiați și să-l inserezi aici.",
"license.code.label": "Te rog introdu codul tău de licență",
"license.remove.text": "<p>Removing the license will irreversibly delete the license file from this site. You can then activate this site with a different license key or re-register the same license key if the domain remains the same.</p><p>To change the domain associated with the license, please contact the Kirby team. <a href='https://getkirby.com/license'>Read more &rarr;</a></p>",
"license.remove.text": "<p>Prin înlăturarea licenței se va șterge în mod ireversibil fișierul de licență de pe acest site. Vei putea apoi activa site-ul cu o altă cheie de licență sau să folosești din nou aceeași cheie în caz că domeniul rămâne același.</p><p>Pentru a schimba domeniul asociat licenței, contactează te rog echipa Kirby. <a href='https://getkirby.com/license'>Citește mai multe &rarr;</a></p>",
"license.status.active.info": "Include noi versiuni majore până la data de {date}",
"license.status.active.label": "Licență validă",
"license.status.demo.info": "Aceasta este o instalare demo",
@ -631,7 +635,9 @@
"plugin": "Plugin",
"plugins": "Plugin-uri",
"prev": "Precedenta",
"preview": "Previzualizează",
"preview.browser.scroll": "Sync scroll",
"publish": "Publică",
"published": "Publicate",
@ -667,7 +673,7 @@
"security": "Securitate",
"select": "Alege",
"select.all": "Select all",
"select.all": "Alege toate",
"server": "Server",
"settings": "Reglaje",
"show": "Arată",
@ -776,12 +782,13 @@
"user.changePassword.current": "Parola ta curentă",
"user.changePassword.new": "Parola nouă",
"user.changePassword.new.confirm": "Confirmă parola nouă...",
"user.changePassword.own": "Your own password",
"user.changePassword.own": "Parola proprie",
"user.changeRole": "Schimbă rolul",
"user.changeRole.select": "Alege un rol nou",
"user.create": "Adaugă un nou utilizator",
"user.delete": "Șterge acest utilizator",
"user.delete.confirm": "Chiar vrei să ștergi <br><strong>{email}</strong>?",
"user.setPassword": "Set password",
"users": "Utilizatori",

View file

@ -298,6 +298,10 @@
"error.validation.uuid": "Пожалуйста, введите правильный UUID",
"error.validation.url": "Пожалуйста, введите правильный URL",
"error.version.discard.permission": "You are not allowed to discard this version",
"error.version.publish.permission": "You are not allowed to publish this version",
"error.version.save.permission": "You are not allowed to change this version",
"expand": "Развернуть",
"expand.all": "Expand all",
@ -631,7 +635,9 @@
"plugin": "Расширение",
"plugins": "Плагины",
"prev": "Предыдущий",
"preview": "Предпросмотр",
"preview.browser.scroll": "Sync scroll",
"publish": "Опубликовать",
"published": "Опубликовано",
@ -782,6 +788,7 @@
"user.create": "Добавить нового пользователя",
"user.delete": "Удалить этого пользователя",
"user.delete.confirm": "Вы действительно хотите аккаунт <br><strong>{email}</strong>?",
"user.setPassword": "Set password",
"users": "Пользователи",

View file

@ -298,6 +298,10 @@
"error.validation.uuid": "Please enter a valid UUID",
"error.validation.url": "Prosím, zadajte platnú URL",
"error.version.discard.permission": "You are not allowed to discard this version",
"error.version.publish.permission": "You are not allowed to publish this version",
"error.version.save.permission": "You are not allowed to change this version",
"expand": "Rozbaliť",
"expand.all": "Expand all",
@ -631,7 +635,9 @@
"plugin": "Plugin",
"plugins": "Plugins",
"prev": "Predchádzajúci",
"preview": "Preview",
"preview.browser.scroll": "Sync scroll",
"publish": "Publish",
"published": "Zverejnené",
@ -782,6 +788,7 @@
"user.create": "Pridať nového užívateľa",
"user.delete": "Zmazať tohto užívateľa",
"user.delete.confirm": "Ste si istý, že chcete zmazať <br><strong>{email}</strong>?",
"user.setPassword": "Set password",
"users": "Užívatelia",

View file

@ -298,6 +298,10 @@
"error.validation.uuid": "Molimo vas unesite važeći UUID",
"error.validation.url": "Molimo vas da unesete važeći URL",
"error.version.discard.permission": "You are not allowed to discard this version",
"error.version.publish.permission": "You are not allowed to publish this version",
"error.version.save.permission": "You are not allowed to change this version",
"expand": "Proširite",
"expand.all": "Expand all",
@ -631,7 +635,9 @@
"plugin": "Dodatak",
"plugins": "Dodaci",
"prev": "Prethodna",
"preview": "Pregled",
"preview.browser.scroll": "Sync scroll",
"publish": "Publish",
"published": "Objavljeno",
@ -782,6 +788,7 @@
"user.create": "Dodajte novog korisnika",
"user.delete": "Izbrišite ovog korisnika",
"user.delete.confirm": "Da li zaista želite da izbrišete <br><strong>{email}</strong>?",
"user.setPassword": "Set password",
"users": "Korisnici",

View file

@ -298,6 +298,10 @@
"error.validation.uuid": "Ange ett giltigt UUID",
"error.validation.url": "Ange en giltig URL",
"error.version.discard.permission": "You are not allowed to discard this version",
"error.version.publish.permission": "You are not allowed to publish this version",
"error.version.save.permission": "You are not allowed to change this version",
"expand": "Expandera",
"expand.all": "Expand all",
@ -631,7 +635,9 @@
"plugin": "Tillägg",
"plugins": "Tillägg",
"prev": "Föregående",
"preview": "Förhandsgranska",
"preview.browser.scroll": "Sync scroll",
"publish": "Publicera",
"published": "Publicerade",
@ -782,6 +788,7 @@
"user.create": "Lägg till en ny användare",
"user.delete": "Radera denna användare",
"user.delete.confirm": "Vill du verkligen radera <br><strong>{email}</strong>?",
"user.setPassword": "Set password",
"users": "Användare",

View file

@ -298,6 +298,10 @@
"error.validation.uuid": "Lütfen geçerli bir UUID girin",
"error.validation.url": "Lütfen geçerli bir adres girin",
"error.version.discard.permission": "Bu sürümü silmenize izin verilmiyor.",
"error.version.publish.permission": "Bu sürümü yayınlamanıza izin verilmiyor.",
"error.version.save.permission": "Bu sürümü değiştirmenize izin verilmiyor.",
"expand": "Genişlet",
"expand.all": "Tümünü genişlet",
@ -631,7 +635,9 @@
"plugin": "Eklenti",
"plugins": "Eklentiler",
"prev": "Önceki",
"preview": "Önizle",
"preview.browser.scroll": "Senkronize kaydırma",
"publish": "Yayınla",
"published": "Yayınlandı",
@ -782,6 +788,7 @@
"user.create": "Yeni bir kullanıcı ekle",
"user.delete": "Bu kullanıcıyı sil",
"user.delete.confirm": "<strong>{email}</strong> kullanıcısını silmek istediğinizden emin misiniz?",
"user.setPassword": "Şifre belirle",
"users": "Kullanıcılar",

View file

@ -298,6 +298,10 @@
"error.validation.uuid": "請輸入有效的 UUID",
"error.validation.url": "請輸入有效的網址",
"error.version.discard.permission": "You are not allowed to discard this version",
"error.version.publish.permission": "You are not allowed to publish this version",
"error.version.save.permission": "You are not allowed to change this version",
"expand": "展開",
"expand.all": "Expand all",
@ -631,7 +635,9 @@
"plugin": "外掛",
"plugins": "外掛列表",
"prev": "上一步",
"preview": "預覽",
"preview.browser.scroll": "Sync scroll",
"publish": "發佈",
"published": "已發佈",
@ -782,6 +788,7 @@
"user.create": "新增使用者",
"user.delete": "刪除使用者",
"user.delete.confirm": "你確定要刪除「{email}」嗎?",
"user.setPassword": "Set password",
"users": "使用者",

File diff suppressed because one or more lines are too long

View file

@ -384,12 +384,18 @@
<symbol id="icon-layout-columns" viewBox="0 0 24 24">
<path d="M11 5H5V19H11V5ZM13 5V19H19V5H13ZM4 3H20C20.5523 3 21 3.44772 21 4V20C21 20.5523 20.5523 21 20 21H4C3.44772 21 3 20.5523 3 20V4C3 3.44772 3.44772 3 4 3Z" />
</symbol>
<symbol id="icon-layout-bottom" viewBox="0 0 24 24">
<path d="M21 3C21.5523 3 22 3.44772 22 4V20C22 20.5523 21.5523 21 21 21H3C2.44772 21 2 20.5523 2 20V4C2 3.44772 2.44772 3 3 3H21ZM4 16V19H20V16H4ZM4 14H20V5H4V14Z" />
</symbol>
<symbol id="icon-layout-left" viewBox="0 0 24 24">
<path d="M21 3C21.5523 3 22 3.44772 22 4V20C22 20.5523 21.5523 21 21 21H3C2.44772 21 2 20.5523 2 20V4C2 3.44772 2.44772 3 3 3H21ZM7 5H4V19H7V5ZM20 5H9V19H20V5Z" />
</symbol>
<symbol id="icon-layout-right" viewBox="0 0 24 24">
<path d="M21 3C21.5523 3 22 3.44772 22 4V20C22 20.5523 21.5523 21 21 21H3C2.44772 21 2 20.5523 2 20V4C2 3.44772 2.44772 3 3 3H21ZM15 5H4V19H15V5ZM20 5H17V19H20V5Z" />
</symbol>
<symbol id="icon-layout-top" viewBox="0 0 24 24">
<path d="M21 3C21.5523 3 22 3.44772 22 4V20C22 20.5523 21.5523 21 21 21H3C2.44772 21 2 20.5523 2 20V4C2 3.44772 2.44772 3 3 3H21ZM4 10V19H20V10H4ZM4 8H20V5H4V8Z" />
</symbol>
<symbol id="icon-linkedin" viewBox="0 0 24 24">
<path d="M6.94048 4.99993C6.94011 5.81424 6.44608 6.54702 5.69134 6.85273C4.9366 7.15845 4.07187 6.97605 3.5049 6.39155C2.93793 5.80704 2.78195 4.93715 3.1105 4.19207C3.43906 3.44699 4.18654 2.9755 5.00048 2.99993C6.08155 3.03238 6.94097 3.91837 6.94048 4.99993ZM7.00048 8.47993H3.00048V20.9999H7.00048V8.47993ZM13.3205 8.47993H9.34048V20.9999H13.2805V14.4299C13.2805 10.7699 18.0505 10.4299 18.0505 14.4299V20.9999H22.0005V13.0699C22.0005 6.89993 14.9405 7.12993 13.2805 10.1599L13.3205 8.47993Z"/>
</symbol>
@ -523,6 +529,9 @@
<symbol id="icon-rss" viewBox="0 0 24 24">
<path d="M3 3C12.9411 3 21 11.0589 21 21H18C18 12.7157 11.2843 6 3 6V3ZM3 10C9.07513 10 14 14.9249 14 21H11C11 16.5817 7.41828 13 3 13V10ZM3 17C5.20914 17 7 18.7909 7 21H3V17Z"/>
</symbol>
<symbol id="icon-scroll-to-bottom" viewBox="0 0 24 24">
<path d="M8.01266 4.56502C8.75361 4.16876 9.5587 4 11.1411 4H12.8589C14.4413 4 15.2464 4.16876 15.9873 4.56502C16.6166 4.90155 17.0985 5.38342 17.435 6.01266C17.8312 6.75361 18 7.5587 18 9.14111V14.8589C18 16.4413 17.8312 17.2464 17.435 17.9873C17.0985 18.6166 16.6166 19.0985 15.9873 19.435C15.2464 19.8312 14.4413 20 12.8589 20H11.1411C9.5587 20 8.75361 19.8312 8.01266 19.435C7.38342 19.0985 6.90155 18.6166 6.56502 17.9873C6.16876 17.2464 6 16.4413 6 14.8589V9.14111C6 7.5587 6.16876 6.75361 6.56502 6.01266C6.90155 5.38342 7.38342 4.90155 8.01266 4.56502ZM12.8589 2H11.1411C9.12721 2 8.04724 2.27848 7.06946 2.8014C6.09168 3.32432 5.32432 4.09168 4.8014 5.06946C4.27848 6.04724 4 7.12721 4 9.14111V14.8589C4 16.8728 4.27848 17.9528 4.8014 18.9305C5.32432 19.9083 6.09168 20.6757 7.06946 21.1986C8.04724 21.7215 9.12721 22 11.1411 22H12.8589C14.8728 22 15.9528 21.7215 16.9305 21.1986C17.9083 20.6757 18.6757 19.9083 19.1986 18.9305C19.7215 17.9528 20 16.8728 20 14.8589V9.14111C20 7.12721 19.7215 6.04724 19.1986 5.06946C18.6757 4.09168 17.9083 3.32432 16.9305 2.8014C15.9528 2.27848 14.8728 2 12.8589 2ZM13 6H11V11H13V6ZM7.75781 13.758L12.0005 18.0006L16.2431 13.758L14.8289 12.3438L12.0005 15.1722L9.17203 12.3438L7.75781 13.758Z" />
</symbol>
<symbol id="icon-search" viewBox="0 0 24 24">
<path d="M18.031 16.6168L22.3137 20.8995L20.8995 22.3137L16.6168 18.031C15.0769 19.263 13.124 20 11 20C6.032 20 2 15.968 2 11C2 6.032 6.032 2 11 2C15.968 2 20 6.032 20 11C20 13.124 19.263 15.0769 18.031 16.6168ZM16.0247 15.8748C17.2475 14.6146 18 12.8956 18 11C18 7.1325 14.8675 4 11 4C7.1325 4 4 7.1325 4 11C4 14.8675 7.1325 18 11 18C12.8956 18 14.6146 17.2475 15.8748 16.0247L16.0247 15.8748Z"/>
</symbol>

Before

Width:  |  Height:  |  Size: 110 KiB

After

Width:  |  Height:  |  Size: 112 KiB

Before After
Before After

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -5,6 +5,7 @@ namespace Kirby\Api\Controller;
use Kirby\Cms\Language;
use Kirby\Cms\ModelWithContent;
use Kirby\Content\Lock;
use Kirby\Exception\PermissionException;
use Kirby\Filesystem\F;
use Kirby\Form\Fields;
use Kirby\Form\Form;
@ -40,6 +41,12 @@ class Changes
*/
public static function discard(ModelWithContent $model): array
{
if ($model->permissions()->can('update') === false) {
throw new PermissionException(
key: 'version.discard.permission',
);
}
$model->version('changes')->delete('current');
// Removes the old .lock file when it is no longer needed
@ -56,6 +63,12 @@ class Changes
*/
public static function publish(ModelWithContent $model, array $input): array
{
if ($model->permissions()->can('update') === false) {
throw new PermissionException(
key: 'version.publish.permission',
);
}
// save the given changes first
static::save(
model: $model,
@ -91,6 +104,12 @@ class Changes
*/
public static function save(ModelWithContent $model, array $input): array
{
if ($model->permissions()->can('update') === false) {
throw new PermissionException(
key: 'version.save.permission',
);
}
// Removes the old .lock file when it is no longer needed
// @todo Remove in 6.0.0
static::cleanup($model);

View file

@ -36,6 +36,7 @@ use Kirby\Toolkit\LazyValue;
use Kirby\Toolkit\Locale;
use Kirby\Toolkit\Str;
use Kirby\Uuid\Uuid;
use Kirby\Uuid\Uuids;
use Throwable;
/**
@ -106,6 +107,9 @@ class App
Snippet::$cache = [];
VersionCache::reset();
// reset the UUIDs option cache
Uuids::$enabled = null;
// register all roots to be able to load stuff afterwards
$this->bakeRoots($props['roots'] ?? []);
@ -421,6 +425,7 @@ class App
public function contentToken(object|null $model, string $value): string
{
$default = $this->root('content');
$default = realpath($default) ?: $default;
if ($model !== null && method_exists($model, 'id') === true) {
$default .= '/' . $model->id();
@ -1029,7 +1034,7 @@ class App
// load the main config options
$root = $this->root('config');
$options = F::load($root . '/config.php', [], allowOutput: false);
$options = F::load($root . '/config.php', [], allowOutput: false, cache: true);
// merge into one clean options array
return $this->options = array_replace_recursive(Config::$data, $options);
@ -1044,7 +1049,7 @@ class App
$root = $this->root('config');
// first load `config/env.php` to access its `url` option
$envOptions = F::load($root . '/env.php', [], allowOutput: false);
$envOptions = F::load($root . '/env.php', [], allowOutput: false, cache: true);
// use the option from the main `config.php`,
// but allow the `env.php` to override it

View file

@ -4,7 +4,6 @@ namespace Kirby\Cms;
use Closure;
use Kirby\Exception\Exception;
use Kirby\Filesystem\F;
use Kirby\Http\Response;
use Kirby\Toolkit\I18n;
use Throwable;
@ -38,6 +37,25 @@ trait AppErrors
*/
protected Whoops $whoops;
/**
* Replaces absolute file paths with placeholders such as
* {kirby_folder}, {site_folder} or {index_folder} to avoid
* exposing too many details about the filesystem and keeping
* error responses short and readable in debug mode.
*
* @since 5.3.0
*/
protected function disguiseFilePath(string $file): string
{
$disguise = [
$this->root('kirby') => '{kirby}',
$this->root('site') => '{site}',
$this->root('index') => '{index}'
];
return str_replace(array_keys($disguise), array_values($disguise), $file);
}
/**
* Registers the PHP error handler for CLI usage
*/
@ -150,10 +168,7 @@ trait AppErrors
'code' => $code,
'message' => $exception->getMessage(),
'details' => $details,
'file' => F::relativepath(
$exception->getFile(),
$this->environment()->get('DOCUMENT_ROOT', '')
),
'file' => $this->disguiseFilePath($exception->getFile()),
'line' => $exception->getLine(),
], $httpCode);
} else {

View file

@ -351,6 +351,7 @@ class Auth
/**
* Returns the hashed ip of the visitor
* which is used to track invalid logins
* @deprecated 5.3.0 Use `$visitor->ip(hash: true)` instead. Will be removed in Kirby 6.
*/
public function ipHash(): string
{
@ -365,7 +366,7 @@ class Auth
*/
public function isBlocked(string $email): bool
{
$ip = $this->ipHash();
$ip = $this->kirby->visitor()->ip(hash: true);
$log = $this->log();
$trials = $this->kirby->option('auth.trials', 10);
@ -669,7 +670,7 @@ class Auth
$this->kirby->trigger('user.login:failed', compact('email'));
}
$ip = $this->ipHash();
$ip = $this->kirby->visitor()->ip(hash: true);
$log = $this->log();
$time = time();

View file

@ -124,8 +124,14 @@ class Blueprint
continue;
}
$template = $section->template();
$templates = match ($section->type()) {
'files' => [...$templates, $section->template() ?? 'default'],
'files' => [
...$templates,
...($template
? [$template]
: App::instance()->blueprints('files'))
],
'fields' => [
...$templates,
...$this->acceptedFileTemplatesFromFields($section->fields())

View file

@ -167,7 +167,7 @@ class Collection extends BaseCollection
$groups = new self(parent: $this->parent());
if (is_string($field) === true) {
foreach ($this->data as $key => $item) {
foreach ($this as $key => $item) {
$value = $this->getAttribute($item, $field);
// make sure that there's always a proper value to group by

View file

@ -90,6 +90,8 @@ trait FileActions
$newFile->parent()->files()->remove($oldFile->id());
$newFile->parent()->files()->set($newFile->id(), $newFile);
$newFile->uuid()?->populate();
return $newFile;
});
}
@ -189,6 +191,7 @@ trait FileActions
// overwrite with new UUID (remove old, add new)
if (Uuids::enabled() === true) {
$copy = $copy->save(['uuid' => Uuid::generate()]);
$copy->uuid()->populate();
}
return $copy;
@ -292,6 +295,8 @@ trait FileActions
// store the content if necessary
$file->changeStorage($storage);
$file->uuid()?->populate();
// return a fresh clone
return $file->clone();
});

View file

@ -301,6 +301,14 @@ class Language implements Stringable
return file_exists($this->root());
}
/**
* Check if the language url is custom domain
*/
public function hasCustomDomain(): bool
{
return Url::isAbsolute($this->url);
}
/**
* Checks if the language is the same
* as the given language or language code
@ -547,13 +555,14 @@ class Language implements Stringable
public function toArray(): array
{
return [
'code' => $this->code(),
'default' => $this->isDefault(),
'direction' => $this->direction(),
'locale' => $this->locale(),
'name' => $this->name(),
'rules' => $this->rules(),
'url' => $this->url()
'code' => $this->code(),
'default' => $this->isDefault(),
'direction' => $this->direction(),
'hasCustomDomain' => $this->hasCustomDomain(),
'locale' => $this->locale(),
'name' => $this->name(),
'rules' => $this->rules(),
'url' => $this->url(),
];
}

View file

@ -0,0 +1,551 @@
<?php
namespace Kirby\Cms;
use Closure;
use Iterator;
use Kirby\Exception\LogicException;
/**
* The LazyCollection class is a variant of the CMS
* Collection that is only initialized with keys for
* each collection element or without any data.
* Collection elements and their values (= objects)
* are loaded and initialized lazily when they are
* first used.
*
* You can use LazyCollection in two ways:
* 1. Initialize with keys only (values are `null`),
* define `hydrateElement` method that initializes
* an element dynamically.
* 2. Option 1, but also don't initialize any keys,
* set `$initialized` prop to `false` and define
* `initialize` method that defines which keys
* are available.
*
* @package Kirby Cms
* @author Lukas Bestle <lukas@getkirby.com>
* @link https://getkirby.com
* @copyright Bastian Allgeier
* @license https://getkirby.com/license
*
* @template TValue
* @extends \Kirby\Cms\Collection<TValue>
*/
abstract class LazyCollection extends Collection
{
/**
* Flag that tells whether hydration has been
* completed for all collection elements;
* this is used to increase performance
*/
protected bool $hydrated = false;
/**
* Flag that tells whether all possible collection
* items have been loaded (only relevant in lazy
* initialization mode)
*/
protected bool $initialized = true;
/**
* Temporary auto-hydration whenever a collection
* method is called; some methods may not need raw
* access to all collection data, so performance
* will be improved if methods call initialization
* or hydration themselves only if they need it
* @deprecated
* @todo Remove this in v6
*/
public function __call(string $key, $arguments)
{
$this->hydrate();
return parent::__call($key, $arguments);
}
/**
* Low-level getter for elements
*
* @return TValue|null
*/
public function __get(string $key)
{
$element = parent::__get($key);
// `$element === null` could mean "element does not exist"
// or "element found but not hydrated"
if (
$element === null &&
(array_key_exists($key, $this->data) || $this->initialized === false)
) {
return $this->hydrateElement($key);
}
return $element;
}
/**
* Low-level element remover
*/
public function __unset(string $key)
{
// first initialize, otherwise a later initialization
// might bring back the element that was unset
$this->initialize();
return parent::__unset($key);
}
/**
* Creates chunks of the same size.
* The last chunk may be smaller
*
* @param int $size Number of elements per chunk
* @return static A new collection with an element for each chunk and
* a sub collection in each chunk
*/
public function chunk(int $size): static
{
// chunking at least requires the collection structure
$this->initialize();
return parent::chunk($size);
}
/**
* Counts all elements
*/
public function count(): int
{
$this->initialize();
return parent::count();
}
/**
* Returns the current element
* @deprecated
* @todo Remove in v6
*
* @return TValue
*/
public function current(): mixed
{
$current = parent::current();
// `$current === null` could mean "empty collection"
// or "element found but not hydrated"
if ($current === null && $key = $this->key()) {
return $this->hydrateElement($key);
}
return $current;
}
/**
* Clone and remove all elements from the collection
*/
public function empty(): static
{
$empty = parent::empty();
// prevent new collection from initializing its
// elements into the now empty collection
// (relevant when emptying a collection that
// has not been (fully) initialized yet)
$empty->initialized = true;
return $empty;
}
/**
* Find one or multiple elements by id
*
* @param string ...$keys
* @return TValue|static
*/
public function find(...$keys)
{
$result = parent::find(...$keys);
// when the result is a cloned collection (multiple keys),
// mark it as initialized to prevent it from initializing
// all of its elements again after we filtered it above
// (relevant when finding elements in a collection that
// has not been (fully) initialized yet)
if ($result instanceof static && $result !== $this) {
$result->initialized = true;
}
return $result;
}
/**
* Returns the elements in reverse order
*/
public function flip(): static
{
// flipping at least requires the collection structure
$this->initialize();
return parent::flip();
}
/**
* Filters elements by one of the
* predefined filter methods, by a
* custom filter function or an array of filters
*/
public function filter(string|array|Closure $field, ...$args): static
{
// to filter through values, we need all values present
$this->hydrate();
return parent::filter($field, ...$args);
}
/**
* Returns the first element
*
* @return TValue
*/
public function first()
{
// returning a specific offset requires the collection structure
$this->initialize();
$first = parent::first();
// `$first === null` could mean "empty collection"
// or "element found but not hydrated"
if ($first === null && $key = array_key_first($this->data)) {
return $this->hydrateElement($key);
}
return $first;
}
/**
* Returns an iterator for the elements
* @return \Iterator<TKey, TValue>
*/
public function getIterator(): Iterator
{
// ensure we are looping over all possible elements
$this->initialize();
foreach ($this->data as $key => $value) {
if ($value === null) {
$value = $this->hydrateElement($key);
}
yield $key => $value;
}
}
/**
* Checks by key if an element is included
* @param TKey $key
*/
public function has(mixed $key): bool
{
$this->initialize();
return parent::has($key);
}
/**
* Ensures that all collection elements are loaded,
* essentially converting the lazy collection into a
* normal collection
*/
public function hydrate(): void
{
// first ensure all keys are initialized
$this->initialize();
// skip another hydration loop if no longer needed
if ($this->hydrated === true) {
return;
}
foreach ($this->data as $key => $value) {
if ($value === null) {
$this->hydrateElement($key);
}
}
$this->hydrated = true;
}
/**
* Loads a collection element, sets it in `$this->data[$key]`
* and returns the hydrated object value (or `null` if the
* element does not exist in the collection); to be
* implemented in each specific collection
*/
abstract protected function hydrateElement(string $key): object|null;
/**
* Ensures that the keys for all valid collection elements
* are loaded in the `$data` array and sets `$initialized`
* to `true` afterwards; to be implemented in each collection
* that wants to use lazy initialization; be sure to keep
* existing `$data` values and not overwrite the entire array
*/
public function initialize(): void
{
if ($this->initialized === true) {
return;
}
throw new LogicException(static::class . ' class does not implement `initialize()` method that is required for lazy initialization'); // @codeCoverageIgnore
}
/**
* Returns an array of all keys
*/
public function keys(): array
{
// ensure we are returning all possible keys
$this->initialize();
return parent::keys();
}
/**
* Tries to find the key for the given element
*
* @param TValue $needle the element to search for
* @return int|string|false the name of the key or false
*/
public function keyOf(mixed $needle): int|string|false
{
// quick lookup without having to hydrate the collection
// (keys in CMS collections are the object IDs)
if (
is_object($needle) === true &&
method_exists($needle, 'id') === true
) {
return $needle->id();
}
$this->hydrate();
return parent::keyOf($needle);
}
/**
* Returns the last element
*
* @return TValue
*/
public function last()
{
// returning a specific offset requires the collection structure
$this->initialize();
$last = parent::last();
// `$last === null` could mean "empty collection"
// or "element found but not hydrated"
if ($last === null && $key = array_key_last($this->data)) {
return $this->hydrateElement($key);
}
return $last;
}
/**
* Map a function to each element
*
* @return $this
*/
public function map(callable $callback): static
{
// to map a function, we need all values present
$this->hydrate();
return parent::map($callback);
}
/**
* Moves the cursor to the next element
* and returns it
* @deprecated
* @todo Remove in v6
*
* @return TValue
*/
public function next(): mixed
{
$this->initialize();
$next = parent::next();
// `$next === null` could mean "empty collection"
// or "element found but not hydrated"
if ($next === null && $key = $this->key()) {
return $this->hydrateElement($key);
}
return $next;
}
/**
* Returns the nth element from the collection
*
* @return TValue|null
*/
public function nth(int $n)
{
// returning a specific offset requires the collection structure
$this->initialize();
$nth = parent::nth($n);
// `$nth === null` could mean "empty collection"
// or "element found but not hydrated"
if ($nth === null) {
$key = array_keys($this->data)[$n] ?? null;
if (is_string($key) === true) {
return $this->hydrateElement($key);
}
}
return $nth;
}
/**
* Prepends an element to the data array
*
* ```php
* $collection->prepend('key', $value);
* $collection->prepend($value);
* ```
*
* @param string|TValue ...$args
* @return $this
*/
public function prepend(...$args): static
{
// prepending to an uninitialized collection would
// destroy the order on later initialization
$this->initialize();
return parent::prepend(...$args);
}
/**
* Moves the cursor to the previous element
* and returns it
* @deprecated
* @todo Remove in v6
*
* @return TValue
*/
public function prev(): mixed
{
$this->initialize();
$prev = parent::prev();
// `$prev === null` could mean "empty collection"
// or "element found but not hydrated"
if ($prev === null && $key = $this->key()) {
return $this->hydrateElement($key);
}
return $prev;
}
/**
* Returns a new collection consisting of random elements,
* from the original collection, shuffled or ordered
*/
public function random(int $count = 1, bool $shuffle = false): static
{
// picking random elements at least requires the collection structure
$this->initialize();
return parent::random($count, $shuffle);
}
/**
* Shuffle all elements
*/
public function shuffle(): static
{
// shuffling at least requires the collection structure
$this->initialize();
return parent::shuffle();
}
/**
* Returns a slice of the object
*
* @param int $offset The optional index to start the slice from
* @param int|null $limit The optional number of elements to return
* @return $this|static
* @psalm-return ($offset is 0 && $limit is null ? $this : static)
*/
public function slice(
int $offset = 0,
int|null $limit = null
): static {
// returning a specific subset requires the collection structure
$this->initialize();
return parent::slice($offset, $limit);
}
/**
* Sorts the elements by any number of fields
*
* ```php
* $collection->sort('fieldName');
* $collection->sort('fieldName', 'desc');
* $collection->sort('fieldName', 'asc', SORT_REGULAR);
* $collection->sort(fn ($a) => ...);
* ```
*
* @param string|callable $field Field name or value callback to sort by
* @param string|null $direction asc or desc
* @param int|null $method The sort flag, SORT_REGULAR, SORT_NUMERIC etc.
* @return $this|static
*/
public function sort(...$args): static
{
// to sort through values, we need all values present
$this->hydrate();
return parent::sort(...$args);
}
/**
* Converts all objects in the collection
* to an array. This can also take a callback
* function to further modify the array result.
*/
public function toArray(Closure|null $map = null): array
{
// to export an array, we need all values present
$this->hydrate();
return parent::toArray($map);
}
/**
* Returns a non-associative array
* with all values. If a mapping Closure is passed,
* all values are processed by the Closure.
*/
public function values(Closure|null $map = null): array
{
// to export an array, we need all values present
$this->hydrate();
return parent::values($map);
}
}

View file

@ -7,6 +7,7 @@ use Kirby\Exception\InvalidArgumentException;
use Kirby\Exception\NotFoundException;
use Kirby\Filesystem\Dir;
use Kirby\Filesystem\F;
use Kirby\Http\Response;
use Kirby\Toolkit\Str;
use Throwable;
@ -53,7 +54,7 @@ class Media
}
// send the file to the browser
return Response::file($file->publish()->mediaRoot());
return Response::file($file->publish()->root());
}
// try to generate a thumb for the file

View file

@ -119,7 +119,7 @@ trait PageActions
]);
// clear UUID cache recursively (for children and files as well)
$oldPage->uuid()?->clear(true);
$oldPage->uuid()?->clear(recursive: true);
if ($oldPage->exists() === true) {
// actually move stuff on disk
@ -142,6 +142,8 @@ trait PageActions
Dir::remove($oldPage->mediaRoot());
}
$newPage->uuid()?->populate(recursive: true);
return $newPage;
});
}
@ -422,6 +424,8 @@ trait PageActions
parent: $parentModel
);
$copy->uuid()?->populate(recursive: true);
return $copy;
}
@ -487,6 +491,8 @@ trait PageActions
$page = $page->changeStatus('listed', $props['num']);
}
$page->uuid()?->populate();
return $page;
}
@ -583,7 +589,7 @@ trait PageActions
$page->changeStorage(ImmutableMemoryStorage::class);
// clear UUID cache
$page->uuid()?->clear();
$page->uuid()?->clear(recursive: true);
// Explanation: The two while loops below are only
// necessary because our property caches result in
@ -697,6 +703,8 @@ trait PageActions
);
}
$newPage->uuid()?->populate(recursive: true);
return $newPage;
});
}

View file

@ -5,7 +5,7 @@ namespace Kirby\Cms;
use Kirby\Exception\InvalidArgumentException;
use Kirby\Filesystem\Mime;
use Kirby\Http\Response as HttpResponse;
use Kirby\Toolkit\A;
use Kirby\Http\VolatileHeaders;
use Kirby\Toolkit\Str;
use Stringable;
@ -66,10 +66,9 @@ class Responder implements Stringable
protected array $usesCookies = [];
/**
* Tracks headers that depend on the request
* and must not be persisted in the cache
* Volatile headers manager
*/
protected array $volatileHeaders = [];
protected VolatileHeaders|null $volatileHeaders = null;
/**
* Creates and sends the response
@ -244,7 +243,7 @@ class Responder implements Stringable
$this->type($response['type'] ?? null);
$this->usesAuth($response['usesAuth'] ?? null);
$this->usesCookies($response['usesCookies'] ?? null);
$this->volatileHeaders = $response['volatileHeaders'] ?? [];
$this->volatileHeaders($response['volatileHeaders'] ?? null);
}
/**
@ -325,7 +324,7 @@ class Responder implements Stringable
}
$this->headers = $headers;
$this->volatileHeaders = [];
$this->volatileHeaders([]);
return $this;
}
@ -405,13 +404,13 @@ class Responder implements Stringable
public function toCacheArray(): array
{
$response = $this->toArray();
$volatile = $this->collectVolatileHeaders();
$volatile = $this->volatileHeaders()->collect();
if ($volatile === []) {
return $response;
}
$response['headers'] = $this->stripVolatileHeaders($response['headers'], $volatile);
$response['headers'] = $this->volatileHeaders()->strip($response['headers'], $volatile);
return $response;
}
@ -465,114 +464,32 @@ class Responder implements Stringable
* can be subtracted before caching a response snapshot
*
* @since 5.2.0
* @deprecated 5.3.0 Use `::volatileHeaders()->mark($name, $values)` instead. Will be removed in Kirby 6.
*/
public function markVolatileHeader(string $name, array|null $values = null): void
{
$this->appendVolatileHeader($this->volatileHeaders, $name, $values);
$this->volatileHeaders()->mark($name, $values);
}
/**
* Collects volatile headers from both manual configuration
* and automatically injected CORS headers
* Setter and getter for the volatile headers manager
* @since 5.3.0
*/
protected function collectVolatileHeaders(): array
public function volatileHeaders(VolatileHeaders|array|null $headers = null): VolatileHeaders
{
$volatile = $this->volatileHeaders;
$corsHeaders = Cors::headers();
if ($corsHeaders === []) {
return $volatile;
if ($headers === null) {
return $this->volatileHeaders ??= new VolatileHeaders();
}
foreach ($corsHeaders as $name => $value) {
if ($name === 'Vary') {
$corsVaryValues = array_map('trim', explode(',', $value));
$this->appendVolatileHeader($volatile, 'Vary', $corsVaryValues);
continue;
}
$this->appendVolatileHeader($volatile, $name);
if ($headers instanceof VolatileHeaders) {
return $this->volatileHeaders = $headers;
}
return $volatile;
}
/**
* Strips request-dependent headers for safe caching
*/
protected function stripVolatileHeaders(array $headers, array $volatile): array
{
foreach ($volatile as $name => $values) {
if ($name === 'Vary' && is_array($values) === true) {
if (isset($headers['Vary']) === false) {
continue;
}
$current = $this->normalizeVaryValues($headers['Vary']);
$remaining = $this->removeVaryValues($current, $values);
if ($remaining === []) {
unset($headers['Vary']);
} else {
$headers['Vary'] = implode(', ', $remaining);
}
continue;
}
unset($headers[$name]);
$volatileHeaders = new VolatileHeaders();
foreach ($headers as $name => $values) {
$volatileHeaders->mark($name, $values);
}
return $headers;
}
/**
* Adds (parts of) a header to the provided volatile header list
*/
protected function appendVolatileHeader(array &$target, string $name, array|null $values = null): void
{
if ($values === null) {
$target[$name] = null;
return;
}
if (array_key_exists($name, $target) === true && $target[$name] === null) {
return;
}
$values = A::map($values, static fn ($value) => strtolower(trim($value)));
$values = A::filter($values, static fn ($value) => $value !== '');
if ($values === []) {
return;
}
$existingValues = $target[$name] ?? [];
$target[$name] = array_values(array_unique([...$existingValues, ...$values]));
}
/**
* Normalizes a comma-separated list of Vary values
* into a unique array without empty entries
*/
protected function normalizeVaryValues(string $value): array
{
$values = A::map(explode(',', $value), 'trim');
$values = A::filter($values, static fn ($entry) => $entry !== '');
return array_values(array_unique($values));
}
/**
* Returns the Vary values with the provided entries removed
*/
protected function removeVaryValues(array $values, array $remove): array
{
$removeLower = A::map($remove, 'strtolower');
return array_values(A::filter(
$values,
static fn ($value) => in_array(strtolower($value), $removeLower, true) === false
));
return $this->volatileHeaders = $volatileHeaders;
}
}

View file

@ -471,9 +471,15 @@ class Site extends ModelWithContent
string|Page $page,
string|null $languageCode = null
): Page {
// always set the locale; in single-language mode this
// applies the locale from config, in multi-language mode
// it falls back to the default language when `null` is passed
$this->kirby()->setCurrentLanguage($languageCode);
// only set translation when explicitly passed;
// otherwise it would always fall back to 'en'
if ($languageCode !== null) {
$this->kirby()->setCurrentTranslation($languageCode);
$this->kirby()->setCurrentLanguage($languageCode);
}
// convert ids to a Page object

View file

@ -82,6 +82,10 @@ class User extends ModelWithContent
$this->password = $props['password'] ?? null;
$this->role = $set('role', fn ($role) => Str::lower(trim($role)));
if (isset($props['credentials'])) {
$this->credentials = $props['credentials'];
}
// Set blueprint before setting content
// or translations in the parent constructor.
// Otherwise, the blueprint definition cannot be
@ -229,13 +233,23 @@ class User extends ModelWithContent
#[SensitiveParameter]
string|null $password = null
): string|null {
if ($password !== null) {
if ($password !== null && $password !== '') {
$password = password_hash($password, PASSWORD_DEFAULT);
}
return $password;
}
/**
* Checks if the user has a stored password
* @since 5.3.0
*/
public function hasPassword(): bool
{
$password = $this->password();
return $password !== '' && $password !== null;
}
/**
* Returns the user id
*/
@ -699,7 +713,7 @@ class User extends ModelWithContent
#[SensitiveParameter]
string|null $password = null
): bool {
if (empty($this->password()) === true) {
if ($this->hasPassword() === false) {
throw new NotFoundException(
key: 'user.password.undefined'
);

View file

@ -3,6 +3,7 @@
namespace Kirby\Cms;
use Kirby\Exception\InvalidArgumentException;
use Kirby\Exception\LogicException;
use Kirby\Filesystem\Dir;
use Kirby\Filesystem\F;
use Kirby\Toolkit\Str;
@ -21,12 +22,29 @@ use Kirby\Uuid\HasUuids;
* @license https://getkirby.com/license
*
* @template TUser of \Kirby\Cms\User
* @extends \Kirby\Cms\Collection<TUser>
* @extends \Kirby\Cms\LazyCollection<TUser>
*/
class Users extends Collection
class Users extends LazyCollection
{
use HasUuids;
/**
* Creates a new Collection with the given objects
*
* @param iterable<TUser> $objects
* @param string|null $root Directory to dynamically load user
* objects from during hydration
* @param array $inject Props to inject into hydrated user objects
*/
public function __construct(
iterable $objects = [],
protected object|null $parent = null,
protected string|null $root = null,
protected array $inject = []
) {
parent::__construct($objects, $parent);
}
/**
* All registered users methods
*/
@ -98,7 +116,7 @@ class Users extends Collection
{
$files = new Files([], $this->parent);
foreach ($this->data as $user) {
foreach ($this as $user) {
foreach ($user->files() as $fileKey => $file) {
$files->data[$fileKey] = $file;
}
@ -126,32 +144,86 @@ class Users extends Collection
}
/**
* Loads a user from disk by passing the absolute path (root)
* Loads a user object, sets it in `$this->data[$key]`
* and returns the hydrated user object
*/
public static function load(string $root, array $inject = []): static
protected function hydrateElement(string $key): User|null
{
$users = new static();
if ($this->root === null) {
throw new LogicException('Cannot hydrate user "' . $key . '" with missing root'); // @codeCoverageIgnore
}
foreach (Dir::read($root) as $userDirectory) {
if (is_dir($root . '/' . $userDirectory) === false) {
// ignore empty keys to avoid matching the `accounts` root
// directory itself (e.g. from `false` values coerced to `""`)
if ($key === '') {
return null;
}
// check if the user directory exists if not all keys have been
// populated in the collection, otherwise we can assume that
// this method will only be called on "unhydrated" user IDs
$root = $this->root . '/' . $key;
if ($this->initialized === false && is_dir($root) === false) {
return null;
}
// get role information
$path = $root . '/index.php';
if (is_file($path) === true) {
$credentials = F::load($path, allowOutput: false);
}
// create user model based on role
$user = User::factory([
'id' => $key,
'model' => $credentials['role'] ?? null,
'credentials' => is_array($credentials ?? null) ? $credentials : null
] + $this->inject);
return $this->data[$key] = $user;
}
/**
* Ensures that the IDs for all valid users are loaded in the
* `$data` array and sets `$initialized` to `true` afterwards
*/
public function initialize(): void
{
// skip another initialization if it already has been initialized
if ($this->initialized === true) {
return;
}
if ($this->root === null) {
throw new LogicException('Cannot initialize users with missing root'); // @codeCoverageIgnore
}
// ensure the order matches the filesystem, even if
// individual users have been hydrated/added before
$existing = $this->data;
$this->data = [];
foreach (Dir::read($this->root) as $userDirectory) {
if (is_dir($this->root . '/' . $userDirectory) === false) {
continue;
}
// get role information
$path = $root . '/' . $userDirectory . '/index.php';
if (is_file($path) === true) {
$credentials = F::load($path, allowOutput: false);
}
// create user model based on role
$user = User::factory([
'id' => $userDirectory,
'model' => $credentials['role'] ?? null
] + $inject);
$users->set($user->id(), $user);
$this->data[$userDirectory] = null;
}
$this->data = [...$this->data, ...$existing];
$this->initialized = true;
}
/**
* Loads users from disk by passing the absolute directory path (root)
*/
public static function load(string $root, array $inject = []): static
{
$users = new static(root: $root, inject: $inject);
$users->initialized = false;
return $users;
}

View file

@ -118,6 +118,10 @@ class Changes
{
/**
* @var \Kirby\Cms\Pages $pages
*
* Always pass at least two arguments even if the
* data is empty so that `$site->find()` always
* returns a collection, not a single page
*/
$pages = $this->kirby->site()->find(
false,
@ -185,6 +189,10 @@ class Changes
{
/**
* @var \Kirby\Cms\Users $users
*
* Always pass at least two arguments even if the
* data is empty so that `$users->find()` always
* returns a collection, not a single user
*/
$users = $this->kirby->users()->find(
false,

View file

@ -81,7 +81,7 @@ class FieldOptions
public function render(ModelWithContent $model): array
{
return $this->resolve($model)->render($model);
return $this->resolve($model)->render($model, $this->safeMode);
}
public function resolve(ModelWithContent $model): Options

View file

@ -122,6 +122,11 @@ class F
'YB'
];
/**
* Cache for loaded files when using `load()` with `cache: true`
*/
public static array $loadCache = [];
/**
* Appends new content to an existing file
*
@ -358,8 +363,14 @@ class F
string $file,
mixed $fallback = null,
array $data = [],
bool $allowOutput = true
bool $allowOutput = true,
bool $cache = false
) {
// return cached result if available
if ($cache === true && array_key_exists($file, static::$loadCache)) {
return static::$loadCache[$file];
}
if (is_file($file) === false) {
return $fallback;
}
@ -384,6 +395,11 @@ class F
return $fallback;
}
// cache the result if requested
if ($cache === true) {
static::$loadCache[$file] = $result;
}
return $result;
}
@ -599,6 +615,52 @@ class F
return $size . ' ' . static::$units[$unit];
}
/**
* Reads a specific byte range from a file
* @since 5.3.0
*
* @param string $file The path to the file
* @param int $offset The byte offset to start reading from
* @param int|null $length The number of bytes to read (null = read to end)
*/
public static function range(
string $file,
int $offset = 0,
int|null $length = null
): string|false {
if (str_contains($file, '://') === true) {
return false;
}
// exit early on empty paths that would trigger a PHP `ValueError`
if ($file === '') {
return false;
}
return Helpers::handleErrors(
function () use ($file, $offset, $length): string|false {
$handle = fopen($file, 'rb');
if ($handle === false) {
return false; // @codeCoverageIgnore
}
if ($offset > 0) {
fseek($handle, $offset);
}
$content = $length !== null
? fread($handle, $length)
: fread($handle, filesize($file) - $offset);
fclose($handle);
return $content;
},
fn (int $errno, string $errstr): bool => str_contains($errstr, 'No such file'),
false
);
}
/**
* Reads the content of a file or requests the
* contents of a remote HTTP or HTTPS URL
@ -616,9 +678,9 @@ class F
return false;
}
// to increase performance, directly try to load the file without checking
// if it exists; fall back to a `false` return value if it doesn't exist
// while letting other warnings through
// to increase performance, directly try to load the file
// without checking if it exists; fall back to return `false`
// if it doesn't exist while letting other warnings through
return Helpers::handleErrors(
fn (): string|false => file_get_contents($file),
fn (int $errno, string $errstr): bool => str_contains($errstr, 'No such file'),

View file

@ -809,7 +809,8 @@ class Environment
$configCli = F::load(
file: $root . '/config.cli.php',
fallback: [],
allowOutput: false
allowOutput: false,
cache: true
);
}
@ -821,7 +822,8 @@ class Environment
$configHost = F::load(
file: $path,
fallback: [],
allowOutput: false
allowOutput: false,
cache: true
);
}
@ -833,7 +835,8 @@ class Environment
$configAddr = F::load(
file: $path,
fallback: [],
allowOutput: false
allowOutput: false,
cache: true
);
}

159
kirby/src/Http/Range.php Normal file
View file

@ -0,0 +1,159 @@
<?php
namespace Kirby\Http;
use Kirby\Filesystem\F;
/**
* Handles HTTP Range requests (RFC 7233)
* for partial content delivery, primarily
* used for video streaming in browsers
*
* @package Kirby Http
* @author Nico Hoffmann <nico@getkirby.com>
* @link https://getkirby.com
* @copyright Bastian Allgeier
* @license https://opensource.org/licenses/MIT
* @since 5.3.0
*/
class Range
{
/**
* Parses the Range header and returns start and end byte positions
*
* @return array{int, int}|false Array of [start, end] or false if invalid
*/
public static function parse(
string $range,
int $size
): array|false {
if ($size <= 0) {
return false;
}
$range = trim($range);
// only support byte ranges (not other units)
if (strncasecmp($range, 'bytes=', 6) !== 0) {
return false;
}
// extract the range part after "bytes="
$range = substr($range, 6);
// support only single ranges (not multiple ranges like "0-100,200-300")
if (str_contains($range, ',') === true) {
return false;
}
// split start and end
$parts = explode('-', $range, 2);
if (count($parts) !== 2) {
return false;
}
[$startStr, $endStr] = $parts;
$startStr = trim($startStr);
$endStr = trim($endStr);
// handle "bytes=-500" (last 500 bytes)
if ($startStr === '') {
if (is_numeric($endStr) === false) {
return false;
}
$suffix = (int)$endStr;
if ($suffix <= 0) {
return false;
}
if ($suffix > $size) {
$suffix = $size;
}
$start = $size - $suffix;
$end = $size - 1;
return [$start, $end];
}
// validate that start is numeric
if (is_numeric($startStr) === false) {
return false;
}
$start = (int)$startStr;
// handle "bytes=1024-" (from byte 1024 to end)
if ($endStr === '') {
$end = $size - 1;
} elseif (is_numeric($endStr) === false) {
return false;
} else {
$end = (int)$endStr;
// clamp end to file size if a client overshoots
if ($end >= $size) {
$end = $size - 1;
}
}
// validate the range
if (
$start < 0 ||
$start >= $size ||
$end < $start
) {
return false;
}
return [$start, $end];
}
/**
* Creates a response for a partial file request (byte-range)
*/
public static function response(
string $file,
string $range,
array $props = []
): Response {
// parse the Range header (e.g., "bytes=0-1" or "bytes=1024-")
$size = filesize($file);
$parsed = static::parse($range, $size);
// if the range is invalid, return 416 Range Not Satisfiable
if ($parsed === false) {
return new Response(
code: 416,
body: 'Requested Range Not Satisfiable',
headers: [
'Content-Range' => 'bytes */' . $size
]
);
}
[$start, $end] = $parsed;
$length = $end - $start + 1;
// read only the requested byte range from the file
$body = F::range($file, offset: $start, length: $length);
$props = Response::ensureSafeMimeType([
'body' => $body,
'code' => 206, // Partial Content
'type' => F::extensionToMime(F::extension($file)),
'headers' => [
'Accept-Ranges' => 'bytes',
'Content-Range' => 'bytes ' . $start . '-' . $end . '/' . $size,
'Content-Length' => $length,
...$props['headers'] ?? []
],
...$props
]);
return new Response($props);
}
}

View file

@ -310,7 +310,18 @@ class Remote
*/
public function json(bool $array = true): array|stdClass|null
{
return json_decode($this->content(), $array);
if ($content = $this->content()) {
$json = json_decode($content, $array);
if (
is_array($json) === true ||
$json instanceof stdClass === true
) {
return $json;
}
}
return null;
}
/**

View file

@ -4,6 +4,7 @@ namespace Kirby\Http;
use Closure;
use Exception;
use Kirby\Cms\App;
use Kirby\Exception\LogicException;
use Kirby\Filesystem\F;
use Stringable;
@ -160,6 +161,23 @@ class Response implements Stringable
return new static($props);
}
/**
* Ensures safe MIME type handling by forcing plain text
* for files without recognizable MIME types to harden
* against attacks from malicious file uploads
* @since 5.3.0
* @internal
*/
public static function ensureSafeMimeType(array $props): array
{
if ($props['type'] === null) {
$props['type'] = 'text/plain';
$props['headers']['X-Content-Type-Options'] = 'nosniff';
}
return $props;
}
/**
* Creates a response for a file and
* sends the file content to the browser
@ -168,23 +186,24 @@ class Response implements Stringable
*/
public static function file(string $file, array $props = []): static
{
$props = [
$request = App::instance(lazy: true)?->request();
// handle byte-range requests (e.g., for video streaming in Safari)
if ($range = $request?->header('Range')) {
return Range::response($file, $range, $props);
}
// always indicate that byte-range requests are supported
$props['headers'] = [
'Accept-Ranges' => 'bytes',
...$props['headers'] ?? []
];
$props = static::ensureSafeMimeType([
'body' => F::read($file),
'type' => F::extensionToMime(F::extension($file)),
...$props
];
// if we couldn't serve a correct MIME type, force
// the browser to display the file as plain text to
// harden against attacks from malicious file uploads
if ($props['type'] === null) {
if (isset($props['headers']) !== true) {
$props['headers'] = [];
}
$props['type'] = 'text/plain';
$props['headers']['X-Content-Type-Options'] = 'nosniff';
}
]);
return new static($props);
}

View file

@ -3,6 +3,7 @@
namespace Kirby\Http;
use Kirby\Toolkit\Str;
use Whoops\Handler\PrettyPageHandler;
/**
* Static URL tools
@ -63,6 +64,23 @@ class Url
return dirname(static::current());
}
/**
* Use Whoops to create an editor URL to open
* a file at the given line number
* @since 5.3.0
*/
public static function editor(string|false $editor, string|null $file, int $line = 0): string|null
{
if ($editor === false || $file === null) {
return null;
}
$handler = new PrettyPageHandler();
$handler->setEditor($editor);
return $handler->getEditorHref($file, $line);
}
/**
* Tries to fix a broken url without protocol
* @psalm-return ($url is null ? string|null : string)
@ -223,6 +241,7 @@ class Url
/**
* Smart resolver for internal and external urls
* @deprecated 5.3.0 Use `Kirby\Cms\Url::to()` instead
*/
public static function to(
string|null $path = null,

View file

@ -157,6 +157,31 @@ class Visitor
return Mime::isAccepted($mimeType, $this->acceptedMimeType);
}
/**
* Sets the ip address if provided
* or returns the ip of the current
* visitor otherwise
*
* @return $this|string|null
*/
public function ip(
string|null $ip = null,
bool $hash = false
): static|string|null {
if ($ip === null) {
if ($hash === true) {
// only use the first 50 chars to ensure privacy
$hash = hash('sha256', $this->ip);
return substr($hash, 0, 50);
}
return $this->ip;
}
$this->ip = $ip;
return $this;
}
/**
* Returns the MIME type from the provided list that
* is most accepted (= preferred) by the visitor
@ -195,23 +220,6 @@ class Visitor
return $preferred === 'application/json';
}
/**
* Sets the ip address if provided
* or returns the ip of the current
* visitor otherwise
*
* @return $this|string|null
*/
public function ip(string|null $ip = null): static|string|null
{
if ($ip === null) {
return $this->ip;
}
$this->ip = $ip;
return $this;
}
/**
* Sets the user agent if provided
* or returns the user agent string of

View file

@ -0,0 +1,151 @@
<?php
namespace Kirby\Http;
use Kirby\Cms\Cors;
use Kirby\Toolkit\A;
/**
* Manages request-dependent headers that must not be
* persisted in cached responses
*
* @package Kirby Cms
* @author Bastian Allgeier <bastian@getkirby.com>
* @link https://getkirby.com
* @copyright Bastian Allgeier
* @license https://getkirby.com/license
* @since 5.3.0
*/
class VolatileHeaders
{
/**
* Stored volatile header configurations
*/
protected array $headers = [];
/**
* Adds (parts of) a header to the volatile list
*/
protected function append(
string $name,
array|null $values = null,
array|null &$target = null
): void {
if ($values === null) {
$target[$name] = null;
return;
}
if (array_key_exists($name, $target) === true && $target[$name] === null) {
return;
}
$values = A::map($values, static fn ($value) => strtolower(trim($value)));
$values = A::filter($values, static fn ($value) => $value !== '');
if ($values === []) {
return;
}
$existingValues = $target[$name] ?? [];
$target[$name] = array_values(array_unique([...$existingValues, ...$values]));
}
/**
* Collects all volatile headers including CORS headers
*/
public function collect(): array
{
$volatile = $this->headers;
$corsHeaders = Cors::headers();
if ($corsHeaders === []) {
return $volatile;
}
foreach ($corsHeaders as $name => $value) {
if ($name === 'Vary') {
$corsVaryValues = array_map('trim', explode(',', $value));
$this->append($name, $corsVaryValues, $volatile);
continue;
}
$this->append($name, null, $volatile);
}
return $volatile;
}
/**
* Marks headers (or header parts) as request-dependent
*/
public function mark(string $name, array|null $values = null): void
{
$this->append($name, $values, $this->headers);
}
/**
* Normalizes a comma-separated list of Vary values
* into a unique array without empty entries
*/
protected function normalizeVaryValues(string $value): array
{
$values = A::map(explode(',', $value), 'trim');
$values = A::filter($values, static fn ($entry) => $entry !== '');
return array_values(array_unique($values));
}
/**
* Returns the Vary values with the provided entries removed
*/
protected function removeVaryValues(array $values, array $remove): array
{
$removeLower = A::map($remove, 'strtolower');
return array_values(A::filter(
$values,
static fn ($value) => in_array(strtolower($value), $removeLower, true) === false
));
}
/**
* Strips volatile headers from the provided header array
*/
public function strip(array $headers, array|null $volatile = null): array
{
$volatile ??= $this->collect();
foreach ($volatile as $name => $values) {
if ($name === 'Vary' && is_array($values) === true) {
$headers = $this->stripVaryHeader($headers, $values);
continue;
}
unset($headers[$name]);
}
return $headers;
}
/**
* Strips Vary header values from the headers array
*/
protected function stripVaryHeader(array $headers, array $values): array
{
if (isset($headers['Vary']) === false) {
return $headers;
}
$current = $this->normalizeVaryValues($headers['Vary']);
$remaining = $this->removeVaryValues($current, $values);
if ($remaining === []) {
unset($headers['Vary']);
} else {
$headers['Vary'] = implode(', ', $remaining);
}
return $headers;
}
}

View file

@ -188,8 +188,10 @@ class ImageMagick extends Darkroom
*/
protected function save(string $file, array $options): string
{
// use the format: prefix to output in the specified format
// while writing to the original path
if ($options['format'] !== null) {
$file = pathinfo($file, PATHINFO_DIRNAME) . '/' . pathinfo($file, PATHINFO_FILENAME) . '.' . $options['format'];
return escapeshellarg($options['format'] . ':' . $file);
}
return escapeshellarg($file);

View file

@ -195,8 +195,10 @@ class Imagick extends Darkroom
*/
protected function save(Image $image, string $file, array $options): bool
{
// set the output format explicitly if specified;
// writing to the original path
if ($options['format'] !== null) {
$file = pathinfo($file, PATHINFO_DIRNAME) . '/' . pathinfo($file, PATHINFO_FILENAME) . '.' . $options['format'];
$image->setImageFormat($options['format']);
}
return $image->writeImages($file, true);

View file

@ -65,16 +65,19 @@ class Option
/**
* Renders all data for the option
*/
public function render(ModelWithContent $model): array
{
public function render(
ModelWithContent $model,
bool $safeMode = true
): array {
$info = I18n::translate($this->info, $this->info);
$text = I18n::translate($this->text, $this->text);
$method = $safeMode === true ? 'toSafeString' : 'toString';
return [
'disabled' => $this->disabled,
'icon' => $this->icon,
'info' => $info ? $model->toSafeString($info) : $info,
'text' => $text ? $model->toSafeString($text) : $text,
'info' => $info ? $model->$method($info) : $info,
'text' => $text ? $model->$method($text) : $text,
'value' => $this->value
];
}

View file

@ -63,12 +63,12 @@ class Options extends Collection
return $collection;
}
public function render(ModelWithContent $model): array
public function render(ModelWithContent $model, bool $safeMode = true): array
{
$options = [];
foreach ($this->data as $key => $option) {
$options[$key] = $option->render($model);
$options[$key] = $option->render($model, $safeMode);
}
return array_values($options);

View file

@ -10,11 +10,12 @@ use Kirby\Cms\StructureObject;
use Kirby\Cms\User;
use Kirby\Content\Field;
use Kirby\Exception\InvalidArgumentException;
use Kirby\Toolkit\A;
use Kirby\Toolkit\Collection;
use Kirby\Toolkit\Obj;
/**
* Options derrived from running a query against
* Options derived from running a query against
* pages, files, users or structures to create
* options out of them.
*
@ -38,11 +39,14 @@ class OptionsQuery extends OptionsProvider
protected function collection(array $array): Collection
{
$isAssociative = A::isAssociative($array);
foreach ($array as $key => $value) {
if (is_scalar($value) === true) {
$array[$key] = new Obj([
'key' => new Field(null, 'key', $key),
'value' => new Field(null, 'value', $value),
'key' => new Field(null, 'key', $key),
'value' => new Field(null, 'value', $value),
'hasStringKey' => $isAssociative,
]);
}
}
@ -72,6 +76,12 @@ class OptionsQuery extends OptionsProvider
protected function itemToDefaults(array|object $item): array
{
return match (true) {
$item instanceof Obj && $item->hasStringKey === true => [
'arrayItem',
'{{ item.value }}',
'{{ item.key }}'
],
is_array($item),
$item instanceof Obj => [
'arrayItem',

View file

@ -50,6 +50,7 @@ class Page extends Model
return ViewButtons::view($this)->defaults(
'open',
'preview',
'-',
'settings',
'languages',
'status'

View file

@ -273,18 +273,17 @@ class PageCreateDialog
}
$props = [
'slug' => '__new__',
'slug' => $this->slug ?? '__new__',
'template' => $this->template,
'model' => $this->template,
'parent' => $this->parent instanceof Page ? $this->parent : null
'parent' => $this->parent instanceof Page ? $this->parent : null,
'content' => ['title' => $this->title],
];
// make sure that a UUID gets generated
// and added to content right away
if (Uuids::enabled() === true) {
$props['content'] = [
'uuid' => $this->uuid = Uuid::generate()
];
$props['content']['uuid'] = $this->uuid = Uuid::generate();
}
$this->model = Page::factory($props);

View file

@ -69,6 +69,12 @@ class ViewButtons
$buttons = [];
foreach ($this->buttons ?? [] as $name => $button) {
// separator, keep as is in array
if ($button === '-') {
$buttons[] = '-';
continue;
}
$buttons[] = ViewButton::factory(
button: $button,
name: $name,

View file

@ -100,7 +100,7 @@ class User extends Model
$result[] = [
'dialog' => $url . '/changePassword',
'icon' => 'key',
'text' => I18n::translate('user.changePassword'),
'text' => I18n::translate('user.' . ($this->model->hasPassword() === true ? 'changePassword' : 'setPassword')),
'disabled' => $this->isDisabledDropdownOption('changePassword', $options, $permissions)
];

View file

@ -37,6 +37,7 @@ class SmartyPants
{
return [
'attr' => 1,
'convert.quot' => true,
'doublequote.open' => '&#8220;',
'doublequote.close' => '&#8221;',
'doublequote.low' => '&#8222;',
@ -76,6 +77,7 @@ class SmartyPants
$this->parser = new SmartyPantsTypographer($this->options['attr']);
// configuration
$this->parser->convert_quot = $this->options['convert.quot'];
$this->parser->smart_doublequote_open = $this->options['doublequote.open'];
$this->parser->smart_doublequote_close = $this->options['doublequote.close'];
$this->parser->smart_singlequote_open = $this->options['singlequote.open'];
@ -111,7 +113,6 @@ class SmartyPants
{
// prepare the text
$text ??= '';
$text = str_replace('&quot;', '"', $text);
// parse the text
return $this->parser->transform($text);

View file

@ -289,6 +289,23 @@ class A
$keys = explode('.', $key);
$firstKey = array_shift($keys);
// prefer a dotted prefix key if it exists
// (e.g. plugin namespaces).
for ($i = count($keys); $i > 0; $i--) {
$prefix = $firstKey . '.' . implode('.', array_slice($keys, 0, $i));
if (
isset($array[$prefix]) === true &&
is_array($array[$prefix]) === true
) {
return static::get(
$array[$prefix],
implode('.', array_slice($keys, $i)),
$default
);
}
}
// if the input array also uses dot notation,
// try to find a subset of the $keys
if (isset($array[$firstKey]) === false) {

View file

@ -391,7 +391,7 @@ class Collection extends Iterator implements Stringable
*/
public function findBy(string $attribute, $value)
{
foreach ($this->data as $item) {
foreach ($this as $item) {
if ($this->getAttribute($item, $attribute) == $value) {
return $item;
}
@ -516,12 +516,12 @@ class Collection extends Iterator implements Stringable
if (is_callable($field) === true) {
$groups = [];
foreach ($this->data as $key => $item) {
foreach ($this as $key => $item) {
// get the value to group by
$value = $field($item);
// make sure that there's always a proper value to group by
if (!$value) {
if ($value === null || $value === false) {
throw new Exception(
message: 'Invalid grouping value for key: ' . $key
);
@ -689,7 +689,7 @@ class Collection extends Iterator implements Stringable
$collection = clone $this;
foreach ($keys as $key) {
unset($collection->data[$key]);
unset($collection->{$key});
}
return $collection;
@ -742,7 +742,7 @@ class Collection extends Iterator implements Stringable
): array {
$result = [];
foreach ($this->data as $item) {
foreach ($this as $item) {
$row = $this->getAttribute($item, $field);
if ($split !== null) {

View file

@ -51,30 +51,54 @@ class Dom
$this->doc = new DOMDocument();
$this->type = strtoupper($type);
// switch to "user error handling"
// Switch libxml into internal error handling mode so warnings
// dont leak into output or interrupt parsing
$errors = libxml_use_internal_errors(true);
if ($this->type === 'HTML') {
// ensure proper parsing for HTML snippets
// If this is an HTML fragment (no <html> or <body> root),
// wrap it in <body> so DOMDocument has a valid container.
if (preg_match('/<(html|body)[> ]/i', $code) !== 1) {
$code = '<body>' . $code . '</body>';
}
// the loadHTML() method expects ISO-8859-1 by default;
// force parsing as UTF-8 by injecting an XML declaration
// DOMDocument::loadHTML() historically assumes ISO-8859-1 input.
// To force UTF-8 parsing, Kirby injects an XML declaration.
// The random ID allows us to reliably identify *our* injected node
// later and remove it again.
$xml = 'encoding="UTF-8" id="' . Str::random(10) . '"';
$load = $this->doc->loadHTML('<?xml ' . $xml . '>' . $code);
// remove the injected XML declaration again
$pis = $this->query('//processing-instruction()');
foreach (iterator_to_array($pis, false) as $pi) {
if ($pi->data === $xml) {
static::remove($pi);
// Newer libxml2 versions may not attach the injected XML node
// inside <html>. Instead, they may convert it into a top-level
// comment node that sits before <html>:
// <!--?xml encoding="UTF-8" id="XYZ"--><html>...
//
// XPath queries like //comment() or //processing-instruction()
// often operate relative to the document element (<html>) and
// therefore miss this node entirely.
// To fix this, we must also inspect and clean up the documents
// top-level child nodes explicitly.
//
// Walk all top-level nodes of the document and remove
// any node that matches the injected XML marker
for ($node = $this->doc->firstChild; $node !== null; $node = $next) {
$next = $node->nextSibling;
if (
// Case 1: libxml preserved it as a processing instruction
($node->nodeType === XML_PI_NODE && $node->data === $xml) ||
// Case 2: libxml converted it into a comment node
// (<!--?xml encoding="UTF-8" id="..."-->)
($node->nodeType === XML_COMMENT_NODE && strpos($node->data, $xml) !== false)
) {
static::remove($node);
break;
}
}
// remove the default doctype
// Remove the default doctype
if (Str::contains($code, '<!DOCTYPE ', true) === false) {
static::remove($this->doc->doctype);
}
@ -655,6 +679,17 @@ class Dom
static::remove($metaTag);
$html = str_replace($this->doc->saveHTML($metaTag), '', $html);
// if the original input contained an HTML doctype, some libxml
// implementations expand it to the long HTML4 transitional doctype
// when saving. Normalize it back to the short `<!DOCTYPE html>`
// to keep behavior consistent across environments.
if (
Str::contains($this->code, '<!DOCTYPE ', true) === true &&
preg_match('/<!doctype\s+html/i', $this->code) === 1
) {
$html = preg_replace('/^<!DOCTYPE[^>]*>\s*/i', '<!DOCTYPE html>' . "\n", $html, 1);
}
return trim($html);
}

View file

@ -4,6 +4,7 @@ namespace Kirby\Toolkit;
use ArrayIterator;
use Countable;
use Iterator as PhpIterator;
use IteratorAggregate;
/**
@ -34,16 +35,18 @@ class Iterator implements Countable, IteratorAggregate
}
/**
* Get an iterator for the items.
* Returns an iterator for the elements
* @return \ArrayIterator<TKey, TValue>
*/
public function getIterator(): ArrayIterator
public function getIterator(): PhpIterator
{
return new ArrayIterator($this->data);
}
/**
* Returns the current key
* @deprecated
* @todo Remove in v6
*/
public function key(): int|string|null
{
@ -60,6 +63,8 @@ class Iterator implements Countable, IteratorAggregate
/**
* Returns the current element
* @deprecated
* @todo Remove in v6
* @return TValue
*/
public function current(): mixed
@ -70,6 +75,8 @@ class Iterator implements Countable, IteratorAggregate
/**
* Moves the cursor to the previous element
* and returns it
* @deprecated
* @todo Remove in v6
* @return TValue
*/
public function prev(): mixed
@ -80,6 +87,8 @@ class Iterator implements Countable, IteratorAggregate
/**
* Moves the cursor to the next element
* and returns it
* @deprecated
* @todo Remove in v6
* @return TValue
*/
public function next(): mixed
@ -89,6 +98,8 @@ class Iterator implements Countable, IteratorAggregate
/**
* Moves the cursor to the first element
* @deprecated
* @todo Remove in v6
*/
public function rewind(): void
{
@ -97,6 +108,8 @@ class Iterator implements Countable, IteratorAggregate
/**
* Checks if the current element is valid
* @deprecated
* @todo Remove in v6
*/
public function valid(): bool
{
@ -139,7 +152,7 @@ class Iterator implements Countable, IteratorAggregate
*/
public function has(mixed $key): bool
{
return isset($this->data[$key]) === true;
return array_key_exists($key, $this->data) === true;
}
/**

View file

@ -651,10 +651,17 @@ class Str
}
/**
* Safe ltrim alternative
* Trims away a fixed sequence at the beginning of the string.
* For character list trimming, use PHP's native `ltrim()` function.
*
* ```php
* Str::ltrim('abababaC', 'ab'); // 'aC'
* ```
*/
public static function ltrim(string $string, string $trim = ' '): string
{
public static function ltrim(
string $string,
string $trim = ' '
): string {
return preg_replace('!^(' . preg_quote($trim) . ')+!', '', $string);
}
@ -997,10 +1004,17 @@ class Str
}
/**
* Safe rtrim alternative
* Trims away a fixed sequence at the end of the string.
* For character list trimming, use PHP's native `rtrim()` function.
*
* ```php
* Str::rtrim('Cabababa', 'ba'); // 'Ca'
* ```
*/
public static function rtrim(string $string, string $trim = ' '): string
{
public static function rtrim(
string $string,
string $trim = ' '
): string {
return preg_replace('!(' . preg_quote($trim) . ')+$!', '', $string);
}
@ -1342,8 +1356,8 @@ class Str
array $data = [],
array $options = []
): string {
$start = $options['start'] ?? '{{1,2}';
$end = $options['end'] ?? '}{1,2}';
$start = $options['start'] ?? '(?:{{|{<|{)';
$end = $options['end'] ?? '(?:}}|>}|})';
$fallback = $options['fallback'] ?? null;
$callback = $options['callback'] ?? null;
@ -1425,11 +1439,20 @@ class Str
}
/**
* Safe trim alternative
* Trims away a fixed sequence at the beginning and end of the string.
* For character list trimming, use PHP's native `trim()` function.
*
* ```php
* Str::trim('ababaCbabab', 'ab'); // 'aCb'
* ```
*/
public static function trim(string $string, string $trim = ' '): string
{
return static::rtrim(static::ltrim($string, $trim), $trim);
public static function trim(
string $string,
string $trim = ' '
): string {
$string = static::ltrim($string, $trim);
$string = static::rtrim($string, $trim);
return $string;
}
/**

View file

@ -25,6 +25,25 @@ class PageUuid extends ModelUuid
*/
public Identifiable|null $model = null;
/**
* Removes the current UUID from cache,
* recursively including all children if needed
*/
public function clear(bool $recursive = false): bool
{
/**
* If $recursive, also clear UUIDs from cache for all children
* @var \Kirby\Cms\Page $model
*/
if ($recursive === true && $model = $this->model()) {
foreach ($model->children() as $child) {
$child->uuid()->clear(true);
}
}
return parent::clear();
}
/**
* Looks up UUID in cache and resolves
* to page object
@ -55,6 +74,27 @@ class PageUuid extends ModelUuid
}
}
/**
* Feeds the UUID for the page (and optionally
* its children) into the cache
*/
public function populate(
bool $force = false,
bool $recursive = false
): bool {
/**
* If $recursive, also populate UUIDs for all children
* @var \Kirby\Cms\Page $model
*/
if ($recursive === true && $model = $this->model()) {
foreach ($model->children() as $child) {
$child->uuid()->populate($force, true);
}
}
return parent::populate($force);
}
/**
* Returns permalink url
*/

View file

@ -100,18 +100,8 @@ abstract class Uuid implements Stringable
* Removes the current UUID from cache,
* recursively including all children if needed
*/
public function clear(bool $recursive = false): bool
public function clear(): bool
{
// For all models with children: if $recursive,
// also clear UUIDs from cache for all children
if ($recursive === true && $model = $this->model()) {
if (method_exists($model, 'children') === true) {
foreach ($model->children() as $child) {
$child->uuid()->clear(true);
}
}
}
if ($key = $this->key()) {
return Uuids::cache()->remove($key);
}

View file

@ -19,6 +19,11 @@ use Kirby\Exception\LogicException;
*/
class Uuids
{
/**
* Cache for the uuid option state
*/
public static bool|null $enabled = null;
/**
* Returns the instance for the lookup cache
*/
@ -82,7 +87,7 @@ class Uuids
public static function enabled(): bool
{
return App::instance()->option('content.uuid') !== false;
return static::$enabled ??= App::instance()->option('content.uuid') !== false;
}
/**

View file

@ -1,22 +0,0 @@
<?php
// autoload.php @generated by Composer
if (PHP_VERSION_ID < 50600) {
if (!headers_sent()) {
header('HTTP/1.1 500 Internal Server Error');
}
$err = 'Composer 2.3.0 dropped support for autoloading on PHP <5.6 and you are running '.PHP_VERSION.', please upgrade PHP or use Composer 2.2 LTS via "composer self-update --2.2". Aborting.'.PHP_EOL;
if (!ini_get('display_errors')) {
if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') {
fwrite(STDERR, $err);
} elseif (!headers_sent()) {
echo $err;
}
}
throw new RuntimeException($err);
}
require_once __DIR__ . '/composer/autoload_real.php';
return ComposerAutoloaderInit0bf5c8a9cfa251a218fc581ac888fe35::getLoader();

View file

@ -1,119 +0,0 @@
#!/usr/bin/env php
<?php
/**
* Proxy PHP file generated by Composer
*
* This file includes the referenced bin path (../symfony/yaml/Resources/bin/yaml-lint)
* using a stream wrapper to prevent the shebang from being output on PHP<8
*
* @generated
*/
namespace Composer;
$GLOBALS['_composer_bin_dir'] = __DIR__;
$GLOBALS['_composer_autoload_path'] = __DIR__ . '/..'.'/autoload.php';
if (PHP_VERSION_ID < 80000) {
if (!class_exists('Composer\BinProxyWrapper')) {
/**
* @internal
*/
final class BinProxyWrapper
{
private $handle;
private $position;
private $realpath;
public function stream_open($path, $mode, $options, &$opened_path)
{
// get rid of phpvfscomposer:// prefix for __FILE__ & __DIR__ resolution
$opened_path = substr($path, 17);
$this->realpath = realpath($opened_path) ?: $opened_path;
$opened_path = $this->realpath;
$this->handle = fopen($this->realpath, $mode);
$this->position = 0;
return (bool) $this->handle;
}
public function stream_read($count)
{
$data = fread($this->handle, $count);
if ($this->position === 0) {
$data = preg_replace('{^#!.*\r?\n}', '', $data);
}
$this->position += strlen($data);
return $data;
}
public function stream_cast($castAs)
{
return $this->handle;
}
public function stream_close()
{
fclose($this->handle);
}
public function stream_lock($operation)
{
return $operation ? flock($this->handle, $operation) : true;
}
public function stream_seek($offset, $whence)
{
if (0 === fseek($this->handle, $offset, $whence)) {
$this->position = ftell($this->handle);
return true;
}
return false;
}
public function stream_tell()
{
return $this->position;
}
public function stream_eof()
{
return feof($this->handle);
}
public function stream_stat()
{
return array();
}
public function stream_set_option($option, $arg1, $arg2)
{
return true;
}
public function url_stat($path, $flags)
{
$path = substr($path, 17);
if (file_exists($path)) {
return stat($path);
}
return false;
}
}
}
if (
(function_exists('stream_get_wrappers') && in_array('phpvfscomposer', stream_get_wrappers(), true))
|| (function_exists('stream_wrapper_register') && stream_wrapper_register('phpvfscomposer', 'Composer\BinProxyWrapper'))
) {
return include("phpvfscomposer://" . __DIR__ . '/..'.'/symfony/yaml/Resources/bin/yaml-lint');
}
}
return include __DIR__ . '/..'.'/symfony/yaml/Resources/bin/yaml-lint';

View file

@ -1,19 +0,0 @@
Copyright (c) 2013-2014 Christian Riesen
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View file

@ -1,168 +0,0 @@
<?php
declare(strict_types=1);
namespace Base32;
/**
* Base32 encoder and decoder.
*
* RFC 4648 compliant
*
* @see http://www.ietf.org/rfc/rfc4648.txt
* Some groundwork based on this class
* https://github.com/NTICompass/PHP-Base32
*
* @author Christian Riesen <chris.riesen@gmail.com>
* @author Sam Williams <sam@badcow.co>
*
* @see http://christianriesen.com
*
* @license MIT License see LICENSE file
*/
class Base32
{
/**
* Alphabet for encoding and decoding base32.
*
* @var string
*/
protected const ALPHABET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567=';
protected const BASE32HEX_PATTERN = '/[^A-Z2-7]/';
/**
* Maps the Base32 character to its corresponding bit value.
*/
protected const MAPPING = [
'=' => 0b00000,
'A' => 0b00000,
'B' => 0b00001,
'C' => 0b00010,
'D' => 0b00011,
'E' => 0b00100,
'F' => 0b00101,
'G' => 0b00110,
'H' => 0b00111,
'I' => 0b01000,
'J' => 0b01001,
'K' => 0b01010,
'L' => 0b01011,
'M' => 0b01100,
'N' => 0b01101,
'O' => 0b01110,
'P' => 0b01111,
'Q' => 0b10000,
'R' => 0b10001,
'S' => 0b10010,
'T' => 0b10011,
'U' => 0b10100,
'V' => 0b10101,
'W' => 0b10110,
'X' => 0b10111,
'Y' => 0b11000,
'Z' => 0b11001,
'2' => 0b11010,
'3' => 0b11011,
'4' => 0b11100,
'5' => 0b11101,
'6' => 0b11110,
'7' => 0b11111,
];
/**
* Encodes into base32.
*
* @param string $string Clear text string
*
* @return string Base32 encoded string
*/
public static function encode(string $string): string
{
// Empty string results in empty string
if ('' === $string) {
return '';
}
$encoded = '';
//Set the initial values
$n = $bitLen = $val = 0;
$len = \strlen($string);
//Pad the end of the string - this ensures that there are enough zeros
$string .= \str_repeat(\chr(0), 4);
//Explode string into integers
$chars = (array) \unpack('C*', $string, 0);
while ($n < $len || 0 !== $bitLen) {
//If the bit length has fallen below 5, shift left 8 and add the next character.
if ($bitLen < 5) {
$val = $val << 8;
$bitLen += 8;
$n++;
$val += $chars[$n];
}
$shift = $bitLen - 5;
$encoded .= ($n - (int)($bitLen > 8) > $len && 0 == $val) ? '=' : static::ALPHABET[$val >> $shift];
$val = $val & ((1 << $shift) - 1);
$bitLen -= 5;
}
return $encoded;
}
/**
* Decodes base32.
*
* @param string $base32String Base32 encoded string
*
* @return string Clear text string
*/
public static function decode(string $base32String): string
{
// Only work in upper cases
$base32String = \strtoupper($base32String);
// Remove anything that is not base32 alphabet
$base32String = \preg_replace(static::BASE32HEX_PATTERN, '', $base32String);
// Empty string results in empty string
if ('' === $base32String || null === $base32String) {
return '';
}
$decoded = '';
//Set the initial values
$len = \strlen($base32String);
$n = 0;
$bitLen = 5;
$val = static::MAPPING[$base32String[0]];
while ($n < $len) {
//If the bit length has fallen below 8, shift left 5 and add the next pentet.
if ($bitLen < 8) {
$val = $val << 5;
$bitLen += 5;
$n++;
$pentet = $base32String[$n] ?? '=';
//If the new pentet is padding, make this the last iteration.
if ('=' === $pentet) {
$n = $len;
}
$val += static::MAPPING[$pentet];
continue;
}
$shift = $bitLen - 8;
$decoded .= \chr($val >> $shift);
$val = $val & ((1 << $shift) - 1);
$bitLen -= 8;
}
return $decoded;
}
}

View file

@ -1,68 +0,0 @@
<?php
declare(strict_types=1);
namespace Base32;
/**
* Base32Hex encoder and decoder.
*
* RFC 4648 compliant
* @see http://www.ietf.org/rfc/rfc4648.txt
*
* @author Sam Williams <sam@badcow.co>
*
* @see http://christianriesen.com
*
* @license MIT License see LICENSE file
*/
class Base32Hex extends Base32
{
/**
* Alphabet for encoding and decoding base32 extended hex.
*
* @var string
*/
protected const ALPHABET = '0123456789ABCDEFGHIJKLMNOPQRSTUV=';
protected const BASE32HEX_PATTERN = '/[^0-9A-V]/';
/**
* Maps the Base32 character to its corresponding bit value.
*/
protected const MAPPING = [
'=' => 0b00000,
'0' => 0b00000,
'1' => 0b00001,
'2' => 0b00010,
'3' => 0b00011,
'4' => 0b00100,
'5' => 0b00101,
'6' => 0b00110,
'7' => 0b00111,
'8' => 0b01000,
'9' => 0b01001,
'A' => 0b01010,
'B' => 0b01011,
'C' => 0b01100,
'D' => 0b01101,
'E' => 0b01110,
'F' => 0b01111,
'G' => 0b10000,
'H' => 0b10001,
'I' => 0b10010,
'J' => 0b10011,
'K' => 0b10100,
'L' => 0b10101,
'M' => 0b10110,
'N' => 0b10111,
'O' => 0b11000,
'P' => 0b11001,
'Q' => 0b11010,
'R' => 0b11011,
'S' => 0b11100,
'T' => 0b11101,
'U' => 0b11110,
'V' => 0b11111,
];
}

View file

@ -1,7 +0,0 @@
Copyright 2017 A Beautiful Site, LLC
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View file

@ -1,26 +0,0 @@
{
"name": "claviska/simpleimage",
"description": "A PHP class that makes working with images as simple as possible.",
"license": "MIT",
"require": {
"php": ">=8.0",
"ext-gd": "*",
"league/color-extractor": "0.4.*"
},
"authors": [
{
"name": "Cory LaViska",
"homepage": "http://www.abeautifulsite.net/",
"role": "Developer"
}
],
"autoload": {
"psr-0": {
"claviska": "src/"
}
},
"require-dev": {
"laravel/pint": "^1.5",
"phpstan/phpstan": "^1.10"
}
}

View file

@ -1,209 +0,0 @@
{
"_readme": [
"This file locks the dependencies of your project to a known state",
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "eb94dc95686ec297093755af85d5e7dd",
"packages": [
{
"name": "league/color-extractor",
"version": "0.4.0",
"source": {
"type": "git",
"url": "https://github.com/thephpleague/color-extractor.git",
"reference": "21fcac6249c5ef7d00eb83e128743ee6678fe505"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/thephpleague/color-extractor/zipball/21fcac6249c5ef7d00eb83e128743ee6678fe505",
"reference": "21fcac6249c5ef7d00eb83e128743ee6678fe505",
"shasum": ""
},
"require": {
"ext-gd": "*",
"php": "^7.3 || ^8.0"
},
"replace": {
"matthecat/colorextractor": "*"
},
"require-dev": {
"friendsofphp/php-cs-fixer": "~2",
"phpunit/phpunit": "^9.5"
},
"suggest": {
"ext-curl": "To download images from remote URLs if allow_url_fopen is disabled for security reasons"
},
"type": "library",
"autoload": {
"psr-4": {
"League\\ColorExtractor\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Mathieu Lechat",
"email": "math.lechat@gmail.com",
"homepage": "http://matthecat.com",
"role": "Developer"
}
],
"description": "Extract colors from an image as a human would do.",
"homepage": "https://github.com/thephpleague/color-extractor",
"keywords": [
"color",
"extract",
"human",
"image",
"palette"
],
"support": {
"issues": "https://github.com/thephpleague/color-extractor/issues",
"source": "https://github.com/thephpleague/color-extractor/tree/0.4.0"
},
"time": "2022-09-24T15:57:16+00:00"
}
],
"packages-dev": [
{
"name": "laravel/pint",
"version": "v1.5.0",
"source": {
"type": "git",
"url": "https://github.com/laravel/pint.git",
"reference": "e0a8cef58b74662f27355be9cdea0e726bbac362"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laravel/pint/zipball/e0a8cef58b74662f27355be9cdea0e726bbac362",
"reference": "e0a8cef58b74662f27355be9cdea0e726bbac362",
"shasum": ""
},
"require": {
"ext-json": "*",
"ext-mbstring": "*",
"ext-tokenizer": "*",
"ext-xml": "*",
"php": "^8.0"
},
"require-dev": {
"friendsofphp/php-cs-fixer": "^3.14.4",
"illuminate/view": "^9.51.0",
"laravel-zero/framework": "^9.2.0",
"mockery/mockery": "^1.5.1",
"nunomaduro/larastan": "^2.4.0",
"nunomaduro/termwind": "^1.15.1",
"pestphp/pest": "^1.22.4"
},
"bin": [
"builds/pint"
],
"type": "project",
"autoload": {
"psr-4": {
"App\\": "app/",
"Database\\Seeders\\": "database/seeders/",
"Database\\Factories\\": "database/factories/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nuno Maduro",
"email": "enunomaduro@gmail.com"
}
],
"description": "An opinionated code formatter for PHP.",
"homepage": "https://laravel.com",
"keywords": [
"format",
"formatter",
"lint",
"linter",
"php"
],
"support": {
"issues": "https://github.com/laravel/pint/issues",
"source": "https://github.com/laravel/pint"
},
"time": "2023-02-14T16:31:02+00:00"
},
{
"name": "phpstan/phpstan",
"version": "1.10.2",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpstan.git",
"reference": "a2ffec7db373d8da4973d1d62add872db5cd22dd"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/a2ffec7db373d8da4973d1d62add872db5cd22dd",
"reference": "a2ffec7db373d8da4973d1d62add872db5cd22dd",
"shasum": ""
},
"require": {
"php": "^7.2|^8.0"
},
"conflict": {
"phpstan/phpstan-shim": "*"
},
"bin": [
"phpstan",
"phpstan.phar"
],
"type": "library",
"autoload": {
"files": [
"bootstrap.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"description": "PHPStan - PHP Static Analysis Tool",
"keywords": [
"dev",
"static analysis"
],
"support": {
"issues": "https://github.com/phpstan/phpstan/issues",
"source": "https://github.com/phpstan/phpstan/tree/1.10.2"
},
"funding": [
{
"url": "https://github.com/ondrejmirtes",
"type": "github"
},
{
"url": "https://github.com/phpstan",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/phpstan/phpstan",
"type": "tidelift"
}
],
"time": "2023-02-23T14:36:46+00:00"
}
],
"aliases": [],
"minimum-stability": "stable",
"stability-flags": [],
"prefer-stable": false,
"prefer-lowest": false,
"platform": {
"php": ">=8.0",
"ext-gd": "*"
},
"platform-dev": [],
"plugin-api-version": "2.3.0"
}

File diff suppressed because it is too large Load diff

View file

@ -1,579 +0,0 @@
<?php
/*
* This file is part of Composer.
*
* (c) Nils Adermann <naderman@naderman.de>
* Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Composer\Autoload;
/**
* ClassLoader implements a PSR-0, PSR-4 and classmap class loader.
*
* $loader = new \Composer\Autoload\ClassLoader();
*
* // register classes with namespaces
* $loader->add('Symfony\Component', __DIR__.'/component');
* $loader->add('Symfony', __DIR__.'/framework');
*
* // activate the autoloader
* $loader->register();
*
* // to enable searching the include path (eg. for PEAR packages)
* $loader->setUseIncludePath(true);
*
* In this example, if you try to use a class in the Symfony\Component
* namespace or one of its children (Symfony\Component\Console for instance),
* the autoloader will first look for the class under the component/
* directory, and it will then fallback to the framework/ directory if not
* found before giving up.
*
* This class is loosely based on the Symfony UniversalClassLoader.
*
* @author Fabien Potencier <fabien@symfony.com>
* @author Jordi Boggiano <j.boggiano@seld.be>
* @see https://www.php-fig.org/psr/psr-0/
* @see https://www.php-fig.org/psr/psr-4/
*/
class ClassLoader
{
/** @var \Closure(string):void */
private static $includeFile;
/** @var string|null */
private $vendorDir;
// PSR-4
/**
* @var array<string, array<string, int>>
*/
private $prefixLengthsPsr4 = array();
/**
* @var array<string, list<string>>
*/
private $prefixDirsPsr4 = array();
/**
* @var list<string>
*/
private $fallbackDirsPsr4 = array();
// PSR-0
/**
* List of PSR-0 prefixes
*
* Structured as array('F (first letter)' => array('Foo\Bar (full prefix)' => array('path', 'path2')))
*
* @var array<string, array<string, list<string>>>
*/
private $prefixesPsr0 = array();
/**
* @var list<string>
*/
private $fallbackDirsPsr0 = array();
/** @var bool */
private $useIncludePath = false;
/**
* @var array<string, string>
*/
private $classMap = array();
/** @var bool */
private $classMapAuthoritative = false;
/**
* @var array<string, bool>
*/
private $missingClasses = array();
/** @var string|null */
private $apcuPrefix;
/**
* @var array<string, self>
*/
private static $registeredLoaders = array();
/**
* @param string|null $vendorDir
*/
public function __construct($vendorDir = null)
{
$this->vendorDir = $vendorDir;
self::initializeIncludeClosure();
}
/**
* @return array<string, list<string>>
*/
public function getPrefixes()
{
if (!empty($this->prefixesPsr0)) {
return call_user_func_array('array_merge', array_values($this->prefixesPsr0));
}
return array();
}
/**
* @return array<string, list<string>>
*/
public function getPrefixesPsr4()
{
return $this->prefixDirsPsr4;
}
/**
* @return list<string>
*/
public function getFallbackDirs()
{
return $this->fallbackDirsPsr0;
}
/**
* @return list<string>
*/
public function getFallbackDirsPsr4()
{
return $this->fallbackDirsPsr4;
}
/**
* @return array<string, string> Array of classname => path
*/
public function getClassMap()
{
return $this->classMap;
}
/**
* @param array<string, string> $classMap Class to filename map
*
* @return void
*/
public function addClassMap(array $classMap)
{
if ($this->classMap) {
$this->classMap = array_merge($this->classMap, $classMap);
} else {
$this->classMap = $classMap;
}
}
/**
* Registers a set of PSR-0 directories for a given prefix, either
* appending or prepending to the ones previously set for this prefix.
*
* @param string $prefix The prefix
* @param list<string>|string $paths The PSR-0 root directories
* @param bool $prepend Whether to prepend the directories
*
* @return void
*/
public function add($prefix, $paths, $prepend = false)
{
$paths = (array) $paths;
if (!$prefix) {
if ($prepend) {
$this->fallbackDirsPsr0 = array_merge(
$paths,
$this->fallbackDirsPsr0
);
} else {
$this->fallbackDirsPsr0 = array_merge(
$this->fallbackDirsPsr0,
$paths
);
}
return;
}
$first = $prefix[0];
if (!isset($this->prefixesPsr0[$first][$prefix])) {
$this->prefixesPsr0[$first][$prefix] = $paths;
return;
}
if ($prepend) {
$this->prefixesPsr0[$first][$prefix] = array_merge(
$paths,
$this->prefixesPsr0[$first][$prefix]
);
} else {
$this->prefixesPsr0[$first][$prefix] = array_merge(
$this->prefixesPsr0[$first][$prefix],
$paths
);
}
}
/**
* Registers a set of PSR-4 directories for a given namespace, either
* appending or prepending to the ones previously set for this namespace.
*
* @param string $prefix The prefix/namespace, with trailing '\\'
* @param list<string>|string $paths The PSR-4 base directories
* @param bool $prepend Whether to prepend the directories
*
* @throws \InvalidArgumentException
*
* @return void
*/
public function addPsr4($prefix, $paths, $prepend = false)
{
$paths = (array) $paths;
if (!$prefix) {
// Register directories for the root namespace.
if ($prepend) {
$this->fallbackDirsPsr4 = array_merge(
$paths,
$this->fallbackDirsPsr4
);
} else {
$this->fallbackDirsPsr4 = array_merge(
$this->fallbackDirsPsr4,
$paths
);
}
} elseif (!isset($this->prefixDirsPsr4[$prefix])) {
// Register directories for a new namespace.
$length = strlen($prefix);
if ('\\' !== $prefix[$length - 1]) {
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
}
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
$this->prefixDirsPsr4[$prefix] = $paths;
} elseif ($prepend) {
// Prepend directories for an already registered namespace.
$this->prefixDirsPsr4[$prefix] = array_merge(
$paths,
$this->prefixDirsPsr4[$prefix]
);
} else {
// Append directories for an already registered namespace.
$this->prefixDirsPsr4[$prefix] = array_merge(
$this->prefixDirsPsr4[$prefix],
$paths
);
}
}
/**
* Registers a set of PSR-0 directories for a given prefix,
* replacing any others previously set for this prefix.
*
* @param string $prefix The prefix
* @param list<string>|string $paths The PSR-0 base directories
*
* @return void
*/
public function set($prefix, $paths)
{
if (!$prefix) {
$this->fallbackDirsPsr0 = (array) $paths;
} else {
$this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths;
}
}
/**
* Registers a set of PSR-4 directories for a given namespace,
* replacing any others previously set for this namespace.
*
* @param string $prefix The prefix/namespace, with trailing '\\'
* @param list<string>|string $paths The PSR-4 base directories
*
* @throws \InvalidArgumentException
*
* @return void
*/
public function setPsr4($prefix, $paths)
{
if (!$prefix) {
$this->fallbackDirsPsr4 = (array) $paths;
} else {
$length = strlen($prefix);
if ('\\' !== $prefix[$length - 1]) {
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
}
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
$this->prefixDirsPsr4[$prefix] = (array) $paths;
}
}
/**
* Turns on searching the include path for class files.
*
* @param bool $useIncludePath
*
* @return void
*/
public function setUseIncludePath($useIncludePath)
{
$this->useIncludePath = $useIncludePath;
}
/**
* Can be used to check if the autoloader uses the include path to check
* for classes.
*
* @return bool
*/
public function getUseIncludePath()
{
return $this->useIncludePath;
}
/**
* Turns off searching the prefix and fallback directories for classes
* that have not been registered with the class map.
*
* @param bool $classMapAuthoritative
*
* @return void
*/
public function setClassMapAuthoritative($classMapAuthoritative)
{
$this->classMapAuthoritative = $classMapAuthoritative;
}
/**
* Should class lookup fail if not found in the current class map?
*
* @return bool
*/
public function isClassMapAuthoritative()
{
return $this->classMapAuthoritative;
}
/**
* APCu prefix to use to cache found/not-found classes, if the extension is enabled.
*
* @param string|null $apcuPrefix
*
* @return void
*/
public function setApcuPrefix($apcuPrefix)
{
$this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null;
}
/**
* The APCu prefix in use, or null if APCu caching is not enabled.
*
* @return string|null
*/
public function getApcuPrefix()
{
return $this->apcuPrefix;
}
/**
* Registers this instance as an autoloader.
*
* @param bool $prepend Whether to prepend the autoloader or not
*
* @return void
*/
public function register($prepend = false)
{
spl_autoload_register(array($this, 'loadClass'), true, $prepend);
if (null === $this->vendorDir) {
return;
}
if ($prepend) {
self::$registeredLoaders = array($this->vendorDir => $this) + self::$registeredLoaders;
} else {
unset(self::$registeredLoaders[$this->vendorDir]);
self::$registeredLoaders[$this->vendorDir] = $this;
}
}
/**
* Unregisters this instance as an autoloader.
*
* @return void
*/
public function unregister()
{
spl_autoload_unregister(array($this, 'loadClass'));
if (null !== $this->vendorDir) {
unset(self::$registeredLoaders[$this->vendorDir]);
}
}
/**
* Loads the given class or interface.
*
* @param string $class The name of the class
* @return true|null True if loaded, null otherwise
*/
public function loadClass($class)
{
if ($file = $this->findFile($class)) {
$includeFile = self::$includeFile;
$includeFile($file);
return true;
}
return null;
}
/**
* Finds the path to the file where the class is defined.
*
* @param string $class The name of the class
*
* @return string|false The path if found, false otherwise
*/
public function findFile($class)
{
// class map lookup
if (isset($this->classMap[$class])) {
return $this->classMap[$class];
}
if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) {
return false;
}
if (null !== $this->apcuPrefix) {
$file = apcu_fetch($this->apcuPrefix.$class, $hit);
if ($hit) {
return $file;
}
}
$file = $this->findFileWithExtension($class, '.php');
// Search for Hack files if we are running on HHVM
if (false === $file && defined('HHVM_VERSION')) {
$file = $this->findFileWithExtension($class, '.hh');
}
if (null !== $this->apcuPrefix) {
apcu_add($this->apcuPrefix.$class, $file);
}
if (false === $file) {
// Remember that this class does not exist.
$this->missingClasses[$class] = true;
}
return $file;
}
/**
* Returns the currently registered loaders keyed by their corresponding vendor directories.
*
* @return array<string, self>
*/
public static function getRegisteredLoaders()
{
return self::$registeredLoaders;
}
/**
* @param string $class
* @param string $ext
* @return string|false
*/
private function findFileWithExtension($class, $ext)
{
// PSR-4 lookup
$logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext;
$first = $class[0];
if (isset($this->prefixLengthsPsr4[$first])) {
$subPath = $class;
while (false !== $lastPos = strrpos($subPath, '\\')) {
$subPath = substr($subPath, 0, $lastPos);
$search = $subPath . '\\';
if (isset($this->prefixDirsPsr4[$search])) {
$pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1);
foreach ($this->prefixDirsPsr4[$search] as $dir) {
if (file_exists($file = $dir . $pathEnd)) {
return $file;
}
}
}
}
}
// PSR-4 fallback dirs
foreach ($this->fallbackDirsPsr4 as $dir) {
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {
return $file;
}
}
// PSR-0 lookup
if (false !== $pos = strrpos($class, '\\')) {
// namespaced class name
$logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
. strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR);
} else {
// PEAR-like class name
$logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext;
}
if (isset($this->prefixesPsr0[$first])) {
foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) {
if (0 === strpos($class, $prefix)) {
foreach ($dirs as $dir) {
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
return $file;
}
}
}
}
}
// PSR-0 fallback dirs
foreach ($this->fallbackDirsPsr0 as $dir) {
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
return $file;
}
}
// PSR-0 include paths.
if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
return $file;
}
return false;
}
/**
* @return void
*/
private static function initializeIncludeClosure()
{
if (self::$includeFile !== null) {
return;
}
/**
* Scope isolated include.
*
* Prevents access to $this/self from included files.
*
* @param string $file
* @return void
*/
self::$includeFile = \Closure::bind(static function($file) {
include $file;
}, null, null);
}
}

View file

@ -1,396 +0,0 @@
<?php
/*
* This file is part of Composer.
*
* (c) Nils Adermann <naderman@naderman.de>
* Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Composer;
use Composer\Autoload\ClassLoader;
use Composer\Semver\VersionParser;
/**
* This class is copied in every Composer installed project and available to all
*
* See also https://getcomposer.org/doc/07-runtime.md#installed-versions
*
* To require its presence, you can require `composer-runtime-api ^2.0`
*
* @final
*/
class InstalledVersions
{
/**
* @var string|null if set (by reflection by Composer), this should be set to the path where this class is being copied to
* @internal
*/
private static $selfDir = null;
/**
* @var mixed[]|null
* @psalm-var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}|array{}|null
*/
private static $installed;
/**
* @var bool
*/
private static $installedIsLocalDir;
/**
* @var bool|null
*/
private static $canGetVendors;
/**
* @var array[]
* @psalm-var array<string, array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
*/
private static $installedByVendor = array();
/**
* Returns a list of all package names which are present, either by being installed, replaced or provided
*
* @return string[]
* @psalm-return list<string>
*/
public static function getInstalledPackages()
{
$packages = array();
foreach (self::getInstalled() as $installed) {
$packages[] = array_keys($installed['versions']);
}
if (1 === \count($packages)) {
return $packages[0];
}
return array_keys(array_flip(\call_user_func_array('array_merge', $packages)));
}
/**
* Returns a list of all package names with a specific type e.g. 'library'
*
* @param string $type
* @return string[]
* @psalm-return list<string>
*/
public static function getInstalledPackagesByType($type)
{
$packagesByType = array();
foreach (self::getInstalled() as $installed) {
foreach ($installed['versions'] as $name => $package) {
if (isset($package['type']) && $package['type'] === $type) {
$packagesByType[] = $name;
}
}
}
return $packagesByType;
}
/**
* Checks whether the given package is installed
*
* This also returns true if the package name is provided or replaced by another package
*
* @param string $packageName
* @param bool $includeDevRequirements
* @return bool
*/
public static function isInstalled($packageName, $includeDevRequirements = true)
{
foreach (self::getInstalled() as $installed) {
if (isset($installed['versions'][$packageName])) {
return $includeDevRequirements || !isset($installed['versions'][$packageName]['dev_requirement']) || $installed['versions'][$packageName]['dev_requirement'] === false;
}
}
return false;
}
/**
* Checks whether the given package satisfies a version constraint
*
* e.g. If you want to know whether version 2.3+ of package foo/bar is installed, you would call:
*
* Composer\InstalledVersions::satisfies(new VersionParser, 'foo/bar', '^2.3')
*
* @param VersionParser $parser Install composer/semver to have access to this class and functionality
* @param string $packageName
* @param string|null $constraint A version constraint to check for, if you pass one you have to make sure composer/semver is required by your package
* @return bool
*/
public static function satisfies(VersionParser $parser, $packageName, $constraint)
{
$constraint = $parser->parseConstraints((string) $constraint);
$provided = $parser->parseConstraints(self::getVersionRanges($packageName));
return $provided->matches($constraint);
}
/**
* Returns a version constraint representing all the range(s) which are installed for a given package
*
* It is easier to use this via isInstalled() with the $constraint argument if you need to check
* whether a given version of a package is installed, and not just whether it exists
*
* @param string $packageName
* @return string Version constraint usable with composer/semver
*/
public static function getVersionRanges($packageName)
{
foreach (self::getInstalled() as $installed) {
if (!isset($installed['versions'][$packageName])) {
continue;
}
$ranges = array();
if (isset($installed['versions'][$packageName]['pretty_version'])) {
$ranges[] = $installed['versions'][$packageName]['pretty_version'];
}
if (array_key_exists('aliases', $installed['versions'][$packageName])) {
$ranges = array_merge($ranges, $installed['versions'][$packageName]['aliases']);
}
if (array_key_exists('replaced', $installed['versions'][$packageName])) {
$ranges = array_merge($ranges, $installed['versions'][$packageName]['replaced']);
}
if (array_key_exists('provided', $installed['versions'][$packageName])) {
$ranges = array_merge($ranges, $installed['versions'][$packageName]['provided']);
}
return implode(' || ', $ranges);
}
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
}
/**
* @param string $packageName
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present
*/
public static function getVersion($packageName)
{
foreach (self::getInstalled() as $installed) {
if (!isset($installed['versions'][$packageName])) {
continue;
}
if (!isset($installed['versions'][$packageName]['version'])) {
return null;
}
return $installed['versions'][$packageName]['version'];
}
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
}
/**
* @param string $packageName
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present
*/
public static function getPrettyVersion($packageName)
{
foreach (self::getInstalled() as $installed) {
if (!isset($installed['versions'][$packageName])) {
continue;
}
if (!isset($installed['versions'][$packageName]['pretty_version'])) {
return null;
}
return $installed['versions'][$packageName]['pretty_version'];
}
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
}
/**
* @param string $packageName
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as reference
*/
public static function getReference($packageName)
{
foreach (self::getInstalled() as $installed) {
if (!isset($installed['versions'][$packageName])) {
continue;
}
if (!isset($installed['versions'][$packageName]['reference'])) {
return null;
}
return $installed['versions'][$packageName]['reference'];
}
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
}
/**
* @param string $packageName
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as install path. Packages of type metapackages also have a null install path.
*/
public static function getInstallPath($packageName)
{
foreach (self::getInstalled() as $installed) {
if (!isset($installed['versions'][$packageName])) {
continue;
}
return isset($installed['versions'][$packageName]['install_path']) ? $installed['versions'][$packageName]['install_path'] : null;
}
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
}
/**
* @return array
* @psalm-return array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}
*/
public static function getRootPackage()
{
$installed = self::getInstalled();
return $installed[0]['root'];
}
/**
* Returns the raw installed.php data for custom implementations
*
* @deprecated Use getAllRawData() instead which returns all datasets for all autoloaders present in the process. getRawData only returns the first dataset loaded, which may not be what you expect.
* @return array[]
* @psalm-return array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}
*/
public static function getRawData()
{
@trigger_error('getRawData only returns the first dataset loaded, which may not be what you expect. Use getAllRawData() instead which returns all datasets for all autoloaders present in the process.', E_USER_DEPRECATED);
if (null === self::$installed) {
// only require the installed.php file if this file is loaded from its dumped location,
// and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
if (substr(__DIR__, -8, 1) !== 'C') {
self::$installed = include __DIR__ . '/installed.php';
} else {
self::$installed = array();
}
}
return self::$installed;
}
/**
* Returns the raw data of all installed.php which are currently loaded for custom implementations
*
* @return array[]
* @psalm-return list<array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
*/
public static function getAllRawData()
{
return self::getInstalled();
}
/**
* Lets you reload the static array from another file
*
* This is only useful for complex integrations in which a project needs to use
* this class but then also needs to execute another project's autoloader in process,
* and wants to ensure both projects have access to their version of installed.php.
*
* A typical case would be PHPUnit, where it would need to make sure it reads all
* the data it needs from this class, then call reload() with
* `require $CWD/vendor/composer/installed.php` (or similar) as input to make sure
* the project in which it runs can then also use this class safely, without
* interference between PHPUnit's dependencies and the project's dependencies.
*
* @param array[] $data A vendor/composer/installed.php data set
* @return void
*
* @psalm-param array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $data
*/
public static function reload($data)
{
self::$installed = $data;
self::$installedByVendor = array();
// when using reload, we disable the duplicate protection to ensure that self::$installed data is
// always returned, but we cannot know whether it comes from the installed.php in __DIR__ or not,
// so we have to assume it does not, and that may result in duplicate data being returned when listing
// all installed packages for example
self::$installedIsLocalDir = false;
}
/**
* @return string
*/
private static function getSelfDir()
{
if (self::$selfDir === null) {
self::$selfDir = strtr(__DIR__, '\\', '/');
}
return self::$selfDir;
}
/**
* @return array[]
* @psalm-return list<array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
*/
private static function getInstalled()
{
if (null === self::$canGetVendors) {
self::$canGetVendors = method_exists('Composer\Autoload\ClassLoader', 'getRegisteredLoaders');
}
$installed = array();
$copiedLocalDir = false;
if (self::$canGetVendors) {
$selfDir = self::getSelfDir();
foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) {
$vendorDir = strtr($vendorDir, '\\', '/');
if (isset(self::$installedByVendor[$vendorDir])) {
$installed[] = self::$installedByVendor[$vendorDir];
} elseif (is_file($vendorDir.'/composer/installed.php')) {
/** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $required */
$required = require $vendorDir.'/composer/installed.php';
self::$installedByVendor[$vendorDir] = $required;
$installed[] = $required;
if (self::$installed === null && $vendorDir.'/composer' === $selfDir) {
self::$installed = $required;
self::$installedIsLocalDir = true;
}
}
if (self::$installedIsLocalDir && $vendorDir.'/composer' === $selfDir) {
$copiedLocalDir = true;
}
}
}
if (null === self::$installed) {
// only require the installed.php file if this file is loaded from its dumped location,
// and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
if (substr(__DIR__, -8, 1) !== 'C') {
/** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $required */
$required = require __DIR__ . '/installed.php';
self::$installed = $required;
} else {
self::$installed = array();
}
}
if (self::$installed !== array() && !$copiedLocalDir) {
$installed[] = self::$installed;
}
return $installed;
}
}

View file

@ -1,21 +0,0 @@
Copyright (c) Nils Adermann, Jordi Boggiano
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View file

@ -1,503 +0,0 @@
<?php
// autoload_classmap.php @generated by Composer
$vendorDir = dirname(__DIR__);
$baseDir = dirname($vendorDir);
return array(
'Base32\\Base32' => $vendorDir . '/christian-riesen/base32/src/Base32.php',
'Base32\\Base32Hex' => $vendorDir . '/christian-riesen/base32/src/Base32Hex.php',
'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php',
'Composer\\Semver\\Comparator' => $vendorDir . '/composer/semver/src/Comparator.php',
'Composer\\Semver\\CompilingMatcher' => $vendorDir . '/composer/semver/src/CompilingMatcher.php',
'Composer\\Semver\\Constraint\\Bound' => $vendorDir . '/composer/semver/src/Constraint/Bound.php',
'Composer\\Semver\\Constraint\\Constraint' => $vendorDir . '/composer/semver/src/Constraint/Constraint.php',
'Composer\\Semver\\Constraint\\ConstraintInterface' => $vendorDir . '/composer/semver/src/Constraint/ConstraintInterface.php',
'Composer\\Semver\\Constraint\\MatchAllConstraint' => $vendorDir . '/composer/semver/src/Constraint/MatchAllConstraint.php',
'Composer\\Semver\\Constraint\\MatchNoneConstraint' => $vendorDir . '/composer/semver/src/Constraint/MatchNoneConstraint.php',
'Composer\\Semver\\Constraint\\MultiConstraint' => $vendorDir . '/composer/semver/src/Constraint/MultiConstraint.php',
'Composer\\Semver\\Interval' => $vendorDir . '/composer/semver/src/Interval.php',
'Composer\\Semver\\Intervals' => $vendorDir . '/composer/semver/src/Intervals.php',
'Composer\\Semver\\Semver' => $vendorDir . '/composer/semver/src/Semver.php',
'Composer\\Semver\\VersionParser' => $vendorDir . '/composer/semver/src/VersionParser.php',
'Kirby\\Api\\Api' => $baseDir . '/src/Api/Api.php',
'Kirby\\Api\\Collection' => $baseDir . '/src/Api/Collection.php',
'Kirby\\Api\\Controller\\Changes' => $baseDir . '/src/Api/Controller/Changes.php',
'Kirby\\Api\\Model' => $baseDir . '/src/Api/Model.php',
'Kirby\\Api\\Upload' => $baseDir . '/src/Api/Upload.php',
'Kirby\\Cache\\ApcuCache' => $baseDir . '/src/Cache/ApcuCache.php',
'Kirby\\Cache\\Cache' => $baseDir . '/src/Cache/Cache.php',
'Kirby\\Cache\\FileCache' => $baseDir . '/src/Cache/FileCache.php',
'Kirby\\Cache\\MemCached' => $baseDir . '/src/Cache/MemCached.php',
'Kirby\\Cache\\MemoryCache' => $baseDir . '/src/Cache/MemoryCache.php',
'Kirby\\Cache\\NullCache' => $baseDir . '/src/Cache/NullCache.php',
'Kirby\\Cache\\RedisCache' => $baseDir . '/src/Cache/RedisCache.php',
'Kirby\\Cache\\Value' => $baseDir . '/src/Cache/Value.php',
'Kirby\\Cms\\Api' => $baseDir . '/src/Cms/Api.php',
'Kirby\\Cms\\App' => $baseDir . '/src/Cms/App.php',
'Kirby\\Cms\\AppCaches' => $baseDir . '/src/Cms/AppCaches.php',
'Kirby\\Cms\\AppErrors' => $baseDir . '/src/Cms/AppErrors.php',
'Kirby\\Cms\\AppPlugins' => $baseDir . '/src/Cms/AppPlugins.php',
'Kirby\\Cms\\AppTranslations' => $baseDir . '/src/Cms/AppTranslations.php',
'Kirby\\Cms\\AppUsers' => $baseDir . '/src/Cms/AppUsers.php',
'Kirby\\Cms\\Auth' => $baseDir . '/src/Cms/Auth.php',
'Kirby\\Cms\\Auth\\Challenge' => $baseDir . '/src/Cms/Auth/Challenge.php',
'Kirby\\Cms\\Auth\\EmailChallenge' => $baseDir . '/src/Cms/Auth/EmailChallenge.php',
'Kirby\\Cms\\Auth\\Status' => $baseDir . '/src/Cms/Auth/Status.php',
'Kirby\\Cms\\Auth\\TotpChallenge' => $baseDir . '/src/Cms/Auth/TotpChallenge.php',
'Kirby\\Cms\\Block' => $baseDir . '/src/Cms/Block.php',
'Kirby\\Cms\\BlockConverter' => $baseDir . '/src/Cms/BlockConverter.php',
'Kirby\\Cms\\Blocks' => $baseDir . '/src/Cms/Blocks.php',
'Kirby\\Cms\\Blueprint' => $baseDir . '/src/Cms/Blueprint.php',
'Kirby\\Cms\\Collection' => $baseDir . '/src/Cms/Collection.php',
'Kirby\\Cms\\Collections' => $baseDir . '/src/Cms/Collections.php',
'Kirby\\Cms\\Core' => $baseDir . '/src/Cms/Core.php',
'Kirby\\Cms\\Cors' => $baseDir . '/src/Cms/Cors.php',
'Kirby\\Cms\\Email' => $baseDir . '/src/Cms/Email.php',
'Kirby\\Cms\\Event' => $baseDir . '/src/Cms/Event.php',
'Kirby\\Cms\\Events' => $baseDir . '/src/Cms/Events.php',
'Kirby\\Cms\\Fieldset' => $baseDir . '/src/Cms/Fieldset.php',
'Kirby\\Cms\\Fieldsets' => $baseDir . '/src/Cms/Fieldsets.php',
'Kirby\\Cms\\File' => $baseDir . '/src/Cms/File.php',
'Kirby\\Cms\\FileActions' => $baseDir . '/src/Cms/FileActions.php',
'Kirby\\Cms\\FileBlueprint' => $baseDir . '/src/Cms/FileBlueprint.php',
'Kirby\\Cms\\FileModifications' => $baseDir . '/src/Cms/FileModifications.php',
'Kirby\\Cms\\FilePermissions' => $baseDir . '/src/Cms/FilePermissions.php',
'Kirby\\Cms\\FilePicker' => $baseDir . '/src/Cms/FilePicker.php',
'Kirby\\Cms\\FileRules' => $baseDir . '/src/Cms/FileRules.php',
'Kirby\\Cms\\FileVersion' => $baseDir . '/src/Cms/FileVersion.php',
'Kirby\\Cms\\Files' => $baseDir . '/src/Cms/Files.php',
'Kirby\\Cms\\Find' => $baseDir . '/src/Cms/Find.php',
'Kirby\\Cms\\HasChildren' => $baseDir . '/src/Cms/HasChildren.php',
'Kirby\\Cms\\HasFiles' => $baseDir . '/src/Cms/HasFiles.php',
'Kirby\\Cms\\HasMethods' => $baseDir . '/src/Cms/HasMethods.php',
'Kirby\\Cms\\HasModels' => $baseDir . '/src/Cms/HasModels.php',
'Kirby\\Cms\\HasSiblings' => $baseDir . '/src/Cms/HasSiblings.php',
'Kirby\\Cms\\Helpers' => $baseDir . '/src/Cms/Helpers.php',
'Kirby\\Cms\\Html' => $baseDir . '/src/Cms/Html.php',
'Kirby\\Cms\\Ingredients' => $baseDir . '/src/Cms/Ingredients.php',
'Kirby\\Cms\\Item' => $baseDir . '/src/Cms/Item.php',
'Kirby\\Cms\\Items' => $baseDir . '/src/Cms/Items.php',
'Kirby\\Cms\\Language' => $baseDir . '/src/Cms/Language.php',
'Kirby\\Cms\\LanguagePermissions' => $baseDir . '/src/Cms/LanguagePermissions.php',
'Kirby\\Cms\\LanguageRouter' => $baseDir . '/src/Cms/LanguageRouter.php',
'Kirby\\Cms\\LanguageRoutes' => $baseDir . '/src/Cms/LanguageRoutes.php',
'Kirby\\Cms\\LanguageRules' => $baseDir . '/src/Cms/LanguageRules.php',
'Kirby\\Cms\\LanguageVariable' => $baseDir . '/src/Cms/LanguageVariable.php',
'Kirby\\Cms\\Languages' => $baseDir . '/src/Cms/Languages.php',
'Kirby\\Cms\\Layout' => $baseDir . '/src/Cms/Layout.php',
'Kirby\\Cms\\LayoutColumn' => $baseDir . '/src/Cms/LayoutColumn.php',
'Kirby\\Cms\\LayoutColumns' => $baseDir . '/src/Cms/LayoutColumns.php',
'Kirby\\Cms\\Layouts' => $baseDir . '/src/Cms/Layouts.php',
'Kirby\\Cms\\License' => $baseDir . '/src/Cms/License.php',
'Kirby\\Cms\\LicenseStatus' => $baseDir . '/src/Cms/LicenseStatus.php',
'Kirby\\Cms\\LicenseType' => $baseDir . '/src/Cms/LicenseType.php',
'Kirby\\Cms\\Loader' => $baseDir . '/src/Cms/Loader.php',
'Kirby\\Cms\\Media' => $baseDir . '/src/Cms/Media.php',
'Kirby\\Cms\\ModelCommit' => $baseDir . '/src/Cms/ModelCommit.php',
'Kirby\\Cms\\ModelPermissions' => $baseDir . '/src/Cms/ModelPermissions.php',
'Kirby\\Cms\\ModelState' => $baseDir . '/src/Cms/ModelState.php',
'Kirby\\Cms\\ModelWithContent' => $baseDir . '/src/Cms/ModelWithContent.php',
'Kirby\\Cms\\Nest' => $baseDir . '/src/Cms/Nest.php',
'Kirby\\Cms\\NestCollection' => $baseDir . '/src/Cms/NestCollection.php',
'Kirby\\Cms\\NestObject' => $baseDir . '/src/Cms/NestObject.php',
'Kirby\\Cms\\Page' => $baseDir . '/src/Cms/Page.php',
'Kirby\\Cms\\PageActions' => $baseDir . '/src/Cms/PageActions.php',
'Kirby\\Cms\\PageBlueprint' => $baseDir . '/src/Cms/PageBlueprint.php',
'Kirby\\Cms\\PageCopy' => $baseDir . '/src/Cms/PageCopy.php',
'Kirby\\Cms\\PagePermissions' => $baseDir . '/src/Cms/PagePermissions.php',
'Kirby\\Cms\\PagePicker' => $baseDir . '/src/Cms/PagePicker.php',
'Kirby\\Cms\\PageRules' => $baseDir . '/src/Cms/PageRules.php',
'Kirby\\Cms\\PageSiblings' => $baseDir . '/src/Cms/PageSiblings.php',
'Kirby\\Cms\\Pages' => $baseDir . '/src/Cms/Pages.php',
'Kirby\\Cms\\Pagination' => $baseDir . '/src/Cms/Pagination.php',
'Kirby\\Cms\\Permissions' => $baseDir . '/src/Cms/Permissions.php',
'Kirby\\Cms\\Picker' => $baseDir . '/src/Cms/Picker.php',
'Kirby\\Cms\\R' => $baseDir . '/src/Cms/R.php',
'Kirby\\Cms\\Responder' => $baseDir . '/src/Cms/Responder.php',
'Kirby\\Cms\\Response' => $baseDir . '/src/Cms/Response.php',
'Kirby\\Cms\\Role' => $baseDir . '/src/Cms/Role.php',
'Kirby\\Cms\\Roles' => $baseDir . '/src/Cms/Roles.php',
'Kirby\\Cms\\S' => $baseDir . '/src/Cms/S.php',
'Kirby\\Cms\\Search' => $baseDir . '/src/Cms/Search.php',
'Kirby\\Cms\\Section' => $baseDir . '/src/Cms/Section.php',
'Kirby\\Cms\\Site' => $baseDir . '/src/Cms/Site.php',
'Kirby\\Cms\\SiteActions' => $baseDir . '/src/Cms/SiteActions.php',
'Kirby\\Cms\\SiteBlueprint' => $baseDir . '/src/Cms/SiteBlueprint.php',
'Kirby\\Cms\\SitePermissions' => $baseDir . '/src/Cms/SitePermissions.php',
'Kirby\\Cms\\SiteRules' => $baseDir . '/src/Cms/SiteRules.php',
'Kirby\\Cms\\Structure' => $baseDir . '/src/Cms/Structure.php',
'Kirby\\Cms\\StructureObject' => $baseDir . '/src/Cms/StructureObject.php',
'Kirby\\Cms\\System' => $baseDir . '/src/Cms/System.php',
'Kirby\\Cms\\System\\UpdateStatus' => $baseDir . '/src/Cms/System/UpdateStatus.php',
'Kirby\\Cms\\Translation' => $baseDir . '/src/Cms/Translation.php',
'Kirby\\Cms\\Translations' => $baseDir . '/src/Cms/Translations.php',
'Kirby\\Cms\\Url' => $baseDir . '/src/Cms/Url.php',
'Kirby\\Cms\\User' => $baseDir . '/src/Cms/User.php',
'Kirby\\Cms\\UserActions' => $baseDir . '/src/Cms/UserActions.php',
'Kirby\\Cms\\UserBlueprint' => $baseDir . '/src/Cms/UserBlueprint.php',
'Kirby\\Cms\\UserPermissions' => $baseDir . '/src/Cms/UserPermissions.php',
'Kirby\\Cms\\UserPicker' => $baseDir . '/src/Cms/UserPicker.php',
'Kirby\\Cms\\UserRules' => $baseDir . '/src/Cms/UserRules.php',
'Kirby\\Cms\\Users' => $baseDir . '/src/Cms/Users.php',
'Kirby\\Cms\\Visitor' => $baseDir . '/src/Cms/Visitor.php',
'Kirby\\ComposerInstaller\\CmsInstaller' => $vendorDir . '/getkirby/composer-installer/src/ComposerInstaller/CmsInstaller.php',
'Kirby\\ComposerInstaller\\Installer' => $vendorDir . '/getkirby/composer-installer/src/ComposerInstaller/Installer.php',
'Kirby\\ComposerInstaller\\Plugin' => $vendorDir . '/getkirby/composer-installer/src/ComposerInstaller/Plugin.php',
'Kirby\\ComposerInstaller\\PluginInstaller' => $vendorDir . '/getkirby/composer-installer/src/ComposerInstaller/PluginInstaller.php',
'Kirby\\Content\\Changes' => $baseDir . '/src/Content/Changes.php',
'Kirby\\Content\\Content' => $baseDir . '/src/Content/Content.php',
'Kirby\\Content\\Field' => $baseDir . '/src/Content/Field.php',
'Kirby\\Content\\ImmutableMemoryStorage' => $baseDir . '/src/Content/ImmutableMemoryStorage.php',
'Kirby\\Content\\Lock' => $baseDir . '/src/Content/Lock.php',
'Kirby\\Content\\LockedContentException' => $baseDir . '/src/Content/LockedContentException.php',
'Kirby\\Content\\MemoryStorage' => $baseDir . '/src/Content/MemoryStorage.php',
'Kirby\\Content\\PlainTextStorage' => $baseDir . '/src/Content/PlainTextStorage.php',
'Kirby\\Content\\Storage' => $baseDir . '/src/Content/Storage.php',
'Kirby\\Content\\Translation' => $baseDir . '/src/Content/Translation.php',
'Kirby\\Content\\Translations' => $baseDir . '/src/Content/Translations.php',
'Kirby\\Content\\Version' => $baseDir . '/src/Content/Version.php',
'Kirby\\Content\\VersionCache' => $baseDir . '/src/Content/VersionCache.php',
'Kirby\\Content\\VersionId' => $baseDir . '/src/Content/VersionId.php',
'Kirby\\Content\\VersionRules' => $baseDir . '/src/Content/VersionRules.php',
'Kirby\\Content\\Versions' => $baseDir . '/src/Content/Versions.php',
'Kirby\\Data\\Data' => $baseDir . '/src/Data/Data.php',
'Kirby\\Data\\Handler' => $baseDir . '/src/Data/Handler.php',
'Kirby\\Data\\Json' => $baseDir . '/src/Data/Json.php',
'Kirby\\Data\\PHP' => $baseDir . '/src/Data/PHP.php',
'Kirby\\Data\\Txt' => $baseDir . '/src/Data/Txt.php',
'Kirby\\Data\\Xml' => $baseDir . '/src/Data/Xml.php',
'Kirby\\Data\\Yaml' => $baseDir . '/src/Data/Yaml.php',
'Kirby\\Data\\YamlSpyc' => $baseDir . '/src/Data/YamlSpyc.php',
'Kirby\\Data\\YamlSymfony' => $baseDir . '/src/Data/YamlSymfony.php',
'Kirby\\Database\\Database' => $baseDir . '/src/Database/Database.php',
'Kirby\\Database\\Db' => $baseDir . '/src/Database/Db.php',
'Kirby\\Database\\Query' => $baseDir . '/src/Database/Query.php',
'Kirby\\Database\\Sql' => $baseDir . '/src/Database/Sql.php',
'Kirby\\Database\\Sql\\Mysql' => $baseDir . '/src/Database/Sql/Mysql.php',
'Kirby\\Database\\Sql\\Sqlite' => $baseDir . '/src/Database/Sql/Sqlite.php',
'Kirby\\Email\\Body' => $baseDir . '/src/Email/Body.php',
'Kirby\\Email\\Email' => $baseDir . '/src/Email/Email.php',
'Kirby\\Email\\PHPMailer' => $baseDir . '/src/Email/PHPMailer.php',
'Kirby\\Exception\\AuthException' => $baseDir . '/src/Exception/AuthException.php',
'Kirby\\Exception\\BadMethodCallException' => $baseDir . '/src/Exception/BadMethodCallException.php',
'Kirby\\Exception\\DuplicateException' => $baseDir . '/src/Exception/DuplicateException.php',
'Kirby\\Exception\\ErrorPageException' => $baseDir . '/src/Exception/ErrorPageException.php',
'Kirby\\Exception\\Exception' => $baseDir . '/src/Exception/Exception.php',
'Kirby\\Exception\\InvalidArgumentException' => $baseDir . '/src/Exception/InvalidArgumentException.php',
'Kirby\\Exception\\LogicException' => $baseDir . '/src/Exception/LogicException.php',
'Kirby\\Exception\\NotFoundException' => $baseDir . '/src/Exception/NotFoundException.php',
'Kirby\\Exception\\PermissionException' => $baseDir . '/src/Exception/PermissionException.php',
'Kirby\\Field\\FieldOptions' => $baseDir . '/src/Field/FieldOptions.php',
'Kirby\\Filesystem\\Asset' => $baseDir . '/src/Filesystem/Asset.php',
'Kirby\\Filesystem\\Dir' => $baseDir . '/src/Filesystem/Dir.php',
'Kirby\\Filesystem\\F' => $baseDir . '/src/Filesystem/F.php',
'Kirby\\Filesystem\\File' => $baseDir . '/src/Filesystem/File.php',
'Kirby\\Filesystem\\Filename' => $baseDir . '/src/Filesystem/Filename.php',
'Kirby\\Filesystem\\IsFile' => $baseDir . '/src/Filesystem/IsFile.php',
'Kirby\\Filesystem\\Mime' => $baseDir . '/src/Filesystem/Mime.php',
'Kirby\\Form\\Field' => $baseDir . '/src/Form/Field.php',
'Kirby\\Form\\FieldClass' => $baseDir . '/src/Form/FieldClass.php',
'Kirby\\Form\\Field\\BlocksField' => $baseDir . '/src/Form/Field/BlocksField.php',
'Kirby\\Form\\Field\\EntriesField' => $baseDir . '/src/Form/Field/EntriesField.php',
'Kirby\\Form\\Field\\LayoutField' => $baseDir . '/src/Form/Field/LayoutField.php',
'Kirby\\Form\\Field\\StatsField' => $baseDir . '/src/Form/Field/StatsField.php',
'Kirby\\Form\\Fields' => $baseDir . '/src/Form/Fields.php',
'Kirby\\Form\\Form' => $baseDir . '/src/Form/Form.php',
'Kirby\\Form\\Mixin\\After' => $baseDir . '/src/Form/Mixin/After.php',
'Kirby\\Form\\Mixin\\Api' => $baseDir . '/src/Form/Mixin/Api.php',
'Kirby\\Form\\Mixin\\Autofocus' => $baseDir . '/src/Form/Mixin/Autofocus.php',
'Kirby\\Form\\Mixin\\Before' => $baseDir . '/src/Form/Mixin/Before.php',
'Kirby\\Form\\Mixin\\EmptyState' => $baseDir . '/src/Form/Mixin/EmptyState.php',
'Kirby\\Form\\Mixin\\Help' => $baseDir . '/src/Form/Mixin/Help.php',
'Kirby\\Form\\Mixin\\Icon' => $baseDir . '/src/Form/Mixin/Icon.php',
'Kirby\\Form\\Mixin\\Label' => $baseDir . '/src/Form/Mixin/Label.php',
'Kirby\\Form\\Mixin\\Max' => $baseDir . '/src/Form/Mixin/Max.php',
'Kirby\\Form\\Mixin\\Min' => $baseDir . '/src/Form/Mixin/Min.php',
'Kirby\\Form\\Mixin\\Model' => $baseDir . '/src/Form/Mixin/Model.php',
'Kirby\\Form\\Mixin\\Placeholder' => $baseDir . '/src/Form/Mixin/Placeholder.php',
'Kirby\\Form\\Mixin\\Translatable' => $baseDir . '/src/Form/Mixin/Translatable.php',
'Kirby\\Form\\Mixin\\Validation' => $baseDir . '/src/Form/Mixin/Validation.php',
'Kirby\\Form\\Mixin\\Value' => $baseDir . '/src/Form/Mixin/Value.php',
'Kirby\\Form\\Mixin\\When' => $baseDir . '/src/Form/Mixin/When.php',
'Kirby\\Form\\Mixin\\Width' => $baseDir . '/src/Form/Mixin/Width.php',
'Kirby\\Form\\Validations' => $baseDir . '/src/Form/Validations.php',
'Kirby\\Http\\Cookie' => $baseDir . '/src/Http/Cookie.php',
'Kirby\\Http\\Environment' => $baseDir . '/src/Http/Environment.php',
'Kirby\\Http\\Exceptions\\NextRouteException' => $baseDir . '/src/Http/Exceptions/NextRouteException.php',
'Kirby\\Http\\Header' => $baseDir . '/src/Http/Header.php',
'Kirby\\Http\\Idn' => $baseDir . '/src/Http/Idn.php',
'Kirby\\Http\\Params' => $baseDir . '/src/Http/Params.php',
'Kirby\\Http\\Path' => $baseDir . '/src/Http/Path.php',
'Kirby\\Http\\Query' => $baseDir . '/src/Http/Query.php',
'Kirby\\Http\\Remote' => $baseDir . '/src/Http/Remote.php',
'Kirby\\Http\\Request' => $baseDir . '/src/Http/Request.php',
'Kirby\\Http\\Request\\Auth' => $baseDir . '/src/Http/Request/Auth.php',
'Kirby\\Http\\Request\\Auth\\BasicAuth' => $baseDir . '/src/Http/Request/Auth/BasicAuth.php',
'Kirby\\Http\\Request\\Auth\\BearerAuth' => $baseDir . '/src/Http/Request/Auth/BearerAuth.php',
'Kirby\\Http\\Request\\Auth\\SessionAuth' => $baseDir . '/src/Http/Request/Auth/SessionAuth.php',
'Kirby\\Http\\Request\\Body' => $baseDir . '/src/Http/Request/Body.php',
'Kirby\\Http\\Request\\Data' => $baseDir . '/src/Http/Request/Data.php',
'Kirby\\Http\\Request\\Files' => $baseDir . '/src/Http/Request/Files.php',
'Kirby\\Http\\Request\\Query' => $baseDir . '/src/Http/Request/Query.php',
'Kirby\\Http\\Response' => $baseDir . '/src/Http/Response.php',
'Kirby\\Http\\Route' => $baseDir . '/src/Http/Route.php',
'Kirby\\Http\\Router' => $baseDir . '/src/Http/Router.php',
'Kirby\\Http\\Uri' => $baseDir . '/src/Http/Uri.php',
'Kirby\\Http\\Url' => $baseDir . '/src/Http/Url.php',
'Kirby\\Http\\Visitor' => $baseDir . '/src/Http/Visitor.php',
'Kirby\\Image\\Camera' => $baseDir . '/src/Image/Camera.php',
'Kirby\\Image\\Darkroom' => $baseDir . '/src/Image/Darkroom.php',
'Kirby\\Image\\Darkroom\\GdLib' => $baseDir . '/src/Image/Darkroom/GdLib.php',
'Kirby\\Image\\Darkroom\\ImageMagick' => $baseDir . '/src/Image/Darkroom/ImageMagick.php',
'Kirby\\Image\\Darkroom\\Imagick' => $baseDir . '/src/Image/Darkroom/Imagick.php',
'Kirby\\Image\\Dimensions' => $baseDir . '/src/Image/Dimensions.php',
'Kirby\\Image\\Exif' => $baseDir . '/src/Image/Exif.php',
'Kirby\\Image\\Focus' => $baseDir . '/src/Image/Focus.php',
'Kirby\\Image\\Gravity' => $baseDir . '/src/Image/Gravity.php',
'Kirby\\Image\\Image' => $baseDir . '/src/Image/Image.php',
'Kirby\\Image\\Location' => $baseDir . '/src/Image/Location.php',
'Kirby\\Image\\QrCode' => $baseDir . '/src/Image/QrCode.php',
'Kirby\\Option\\Option' => $baseDir . '/src/Option/Option.php',
'Kirby\\Option\\Options' => $baseDir . '/src/Option/Options.php',
'Kirby\\Option\\OptionsApi' => $baseDir . '/src/Option/OptionsApi.php',
'Kirby\\Option\\OptionsProvider' => $baseDir . '/src/Option/OptionsProvider.php',
'Kirby\\Option\\OptionsQuery' => $baseDir . '/src/Option/OptionsQuery.php',
'Kirby\\Panel\\Assets' => $baseDir . '/src/Panel/Assets.php',
'Kirby\\Panel\\ChangesDialog' => $baseDir . '/src/Panel/ChangesDialog.php',
'Kirby\\Panel\\Collector\\FilesCollector' => $baseDir . '/src/Panel/Collector/FilesCollector.php',
'Kirby\\Panel\\Collector\\ModelsCollector' => $baseDir . '/src/Panel/Collector/ModelsCollector.php',
'Kirby\\Panel\\Collector\\PagesCollector' => $baseDir . '/src/Panel/Collector/PagesCollector.php',
'Kirby\\Panel\\Collector\\UsersCollector' => $baseDir . '/src/Panel/Collector/UsersCollector.php',
'Kirby\\Panel\\Controller\\PageTree' => $baseDir . '/src/Panel/Controller/PageTree.php',
'Kirby\\Panel\\Controller\\Search' => $baseDir . '/src/Panel/Controller/Search.php',
'Kirby\\Panel\\Dialog' => $baseDir . '/src/Panel/Dialog.php',
'Kirby\\Panel\\Document' => $baseDir . '/src/Panel/Document.php',
'Kirby\\Panel\\Drawer' => $baseDir . '/src/Panel/Drawer.php',
'Kirby\\Panel\\Dropdown' => $baseDir . '/src/Panel/Dropdown.php',
'Kirby\\Panel\\Field' => $baseDir . '/src/Panel/Field.php',
'Kirby\\Panel\\File' => $baseDir . '/src/Panel/File.php',
'Kirby\\Panel\\Home' => $baseDir . '/src/Panel/Home.php',
'Kirby\\Panel\\Json' => $baseDir . '/src/Panel/Json.php',
'Kirby\\Panel\\Lab\\Category' => $baseDir . '/src/Panel/Lab/Category.php',
'Kirby\\Panel\\Lab\\Doc' => $baseDir . '/src/Panel/Lab/Doc.php',
'Kirby\\Panel\\Lab\\Doc\\Argument' => $baseDir . '/src/Panel/Lab/Doc/Argument.php',
'Kirby\\Panel\\Lab\\Doc\\Event' => $baseDir . '/src/Panel/Lab/Doc/Event.php',
'Kirby\\Panel\\Lab\\Doc\\Method' => $baseDir . '/src/Panel/Lab/Doc/Method.php',
'Kirby\\Panel\\Lab\\Doc\\Prop' => $baseDir . '/src/Panel/Lab/Doc/Prop.php',
'Kirby\\Panel\\Lab\\Doc\\Slot' => $baseDir . '/src/Panel/Lab/Doc/Slot.php',
'Kirby\\Panel\\Lab\\Docs' => $baseDir . '/src/Panel/Lab/Docs.php',
'Kirby\\Panel\\Lab\\Example' => $baseDir . '/src/Panel/Lab/Example.php',
'Kirby\\Panel\\Lab\\Responses' => $baseDir . '/src/Panel/Lab/Responses.php',
'Kirby\\Panel\\Lab\\Snippet' => $baseDir . '/src/Panel/Lab/Snippet.php',
'Kirby\\Panel\\Lab\\Template' => $baseDir . '/src/Panel/Lab/Template.php',
'Kirby\\Panel\\Menu' => $baseDir . '/src/Panel/Menu.php',
'Kirby\\Panel\\Model' => $baseDir . '/src/Panel/Model.php',
'Kirby\\Panel\\Page' => $baseDir . '/src/Panel/Page.php',
'Kirby\\Panel\\PageCreateDialog' => $baseDir . '/src/Panel/PageCreateDialog.php',
'Kirby\\Panel\\Panel' => $baseDir . '/src/Panel/Panel.php',
'Kirby\\Panel\\Plugins' => $baseDir . '/src/Panel/Plugins.php',
'Kirby\\Panel\\Redirect' => $baseDir . '/src/Panel/Redirect.php',
'Kirby\\Panel\\Request' => $baseDir . '/src/Panel/Request.php',
'Kirby\\Panel\\Search' => $baseDir . '/src/Panel/Search.php',
'Kirby\\Panel\\Site' => $baseDir . '/src/Panel/Site.php',
'Kirby\\Panel\\Ui\\Button' => $baseDir . '/src/Panel/Ui/Button.php',
'Kirby\\Panel\\Ui\\Buttons\\LanguageCreateButton' => $baseDir . '/src/Panel/Ui/Buttons/LanguageCreateButton.php',
'Kirby\\Panel\\Ui\\Buttons\\LanguageDeleteButton' => $baseDir . '/src/Panel/Ui/Buttons/LanguageDeleteButton.php',
'Kirby\\Panel\\Ui\\Buttons\\LanguageSettingsButton' => $baseDir . '/src/Panel/Ui/Buttons/LanguageSettingsButton.php',
'Kirby\\Panel\\Ui\\Buttons\\LanguagesDropdown' => $baseDir . '/src/Panel/Ui/Buttons/LanguagesDropdown.php',
'Kirby\\Panel\\Ui\\Buttons\\OpenButton' => $baseDir . '/src/Panel/Ui/Buttons/OpenButton.php',
'Kirby\\Panel\\Ui\\Buttons\\PageStatusButton' => $baseDir . '/src/Panel/Ui/Buttons/PageStatusButton.php',
'Kirby\\Panel\\Ui\\Buttons\\PreviewButton' => $baseDir . '/src/Panel/Ui/Buttons/PreviewButton.php',
'Kirby\\Panel\\Ui\\Buttons\\SettingsButton' => $baseDir . '/src/Panel/Ui/Buttons/SettingsButton.php',
'Kirby\\Panel\\Ui\\Buttons\\VersionsButton' => $baseDir . '/src/Panel/Ui/Buttons/VersionsButton.php',
'Kirby\\Panel\\Ui\\Buttons\\ViewButton' => $baseDir . '/src/Panel/Ui/Buttons/ViewButton.php',
'Kirby\\Panel\\Ui\\Buttons\\ViewButtons' => $baseDir . '/src/Panel/Ui/Buttons/ViewButtons.php',
'Kirby\\Panel\\Ui\\Component' => $baseDir . '/src/Panel/Ui/Component.php',
'Kirby\\Panel\\Ui\\FilePreview' => $baseDir . '/src/Panel/Ui/FilePreview.php',
'Kirby\\Panel\\Ui\\FilePreviews\\AudioFilePreview' => $baseDir . '/src/Panel/Ui/FilePreviews/AudioFilePreview.php',
'Kirby\\Panel\\Ui\\FilePreviews\\DefaultFilePreview' => $baseDir . '/src/Panel/Ui/FilePreviews/DefaultFilePreview.php',
'Kirby\\Panel\\Ui\\FilePreviews\\ImageFilePreview' => $baseDir . '/src/Panel/Ui/FilePreviews/ImageFilePreview.php',
'Kirby\\Panel\\Ui\\FilePreviews\\PdfFilePreview' => $baseDir . '/src/Panel/Ui/FilePreviews/PdfFilePreview.php',
'Kirby\\Panel\\Ui\\FilePreviews\\VideoFilePreview' => $baseDir . '/src/Panel/Ui/FilePreviews/VideoFilePreview.php',
'Kirby\\Panel\\Ui\\Item\\FileItem' => $baseDir . '/src/Panel/Ui/Item/FileItem.php',
'Kirby\\Panel\\Ui\\Item\\ModelItem' => $baseDir . '/src/Panel/Ui/Item/ModelItem.php',
'Kirby\\Panel\\Ui\\Item\\PageItem' => $baseDir . '/src/Panel/Ui/Item/PageItem.php',
'Kirby\\Panel\\Ui\\Item\\UserItem' => $baseDir . '/src/Panel/Ui/Item/UserItem.php',
'Kirby\\Panel\\Ui\\Stat' => $baseDir . '/src/Panel/Ui/Stat.php',
'Kirby\\Panel\\Ui\\Stats' => $baseDir . '/src/Panel/Ui/Stats.php',
'Kirby\\Panel\\Ui\\Upload' => $baseDir . '/src/Panel/Ui/Upload.php',
'Kirby\\Panel\\User' => $baseDir . '/src/Panel/User.php',
'Kirby\\Panel\\UserTotpDisableDialog' => $baseDir . '/src/Panel/UserTotpDisableDialog.php',
'Kirby\\Panel\\UserTotpEnableDialog' => $baseDir . '/src/Panel/UserTotpEnableDialog.php',
'Kirby\\Panel\\View' => $baseDir . '/src/Panel/View.php',
'Kirby\\Parsley\\Element' => $baseDir . '/src/Parsley/Element.php',
'Kirby\\Parsley\\Inline' => $baseDir . '/src/Parsley/Inline.php',
'Kirby\\Parsley\\Parsley' => $baseDir . '/src/Parsley/Parsley.php',
'Kirby\\Parsley\\Schema' => $baseDir . '/src/Parsley/Schema.php',
'Kirby\\Parsley\\Schema\\Blocks' => $baseDir . '/src/Parsley/Schema/Blocks.php',
'Kirby\\Parsley\\Schema\\Plain' => $baseDir . '/src/Parsley/Schema/Plain.php',
'Kirby\\Plugin\\Asset' => $baseDir . '/src/Plugin/Asset.php',
'Kirby\\Plugin\\Assets' => $baseDir . '/src/Plugin/Assets.php',
'Kirby\\Plugin\\License' => $baseDir . '/src/Plugin/License.php',
'Kirby\\Plugin\\LicenseStatus' => $baseDir . '/src/Plugin/LicenseStatus.php',
'Kirby\\Plugin\\Plugin' => $baseDir . '/src/Plugin/Plugin.php',
'Kirby\\Query\\AST\\ArgumentListNode' => $baseDir . '/src/Query/AST/ArgumentListNode.php',
'Kirby\\Query\\AST\\ArithmeticNode' => $baseDir . '/src/Query/AST/ArithmeticNode.php',
'Kirby\\Query\\AST\\ArrayListNode' => $baseDir . '/src/Query/AST/ArrayListNode.php',
'Kirby\\Query\\AST\\ClosureNode' => $baseDir . '/src/Query/AST/ClosureNode.php',
'Kirby\\Query\\AST\\CoalesceNode' => $baseDir . '/src/Query/AST/CoalesceNode.php',
'Kirby\\Query\\AST\\ComparisonNode' => $baseDir . '/src/Query/AST/ComparisonNode.php',
'Kirby\\Query\\AST\\GlobalFunctionNode' => $baseDir . '/src/Query/AST/GlobalFunctionNode.php',
'Kirby\\Query\\AST\\LiteralNode' => $baseDir . '/src/Query/AST/LiteralNode.php',
'Kirby\\Query\\AST\\LogicalNode' => $baseDir . '/src/Query/AST/LogicalNode.php',
'Kirby\\Query\\AST\\MemberAccessNode' => $baseDir . '/src/Query/AST/MemberAccessNode.php',
'Kirby\\Query\\AST\\Node' => $baseDir . '/src/Query/AST/Node.php',
'Kirby\\Query\\AST\\TernaryNode' => $baseDir . '/src/Query/AST/TernaryNode.php',
'Kirby\\Query\\AST\\VariableNode' => $baseDir . '/src/Query/AST/VariableNode.php',
'Kirby\\Query\\Argument' => $baseDir . '/src/Query/Argument.php',
'Kirby\\Query\\Arguments' => $baseDir . '/src/Query/Arguments.php',
'Kirby\\Query\\Expression' => $baseDir . '/src/Query/Expression.php',
'Kirby\\Query\\Parser\\Parser' => $baseDir . '/src/Query/Parser/Parser.php',
'Kirby\\Query\\Parser\\Token' => $baseDir . '/src/Query/Parser/Token.php',
'Kirby\\Query\\Parser\\TokenType' => $baseDir . '/src/Query/Parser/TokenType.php',
'Kirby\\Query\\Parser\\Tokenizer' => $baseDir . '/src/Query/Parser/Tokenizer.php',
'Kirby\\Query\\Query' => $baseDir . '/src/Query/Query.php',
'Kirby\\Query\\Runners\\DefaultRunner' => $baseDir . '/src/Query/Runners/DefaultRunner.php',
'Kirby\\Query\\Runners\\Runner' => $baseDir . '/src/Query/Runners/Runner.php',
'Kirby\\Query\\Runners\\Scope' => $baseDir . '/src/Query/Runners/Scope.php',
'Kirby\\Query\\Segment' => $baseDir . '/src/Query/Segment.php',
'Kirby\\Query\\Segments' => $baseDir . '/src/Query/Segments.php',
'Kirby\\Query\\Visitors\\DefaultVisitor' => $baseDir . '/src/Query/Visitors/DefaultVisitor.php',
'Kirby\\Query\\Visitors\\Visitor' => $baseDir . '/src/Query/Visitors/Visitor.php',
'Kirby\\Reflection\\Constructor' => $baseDir . '/src/Reflection/Constructor.php',
'Kirby\\Sane\\DomHandler' => $baseDir . '/src/Sane/DomHandler.php',
'Kirby\\Sane\\Handler' => $baseDir . '/src/Sane/Handler.php',
'Kirby\\Sane\\Html' => $baseDir . '/src/Sane/Html.php',
'Kirby\\Sane\\Sane' => $baseDir . '/src/Sane/Sane.php',
'Kirby\\Sane\\Svg' => $baseDir . '/src/Sane/Svg.php',
'Kirby\\Sane\\Svgz' => $baseDir . '/src/Sane/Svgz.php',
'Kirby\\Sane\\Xml' => $baseDir . '/src/Sane/Xml.php',
'Kirby\\Session\\AutoSession' => $baseDir . '/src/Session/AutoSession.php',
'Kirby\\Session\\FileSessionStore' => $baseDir . '/src/Session/FileSessionStore.php',
'Kirby\\Session\\Session' => $baseDir . '/src/Session/Session.php',
'Kirby\\Session\\SessionData' => $baseDir . '/src/Session/SessionData.php',
'Kirby\\Session\\SessionStore' => $baseDir . '/src/Session/SessionStore.php',
'Kirby\\Session\\Sessions' => $baseDir . '/src/Session/Sessions.php',
'Kirby\\Template\\Slot' => $baseDir . '/src/Template/Slot.php',
'Kirby\\Template\\Slots' => $baseDir . '/src/Template/Slots.php',
'Kirby\\Template\\Snippet' => $baseDir . '/src/Template/Snippet.php',
'Kirby\\Template\\Template' => $baseDir . '/src/Template/Template.php',
'Kirby\\Text\\KirbyTag' => $baseDir . '/src/Text/KirbyTag.php',
'Kirby\\Text\\KirbyTags' => $baseDir . '/src/Text/KirbyTags.php',
'Kirby\\Text\\Markdown' => $baseDir . '/src/Text/Markdown.php',
'Kirby\\Text\\SmartyPants' => $baseDir . '/src/Text/SmartyPants.php',
'Kirby\\Toolkit\\A' => $baseDir . '/src/Toolkit/A.php',
'Kirby\\Toolkit\\Collection' => $baseDir . '/src/Toolkit/Collection.php',
'Kirby\\Toolkit\\Component' => $baseDir . '/src/Toolkit/Component.php',
'Kirby\\Toolkit\\Config' => $baseDir . '/src/Toolkit/Config.php',
'Kirby\\Toolkit\\Controller' => $baseDir . '/src/Toolkit/Controller.php',
'Kirby\\Toolkit\\Date' => $baseDir . '/src/Toolkit/Date.php',
'Kirby\\Toolkit\\Dom' => $baseDir . '/src/Toolkit/Dom.php',
'Kirby\\Toolkit\\Escape' => $baseDir . '/src/Toolkit/Escape.php',
'Kirby\\Toolkit\\Facade' => $baseDir . '/src/Toolkit/Facade.php',
'Kirby\\Toolkit\\Html' => $baseDir . '/src/Toolkit/Html.php',
'Kirby\\Toolkit\\I18n' => $baseDir . '/src/Toolkit/I18n.php',
'Kirby\\Toolkit\\Iterator' => $baseDir . '/src/Toolkit/Iterator.php',
'Kirby\\Toolkit\\LazyValue' => $baseDir . '/src/Toolkit/LazyValue.php',
'Kirby\\Toolkit\\Locale' => $baseDir . '/src/Toolkit/Locale.php',
'Kirby\\Toolkit\\Obj' => $baseDir . '/src/Toolkit/Obj.php',
'Kirby\\Toolkit\\Pagination' => $baseDir . '/src/Toolkit/Pagination.php',
'Kirby\\Toolkit\\Silo' => $baseDir . '/src/Toolkit/Silo.php',
'Kirby\\Toolkit\\Str' => $baseDir . '/src/Toolkit/Str.php',
'Kirby\\Toolkit\\SymmetricCrypto' => $baseDir . '/src/Toolkit/SymmetricCrypto.php',
'Kirby\\Toolkit\\Totp' => $baseDir . '/src/Toolkit/Totp.php',
'Kirby\\Toolkit\\Tpl' => $baseDir . '/src/Toolkit/Tpl.php',
'Kirby\\Toolkit\\V' => $baseDir . '/src/Toolkit/V.php',
'Kirby\\Toolkit\\View' => $baseDir . '/src/Toolkit/View.php',
'Kirby\\Toolkit\\Xml' => $baseDir . '/src/Toolkit/Xml.php',
'Kirby\\Uuid\\BlockUuid' => $baseDir . '/src/Uuid/BlockUuid.php',
'Kirby\\Uuid\\FieldUuid' => $baseDir . '/src/Uuid/FieldUuid.php',
'Kirby\\Uuid\\FileUuid' => $baseDir . '/src/Uuid/FileUuid.php',
'Kirby\\Uuid\\HasUuids' => $baseDir . '/src/Uuid/HasUuids.php',
'Kirby\\Uuid\\Identifiable' => $baseDir . '/src/Uuid/Identifiable.php',
'Kirby\\Uuid\\ModelUuid' => $baseDir . '/src/Uuid/ModelUuid.php',
'Kirby\\Uuid\\PageUuid' => $baseDir . '/src/Uuid/PageUuid.php',
'Kirby\\Uuid\\SiteUuid' => $baseDir . '/src/Uuid/SiteUuid.php',
'Kirby\\Uuid\\StructureUuid' => $baseDir . '/src/Uuid/StructureUuid.php',
'Kirby\\Uuid\\Uri' => $baseDir . '/src/Uuid/Uri.php',
'Kirby\\Uuid\\UserUuid' => $baseDir . '/src/Uuid/UserUuid.php',
'Kirby\\Uuid\\Uuid' => $baseDir . '/src/Uuid/Uuid.php',
'Kirby\\Uuid\\Uuids' => $baseDir . '/src/Uuid/Uuids.php',
'Laminas\\Escaper\\Escaper' => $vendorDir . '/laminas/laminas-escaper/src/Escaper.php',
'Laminas\\Escaper\\EscaperInterface' => $vendorDir . '/laminas/laminas-escaper/src/EscaperInterface.php',
'Laminas\\Escaper\\Exception\\ExceptionInterface' => $vendorDir . '/laminas/laminas-escaper/src/Exception/ExceptionInterface.php',
'Laminas\\Escaper\\Exception\\InvalidArgumentException' => $vendorDir . '/laminas/laminas-escaper/src/Exception/InvalidArgumentException.php',
'Laminas\\Escaper\\Exception\\RuntimeException' => $vendorDir . '/laminas/laminas-escaper/src/Exception/RuntimeException.php',
'League\\ColorExtractor\\Color' => $vendorDir . '/league/color-extractor/src/Color.php',
'League\\ColorExtractor\\ColorExtractor' => $vendorDir . '/league/color-extractor/src/ColorExtractor.php',
'League\\ColorExtractor\\Palette' => $vendorDir . '/league/color-extractor/src/Palette.php',
'Michelf\\SmartyPants' => $vendorDir . '/michelf/php-smartypants/Michelf/SmartyPants.php',
'Michelf\\SmartyPantsTypographer' => $vendorDir . '/michelf/php-smartypants/Michelf/SmartyPantsTypographer.php',
'Normalizer' => $vendorDir . '/symfony/polyfill-intl-normalizer/Resources/stubs/Normalizer.php',
'PHPMailer\\PHPMailer\\DSNConfigurator' => $vendorDir . '/phpmailer/phpmailer/src/DSNConfigurator.php',
'PHPMailer\\PHPMailer\\Exception' => $vendorDir . '/phpmailer/phpmailer/src/Exception.php',
'PHPMailer\\PHPMailer\\OAuth' => $vendorDir . '/phpmailer/phpmailer/src/OAuth.php',
'PHPMailer\\PHPMailer\\OAuthTokenProvider' => $vendorDir . '/phpmailer/phpmailer/src/OAuthTokenProvider.php',
'PHPMailer\\PHPMailer\\PHPMailer' => $vendorDir . '/phpmailer/phpmailer/src/PHPMailer.php',
'PHPMailer\\PHPMailer\\POP3' => $vendorDir . '/phpmailer/phpmailer/src/POP3.php',
'PHPMailer\\PHPMailer\\SMTP' => $vendorDir . '/phpmailer/phpmailer/src/SMTP.php',
'Parsedown' => $baseDir . '/dependencies/parsedown/Parsedown.php',
'ParsedownExtra' => $baseDir . '/dependencies/parsedown-extra/ParsedownExtra.php',
'Psr\\Log\\AbstractLogger' => $vendorDir . '/psr/log/src/AbstractLogger.php',
'Psr\\Log\\InvalidArgumentException' => $vendorDir . '/psr/log/src/InvalidArgumentException.php',
'Psr\\Log\\LogLevel' => $vendorDir . '/psr/log/src/LogLevel.php',
'Psr\\Log\\LoggerAwareInterface' => $vendorDir . '/psr/log/src/LoggerAwareInterface.php',
'Psr\\Log\\LoggerAwareTrait' => $vendorDir . '/psr/log/src/LoggerAwareTrait.php',
'Psr\\Log\\LoggerInterface' => $vendorDir . '/psr/log/src/LoggerInterface.php',
'Psr\\Log\\LoggerTrait' => $vendorDir . '/psr/log/src/LoggerTrait.php',
'Psr\\Log\\NullLogger' => $vendorDir . '/psr/log/src/NullLogger.php',
'Spyc' => $baseDir . '/dependencies/spyc/Spyc.php',
'Symfony\\Component\\Yaml\\Command\\LintCommand' => $vendorDir . '/symfony/yaml/Command/LintCommand.php',
'Symfony\\Component\\Yaml\\Dumper' => $vendorDir . '/symfony/yaml/Dumper.php',
'Symfony\\Component\\Yaml\\Escaper' => $vendorDir . '/symfony/yaml/Escaper.php',
'Symfony\\Component\\Yaml\\Exception\\DumpException' => $vendorDir . '/symfony/yaml/Exception/DumpException.php',
'Symfony\\Component\\Yaml\\Exception\\ExceptionInterface' => $vendorDir . '/symfony/yaml/Exception/ExceptionInterface.php',
'Symfony\\Component\\Yaml\\Exception\\ParseException' => $vendorDir . '/symfony/yaml/Exception/ParseException.php',
'Symfony\\Component\\Yaml\\Exception\\RuntimeException' => $vendorDir . '/symfony/yaml/Exception/RuntimeException.php',
'Symfony\\Component\\Yaml\\Inline' => $vendorDir . '/symfony/yaml/Inline.php',
'Symfony\\Component\\Yaml\\Parser' => $vendorDir . '/symfony/yaml/Parser.php',
'Symfony\\Component\\Yaml\\Tag\\TaggedValue' => $vendorDir . '/symfony/yaml/Tag/TaggedValue.php',
'Symfony\\Component\\Yaml\\Unescaper' => $vendorDir . '/symfony/yaml/Unescaper.php',
'Symfony\\Component\\Yaml\\Yaml' => $vendorDir . '/symfony/yaml/Yaml.php',
'Symfony\\Polyfill\\Ctype\\Ctype' => $vendorDir . '/symfony/polyfill-ctype/Ctype.php',
'Symfony\\Polyfill\\Intl\\Idn\\Idn' => $vendorDir . '/symfony/polyfill-intl-idn/Idn.php',
'Symfony\\Polyfill\\Intl\\Idn\\Info' => $vendorDir . '/symfony/polyfill-intl-idn/Info.php',
'Symfony\\Polyfill\\Intl\\Idn\\Resources\\unidata\\DisallowedRanges' => $vendorDir . '/symfony/polyfill-intl-idn/Resources/unidata/DisallowedRanges.php',
'Symfony\\Polyfill\\Intl\\Idn\\Resources\\unidata\\Regex' => $vendorDir . '/symfony/polyfill-intl-idn/Resources/unidata/Regex.php',
'Symfony\\Polyfill\\Intl\\Normalizer\\Normalizer' => $vendorDir . '/symfony/polyfill-intl-normalizer/Normalizer.php',
'Symfony\\Polyfill\\Mbstring\\Mbstring' => $vendorDir . '/symfony/polyfill-mbstring/Mbstring.php',
'Whoops\\Exception\\ErrorException' => $vendorDir . '/filp/whoops/src/Whoops/Exception/ErrorException.php',
'Whoops\\Exception\\Formatter' => $vendorDir . '/filp/whoops/src/Whoops/Exception/Formatter.php',
'Whoops\\Exception\\Frame' => $vendorDir . '/filp/whoops/src/Whoops/Exception/Frame.php',
'Whoops\\Exception\\FrameCollection' => $vendorDir . '/filp/whoops/src/Whoops/Exception/FrameCollection.php',
'Whoops\\Exception\\Inspector' => $vendorDir . '/filp/whoops/src/Whoops/Exception/Inspector.php',
'Whoops\\Handler\\CallbackHandler' => $vendorDir . '/filp/whoops/src/Whoops/Handler/CallbackHandler.php',
'Whoops\\Handler\\Handler' => $vendorDir . '/filp/whoops/src/Whoops/Handler/Handler.php',
'Whoops\\Handler\\HandlerInterface' => $vendorDir . '/filp/whoops/src/Whoops/Handler/HandlerInterface.php',
'Whoops\\Handler\\JsonResponseHandler' => $vendorDir . '/filp/whoops/src/Whoops/Handler/JsonResponseHandler.php',
'Whoops\\Handler\\PlainTextHandler' => $vendorDir . '/filp/whoops/src/Whoops/Handler/PlainTextHandler.php',
'Whoops\\Handler\\PrettyPageHandler' => $vendorDir . '/filp/whoops/src/Whoops/Handler/PrettyPageHandler.php',
'Whoops\\Handler\\XmlResponseHandler' => $vendorDir . '/filp/whoops/src/Whoops/Handler/XmlResponseHandler.php',
'Whoops\\Inspector\\InspectorFactory' => $vendorDir . '/filp/whoops/src/Whoops/Inspector/InspectorFactory.php',
'Whoops\\Inspector\\InspectorFactoryInterface' => $vendorDir . '/filp/whoops/src/Whoops/Inspector/InspectorFactoryInterface.php',
'Whoops\\Inspector\\InspectorInterface' => $vendorDir . '/filp/whoops/src/Whoops/Inspector/InspectorInterface.php',
'Whoops\\Run' => $vendorDir . '/filp/whoops/src/Whoops/Run.php',
'Whoops\\RunInterface' => $vendorDir . '/filp/whoops/src/Whoops/RunInterface.php',
'Whoops\\Util\\HtmlDumperOutput' => $vendorDir . '/filp/whoops/src/Whoops/Util/HtmlDumperOutput.php',
'Whoops\\Util\\Misc' => $vendorDir . '/filp/whoops/src/Whoops/Util/Misc.php',
'Whoops\\Util\\SystemFacade' => $vendorDir . '/filp/whoops/src/Whoops/Util/SystemFacade.php',
'Whoops\\Util\\TemplateHelper' => $vendorDir . '/filp/whoops/src/Whoops/Util/TemplateHelper.php',
'claviska\\SimpleImage' => $vendorDir . '/claviska/simpleimage/src/claviska/SimpleImage.php',
);

View file

@ -1,16 +0,0 @@
<?php
// autoload_files.php @generated by Composer
$vendorDir = dirname(__DIR__);
$baseDir = dirname($vendorDir);
return array(
'6e3fae29631ef280660b3cdad06f25a8' => $vendorDir . '/symfony/deprecation-contracts/function.php',
'320cde22f66dd4f5d3fd621d3e88b98f' => $vendorDir . '/symfony/polyfill-ctype/bootstrap.php',
'e69f7f6ee287b969198c3c9d6777bd38' => $vendorDir . '/symfony/polyfill-intl-normalizer/bootstrap.php',
'f598d06aa772fa33d905e87be6398fb1' => $vendorDir . '/symfony/polyfill-intl-idn/bootstrap.php',
'0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => $vendorDir . '/symfony/polyfill-mbstring/bootstrap.php',
'f864ae44e8154e5ff6f4eec32f46d37f' => $baseDir . '/config/setup.php',
'87988fc7b1c1f093da22a1a3de972f3a' => $baseDir . '/config/helpers.php',
);

View file

@ -1,11 +0,0 @@
<?php
// autoload_namespaces.php @generated by Composer
$vendorDir = dirname(__DIR__);
$baseDir = dirname($vendorDir);
return array(
'claviska' => array($vendorDir . '/claviska/simpleimage/src'),
'Michelf' => array($vendorDir . '/michelf/php-smartypants'),
);

Some files were not shown because too many files have changed in this diff Show more