Upgrade Chyrp Lite to "Oak"

This commit is contained in:
Helen Chong 2024-09-06 01:51:48 +08:00
parent b08bcd7a89
commit 583b3409d5
337 changed files with 8788 additions and 7328 deletions

106
README.md
View File

@ -1,8 +1,102 @@
# Leilukin's Tumbleblog
[English](README.md), [Deutsch](README_de_DE.md), [Italiano](README_it_IT.md), [한국인](README_ko_KR.md), [Nederlands](README_nl_NL.md), [简体中文](README_zh_CN.md).
Leilukin's tumbleblog. Built with [Chyrp Lite](https://chyrplite.net/).
## What can Chyrp Lite do for me?
I have made changes to the code to suit my purposes:
- Added my own favicon
- Added the Lexend and Intel One Mono typefaces
- Created my custom blog theme based on the Umbra theme
Chyrp Lite makes it possible to host a blog on your own web server with minimal fuss. You can have
a traditional blog, a tumbleblog, or you can add oodles of customisation and build a general-purpose
web publishing platform with blogging features on the side. You get five beautiful blog themes and
a friendly administration console, all fully navigable on a broad range of devices, thanks to the
power of responsive HTML5. Semantic markup and comprehensive ARIA labelling ensure your blog will be
accessible to visitors who use assistive technologies.
With a flexible system of Feathers and Pages, you can make your website whatever you want it to be.
Feathers enable different types of blog content you can restrict yourself to absolute textual purity,
or you can create a multimedia rainbow. Pages let you publish articles separate from your blog content
be it a simple colophon or a hierarchy of multiple pages, optionally including a homepage that your
visitors will see when they first arrive at your website.
## What are the key features?
#### Core:
* Easy to install, simple to maintain, extensible by design.
* Built with responsive and accessible W3C-validated HTML5.
* Universal support for plain text, Markdown, or raw markup.
* Personalise your blog using powerful extensions.
* Theme development is easy with the Twig template engine.
* Manage users and visitors with a comprehensive rights model.
#### Feathers:
* Text: write textual blog entries.
* Photo: upload an image.
* Quote: make a quotation.
* Link: link to another website.
* Video: upload a video file.
* Audio: upload an audio file.
* Uploader: upload multiple files.
#### Modules:
* Cacher: cache your blog pages for reduced server load.
* Categorize: give each of your blog entries a category.
* Tags: apply multiple searchable tags to your blog entries.
* Mentionable: register webmentions from blogs that link to yours.
* Comments: a comprehensive comments system for your blog.
* Likes: allow your visitors to show their appreciation.
* Read More: excerpt long blog entries on the blog index.
* Rights: set attribution and copyright/left for your entries.
* Cascade: ajax-powered infinite scrolling for your blog.
* Lightbox: on-page image viewer with image protection.
* Sitemap: index your blog for search engines.
* MAPTCHA: use simple mathematics problems to prevent spam.
* Highlighter: syntax highlighting for your code snippets.
* Easy Embed: the easiest way to embed videos in your blog.
* Post Views: maintain a view count for your blog entries.
* MathJax: a JavaScript display engine for mathematics.
## Requirements
* [PHP 8.0+](https://www.php.net/supported-versions.php) with default extensions (Session, JSON, Ctype, Filter, libxml, SimpleXML)
* [Multibyte String](https://www.php.net/manual/en/book.mbstring.php)
* [PDO](https://www.php.net/manual/en/book.pdo.php)
* [cURL](https://www.php.net/manual/en/book.curl.php)
* MySQL 5.7+
* SQLite 3+
* PostgreSQL 10+
## Installation
You can install Chyrp Lite in three steps:
1. If using MySQL, create a MySQL database with a username and password.
2. Download the [latest release](https://github.com/xenocrat/chyrp-lite/releases), unzip, and upload to your web server.
3. Run the installation process by visiting [install.php](install.php) in your web browser.
## Upgrading
You can upgrade Chyrp Lite in six steps:
1. __Backup your database before proceeding!__
2. Download the latest version of Chyrp Lite.
3. Move your _uploads_ folder and _includes/config.json.php_ somewhere safe.
4. Overwrite your current version with the new one.
5. Restore your _uploads_ folder and _includes/config.json.php_.
6. Run the upgrade process by visiting [upgrade.php](upgrade.php) in your web browser.
## Documentation
The Chyrp Lite [wiki](https://chyrplite.net/wiki/) has comprehensive documentation
for users and developers.
## Authors
Chyrp Lite was created by the following people:
* Lite Developer: Daniel Pimley
* Chyrp Developer: Arian Xhezairi
* Project Founder: Alex Suraci
* Module authors and other contributors.
## Licenses
Chyrp Lite is Copyright 2008-2024 Alex Suraci, Arian Xhezairi, Daniel Pimley, and other contributors,
distributed under the [BSD license](https://raw.githubusercontent.com/xenocrat/chyrp-lite/master/LICENSE.md).
Please see the [licenses](licenses) directory for the full license text of all software packages distributed with Chyrp Lite.

View File

@ -70,11 +70,11 @@ function toggle_all() {
}
// Validates slug fields.
function validate_slug() {
$("input[name='slug']").keyup(
$("input[pattern='^[a-z0-9\\\\-]*$']").keyup(
function(e) {
var slug = $(this).val();
if (/^([a-z0-9\-]*)$/.test(slug))
if (/^[a-z0-9\-]*$/.test(slug))
$(this).removeClass("error");
else
$(this).addClass("error");
@ -213,7 +213,7 @@ function test_uploads() {
if (file.size > Uploads.limit) {
e.target.value = null;
alert(Uploads.message);
alert(Uploads.messages.size_err);
break;
}
}
@ -240,7 +240,12 @@ var Oops = {
}
var Uploads = {
limit: <?php esce(intval($config->uploads_limit * 1000000)); ?>,
message: '<?php esce(_f("Maximum file size: %d Megabytes!", $config->uploads_limit)); ?>',
messages: {
send_msg: '<?php esce(__("Uploading...", "admin")); ?>',
send_err: '<?php esce(__("File upload failed!", "admin")); ?>',
type_err: '<?php esce(__("File type not supported!", "admin")); ?>',
size_err: '<?php esce(_f("Maximum file size: %d Megabytes!", $config->uploads_limit, "admin")); ?>'
},
active: 0,
send: function(file, doneCallback, failCallback, alwaysCallback) {
Uploads.active++;
@ -672,14 +677,20 @@ var Write = {
if (!!e.target.files && e.target.files.length > 0) {
var file = e.target.files[0];
// Reject files too large to upload.
if (file.size > Uploads.limit) {
e.target.value = null;
tray.html(Uploads.message);
// Reject files that are not images.
if (file.type.indexOf("image/") != 0) {
tray.html(Uploads.messages.type_err);
return;
}
tray.loader().html('<?php esce(__("Uploading...", "admin")); ?>');
// Reject files too large to upload.
if (file.size > Uploads.limit) {
e.target.value = null;
tray.html(Uploads.messages.size_err);
return;
}
tray.loader().html(Uploads.messages.send_msg);
// Upload the file and insert the tag if successful.
Uploads.send(
@ -688,7 +699,7 @@ var Write = {
Write.formatting(target, "img", response.data.url);
},
function(response) {
tray.html(Oops.message);
tray.html(Uploads.messages.send_err);
},
function(response) {
tray.loader(true);
@ -918,30 +929,34 @@ var Write = {
var form = new FormData();
var tray = $("#" + $(e.target).attr("id") + "_tray");
if (file.type.indexOf("image/") == 0) {
// Reject files too large to upload.
if (file.size > Uploads.limit) {
tray.html(Uploads.message);
return;
}
tray.loader().html('<?php esce(__("Uploading...", "admin")); ?>');
// Upload the file and insert the tag if successful.
Uploads.send(
file,
function(response) {
Write.formatting($(e.target), "img", response.data.url);
},
function(response) {
tray.html(Oops.message);
},
function(response) {
tray.loader(true);
$(e.target).removeClass("drag_highlight");
}
);
// Reject files that are not images.
if (file.type.indexOf("image/") != 0) {
tray.html(Uploads.messages.type_err);
return;
}
// Reject files too large to upload.
if (file.size > Uploads.limit) {
tray.html(Uploads.messages.size_err);
return;
}
tray.loader().html(Uploads.messages.send_msg);
// Upload the file and insert the tag if successful.
Uploads.send(
file,
function(response) {
Write.formatting($(e.target), "img", response.data.url);
},
function(response) {
tray.html(Uploads.messages.send_err);
},
function(response) {
tray.loader(true);
$(e.target).removeClass("drag_highlight");
}
);
}
},
formatting: function(target, effect, fragment = "") {

View File

@ -14,10 +14,9 @@
{{- " | " -}}
{{- site.name | fix -}}
</title>
<link rel="apple-touch-icon" sizes="180x180" href="{{ site.chyrp_url }}/favicon/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="{{ site.chyrp_url }}/favicon/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="{{ site.chyrp_url }}/favicon/favicon-16x16.png">
<link rel="manifest" href="{{ site.chyrp_url }}/favicon/site.webmanifest">
<link rel="icon" sizes="32x32" type="image/x-icon" href="{{ site.chyrp_url }}/favicon.ico">
<link rel="icon" sizes="any" type="image/svg+xml" href="{{ site.chyrp_url }}/favicon.svg">
<link rel="mask-icon" href="{{ site.chyrp_url }}/favicon.svg" color="#4f4f4f">
<link rel="stylesheet" href="{{ site.chyrp_url }}/admin/stylesheets/all.css" type="text/css" media="all">
{% if site.monospace_font %}
<link rel="stylesheet" href="{{ site.chyrp_url }}/admin/stylesheets/monospace.css" type="text/css" media="all">

View File

@ -116,7 +116,7 @@ msgid "## Heading"
msgstr "## Kopf"
#: admin/help/markdown.twig:20 admin/help/markdown.twig:24
#: admin/javascripts/admin.js.php:450 admin/javascripts/admin.js.php:451
#: admin/javascripts/admin.js.php:455 admin/javascripts/admin.js.php:456
msgid "Heading"
msgstr "Kopf"
@ -128,8 +128,8 @@ msgstr "### Kopf"
msgid "**Strong**"
msgstr "**Stark**"
#: admin/help/markdown.twig:28 admin/javascripts/admin.js.php:475
#: admin/javascripts/admin.js.php:476
#: admin/help/markdown.twig:28 admin/javascripts/admin.js.php:480
#: admin/javascripts/admin.js.php:481
msgid "Strong"
msgstr "Stark"
@ -137,8 +137,8 @@ msgstr "Stark"
msgid "*Emphasis*"
msgstr "*Schwerpunkt*"
#: admin/help/markdown.twig:32 admin/javascripts/admin.js.php:500
#: admin/javascripts/admin.js.php:501
#: admin/help/markdown.twig:32 admin/javascripts/admin.js.php:505
#: admin/javascripts/admin.js.php:506
msgid "Emphasis"
msgstr "Schwerpunkt"
@ -154,8 +154,8 @@ msgstr "Zitat"
msgid "~~Strikethrough~~"
msgstr "~~Durchgestrichen~~"
#: admin/help/markdown.twig:40 admin/javascripts/admin.js.php:525
#: admin/javascripts/admin.js.php:526
#: admin/help/markdown.twig:40 admin/javascripts/admin.js.php:530
#: admin/javascripts/admin.js.php:531
msgid "Strikethrough"
msgstr "Durchgestrichen"
@ -163,8 +163,8 @@ msgstr "Durchgestrichen"
msgid "`Code`"
msgstr "`Code`"
#: admin/help/markdown.twig:44 admin/javascripts/admin.js.php:575
#: admin/javascripts/admin.js.php:576
#: admin/help/markdown.twig:44 admin/javascripts/admin.js.php:580
#: admin/javascripts/admin.js.php:581
msgid "Code"
msgstr "Code"
@ -172,8 +172,8 @@ msgstr "Code"
msgid "==Highlight=="
msgstr "==Markieren=="
#: admin/help/markdown.twig:48 admin/javascripts/admin.js.php:550
#: admin/javascripts/admin.js.php:551
#: admin/help/markdown.twig:48 admin/javascripts/admin.js.php:555
#: admin/javascripts/admin.js.php:556
msgid "Highlight"
msgstr "Markieren"
@ -205,8 +205,8 @@ msgstr "Neuer Absatz"
msgid "[title](URL)"
msgstr "[title](URL)"
#: admin/help/markdown.twig:65 admin/javascripts/admin.js.php:600
#: admin/javascripts/admin.js.php:601
#: admin/help/markdown.twig:65 admin/javascripts/admin.js.php:605
#: admin/javascripts/admin.js.php:606
msgid "Hyperlink"
msgstr "Hyperlink"
@ -214,8 +214,8 @@ msgstr "Hyperlink"
msgid "![description](URL)"
msgstr "![description](URL)"
#: admin/help/markdown.twig:69 admin/javascripts/admin.js.php:625
#: admin/javascripts/admin.js.php:626
#: admin/help/markdown.twig:69 admin/javascripts/admin.js.php:630
#: admin/javascripts/admin.js.php:631
msgid "Image"
msgstr "Bild"
@ -332,91 +332,104 @@ msgstr "Alle umschalten"
msgid "Are you sure you want to proceed?"
msgstr "Sind Sie sicher, dass Sie fortfahren möchten?"
#: admin/javascripts/admin.js.php:295 admin/javascripts/admin.js.php:383
#: admin/javascripts/admin.js.php:1171
msgid "Modal window"
msgstr "Modales Fenster"
#: admin/javascripts/admin.js.php:304 admin/pages/manage_uploads.twig:18
msgid "Uploads"
msgstr "Hochladungen"
#: admin/javascripts/admin.js.php:330 admin/javascripts/admin.js.php:409
#: admin/javascripts/admin.js.php:1199
msgid "Close"
msgstr "Schliessen"
#: admin/javascripts/admin.js.php:344 admin/javascripts/admin.js.php:423
#: admin/javascripts/admin.js.php:1213
msgid "close"
msgstr "schliessen"
#: admin/javascripts/admin.js.php:392
msgid "Help content"
msgstr "Hilfe inhalte"
#: admin/javascripts/admin.js.php:464
msgid "heading"
msgstr "kopf"
#: admin/javascripts/admin.js.php:489
msgid "strong"
msgstr "stark"
#: admin/javascripts/admin.js.php:514
msgid "emphasis"
msgstr "schwerpunkt"
#: admin/javascripts/admin.js.php:539
msgid "strikethrough"
msgstr "durchgestrichen"
#: admin/javascripts/admin.js.php:564
msgid "highlight"
msgstr "markieren"
#: admin/javascripts/admin.js.php:589
msgid "code"
msgstr "code"
#: admin/javascripts/admin.js.php:614
msgid "hyperlink"
msgstr "hyperlink"
#: admin/javascripts/admin.js.php:639 admin/javascripts/admin.js.php:705
msgid "image"
msgstr "bild"
#: admin/javascripts/admin.js.php:654 admin/javascripts/admin.js.php:655
msgid "Upload"
msgstr "Hochladen"
#: admin/javascripts/admin.js.php:682 admin/javascripts/admin.js.php:928
#: admin/javascripts/admin.js.php:244
msgid "Uploading..."
msgstr "Hochladen..."
#: admin/javascripts/admin.js.php:718 admin/javascripts/admin.js.php:719
#: admin/javascripts/admin.js.php:245
msgid "File upload failed!"
msgstr "Datei-Upload fehlgeschlagen!"
#: admin/javascripts/admin.js.php:246
msgid "File type not supported!"
msgstr "Dateityp wird nicht unterstützt!"
#: admin/javascripts/admin.js.php:247
#, php-format
msgid "Maximum file size: %d Megabytes!"
msgstr "Maximale Dateigröße: %d Megabyte!"
#: admin/javascripts/admin.js.php:300 admin/javascripts/admin.js.php:388
#: admin/javascripts/admin.js.php:1186
msgid "Modal window"
msgstr "Modales Fenster"
#: admin/javascripts/admin.js.php:309 admin/pages/manage_uploads.twig:18
msgid "Uploads"
msgstr "Hochladungen"
#: admin/javascripts/admin.js.php:335 admin/javascripts/admin.js.php:414
#: admin/javascripts/admin.js.php:1214
msgid "Close"
msgstr "Schliessen"
#: admin/javascripts/admin.js.php:349 admin/javascripts/admin.js.php:428
#: admin/javascripts/admin.js.php:1228
msgid "close"
msgstr "schliessen"
#: admin/javascripts/admin.js.php:397
msgid "Help content"
msgstr "Hilfe inhalte"
#: admin/javascripts/admin.js.php:469
msgid "heading"
msgstr "kopf"
#: admin/javascripts/admin.js.php:494
msgid "strong"
msgstr "stark"
#: admin/javascripts/admin.js.php:519
msgid "emphasis"
msgstr "schwerpunkt"
#: admin/javascripts/admin.js.php:544
msgid "strikethrough"
msgstr "durchgestrichen"
#: admin/javascripts/admin.js.php:569
msgid "highlight"
msgstr "markieren"
#: admin/javascripts/admin.js.php:594
msgid "code"
msgstr "code"
#: admin/javascripts/admin.js.php:619
msgid "hyperlink"
msgstr "hyperlink"
#: admin/javascripts/admin.js.php:644 admin/javascripts/admin.js.php:716
msgid "image"
msgstr "bild"
#: admin/javascripts/admin.js.php:659 admin/javascripts/admin.js.php:660
msgid "Upload"
msgstr "Hochladen"
#: admin/javascripts/admin.js.php:729 admin/javascripts/admin.js.php:730
msgid "Insert"
msgstr "Einfügen"
#: admin/javascripts/admin.js.php:747
#: admin/javascripts/admin.js.php:758
msgid "insert"
msgstr "einfügen"
#: admin/javascripts/admin.js.php:766 admin/javascripts/admin.js.php:767
#: admin/javascripts/admin.js.php:777 admin/javascripts/admin.js.php:778
#: admin/pages/themes.twig:24
msgid "Preview"
msgstr "Vorschau"
#: admin/javascripts/admin.js.php:792
#: admin/javascripts/admin.js.php:803
msgid "preview"
msgstr "vorschau"
#: admin/javascripts/admin.js.php:824
#: admin/javascripts/admin.js.php:835
msgid "Words:"
msgstr "Wörter:"
#: admin/javascripts/admin.js.php:1181
#: admin/javascripts/admin.js.php:1196
msgid "Preview content"
msgstr "Vorschau inhalt"

View File

@ -62,8 +62,8 @@ msgstr ""
#: admin/help/markdown.twig:20
#: admin/help/markdown.twig:24
#: admin/javascripts/admin.js.php:450
#: admin/javascripts/admin.js.php:451
#: admin/javascripts/admin.js.php:455
#: admin/javascripts/admin.js.php:456
msgid "Heading"
msgstr ""
@ -76,8 +76,8 @@ msgid "**Strong**"
msgstr ""
#: admin/help/markdown.twig:28
#: admin/javascripts/admin.js.php:475
#: admin/javascripts/admin.js.php:476
#: admin/javascripts/admin.js.php:480
#: admin/javascripts/admin.js.php:481
msgid "Strong"
msgstr ""
@ -86,8 +86,8 @@ msgid "*Emphasis*"
msgstr ""
#: admin/help/markdown.twig:32
#: admin/javascripts/admin.js.php:500
#: admin/javascripts/admin.js.php:501
#: admin/javascripts/admin.js.php:505
#: admin/javascripts/admin.js.php:506
msgid "Emphasis"
msgstr ""
@ -104,8 +104,8 @@ msgid "~~Strikethrough~~"
msgstr ""
#: admin/help/markdown.twig:40
#: admin/javascripts/admin.js.php:525
#: admin/javascripts/admin.js.php:526
#: admin/javascripts/admin.js.php:530
#: admin/javascripts/admin.js.php:531
msgid "Strikethrough"
msgstr ""
@ -114,8 +114,8 @@ msgid "`Code`"
msgstr ""
#: admin/help/markdown.twig:44
#: admin/javascripts/admin.js.php:575
#: admin/javascripts/admin.js.php:576
#: admin/javascripts/admin.js.php:580
#: admin/javascripts/admin.js.php:581
msgid "Code"
msgstr ""
@ -124,8 +124,8 @@ msgid "==Highlight=="
msgstr ""
#: admin/help/markdown.twig:48
#: admin/javascripts/admin.js.php:550
#: admin/javascripts/admin.js.php:551
#: admin/javascripts/admin.js.php:555
#: admin/javascripts/admin.js.php:556
msgid "Highlight"
msgstr ""
@ -158,8 +158,8 @@ msgid "[title](URL)"
msgstr ""
#: admin/help/markdown.twig:65
#: admin/javascripts/admin.js.php:600
#: admin/javascripts/admin.js.php:601
#: admin/javascripts/admin.js.php:605
#: admin/javascripts/admin.js.php:606
msgid "Hyperlink"
msgstr ""
@ -168,8 +168,8 @@ msgid "![description](URL)"
msgstr ""
#: admin/help/markdown.twig:69
#: admin/javascripts/admin.js.php:625
#: admin/javascripts/admin.js.php:626
#: admin/javascripts/admin.js.php:630
#: admin/javascripts/admin.js.php:631
msgid "Image"
msgstr ""
@ -275,100 +275,112 @@ msgstr ""
msgid "Are you sure you want to proceed?"
msgstr ""
#: admin/javascripts/admin.js.php:295
#: admin/javascripts/admin.js.php:383
#: admin/javascripts/admin.js.php:1171
#: admin/javascripts/admin.js.php:244
msgid "Uploading..."
msgstr ""
#: admin/javascripts/admin.js.php:245
msgid "File upload failed!"
msgstr ""
#: admin/javascripts/admin.js.php:246
msgid "File type not supported!"
msgstr ""
#: admin/javascripts/admin.js.php:247
#, php-format
msgid "Maximum file size: %d Megabytes!"
msgstr ""
#: admin/javascripts/admin.js.php:300
#: admin/javascripts/admin.js.php:388
#: admin/javascripts/admin.js.php:1186
msgid "Modal window"
msgstr ""
#: admin/javascripts/admin.js.php:304
#: admin/javascripts/admin.js.php:309
#: admin/pages/manage_uploads.twig:18
msgid "Uploads"
msgstr ""
#: admin/javascripts/admin.js.php:330
#: admin/javascripts/admin.js.php:409
#: admin/javascripts/admin.js.php:1199
#: admin/javascripts/admin.js.php:335
#: admin/javascripts/admin.js.php:414
#: admin/javascripts/admin.js.php:1214
msgid "Close"
msgstr ""
#: admin/javascripts/admin.js.php:344
#: admin/javascripts/admin.js.php:423
#: admin/javascripts/admin.js.php:1213
#: admin/javascripts/admin.js.php:349
#: admin/javascripts/admin.js.php:428
#: admin/javascripts/admin.js.php:1228
msgid "close"
msgstr ""
#: admin/javascripts/admin.js.php:392
#: admin/javascripts/admin.js.php:397
msgid "Help content"
msgstr ""
#: admin/javascripts/admin.js.php:464
#: admin/javascripts/admin.js.php:469
msgid "heading"
msgstr ""
#: admin/javascripts/admin.js.php:489
#: admin/javascripts/admin.js.php:494
msgid "strong"
msgstr ""
#: admin/javascripts/admin.js.php:514
#: admin/javascripts/admin.js.php:519
msgid "emphasis"
msgstr ""
#: admin/javascripts/admin.js.php:539
#: admin/javascripts/admin.js.php:544
msgid "strikethrough"
msgstr ""
#: admin/javascripts/admin.js.php:564
#: admin/javascripts/admin.js.php:569
msgid "highlight"
msgstr ""
#: admin/javascripts/admin.js.php:589
#: admin/javascripts/admin.js.php:594
msgid "code"
msgstr ""
#: admin/javascripts/admin.js.php:614
#: admin/javascripts/admin.js.php:619
msgid "hyperlink"
msgstr ""
#: admin/javascripts/admin.js.php:639
#: admin/javascripts/admin.js.php:705
#: admin/javascripts/admin.js.php:644
#: admin/javascripts/admin.js.php:716
msgid "image"
msgstr ""
#: admin/javascripts/admin.js.php:654
#: admin/javascripts/admin.js.php:655
#: admin/javascripts/admin.js.php:659
#: admin/javascripts/admin.js.php:660
msgid "Upload"
msgstr ""
#: admin/javascripts/admin.js.php:682
#: admin/javascripts/admin.js.php:928
msgid "Uploading..."
msgstr ""
#: admin/javascripts/admin.js.php:718
#: admin/javascripts/admin.js.php:719
#: admin/javascripts/admin.js.php:729
#: admin/javascripts/admin.js.php:730
msgid "Insert"
msgstr ""
#: admin/javascripts/admin.js.php:747
#: admin/javascripts/admin.js.php:758
msgid "insert"
msgstr ""
#: admin/javascripts/admin.js.php:766
#: admin/javascripts/admin.js.php:767
#: admin/javascripts/admin.js.php:777
#: admin/javascripts/admin.js.php:778
#: admin/pages/themes.twig:24
msgid "Preview"
msgstr ""
#: admin/javascripts/admin.js.php:792
#: admin/javascripts/admin.js.php:803
msgid "preview"
msgstr ""
#: admin/javascripts/admin.js.php:824
#: admin/javascripts/admin.js.php:835
msgid "Words:"
msgstr ""
#: admin/javascripts/admin.js.php:1181
#: admin/javascripts/admin.js.php:1196
msgid "Preview content"
msgstr ""

View File

@ -114,7 +114,7 @@ msgid "## Heading"
msgstr "## Titre"
#: admin/help/markdown.twig:20 admin/help/markdown.twig:24
#: admin/javascripts/admin.js.php:450 admin/javascripts/admin.js.php:451
#: admin/javascripts/admin.js.php:455 admin/javascripts/admin.js.php:456
msgid "Heading"
msgstr "Titre"
@ -126,8 +126,8 @@ msgstr "### Titre"
msgid "**Strong**"
msgstr "**Gras**"
#: admin/help/markdown.twig:28 admin/javascripts/admin.js.php:475
#: admin/javascripts/admin.js.php:476
#: admin/help/markdown.twig:28 admin/javascripts/admin.js.php:480
#: admin/javascripts/admin.js.php:481
msgid "Strong"
msgstr "Gras"
@ -135,8 +135,8 @@ msgstr "Gras"
msgid "*Emphasis*"
msgstr "*Emphase*"
#: admin/help/markdown.twig:32 admin/javascripts/admin.js.php:500
#: admin/javascripts/admin.js.php:501
#: admin/help/markdown.twig:32 admin/javascripts/admin.js.php:505
#: admin/javascripts/admin.js.php:506
msgid "Emphasis"
msgstr "Emphase"
@ -152,8 +152,8 @@ msgstr "Citation"
msgid "~~Strikethrough~~"
msgstr "~~Barré~~"
#: admin/help/markdown.twig:40 admin/javascripts/admin.js.php:525
#: admin/javascripts/admin.js.php:526
#: admin/help/markdown.twig:40 admin/javascripts/admin.js.php:530
#: admin/javascripts/admin.js.php:531
msgid "Strikethrough"
msgstr "Barré"
@ -161,8 +161,8 @@ msgstr "Barré"
msgid "`Code`"
msgstr "`Code`"
#: admin/help/markdown.twig:44 admin/javascripts/admin.js.php:575
#: admin/javascripts/admin.js.php:576
#: admin/help/markdown.twig:44 admin/javascripts/admin.js.php:580
#: admin/javascripts/admin.js.php:581
msgid "Code"
msgstr "Code"
@ -170,8 +170,8 @@ msgstr "Code"
msgid "==Highlight=="
msgstr "==Surligné=="
#: admin/help/markdown.twig:48 admin/javascripts/admin.js.php:550
#: admin/javascripts/admin.js.php:551
#: admin/help/markdown.twig:48 admin/javascripts/admin.js.php:555
#: admin/javascripts/admin.js.php:556
msgid "Highlight"
msgstr "Surligné"
@ -203,8 +203,8 @@ msgstr "Nouveau paragraphe"
msgid "[title](URL)"
msgstr "[titre](URL)"
#: admin/help/markdown.twig:65 admin/javascripts/admin.js.php:600
#: admin/javascripts/admin.js.php:601
#: admin/help/markdown.twig:65 admin/javascripts/admin.js.php:605
#: admin/javascripts/admin.js.php:606
msgid "Hyperlink"
msgstr "Lien hypertexte"
@ -212,8 +212,8 @@ msgstr "Lien hypertexte"
msgid "![description](URL)"
msgstr "![description](URL)"
#: admin/help/markdown.twig:69 admin/javascripts/admin.js.php:625
#: admin/javascripts/admin.js.php:626
#: admin/help/markdown.twig:69 admin/javascripts/admin.js.php:630
#: admin/javascripts/admin.js.php:631
msgid "Image"
msgstr "Image"
@ -326,91 +326,104 @@ msgstr "Tout basculer"
msgid "Are you sure you want to proceed?"
msgstr "Êtes-vous sûr de vouloir continuer ?"
#: admin/javascripts/admin.js.php:295 admin/javascripts/admin.js.php:383
#: admin/javascripts/admin.js.php:1171
msgid "Modal window"
msgstr "Fenêtre modale"
#: admin/javascripts/admin.js.php:304 admin/pages/manage_uploads.twig:18
msgid "Uploads"
msgstr "Téléchargements"
#: admin/javascripts/admin.js.php:330 admin/javascripts/admin.js.php:409
#: admin/javascripts/admin.js.php:1199
msgid "Close"
msgstr "Fermer"
#: admin/javascripts/admin.js.php:344 admin/javascripts/admin.js.php:423
#: admin/javascripts/admin.js.php:1213
msgid "close"
msgstr "fermer"
#: admin/javascripts/admin.js.php:392
msgid "Help content"
msgstr "Contenu de laide"
#: admin/javascripts/admin.js.php:464
msgid "heading"
msgstr "titre"
#: admin/javascripts/admin.js.php:489
msgid "strong"
msgstr "gras"
#: admin/javascripts/admin.js.php:514
msgid "emphasis"
msgstr "italique"
#: admin/javascripts/admin.js.php:539
msgid "strikethrough"
msgstr "barré"
#: admin/javascripts/admin.js.php:564
msgid "highlight"
msgstr "surligné"
#: admin/javascripts/admin.js.php:589
msgid "code"
msgstr "code"
#: admin/javascripts/admin.js.php:614
msgid "hyperlink"
msgstr "lien hypertexte"
#: admin/javascripts/admin.js.php:639 admin/javascripts/admin.js.php:705
msgid "image"
msgstr "image"
#: admin/javascripts/admin.js.php:654 admin/javascripts/admin.js.php:655
msgid "Upload"
msgstr "Téléchargement"
#: admin/javascripts/admin.js.php:682 admin/javascripts/admin.js.php:928
#: admin/javascripts/admin.js.php:244
msgid "Uploading..."
msgstr "Téléchargement..."
#: admin/javascripts/admin.js.php:718 admin/javascripts/admin.js.php:719
#: admin/javascripts/admin.js.php:245
msgid "File upload failed!"
msgstr "Le téléchargement du fichier a échoué !"
#: admin/javascripts/admin.js.php:246
msgid "File type not supported!"
msgstr "Le type de fichier nest pas pris en charge !"
#: admin/javascripts/admin.js.php:247
#, php-format
msgid "Maximum file size: %d Megabytes!"
msgstr "Taille maximale du fichier : %d mégaoctets !"
#: admin/javascripts/admin.js.php:300 admin/javascripts/admin.js.php:388
#: admin/javascripts/admin.js.php:1186
msgid "Modal window"
msgstr "Fenêtre modale"
#: admin/javascripts/admin.js.php:309 admin/pages/manage_uploads.twig:18
msgid "Uploads"
msgstr "Téléchargements"
#: admin/javascripts/admin.js.php:335 admin/javascripts/admin.js.php:414
#: admin/javascripts/admin.js.php:1214
msgid "Close"
msgstr "Fermer"
#: admin/javascripts/admin.js.php:349 admin/javascripts/admin.js.php:428
#: admin/javascripts/admin.js.php:1228
msgid "close"
msgstr "fermer"
#: admin/javascripts/admin.js.php:397
msgid "Help content"
msgstr "Contenu de laide"
#: admin/javascripts/admin.js.php:469
msgid "heading"
msgstr "titre"
#: admin/javascripts/admin.js.php:494
msgid "strong"
msgstr "gras"
#: admin/javascripts/admin.js.php:519
msgid "emphasis"
msgstr "italique"
#: admin/javascripts/admin.js.php:544
msgid "strikethrough"
msgstr "barré"
#: admin/javascripts/admin.js.php:569
msgid "highlight"
msgstr "surligné"
#: admin/javascripts/admin.js.php:594
msgid "code"
msgstr "code"
#: admin/javascripts/admin.js.php:619
msgid "hyperlink"
msgstr "lien hypertexte"
#: admin/javascripts/admin.js.php:644 admin/javascripts/admin.js.php:716
msgid "image"
msgstr "image"
#: admin/javascripts/admin.js.php:659 admin/javascripts/admin.js.php:660
msgid "Upload"
msgstr "Téléchargement"
#: admin/javascripts/admin.js.php:729 admin/javascripts/admin.js.php:730
msgid "Insert"
msgstr "Insérer"
#: admin/javascripts/admin.js.php:747
#: admin/javascripts/admin.js.php:758
msgid "insert"
msgstr "insérer"
#: admin/javascripts/admin.js.php:766 admin/javascripts/admin.js.php:767
#: admin/javascripts/admin.js.php:777 admin/javascripts/admin.js.php:778
#: admin/pages/themes.twig:24
msgid "Preview"
msgstr "Prévisualisation"
#: admin/javascripts/admin.js.php:792
#: admin/javascripts/admin.js.php:803
msgid "preview"
msgstr "prévisualisation"
#: admin/javascripts/admin.js.php:824
#: admin/javascripts/admin.js.php:835
msgid "Words:"
msgstr "Mots :"
#: admin/javascripts/admin.js.php:1181
#: admin/javascripts/admin.js.php:1196
msgid "Preview content"
msgstr "Contenu du prévisualisation"

View File

@ -114,7 +114,7 @@ msgid "## Heading"
msgstr "## Intestazione"
#: admin/help/markdown.twig:20 admin/help/markdown.twig:24
#: admin/javascripts/admin.js.php:450 admin/javascripts/admin.js.php:451
#: admin/javascripts/admin.js.php:455 admin/javascripts/admin.js.php:456
msgid "Heading"
msgstr "Intestazione"
@ -126,8 +126,8 @@ msgstr "### Intestazione"
msgid "**Strong**"
msgstr "**Forte**"
#: admin/help/markdown.twig:28 admin/javascripts/admin.js.php:475
#: admin/javascripts/admin.js.php:476
#: admin/help/markdown.twig:28 admin/javascripts/admin.js.php:480
#: admin/javascripts/admin.js.php:481
msgid "Strong"
msgstr "Forte"
@ -135,8 +135,8 @@ msgstr "Forte"
msgid "*Emphasis*"
msgstr "*Enfasi*"
#: admin/help/markdown.twig:32 admin/javascripts/admin.js.php:500
#: admin/javascripts/admin.js.php:501
#: admin/help/markdown.twig:32 admin/javascripts/admin.js.php:505
#: admin/javascripts/admin.js.php:506
msgid "Emphasis"
msgstr "Enfasi"
@ -152,8 +152,8 @@ msgstr "Citazione"
msgid "~~Strikethrough~~"
msgstr "~~Barrato~~"
#: admin/help/markdown.twig:40 admin/javascripts/admin.js.php:525
#: admin/javascripts/admin.js.php:526
#: admin/help/markdown.twig:40 admin/javascripts/admin.js.php:530
#: admin/javascripts/admin.js.php:531
msgid "Strikethrough"
msgstr "Barrato"
@ -161,8 +161,8 @@ msgstr "Barrato"
msgid "`Code`"
msgstr "`Codice`"
#: admin/help/markdown.twig:44 admin/javascripts/admin.js.php:575
#: admin/javascripts/admin.js.php:576
#: admin/help/markdown.twig:44 admin/javascripts/admin.js.php:580
#: admin/javascripts/admin.js.php:581
msgid "Code"
msgstr "Codice"
@ -170,8 +170,8 @@ msgstr "Codice"
msgid "==Highlight=="
msgstr "==Evidenziare=="
#: admin/help/markdown.twig:48 admin/javascripts/admin.js.php:550
#: admin/javascripts/admin.js.php:551
#: admin/help/markdown.twig:48 admin/javascripts/admin.js.php:555
#: admin/javascripts/admin.js.php:556
msgid "Highlight"
msgstr "Evidenziare"
@ -203,8 +203,8 @@ msgstr "Nuovo paragrafo"
msgid "[title](URL)"
msgstr "[titolo](URL)"
#: admin/help/markdown.twig:65 admin/javascripts/admin.js.php:600
#: admin/javascripts/admin.js.php:601
#: admin/help/markdown.twig:65 admin/javascripts/admin.js.php:605
#: admin/javascripts/admin.js.php:606
msgid "Hyperlink"
msgstr "Collegamento ipertestuale"
@ -212,8 +212,8 @@ msgstr "Collegamento ipertestuale"
msgid "![description](URL)"
msgstr "![descrizione](URL)"
#: admin/help/markdown.twig:69 admin/javascripts/admin.js.php:625
#: admin/javascripts/admin.js.php:626
#: admin/help/markdown.twig:69 admin/javascripts/admin.js.php:630
#: admin/javascripts/admin.js.php:631
msgid "Image"
msgstr "Immagine"
@ -329,91 +329,104 @@ msgstr "Spunta tutto"
msgid "Are you sure you want to proceed?"
msgstr "Sei sicuro di volere procedere?"
#: admin/javascripts/admin.js.php:295 admin/javascripts/admin.js.php:383
#: admin/javascripts/admin.js.php:1171
msgid "Modal window"
msgstr "Finestra modale"
#: admin/javascripts/admin.js.php:304 admin/pages/manage_uploads.twig:18
msgid "Uploads"
msgstr "Caricamenti"
#: admin/javascripts/admin.js.php:330 admin/javascripts/admin.js.php:409
#: admin/javascripts/admin.js.php:1199
msgid "Close"
msgstr "Chiudi"
#: admin/javascripts/admin.js.php:344 admin/javascripts/admin.js.php:423
#: admin/javascripts/admin.js.php:1213
msgid "close"
msgstr "chiudi"
#: admin/javascripts/admin.js.php:392
msgid "Help content"
msgstr "Contenuto di aiuto"
#: admin/javascripts/admin.js.php:464
msgid "heading"
msgstr "intestazione"
#: admin/javascripts/admin.js.php:489
msgid "strong"
msgstr "forte"
#: admin/javascripts/admin.js.php:514
msgid "emphasis"
msgstr "enfasi"
#: admin/javascripts/admin.js.php:539
msgid "strikethrough"
msgstr "barrato"
#: admin/javascripts/admin.js.php:564
msgid "highlight"
msgstr "evidenza"
#: admin/javascripts/admin.js.php:589
msgid "code"
msgstr "codice"
#: admin/javascripts/admin.js.php:614
msgid "hyperlink"
msgstr "collegamento ipertestuale"
#: admin/javascripts/admin.js.php:639 admin/javascripts/admin.js.php:705
msgid "image"
msgstr "immagine"
#: admin/javascripts/admin.js.php:654 admin/javascripts/admin.js.php:655
msgid "Upload"
msgstr "Carica"
#: admin/javascripts/admin.js.php:682 admin/javascripts/admin.js.php:928
#: admin/javascripts/admin.js.php:244
msgid "Uploading..."
msgstr "Caricamento in corso…."
#: admin/javascripts/admin.js.php:718 admin/javascripts/admin.js.php:719
#: admin/javascripts/admin.js.php:245
msgid "File upload failed!"
msgstr "Caricamento file fallito!"
#: admin/javascripts/admin.js.php:246
msgid "File type not supported!"
msgstr "Tipo di file non supportato!"
#: admin/javascripts/admin.js.php:247
#, php-format
msgid "Maximum file size: %d Megabytes!"
msgstr "Dimensione massima del file: %d Megabyte!"
#: admin/javascripts/admin.js.php:300 admin/javascripts/admin.js.php:388
#: admin/javascripts/admin.js.php:1186
msgid "Modal window"
msgstr "Finestra modale"
#: admin/javascripts/admin.js.php:309 admin/pages/manage_uploads.twig:18
msgid "Uploads"
msgstr "Caricamenti"
#: admin/javascripts/admin.js.php:335 admin/javascripts/admin.js.php:414
#: admin/javascripts/admin.js.php:1214
msgid "Close"
msgstr "Chiudi"
#: admin/javascripts/admin.js.php:349 admin/javascripts/admin.js.php:428
#: admin/javascripts/admin.js.php:1228
msgid "close"
msgstr "chiudi"
#: admin/javascripts/admin.js.php:397
msgid "Help content"
msgstr "Contenuto di aiuto"
#: admin/javascripts/admin.js.php:469
msgid "heading"
msgstr "intestazione"
#: admin/javascripts/admin.js.php:494
msgid "strong"
msgstr "forte"
#: admin/javascripts/admin.js.php:519
msgid "emphasis"
msgstr "enfasi"
#: admin/javascripts/admin.js.php:544
msgid "strikethrough"
msgstr "barrato"
#: admin/javascripts/admin.js.php:569
msgid "highlight"
msgstr "evidenza"
#: admin/javascripts/admin.js.php:594
msgid "code"
msgstr "codice"
#: admin/javascripts/admin.js.php:619
msgid "hyperlink"
msgstr "collegamento ipertestuale"
#: admin/javascripts/admin.js.php:644 admin/javascripts/admin.js.php:716
msgid "image"
msgstr "immagine"
#: admin/javascripts/admin.js.php:659 admin/javascripts/admin.js.php:660
msgid "Upload"
msgstr "Carica"
#: admin/javascripts/admin.js.php:729 admin/javascripts/admin.js.php:730
msgid "Insert"
msgstr "Inserisci"
#: admin/javascripts/admin.js.php:747
#: admin/javascripts/admin.js.php:758
msgid "insert"
msgstr "inserisci"
#: admin/javascripts/admin.js.php:766 admin/javascripts/admin.js.php:767
#: admin/javascripts/admin.js.php:777 admin/javascripts/admin.js.php:778
#: admin/pages/themes.twig:24
msgid "Preview"
msgstr "Anteprima"
#: admin/javascripts/admin.js.php:792
#: admin/javascripts/admin.js.php:803
msgid "preview"
msgstr "anteprima"
#: admin/javascripts/admin.js.php:824
#: admin/javascripts/admin.js.php:835
msgid "Words:"
msgstr "Parole:"
#: admin/javascripts/admin.js.php:1181
#: admin/javascripts/admin.js.php:1196
msgid "Preview content"
msgstr "Contenuto di anteprima"

View File

@ -112,7 +112,7 @@ msgid "## Heading"
msgstr "## Kop"
#: admin/help/markdown.twig:20 admin/help/markdown.twig:24
#: admin/javascripts/admin.js.php:450 admin/javascripts/admin.js.php:451
#: admin/javascripts/admin.js.php:455 admin/javascripts/admin.js.php:456
msgid "Heading"
msgstr "Kop"
@ -124,8 +124,8 @@ msgstr "### Kop"
msgid "**Strong**"
msgstr "**Sterk**"
#: admin/help/markdown.twig:28 admin/javascripts/admin.js.php:475
#: admin/javascripts/admin.js.php:476
#: admin/help/markdown.twig:28 admin/javascripts/admin.js.php:480
#: admin/javascripts/admin.js.php:481
msgid "Strong"
msgstr "Sterk"
@ -133,8 +133,8 @@ msgstr "Sterk"
msgid "*Emphasis*"
msgstr "*Vet*"
#: admin/help/markdown.twig:32 admin/javascripts/admin.js.php:500
#: admin/javascripts/admin.js.php:501
#: admin/help/markdown.twig:32 admin/javascripts/admin.js.php:505
#: admin/javascripts/admin.js.php:506
msgid "Emphasis"
msgstr "Vet"
@ -150,8 +150,8 @@ msgstr "Citaat"
msgid "~~Strikethrough~~"
msgstr "~~Doorhalen~~"
#: admin/help/markdown.twig:40 admin/javascripts/admin.js.php:525
#: admin/javascripts/admin.js.php:526
#: admin/help/markdown.twig:40 admin/javascripts/admin.js.php:530
#: admin/javascripts/admin.js.php:531
msgid "Strikethrough"
msgstr "Doorhalen"
@ -159,8 +159,8 @@ msgstr "Doorhalen"
msgid "`Code`"
msgstr "`Code`"
#: admin/help/markdown.twig:44 admin/javascripts/admin.js.php:575
#: admin/javascripts/admin.js.php:576
#: admin/help/markdown.twig:44 admin/javascripts/admin.js.php:580
#: admin/javascripts/admin.js.php:581
msgid "Code"
msgstr "Code"
@ -168,8 +168,8 @@ msgstr "Code"
msgid "==Highlight=="
msgstr "==Markeren=="
#: admin/help/markdown.twig:48 admin/javascripts/admin.js.php:550
#: admin/javascripts/admin.js.php:551
#: admin/help/markdown.twig:48 admin/javascripts/admin.js.php:555
#: admin/javascripts/admin.js.php:556
msgid "Highlight"
msgstr "Markeren"
@ -201,8 +201,8 @@ msgstr "Nieuwe paragraaf"
msgid "[title](URL)"
msgstr "[titel](URL)"
#: admin/help/markdown.twig:65 admin/javascripts/admin.js.php:600
#: admin/javascripts/admin.js.php:601
#: admin/help/markdown.twig:65 admin/javascripts/admin.js.php:605
#: admin/javascripts/admin.js.php:606
msgid "Hyperlink"
msgstr "Hyperlink"
@ -210,8 +210,8 @@ msgstr "Hyperlink"
msgid "![description](URL)"
msgstr "![beschrijving](URL)"
#: admin/help/markdown.twig:69 admin/javascripts/admin.js.php:625
#: admin/javascripts/admin.js.php:626
#: admin/help/markdown.twig:69 admin/javascripts/admin.js.php:630
#: admin/javascripts/admin.js.php:631
msgid "Image"
msgstr "Afbeelding"
@ -327,91 +327,104 @@ msgstr "Alles selecteren"
msgid "Are you sure you want to proceed?"
msgstr "Weet je zeker dat je wilt doorgaan?"
#: admin/javascripts/admin.js.php:295 admin/javascripts/admin.js.php:383
#: admin/javascripts/admin.js.php:1171
msgid "Modal window"
msgstr "Voorscherm"
#: admin/javascripts/admin.js.php:304 admin/pages/manage_uploads.twig:18
msgid "Uploads"
msgstr "Uploads"
#: admin/javascripts/admin.js.php:330 admin/javascripts/admin.js.php:409
#: admin/javascripts/admin.js.php:1199
msgid "Close"
msgstr "Sluit"
#: admin/javascripts/admin.js.php:344 admin/javascripts/admin.js.php:423
#: admin/javascripts/admin.js.php:1213
msgid "close"
msgstr "sluit"
#: admin/javascripts/admin.js.php:392
msgid "Help content"
msgstr "Help inhoud"
#: admin/javascripts/admin.js.php:464
msgid "heading"
msgstr "kop"
#: admin/javascripts/admin.js.php:489
msgid "strong"
msgstr "sterk"
#: admin/javascripts/admin.js.php:514
msgid "emphasis"
msgstr "vet"
#: admin/javascripts/admin.js.php:539
msgid "strikethrough"
msgstr "doorhalen"
#: admin/javascripts/admin.js.php:564
msgid "highlight"
msgstr "markeren"
#: admin/javascripts/admin.js.php:589
msgid "code"
msgstr "code"
#: admin/javascripts/admin.js.php:614
msgid "hyperlink"
msgstr "hyperlink"
#: admin/javascripts/admin.js.php:639 admin/javascripts/admin.js.php:705
msgid "image"
msgstr "afbeelding"
#: admin/javascripts/admin.js.php:654 admin/javascripts/admin.js.php:655
msgid "Upload"
msgstr "Upload"
#: admin/javascripts/admin.js.php:682 admin/javascripts/admin.js.php:928
#: admin/javascripts/admin.js.php:244
msgid "Uploading..."
msgstr "Aan het uploaden..."
#: admin/javascripts/admin.js.php:718 admin/javascripts/admin.js.php:719
#: admin/javascripts/admin.js.php:245
msgid "File upload failed!"
msgstr "Het uploaden van bestanden is mislukt!"
#: admin/javascripts/admin.js.php:246
msgid "File type not supported!"
msgstr "Bestandstype wordt niet ondersteund!"
#: admin/javascripts/admin.js.php:247
#, php-format
msgid "Maximum file size: %d Megabytes!"
msgstr "Maximale bestandsgrootte: %d Megabytes!"
#: admin/javascripts/admin.js.php:300 admin/javascripts/admin.js.php:388
#: admin/javascripts/admin.js.php:1186
msgid "Modal window"
msgstr "Voorscherm"
#: admin/javascripts/admin.js.php:309 admin/pages/manage_uploads.twig:18
msgid "Uploads"
msgstr "Uploads"
#: admin/javascripts/admin.js.php:335 admin/javascripts/admin.js.php:414
#: admin/javascripts/admin.js.php:1214
msgid "Close"
msgstr "Sluit"
#: admin/javascripts/admin.js.php:349 admin/javascripts/admin.js.php:428
#: admin/javascripts/admin.js.php:1228
msgid "close"
msgstr "sluit"
#: admin/javascripts/admin.js.php:397
msgid "Help content"
msgstr "Help inhoud"
#: admin/javascripts/admin.js.php:469
msgid "heading"
msgstr "kop"
#: admin/javascripts/admin.js.php:494
msgid "strong"
msgstr "sterk"
#: admin/javascripts/admin.js.php:519
msgid "emphasis"
msgstr "vet"
#: admin/javascripts/admin.js.php:544
msgid "strikethrough"
msgstr "doorhalen"
#: admin/javascripts/admin.js.php:569
msgid "highlight"
msgstr "markeren"
#: admin/javascripts/admin.js.php:594
msgid "code"
msgstr "code"
#: admin/javascripts/admin.js.php:619
msgid "hyperlink"
msgstr "hyperlink"
#: admin/javascripts/admin.js.php:644 admin/javascripts/admin.js.php:716
msgid "image"
msgstr "afbeelding"
#: admin/javascripts/admin.js.php:659 admin/javascripts/admin.js.php:660
msgid "Upload"
msgstr "Upload"
#: admin/javascripts/admin.js.php:729 admin/javascripts/admin.js.php:730
msgid "Insert"
msgstr "Invoegen"
#: admin/javascripts/admin.js.php:747
#: admin/javascripts/admin.js.php:758
msgid "insert"
msgstr "invoegen"
#: admin/javascripts/admin.js.php:766 admin/javascripts/admin.js.php:767
#: admin/javascripts/admin.js.php:777 admin/javascripts/admin.js.php:778
#: admin/pages/themes.twig:24
msgid "Preview"
msgstr "Vooruitblik"
#: admin/javascripts/admin.js.php:792
#: admin/javascripts/admin.js.php:803
msgid "preview"
msgstr "vooruitblik"
#: admin/javascripts/admin.js.php:824
#: admin/javascripts/admin.js.php:835
msgid "Words:"
msgstr "Woorden:"
#: admin/javascripts/admin.js.php:1181
#: admin/javascripts/admin.js.php:1196
msgid "Preview content"
msgstr "Vooruitblik inhoud"

View File

@ -100,7 +100,7 @@ msgid "## Heading"
msgstr ""
#: admin/help/markdown.twig:20 admin/help/markdown.twig:24
#: admin/javascripts/admin.js.php:450 admin/javascripts/admin.js.php:451
#: admin/javascripts/admin.js.php:455 admin/javascripts/admin.js.php:456
msgid "Heading"
msgstr ""
@ -112,8 +112,8 @@ msgstr ""
msgid "**Strong**"
msgstr ""
#: admin/help/markdown.twig:28 admin/javascripts/admin.js.php:475
#: admin/javascripts/admin.js.php:476
#: admin/help/markdown.twig:28 admin/javascripts/admin.js.php:480
#: admin/javascripts/admin.js.php:481
msgid "Strong"
msgstr ""
@ -121,8 +121,8 @@ msgstr ""
msgid "*Emphasis*"
msgstr ""
#: admin/help/markdown.twig:32 admin/javascripts/admin.js.php:500
#: admin/javascripts/admin.js.php:501
#: admin/help/markdown.twig:32 admin/javascripts/admin.js.php:505
#: admin/javascripts/admin.js.php:506
msgid "Emphasis"
msgstr ""
@ -138,8 +138,8 @@ msgstr ""
msgid "~~Strikethrough~~"
msgstr ""
#: admin/help/markdown.twig:40 admin/javascripts/admin.js.php:525
#: admin/javascripts/admin.js.php:526
#: admin/help/markdown.twig:40 admin/javascripts/admin.js.php:530
#: admin/javascripts/admin.js.php:531
msgid "Strikethrough"
msgstr ""
@ -147,8 +147,8 @@ msgstr ""
msgid "`Code`"
msgstr ""
#: admin/help/markdown.twig:44 admin/javascripts/admin.js.php:575
#: admin/javascripts/admin.js.php:576
#: admin/help/markdown.twig:44 admin/javascripts/admin.js.php:580
#: admin/javascripts/admin.js.php:581
msgid "Code"
msgstr ""
@ -156,8 +156,8 @@ msgstr ""
msgid "==Highlight=="
msgstr ""
#: admin/help/markdown.twig:48 admin/javascripts/admin.js.php:550
#: admin/javascripts/admin.js.php:551
#: admin/help/markdown.twig:48 admin/javascripts/admin.js.php:555
#: admin/javascripts/admin.js.php:556
msgid "Highlight"
msgstr ""
@ -189,8 +189,8 @@ msgstr "新行"
msgid "[title](URL)"
msgstr ""
#: admin/help/markdown.twig:65 admin/javascripts/admin.js.php:600
#: admin/javascripts/admin.js.php:601
#: admin/help/markdown.twig:65 admin/javascripts/admin.js.php:605
#: admin/javascripts/admin.js.php:606
msgid "Hyperlink"
msgstr ""
@ -198,8 +198,8 @@ msgstr ""
msgid "![description](URL)"
msgstr ""
#: admin/help/markdown.twig:69 admin/javascripts/admin.js.php:625
#: admin/javascripts/admin.js.php:626
#: admin/help/markdown.twig:69 admin/javascripts/admin.js.php:630
#: admin/javascripts/admin.js.php:631
msgid "Image"
msgstr "图像"
@ -311,91 +311,104 @@ msgstr "全部切换"
msgid "Are you sure you want to proceed?"
msgstr "确定继续?"
#: admin/javascripts/admin.js.php:295 admin/javascripts/admin.js.php:383
#: admin/javascripts/admin.js.php:1171
msgid "Modal window"
msgstr "模态窗口"
#: admin/javascripts/admin.js.php:304 admin/pages/manage_uploads.twig:18
msgid "Uploads"
msgstr "上传"
#: admin/javascripts/admin.js.php:330 admin/javascripts/admin.js.php:409
#: admin/javascripts/admin.js.php:1199
msgid "Close"
msgstr "关闭"
#: admin/javascripts/admin.js.php:344 admin/javascripts/admin.js.php:423
#: admin/javascripts/admin.js.php:1213
msgid "close"
msgstr "关闭"
#: admin/javascripts/admin.js.php:392
msgid "Help content"
msgstr "帮助内容"
#: admin/javascripts/admin.js.php:464
msgid "heading"
msgstr "标题"
#: admin/javascripts/admin.js.php:489
msgid "strong"
msgstr "强"
#: admin/javascripts/admin.js.php:514
msgid "emphasis"
msgstr "重点"
#: admin/javascripts/admin.js.php:539
msgid "strikethrough"
msgstr "穿越"
#: admin/javascripts/admin.js.php:564
msgid "highlight"
msgstr "突出"
#: admin/javascripts/admin.js.php:589
msgid "code"
msgstr "代码"
#: admin/javascripts/admin.js.php:614
msgid "hyperlink"
msgstr "链接"
#: admin/javascripts/admin.js.php:639 admin/javascripts/admin.js.php:705
msgid "image"
msgstr "图像"
#: admin/javascripts/admin.js.php:654 admin/javascripts/admin.js.php:655
msgid "Upload"
msgstr "上传"
#: admin/javascripts/admin.js.php:682 admin/javascripts/admin.js.php:928
#: admin/javascripts/admin.js.php:244
msgid "Uploading..."
msgstr "上传中..."
#: admin/javascripts/admin.js.php:718 admin/javascripts/admin.js.php:719
#: admin/javascripts/admin.js.php:245
msgid "File upload failed!"
msgstr "文件上传失败!"
#: admin/javascripts/admin.js.php:246
msgid "File type not supported!"
msgstr "不支持文件类型!"
#: admin/javascripts/admin.js.php:247
#, php-format
msgid "Maximum file size: %d Megabytes!"
msgstr "最大文件大小:%d兆字节"
#: admin/javascripts/admin.js.php:300 admin/javascripts/admin.js.php:388
#: admin/javascripts/admin.js.php:1186
msgid "Modal window"
msgstr "模态窗口"
#: admin/javascripts/admin.js.php:309 admin/pages/manage_uploads.twig:18
msgid "Uploads"
msgstr "上传"
#: admin/javascripts/admin.js.php:335 admin/javascripts/admin.js.php:414
#: admin/javascripts/admin.js.php:1214
msgid "Close"
msgstr "关闭"
#: admin/javascripts/admin.js.php:349 admin/javascripts/admin.js.php:428
#: admin/javascripts/admin.js.php:1228
msgid "close"
msgstr "关闭"
#: admin/javascripts/admin.js.php:397
msgid "Help content"
msgstr "帮助内容"
#: admin/javascripts/admin.js.php:469
msgid "heading"
msgstr "标题"
#: admin/javascripts/admin.js.php:494
msgid "strong"
msgstr "强"
#: admin/javascripts/admin.js.php:519
msgid "emphasis"
msgstr "重点"
#: admin/javascripts/admin.js.php:544
msgid "strikethrough"
msgstr "穿越"
#: admin/javascripts/admin.js.php:569
msgid "highlight"
msgstr "突出"
#: admin/javascripts/admin.js.php:594
msgid "code"
msgstr "代码"
#: admin/javascripts/admin.js.php:619
msgid "hyperlink"
msgstr "链接"
#: admin/javascripts/admin.js.php:644 admin/javascripts/admin.js.php:716
msgid "image"
msgstr "图像"
#: admin/javascripts/admin.js.php:659 admin/javascripts/admin.js.php:660
msgid "Upload"
msgstr "上传"
#: admin/javascripts/admin.js.php:729 admin/javascripts/admin.js.php:730
msgid "Insert"
msgstr "插入"
#: admin/javascripts/admin.js.php:747
#: admin/javascripts/admin.js.php:758
msgid "insert"
msgstr "插入"
#: admin/javascripts/admin.js.php:766 admin/javascripts/admin.js.php:767
#: admin/javascripts/admin.js.php:777 admin/javascripts/admin.js.php:778
#: admin/pages/themes.twig:24
msgid "Preview"
msgstr "预览"
#: admin/javascripts/admin.js.php:792
#: admin/javascripts/admin.js.php:803
msgid "preview"
msgstr "预览"
#: admin/javascripts/admin.js.php:824
#: admin/javascripts/admin.js.php:835
msgid "Words:"
msgstr ""
#: admin/javascripts/admin.js.php:1181
#: admin/javascripts/admin.js.php:1196
msgid "Preview content"
msgstr "预览内容"

View File

@ -25,7 +25,7 @@
{{- icon_img("help.svg", "help" | translate) -}}
</a>
</label>
<input class="text" type="text" name="slug" value="{{ page is defined ? page.clean | fix(true) : '' }}" id="slug" maxlength="80">
<input class="text" type="text" name="slug" value="{{ page is defined ? page.clean | fix(true) : '' }}" id="slug" maxlength="128"{{ slug_pattern() }}>
</p>
<p class="more_options_option">
<label for="status">{{ "Status" | translate }}</label>

View File

@ -124,7 +124,7 @@
{{- icon_img("help.svg", "help" | translate) -}}
</a>
</label>
<input id="slug" class="text" type="text" name="slug" value="{{ post is defined ? post.clean | fix(true) : '' }}" maxlength="80">
<input id="slug" class="text" type="text" name="slug" value="{{ post is defined ? post.clean | fix(true) : '' }}" maxlength="128"{{ slug_pattern() }}>
</p>
<p class="more_options_option">
<label for="created_at">{{ "Timestamp" | translate }}</label>

View File

@ -825,7 +825,7 @@ a.prev_page {
color: #1f1f23;
text-align: center;
margin: 0rem;
padding: 0.5rem;
padding: 0.5rem 1rem;
background-color: #f2fbff;
border: 2px solid #b8cdd9;
border-radius: 0.25em;
@ -1083,9 +1083,11 @@ a.emblem:focus > img,
button.emblem:focus > img,
label.emblem.toolbar > input:focus + img {
outline: #ff7f00 dashed 2px;
outline-offset: 1px;
}
input.toolbar.hidden {
display: inline !important;
opacity: 0 !important;
font: inherit !important;
width: 1px !important;
height: 16px !important;
@ -1093,7 +1095,6 @@ input.toolbar.hidden {
border: none !important;
padding: 0rem !important;
margin: 0rem !important;
visibility: hidden !important;
}
input.toolbar.hidden::file-selector-button {
display: none !important;
@ -1133,6 +1134,7 @@ input.toolbar.hidden::file-selector-button {
}
.iframe_foreground:focus {
outline: #ff7f00 dashed 2px;
outline-offset: 1px;
}
.iframe_close_gadget {
display: block;
@ -1262,7 +1264,7 @@ input.toolbar.hidden::file-selector-button {
}
button:not(.toolbar):has(img),
a.button:not(.toolbar):has(img) {
padding-right: calc(16px + 0.5rem) !important;
padding-right: calc(16px + 1rem) !important;
}
div.more_options {
grid-template-columns: 1fr;

View File

@ -85,7 +85,7 @@
"captions" => fallback($captions, ""),
"description" => $_POST['description']
),
clean:sanitize($_POST['slug']),
clean:sanitize($_POST['slug'], true, SLUG_STRICT, 128),
feather:"audio",
pinned:!empty($_POST['pinned']),
status:$_POST['status'],
@ -98,7 +98,7 @@
public function update($post): Post|false {
fallback($_POST['title'], "");
fallback($_POST['description'], "");
fallback($_POST['slug'], $post->clean);
fallback($_POST['slug'], "");
fallback($_POST['status'], $post->status);
fallback($_POST['created_at'], $post->created_at);
fallback($_POST['option'], array());
@ -111,6 +111,12 @@
$this->audio_extensions()
);
if (isset($_FILES['captions']) and upload_tester($_FILES['captions']))
$captions = upload(
$_FILES['captions'],
array("vtt")
);
return $post->update(
values:array(
"title" => $_POST['title'],
@ -120,7 +126,7 @@
),
pinned:!empty($_POST['pinned']),
status:$_POST['status'],
clean:sanitize($_POST['slug']),
clean:sanitize($_POST['slug'], true, SLUG_STRICT, 128),
created_at:datetime($_POST['created_at']),
options:$_POST['option']
);

View File

@ -2,7 +2,7 @@
return array(
"name" => __("Audio", "audio"),
"url" => "http://chyrplite.net/",
"version" => "2024.01",
"version" => "2024.03",
"description" => __("A feather for audio.", "audio"),
"author" => array(
"name" => "Daniel Pimley",

View File

@ -9,7 +9,7 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: Poedit 3.4.2\n"
"X-Generator: Poedit 3.4.4\n"
#. This file is distributed under the same license as the Chyrp Lite package.
#: feathers/audio/audio.php:10
@ -32,7 +32,7 @@ msgstr "Beschreibung"
msgid "You did not select any audio to upload."
msgstr "Sie haben kein Audio zum Hochladen ausgewählt."
#: feathers/audio/audio.php:186
#: feathers/audio/audio.php:192
msgid "Your web browser does not support the <code>audio</code> element."
msgstr "Ihr Webbrowser unterstützt das <code>Audioelement</code> nicht."

View File

@ -20,7 +20,7 @@ msgstr ""
msgid "You did not select any audio to upload."
msgstr ""
#: feathers/audio/audio.php:186
#: feathers/audio/audio.php:192
msgid "Your web browser does not support the <code>audio</code> element."
msgstr ""

View File

@ -10,7 +10,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
"X-Generator: Poedit 3.0.1\n"
"X-Generator: Poedit 3.4.4\n"
#. This file is distributed under the same license as the Chyrp Lite package.
#: feathers/audio/audio.php:10
@ -33,7 +33,7 @@ msgstr "Description"
msgid "You did not select any audio to upload."
msgstr "Vous n'avez sélectionné aucun fichier audio à télécharger."
#: feathers/audio/audio.php:186
#: feathers/audio/audio.php:192
msgid "Your web browser does not support the <code>audio</code> element."
msgstr "Votre navigateur ne supporte pas cet élément <code>audio</audio>."

View File

@ -10,7 +10,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-Generator: Poedit 3.4.2\n"
"X-Generator: Poedit 3.4.4\n"
#. This file is distributed under the same license as the Chyrp Lite package.
#: feathers/audio/audio.php:10
@ -33,7 +33,7 @@ msgstr "Descrizione"
msgid "You did not select any audio to upload."
msgstr "Non è stato selezionato alcun audio da caricare."
#: feathers/audio/audio.php:186
#: feathers/audio/audio.php:192
msgid "Your web browser does not support the <code>audio</code> element."
msgstr "Il browser web non supporta l'elemento <code>audio</code>."

View File

@ -9,7 +9,7 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: Poedit 3.4.2\n"
"X-Generator: Poedit 3.4.4\n"
#. This file is distributed under the same license as the Chyrp Lite package.
#: feathers/audio/audio.php:10
@ -32,7 +32,7 @@ msgstr "Beschrijving"
msgid "You did not select any audio to upload."
msgstr "Je hebt geen audio geselecteerd om te uploaden."
#: feathers/audio/audio.php:186
#: feathers/audio/audio.php:192
msgid "Your web browser does not support the <code>audio</code> element."
msgstr "Je webbrowser ondersteunt het <code>audio</code> element niet."

View File

@ -10,7 +10,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=1; plural=0;\n"
"X-Generator: Poedit 3.4.2\n"
"X-Generator: Poedit 3.4.4\n"
#. This file is distributed under the same license as the Chyrp Lite package.
#: feathers/audio/audio.php:10
@ -33,7 +33,7 @@ msgstr "描述"
msgid "You did not select any audio to upload."
msgstr "你灭有选择任何上传的音频文件。"
#: feathers/audio/audio.php:186
#: feathers/audio/audio.php:192
msgid "Your web browser does not support the <code>audio</code> element."
msgstr "你的浏览器不支持 <code>audio</code> 元素。"

View File

@ -2,7 +2,7 @@
return array(
"name" => __("Link", "link"),
"url" => "http://chyrplite.net/",
"version" => "2023.01",
"version" => "2024.03",
"description" => __("Link to other sites and add an optional description.", "link"),
"author" => array(
"name" => "Alex Suraci",

View File

@ -65,7 +65,7 @@
"source" => $_POST['source'],
"description" => $_POST['description']
),
clean:sanitize($_POST['slug']),
clean:sanitize($_POST['slug'], true, SLUG_STRICT, 128),
feather:"link",
pinned:!empty($_POST['pinned']),
status:$_POST['status'],
@ -91,7 +91,7 @@
fallback($_POST['name'], "");
fallback($_POST['description'], "");
fallback($_POST['slug'], $post->clean);
fallback($_POST['slug'], "");
fallback($_POST['status'], $post->status);
fallback($_POST['created_at'], $post->created_at);
fallback($_POST['option'], array());
@ -106,7 +106,7 @@
),
pinned:!empty($_POST['pinned']),
status:$_POST['status'],
clean:sanitize($_POST['slug']),
clean:sanitize($_POST['slug'], true, SLUG_STRICT, 128),
created_at:datetime($_POST['created_at']),
options:$_POST['option']
);

View File

@ -2,7 +2,7 @@
return array(
"name" => __("Photo", "photo"),
"url" => "http://chyrplite.net/",
"version" => "2024.01",
"version" => "2024.03",
"description" => __("Upload and display an image with a caption.", "photo"),
"author" => array(
"name" => "Alex Suraci",

View File

@ -9,11 +9,11 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: Poedit 3.4.2\n"
"X-Generator: Poedit 3.4.4\n"
#. This file is distributed under the same license as the Chyrp Lite package.
#: feathers/photo/admin/help/photo_alt_text.twig:3
#: feathers/photo/admin/help/photo_alt_text.twig:6 feathers/photo/photo.php:154
#: feathers/photo/admin/help/photo_alt_text.twig:6 feathers/photo/photo.php:156
msgid "Alternative Text"
msgstr "Alternativer Text"
@ -59,6 +59,6 @@ msgstr "Bildunterschrift"
msgid "You did not select a photo to upload."
msgstr "Sie haben kein Foto zum Hochladen ausgewählt."
#: feathers/photo/photo.php:162
#: feathers/photo/photo.php:164
msgid "Source"
msgstr "Quelle"

View File

@ -2,7 +2,7 @@
#: feathers/photo/admin/help/photo_alt_text.twig:3
#: feathers/photo/admin/help/photo_alt_text.twig:6
#: feathers/photo/photo.php:154
#: feathers/photo/photo.php:156
msgid "Alternative Text"
msgstr ""
@ -40,7 +40,7 @@ msgstr ""
msgid "You did not select a photo to upload."
msgstr ""
#: feathers/photo/photo.php:162
#: feathers/photo/photo.php:164
msgid "Source"
msgstr ""

View File

@ -10,11 +10,11 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
"X-Generator: Poedit 3.0.1\n"
"X-Generator: Poedit 3.4.4\n"
#. This file is distributed under the same license as the Chyrp Lite package.
#: feathers/photo/admin/help/photo_alt_text.twig:3
#: feathers/photo/admin/help/photo_alt_text.twig:6 feathers/photo/photo.php:154
#: feathers/photo/admin/help/photo_alt_text.twig:6 feathers/photo/photo.php:156
msgid "Alternative Text"
msgstr "Texte alternatif"
@ -59,6 +59,6 @@ msgstr "Légende"
msgid "You did not select a photo to upload."
msgstr "Vous n'avez pas sélectionné de photo à télécharger."
#: feathers/photo/photo.php:162
#: feathers/photo/photo.php:164
msgid "Source"
msgstr "Source"

View File

@ -10,11 +10,11 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-Generator: Poedit 3.4.2\n"
"X-Generator: Poedit 3.4.4\n"
#. This file is distributed under the same license as the Chyrp Lite package.
#: feathers/photo/admin/help/photo_alt_text.twig:3
#: feathers/photo/admin/help/photo_alt_text.twig:6 feathers/photo/photo.php:154
#: feathers/photo/admin/help/photo_alt_text.twig:6 feathers/photo/photo.php:156
msgid "Alternative Text"
msgstr "Testo Alternative"
@ -59,6 +59,6 @@ msgstr "Didascalia"
msgid "You did not select a photo to upload."
msgstr "Non é stata selezionata alcuna foto da caricare."
#: feathers/photo/photo.php:162
#: feathers/photo/photo.php:164
msgid "Source"
msgstr "Sorgente"

View File

@ -9,11 +9,11 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: Poedit 3.4.2\n"
"X-Generator: Poedit 3.4.4\n"
#. This file is distributed under the same license as the Chyrp Lite package.
#: feathers/photo/admin/help/photo_alt_text.twig:3
#: feathers/photo/admin/help/photo_alt_text.twig:6 feathers/photo/photo.php:154
#: feathers/photo/admin/help/photo_alt_text.twig:6 feathers/photo/photo.php:156
msgid "Alternative Text"
msgstr "Alternatieve tekst"
@ -58,6 +58,6 @@ msgstr "Toelichting"
msgid "You did not select a photo to upload."
msgstr "Je hebt geen afbeelding geslecteerd om te uploaden."
#: feathers/photo/photo.php:162
#: feathers/photo/photo.php:164
msgid "Source"
msgstr "Bron"

View File

@ -10,11 +10,11 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=1; plural=0;\n"
"X-Generator: Poedit 3.4.2\n"
"X-Generator: Poedit 3.4.4\n"
#. This file is distributed under the same license as the Chyrp Lite package.
#: feathers/photo/admin/help/photo_alt_text.twig:3
#: feathers/photo/admin/help/photo_alt_text.twig:6 feathers/photo/photo.php:154
#: feathers/photo/admin/help/photo_alt_text.twig:6 feathers/photo/photo.php:156
msgid "Alternative Text"
msgstr "替代文本"
@ -57,6 +57,6 @@ msgstr "标题"
msgid "You did not select a photo to upload."
msgstr "您没有选择上传的照片。"
#: feathers/photo/photo.php:162
#: feathers/photo/photo.php:164
msgid "Source"
msgstr "来源"

View File

@ -55,15 +55,16 @@
code:422
);
if (isset($_POST['option']['source']) and is_url($_POST['option']['source']))
$_POST['option']['source'] = add_scheme($_POST['option']['source']);
fallback($_POST['title'], "");
fallback($_POST['caption'], "");
fallback($_POST['slug'], $_POST['title']);
fallback($_POST['status'], "public");
fallback($_POST['created_at'], datetime());
fallback($_POST['option'], array());
fallback($_POST['option']['source'], "");
if (is_url($_POST['option']['source']))
$_POST['option']['source'] = add_scheme($_POST['option']['source']);
return Post::add(
values:array(
@ -71,7 +72,7 @@
"filename" => $filename,
"caption" => $_POST['caption']
),
clean:sanitize($_POST['slug']),
clean:sanitize($_POST['slug'], true, SLUG_STRICT, 128),
feather:"photo",
pinned:!empty($_POST['pinned']),
status:$_POST['status'],
@ -84,13 +85,14 @@
public function update($post): Post|false {
fallback($_POST['title'], "");
fallback($_POST['caption'], "");
fallback($_POST['slug'], $post->clean);
fallback($_POST['slug'], "");
fallback($_POST['status'], $post->status);
fallback($_POST['created_at'], $post->created_at);
fallback($_POST['option'], array());
fallback($_POST['option']['source'], "");
$filename = $post->filename;
if (isset($_POST['option']['source']) and is_url($_POST['option']['source']))
if (is_url($_POST['option']['source']))
$_POST['option']['source'] = add_scheme($_POST['option']['source']);
if (isset($_FILES['filename']) and upload_tester($_FILES['filename']))
@ -107,7 +109,7 @@
),
pinned:!empty($_POST['pinned']),
status:$_POST['status'],
clean:sanitize($_POST['slug']),
clean:sanitize($_POST['slug'], true, SLUG_STRICT, 128),
created_at:datetime($_POST['created_at']),
options:$_POST['option']
);

View File

@ -2,7 +2,7 @@
return array(
"name" => __("Quote", "quote"),
"url" => "http://chyrplite.net/",
"version" => "2023.01",
"version" => "2024.03",
"description" => __("Post quotes and cite sources.", "quote"),
"author" => array(
"name" => "Alex Suraci",

View File

@ -47,7 +47,7 @@
"quote" => $_POST['quote'],
"source" => $_POST['source']
),
clean:sanitize($_POST['slug']),
clean:sanitize($_POST['slug'], true, SLUG_STRICT, 128),
feather:"quote",
pinned:!empty($_POST['pinned']),
status:$_POST['status'],
@ -66,7 +66,7 @@
);
fallback($_POST['source'], "");
fallback($_POST['slug'], $post->clean);
fallback($_POST['slug'], "");
fallback($_POST['status'], $post->status);
fallback($_POST['created_at'], $post->created_at);
fallback($_POST['option'], array());
@ -78,7 +78,7 @@
),
pinned:!empty($_POST['pinned']),
status:$_POST['status'],
clean:sanitize($_POST['slug']),
clean:sanitize($_POST['slug'], true, SLUG_STRICT, 128),
created_at:datetime($_POST['created_at']),
options:$_POST['option']
);

View File

@ -2,7 +2,7 @@
return array(
"name" => __("Text", "text"),
"url" => "http://chyrplite.net/",
"version" => "2023.01",
"version" => "2024.03",
"description" => __("A basic text feather.", "text"),
"author" => array(
"name" => "Chyrp Team",

View File

@ -46,7 +46,7 @@
"title" => $_POST['title'],
"body" => $_POST['body']
),
clean:sanitize($_POST['slug']),
clean:sanitize($_POST['slug'], true, SLUG_STRICT, 128),
feather:"text",
pinned:!empty($_POST['pinned']),
status:$_POST['status'],
@ -65,7 +65,7 @@
);
fallback($_POST['title'], "");
fallback($_POST['slug'], $post->clean);
fallback($_POST['slug'], "");
fallback($_POST['status'], $post->status);
fallback($_POST['created_at'], $post->created_at);
fallback($_POST['option'], array());
@ -77,7 +77,7 @@
),
pinned:!empty($_POST['pinned']),
status:$_POST['status'],
clean:sanitize($_POST['slug']),
clean:sanitize($_POST['slug'], true, SLUG_STRICT, 128),
created_at:datetime($_POST['created_at']),
options:$_POST['option']
);

View File

@ -2,7 +2,7 @@
return array(
"name" => __("Uploader", "uploader"),
"url" => "http://chyrplite.net/",
"version" => "2024.01",
"version" => "2024.03",
"description" => __("Upload files and make them available for visitors to download.", "uploader"),
"author" => array(
"name" => "Daniel Pimley",

View File

@ -9,7 +9,7 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: Poedit 3.4.2\n"
"X-Generator: Poedit 3.4.4\n"
#. This file is distributed under the same license as the Chyrp Lite package.
#: feathers/uploader/admin/help/uploader_source.twig:3
@ -45,6 +45,6 @@ msgstr "Unterschrift"
msgid "You did not select any files to upload."
msgstr "Sie haben keine Dateien zum hochladen selektiert."
#: feathers/uploader/uploader.php:214
#: feathers/uploader/uploader.php:216
msgid "Source"
msgstr "Quelle"

View File

@ -33,7 +33,7 @@ msgstr ""
msgid "You did not select any files to upload."
msgstr ""
#: feathers/uploader/uploader.php:214
#: feathers/uploader/uploader.php:216
msgid "Source"
msgstr ""

View File

@ -10,7 +10,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
"X-Generator: Poedit 3.0.1\n"
"X-Generator: Poedit 3.4.4\n"
#. This file is distributed under the same license as the Chyrp Lite package.
#: feathers/uploader/admin/help/uploader_source.twig:3
@ -46,6 +46,6 @@ msgstr "Légende"
msgid "You did not select any files to upload."
msgstr "Vous n'avez pas sélectionné de fichier à télécharger."
#: feathers/uploader/uploader.php:214
#: feathers/uploader/uploader.php:216
msgid "Source"
msgstr "Source"

View File

@ -10,7 +10,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-Generator: Poedit 3.4.2\n"
"X-Generator: Poedit 3.4.4\n"
#. This file is distributed under the same license as the Chyrp Lite package.
#: feathers/uploader/admin/help/uploader_source.twig:3
@ -46,6 +46,6 @@ msgstr "Didascalia"
msgid "You did not select any files to upload."
msgstr "Non è stato selezionato alcun file da caricare."
#: feathers/uploader/uploader.php:214
#: feathers/uploader/uploader.php:216
msgid "Source"
msgstr "Sorgente"

View File

@ -9,7 +9,7 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: Poedit 3.4.2\n"
"X-Generator: Poedit 3.4.4\n"
#. This file is distributed under the same license as the Chyrp Lite package.
#: feathers/uploader/admin/help/uploader_source.twig:3
@ -45,6 +45,6 @@ msgstr "Toelichting"
msgid "You did not select any files to upload."
msgstr "Je hebt geen bestanden geselecteerd om te uploaden."
#: feathers/uploader/uploader.php:214
#: feathers/uploader/uploader.php:216
msgid "Source"
msgstr "Bron"

View File

@ -10,7 +10,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=1; plural=0;\n"
"X-Generator: Poedit 3.4.2\n"
"X-Generator: Poedit 3.4.4\n"
#. This file is distributed under the same license as the Chyrp Lite package.
#: feathers/uploader/admin/help/uploader_source.twig:3
@ -46,6 +46,6 @@ msgstr "说明"
msgid "You did not select any files to upload."
msgstr "您没有选择任何文件上传。"
#: feathers/uploader/uploader.php:214
#: feathers/uploader/uploader.php:216
msgid "Source"
msgstr "来源"

View File

@ -78,15 +78,16 @@
code:422
);
if (isset($_POST['option']['source']) and is_url($_POST['option']['source']))
$_POST['option']['source'] = add_scheme($_POST['option']['source']);
fallback($_POST['title'], "");
fallback($_POST['caption'], "");
fallback($_POST['slug'], $_POST['title']);
fallback($_POST['status'], "public");
fallback($_POST['created_at'], datetime());
fallback($_POST['option'], array());
fallback($_POST['option']['source'], "");
if (is_url($_POST['option']['source']))
$_POST['option']['source'] = add_scheme($_POST['option']['source']);
return Post::add(
values:array(
@ -94,7 +95,7 @@
"caption" => $_POST['caption'],
"title" => $_POST['title']
),
clean:sanitize($_POST['slug']),
clean:sanitize($_POST['slug'], true, SLUG_STRICT, 128),
feather:"uploader",
pinned:!empty($_POST['pinned']),
status:$_POST['status'],
@ -107,13 +108,14 @@
public function update($post): Post|false {
fallback($_POST['title'], "");
fallback($_POST['caption'], "");
fallback($_POST['slug'], $post->clean);
fallback($_POST['slug'], "");
fallback($_POST['status'], $post->status);
fallback($_POST['created_at'], $post->created_at);
fallback($_POST['option'], array());
fallback($_POST['option']['source'], "");
$filenames = $post->filenames;
if (isset($_POST['option']['source']) and is_url($_POST['option']['source']))
if (is_url($_POST['option']['source']))
$_POST['option']['source'] = add_scheme($_POST['option']['source']);
if (isset($_FILES['filenames']) and upload_tester($_FILES['filenames'])) {
@ -143,7 +145,7 @@
),
pinned:!empty($_POST['pinned']),
status:$_POST['status'],
clean:sanitize($_POST['slug']),
clean:sanitize($_POST['slug'], true, SLUG_STRICT, 128),
created_at:datetime($_POST['created_at']),
options:$_POST['option']
);

View File

@ -2,7 +2,7 @@
return array(
"name" => __("Video", "video"),
"url" => "http://chyrplite.net/",
"version" => "2024.01",
"version" => "2024.03",
"description" => __("A feather for video.", "video"),
"author" => array(
"name" => "Daniel Pimley",

View File

@ -102,7 +102,7 @@
"poster_image" => fallback($poster_image, ""),
"description" => $_POST['description']
),
clean:sanitize($_POST['slug']),
clean:sanitize($_POST['slug'], true, SLUG_STRICT, 128),
feather:"video",
pinned:!empty($_POST['pinned']),
status:$_POST['status'],
@ -115,7 +115,7 @@
public function update($post): Post|false {
fallback($_POST['title'], "");
fallback($_POST['description'], "");
fallback($_POST['slug'], $post->clean);
fallback($_POST['slug'], "");
fallback($_POST['status'], $post->status);
fallback($_POST['created_at'], $post->created_at);
fallback($_POST['option'], array());
@ -151,7 +151,7 @@
),
pinned:!empty($_POST['pinned']),
status:$_POST['status'],
clean:sanitize($_POST['slug']),
clean:sanitize($_POST['slug'], true, SLUG_STRICT, 128),
created_at:datetime($_POST['created_at']),
options:$_POST['option']
);

View File

@ -1,7 +1,7 @@
##
## Bundle of CA Root Certificates
##
## Certificate data from Mozilla as of: Tue Dec 12 04:12:04 2023 GMT
## Certificate data from Mozilla as of: Tue Jul 2 03:12:04 2024 GMT
##
## This is a bundle of X.509 certificates of public Certificate Authorities
## (CA). These were automatically extracted from Mozilla's root certificates
@ -14,7 +14,7 @@
## Just configure this file as the SSLCACertificateFile.
##
## Conversion done with mk-ca-bundle.pl version 1.29.
## SHA256: 1970dd65858925d68498d2356aea6d03f764422523c5887deca8ce3ba9e1f845
## SHA256: 456ff095dde6dd73354c5c28c73d9c06f53b61a803963414cb91a1d92945cdd3
##
@ -2600,36 +2600,6 @@ vLtoURMMA/cVi4RguYv/Uo7njLwcAjA8+RHUjE7AwWHCFUyqqx0LMV87HOIAl0Qx5v5zli/altP+
CAezNIm8BZ/3Hobui3A=
-----END CERTIFICATE-----
GLOBALTRUST 2020
================
-----BEGIN CERTIFICATE-----
MIIFgjCCA2qgAwIBAgILWku9WvtPilv6ZeUwDQYJKoZIhvcNAQELBQAwTTELMAkGA1UEBhMCQVQx
IzAhBgNVBAoTGmUtY29tbWVyY2UgbW9uaXRvcmluZyBHbWJIMRkwFwYDVQQDExBHTE9CQUxUUlVT
VCAyMDIwMB4XDTIwMDIxMDAwMDAwMFoXDTQwMDYxMDAwMDAwMFowTTELMAkGA1UEBhMCQVQxIzAh
BgNVBAoTGmUtY29tbWVyY2UgbW9uaXRvcmluZyBHbWJIMRkwFwYDVQQDExBHTE9CQUxUUlVTVCAy
MDIwMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAri5WrRsc7/aVj6B3GyvTY4+ETUWi
D59bRatZe1E0+eyLinjF3WuvvcTfk0Uev5E4C64OFudBc/jbu9G4UeDLgztzOG53ig9ZYybNpyrO
VPu44sB8R85gfD+yc/LAGbaKkoc1DZAoouQVBGM+uq/ufF7MpotQsjj3QWPKzv9pj2gOlTblzLmM
CcpL3TGQlsjMH/1WljTbjhzqLL6FLmPdqqmV0/0plRPwyJiT2S0WR5ARg6I6IqIoV6Lr/sCMKKCm
fecqQjuCgGOlYx8ZzHyyZqjC0203b+J+BlHZRYQfEs4kUmSFC0iAToexIiIwquuuvuAC4EDosEKA
A1GqtH6qRNdDYfOiaxaJSaSjpCuKAsR49GiKweR6NrFvG5Ybd0mN1MkGco/PU+PcF4UgStyYJ9OR
JitHHmkHr96i5OTUawuzXnzUJIBHKWk7buis/UDr2O1xcSvy6Fgd60GXIsUf1DnQJ4+H4xj04KlG
DfV0OoIu0G4skaMxXDtG6nsEEFZegB31pWXogvziB4xiRfUg3kZwhqG8k9MedKZssCz3AwyIDMvU
clOGvGBG85hqwvG/Q/lwIHfKN0F5VVJjjVsSn8VoxIidrPIwq7ejMZdnrY8XD2zHc+0klGvIg5rQ
mjdJBKuxFshsSUktq6HQjJLyQUp5ISXbY9e2nKd+Qmn7OmMCAwEAAaNjMGEwDwYDVR0TAQH/BAUw
AwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFNwuH9FhN3nkq9XVsxJxaD1qaJwiMB8GA1Ud
IwQYMBaAFNwuH9FhN3nkq9XVsxJxaD1qaJwiMA0GCSqGSIb3DQEBCwUAA4ICAQCR8EICaEDuw2jA
VC/f7GLDw56KoDEoqoOOpFaWEhCGVrqXctJUMHytGdUdaG/7FELYjQ7ztdGl4wJCXtzoRlgHNQIw
4Lx0SsFDKv/bGtCwr2zD/cuz9X9tAy5ZVp0tLTWMstZDFyySCstd6IwPS3BD0IL/qMy/pJTAvoe9
iuOTe8aPmxadJ2W8esVCgmxcB9CpwYhgROmYhRZf+I/KARDOJcP5YBugxZfD0yyIMaK9MOzQ0MAS
8cE54+X1+NZK3TTN+2/BT+MAi1bikvcoskJ3ciNnxz8RFbLEAwW+uxF7Cr+obuf/WEPPm2eggAe2
HcqtbepBEX4tdJP7wry+UUTF72glJ4DjyKDUEuzZpTcdN3y0kcra1LGWge9oXHYQSa9+pTeAsRxS
vTOBTI/53WXZFM2KJVj04sWDpQmQ1GwUY7VA3+vA/MRYfg0UFodUJ25W5HCEuGwyEn6CMUO+1918
oa2u1qsgEu8KwxCMSZY13At1XrFP1U80DhEgB3VDRemjEdqso5nCtnkn4rnvyOL2NSl6dPrFf4IF
YqYK6miyeUcGbvJXqBUzxvd4Sj1Ce2t+/vdG6tHrju+IaFvowdlxfv1k7/9nR4hYJS8+hge9+6jl
gqispdNpQ80xiEmEU5LAsTkbOYMBMMTyqfrQA71yN2BWHzZ8vTmR9W0Nv3vXkg==
-----END CERTIFICATE-----
ANF Secure Server Root CA
=========================
-----BEGIN CERTIFICATE-----
@ -3532,3 +3502,67 @@ dVwPaFsdZcJfMw8eD/A7hvWwTruc9+olBdytoptLFwG+Qt81IR2tq670v64fG9PiO/yzcnMcmyiQ
iRM9HcEARwmWmjgb3bHPDcK0RPOWlc4yOo80nOAXx17Org3bhzjlP1v9mxnhMUF6cKojawHhRUzN
lM47ni3niAIi9G7oyOzWPPO5std3eqx7
-----END CERTIFICATE-----
Telekom Security TLS ECC Root 2020
==================================
-----BEGIN CERTIFICATE-----
MIICQjCCAcmgAwIBAgIQNjqWjMlcsljN0AFdxeVXADAKBggqhkjOPQQDAzBjMQswCQYDVQQGEwJE
RTEnMCUGA1UECgweRGV1dHNjaGUgVGVsZWtvbSBTZWN1cml0eSBHbWJIMSswKQYDVQQDDCJUZWxl
a29tIFNlY3VyaXR5IFRMUyBFQ0MgUm9vdCAyMDIwMB4XDTIwMDgyNTA3NDgyMFoXDTQ1MDgyNTIz
NTk1OVowYzELMAkGA1UEBhMCREUxJzAlBgNVBAoMHkRldXRzY2hlIFRlbGVrb20gU2VjdXJpdHkg
R21iSDErMCkGA1UEAwwiVGVsZWtvbSBTZWN1cml0eSBUTFMgRUNDIFJvb3QgMjAyMDB2MBAGByqG
SM49AgEGBSuBBAAiA2IABM6//leov9Wq9xCazbzREaK9Z0LMkOsVGJDZos0MKiXrPk/OtdKPD/M1
2kOLAoC+b1EkHQ9rK8qfwm9QMuU3ILYg/4gND21Ju9sGpIeQkpT0CdDPf8iAC8GXs7s1J8nCG6NC
MEAwHQYDVR0OBBYEFONyzG6VmUex5rNhTNHLq+O6zd6fMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0P
AQH/BAQDAgEGMAoGCCqGSM49BAMDA2cAMGQCMHVSi7ekEE+uShCLsoRbQuHmKjYC2qBuGT8lv9pZ
Mo7k+5Dck2TOrbRBR2Diz6fLHgIwN0GMZt9Ba9aDAEH9L1r3ULRn0SyocddDypwnJJGDSA3PzfdU
ga/sf+Rn27iQ7t0l
-----END CERTIFICATE-----
Telekom Security TLS RSA Root 2023
==================================
-----BEGIN CERTIFICATE-----
MIIFszCCA5ugAwIBAgIQIZxULej27HF3+k7ow3BXlzANBgkqhkiG9w0BAQwFADBjMQswCQYDVQQG
EwJERTEnMCUGA1UECgweRGV1dHNjaGUgVGVsZWtvbSBTZWN1cml0eSBHbWJIMSswKQYDVQQDDCJU
ZWxla29tIFNlY3VyaXR5IFRMUyBSU0EgUm9vdCAyMDIzMB4XDTIzMDMyODEyMTY0NVoXDTQ4MDMy
NzIzNTk1OVowYzELMAkGA1UEBhMCREUxJzAlBgNVBAoMHkRldXRzY2hlIFRlbGVrb20gU2VjdXJp
dHkgR21iSDErMCkGA1UEAwwiVGVsZWtvbSBTZWN1cml0eSBUTFMgUlNBIFJvb3QgMjAyMzCCAiIw
DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAO01oYGA88tKaVvC+1GDrib94W7zgRJ9cUD/h3VC
KSHtgVIs3xLBGYSJwb3FKNXVS2xE1kzbB5ZKVXrKNoIENqil/Cf2SfHVcp6R+SPWcHu79ZvB7JPP
GeplfohwoHP89v+1VmLhc2o0mD6CuKyVU/QBoCcHcqMAU6DksquDOFczJZSfvkgdmOGjup5czQRx
UX11eKvzWarE4GC+j4NSuHUaQTXtvPM6Y+mpFEXX5lLRbtLevOP1Czvm4MS9Q2QTps70mDdsipWo
l8hHD/BeEIvnHRz+sTugBTNoBUGCwQMrAcjnj02r6LX2zWtEtefdi+zqJbQAIldNsLGyMcEWzv/9
FIS3R/qy8XDe24tsNlikfLMR0cN3f1+2JeANxdKz+bi4d9s3cXFH42AYTyS2dTd4uaNir73Jco4v
zLuu2+QVUhkHM/tqty1LkCiCc/4YizWN26cEar7qwU02OxY2kTLvtkCJkUPg8qKrBC7m8kwOFjQg
rIfBLX7JZkcXFBGk8/ehJImr2BrIoVyxo/eMbcgByU/J7MT8rFEz0ciD0cmfHdRHNCk+y7AO+oML
KFjlKdw/fKifybYKu6boRhYPluV75Gp6SG12mAWl3G0eQh5C2hrgUve1g8Aae3g1LDj1H/1Joy7S
WWO/gLCMk3PLNaaZlSJhZQNg+y+TS/qanIA7AgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIBBjAdBgNV
HQ4EFgQUtqeXgj10hZv3PJ+TmpV5dVKMbUcwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBS2
p5eCPXSFm/c8n5OalXl1UoxtRzANBgkqhkiG9w0BAQwFAAOCAgEAqMxhpr51nhVQpGv7qHBFfLp+
sVr8WyP6Cnf4mHGCDG3gXkaqk/QeoMPhk9tLrbKmXauw1GLLXrtm9S3ul0A8Yute1hTWjOKWi0Fp
kzXmuZlrYrShF2Y0pmtjxrlO8iLpWA1WQdH6DErwM807u20hOq6OcrXDSvvpfeWxm4bu4uB9tPcy
/SKE8YXJN3nptT+/XOR0so8RYgDdGGah2XsjX/GO1WfoVNpbOms2b/mBsTNHM3dA+VKq3dSDz4V4
mZqTuXNnQkYRIer+CqkbGmVps4+uFrb2S1ayLfmlyOw7YqPta9BO1UAJpB+Y1zqlklkg5LB9zVtz
aL1txKITDmcZuI1CfmwMmm6gJC3VRRvcxAIU/oVbZZfKTpBQCHpCNfnqwmbU+AGuHrS+w6jv/naa
oqYfRvaE7fzbzsQCzndILIyy7MMAo+wsVRjBfhnu4S/yrYObnqsZ38aKL4x35bcF7DvB7L6Gs4a8
wPfc5+pbrrLMtTWGS9DiP7bY+A4A7l3j941Y/8+LN+ljX273CXE2whJdV/LItM3z7gLfEdxquVeE
HVlNjM7IDiPCtyaaEBRx/pOyiriA8A4QntOoUAw3gi/q4Iqd4Sw5/7W0cwDk90imc6y/st53BIe0
o82bNSQ3+pCTE4FCxpgmdTdmQRCsu/WU48IxK63nI1bMNSWSs1A=
-----END CERTIFICATE-----
FIRMAPROFESIONAL CA ROOT-A WEB
==============================
-----BEGIN CERTIFICATE-----
MIICejCCAgCgAwIBAgIQMZch7a+JQn81QYehZ1ZMbTAKBggqhkjOPQQDAzBuMQswCQYDVQQGEwJF
UzEcMBoGA1UECgwTRmlybWFwcm9mZXNpb25hbCBTQTEYMBYGA1UEYQwPVkFURVMtQTYyNjM0MDY4
MScwJQYDVQQDDB5GSVJNQVBST0ZFU0lPTkFMIENBIFJPT1QtQSBXRUIwHhcNMjIwNDA2MDkwMTM2
WhcNNDcwMzMxMDkwMTM2WjBuMQswCQYDVQQGEwJFUzEcMBoGA1UECgwTRmlybWFwcm9mZXNpb25h
bCBTQTEYMBYGA1UEYQwPVkFURVMtQTYyNjM0MDY4MScwJQYDVQQDDB5GSVJNQVBST0ZFU0lPTkFM
IENBIFJPT1QtQSBXRUIwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAARHU+osEaR3xyrq89Zfe9MEkVz6
iMYiuYMQYneEMy3pA4jU4DP37XcsSmDq5G+tbbT4TIqk5B/K6k84Si6CcyvHZpsKjECcfIr28jlg
st7L7Ljkb+qbXbdTkBgyVcUgt5SjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUk+FD
Y1w8ndYn81LsF7Kpryz3dvgwHQYDVR0OBBYEFJPhQ2NcPJ3WJ/NS7Beyqa8s93b4MA4GA1UdDwEB
/wQEAwIBBjAKBggqhkjOPQQDAwNoADBlAjAdfKR7w4l1M+E7qUW/Runpod3JIha3RxEL2Jq68cgL
cFBTApFwhVmpHqTm6iMxoAACMQD94vizrxa5HnPEluPBMBnYfubDl94cT7iJLzPrSA8Z94dGXSaQ
pYXFuXqUPoeovQA=
-----END CERTIFICATE-----

View File

@ -8,6 +8,10 @@
# #...
# }
@twigs {
path *.twig
}
@admin {
path /{chyrp_path}/admin/*
file {
@ -22,6 +26,6 @@
}
}
rewrite *.twig /{chyrp_path}/index.php
rewrite @twigs /{chyrp_path}/index.php
rewrite @admin {http.matchers.file.relative}
rewrite @chyrp {http.matchers.file.relative}

View File

@ -56,7 +56,10 @@
$this->has_many = (array) $this->has_many;
$this->has_one = (array) $this->has_one;
if (in_array($name, $this->belongs_to) or isset($this->belongs_to[$name])) {
if (
in_array($name, $this->belongs_to) or
isset($this->belongs_to[$name])
) {
if (isset($this->belongs_to[$name])) {
$opts =& $this->belongs_to[$name];
@ -68,7 +71,11 @@
$opts["by"] :
strtolower($name) ;
fallback($opts["where"], array("id" => $this->data[$match."_id"]));
fallback(
$opts["where"],
array("id" => $this->data[$match."_id"])
);
$opts["where"] = (array) $opts["where"];
} else {
$model = $name;
@ -80,7 +87,10 @@
$this->data[$name] = new $model(null, $opts);
return $this->data[$name];
} elseif (in_array($name, $this->has_many) or isset($this->has_many[$name])) {
} elseif (
in_array($name, $this->has_many) or
isset($this->has_many[$name])
) {
if (isset($this->has_many[$name])) {
$opts =& $this->has_many[$name];
@ -92,7 +102,11 @@
$opts["by"] :
strtolower($name) ;
fallback($opts["where"], array($match."_id" => $this->data["id"]));
fallback(
$opts["where"],
array($match."_id" => $this->data["id"])
);
$opts["where"] = (array) $opts["where"];
} else {
$model = depluralize($name);
@ -105,7 +119,10 @@
$this->data[$name] = call_user_func(array($model, "find"), $opts);
return $this->data[$name];
} elseif (in_array($name, $this->has_one) or isset($this->has_one[$name])) {
} elseif (
in_array($name, $this->has_one) or
isset($this->has_one[$name])
) {
if (isset($this->has_one[$name])) {
$opts =& $this->has_one[$name];
@ -117,7 +134,11 @@
$opts["by"] :
strtolower($name) ;
fallback($opts["where"], array($match."_id" => $this->data["id"]));
fallback(
$opts["where"],
array($match."_id" => $this->data["id"])
);
$opts["where"] = (array) $opts["where"];
} else {
$model = depluralize($name);
@ -126,7 +147,9 @@
"user" :
$model_name ;
$opts = array("where" => array($match."_id" => $this->data["id"]));
$opts = array(
"where" => array($match."_id" => $this->data["id"])
);
}
$this->data[$name] = new $model(null, $opts);
@ -150,9 +173,10 @@
* Handles model relationships, deferred and dynamic attributes.
*/
public function __isset($name): bool {
$trigger = Trigger::current();
$model_name = strtolower(get_class($this));
if (Trigger::current()->exists($model_name."_".$name."_attr"))
if ($trigger->exists($model_name."_".$name."_attr"))
return true;
if (isset($this->data[$name]))
@ -162,13 +186,22 @@
$this->has_many = (array) $this->has_many;
$this->has_one = (array) $this->has_one;
if (in_array($name, $this->belongs_to) or isset($this->belongs_to[$name]))
if (
in_array($name, $this->belongs_to) or
isset($this->belongs_to[$name])
)
return true;
if (in_array($name, $this->has_many) or isset($this->has_many[$name]))
if (
in_array($name, $this->has_many) or
isset($this->has_many[$name])
)
return true;
if (in_array($name, $this->has_one) or isset($this->has_one[$name]))
if (
in_array($name, $this->has_one) or
isset($this->has_one[$name])
)
return true;
return false;
@ -210,8 +243,10 @@
# Return cached results if available.
if (empty($options["read_from"])) {
if (isset($cache_id) and isset(self::$caches[$model_name][$cache_id])) {
if (
isset($cache_id) and
isset(self::$caches[$model_name][$cache_id])
) {
foreach (self::$caches[$model_name][$cache_id] as $attr => $val)
$model->$attr = $val;
@ -237,10 +272,11 @@
$options["from"] = (array) $options["from"];
$options["select"] = (array) $options["select"];
if (is_numeric($id))
if (is_numeric($id)) {
$options["where"]["id"] = $id;
elseif (is_array($id))
} elseif (is_array($id)) {
$options["where"] = array_merge($options["where"], $id);
}
$sql = SQL::current();
$trigger = Trigger::current();
@ -350,6 +386,7 @@
$options = array(),
$options_for_object = array()
): array {
$trigger = Trigger::current();
$model_name = strtolower($model);
fallback($options["select"], "*");
@ -368,7 +405,7 @@
$options["from"] = (array) $options["from"];
$options["select"] = (array) $options["select"];
Trigger::current()->filter($options, pluralize(strtolower($model_name))."_get");
$trigger->filter($options, pluralize(strtolower($model_name))."_get");
$grab = SQL::current()->select(
tables:$options["from"],
@ -493,7 +530,11 @@
$name = strtolower(get_class($this));
$url = url("edit_".$name."/id/".$this->id, AdminController::current());
$url = url(
"edit_".$name."/id/".$this->id,
AdminController::current()
);
$classes = $classes.' '.$name.'_edit_link edit_link';
echo $before.'<a href="'.$url.'" class="'.trim($classes).
@ -523,10 +564,33 @@
$name = strtolower(get_class($this));
$url = url("delete_".$name."/id/".$this->id, AdminController::current());
$url = url(
"delete_".$name."/id/".$this->id,
AdminController::current()
);
$classes = $classes.' '.$name.'_delete_link delete_link';
echo $before.'<a href="'.$url.'" class="'.trim($classes).
'" id="'.$name.'_delete_'.$this->id.'">'.$text.'</a>'.$after;
}
/**
* Function: etag
* Generates an Etag for the object.
*/
public function etag(): string|false {
if ($this->no_results)
return false;
$array = array(get_class($this), $this->id);
if (isset($this->created_at))
$array[] = $this->created_at;
if (isset($this->updated_at))
$array[] = $this->updated_at;
return (isset($this->updated_at) ? '"' : 'W/"').token($array).'"';
}
}

View File

@ -13,7 +13,7 @@
public $result;
# Variable: $queryString
# Holds the query statement.
# Logs a representation of the query statement.
public $queryString = "";
# Variable: $sql
@ -38,7 +38,12 @@
* $params - An associative array of parameters used in the query.
* $throw_exceptions - Throw exceptions instead of calling error()?
*/
public function __construct($sql, $query, $params = array(), $throw_exceptions = false) {
public function __construct(
$sql,
$query,
$params = array(),
$throw_exceptions = false
) {
$this->sql = $sql;
# Don't count config setting queries.
@ -51,6 +56,13 @@
$this->throw_exceptions = $throw_exceptions;
$this->queryString = $query;
foreach ($params as $name => $val)
$this->queryString = preg_replace(
"/{$name}([^a-zA-Z0-9_]|$)/",
"[".serialize($val)."]"."$1",
$this->queryString
);
if ($count and DEBUG) {
$trace = debug_backtrace();
$target = $trace[$index = 0];
@ -68,24 +80,11 @@
break;
}
$logQuery = $query;
foreach ($params as $name => $val)
$logQuery = preg_replace(
"/{$name}([^a-zA-Z0-9_]|$)/",
str_replace(
"\\",
"\\\\",
$this->sql->escape($val, !is_int($val))
)."$1",
$logQuery
);
$this->sql->debug[] = array(
"number" => $this->sql->queries,
"file" => str_replace(MAIN_DIR."/", "", $target["file"]),
"file" => str_replace(MAIN_DIR.DIR, "", $target["file"]),
"line" => $target["line"],
"query" => $logQuery,
"query" => $this->queryString,
"time" => timer_stop()
);
}
@ -93,18 +92,6 @@
try {
$this->query = $this->sql->db->prepare($query);
$this->result = $this->query->execute($params);
$this->queryString = $query;
foreach ($params as $name => $val)
$this->queryString = preg_replace(
"/{$name}([^a-zA-Z0-9_]|$)/",
str_replace(
array("\\", "\$"),
array("\\\\", "\\\$"),
$this->sql->escape($val, !is_int($val))
)."$1",
$this->queryString
);
if (!$this->result)
throw new PDOException(

View File

@ -481,18 +481,31 @@
if (is_object($val) and !$val instanceof Stringable)
$val = null;
if (is_bool($val))
$val = (int) $val;
if (is_float($val))
$val = (string) $val;
$return[] = isset($params[$val]) ?
$val :
SQL::current()->escape($val, !is_int($val)) ;
switch (gettype($val)) {
case "NULL":
$return[] = "NULL";
break;
case "boolean":
$return[] = (string) (int) $val;
break;
case "double":
$return[] = $sql->escape($val);
break;
case "integer":
$return[] = (string) $val;
break;
case "object":
$return[] = $sql->escape($val);
break;
case "string":
$return[] = isset($params[$val]) ?
$val :
$sql->escape($val) ;
break;
}
}
return "(".join(", ", $return).")";
return "(".implode(", ", $return).")";
}
/**
@ -547,13 +560,16 @@
# PostgreSQL: cast to text to enable LIKE operator.
$text = ($sql->adapter == "pgsql") ? "::text" : "" ;
# ESCAPE clause for LIKE.
$escape = " ESCAPE '|'";
foreach ($conds as $key => $val) {
if (is_int($key)) {
# Full expression.
$cond = $val;
} else {
# Key => Val expression.
if (is_string($val) and strlen($val) and strpos($val, ":") === 0) {
if (is_string($val) and str_starts_with($val, ":")) {
$cond = self::safecol($sql, $key)." = ".$val;
} else {
if (is_object($val) and !$val instanceof Stringable)
@ -596,7 +612,7 @@
"_",
$key
)."_".$index;
$likes[] = $key.$text." LIKE :".$param;
$likes[] = $key.$text." LIKE :".$param.$escape;
$params[":".$param] = $match;
}
@ -612,7 +628,7 @@
"_",
$key
)."_".$index;
$likes[] = $key.$text." NOT LIKE :".$param;
$likes[] = $key.$text." NOT LIKE :".$param.$escape;
$params[":".$param] = $match;
}
@ -628,7 +644,7 @@
"_",
$key
)."_".$index;
$likes[] = $key.$text." LIKE :".$param;
$likes[] = $key.$text." LIKE :".$param.$escape;
$params[":".$param] = $match;
}
@ -641,7 +657,7 @@
"_",
$key
);
$cond = $key.$text." NOT LIKE :".$param;
$cond = $key.$text." NOT LIKE :".$param.$escape;
$params[":".$param] = $val;
} elseif (substr($uck, -5) == " LIKE") {
# LIKE.
@ -651,7 +667,7 @@
"_",
$key
);
$cond = $key.$text." LIKE :".$param;
$cond = $key.$text." LIKE :".$param.$escape;
$params[":".$param] = $val;
} elseif (substr_count($key, " ")) {
# Custom operation, e.g. array("foo >" => $bar).

View File

@ -220,7 +220,7 @@
$config->chyrp_url."/".$controller->base ;
# Assume this is a dirty URL and return it without translation.
if (strpos($url, "/") === 0)
if (str_starts_with($url, "/"))
return fix($base.$url, true);
# Assume this is a clean URL and ensure it ends with a slash.

View File

@ -447,22 +447,26 @@
*
* Parameters:
* $string - String to escape.
* $quotes - Wrap the string in single quotes?
*/
public function escape(
$string,
$quotes = true
): string {
public function escape($string): string {
if (!isset($this->db))
$this->connect();
$string = $this->db->quote($string);
$string = str_replace('$', '\$', $string);
switch (gettype($string)) {
case "NULL":
$type = PDO::PARAM_NULL;
break;
case "boolean":
$type = PDO::PARAM_BOOL;
break;
case "integer":
$type = PDO::PARAM_INT;
break;
default:
$type = PDO::PARAM_STR;
}
if (!$quotes)
$string = trim($string, "'");
return $string;
return $this->db->quote($string, $type);
}
/**

View File

@ -26,6 +26,7 @@
*/
private function __construct() {
$this->url = THEME_URL;
$this->safename = PREVIEWING ?
$_SESSION['theme'] :
Config::current()->theme ;
@ -33,17 +34,20 @@
/**
* Function: pages_list
* Returns a simple array of pages with @depth@ and @children@ attributes.
* Returns an array of pages with @depth@ and @children@ attributes.
*
* Parameters:
* $page_id - Page ID to use as the basis.
* $exclude - Page ID to exclude from the list.
* $page_id - Page ID to start from, or zero to return all pages.
* $exclude - Page ID/s to exclude, integer or array of integers.
*/
public function pages_list($page_id = 0, $exclude = null): array {
$cache_id = serialize(array($page_id, $exclude));
if (isset($this->caches["pages_list"][$cache_id]))
if (
isset($this->caches["pages_list"][$cache_id])
) {
return $this->caches["pages_list"][$cache_id];
}
$this->caches["pages"]["flat"] = array();
$this->caches["pages"]["children"] = array();
@ -53,8 +57,12 @@
if (MAIN)
$where["show_in_list"] = true;
$pages = Page::find(array("where" => $where,
"order" => "list_order ASC"));
$pages = Page::find(
array(
"where" => $where,
"order" => "list_order ASC, title ASC"
)
);
if (empty($pages))
return $this->caches["pages_list"][$cache_id] = array();
@ -72,30 +80,36 @@
$this->recurse_pages($page);
}
return $this->caches["pages_list"][$cache_id] = $this->caches["pages"]["flat"];
$list = $this->caches["pages"]["flat"];
return $this->caches["pages_list"][$cache_id] = $list;
}
/**
* Function: recurse_pages
* Populates the page cache and gives each page @depth@ and @children@ attributes.
* Populates the page cache and gives each page the attributes
* of @depth@ (integer, 1 or greater) and @children@ (boolean).
*
* Parameters:
* $page - Page to start recursion at.
*/
private function recurse_pages($page): void {
$page->depth = isset($page->depth) ?
$page->depth :
1 ;
if (!isset($page->depth))
$page->depth = 1;
$page->children = isset($this->caches["pages"]["children"][$page->id]);
$page->children = isset(
$this->caches["pages"]["children"][$page->id]
);
$this->caches["pages"]["flat"][] = $page;
if (isset($this->caches["pages"]["children"][$page->id]))
foreach ($this->caches["pages"]["children"][$page->id] as $child) {
if ($page->children) {
foreach (
$this->caches["pages"]["children"][$page->id] as $child
) {
$child->depth = $page->depth + 1;
$this->recurse_pages($child);
}
}
}
/**
@ -106,8 +120,11 @@
* $limit - Maximum number of months to list.
*/
public function archives_list($limit = 12): array {
if (isset($this->caches["archives_list"][$limit]))
if (
isset($this->caches["archives_list"][$limit])
) {
return $this->caches["archives_list"][$limit];
}
$main = MainController::current();
$sql = SQL::current();
@ -125,7 +142,10 @@
foreach ($results as $result) {
$created_at = strtotime($result["created_at"]);
$this_month = strtotime("midnight first day of this month", $created_at);
$this_month = strtotime(
"midnight first day of this month",
$created_at
);
if (!isset($nums[$this_month])) {
if (count($nums) == $limit)
@ -158,8 +178,11 @@
* $limit - Maximum number of recent posts to list.
*/
public function recent_posts($limit = 5): array {
if (isset($this->caches["recent_posts"][$limit]))
if (
isset($this->caches["recent_posts"][$limit])
) {
return $this->caches["recent_posts"][$limit];
}
$results = Post::find(
array(
@ -171,12 +194,13 @@
$posts = array();
for ($i = 0; $i < $limit; $i++)
for ($i = 0; $i < $limit; $i++) {
if (isset($results[0][$i]))
$posts[] = new Post(
null,
array("read_from" => $results[0][$i])
);
}
return $this->caches["recent_posts"][$limit] = $posts;
}
@ -193,8 +217,11 @@
if ($post->no_results)
return array();
if (isset($this->caches["related_posts"][$post->id][$limit]))
if (
isset($this->caches["related_posts"][$post->id][$limit])
) {
return $this->caches["related_posts"][$post->id][$limit];
}
$ids = array();
@ -206,7 +233,7 @@
$results = Post::find(
array(
"placeholders" => true,
"where" => array("id" => $ids),
"where" => array("id" => array_unique($ids)),
"order" => "created_at DESC, id DESC")
);
@ -253,7 +280,10 @@
fix($stylesheet, true).
'" type="text/css" media="all">';
if (is_dir(THEME_DIR.DIR."stylesheets") or is_dir(THEME_DIR.DIR."css")) {
if (
is_dir(THEME_DIR.DIR."stylesheets") or
is_dir(THEME_DIR.DIR."css")
) {
foreach (
array_merge(
(array) glob(THEME_DIR.DIR."stylesheets".DIR."*.css"),
@ -262,7 +292,7 @@
) {
$filename = basename($filepath);
if (empty($filename) or substr_count($filename, ".inc.css"))
if (empty($filename) or str_ends_with($filename, ".inc.css"))
continue;
$qdir = preg_quote(DIR, "/");
@ -271,7 +301,10 @@
"$2",
$filepath
);
$href = $config->chyrp_url."/themes/".str_replace(DIR, "/", $path);
$href = $config->chyrp_url.
"/themes/".
str_replace(DIR, "/", $path);
$tags[] = '<link rel="stylesheet" href="'.
fix($href, true).
'" type="text/css" media="all">';
@ -298,9 +331,14 @@
$tags = array();
foreach ($scripts as $script)
$tags[] = '<script src="'.fix($script, true).'"></script>';
$tags[] = '<script src="'.
fix($script, true).
'"></script>';
if (is_dir(THEME_DIR.DIR."javascripts") or is_dir(THEME_DIR.DIR."js")) {
if (
is_dir(THEME_DIR.DIR."javascripts") or
is_dir(THEME_DIR.DIR."js")
) {
foreach (
array_merge(
(array) glob(THEME_DIR.DIR."javascripts".DIR."*.js"),
@ -309,7 +347,7 @@
) {
$filename = basename($filepath);
if (empty($filename) or substr_count($filename, ".inc.js"))
if (empty($filename) or str_ends_with($filename, ".inc.js"))
continue;
$qdir = preg_quote(DIR, "/");
@ -318,8 +356,14 @@
"$2",
$filepath
);
$href = $config->chyrp_url."/themes/".str_replace(DIR, "/", $path);
$tags[] = '<script src="'.fix($href, true).'"></script>';
$href = $config->chyrp_url.
"/themes/".
str_replace(DIR, "/", $path);
$tags[] = '<script src="'.
fix($href, true).
'"></script>';
}
}
@ -356,14 +400,20 @@
self_url() ;
$feed_url = ($config->clean_urls) ?
rtrim($page_url, "/")."/feed/" :
$page_url.(substr_count($page_url, "?") ? "&feed" : "?feed") ;
rtrim($page_url, "/")."/feed/"
:
$page_url.(
substr_count($page_url, "?") ?
"&feed" :
"?feed"
)
;
$links[] = array(
"href" => $feed_url,
"type" => BlogFeed::type(),
"title" => $this->title
);
$links[] = array(
"href" => $feed_url,
"type" => BlogFeed::type(),
"title" => $this->title
);
}
# Ask extensions to provide additional links.

View File

@ -10,11 +10,11 @@
# Constant: CHYRP_VERSION
# Version number for this release.
define('CHYRP_VERSION', "2024.02");
define('CHYRP_VERSION', "2024.03");
# Constant: CHYRP_CODENAME
# The codename for this version.
define('CHYRP_CODENAME', "Miombo");
define('CHYRP_CODENAME', "Oak");
# Constant: CHYRP_IDENTITY
# The string identifying this version.
@ -124,6 +124,10 @@
# Deny session storage to robots?
define('SESSION_DENY_BOT', true);
# Constant: SLUG_STRICT
# Use strict sanitization for slugs?
define('SLUG_STRICT', true);
# Constant: GET_REMOTE_UNSAFE
# Allow get_remote() to connect to private and reserved IP addresses?
define('GET_REMOTE_UNSAFE', false);
@ -137,18 +141,31 @@
if (!defined('USE_OB'))
define('USE_OB', true);
# Constant: HTTP_ACCEPT_ZSTD
# Does the user agent accept Zstandard encoding?
define('HTTP_ACCEPT_ZSTD',
isset($_SERVER['HTTP_ACCEPT_ENCODING']) and
str_contains($_SERVER['HTTP_ACCEPT_ENCODING'], "zstd")
);
# Constant: HTTP_ACCEPT_DEFLATE
# Does the user agent accept deflate encoding?
define('HTTP_ACCEPT_DEFLATE',
isset($_SERVER['HTTP_ACCEPT_ENCODING']) and
substr_count($_SERVER['HTTP_ACCEPT_ENCODING'], "deflate")
str_contains($_SERVER['HTTP_ACCEPT_ENCODING'], "deflate")
);
# Constant: HTTP_ACCEPT_GZIP
# Does the user agent accept gzip encoding?
define('HTTP_ACCEPT_GZIP',
isset($_SERVER['HTTP_ACCEPT_ENCODING']) and
substr_count($_SERVER['HTTP_ACCEPT_ENCODING'], "gzip")
str_contains($_SERVER['HTTP_ACCEPT_ENCODING'], "gzip")
);
# Constant: CAN_USE_ZSTD
# Can we use zstd to compress output?
define('CAN_USE_ZSTD',
HTTP_ACCEPT_ZSTD and extension_loaded("zstd")
);
# Constant: CAN_USE_ZLIB
@ -157,16 +174,27 @@
(HTTP_ACCEPT_DEFLATE or HTTP_ACCEPT_GZIP) and extension_loaded("zlib")
);
# Constant: USE_ZLIB
# Use zlib to provide content compression?
if (!defined('USE_ZLIB'))
define('USE_ZLIB', CAN_USE_ZLIB and !ini_get("zlib.output_compression"));
# Constant: USE_COMPRESSION
# Use content compression for responses?
if (!defined('USE_COMPRESSION'))
define('USE_COMPRESSION',
(CAN_USE_ZSTD or CAN_USE_ZLIB) and !ini_get("zlib.output_compression")
);
# Start output buffering and set the header.
if (USE_OB) {
if (USE_ZLIB) {
ob_start("ob_gzhandler");
header("Content-Encoding: ".(HTTP_ACCEPT_GZIP ? "gzip" : "deflate"));
if (USE_COMPRESSION) {
if (CAN_USE_ZSTD) {
ob_start(
function ($data) {
return zstd_compress($data, ZSTD_COMPRESS_LEVEL_DEFAULT);
}
);
header("Content-Encoding: zstd");
} else {
ob_start("ob_gzhandler");
header("Content-Encoding: ".(HTTP_ACCEPT_GZIP ? "gzip" : "deflate"));
}
} else {
ob_start();
}

View File

@ -37,9 +37,12 @@
* Loads the Twig parser and sets up the l10n domain.
*/
private function __construct() {
$chain = array(new \Twig\Loader\FilesystemLoader(MAIN_DIR.DIR."admin"));
$config = Config::current();
$chain = array(
new \Twig\Loader\FilesystemLoader(MAIN_DIR.DIR."admin")
);
foreach ($config->enabled_modules as $module) {
if (is_dir(MODULES_DIR.DIR.$module.DIR."admin"))
$chain[] = new \Twig\Loader\FilesystemLoader(
@ -63,7 +66,9 @@
"strict_variables" => DEBUG,
"charset" => "UTF-8",
"cache" => CACHES_DIR.DIR."twig",
"autoescape" => false)
"autoescape" => false,
"use_yield" => true
)
);
$this->twig->addExtension(
@ -300,9 +305,9 @@
);
if ($post->no_results)
Flash::warning(
__("Post not found."),
"manage_posts"
show_404(
__("Not Found"),
__("Post not found.")
);
if (!$post->editable())
@ -408,9 +413,9 @@
);
if ($post->no_results)
Flash::warning(
__("Post not found."),
"manage_posts"
show_404(
__("Not Found"),
__("Post not found.")
);
if (!$post->deletable())
@ -483,7 +488,11 @@
if (isset($_POST['query']))
redirect(
"manage_posts/query/".
str_ireplace("%2F", "", urlencode($_POST['query'])).
str_ireplace(
array("%2F", "%5C"),
"%5F",
urlencode($_POST['query'])
).
"/"
);
@ -655,7 +664,7 @@
public:$public,
show_in_list:$listed,
list_order:$list_order,
clean:sanitize($_POST['slug'])
clean:sanitize($_POST['slug'], true, true, 128)
);
$page_redirect = ($visitor->group->can("edit_page", "delete_page")) ?
@ -693,9 +702,9 @@
);
if ($page->no_results)
Flash::warning(
__("Page not found."),
"manage_pages"
show_404(
__("Not Found"),
__("Page not found.")
);
if (!empty($_SESSION['redirect_to']))
@ -772,7 +781,7 @@
fallback($_POST['parent_id'], 0);
fallback($_POST['status'], "public");
fallback($_POST['list_priority'], 0);
fallback($_POST['slug'], $page->clean);
fallback($_POST['slug'], "");
$public = in_array(
$_POST['status'],
@ -801,7 +810,7 @@
public:$public,
show_in_list:$listed,
list_order:$list_order,
clean:sanitize($_POST['slug'])
clean:sanitize($_POST['slug'], true, true, 128)
);
Flash::notice(
@ -832,9 +841,9 @@
$page = new Page($_GET['id']);
if ($page->no_results)
Flash::warning(
__("Page not found."),
"manage_pages"
show_404(
__("Not Found"),
__("Page not found.")
);
$this->display(
@ -917,7 +926,11 @@
if (isset($_POST['query']))
redirect(
"manage_pages/query/".
str_ireplace("%2F", "", urlencode($_POST['query'])).
str_ireplace(
array("%2F", "%5C"),
"%5F",
urlencode($_POST['query'])
).
"/"
);
@ -1105,9 +1118,9 @@
$user = new User($_GET['id']);
if ($user->no_results)
Flash::warning(
__("User not found."),
"manage_users"
show_404(
__("Not Found"),
__("User not found.")
);
$options = array(
@ -1280,9 +1293,9 @@
$user = new User($_GET['id']);
if ($user->no_results)
Flash::warning(
__("User not found."),
"manage_users"
show_404(
__("Not Found"),
__("User not found.")
);
if ($user->id == Visitor::current()->id)
@ -1405,7 +1418,11 @@
if (isset($_POST['query']))
redirect(
"manage_users/query/".
str_ireplace("%2F", "", urlencode($_POST['query'])).
str_ireplace(
array("%2F", "%5C"),
"%5F",
urlencode($_POST['query'])
).
"/"
);
@ -1520,9 +1537,9 @@
$group = new Group($_GET['id']);
if ($group->no_results)
Flash::warning(
__("Group not found."),
"manage_groups"
show_404(
__("Not Found"),
__("Group not found.")
);
$this->display(
@ -1789,7 +1806,11 @@
if (isset($_POST['search']))
redirect(
"manage_groups/search/".
str_ireplace("%2F", "", urlencode($_POST['search'])).
str_ireplace(
array("%2F", "%5C"),
"%5F",
urlencode($_POST['search'])
).
"/"
);
@ -1837,9 +1858,9 @@
$filepath = uploaded($filename, false);
if (!is_readable($filepath) or !is_file($filepath))
Flash::warning(
__("File not found."),
"manage_uploads"
show_404(
__("Not Found"),
__("File not found.")
);
$post_count = $sql->count(
@ -1899,9 +1920,9 @@
$filepath = uploaded($filename, false);
if (!is_readable($filepath) or !is_file($filepath))
Flash::warning(
__("File not found."),
"manage_uploads"
show_404(
__("Not Found"),
__("File not found.")
);
if (!delete_upload($filename))
@ -1931,7 +1952,11 @@
if (isset($_POST['search']))
redirect(
"manage_uploads/search/".
str_ireplace("%2F", "", urlencode($_POST['search'])).
str_ireplace(
array("%2F", "%5C"),
"%5F",
urlencode($_POST['search'])
).
"/"
);
@ -2032,7 +2057,8 @@
'<feed xmlns="http://www.w3.org/2005/Atom"'.
' xmlns:chyrp="http://chyrp.net/export/1.0/">'."\n".
'<title>'.
fix($config->name).' | Posts</title>'."\n".
fix($config->name).
'</title>'."\n".
'<subtitle>'.
fix($config->description).
'</subtitle>'."\n".
@ -2045,7 +2071,7 @@
'<link href="'.
fix($config->url, true).
'" rel="alternate" type="text/html" />'."\n".
'<generator uri="http://chyrp.net/" version="'.
'<generator uri="https://chyrplite.net/" version="'.
CHYRP_VERSION.
'">Chyrp</generator>'."\n";
@ -2069,6 +2095,9 @@
'<published>'.
when(DATE_ATOM, $post->created_at).
'</published>'."\n".
'<chyrp:etag>'.
fix($post->etag(), false, true).
'</chyrp:etag>'."\n".
'<author chyrp:user_id="'.$post->user_id.'">'."\n".
'<name>'.
fix(oneof($post->user->full_name, $post->user->login)).
@ -2133,7 +2162,7 @@
'<feed xmlns="http://www.w3.org/2005/Atom"'.
' xmlns:chyrp="http://chyrp.net/export/1.0/">'."\n".
'<title>'.
fix($title, false, true).
fix($config->name).
'</title>'."\n".
'<subtitle>'.
fix($config->description).
@ -2147,7 +2176,7 @@
'<link href="'.
fix($config->url, true).
'" rel="alternate" type="text/html" />'."\n".
'<generator uri="http://chyrp.net/" version="'.
'<generator uri="https://chyrplite.net/" version="'.
CHYRP_VERSION.
'">Chyrp</generator>'."\n";
@ -2170,6 +2199,9 @@
'<published>'.
when(DATE_ATOM, $page->created_at).
'</published>'."\n".
'<chyrp:etag>'.
fix($page->etag(), false, true).
'</chyrp:etag>'."\n".
'<author chyrp:user_id="'.fix($page->user_id).'">'."\n".
'<name>'.
fix(oneof($page->user->full_name, $page->user->login)).
@ -2411,6 +2443,15 @@
set_max_time();
set_max_memory();
if (!empty($_POST['media_url'])) {
$match_url = preg_quote($_POST['media_url'], "/");
$media_url = fix(
$config->chyrp_url.
str_replace(DIR, "/", $config->uploads_path)
);
$media_exp = "/{$match_url}([^\.\!,\?;\"\'<>\(\)\[\]\{\}\s\t ]+)\.([a-zA-Z0-9]+)/";
}
if (isset($imports["groups"])) {
foreach ($imports["groups"] as $name => $permissions) {
$group = new Group(
@ -2465,7 +2506,10 @@
if (isset($imports["posts"])) {
foreach ($imports["posts"]->entry as $entry) {
$chyrp = $entry->children("http://chyrp.net/export/1.0/");
$login = $entry->author->children("http://chyrp.net/export/1.0/")->login;
$login = $entry->author->children(
"http://chyrp.net/export/1.0/"
)->login;
$user = new User(
array("login" => unfix((string) $login))
@ -2477,18 +2521,22 @@
$values[$value->getName()] = unfix((string) $value);
if (!empty($_POST['media_url']))
array_walk_recursive($values, function (&$value) {
$config = Config::current();
$uploads_path = str_replace(DIR, "/", $config->uploads_path);
$old_url = preg_quote($_POST['media_url'], "/");
$new_url = fix($config->chyrp_url.$uploads_path);
$regex = "/{$old_url}([^\.\!,\?;\"\'<>\(\)\[\]\{\}\s\t ]+)\.([a-zA-Z0-9]+)/";
$value = preg_replace($regex, $new_url."$1.$2", $value);
});
array_walk_recursive(
$values,
function (&$value) use ($media_exp, $media_url) {
$value = preg_replace(
$media_exp,
$media_url."$1.$2",
$value
);
}
);
$values["imported_from"] = "chyrp";
$updated = ((string) $entry->updated != (string) $entry->published);
$updated = (
(string) $entry->updated != (string) $entry->published
);
$post = Post::add(
values:$values,
@ -2512,9 +2560,11 @@
$chyrp = $entry->children(
"http://chyrp.net/export/1.0/"
);
$attr = $entry->attributes(
"http://chyrp.net/export/1.0/"
);
$login = $entry->author->children(
"http://chyrp.net/export/1.0/"
)->login;
@ -2523,11 +2573,22 @@
array("login" => unfix((string) $login))
);
$updated = ((string) $entry->updated != (string) $entry->published);
$body = unfix((string) $entry->content);
if (!empty($_POST['media_url']))
$body = preg_replace(
$media_exp,
$media_url."$1.$2",
$body
);
$updated = (
(string) $entry->updated != (string) $entry->published
);
$page = Page::add(
title:unfix((string) $entry->title),
body:unfix((string) $entry->content),
body:$body,
user:(!$user->no_results) ? $user->id : $visitor->id,
parent_id:(int) unfix((string) $attr->parent_id),
public:(bool) unfix((string) $chyrp->public),

View File

@ -47,9 +47,9 @@
* Loads the Twig parser and sets up the l10n domain.
*/
private function __construct() {
$loader = new \Twig\Loader\FilesystemLoader(THEME_DIR);
$config = Config::current();
$theme = Theme::current();
$loader = new \Twig\Loader\FilesystemLoader(THEME_DIR);
$this->twig = new \Twig\Environment(
$loader,
@ -58,7 +58,9 @@
"strict_variables" => DEBUG,
"charset" => "UTF-8",
"cache" => CACHES_DIR.DIR."twig",
"autoescape" => false)
"autoescape" => false,
"use_yield" => true
)
);
$this->twig->addExtension(
@ -92,7 +94,7 @@
return $route->action = "index";
# Serve the index if the first arg is a query and action is unset.
if (empty($route->action) and strpos($route->arg[0], "?") === 0)
if (empty($route->action) and str_starts_with($route->arg[0], "?"))
return $route->action = "index";
# Discover feed requests.
@ -271,9 +273,9 @@
$user = new User($_GET['id']);
if ($user->no_results)
Flash::warning(
__("User not found."),
"/"
show_404(
__("Not Found"),
__("User not found.")
);
$author = (object) array(
@ -479,7 +481,11 @@
if (isset($_POST['query']))
redirect(
"search/".
str_ireplace("%2F", "", urlencode($_POST['query'])).
str_ireplace(
array("%2F", "%5C"),
"%5F",
urlencode($_POST['query'])
).
"/"
);
@ -1217,6 +1223,13 @@
* Webmention receiver endpoint.
*/
public function main_webmention(): void {
if (!Config::current()->send_pingbacks)
error(
__("Error"),
__("Webmention support is disabled for this site."),
code:503
);
webmention_receive(
fallback($_POST['source']),
fallback($_POST['target'])

View File

@ -41,10 +41,7 @@
if (DEBUG)
error_log("DOWNLOAD served ".$filename);
if (
!in_array("ob_gzhandler", ob_list_handlers()) and
!ini_get("zlib.output_compression")
)
if (!USE_COMPRESSION and !ini_get("zlib.output_compression"))
header("Content-Length: ".filesize($filepath));
$safename = addslashes($filename);

View File

@ -110,17 +110,26 @@
case 405:
header($_SERVER['SERVER_PROTOCOL']." 405 Method Not Allowed");
break;
case 406:
header($_SERVER['SERVER_PROTOCOL']." 406 Not Acceptable");
break;
case 409:
header($_SERVER['SERVER_PROTOCOL']." 409 Conflict");
break;
case 410:
header($_SERVER['SERVER_PROTOCOL']." 410 Gone");
break;
case 412:
header($_SERVER['SERVER_PROTOCOL']." 412 Precondition Failed");
break;
case 413:
header($_SERVER['SERVER_PROTOCOL']." 413 Payload Too Large");
break;
case 415:
header($_SERVER['SERVER_PROTOCOL']." 415 Unsupported Media Type");
break;
case 422:
header($_SERVER['SERVER_PROTOCOL']." 422 Unprocessable Entity");
header($_SERVER['SERVER_PROTOCOL']." 422 Unprocessable Content");
break;
case 429:
header($_SERVER['SERVER_PROTOCOL']." 429 Too Many Requests");
@ -375,7 +384,7 @@
color: #1f1f23;
text-decoration: none;
margin: 1rem 0rem;
padding: 0.5rem;
padding: 0.5rem 1rem;
background-color: #f2fbff;
border: 2px solid #b8cdd9;
border-radius: 0.25em;

View File

@ -592,7 +592,7 @@
*
* Parameters:
* $formatting - The date()-compatible formatting.
* $when - A time value to be strtotime() converted.
* $when - A time() value or string to be strtotime() converted.
*
* Returns:
* An internationalized time/date string with the supplied formatting.
@ -632,7 +632,7 @@
*
* Parameters:
* $formatting - The formatting for date().
* $when - A time value to be strtotime() converted.
* $when - A time() value or string to be strtotime() converted.
*
* Returns:
* A time/date string with the supplied formatting.
@ -1131,6 +1131,7 @@
* Returns:
* An array containing an array of "WHERE" conditions, an array
* of "WHERE" parameters, and "ORDER BY" clause for the results.
* Non-keyword text will be parameterized as array[1][":query"].
*/
function keywords($query, $plain, $table = null): array {
$trimmed = trim($query);
@ -1141,6 +1142,13 @@
$sql = SQL::current();
$trigger = Trigger::current();
# Add ESCAPE clause to LIKE operators without one.
$plain = preg_replace(
"/( LIKE :query(?! ESCAPE))($| )/",
"$1 ESCAPE '|'$2",
$plain
);
# PostgreSQL: use ILIKE operator for case-insensitivity.
if ($sql->adapter == "pgsql")
$plain = str_replace(" LIKE ", " ILIKE ", $plain);
@ -1542,8 +1550,11 @@
$parser->convertTabsToSpaces = false;
$parser->html5 = true;
$parser->keepListStartNumber = true;
$parser->keepReversedList = true;
$parser->headlineAnchors = true;
$parser->enableNewlines = false;
$parser->renderCheckboxInputs = false;
$parser->disallowedRawHTML = false;
}
if ($context instanceof Model) {
@ -1933,6 +1944,7 @@
if (!function_exists("curl_version"))
return false;
$cver = curl_version();
$curl = @curl_init($url);
if ($curl === false)
@ -1954,6 +1966,13 @@
)
);
if (
defined('CURLSSLOPT_NATIVE_CA') and
version_compare($cver["version"], "7.71", ">=")
) {
$opts[CURLOPT_SSL_OPTIONS] = CURLSSLOPT_NATIVE_CA;
}
if ($post) {
$opts[CURLOPT_POST] = true;
$opts[CURLOPT_POSTFIELDS] = $data;
@ -2237,7 +2256,7 @@
$path = substr($path, 0, $end + 1);
# Append the relative path, or replace the path if rel begins with "/".
if (strpos($rel, "/") === 0)
if (str_starts_with($rel, "/"))
$path = $rel;
else
$path.= $rel;
@ -2473,7 +2492,8 @@
if ($filename === false)
error(
__("Error"),
__("Uploaded file is of an unsupported type.")
__("Uploaded file is of an unsupported type."),
code:415
);
if (!is_uploaded_file($file['tmp_name']))
@ -3171,10 +3191,7 @@
header("Content-Type: application/octet-stream");
header("Content-Disposition: attachment; filename=\"".$safename."\"");
if (
!in_array("ob_gzhandler", ob_list_handlers()) and
!ini_get("zlib.output_compression")
)
if (!USE_COMPRESSION and !ini_get("zlib.output_compression"))
header("Content-Length: ".strlen($contents));
echo $contents;

View File

@ -29,6 +29,7 @@
new \Twig\TwigFunction("icon_img", "twig_function_icon_img"),
new \Twig\TwigFunction("copyright_notice", "twig_function_copyright_notice"),
new \Twig\TwigFunction("uploaded_search", "twig_function_uploaded_search"),
new \Twig\TwigFunction("slug_pattern", "twig_function_slug_pattern"),
new \Twig\TwigFunction("javascripts_nonce", "twig_function_javascripts_nonce"),
new \Twig\TwigFunction("stylesheets_nonce", "twig_function_stylesheets_nonce")
);
@ -67,9 +68,9 @@
# Custom filters:
new \Twig\TwigFilter("translate", "twig_filter_translate"),
new \Twig\TwigFilter("translate_plural", "twig_filter_translate_plural"),
new \Twig\TwigFilter("translate_time", "twig_filter_translate_time"),
new \Twig\TwigFilter("time", "twig_filter_time"),
new \Twig\TwigFilter("dateformat", "twig_filter_date_format"),
new \Twig\TwigFilter("strftimeformat", "twig_filter_strftime_format"),
new \Twig\TwigFilter("filesizeformat", "twig_filter_filesize_format"),
new \Twig\TwigFilter("preg_match", "twig_filter_preg_match"),
new \Twig\TwigFilter("preg_replace", "twig_filter_preg_replace"),
@ -351,6 +352,16 @@
return uploaded_search($search, $filter);
}
/**
* Function: twig_function_slug_pattern
* Returns a HTML @pattern@ attribute if strict slugs are enabled.
*/
function twig_function_slug_pattern(): string {
return SLUG_STRICT ?
' pattern="^[a-z0-9\\-]*$"' :
' pattern="^[^\\u0021-\\u002f\\u003a-\\u0040\\u005b-\\u0060\\u007b-\\u007e]*$"' ;
}
/**
* Function: twig_function_javascripts_nonce
* Returns a nonce value to enable inline JavaScript with a Content Security Policy.
@ -413,23 +424,61 @@
return _p($single, $plural, $number, $domain);
}
/**
* Function: twig_filter_time
* Returns a <time> HTML element containing an internationalized time representation.
* Function: twig_filter_translate_time
* Returns a formatted and internationalized time string.
*
* Parameters:
* $timestamp - A time value to be strtotime() converted.
* $format - The formatting for the <time> representation.
* $timestamp - A time() value or string to be strtotime() converted.
* $format - The date()-compatible formatting.
*/
function twig_filter_time(
function twig_filter_translate_time(
$timestamp,
$format = null
): string {
if (!isset($format))
$format = (ADMIN) ? "Y-m-d" : "d F Y" ;
return _w($format, $timestamp);
}
/**
* Function: twig_filter_time
* Returns a <time> HTML element containing an internationalized time representation.
*
* Parameters:
* $timestamp - A time() value or string to be strtotime() converted.
* $format - The date()-compatible formatting for the <time> representation.
* $convert - Perform a case conversion:
* "fold", "lower", "title", "upper", or null to retain case as-is.
*/
function twig_filter_time(
$timestamp,
$format = null,
$convert = null
): string {
if (!isset($format))
$format = (ADMIN) ? "Y-m-d" : "d F Y" ;
$string = _w($format, $timestamp);
$datetime = when("c", $timestamp);
switch ($convert) {
case "fold":
$string = mb_convert_case($string, MB_CASE_FOLD, "UTF-8");
break;
case "lower":
$string = mb_convert_case($string, MB_CASE_LOWER, "UTF-8");
break;
case "title":
$string = mb_convert_case($string, MB_CASE_TITLE, "UTF-8");
break;
case "upper":
$string = mb_convert_case($string, MB_CASE_UPPER, "UTF-8");
break;
}
return "<time datetime=\"".$datetime."\">".$string."</time>";
}
@ -438,8 +487,8 @@
* Returns date formatting for a string that isn't a regular time() value.
*
* Parameters:
* $timestamp - A time value to be strtotime() converted.
* $formatting - The formatting for date().
* $timestamp - A time() value or string to be strtotime() converted.
* $formatting - The date()-compatible formatting.
*/
function twig_filter_date_format(
$timestamp,
@ -451,23 +500,6 @@
return when($format, $timestamp);
}
/**
* Function: twig_filter_strftime_format
* Returns date formatting for a string that isn't a regular time() value.
*
* Parameters:
* $timestamp - A time value to be strtotime() converted.
*
* Notes:
* Uses date() instead of strftime(). Retained for backwards compatibility.
*/
function twig_filter_strftime_format(
$timestamp,
$format = null
): string {
return when("Y-m-d H:i:s", $timestamp);
}
/**
* Function: twig_filter_filesize_format
* Returns a string containing a formatted filesize value.
@ -667,10 +699,10 @@
$args_filtered = array();
foreach ($args as $arg) {
if (strpos($arg, "max_width=") === 0)
if (str_starts_with($arg, "max_width="))
continue;
if (strpos($arg, "max_height=") === 0)
if (str_starts_with($arg, "max_height="))
continue;
$args_filtered[] = $arg;

View File

@ -0,0 +1,81 @@
<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Cache;
/**
* Chains several caches together.
*
* Cached items are fetched from the first cache having them in its data store.
* They are saved and deleted in all adapters at once.
*
* @author Quentin Devos <quentin@devos.pm>
*/
final class ChainCache implements CacheInterface
{
private $caches;
/**
* @param iterable<CacheInterface> $caches The ordered list of caches used to store and fetch cached items
*/
public function __construct(iterable $caches)
{
$this->caches = $caches;
}
public function generateKey(string $name, string $className): string
{
return $className.'#'.$name;
}
public function write(string $key, string $content): void
{
$splitKey = $this->splitKey($key);
foreach ($this->caches as $cache) {
$cache->write($cache->generateKey(...$splitKey), $content);
}
}
public function load(string $key): void
{
[$name, $className] = $this->splitKey($key);
foreach ($this->caches as $cache) {
$cache->load($cache->generateKey($name, $className));
if (class_exists($className, false)) {
break;
}
}
}
public function getTimestamp(string $key): int
{
$splitKey = $this->splitKey($key);
foreach ($this->caches as $cache) {
if (0 < $timestamp = $cache->getTimestamp($cache->generateKey(...$splitKey))) {
return $timestamp;
}
}
return 0;
}
/**
* @return string[]
*/
private function splitKey(string $key): array
{
return array_reverse(explode('#', $key, 2));
}
}

View File

@ -50,11 +50,11 @@ class FilesystemCache implements CacheInterface
if (false === @mkdir($dir, 0777, true)) {
clearstatcache(true, $dir);
if (!is_dir($dir)) {
throw new \RuntimeException(sprintf('Unable to create the cache directory (%s).', $dir));
throw new \RuntimeException(\sprintf('Unable to create the cache directory (%s).', $dir));
}
}
} elseif (!is_writable($dir)) {
throw new \RuntimeException(sprintf('Unable to write in the cache directory (%s).', $dir));
throw new \RuntimeException(\sprintf('Unable to write in the cache directory (%s).', $dir));
}
$tmpFile = tempnam($dir, basename($key));
@ -73,7 +73,7 @@ class FilesystemCache implements CacheInterface
return;
}
throw new \RuntimeException(sprintf('Failed to write cache file "%s".', $key));
throw new \RuntimeException(\sprintf('Failed to write cache file "%s".', $key));
}
public function getTimestamp(string $key): int

View File

@ -0,0 +1,25 @@
<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Cache;
/**
* Implements a cache on the filesystem that can only be read, not written to.
*
* @author Quentin Devos <quentin@devos.pm>
*/
class ReadOnlyFilesystemCache extends FilesystemCache
{
public function write(string $key, string $content): void
{
// Do nothing with the content, it's a read-only filesystem.
}
}

View File

@ -144,7 +144,7 @@ class Compiler
*/
public function string(string $value)
{
$this->source .= sprintf('"%s"', addcslashes($value, "\0\t\"\$\\"));
$this->source .= \sprintf('"%s"', addcslashes($value, "\0\t\"\$\\"));
return $this;
}
@ -196,7 +196,7 @@ class Compiler
public function addDebugInfo(Node $node)
{
if ($node->getTemplateLine() != $this->lastLine) {
$this->write(sprintf("// line %d\n", $node->getTemplateLine()));
$this->write(\sprintf("// line %d\n", $node->getTemplateLine()));
$this->sourceLine += substr_count($this->source, "\n", $this->sourceOffset);
$this->sourceOffset = \strlen($this->source);
@ -244,7 +244,7 @@ class Compiler
public function getVarName(): string
{
return sprintf('__internal_compile_%d', $this->varNameSalt++);
return \sprintf('__internal_compile_%d', $this->varNameSalt++);
}
private function checkForEcho(string $string): void

View File

@ -43,11 +43,11 @@ use Twig\TokenParser\TokenParserInterface;
*/
class Environment
{
public const VERSION = '3.10.2';
public const VERSION_ID = 301002;
public const MAJOR_VERSION = 3;
public const MINOR_VERSION = 10;
public const RELEASE_VERSION = 2;
public const VERSION = '3.11.0';
public const VERSION_ID = 301100;
public const MAJOR_VERSION = 4;
public const MINOR_VERSION = 11;
public const RELEASE_VERSION = 0;
public const EXTRA_VERSION = '';
private $charset;
@ -63,7 +63,6 @@ class Environment
private $resolvedGlobals;
private $loadedTemplates;
private $strictVariables;
private $templateClassPrefix = '__TwigTemplate_';
private $originalCache;
private $extensionSet;
private $runtimeLoaders = [];
@ -290,7 +289,7 @@ class Environment
{
$key = $this->getLoader()->getCacheKey($name).$this->optionsHash;
return $this->templateClassPrefix.hash(\PHP_VERSION_ID < 80100 ? 'sha256' : 'xxh128', $key).(null === $index ? '' : '___'.$index);
return '__TwigTemplate_'.hash(\PHP_VERSION_ID < 80100 ? 'sha256' : 'xxh128', $key).(null === $index ? '' : '___'.$index);
}
/**
@ -393,7 +392,7 @@ class Environment
}
if (!class_exists($cls, false)) {
throw new RuntimeError(sprintf('Failed to load Twig template "%s", index "%s": cache might be corrupted.', $name, $index), -1, $source);
throw new RuntimeError(\sprintf('Failed to load Twig template "%s", index "%s": cache might be corrupted.', $name, $index), -1, $source);
}
}
}
@ -418,9 +417,9 @@ class Environment
{
$hash = hash(\PHP_VERSION_ID < 80100 ? 'sha256' : 'xxh128', $template, false);
if (null !== $name) {
$name = sprintf('%s (string template %s)', $name, $hash);
$name = \sprintf('%s (string template %s)', $name, $hash);
} else {
$name = sprintf('__string_template__%s', $hash);
$name = \sprintf('__string_template__%s', $hash);
}
$loader = new ChainLoader([
@ -485,7 +484,7 @@ class Environment
return $this->load($name);
}
throw new LoaderError(sprintf('Unable to find one of the following templates: "%s".', implode('", "', $names)));
throw new LoaderError(\sprintf('Unable to find one of the following templates: "%s".', implode('", "', $names)));
}
public function setLexer(Lexer $lexer)
@ -554,7 +553,7 @@ class Environment
$e->setSourceContext($source);
throw $e;
} catch (\Exception $e) {
throw new SyntaxError(sprintf('An exception has been thrown during the compilation of a template ("%s").', $e->getMessage()), -1, $source, $e);
throw new SyntaxError(\sprintf('An exception has been thrown during the compilation of a template ("%s").', $e->getMessage()), -1, $source, $e);
}
}
@ -632,7 +631,7 @@ class Environment
return $this->runtimes[$class] = $runtime;
}
throw new RuntimeError(sprintf('Unable to load the "%s" runtime.', $class));
throw new RuntimeError(\sprintf('Unable to load the "%s" runtime.', $class));
}
public function addExtension(ExtensionInterface $extension)
@ -803,7 +802,7 @@ class Environment
public function addGlobal(string $name, $value)
{
if ($this->extensionSet->isInitialized() && !\array_key_exists($name, $this->getGlobals())) {
throw new \LogicException(sprintf('Unable to add global "%s" as the runtime or the extensions have already been initialized.', $name));
throw new \LogicException(\sprintf('Unable to add global "%s" as the runtime or the extensions have already been initialized.', $name));
}
if (null !== $this->resolvedGlobals) {

View File

@ -143,15 +143,15 @@ class Error extends \Exception
if ($this->name) {
if (\is_string($this->name) || (\is_object($this->name) && method_exists($this->name, '__toString'))) {
$name = sprintf('"%s"', $this->name);
$name = \sprintf('"%s"', $this->name);
} else {
$name = json_encode($this->name);
}
$this->message .= sprintf(' in %s', $name);
$this->message .= \sprintf(' in %s', $name);
}
if ($this->lineno && $this->lineno >= 0) {
$this->message .= sprintf(' at line %d', $this->lineno);
$this->message .= \sprintf(' at line %d', $this->lineno);
}
if ($dot) {

View File

@ -41,6 +41,6 @@ class SyntaxError extends Error
asort($alternatives);
$this->appendMessage(sprintf(' Did you mean "%s"?', implode('", "', array_keys($alternatives))));
$this->appendMessage(\sprintf(' Did you mean "%s"?', implode('", "', array_keys($alternatives))));
}
}

View File

@ -265,7 +265,7 @@ class ExpressionParser
if (isset($this->unaryOperators[$token->getValue()])) {
$class = $this->unaryOperators[$token->getValue()]['class'];
if (!\in_array($class, [NegUnary::class, PosUnary::class])) {
throw new SyntaxError(sprintf('Unexpected unary operator "%s".', $token->getValue()), $token->getLine(), $this->parser->getStream()->getSourceContext());
throw new SyntaxError(\sprintf('Unexpected unary operator "%s".', $token->getValue()), $token->getLine(), $this->parser->getStream()->getSourceContext());
}
$this->parser->getStream()->next();
@ -278,13 +278,13 @@ class ExpressionParser
// no break
default:
if ($token->test(/* Token::PUNCTUATION_TYPE */ 9, '[')) {
$node = $this->parseArrayExpression();
$node = $this->parseSequenceExpression();
} elseif ($token->test(/* Token::PUNCTUATION_TYPE */ 9, '{')) {
$node = $this->parseHashExpression();
$node = $this->parseMappingExpression();
} elseif ($token->test(/* Token::OPERATOR_TYPE */ 8, '=') && ('==' === $this->parser->getStream()->look(-1)->getValue() || '!=' === $this->parser->getStream()->look(-1)->getValue())) {
throw new SyntaxError(sprintf('Unexpected operator of value "%s". Did you try to use "===" or "!==" for strict comparison? Use "is same as(value)" instead.', $token->getValue()), $token->getLine(), $this->parser->getStream()->getSourceContext());
throw new SyntaxError(\sprintf('Unexpected operator of value "%s". Did you try to use "===" or "!==" for strict comparison? Use "is same as(value)" instead.', $token->getValue()), $token->getLine(), $this->parser->getStream()->getSourceContext());
} else {
throw new SyntaxError(sprintf('Unexpected token "%s" of value "%s".', Token::typeToEnglish($token->getType()), $token->getValue()), $token->getLine(), $this->parser->getStream()->getSourceContext());
throw new SyntaxError(\sprintf('Unexpected token "%s" of value "%s".', Token::typeToEnglish($token->getType()), $token->getValue()), $token->getLine(), $this->parser->getStream()->getSourceContext());
}
}
@ -319,16 +319,26 @@ class ExpressionParser
return $expr;
}
/**
* @deprecated since 3.11, use parseSequenceExpression() instead
*/
public function parseArrayExpression()
{
trigger_deprecation('twig/twig', '3.11', 'Calling "%s()" is deprecated, use "parseSequenceExpression()" instead.', __METHOD__);
return $this->parseSequenceExpression();
}
public function parseSequenceExpression()
{
$stream = $this->parser->getStream();
$stream->expect(/* Token::PUNCTUATION_TYPE */ 9, '[', 'An array element was expected');
$stream->expect(/* Token::PUNCTUATION_TYPE */ 9, '[', 'A sequence element was expected');
$node = new ArrayExpression([], $stream->getCurrent()->getLine());
$first = true;
while (!$stream->test(/* Token::PUNCTUATION_TYPE */ 9, ']')) {
if (!$first) {
$stream->expect(/* Token::PUNCTUATION_TYPE */ 9, ',', 'An array element must be followed by a comma');
$stream->expect(/* Token::PUNCTUATION_TYPE */ 9, ',', 'A sequence element must be followed by a comma');
// trailing ,?
if ($stream->test(/* Token::PUNCTUATION_TYPE */ 9, ']')) {
@ -346,21 +356,31 @@ class ExpressionParser
$node->addElement($this->parseExpression());
}
}
$stream->expect(/* Token::PUNCTUATION_TYPE */ 9, ']', 'An opened array is not properly closed');
$stream->expect(/* Token::PUNCTUATION_TYPE */ 9, ']', 'An opened sequence is not properly closed');
return $node;
}
/**
* @deprecated since 3.11, use parseMappingExpression() instead
*/
public function parseHashExpression()
{
trigger_deprecation('twig/twig', '3.11', 'Calling "%s()" is deprecated, use "parseMappingExpression()" instead.', __METHOD__);
return $this->parseMappingExpression();
}
public function parseMappingExpression()
{
$stream = $this->parser->getStream();
$stream->expect(/* Token::PUNCTUATION_TYPE */ 9, '{', 'A hash element was expected');
$stream->expect(/* Token::PUNCTUATION_TYPE */ 9, '{', 'A mapping element was expected');
$node = new ArrayExpression([], $stream->getCurrent()->getLine());
$first = true;
while (!$stream->test(/* Token::PUNCTUATION_TYPE */ 9, '}')) {
if (!$first) {
$stream->expect(/* Token::PUNCTUATION_TYPE */ 9, ',', 'A hash value must be followed by a comma');
$stream->expect(/* Token::PUNCTUATION_TYPE */ 9, ',', 'A mapping value must be followed by a comma');
// trailing ,?
if ($stream->test(/* Token::PUNCTUATION_TYPE */ 9, '}')) {
@ -377,7 +397,7 @@ class ExpressionParser
continue;
}
// a hash key can be:
// a mapping key can be:
//
// * a number -- 12
// * a string -- 'a'
@ -399,15 +419,15 @@ class ExpressionParser
} else {
$current = $stream->getCurrent();
throw new SyntaxError(sprintf('A hash key must be a quoted string, a number, a name, or an expression enclosed in parentheses (unexpected token "%s" of value "%s".', Token::typeToEnglish($current->getType()), $current->getValue()), $current->getLine(), $stream->getSourceContext());
throw new SyntaxError(\sprintf('A mapping key must be a quoted string, a number, a name, or an expression enclosed in parentheses (unexpected token "%s" of value "%s".', Token::typeToEnglish($current->getType()), $current->getValue()), $current->getLine(), $stream->getSourceContext());
}
$stream->expect(/* Token::PUNCTUATION_TYPE */ 9, ':', 'A hash key must be followed by a colon (:)');
$stream->expect(/* Token::PUNCTUATION_TYPE */ 9, ':', 'A mapping key must be followed by a colon (:)');
$value = $this->parseExpression();
$node->addElement($value, $key);
}
$stream->expect(/* Token::PUNCTUATION_TYPE */ 9, '}', 'An opened hash is not properly closed');
$stream->expect(/* Token::PUNCTUATION_TYPE */ 9, '}', 'An opened mapping is not properly closed');
return $node;
}
@ -505,7 +525,7 @@ class ExpressionParser
}
}
} else {
throw new SyntaxError(sprintf('Expected name or number, got value "%s" of type %s.', $token->getValue(), Token::typeToEnglish($token->getType())), $lineno, $stream->getSourceContext());
throw new SyntaxError(\sprintf('Expected name or number, got value "%s" of type %s.', $token->getValue(), Token::typeToEnglish($token->getType())), $lineno, $stream->getSourceContext());
}
if ($node instanceof NameExpression && null !== $this->parser->getImportedSymbol('template', $node->getAttribute('name'))) {
@ -623,7 +643,7 @@ class ExpressionParser
$name = null;
if ($namedArguments && $token = $stream->nextIf(/* Token::OPERATOR_TYPE */ 8, '=')) {
if (!$value instanceof NameExpression) {
throw new SyntaxError(sprintf('A parameter name must be a string, "%s" given.', \get_class($value)), $token->getLine(), $stream->getSourceContext());
throw new SyntaxError(\sprintf('A parameter name must be a string, "%s" given.', \get_class($value)), $token->getLine(), $stream->getSourceContext());
}
$name = $value->getAttribute('name');
@ -631,7 +651,7 @@ class ExpressionParser
$value = $this->parsePrimaryExpression();
if (!$this->checkConstantExpression($value)) {
throw new SyntaxError('A default value for an argument must be a constant (a boolean, a string, a number, or an array).', $token->getLine(), $stream->getSourceContext());
throw new SyntaxError('A default value for an argument must be a constant (a boolean, a string, a number, a sequence, or a mapping).', $token->getLine(), $stream->getSourceContext());
}
} else {
$value = $this->parseExpression(0, $allowArrow);
@ -671,7 +691,7 @@ class ExpressionParser
}
$value = $token->getValue();
if (\in_array(strtr($value, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'), ['true', 'false', 'none', 'null'])) {
throw new SyntaxError(sprintf('You cannot assign a value to "%s".', $value), $token->getLine(), $stream->getSourceContext());
throw new SyntaxError(\sprintf('You cannot assign a value to "%s".', $value), $token->getLine(), $stream->getSourceContext());
}
$targets[] = new AssignNameExpression($value, $token->getLine());
@ -742,7 +762,7 @@ class ExpressionParser
}
}
$e = new SyntaxError(sprintf('Unknown "%s" test.', $name), $line, $stream->getSourceContext());
$e = new SyntaxError(\sprintf('Unknown "%s" test.', $name), $line, $stream->getSourceContext());
$e->addSuggestions($name, array_keys($this->env->getTests()));
throw $e;
@ -752,18 +772,15 @@ class ExpressionParser
{
if ($test->isDeprecated()) {
$stream = $this->parser->getStream();
$message = sprintf('Twig Test "%s" is deprecated', $test->getName());
$message = \sprintf('Twig Test "%s" is deprecated', $test->getName());
if ($test->getDeprecatedVersion()) {
$message .= sprintf(' since version %s', $test->getDeprecatedVersion());
}
if ($test->getAlternative()) {
$message .= sprintf('. Use "%s" instead', $test->getAlternative());
$message .= \sprintf('. Use "%s" instead', $test->getAlternative());
}
$src = $stream->getSourceContext();
$message .= sprintf(' in %s at line %d.', $src->getPath() ?: $src->getName(), $stream->getCurrent()->getLine());
$message .= \sprintf(' in %s at line %d.', $src->getPath() ?: $src->getName(), $stream->getCurrent()->getLine());
@trigger_error($message, \E_USER_DEPRECATED);
trigger_deprecation($test->getDeprecatingPackage(), $test->getDeprecatedVersion(), $message);
}
return $test->getNodeClass();
@ -772,24 +789,21 @@ class ExpressionParser
private function getFunctionNodeClass(string $name, int $line): string
{
if (!$function = $this->env->getFunction($name)) {
$e = new SyntaxError(sprintf('Unknown "%s" function.', $name), $line, $this->parser->getStream()->getSourceContext());
$e = new SyntaxError(\sprintf('Unknown "%s" function.', $name), $line, $this->parser->getStream()->getSourceContext());
$e->addSuggestions($name, array_keys($this->env->getFunctions()));
throw $e;
}
if ($function->isDeprecated()) {
$message = sprintf('Twig Function "%s" is deprecated', $function->getName());
if ($function->getDeprecatedVersion()) {
$message .= sprintf(' since version %s', $function->getDeprecatedVersion());
}
$message = \sprintf('Twig Function "%s" is deprecated', $function->getName());
if ($function->getAlternative()) {
$message .= sprintf('. Use "%s" instead', $function->getAlternative());
$message .= \sprintf('. Use "%s" instead', $function->getAlternative());
}
$src = $this->parser->getStream()->getSourceContext();
$message .= sprintf(' in %s at line %d.', $src->getPath() ?: $src->getName(), $line);
$message .= \sprintf(' in %s at line %d.', $src->getPath() ?: $src->getName(), $line);
@trigger_error($message, \E_USER_DEPRECATED);
trigger_deprecation($function->getDeprecatingPackage(), $function->getDeprecatedVersion(), $message);
}
return $function->getNodeClass();
@ -798,24 +812,21 @@ class ExpressionParser
private function getFilterNodeClass(string $name, int $line): string
{
if (!$filter = $this->env->getFilter($name)) {
$e = new SyntaxError(sprintf('Unknown "%s" filter.', $name), $line, $this->parser->getStream()->getSourceContext());
$e = new SyntaxError(\sprintf('Unknown "%s" filter.', $name), $line, $this->parser->getStream()->getSourceContext());
$e->addSuggestions($name, array_keys($this->env->getFilters()));
throw $e;
}
if ($filter->isDeprecated()) {
$message = sprintf('Twig Filter "%s" is deprecated', $filter->getName());
if ($filter->getDeprecatedVersion()) {
$message .= sprintf(' since version %s', $filter->getDeprecatedVersion());
}
$message = \sprintf('Twig Filter "%s" is deprecated', $filter->getName());
if ($filter->getAlternative()) {
$message .= sprintf('. Use "%s" instead', $filter->getAlternative());
$message .= \sprintf('. Use "%s" instead', $filter->getAlternative());
}
$src = $this->parser->getStream()->getSourceContext();
$message .= sprintf(' in %s at line %d.', $src->getPath() ?: $src->getName(), $line);
$message .= \sprintf(' in %s at line %d.', $src->getPath() ?: $src->getName(), $line);
@trigger_error($message, \E_USER_DEPRECATED);
trigger_deprecation($filter->getDeprecatingPackage(), $filter->getDeprecatedVersion(), $message);
}
return $filter->getNodeClass();

View File

@ -40,6 +40,6 @@ abstract class AbstractExtension implements ExtensionInterface
public function getOperators()
{
return [];
return [[], []];
}
}

View File

@ -218,9 +218,11 @@ final class CoreExtension extends AbstractExtension
new TwigFilter('filter', [self::class, 'filter'], ['needs_environment' => true]),
new TwigFilter('map', [self::class, 'map'], ['needs_environment' => true]),
new TwigFilter('reduce', [self::class, 'reduce'], ['needs_environment' => true]),
new TwigFilter('find', [self::class, 'find'], ['needs_environment' => true]),
// string/array filters
new TwigFilter('reverse', [self::class, 'reverse'], ['needs_charset' => true]),
new TwigFilter('shuffle', [self::class, 'shuffle'], ['needs_charset' => true]),
new TwigFilter('length', [self::class, 'length'], ['needs_charset' => true]),
new TwigFilter('slice', [self::class, 'slice'], ['needs_charset' => true]),
new TwigFilter('first', [self::class, 'first'], ['needs_charset' => true]),
@ -260,6 +262,8 @@ final class CoreExtension extends AbstractExtension
new TwigTest('constant', null, ['node_class' => ConstantTest::class]),
new TwigTest('empty', [self::class, 'testEmpty']),
new TwigTest('iterable', 'is_iterable'),
new TwigTest('sequence', [self::class, 'testSequence']),
new TwigTest('mapping', [self::class, 'testMapping']),
];
}
@ -329,7 +333,7 @@ final class CoreExtension extends AbstractExtension
}
if (!\count($values)) {
throw new RuntimeError('The "cycle" function does not work on empty arrays.');
throw new RuntimeError('The "cycle" function does not work on empty sequences/mappings.');
}
return $values[$position % \count($values)];
@ -399,7 +403,7 @@ final class CoreExtension extends AbstractExtension
$values = self::toArray($values);
if (0 === \count($values)) {
throw new RuntimeError('The random function cannot pick from an empty array.');
throw new RuntimeError('The random function cannot pick from an empty sequence/mapping.');
}
return $values[array_rand($values, 1)];
@ -455,7 +459,7 @@ final class CoreExtension extends AbstractExtension
*/
public static function sprintf($format, ...$values): string
{
return sprintf($format ?? '', ...$values);
return \sprintf($format ?? '', ...$values);
}
/**
@ -536,7 +540,7 @@ final class CoreExtension extends AbstractExtension
public static function replace($str, $from): string
{
if (!is_iterable($from)) {
throw new RuntimeError(sprintf('The "replace" filter expects an array or "Traversable" as replace values, got "%s".', \is_object($from) ? \get_class($from) : \gettype($from)));
throw new RuntimeError(\sprintf('The "replace" filter expects a sequence/mapping or "Traversable" as replace values, got "%s".', \is_object($from) ? \get_class($from) : \gettype($from)));
}
return strtr($str ?? '', self::toArray($from));
@ -633,7 +637,7 @@ final class CoreExtension extends AbstractExtension
foreach ($arrays as $argNumber => $array) {
if (!is_iterable($array)) {
throw new RuntimeError(sprintf('The merge filter only works with arrays or "Traversable", got "%s" for argument %d.', \gettype($array), $argNumber + 1));
throw new RuntimeError(\sprintf('The merge filter only works with sequences/mappings or "Traversable", got "%s" for argument %d.', \gettype($array), $argNumber + 1));
}
$result = array_merge($result, self::toArray($array));
@ -895,6 +899,42 @@ final class CoreExtension extends AbstractExtension
return $string;
}
/**
* Shuffles an array, a \Traversable instance, or a string.
* The function does not preserve keys.
*
* @param array|\Traversable|string|null $item
*
* @return mixed
*
* @internal
*/
public static function shuffle(string $charset, $item)
{
if (\is_string($item)) {
if ('UTF-8' !== $charset) {
$item = self::convertEncoding($item, 'UTF-8', $charset);
}
$item = preg_split('/(?<!^)(?!$)/u', $item, -1);
shuffle($item);
$item = implode('', $item);
if ('UTF-8' !== $charset) {
$item = self::convertEncoding($item, $charset, 'UTF-8');
}
return $item;
}
if (is_iterable($item)) {
$item = self::toArray($item, false);
shuffle($item);
}
return $item;
}
/**
* Sorts an array.
*
@ -907,7 +947,7 @@ final class CoreExtension extends AbstractExtension
if ($array instanceof \Traversable) {
$array = iterator_to_array($array);
} elseif (!\is_array($array)) {
throw new RuntimeError(sprintf('The sort filter only works with arrays or "Traversable", got "%s".', \gettype($array)));
throw new RuntimeError(\sprintf('The sort filter only works with sequences/mappings or "Traversable", got "%s".', \gettype($array)));
}
if (null !== $arrow) {
@ -1038,7 +1078,7 @@ final class CoreExtension extends AbstractExtension
public static function matches(string $regexp, ?string $str): int
{
set_error_handler(function ($t, $m) use ($regexp) {
throw new RuntimeError(sprintf('Regexp "%s" passed to "matches" is not valid', $regexp).substr($m, 12));
throw new RuntimeError(\sprintf('Regexp "%s" passed to "matches" is not valid', $regexp).substr($m, 12));
});
try {
return preg_match($regexp, $str ?? '');
@ -1222,7 +1262,7 @@ final class CoreExtension extends AbstractExtension
}
}
throw new RuntimeError(sprintf('Macro "%s" is not defined in template "%s".', substr($method, \strlen('macro_')), $template->getTemplateName()), $lineno, $source);
throw new RuntimeError(\sprintf('Macro "%s" is not defined in template "%s".', substr($method, \strlen('macro_')), $template->getTemplateName()), $lineno, $source);
}
return $template->$method(...$args);
@ -1285,6 +1325,56 @@ final class CoreExtension extends AbstractExtension
return '' === $value || false === $value || null === $value || [] === $value;
}
/**
* Checks if a variable is a sequence.
*
* {# evaluates to true if the foo variable is a sequence #}
* {% if foo is sequence %}
* {# ... #}
* {% endif %}
*
* @param mixed $value
*
* @internal
*/
public static function testSequence($value): bool
{
if ($value instanceof \ArrayObject) {
$value = $value->getArrayCopy();
}
if ($value instanceof \Traversable) {
$value = iterator_to_array($value);
}
return \is_array($value) && array_is_list($value);
}
/**
* Checks if a variable is a mapping.
*
* {# evaluates to true if the foo variable is a mapping #}
* {% if foo is mapping %}
* {# ... #}
* {% endif %}
*
* @param mixed $value
*
* @internal
*/
public static function testMapping($value): bool
{
if ($value instanceof \ArrayObject) {
$value = $value->getArrayCopy();
}
if ($value instanceof \Traversable) {
$value = iterator_to_array($value);
}
return (\is_array($value) && !array_is_list($value)) || \is_object($value);
}
/**
* Renders a template.
*
@ -1382,10 +1472,10 @@ final class CoreExtension extends AbstractExtension
if (!\defined($constant)) {
if ('::class' === strtolower(substr($constant, -7))) {
throw new RuntimeError(sprintf('You cannot use the Twig function "constant()" to access "%s". You could provide an object and call constant("class", $object) or use the class name directly as a string.', $constant));
throw new RuntimeError(\sprintf('You cannot use the Twig function "constant()" to access "%s". You could provide an object and call constant("class", $object) or use the class name directly as a string.', $constant));
}
throw new RuntimeError(sprintf('Constant "%s" is undefined.', $constant));
throw new RuntimeError(\sprintf('Constant "%s" is undefined.', $constant));
}
return \constant($constant);
@ -1424,10 +1514,10 @@ final class CoreExtension extends AbstractExtension
public static function batch($items, $size, $fill = null, $preserveKeys = true): array
{
if (!is_iterable($items)) {
throw new RuntimeError(sprintf('The "batch" filter expects an array or "Traversable", got "%s".', \is_object($items) ? \get_class($items) : \gettype($items)));
throw new RuntimeError(\sprintf('The "batch" filter expects a sequence/mapping or "Traversable", got "%s".', \is_object($items) ? \get_class($items) : \gettype($items)));
}
$size = ceil($size);
$size = (int) ceil($size);
$result = array_chunk(self::toArray($items, $preserveKeys), $size, $preserveKeys);
@ -1486,25 +1576,25 @@ final class CoreExtension extends AbstractExtension
}
if ($object instanceof \ArrayAccess) {
$message = sprintf('Key "%s" in object with ArrayAccess of class "%s" does not exist.', $arrayItem, \get_class($object));
$message = \sprintf('Key "%s" in object with ArrayAccess of class "%s" does not exist.', $arrayItem, \get_class($object));
} elseif (\is_object($object)) {
$message = sprintf('Impossible to access a key "%s" on an object of class "%s" that does not implement ArrayAccess interface.', $item, \get_class($object));
$message = \sprintf('Impossible to access a key "%s" on an object of class "%s" that does not implement ArrayAccess interface.', $item, \get_class($object));
} elseif (\is_array($object)) {
if (empty($object)) {
$message = sprintf('Key "%s" does not exist as the array is empty.', $arrayItem);
$message = \sprintf('Key "%s" does not exist as the sequence/mapping is empty.', $arrayItem);
} else {
$message = sprintf('Key "%s" for array with keys "%s" does not exist.', $arrayItem, implode(', ', array_keys($object)));
$message = \sprintf('Key "%s" for sequence/mapping with keys "%s" does not exist.', $arrayItem, implode(', ', array_keys($object)));
}
} elseif (/* Template::ARRAY_CALL */ 'array' === $type) {
if (null === $object) {
$message = sprintf('Impossible to access a key ("%s") on a null variable.', $item);
$message = \sprintf('Impossible to access a key ("%s") on a null variable.', $item);
} else {
$message = sprintf('Impossible to access a key ("%s") on a %s variable ("%s").', $item, \gettype($object), $object);
$message = \sprintf('Impossible to access a key ("%s") on a %s variable ("%s").', $item, \gettype($object), $object);
}
} elseif (null === $object) {
$message = sprintf('Impossible to access an attribute ("%s") on a null variable.', $item);
$message = \sprintf('Impossible to access an attribute ("%s") on a null variable.', $item);
} else {
$message = sprintf('Impossible to access an attribute ("%s") on a %s variable ("%s").', $item, \gettype($object), $object);
$message = \sprintf('Impossible to access an attribute ("%s") on a %s variable ("%s").', $item, \gettype($object), $object);
}
throw new RuntimeError($message, $lineno, $source);
@ -1521,11 +1611,11 @@ final class CoreExtension extends AbstractExtension
}
if (null === $object) {
$message = sprintf('Impossible to invoke a method ("%s") on a null variable.', $item);
$message = \sprintf('Impossible to invoke a method ("%s") on a null variable.', $item);
} elseif (\is_array($object)) {
$message = sprintf('Impossible to invoke a method ("%s") on an array.', $item);
$message = \sprintf('Impossible to invoke a method ("%s") on a sequence/mapping.', $item);
} else {
$message = sprintf('Impossible to invoke a method ("%s") on a %s variable ("%s").', $item, \gettype($object), $object);
$message = \sprintf('Impossible to invoke a method ("%s") on a %s variable ("%s").', $item, \gettype($object), $object);
}
throw new RuntimeError($message, $lineno, $source);
@ -1612,7 +1702,7 @@ final class CoreExtension extends AbstractExtension
return;
}
throw new RuntimeError(sprintf('Neither the property "%1$s" nor one of the methods "%1$s()", "get%1$s()"/"is%1$s()"/"has%1$s()" or "__call()" exist and have public access in class "%2$s".', $item, $class), $lineno, $source);
throw new RuntimeError(\sprintf('Neither the property "%1$s" nor one of the methods "%1$s()", "get%1$s()"/"is%1$s()"/"has%1$s()" or "__call()" exist and have public access in class "%2$s".', $item, $class), $lineno, $source);
}
if ($isDefinedTest) {
@ -1661,7 +1751,7 @@ final class CoreExtension extends AbstractExtension
if ($array instanceof \Traversable) {
$array = iterator_to_array($array);
} elseif (!\is_array($array)) {
throw new RuntimeError(sprintf('The column filter only works with arrays or "Traversable", got "%s" as first argument.', \gettype($array)));
throw new RuntimeError(\sprintf('The column filter only works with sequences/mappings or "Traversable", got "%s" as first argument.', \gettype($array)));
}
return array_column($array, $name, $index);
@ -1673,7 +1763,7 @@ final class CoreExtension extends AbstractExtension
public static function filter(Environment $env, $array, $arrow)
{
if (!is_iterable($array)) {
throw new RuntimeError(sprintf('The "filter" filter expects an array or "Traversable", got "%s".', \is_object($array) ? \get_class($array) : \gettype($array)));
throw new RuntimeError(\sprintf('The "filter" filter expects a sequence/mapping or "Traversable", got "%s".', \is_object($array) ? \get_class($array) : \gettype($array)));
}
self::checkArrowInSandbox($env, $arrow, 'filter', 'filter');
@ -1686,6 +1776,22 @@ final class CoreExtension extends AbstractExtension
return new \CallbackFilterIterator(new \IteratorIterator($array), $arrow);
}
/**
* @internal
*/
public static function find(Environment $env, $array, $arrow)
{
self::checkArrowInSandbox($env, $arrow, 'find', 'filter');
foreach ($array as $k => $v) {
if ($arrow($v, $k)) {
return $v;
}
}
return null;
}
/**
* @internal
*/
@ -1709,7 +1815,7 @@ final class CoreExtension extends AbstractExtension
self::checkArrowInSandbox($env, $arrow, 'reduce', 'filter');
if (!\is_array($array) && !$array instanceof \Traversable) {
throw new RuntimeError(sprintf('The "reduce" filter only works with arrays or "Traversable", got "%s" as first argument.', \gettype($array)));
throw new RuntimeError(\sprintf('The "reduce" filter only works with sequences/mappings or "Traversable", got "%s" as first argument.', \gettype($array)));
}
$accumulator = $initial;
@ -1758,7 +1864,7 @@ final class CoreExtension extends AbstractExtension
public static function checkArrowInSandbox(Environment $env, $arrow, $thing, $type)
{
if (!$arrow instanceof \Closure && $env->hasExtension(SandboxExtension::class) && $env->getExtension(SandboxExtension::class)->isSandboxed()) {
throw new RuntimeError(sprintf('The callable passed to the "%s" %s must be a Closure in sandbox mode.', $thing, $type));
throw new RuntimeError(\sprintf('The callable passed to the "%s" %s must be a Closure in sandbox mode.', $thing, $type));
}
}

View File

@ -14,6 +14,7 @@ namespace Twig\Extension;
use Twig\Environment;
use Twig\FileExtensionEscapingStrategy;
use Twig\Node\Expression\ConstantExpression;
use Twig\Node\Expression\Filter\RawFilter;
use Twig\Node\Node;
use Twig\NodeVisitor\EscaperNodeVisitor;
use Twig\Runtime\EscaperRuntime;
@ -52,7 +53,7 @@ final class EscaperExtension extends AbstractExtension
return [
new TwigFilter('escape', [EscaperRuntime::class, 'escape'], ['is_safe_callback' => [self::class, 'escapeFilterIsSafe']]),
new TwigFilter('e', [EscaperRuntime::class, 'escape'], ['is_safe_callback' => [self::class, 'escapeFilterIsSafe']]),
new TwigFilter('raw', [self::class, 'raw'], ['is_safe' => ['all']]),
new TwigFilter('raw', null, ['is_safe' => ['all'], 'node_class' => RawFilter::class]),
];
}
@ -117,8 +118,8 @@ final class EscaperExtension extends AbstractExtension
/**
* Defines a new escaper to be used via the escape filter.
*
* @param string $strategy The strategy name that should be used as a strategy in the escape call
* @param callable(Environment, string, string) $callable A valid PHP callable
* @param string $strategy The strategy name that should be used as a strategy in the escape call
* @param callable(Environment, string, string): string $callable A valid PHP callable
*
* @deprecated since Twig 3.10
*/
@ -127,7 +128,7 @@ final class EscaperExtension extends AbstractExtension
trigger_deprecation('twig/twig', '3.10', 'The "%s()" method is deprecated, use the "Twig\Runtime\EscaperRuntime::setEscaper()" method instead (be warned that Environment is not passed anymore to the callable).', __METHOD__);
if (!isset($this->environment)) {
throw new \LogicException(sprintf('You must call "setEnvironment()" before calling "%s()".', __METHOD__));
throw new \LogicException(\sprintf('You must call "setEnvironment()" before calling "%s()".', __METHOD__));
}
$this->escapers[$strategy] = $callable;
@ -141,7 +142,7 @@ final class EscaperExtension extends AbstractExtension
/**
* Gets all defined escapers.
*
* @return array<callable(Environment, string, string)> An array of escapers
* @return array<string, callable(Environment, string, string): string> An array of escapers
*
* @deprecated since Twig 3.10
*/
@ -160,7 +161,7 @@ final class EscaperExtension extends AbstractExtension
trigger_deprecation('twig/twig', '3.10', 'The "%s()" method is deprecated, use the "Twig\Runtime\EscaperRuntime::setSafeClasses()" method instead.', __METHOD__);
if (!isset($this->escaper)) {
throw new \LogicException(sprintf('You must call "setEnvironment()" before calling "%s()".', __METHOD__));
throw new \LogicException(\sprintf('You must call "setEnvironment()" before calling "%s()".', __METHOD__));
}
$this->escaper->setSafeClasses($safeClasses);
@ -174,24 +175,12 @@ final class EscaperExtension extends AbstractExtension
trigger_deprecation('twig/twig', '3.10', 'The "%s()" method is deprecated, use the "Twig\Runtime\EscaperRuntime::addSafeClass()" method instead.', __METHOD__);
if (!isset($this->escaper)) {
throw new \LogicException(sprintf('You must call "setEnvironment()" before calling "%s()".', __METHOD__));
throw new \LogicException(\sprintf('You must call "setEnvironment()" before calling "%s()".', __METHOD__));
}
$this->escaper->addSafeClass($class, $strategies);
}
/**
* Marks a variable as being safe.
*
* @param string $string A PHP variable
*
* @internal
*/
public static function raw($string)
{
return $string;
}
/**
* @internal
*/

View File

@ -12,8 +12,7 @@
namespace Twig\Extension;
use Twig\ExpressionParser;
use Twig\Node\Expression\Binary\AbstractBinary;
use Twig\Node\Expression\Unary\AbstractUnary;
use Twig\Node\Expression\AbstractExpression;
use Twig\NodeVisitor\NodeVisitorInterface;
use Twig\TokenParser\TokenParserInterface;
use Twig\TwigFilter;
@ -68,8 +67,8 @@ interface ExtensionInterface
* @return array<array> First array of unary operators, second array of binary operators
*
* @psalm-return array{
* array<string, array{precedence: int, class: class-string<AbstractUnary>}>,
* array<string, array{precedence: int, class: class-string<AbstractBinary>, associativity: ExpressionParser::OPERATOR_*}>
* array<string, array{precedence: int, class: class-string<AbstractExpression>}>,
* array<string, array{precedence: int, class?: class-string<AbstractExpression>, associativity: ExpressionParser::OPERATOR_*}>
* }
*/
public function getOperators();

View File

@ -35,7 +35,7 @@ final class StagingExtension extends AbstractExtension
public function addFunction(TwigFunction $function): void
{
if (isset($this->functions[$function->getName()])) {
throw new \LogicException(sprintf('Function "%s" is already registered.', $function->getName()));
throw new \LogicException(\sprintf('Function "%s" is already registered.', $function->getName()));
}
$this->functions[$function->getName()] = $function;
@ -49,7 +49,7 @@ final class StagingExtension extends AbstractExtension
public function addFilter(TwigFilter $filter): void
{
if (isset($this->filters[$filter->getName()])) {
throw new \LogicException(sprintf('Filter "%s" is already registered.', $filter->getName()));
throw new \LogicException(\sprintf('Filter "%s" is already registered.', $filter->getName()));
}
$this->filters[$filter->getName()] = $filter;
@ -73,7 +73,7 @@ final class StagingExtension extends AbstractExtension
public function addTokenParser(TokenParserInterface $parser): void
{
if (isset($this->tokenParsers[$parser->getTag()])) {
throw new \LogicException(sprintf('Tag "%s" is already registered.', $parser->getTag()));
throw new \LogicException(\sprintf('Tag "%s" is already registered.', $parser->getTag()));
}
$this->tokenParsers[$parser->getTag()] = $parser;
@ -87,7 +87,7 @@ final class StagingExtension extends AbstractExtension
public function addTest(TwigTest $test): void
{
if (isset($this->tests[$test->getName()])) {
throw new \LogicException(sprintf('Test "%s" is already registered.', $test->getName()));
throw new \LogicException(\sprintf('Test "%s" is already registered.', $test->getName()));
}
$this->tests[$test->getName()] = $test;

View File

@ -15,6 +15,7 @@ use Twig\Error\RuntimeError;
use Twig\Extension\ExtensionInterface;
use Twig\Extension\GlobalsInterface;
use Twig\Extension\StagingExtension;
use Twig\Node\Expression\AbstractExpression;
use Twig\Node\Expression\Binary\AbstractBinary;
use Twig\Node\Expression\Unary\AbstractUnary;
use Twig\NodeVisitor\NodeVisitorInterface;
@ -39,9 +40,9 @@ final class ExtensionSet
private $tests;
/** @var array<string, TwigFunction> */
private $functions;
/** @var array<string, array{precedence: int, class: class-string<AbstractUnary>}> */
/** @var array<string, array{precedence: int, class: class-string<AbstractExpression>}> */
private $unaryOperators;
/** @var array<string, array{precedence: int, class: class-string<AbstractBinary>, associativity: ExpressionParser::OPERATOR_*}> */
/** @var array<string, array{precedence: int, class?: class-string<AbstractExpression>, associativity: ExpressionParser::OPERATOR_*}> */
private $binaryOperators;
/** @var array<string, mixed> */
private $globals;
@ -70,7 +71,7 @@ final class ExtensionSet
$class = ltrim($class, '\\');
if (!isset($this->extensions[$class])) {
throw new RuntimeError(sprintf('The "%s" extension is not enabled.', $class));
throw new RuntimeError(\sprintf('The "%s" extension is not enabled.', $class));
}
return $this->extensions[$class];
@ -125,11 +126,11 @@ final class ExtensionSet
$class = \get_class($extension);
if ($this->initialized) {
throw new \LogicException(sprintf('Unable to register extension "%s" as extensions have already been initialized.', $class));
throw new \LogicException(\sprintf('Unable to register extension "%s" as extensions have already been initialized.', $class));
}
if (isset($this->extensions[$class])) {
throw new \LogicException(sprintf('Unable to register extension "%s" as it is already registered.', $class));
throw new \LogicException(\sprintf('Unable to register extension "%s" as it is already registered.', $class));
}
$this->extensions[$class] = $extension;
@ -138,7 +139,7 @@ final class ExtensionSet
public function addFunction(TwigFunction $function): void
{
if ($this->initialized) {
throw new \LogicException(sprintf('Unable to add function "%s" as extensions have already been initialized.', $function->getName()));
throw new \LogicException(\sprintf('Unable to add function "%s" as extensions have already been initialized.', $function->getName()));
}
$this->staging->addFunction($function);
@ -194,7 +195,7 @@ final class ExtensionSet
public function addFilter(TwigFilter $filter): void
{
if ($this->initialized) {
throw new \LogicException(sprintf('Unable to add filter "%s" as extensions have already been initialized.', $filter->getName()));
throw new \LogicException(\sprintf('Unable to add filter "%s" as extensions have already been initialized.', $filter->getName()));
}
$this->staging->addFilter($filter);
@ -330,7 +331,7 @@ final class ExtensionSet
$extGlobals = $extension->getGlobals();
if (!\is_array($extGlobals)) {
throw new \UnexpectedValueException(sprintf('"%s::getGlobals()" must return an array of globals.', \get_class($extension)));
throw new \UnexpectedValueException(\sprintf('"%s::getGlobals()" must return an array of globals.', \get_class($extension)));
}
$globals = array_merge($globals, $extGlobals);
@ -346,7 +347,7 @@ final class ExtensionSet
public function addTest(TwigTest $test): void
{
if ($this->initialized) {
throw new \LogicException(sprintf('Unable to add test "%s" as extensions have already been initialized.', $test->getName()));
throw new \LogicException(\sprintf('Unable to add test "%s" as extensions have already been initialized.', $test->getName()));
}
$this->staging->addTest($test);
@ -391,7 +392,7 @@ final class ExtensionSet
}
/**
* @return array<string, array{precedence: int, class: class-string<AbstractUnary>}>
* @return array<string, array{precedence: int, class: class-string<AbstractExpression>}>
*/
public function getUnaryOperators(): array
{
@ -403,7 +404,7 @@ final class ExtensionSet
}
/**
* @return array<string, array{precedence: int, class: class-string<AbstractBinary>, associativity: ExpressionParser::OPERATOR_*}>
* @return array<string, array{precedence: int, class?: class-string<AbstractExpression>, associativity: ExpressionParser::OPERATOR_*}>
*/
public function getBinaryOperators(): array
{
@ -466,11 +467,11 @@ final class ExtensionSet
// operators
if ($operators = $extension->getOperators()) {
if (!\is_array($operators)) {
throw new \InvalidArgumentException(sprintf('"%s::getOperators()" must return an array with operators, got "%s".', \get_class($extension), \is_object($operators) ? \get_class($operators) : \gettype($operators).(\is_resource($operators) ? '' : '#'.$operators)));
throw new \InvalidArgumentException(\sprintf('"%s::getOperators()" must return an array with operators, got "%s".', \get_class($extension), \is_object($operators) ? \get_class($operators) : \gettype($operators).(\is_resource($operators) ? '' : '#'.$operators)));
}
if (2 !== \count($operators)) {
throw new \InvalidArgumentException(sprintf('"%s::getOperators()" must return an array of 2 elements, got %d.', \get_class($extension), \count($operators)));
throw new \InvalidArgumentException(\sprintf('"%s::getOperators()" must return an array of 2 elements, got %d.', \get_class($extension), \count($operators)));
}
$this->unaryOperators = array_merge($this->unaryOperators, $operators[0]);

View File

@ -211,7 +211,7 @@ class Lexer
if (!empty($this->brackets)) {
[$expect, $lineno] = array_pop($this->brackets);
throw new SyntaxError(sprintf('Unclosed "%s".', $expect), $lineno, $this->source);
throw new SyntaxError(\sprintf('Unclosed "%s".', $expect), $lineno, $this->source);
}
return new TokenStream($this->tokens, $this->source);
@ -311,7 +311,7 @@ class Lexer
$this->moveCursor($match[0]);
if ($this->cursor >= $this->end) {
throw new SyntaxError(sprintf('Unclosed "%s".', self::STATE_BLOCK === $this->state ? 'block' : 'variable'), $this->currentVarBlockLine, $this->source);
throw new SyntaxError(\sprintf('Unclosed "%s".', self::STATE_BLOCK === $this->state ? 'block' : 'variable'), $this->currentVarBlockLine, $this->source);
}
}
@ -353,12 +353,12 @@ class Lexer
// closing bracket
elseif (str_contains(')]}', $this->code[$this->cursor])) {
if (empty($this->brackets)) {
throw new SyntaxError(sprintf('Unexpected "%s".', $this->code[$this->cursor]), $this->lineno, $this->source);
throw new SyntaxError(\sprintf('Unexpected "%s".', $this->code[$this->cursor]), $this->lineno, $this->source);
}
[$expect, $lineno] = array_pop($this->brackets);
if ($this->code[$this->cursor] != strtr($expect, '([{', ')]}')) {
throw new SyntaxError(sprintf('Unclosed "%s".', $expect), $lineno, $this->source);
throw new SyntaxError(\sprintf('Unclosed "%s".', $expect), $lineno, $this->source);
}
}
@ -378,7 +378,7 @@ class Lexer
}
// unlexable
else {
throw new SyntaxError(sprintf('Unexpected character "%s".', $this->code[$this->cursor]), $this->lineno, $this->source);
throw new SyntaxError(\sprintf('Unexpected character "%s".', $this->code[$this->cursor]), $this->lineno, $this->source);
}
}
@ -428,14 +428,14 @@ class Lexer
} elseif (preg_match(self::REGEX_DQ_STRING_DELIM, $this->code, $match, 0, $this->cursor)) {
[$expect, $lineno] = array_pop($this->brackets);
if ('"' != $this->code[$this->cursor]) {
throw new SyntaxError(sprintf('Unclosed "%s".', $expect), $lineno, $this->source);
throw new SyntaxError(\sprintf('Unclosed "%s".', $expect), $lineno, $this->source);
}
$this->popState();
++$this->cursor;
} else {
// unlexable
throw new SyntaxError(sprintf('Unexpected character "%s".', $this->code[$this->cursor]), $this->lineno, $this->source);
throw new SyntaxError(\sprintf('Unexpected character "%s".', $this->code[$this->cursor]), $this->lineno, $this->source);
}
}

View File

@ -46,7 +46,7 @@ final class ArrayLoader implements LoaderInterface
public function getSourceContext(string $name): Source
{
if (!isset($this->templates[$name])) {
throw new LoaderError(sprintf('Template "%s" is not defined.', $name));
throw new LoaderError(\sprintf('Template "%s" is not defined.', $name));
}
return new Source($this->templates[$name], $name);
@ -60,7 +60,7 @@ final class ArrayLoader implements LoaderInterface
public function getCacheKey(string $name): string
{
if (!isset($this->templates[$name])) {
throw new LoaderError(sprintf('Template "%s" is not defined.', $name));
throw new LoaderError(\sprintf('Template "%s" is not defined.', $name));
}
return $name.':'.$this->templates[$name];
@ -69,7 +69,7 @@ final class ArrayLoader implements LoaderInterface
public function isFresh(string $name, int $time): bool
{
if (!isset($this->templates[$name])) {
throw new LoaderError(sprintf('Template "%s" is not defined.', $name));
throw new LoaderError(\sprintf('Template "%s" is not defined.', $name));
}
return true;

View File

@ -63,7 +63,7 @@ final class ChainLoader implements LoaderInterface
}
}
throw new LoaderError(sprintf('Template "%s" is not defined%s.', $name, $exceptions ? ' ('.implode(', ', $exceptions).')' : ''));
throw new LoaderError(\sprintf('Template "%s" is not defined%s.', $name, $exceptions ? ' ('.implode(', ', $exceptions).')' : ''));
}
public function exists(string $name): bool
@ -96,7 +96,7 @@ final class ChainLoader implements LoaderInterface
}
}
throw new LoaderError(sprintf('Template "%s" is not defined%s.', $name, $exceptions ? ' ('.implode(', ', $exceptions).')' : ''));
throw new LoaderError(\sprintf('Template "%s" is not defined%s.', $name, $exceptions ? ' ('.implode(', ', $exceptions).')' : ''));
}
public function isFresh(string $name, int $time): bool
@ -114,6 +114,6 @@ final class ChainLoader implements LoaderInterface
}
}
throw new LoaderError(sprintf('Template "%s" is not defined%s.', $name, $exceptions ? ' ('.implode(', ', $exceptions).')' : ''));
throw new LoaderError(\sprintf('Template "%s" is not defined%s.', $name, $exceptions ? ' ('.implode(', ', $exceptions).')' : ''));
}
}

View File

@ -89,7 +89,7 @@ class FilesystemLoader implements LoaderInterface
$checkPath = $this->isAbsolutePath($path) ? $path : $this->rootPath.$path;
if (!is_dir($checkPath)) {
throw new LoaderError(sprintf('The "%s" directory does not exist ("%s").', $path, $checkPath));
throw new LoaderError(\sprintf('The "%s" directory does not exist ("%s").', $path, $checkPath));
}
$this->paths[$namespace][] = rtrim($path, '/\\');
@ -105,7 +105,7 @@ class FilesystemLoader implements LoaderInterface
$checkPath = $this->isAbsolutePath($path) ? $path : $this->rootPath.$path;
if (!is_dir($checkPath)) {
throw new LoaderError(sprintf('The "%s" directory does not exist ("%s").', $path, $checkPath));
throw new LoaderError(\sprintf('The "%s" directory does not exist ("%s").', $path, $checkPath));
}
$path = rtrim($path, '/\\');
@ -195,7 +195,7 @@ class FilesystemLoader implements LoaderInterface
}
if (!isset($this->paths[$namespace])) {
$this->errorCache[$name] = sprintf('There are no registered paths for namespace "%s".', $namespace);
$this->errorCache[$name] = \sprintf('There are no registered paths for namespace "%s".', $namespace);
if (!$throw) {
return null;
@ -218,7 +218,7 @@ class FilesystemLoader implements LoaderInterface
}
}
$this->errorCache[$name] = sprintf('Unable to find template "%s" (looked into: %s).', $name, implode(', ', $this->paths[$namespace]));
$this->errorCache[$name] = \sprintf('Unable to find template "%s" (looked into: %s).', $name, implode(', ', $this->paths[$namespace]));
if (!$throw) {
return null;
@ -236,7 +236,7 @@ class FilesystemLoader implements LoaderInterface
{
if (isset($name[0]) && '@' == $name[0]) {
if (false === $pos = strpos($name, '/')) {
throw new LoaderError(sprintf('Malformed namespaced template name "%s" (expecting "@namespace/template_name").', $name));
throw new LoaderError(\sprintf('Malformed namespaced template name "%s" (expecting "@namespace/template_name").', $name));
}
$namespace = substr($name, 1, $pos - 1);
@ -265,7 +265,7 @@ class FilesystemLoader implements LoaderInterface
}
if ($level < 0) {
throw new LoaderError(sprintf('Looks like you try to load a template outside configured directories (%s).', $name));
throw new LoaderError(\sprintf('Looks like you try to load a template outside configured directories (%s).', $name));
}
}
}

View File

@ -32,7 +32,7 @@ class BlockNode extends Node
{
$compiler
->addDebugInfo($this)
->write(sprintf("public function block_%s(\$context, array \$blocks = [])\n", $this->getAttribute('name')), "{\n")
->write(\sprintf("public function block_%s(\$context, array \$blocks = [])\n", $this->getAttribute('name')), "{\n")
->indent()
->write("\$macros = \$this->macros;\n")
;

View File

@ -32,7 +32,7 @@ class BlockReferenceNode extends Node implements NodeOutputInterface
{
$compiler
->addDebugInfo($this)
->write(sprintf("yield from \$this->unwrap()->yieldBlock('%s', \$context, \$blocks);\n", $this->getAttribute('name')))
->write(\sprintf("yield from \$this->unwrap()->yieldBlock('%s', \$context, \$blocks);\n", $this->getAttribute('name')))
;
}
}

View File

@ -50,6 +50,8 @@ class CaptureNode extends Node
}
if (!$this->getAttribute('raw')) {
$compiler->raw(") ? '' : new Markup(\$tmp, \$this->env->getCharset());");
} else {
$compiler->raw(';');
}
}
}

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