Compare commits

...

427 Commits

Author SHA1 Message Date
Andy Miller
cc97e2ff45 prepare for beta release
Signed-off-by: Andy Miller <rhuk@mac.com>
2025-10-14 14:30:24 -06:00
Andy Miller
d92c430b8a updated changelog
Signed-off-by: Andy Miller <rhuk@mac.com>
2025-10-14 14:30:01 -06:00
Andy Miller
184cdea75d Merge branch 'develop' into 1.8
Signed-off-by: Andy Miller <rhuk@mac.com>
2025-10-13 14:39:29 -06:00
Andy Miller
7b9567ec28 update vendor libs
Signed-off-by: Andy Miller <rhuk@mac.com>
2025-10-13 14:35:58 -06:00
Nakkouch Tarek
75d8356f1b Fixed Twig Sandbox Bypass due to nested expression (#3939) 2025-10-13 13:36:49 -06:00
pmoreno.rodriguez
c82645a42a wordCount Filter for Grav (#3957) 2025-10-13 13:35:33 -06:00
Andy Miller
9e84d5d004 more fixes for Symfony7 PHP 8+
Signed-off-by: Andy Miller <rhuk@mac.com>
2025-10-07 13:30:40 -06:00
Andy Miller
fd0d3dc463 PHP 8.4 fixes
Signed-off-by: Andy Miller <rhuk@mac.com>
2025-10-07 13:18:04 -06:00
Andy Miller
eb985e875d vendor updates and some fixes
Signed-off-by: Andy Miller <rhuk@mac.com>
2025-10-03 18:16:40 -06:00
Andy Miller
ba3493adce vendor update
Signed-off-by: Andy Miller <rhuk@mac.com>
2025-10-03 16:13:05 -06:00
Andy Miller
d785042a0d set YamlUpdater get/set to public
Signed-off-by: Andy Miller <rhuk@mac.com>
2025-09-22 15:20:53 -06:00
Andy Miller
49096b61f3 fixed sessions to use 1.7 style..
Signed-off-by: Andy Miller <rhuk@mac.com>
2025-09-22 15:12:38 -06:00
Andy Miller
70e986074c prepare beta release
Signed-off-by: Andy Miller <rhuk@mac.com>
2025-09-22 14:06:13 -06:00
Andy Miller
4af22edd36 add missing YamlLinter::exists() method
Signed-off-by: Andy Miller <rhuk@mac.com>
2025-09-22 14:05:32 -06:00
Andy Miller
5bc7d6943f added cache check interval
Signed-off-by: Andy Miller <rhuk@mac.com>
2025-09-22 11:24:50 -06:00
Andy Miller
8eb4085bcd opcache improvements for first hit
Signed-off-by: Andy Miller <rhuk@mac.com>
2025-09-22 11:02:12 -06:00
Andy Miller
b47758e3c7 tweaked changelog
Signed-off-by: Andy Miller <rhuk@mac.com>
2025-09-22 10:26:04 -06:00
Andy Miller
972ec26035 prepare for beta release
Signed-off-by: Andy Miller <rhuk@mac.com>
2025-09-22 10:20:44 -06:00
Andy Miller
9116079e97 twig3 compatiblity layer
Signed-off-by: Andy Miller <rhuk@mac.com>
2025-09-21 11:40:23 -06:00
Andy Miller
51ddb3984c rector casting clarity
Signed-off-by: Andy Miller <rhuk@mac.com>
2025-09-20 22:49:21 -06:00
Andy Miller
22de638e52 composer updates + php fixes
Signed-off-by: Andy Miller <rhuk@mac.com>
2025-09-20 22:33:56 -06:00
Andy Miller
365ab93e7e PHP 8.2+ fixes
Signed-off-by: Andy Miller <rhuk@mac.com>
2025-09-20 22:12:55 -06:00
Andy Miller
c172964025 fix for cache blowing up
Signed-off-by: Andy Miller <rhuk@mac.com>
2025-09-20 19:16:12 -06:00
Andy Miller
cb0bbcdb8b Deferred support in Twig 3
Signed-off-by: Andy Miller <rhuk@mac.com>
2025-09-20 18:38:27 -06:00
Andy Miller
35f5d2f329 Merge branch 'develop' into 1.8
Signed-off-by: Andy Miller <rhuk@mac.com>
2025-09-20 17:57:14 -06:00
Andy Miller
03849923d4 Merge tag '1.7.49.5' into develop
Release v1.7.49.5

# -----BEGIN PGP SIGNATURE-----
#
# iQIzBAABCAAdFiEEwbiolRD/eEYBHGp5nyzziuvbCuAFAmjB3LMACgkQnyzziuvb
# CuC9CQ/8CURB0sfbeDcjZbFIxNei0nGSCQkD8Wqp8IWOpSQ4iu5KiS6y6aQu7OIn
# LzvM6/wlbxJ6BhcYjt7uwMLQOH9mA4uPYMF7SQd5ElZZnoIp0zLcZ3CgDvznwOQj
# m2Kcuij3z749ORl8HjG56uhDwP5pk1C6u8OriGbb/z7uLTirLwxGE9yOoNJjlvWv
# K4ddGYcxF0OphRrIBmwbnMFwx+CoRBB1wg9pWtIba4cpgwu2OUYU9orNcVxGxPMI
# 8kXglIPrQZCKbzkjW2TNxdOVlycLKvw4J0jq+E8zgHVYFuS8yFX8JMR21wBxgCgH
# iCtigNUNwApvQafTpqWNhk+kY7nA2823NjaLNqIRRjEr3jQS7/zNorlRoaGyM7MB
# 8utneW8bH0Km2s6V4KDAKJex1Q3iE8KzFTIdM8kZ/Xnani8unrstHBAkcGkTWz0x
# NgKGEjB8moYb9+t+yRdXj7hcqHh4VkaRXm1Ac1UitaEfeEP+WwfyeBhOWBvIPDHQ
# vrdoSDWGvBHngR6Iq0cXKph7NzzQsxGVAPvKYVMlCtkFRDYNAsQOksVl5UunF5P9
# gpuLkANT7hr0WDWhCi7OMHgQW8IAMkiApp+phfrTK0GNBU2P7O+0MkeJ8LKd7mAi
# cOmZ/FDvtAzZUlwVpTiWuMq2MknwwfTU1BJblXxKGvt5Ysmx7HA=
# =gegb
# -----END PGP SIGNATURE-----
# gpg: Signature made Wed Sep 10 14:16:51 2025 MDT
# gpg:                using RSA key C1B8A89510FF7846011C6A799F2CF38AEBDB0AE0
# gpg: Good signature from "Andy Miller <rhuk@mac.com>" [ultimate]
2025-09-10 14:16:51 -06:00
Andy Miller
3664096550 Merge branch 'release/1.7.49.5' 2025-09-10 14:16:51 -06:00
Andy Miller
6664d98de8 prepare for release
Signed-off-by: Andy Miller <rhuk@mac.com>
2025-09-10 14:16:37 -06:00
Andy Miller
17323ec76c prepare for release
Signed-off-by: Andy Miller <rhuk@mac.com>
2025-09-10 14:16:04 -06:00
Andy Miller
9b9079bdd7 Backup not honoring ignored paths - fixes #3952
Signed-off-by: Andy Miller <rhuk@mac.com>
2025-09-03 18:09:17 -06:00
Andy Miller
db3df738e8 Merge tag '1.7.49.4' into develop
Release v1.7.49.4

# -----BEGIN PGP SIGNATURE-----
#
# iQIzBAABCAAdFiEEwbiolRD/eEYBHGp5nyzziuvbCuAFAmi40TMACgkQnyzziuvb
# CuDw6g//edg76Q77jQBXrdYyuR+WChQrGE3G+AOBJmTjff7YMdQQZG3dl4bUK0L3
# 52Ft0q5dQHdn1gUyAgwxJBnH19TxNrjCC/GqBXFWFOnmJSiKzAwqB2FeWtgKTMY4
# 5RS7AmzCGEGDvqTzhIB9N1x1omHAFZDlKplevUhyTzQ+12/GKd1hIJ3V5JrlVmt2
# HRrOU403mOHEqfGH5Z4kPFM2nCddeHLGqBA/3kosh0Dq548pYgE26o3A02z537F0
# KwulRDITSoR8lN3fwq2MDjhCOJzu9MLiRcWl3s3nMcVC6LhYmZUdZjRvuBF6DmSH
# SdkZ3K1aibdknwWcm1cCPD23QwLblXr9zhTaXNvHEkSY7n8elKLxEVekh7OKDTFF
# gDdtIsaMHb891TucaF/Ejo0fFdwzacaoph4Lr+CYX/Xfs9eh2V+8+Y6hrG2ZOHdd
# M4GvI+U9+LjBbN3pKAbzRF6jiXCXl5qjJSrp7DQd4SBxXCOhO/VfTanXm+8I9f58
# Srhn9kzb2/EqQA64sGjZIZwrV7/yXfqoF5dBpVrsEi1sH4zzm0g9/DCwqGxAhH+b
# zNrxVlHu845wW7K8pWDQX0YbnvYcE83mzOhEYiP5qFUew03fDSIPs30QflApmy+8
# qfXLc4kM/XTMKYnq9febhmjLg2RXBMorxUovCaNPjHGXa0UaK4Q=
# =1m/V
# -----END PGP SIGNATURE-----
# gpg: Signature made Wed Sep  3 17:37:23 2025 MDT
# gpg:                using RSA key C1B8A89510FF7846011C6A799F2CF38AEBDB0AE0
# gpg: Good signature from "Andy Miller <rhuk@mac.com>" [ultimate]
2025-09-03 17:37:23 -06:00
Andy Miller
38075f9c86 Merge branch 'release/1.7.49.4' 2025-09-03 17:37:22 -06:00
Andy Miller
b0dac5f4b4 prepare for release
Signed-off-by: Andy Miller <rhuk@mac.com>
2025-09-03 17:36:39 -06:00
Andy Miller
f7c77d1173 fix for cron force running
Signed-off-by: Andy Miller <rhuk@mac.com>
2025-09-03 17:32:48 -06:00
Andy Miller
0fd734c8df Merge tag '1.7.49.3' into develop
Release v1.7.49.3

# -----BEGIN PGP SIGNATURE-----
#
# iQIzBAABCAAdFiEEwbiolRD/eEYBHGp5nyzziuvbCuAFAmi3XKUACgkQnyzziuvb
# CuCOzw//SUVGgXNxcvWvBGFya/vKhsO9V39buLzDx7DZk5acYA2E0SHN5aRucGmq
# 3p4GaXjHQ9aSRwIB3DTNoW9fWPGd8DFURLGTti7vh4EkvQclF1fI+22sNdlXrs6P
# uRO2DvuJ+5VFDNv7LzyNhx8HdYXlANrC8jFmBS2ehAgkTUQDI3T1JmY+/H/ayyik
# pFmzty9y3jy1IG/8qAhL+g8VPWccDIHTvxM+6EQjJvCQzHybrUk1nb3zjFGqsjQD
# ocIu+jwx05qvymmqvb0S5ULlqK6BBZTz2zBH3xF4viSF4ZF9YqDLhepOrA5wsVs+
# rNRSjUvMs05tIzA7stxwapxTB8s6C8Bm8mSu3XA+0ERtde5F3E40bhptDCwhlCLI
# dTgKb0+UaEcDPl1E7VSZJ8UlrZtvO3dtg5fTt7Ieebv0b1fbRoyxWNldhxbEcgDo
# HaeZAHNu8RMuTq36ACH7vgx2BEghAfe1/qXNfHtGokNdRxQSdvCUPGl8FS5hpBYG
# JVLOkS9mABKNENpqzWyp0pYJ0MORdrv74GnhY62/ue9mG4+Eo/kFcsZtoTUsFiHI
# 7eIhZTdazWxW27BkeI94g/B6sPxcQGFs8qHhaiOZLvveKvRJHynZez5zdHnm2X1G
# 4qa5m2ebjGpxhKK8zDF1nlZEKPsaK6ZZQid4o8LL1nv6PwRcsIk=
# =xk/M
# -----END PGP SIGNATURE-----
# gpg: Signature made Tue Sep  2 15:07:49 2025 MDT
# gpg:                using RSA key C1B8A89510FF7846011C6A799F2CF38AEBDB0AE0
# gpg: Good signature from "Andy Miller <rhuk@mac.com>" [ultimate]
2025-09-02 15:07:49 -06:00
Andy Miller
b642b2c999 Merge branch 'release/1.7.49.3' 2025-09-02 15:07:48 -06:00
Andy Miller
ae147fa53b prepare for release
Signed-off-by: Andy Miller <rhuk@mac.com>
2025-09-02 15:07:38 -06:00
Andy Miller
9e6df39bff fix duplicate job issue
Signed-off-by: Andy Miller <rhuk@mac.com>
2025-09-02 15:05:38 -06:00
Andy Miller
8ac6076f88 allow you to run -r and -d in command line together
Signed-off-by: Andy Miller <rhuk@mac.com>
2025-09-02 15:05:30 -06:00
Andy Miller
cef7812472 fix an error in ZipArchive that sometimes occurs
Signed-off-by: Andy Miller <rhuk@mac.com>
2025-09-02 15:04:51 -06:00
Andy Miller
6f461395a7 update changelog
Signed-off-by: Andy Miller <rhuk@mac.com>
2025-09-02 14:41:40 -06:00
Andy Miller
162fe1acc2 namespace change for cron expression
Signed-off-by: Andy Miller <rhuk@mac.com>
2025-09-02 14:40:44 -06:00
Andy Miller
332748a1f9 removed hardcoded setup commands
Signed-off-by: Andy Miller <rhuk@mac.com>
2025-09-02 14:08:46 -06:00
Andy Miller
1a9a60115d Merge branch 'release/1.7.49.2' 2025-08-28 11:37:21 -06:00
Andy Miller
a55052b8b0 Merge tag '1.7.49.2' into develop
Release v1.7.49.2

# -----BEGIN PGP SIGNATURE-----
#
# iQIzBAABCAAdFiEEwbiolRD/eEYBHGp5nyzziuvbCuAFAmiwk9EACgkQnyzziuvb
# CuDx/A//dPvNxTkFAMbAy6j7W1UrinLF8QZV7jnSR8ig8LYN6gprwRVWKOT8Oui2
# vyfgvt9NfOHaW29EDXGdHRIeuqORTxztHOY/PrsRdP7zKQzZcNTJ4LjEcR2uGc1S
# UndhkPr4KL2hOq66JgoFif8O7Z0zl7EjLshy2d9pA7PU0LXxbLzYhNEmvkZjdLSZ
# RBmq0GmpQGTFV7l+4Rrsr0nK9KX8D/YgbBXwOo9oxIHMQzcH0i0MXFCIZdKX6V6V
# iKPbbA5A4xq7+F3zufUld2PSMIyfsdyPuoA2uJKeMGIdj4hjPUHhsOY2688EUyyf
# MRqLwoX/ZSeT5dIacXitNrS9vhLWwmxvIbNrGbZn/Jrppmwcj6r6ACkbJwkOPjaN
# kSSu6gU6SFEc7gILZXhNH1e5DCE7r1VjTDr/BoebQGZHQWafr9PG5lMMXhZRWpo+
# zPvn5cRKtI8/zDZwwR9RzJx/lUkaO7pJNg5tW5z4oo/XBmtwxYoD++JMxF3BqQvy
# Q1e+uyWhi01YpG+ofPKA5tRbD0H1++N5e5gghqhqdmazLZV3Doz2igRQUy6eVwxL
# KoSZdweJLDIFPIoSMCchU0O9wR+ZAVNNdYuQe9snezNYiBJqXcXOq3nLiEJhMVV+
# CySVvLrM85Yq0cOq6FXsVsYwHhnH8PeW8ebs7+c8EPmzxrLHAdk=
# =qw1P
# -----END PGP SIGNATURE-----
# gpg: Signature made Thu Aug 28 11:37:21 2025 MDT
# gpg:                using RSA key C1B8A89510FF7846011C6A799F2CF38AEBDB0AE0
# gpg: Good signature from "Andy Miller <rhuk@mac.com>" [ultimate]
2025-08-28 11:37:21 -06:00
Andy Miller
dc7354e7e1 prepare for release
Signed-off-by: Andy Miller <rhuk@mac.com>
2025-08-28 11:37:09 -06:00
pmoreno.rodriguez
afc1513aad Fix translation key for image adapter label and help (#3944) 2025-08-25 18:56:12 +01:00
Andy Miller
466b2a16e8 Merge branch 'release/1.7.49.1' 2025-08-25 14:16:45 +01:00
Andy Miller
a21640ace6 Merge tag '1.7.49.1' into develop
Release v1.7.49.1

# -----BEGIN PGP SIGNATURE-----
#
# iQIzBAABCAAdFiEEwbiolRD/eEYBHGp5nyzziuvbCuAFAmisYj0ACgkQnyzziuvb
# CuA6NxAAmqhEkRNcLhnyVDyZrwcinrANkYvD/Z9MKoy9NQfUaQaQmb5v7rl2Qj+T
# etmPUj9qNQI1KpDrwB2lYVAvvrQoVt73Y72GsnX/6OwNtsVNWCT2NhWN8MkRwu5d
# 6h+k7jhiotVAGMGDiI+Srk7v1LbXj+Y29pOalUDA+fZFRVHdXmQGFrYafV7LmMvH
# 7kMRS3Sj8oPII9BTBAWCiBEQ/DVil9Q+RuKwL35u76RRbh3yYJRO6fZym+IWD4YW
# ARXaWDsfG7ayoW12dg+Ufj4yooCxIghLFEXyPBr/2FqXn9/iAndQlEINGN5dSya/
# PvmhWer0bH2Wz3NUFqkTpBoK8QPjaPJThGhl2C6O2RscXIIrAvKa+VViWzNE7AU4
# Jdx7quFyC3xuElxBEPF99vabBpisxdzdtyu5v5VhlpTClNTQswbnRjax7qrUKHt8
# SLzp6tdM3SKE/AN+nXtexpVWjZTUaskl241/MPjRORtatniWSnemddjbfU9aBPmF
# /B8HjRFzGT+UFHt8b+AnP02Bt032JEdPvL8TfEAmfO55WiMpK6+Qutr2oogOznrN
# zn2D+1rUNs+8V3lKKJwaGe4nNe/BVZ1yoPQXWu3q8Z2cxJXRY2+4L66y5RdoNoew
# 1S2HyESWInAjVwHKIoyGoeabnnhVTHJpSLb8fiLNp017BTIISto=
# =LlNI
# -----END PGP SIGNATURE-----
# gpg: Signature made Mon Aug 25 14:16:45 2025 BST
# gpg:                using RSA key C1B8A89510FF7846011C6A799F2CF38AEBDB0AE0
# gpg: Good signature from "Andy Miller <rhuk@mac.com>" [ultimate]
2025-08-25 14:16:45 +01:00
Andy Miller
09920deabc prepare for release
Signed-off-by: Andy Miller <rhuk@mac.com>
2025-08-25 14:16:32 +01:00
Andy Miller
0bd72f4bb9 Merge tag '1.7.49' into develop
Release v1.7.49

# -----BEGIN PGP SIGNATURE-----
#
# iQIzBAABCAAdFiEEwbiolRD/eEYBHGp5nyzziuvbCuAFAmisWskACgkQnyzziuvb
# CuDTlg//TOFe5VqIBV03SDHVFW3frF/nK+2pOGUXgfLXN9sfPHrT8F89drsPDBar
# YwxTynix8NvPXumt/DeeGvEtDJOZt8UYDUiAlTc++F3duNGjCBId/H1XqRKk91jL
# jilxrXPboemQ+nqzVFTcACFi5/GjYKXvscOVPJ6Pflr/EsLjUfzIF11zXG2vCJsv
# rdI2W3J+cGS6VoaxvGF8vfC9k1g+rC9E1bKcj5wSI98bVQf5HCR8kLRxfyfz4fvX
# w0mLvI9qCqJ4CsIa7kLw5AxPI3bFLBQjhQtiuH6WJMNkUNvcUJ51MmU5S4hEZMLt
# BSQAD4xfG5Hb98YZaQyISBVMw3ed4rA3MLYfHVi6kYmL5FHl3lTSIL8RTe9sQSqI
# cojdIlCNJTAOL65TQik78BqmjjfMzi28B8DBCfKF5ZL5SrpHDYNqcKojzSscbytJ
# S7h9mucquI5MaMDKdMi79vZHPrmbk21ML6DbuefVxpGHDQbLGflVIpyDRzMOgvzs
# MPtYVo8gG7ljlD0EcVkUO4lZgSrImw2Ko6U8RccF8rzSG2ZmrlQEik10t/e6SorO
# g20CbctHKYgWq38rkgZmmJ+mUrtpHaYI2N/HrCTPqaaqDV0toG8lvM2/TyKq7TKh
# Aq9Kwhqz9mqDnMqMqb0l0SjA2DFdIKc9Y3Uzqi/VXRgxOmjDoq8=
# =3bpd
# -----END PGP SIGNATURE-----
# gpg: Signature made Mon Aug 25 13:44:57 2025 BST
# gpg:                using RSA key C1B8A89510FF7846011C6A799F2CF38AEBDB0AE0
# gpg: Good signature from "Andy Miller <rhuk@mac.com>" [ultimate]
2025-08-25 13:44:58 +01:00
Andy Miller
ec55a80183 Merge branch 'release/1.7.49' 2025-08-25 13:44:57 +01:00
Andy Miller
d07ac5b6ea prepare for release
Signed-off-by: Andy Miller <rhuk@mac.com>
2025-08-25 13:44:47 +01:00
Andy Miller
fa29f6672a updated changelog + vendor libs again
Signed-off-by: Andy Miller <rhuk@mac.com>
2025-08-25 13:37:44 +01:00
Andy Miller
006d8c85a0 Merge branch 'feature/modern-scheduler' into develop 2025-08-25 13:27:37 +01:00
Andy Miller
c608ed10cf implement a better purge strategy
Signed-off-by: Andy Miller <rhuk@mac.com>
2025-08-25 13:27:23 +01:00
Andy Miller
9d71de8e54 more scheduler improvements
Signed-off-by: Andy Miller <rhuk@mac.com>
2025-08-25 12:53:47 +01:00
Andy Miller
89764a51fb more scheduler fixes
Signed-off-by: Andy Miller <rhuk@mac.com>
2025-08-25 12:36:06 +01:00
Andy Miller
b851d9bf9d added scheduler logging
Signed-off-by: Andy Miller <rhuk@mac.com>
2025-08-24 23:58:28 +01:00
Andy Miller
a0679fc050 scheduler improvements
Signed-off-by: Andy Miller <rhuk@mac.com>
2025-08-24 22:23:18 +01:00
Andy Miller
e497a93da6 simplify extended jobs logic
Signed-off-by: Andy Miller <rhuk@mac.com>
2025-08-24 22:14:14 +01:00
Andy Miller
56cc894c1d initial improved schedular functionality
Signed-off-by: Andy Miller <rhuk@mac.com>
2025-08-24 20:27:28 +01:00
Andy Miller
d07f3770bc chagne order
Signed-off-by: Andy Miller <rhuk@mac.com>
2025-08-17 13:12:08 +01:00
Andy Miller
3baaf19c31 update lock file
Signed-off-by: Andy Miller <rhuk@mac.com>
2025-08-16 13:00:39 +01:00
Andy Miller
7236862a15 Add Imagick adapter support
Signed-off-by: Andy Miller <rhuk@mac.com>
2025-08-16 12:52:55 +01:00
Andy Miller
639be5ac0d pages optimizations
Signed-off-by: Andy Miller <rhuk@mac.com>
2025-06-25 16:17:24 -06:00
Andy Miller
8811b7aad0 revert PHP 8.4 fixes
Signed-off-by: Andy Miller <rhuk@mac.com>
2025-06-12 10:41:38 -06:00
Andy Miller
4a22f3dc8d better match
Signed-off-by: Andy Miller <rhuk@mac.com>
2025-06-05 11:22:28 -06:00
Andy Miller
d3e32799ab use forked copy of parsedown 1.7.x for PHP 8.4 compatibility
Signed-off-by: Andy Miller <rhuk@mac.com>
2025-04-02 05:34:07 -06:00
Andy Miller
3bebfc6dac fixed for tests
Signed-off-by: Andy Miller <rhuk@mac.com>
2025-04-01 17:03:42 -06:00
Andy Miller
9d80a4d992 upgraded to latest phpdebugbar + fixed browser caching
Signed-off-by: Andy Miller <rhuk@mac.com>
2025-04-01 16:55:29 -06:00
Andy Miller
fc7f72f89d Merge branch 'develop' into 1.8
Signed-off-by: Andy Miller <rhuk@mac.com>
2025-03-31 19:32:54 -06:00
Andy Miller
fa56984dc3 use lang string
Signed-off-by: Andy Miller <rhuk@mac.com>
2025-03-31 19:26:01 -06:00
Andy Miller
90fd68d4a5 handle empty value on require with ignore
Signed-off-by: Andy Miller <rhuk@mac.com>
2025-03-31 14:12:05 -06:00
Andy Miller
7613e38b6d Add support for validate match
Signed-off-by: Andy Miller <rhuk@mac.com>
2025-03-31 14:11:35 -06:00
Andy Miller
830a442faa update vendor libs
Signed-off-by: Andy Miller <rhuk@mac.com>
2025-03-30 15:23:22 -06:00
Andy Miller
8d7b658aa6 Some fixes that impacted file uploads
Signed-off-by: Andy Miller <rhuk@mac.com>
2025-03-30 15:22:45 -06:00
Andy Miller
83d098b891 throws error
Signed-off-by: Andy Miller <rhuk@mac.com>
2025-03-07 12:06:58 -07:00
Rotzbua
d798859acd chore(ci): update GH Actions php test (#3867)
- php versions should be strings
- caching updated to current recommendation
- fixed env var name
2025-02-05 11:16:51 -07:00
Andy Miller
53391466b0 prepare for beta release
Signed-off-by: Andy Miller <rhuk@mac.com>
2025-01-27 14:08:11 -07:00
Andy Miller
2fadc14c01 Swtiched to forked getgrav/Twig 2.x with PHP 8.4 support
Signed-off-by: Andy Miller <rhuk@mac.com>
2025-01-27 14:03:31 -07:00
Andy Miller
08d74df6e3 Fix parse error: #3894
Signed-off-by: Andy Miller <rhuk@mac.com>
2025-01-24 15:23:06 -07:00
Andy Miller
de2af9e470 Fix empty string causing parse error: fixes #3894
Signed-off-by: Andy Miller <rhuk@mac.com>
2025-01-24 15:22:35 -07:00
Andy Miller
edfb1a0868 Merge branch 'develop' into 1.8 2025-01-21 14:41:54 +00:00
Andy Miller
9893a605a6 composer update
Signed-off-by: Andy Miller <rhuk@mac.com>
2025-01-20 11:41:51 +00:00
Olivier Dolbeau
2620e836d4 Update code blocks in README (#3886) 2025-01-18 12:39:11 +00:00
Andy Miller
83d291c24b 8.2 stuff
Signed-off-by: Andy Miller <rhuk@mac.com>
2025-01-14 15:55:10 +00:00
Andy Miller
7e723eb7f5 actions/cache@v4 cache for tests
Signed-off-by: Andy Miller <rhuk@mac.com>
2025-01-13 12:30:17 +00:00
Rotzbua
1d1d8da431 fix: twig filter exif_read_data throws critical error (#3878) 2025-01-07 13:53:09 +00:00
Andy Miller
ca1b05ba57 Merge branch 'develop' into 1.8
Signed-off-by: Andy Miller <rhuk@mac.com>

# Conflicts:
#	system/src/Grav/Framework/Collection/AbstractLazyCollection.php
2025-01-06 14:17:08 +00:00
Andy Miller
4097d85daa updated copyright date to current year
Signed-off-by: Andy Miller <rhuk@mac.com>
2025-01-06 14:14:42 +00:00
Andy Miller
350e4c04cd test action on 1.8
Signed-off-by: Andy Miller <rhuk@mac.com>
2024-12-10 14:35:05 -07:00
Andy Miller
d8123a3662 switch to cache@v4 + limit PHP versions
Signed-off-by: Andy Miller <rhuk@mac.com>
2024-12-10 14:33:29 -07:00
Andy Miller
1e430f635e some more composer updates
Signed-off-by: Andy Miller <rhuk@mac.com>
2024-12-09 17:32:00 -07:00
Andy Miller
17548131d3 rector fixes for PHP 8.2+
Signed-off-by: Andy Miller <rhuk@mac.com>
2024-12-09 17:23:56 -07:00
Andy Miller
4a27bd780c vendor updates
Signed-off-by: Andy Miller <rhuk@mac.com>
2024-12-09 17:14:29 -07:00
Andy Miller
2e975dfa90 bug in AbastractLazyCollection
Signed-off-by: Andy Miller <rhuk@mac.com>
2024-12-03 15:33:32 -07:00
Andy Miller
5666d0f211 changelog updated
Signed-off-by: Andy Miller <rhuk@mac.com>
2024-12-03 15:33:10 -07:00
Andy Miller
d17ab9e06c fixed issue with Abstract Lazy Collection
Signed-off-by: Andy Miller <rhuk@mac.com>
2024-12-03 15:33:03 -07:00
Andy Miller
a15fe29f43 update version #
Signed-off-by: Andy Miller <rhuk@mac.com>
2024-11-21 12:46:31 -07:00
Andy Miller
3126fa8388 updated changelog
Signed-off-by: Andy Miller <rhuk@mac.com>
2024-11-21 12:43:32 -07:00
Andy Miller
b0c339c9eb moved to stable version of clockwork (v5.3.1)
Signed-off-by: Andy Miller <rhuk@mac.com>
2024-11-21 12:41:56 -07:00
Andy Miller
f812ee8555 more compoer updates
Signed-off-by: Andy Miller <rhuk@mac.com>
2024-11-18 16:13:08 -07:00
Bob Conan
a1e583f657 Updated SECURITY.md, fix typo(s) (#3870) 2024-11-13 14:01:07 -07:00
Andy Miller
8c6388bb74 package update 2024-10-30 19:26:04 -06:00
Andy Miller
d7aaef986e updated version 2024-10-28 11:43:14 +00:00
Andy Miller
ab9363c478 Merge branch 'develop' into 1.8 2024-10-28 11:32:43 +00:00
Andy Miller
7f2da96c0b update vendor libs 2024-10-28 11:31:20 +00:00
Andy Miller
5cf7ef864b Merge tag '1.7.48' into develop
Release v1.7.48

# -----BEGIN PGP SIGNATURE-----
#
# iQIzBAABCAAdFiEEwbiolRD/eEYBHGp5nyzziuvbCuAFAmcfdcoACgkQnyzziuvb
# CuBypA/+KweJfAVBOokFPS1iFKoQ1mrBQ0jpy4zlYLP2dFdI9OBjIXOyv15dPEkJ
# +9kxQpgsjTV4sc3WmdTUw7OVLdEqhuVZA/xhlZV3x9g3ehYSgx0guvmZTLCWqyex
# b4H4xvWHcIqF7OuNO7jv4vRZijLWTeXE9F8KQajjMIoZvG6z3GVnk20mLKzvV9KD
# mn3PWd8pnXT171TtL59WLcM47rZ93C8vqcInGjHXC2ww0+4ky63/KQbcGi+fSc6U
# /7LyWOqGXuoc8DylLVXXwpDiFGQZoyQKDxH/C9RejgnKdP/fysugBwiSsMpmQPFU
# 1KfU3BZhB74L8pRLbbAbPB0B7qhKxMlOF+S/Gr/HAjmpMwOy7JsfF10E8dIkx3FO
# R9K8awpTg08xzpLXTyeSR5CcN52/rBEgAxASF30t2QWl/t6rmMWZOfaDlPseFdtb
# d1Bz7HrtFdCYLtWGkkxF1ZhI233cR4BnxuvKml9zpjHOTnonlZTo7N2j/zG0hAom
# sFxHmtrDa0sYoWlGvAbwBa0T5SVGe0Y8DbIskud1IKepRRJROOquqtyGpLKL53HJ
# NfNPszfwiN49z9kl1afYq/dK8f497sk2DAok0AhXgVMbes99LaqsPBNZwwioSMkD
# o94p3yW7aR6rzTcqkLr/FyZAa/Iyl58h6ZFlgYTatbMFKi/haDw=
# =XhZk
# -----END PGP SIGNATURE-----
# gpg: Signature made Mon Oct 28 11:30:18 2024 GMT
# gpg:                using RSA key C1B8A89510FF7846011C6A799F2CF38AEBDB0AE0
# gpg: Good signature from "Andy Miller <rhuk@mac.com>" [ultimate]
2024-10-28 11:30:18 +00:00
Andy Miller
199cdd4364 Merge branch 'release/1.7.48' 2024-10-28 11:30:18 +00:00
Andy Miller
2896aea30a prepare for release 2024-10-28 11:30:04 +00:00
Andy Miller
3952491ce9 updated changelog 2024-10-27 12:24:46 +00:00
Andy Miller
6b07088189 cli Alias support in 1.7 2024-10-27 12:24:39 +00:00
Andy Miller
b16db4b9c0 typo 2024-10-27 12:21:00 +00:00
Andy Miller
42c0682dd8 Merge branch '1.8' of github.com:getgrav/grav into 1.8 2024-10-26 15:25:11 +01:00
Andy Miller
1969ec1876 monolog2 support 2024-10-26 15:25:00 +01:00
Jeremy Gonyea
c30661736c Fix for #3164. Adds aliases as possible commands during lookup (#3863) 2024-10-26 15:18:43 +01:00
Andy Miller
3d2dfa2faf Updated changelog 2024-10-25 20:18:33 +01:00
Andy Miller
f06bbfc563 Missing RocketTheme\Toolbox\Event\EventSubscriberInterface 2024-10-25 20:17:41 +01:00
Andy Miller
37e5526a4f updated changelog 2024-10-25 18:21:23 +01:00
Andy Miller
85c4b8279e fixes for PHP 8.4 - Implicitly nullable parameter declarations deprecated 2024-10-25 18:20:41 +01:00
Andy Miller
46736ce256 upgrade to doctrine/collectons 2.2 2024-10-25 17:53:51 +01:00
Andy Miller
800b2e1ecb updated changelog 2024-10-25 17:39:34 +01:00
Andy Miller
4f065b95a7 updated composer to latest version 2024-10-25 17:33:47 +01:00
Andy Miller
b59a3adc80 avif support via getgrav/image updates 2024-10-25 15:29:16 +01:00
Andy Miller
4ec9a3a489 Merge branch 'develop' into 1.8 2024-10-25 10:49:38 +01:00
Artyom Mezin
a0614dc3eb Resolving style conflict for other tooltips (#3861) 2024-10-25 10:44:26 +01:00
pmoreno.rodriguez
346d194125 New Trait for fetchPriority attribute in images (#3850) 2024-10-25 10:42:20 +01:00
Andy Miller
173d08243a use dev-master of Clockwork to support Monolog2/3 2024-10-24 11:58:04 +01:00
Andy Miller
62c60b8ba1 Fixed a couple of monolog deprecations 2024-10-23 17:17:51 +01:00
Andy Miller
59031a8711 use BUILD_SCRIPT_URL_18 in build 2024-10-23 17:07:10 +01:00
Andy Miller
5cd859865f use build-grav-18.sh build script 2024-10-23 16:44:49 +01:00
Andy Miller
16eafbbb04 udpate build.yaml 2024-10-23 14:37:45 +01:00
Andy Miller
3947bb03aa set version properly 2024-10-23 13:14:26 +01:00
Andy Miller
ee55d097f2 set testing true 2024-10-23 13:08:34 +01:00
Andy Miller
ae567469b7 prepare for beta release 2024-10-23 13:08:06 +01:00
Andy Miller
f6decaab15 Merge branch 'develop' into 1.8 2024-10-23 13:04:01 +01:00
Andy Miller
964e37c6f0 Merge branch 'release/1.7.47' 2024-10-23 13:02:17 +01:00
Andy Miller
c55f2bed4a Merge tag '1.7.47' into develop
Release 1.7.47

# -----BEGIN PGP SIGNATURE-----
#
# iQIzBAABCAAdFiEEwbiolRD/eEYBHGp5nyzziuvbCuAFAmcY5ckACgkQnyzziuvb
# CuDjiQ//aAyIya3K+mJOMB4AkKiT24eIq9FPSBCw2tOCsF+YcoAd5WxPe6eE2BKF
# qjrTK99hB5Adig8tkIdecIxvd3FKiDyVyjkQXDkO0UTDLQT++G3S/OBN/2tLfskc
# zJ+Esqco2QJZrKXUj1lttM4z52XFV0eiXZ1qQmnQngaa1uXCgUIKR8MuqjiMl0kF
# IT0a8Y8nHZmy2dDqw186c61cZn90qDE4foSQTJt5Rouy3qmoOzR5J0u6WKWSCbJH
# HkLwbfdDj4ZaOJ0a0hBuoxo/SzalOi3mkwaTqLIYACiMNf/NLuP/K0GJJFIY60lB
# yHa136Hi+nYlAmInGzTiAmhaWJNodB3mIJWc4gjZrDyMHfYD2BxYpjSYd1nDIJ7M
# omUPB37SQufotb58hJf5LRIDrKd2k70joRfiGlb+x0P5AuMOmhZQo0yYqqM7pNPs
# AHNf6Q01wVRu0OUws77BUBEnaNcr/APGHjw4bkucE0VaCoG3tRF9FXM6EoDdLwDy
# tIUh7peuEqhz05ViczqMtWl4YgCKpjU+bBriWUB7ge85YJIZuH8IkNy/PJnLnvfF
# U23zmClG2h+Ke4ACzzAUOjccxxCFPCqcNKrZPkiLx4R7N+abHYHRiwEcH31KVhm4
# GUJlYWLEPtAO80z4igKJibaTeEA/FTm5K79yMUAxs/4iUTVGr/w=
# =oUN6
# -----END PGP SIGNATURE-----
# gpg: Signature made Wed Oct 23 13:02:17 2024 BST
# gpg:                using RSA key C1B8A89510FF7846011C6A799F2CF38AEBDB0AE0
# gpg: Good signature from "Andy Miller <rhuk@mac.com>" [ultimate]
2024-10-23 13:02:17 +01:00
Andy Miller
ecf664c8e6 prepare for release 2024-10-23 13:02:02 +01:00
Andy Miller
10d36a10bc updated composer.lock 2024-10-23 12:16:29 +01:00
Andy Miller
574a430a10 more composer updates 2024-10-23 12:14:45 +01:00
Andy Miller
302f02ca5d revert schema 2024-10-22 18:01:41 +01:00
Andy Miller
c334479e4c Merge branch 'develop' into feature/v1.8 2024-10-22 15:47:58 +01:00
Andy Miller
e2257a9783 logic fix 2024-10-22 15:29:47 +01:00
Andy Miller
6fa63197a0 Fallback to extension on Flex-Objects json check 2024-10-22 14:10:18 +01:00
Andy Miller
f686e0ac64 Added extra checks in Uri::getContentType() 2024-10-22 14:10:03 +01:00
Andy Miller
b96483c49a Fix tests for latest Codeception version 2024-10-22 13:24:35 +01:00
Andy Miller
cccce836f6 Merge branch 'develop' into feature/v1.8 2024-10-22 12:09:26 +01:00
Andy Miller
5a741d9b10 updated changelog 2024-10-22 12:05:21 +01:00
Ricardo Verdugo
16a50767dd Fix JSON output comments check with content type (#3859)
* Update FlexCollection.php

* Update FlexObject.php (#3858)
2024-10-22 10:54:40 +01:00
Artyom Mezin
d72fca121f Annoying output comments fix for json Flex (#3856) 2024-10-22 10:32:54 +01:00
Andy Miller
bdcb77d429 Merge branch 'develop' into feature/v1.8 2024-10-21 14:20:23 +01:00
Andy Miller
e0ff168cf3 Utils::toAscii() should be static 2024-10-21 14:20:05 +01:00
Andy Miller
e15cc86716 toAscii() should be static 2024-10-21 14:19:45 +01:00
Andy Miller
dcfbd73d43 twig compatibility stuff 2024-10-14 20:53:07 +01:00
Andy Miller
1967910789 upgrade to latest symfony 6.4 + PHP 8.2 2024-10-14 19:27:43 +01:00
Andy Miller
4f1f9a7755 Merge branch 'develop' into feature/v1.8
# Conflicts:
#	CHANGELOG.md
#	composer.lock
2024-10-14 19:25:17 +01:00
Andy Miller
bbfc3b5658 updated changelog 2024-10-14 17:28:48 +01:00
Andy Miller
106dc58329 more improvements for clockwork-web support 2024-10-08 17:29:39 +01:00
Andy Miller
ca1e5ebb8a fixes for clockwork web UI 2024-10-08 15:54:59 +01:00
Andy Miller
6a585857b0 vendor updates 2024-10-08 12:50:05 +01:00
Andy Miller
f81a4ca008 Merge branch 'develop' of github.com:getgrav/grav into develop 2024-08-22 15:16:11 +01:00
Andy Miller
8c1b4448e9 fix for exif_imagetype() throwing exception when file !exists 2024-08-22 15:15:57 +01:00
pmoreno.rodriguez
f73813103d Support to Fediverse Creator meta tag (#3844) 2024-07-12 15:04:45 -06:00
Andy Miller
9c697f178d composer update 2024-06-04 14:57:02 +01:00
Raphaël Droz
20ca44fd53 Include modulars for last modification date computation (#3562)
* Include modulars for last modification date computation

Fix #3561

* use ->modified()

---------

Co-authored-by: Andy Miller <1084697+rhukster@users.noreply.github.com>
2024-06-04 14:46:58 +01:00
Rotzbua
24cd0e133f Update jquery-3.x.min.js to v3.7.1 (#3827)
Source: https://code.jquery.com/jquery-3.7.1.min.js
2024-06-04 14:38:48 +01:00
Rotzbua
9f4a86317b fix(composer): remove unused dependency (#3828) 2024-06-04 14:37:32 +01:00
Andy Miller
25ace6458b Utils::toAscii() func 2024-06-04 14:36:47 +01:00
Andy Miller
856a478bd6 fixes #3831 2024-06-04 14:35:33 +01:00
Andy Miller
faa8ee5fe1 Merge branch 'release/1.7.46' 2024-05-15 17:16:00 +01:00
Andy Miller
785f641ea5 Merge tag '1.7.46' into develop
Release v1.7.46
2024-05-15 17:16:00 +01:00
Andy Miller
013ff7ee1b prepare for release 2024-05-15 17:15:30 +01:00
Andy Miller
c97a0ffb16 reworked to use the modified Uri::parseUrl(), plus better fix for multi slashes 2024-05-08 12:45:52 +01:00
Andy Miller
51623ee0da Added custom_base test 2024-05-08 12:35:16 +01:00
Andy Miller
8c941cc6d3 update changelog 2024-05-06 12:48:52 +01:00
Andy Miller
b6bba9eb99 fixes #GHSA-f8v5-jmfh-pr69 2024-05-06 12:48:45 +01:00
Andy Miller
77adfcb831 missed a check in MediaUploadTrait::checkFileMetadata() 2024-05-06 11:31:23 +01:00
Andy Miller
ee8d783d05 better support for external urls in Utils::url() 2024-04-20 15:42:42 +01:00
thebodzio
d184e25f05 Handle the situation when GRAV_ROOT or GRAV_WEBROOT are / (#3667)
* Handle the situation when GRAV_ROOT or GARV_WEBROOT are `/`

* Update defines.php

Replaced `/` with `DS`

* Update Backups.php

Replaced `/` with `DS` in `backup` function
2024-04-16 11:52:38 -06:00
pmoreno.rodriguez
04f9385aa8 Fixed "news" to "new" in Changelog V1.7.45 (#3810) 2024-04-16 11:51:22 -06:00
Andy Miller
afb5b02e57 Fixes for multilang taxonomy 2024-03-21 15:08:44 -06:00
Andy Miller
4187a04235 Merge branch 'release/1.7.45' 2024-03-18 11:35:28 -06:00
Andy Miller
26a6cb75ad Merge tag '1.7.45' into develop
Release v1.7.45
2024-03-18 11:35:28 -06:00
Andy Miller
37d0498e1b prepare for release 2024-03-18 11:35:20 -06:00
Andy Miller
dd8d610ae0 updates + changelog 2024-03-18 11:34:37 -06:00
Andy Miller
b9529d0010 minor lang updates 2024-03-18 11:20:51 -06:00
Andy Miller
4149c81339 fix for safe_functions attack #GHSA-c9gp-64c4-2rrh 2024-03-06 14:53:53 -07:00
Andy Miller
2da91d9c8b Update SECURITY.md 2024-03-04 15:55:29 -07:00
Andy Miller
d69adcf347 Update SECURITY.md 2024-03-04 15:54:54 -07:00
Andy Miller
45e2c27c66 Update SECURITY.md 2024-03-04 15:54:11 -07:00
Andy Miller
f77df43d7a Update SECURITY.md 2024-03-04 15:49:48 -07:00
Andy Miller
de1ccfa12d Mitigate various SSTI injections 2024-03-04 15:41:30 -07:00
Andy Miller
5928411b86 fixed path traversal by santize checking fiilename 2024-03-04 13:39:50 -07:00
Andy Miller
15dc7568a5 typo 2024-03-04 13:31:40 -07:00
Andy Miller
b435d2b884 upgraded built-in composer to 2.7.1 2024-02-13 12:47:21 -07:00
Andy Miller
dbedb60634 update vendor libs 2024-02-13 12:47:00 -07:00
Andy Miller
f9f5781af8 fix for bad page dates + changelog update 2024-02-03 13:45:35 -07:00
pmoreno.rodriguez
ad8b1b79bd New Trait for decoding attribute in images (#3796)
* New Trait for decoding attribute in images

* Update comments info

* decoding default in system/config/system.yaml and system/blueprints/config/system.yaml for the images.defaults.decoding value

* Fixed predefined option in the decoding attribute
2024-02-03 13:24:12 -07:00
Andy Miller
cd2a7d8d98 changelog updated 2024-01-19 12:41:54 +00:00
Andy Miller
1dc6866eab fix other multibyte issues in inflector 2024-01-19 12:40:55 +00:00
Andy Miller
0b16401a91 fix special-chars in titleize - fixes #732 2024-01-19 12:39:24 +00:00
Andy Miller
78b8125eae Merge branch 'release/1.7.44' 2024-01-05 12:43:46 +00:00
Andy Miller
0d7cd64d0d Merge tag '1.7.44' into develop
Release v1.7.44
2024-01-05 12:43:46 +00:00
Andy Miller
3ea86e1794 remvoed outdated PR as it was DRAFT 2024-01-05 12:43:27 +00:00
Andy Miller
6df03063c8 remove test 2024-01-05 12:34:59 +00:00
Andy Miller
e5990f431d Revert "Added 'outdated' option to scheduler command (#3771)"
This reverts commit a71403f158.

# Conflicts:
#	tests/unit/Grav/Common/Scheduler/SchedulerTest.php
2024-01-05 12:31:53 +00:00
Andy Miller
b3d55ca81a remove a debug 2024-01-05 12:26:08 +00:00
Andy Miller
a0e728b540 Merge tag '1.7.44' into develop
Releaese v1.7.44
2024-01-05 11:59:45 +00:00
Andy Miller
171a5c074c Merge branch 'release/1.7.44' 2024-01-05 11:59:44 +00:00
Andy Miller
f33e89fa45 prepare for release 2024-01-05 11:59:37 +00:00
Andy Miller
e33d71e4b9 updated changelog 2024-01-05 11:58:34 +00:00
Andy Miller
ddbb1362dc updated composer again 2024-01-05 11:58:23 +00:00
maelanleborgne
a71403f158 Added 'outdated' option to scheduler command (#3771) 2024-01-05 11:46:14 +00:00
Ron Wardenier
88eb9f915a Allow empty and maolformed links in markdown (#3782)
When a user adds an invalid link in a page in markdown for example [](https://) and that page is parsed to be shown in a blog listing page that blog listing page crashes with a CRITICAL error. Instead of throwing an error the URL is now ignored. See also https://discord.com/channels/501836936584101899/506916956637495306/1185616779486167141
2024-01-05 11:44:44 +00:00
Andy Miller
70e5262512 Merge branch 'develop' of github.com:getgrav/grav into develop 2024-01-05 11:44:00 +00:00
Andy Miller
a1c116dd82 update copyright year 2024-01-05 11:43:52 +00:00
Rotzbua
cc08da0c74 add php 8.3 to test (#3778)
https://www.php.net/releases/8.3/en.php
2024-01-05 11:43:34 +00:00
Andy Miller
f7eab6b163 composer updates 2024-01-05 11:27:02 +00:00
Andy Miller
f59fa9a291 language updates 2024-01-05 11:26:45 +00:00
Andy Miller
458c64086e Revert "Use new groupNames method"
This reverts commit 470b69c775.
2024-01-05 11:20:40 +00:00
Andy Miller
345086538c updated composer and vendor libraries 2023-11-09 12:38:20 +00:00
Andy Miller
c62e173955 updated changelog 2023-11-09 12:37:02 +00:00
JS Media Creation
1b8e267d0a Add mime type for vCards (.vcf files) (#3772)
Adds support for vCards (.vcf files) in case of e.g. scanning a qr-code with the direct url to the file, so that it can be downloaded. 

Only a thumb-vcf.png should be added then too.
2023-11-08 12:06:04 +00:00
Andy Miller
eb72cb32bb updated changelog 2023-11-06 16:52:28 +00:00
Andy Miller
4e01398545 Added debugger output when routes conflict 2023-11-06 16:50:27 +00:00
Andy Miller
b0dd2358f4 Updated packages (including dom-sanitizer 1.0.7) 2023-11-06 16:50:15 +00:00
Djamil Legato
0c9333e60d Revert "fix whitespace encoding in urls" (#3764)
* Revert "fix whitespace encoding in urls (#3719)"

This reverts commit 6a9b1f2214.

* Revert change
2023-10-27 23:58:08 -07:00
Andy Miller
0b53609fa0 updated changelog 2023-10-25 14:49:52 +01:00
Andy Miller
cfa510e7f7 Merge branch 'master' into develop 2023-10-25 12:38:41 +01:00
Andy Miller
6d5f0ff9ba validaiton math rounding - fixes #3761 2023-10-25 12:38:12 +01:00
Angela Ugrinovska
71939e18be Fixed too few arguments exception thrown in the admin with using flex objects (#3658)
Going through older PRs, thanks for this.
2023-10-24 10:33:58 +01:00
Junky Junkerson
45f8fe4d0b Correcting comment in about custom site.yaml value (#3659)
Corrected blog: route: '/blog' comment from system.blog.route to site.blog.route
2023-10-24 10:32:49 +01:00
Vital
2179ef33a7 Fixed exception: "Property 'jsmodule_pipeline_include_externals' does not exist in the object!" (#3661)
Co-authored-by: Artemkin_V <avr@vital-web.ru>
2023-10-24 10:32:19 +01:00
Rotzbua
d0ae677e61 Update jquery-3.x.min.js to v3.6.4 (#3713)
Source: https://code.jquery.com/jquery-3.6.4.min.js
2023-10-24 10:30:19 +01:00
dirkjf
6a9b1f2214 fix whitespace encoding in urls (#3719)
* fix broken src url encoding

* remove redundant code

* Revert "remove redundant code"

This reverts commit 4e0020114e.

* Revert "fix broken src url encoding"

This reverts commit 3e8259da3a.

* encode whitespaces in url paths
2023-10-24 10:30:00 +01:00
yiwu
b1117e45c9 Update system.yaml (#3721)
add ISO 8601 dateformat
2023-10-24 10:28:44 +01:00
Ricardo Verdugo
382a836d80 Fix invalid input to foreach (#3724)
* Fix invalid input to foreach

This happens with discord oauth, possibly others

* Update UserGroupObject.php

---------

Co-authored-by: Andy Miller <1084697+rhukster@users.noreply.github.com>
2023-10-24 10:28:23 +01:00
Raffael Herrmann
db3e39f0cb Added detection of external triggers of the scheduler (#3726)
Added extension to the isCrontabSetup method to detect external triggers of the scheduler, so that in the admin interface the error message is hidden when the scheduler is called by an external trigger.
2023-10-24 10:25:44 +01:00
Jeremy Angele
80ce87e4a9 Update dangerous extensions (#3756)
Thanks for this!
2023-10-24 10:20:22 +01:00
Jeff
f0f29891d6 Update Inflector::ordinalize() (#3759)
put the init() call before the $ordinals test
2023-10-24 10:19:24 +01:00
Andy Miller
c66da5bedb Merge tag '1.7.43' into develop
Release 1.7.43
2023-10-02 10:41:37 -06:00
Andy Miller
1f21d259ea Merge branch 'release/1.7.43' 2023-10-02 10:41:36 -06:00
Andy Miller
21b218e464 prepare for release 2023-10-02 10:41:26 -06:00
Andy Miller
3b2fb023b8 change version number 2023-10-02 10:36:33 -06:00
Andy Miller
92babda742 updated changelog 2023-10-02 10:30:31 -06:00
pamtbaau
3cdbc5890a Fix url of @import not being rewritten (#3750)
Looks good.  thanks.
2023-10-02 10:04:29 -06:00
Andy Miller
a8042a666c updated composer - fixes #3748 2023-10-02 09:52:50 -06:00
Andy Miller
79f9640b12 move language debug to debugger - fixes #3752 2023-10-02 09:51:22 -06:00
Andy Miller
65aeb82e21 add ability to override modified date via frontmatter 2023-10-02 09:36:22 -06:00
Andy Miller
e3b0aa0c50 inlcude phar in dangerous extensions 2023-08-22 11:57:13 +01:00
Andy Miller
7e617a632e updated security.md 2023-08-22 09:24:41 +01:00
Andy Miller
fb5dd14875 Merge branch 'release/1.7.42.3' 2023-07-18 12:41:08 -06:00
Andy Miller
490bdd6ce7 Merge tag '1.7.42.3' into develop
Release v1.7.42.3
2023-07-18 12:41:08 -06:00
Andy Miller
893b1dd1db prepare for release 2023-07-18 12:40:57 -06:00
Andy Miller
1146959806 fixed a typo 2023-07-18 12:40:27 -06:00
Andy Miller
45103f81b4 Merge branch 'release/1.7.42.2' 2023-07-18 10:50:51 -06:00
Andy Miller
c426f4a9cc Merge tag '1.7.42.2' into develop
Release v1.7.42.2
2023-07-18 10:50:51 -06:00
Andy Miller
0d27f2d77e prepare for release 2023-07-18 10:50:36 -06:00
Andy Miller
b4c62101a4 SSTI attack mitigation - GHSA-9436-3gmp-4f53 2023-07-18 10:49:47 -06:00
Andy Miller
950cd0854f updated vendor libs 2023-06-15 15:32:06 -06:00
Andy Miller
4cd137830b Merge branch 'release/1.7.42.1' 2023-06-15 12:57:56 -06:00
Andy Miller
aa19bcdcbe Merge tag '1.7.42.1' into develop
Release v1.7.42.1
2023-06-15 12:57:56 -06:00
Andy Miller
cf6bf7d1ec prepare for release 2023-06-15 12:57:46 -06:00
Andy Miller
47665dbddb Fixes #3727 - filter field being a closure 2023-06-15 09:03:12 -06:00
Andy Miller
dc209453d0 Merge branch 'release/1.7.42' 2023-06-14 14:19:10 -06:00
Andy Miller
5b89091f13 Merge tag '1.7.42' into develop
Release 1.7.42
2023-06-14 14:19:10 -06:00
Andy Miller
50ee844759 prepare for release 2023-06-14 14:19:00 -06:00
Andy Miller
244758d438 also handle SSTI in reduce twig filter + function 2023-06-14 11:08:17 -06:00
Andy Miller
71bbed12f9 more SSTI fixes in Utils::isDangerousFunction() 2023-06-13 17:57:11 -06:00
Andy Miller
8c2c1cb726 better SSTI in |map and |filter 2023-06-13 17:45:40 -06:00
Andy Miller
9d01140a63 Fix for dangerous tags in |map filter 2023-06-13 17:07:39 -06:00
Andy Miller
259e775db8 Added languages debug option 2023-06-08 14:50:52 -06:00
Andy Miller
d4c617ff19 Merge branch 'release/1.7.41.2' 2023-06-01 15:19:12 -06:00
Andy Miller
c7680bb50a Merge tag '1.7.41.2' into develop
Release v1.7.41.2
2023-06-01 15:19:12 -06:00
Andy Miller
722ce55ccb prepare for release 2023-06-01 15:18:53 -06:00
Andy Miller
5b950ce73f update changelog 2023-06-01 15:17:47 -06:00
Andy Miller
8dfa2110bf fix for special chars in slugs causing redirect loops 2023-06-01 15:16:56 -06:00
Andy Miller
31aeaf6309 improved the Twig Cache Tag with customizable key (lang specific if needed) 2023-05-23 15:54:48 -06:00
Andy Miller
e4f483998d composer lock file 2023-05-12 13:50:50 -06:00
Andy Miller
7a393101ee Merge branch 'develop' into feature/v1.8
# Conflicts:
#	CHANGELOG.md
#	composer.json
#	composer.lock
#	system/blueprints/config/system.yaml
#	system/src/Grav/Common/Twig/WriteCacheFileTrait.php
2023-05-12 13:44:07 -06:00
Andy Miller
d96b023d72 Merge branch 'release/1.7.41.1' 2023-05-10 08:34:58 -06:00
Andy Miller
4de3cab522 Merge tag '1.7.41.1' into develop
Release v1.7.41.1
2023-05-10 08:34:58 -06:00
Andy Miller
b34f70f91d prepare for release 2023-05-10 08:34:45 -06:00
Andy Miller
9da8cad7fe truncator fix 2023-05-10 08:34:09 -06:00
Andy Miller
e4a30f5966 Merge branch 'release/1.7.41' 2023-05-09 12:44:53 -06:00
Andy Miller
814a050858 Merge tag '1.7.41' into develop
Release v1.7.41
2023-05-09 12:44:53 -06:00
Andy Miller
b6179bd2de prepare for release 2023-05-09 12:44:44 -06:00
Andy Miller
e5ac37e3cf FILTER_SANITIZE_STRING + Toolbox 1.6.5 2023-05-09 12:13:46 -06:00
Andy Miller
66463ddff3 more FILTER_SANITIZE_STRING fixes 2023-05-09 12:13:32 -06:00
Andy Miller
956c2993ae more filter fixes 2023-05-09 11:22:28 -06:00
Andy Miller
3cf67cb2fd deprecation fix 2023-05-09 11:18:36 -06:00
Andy Miller
36afa9d848 won’t work internally in Parsedown 2023-05-08 19:31:37 -06:00
Andy Miller
694ab76d1e added parse_url to the list of Grav Twig functions 2023-05-08 19:03:29 -06:00
Andy Miller
369c2e9ffa remove filter_input in favor of htmlspecialchars + strip_tags 2023-05-08 18:42:52 -06:00
Andy Miller
95ae35216a various cast fixes 2023-05-08 18:41:19 -06:00
Andy Miller
9c0477fa52 fix dynamic class value 2023-05-08 18:41:04 -06:00
Andy Miller
e1ab15e323 another cast fix 2023-05-08 17:44:52 -06:00
Andy Miller
ff77d58acb more casting fixes 2023-05-08 17:37:42 -06:00
Andy Miller
adfbd5730b changelog updated 2023-05-08 17:31:26 -06:00
Andy Miller
bf175983ec various deprecated fixes 2023-05-08 17:31:15 -06:00
Andy Miller
470b69c775 Use new groupNames method 2023-05-08 17:27:54 -06:00
Andy Miller
60648c43db Update to latest getgrav/image package 2023-05-08 17:27:43 -06:00
Andy Miller
75cd4f4306 Various casting fixes for deprecated messages 2023-05-08 17:27:03 -06:00
Andy Miller
2412115f41 TwigDeferredExtension updates 2023-05-08 17:26:22 -06:00
Andy Miller
598836d656 fix parsedown dynamic properties 2023-05-08 12:39:35 -06:00
Andy Miller
e1019c4420 remove FILTER_SANITIZE_STRING as deprecated 2023-05-08 12:21:09 -06:00
Djamil Legato
a8a6c0c520 Better and generic ignore pattern for security.yaml (fixes #3706) 2023-04-06 10:29:35 -07:00
Andy Miller
685d76231a Merge branch 'release/1.7.40' 2023-03-22 11:30:00 -06:00
Andy Miller
0f9b9f780f Merge tag '1.7.40' into develop
Release 1.7.40
2023-03-22 11:30:00 -06:00
Andy Miller
1e2792874d prepare for release 2023-03-22 11:29:52 -06:00
Andy Miller
0a061ce95e bugfix for timestamp logic 2023-03-22 10:18:07 -06:00
Andy Miller
d82ee029e1 updated changelog 2023-03-22 10:09:06 -06:00
Andy Miller
3b83c8204d Merge branch 'develop' of github.com:getgrav/grav into develop 2023-03-22 10:07:18 -06:00
Andy Miller
9ab7a4759a Added timestamp: true|false option for assets 2023-03-22 10:07:14 -06:00
Vilius Šumskas
c261d0d3f7 Fix force_ssl redirect in case of undefined hostname (#3702) 2023-03-17 08:53:45 -06:00
Andy Miller
940415dddb updated changelog 2023-03-07 10:47:55 -07:00
Andy Miller
60506e6f34 fixed duplicate page paths 2023-03-07 10:45:01 -07:00
Djamil Legato
bd7a74d79e Coerce ignore validation to array to cover both array/non-array values 2023-03-06 11:01:15 -08:00
Djamil Legato
5fcf690918 Fixed BlueprintSchema:flattenData to properly handle ignored fields 2023-03-06 10:40:36 -08:00
Anael Mobilia
904ec46a9f Update robots.txt reflecting actual folders (#3625)
* Update robots.txt

"grav" folder no longer exists

* Add folders now existing
2023-03-06 10:21:03 -07:00
Vilius Šumskas
259c148edb Fix whoami command usage (#3695)
Passing process as a string is deprecated since Symfony 4.2.
2023-03-06 10:19:23 -07:00
Rotzbua
0ae980062f Remove outdated setting xcache (#3615)
Already removed in commit ba2c37c216
2023-03-06 10:18:57 -07:00
Ari Cooper Davis
a888f19ad1 Fix LogViewer regex to reduce greediness (#3684) 2023-03-06 09:25:12 -07:00
Andy Miller
479b89134d Update composer.json 2023-02-23 18:46:44 -07:00
Andy Miller
d0d083d985 not just 7.3! 2023-02-23 18:01:01 -07:00
Andy Miller
396b412dda Merge tag '1.7.39.4' into develop
Release v1.7.39.4
2023-02-22 09:20:28 -07:00
Andy Miller
8be02e44c6 Merge branch 'release/1.7.39.4' 2023-02-22 09:20:27 -07:00
Andy Miller
ec115a6a64 prepare for release 2023-02-22 09:20:07 -07:00
Andy Miller
3b92c1aca4 updated changelog 2023-02-22 09:19:24 -07:00
Andy Miller
2d9df03766 Revert "move account info under account section"
This reverts commit 1fae4504a2.
2023-02-22 09:16:54 -07:00
Andy Miller
f086f84ff2 Merge branch 'release/1.7.39.3' 2023-02-21 15:12:34 -07:00
Andy Miller
a2b23ad80e Merge tag '1.7.39.3' into develop
Release 1.7.39.3
2023-02-21 15:12:34 -07:00
Andy Miller
88350d9090 prepare for release 2023-02-21 15:12:24 -07:00
Andy Miller
b2f27fbdf2 cleaner fix for template bug 2023-02-21 12:55:50 -07:00
Andy Miller
72b769aa63 fix for rendering specific templates fixes #3698 2023-02-21 09:39:14 -07:00
Andy Miller
8a7e38751a Merge branch 'release/1.7.39.2' 2023-02-20 14:31:42 -07:00
Andy Miller
3e6c719441 Merge tag '1.7.39.2' into develop
Release v1.7.39.2
2023-02-20 14:31:42 -07:00
Andy Miller
8efb000801 prepare for release 2023-02-20 14:31:30 -07:00
Andy Miller
6d6e92048e flex accounts session fix 2023-02-20 14:02:13 -07:00
Andy Miller
8c365d45a4 Merge branch 'release/1.7.39.1'
# Conflicts:
#	CHANGELOG.md
2023-02-20 11:52:11 -07:00
Andy Miller
ee6448c307 prepare for release 2023-02-20 11:51:36 -07:00
Andy Miller
f8c9e9ada4 css fix for phpdebugbar 2023-02-20 11:49:47 -07:00
Andy Miller
87ab3ae4a7 Fix for debugbar rendering 2023-02-20 10:01:30 -07:00
Andy Miller
68dc461bc0 Merge tag '1.7.39' into develop
Release v1.7.39
2023-02-19 14:52:00 -07:00
Andy Miller
4dd98610a4 Merge branch 'release/1.7.39' 2023-02-19 14:51:59 -07:00
Andy Miller
0358e55aed Merge branch 'master' into develop 2023-02-19 14:51:07 -07:00
Andy Miller
9e5ed10925 typo in types 2023-02-19 14:50:16 -07:00
Andy Miller
3b7eb198cf Merge tag '1.7.39' into develop
Release v1.7.39
2023-02-19 14:44:21 -07:00
Andy Miller
81ed7379a9 Merge branch 'release/1.7.39' 2023-02-19 14:44:21 -07:00
Andy Miller
e1950e985b prepare for release 2023-02-19 14:44:10 -07:00
Andy Miller
84c61af807 updated changelog 2023-02-19 14:43:34 -07:00
Andy Miller
93755c7329 fix UtilsTest for PHPUnit 10 2023-02-19 13:48:13 -07:00
Andy Miller
5329918e2f Merge branch 'develop' of github.com:getgrav/grav into develop 2023-02-19 13:27:58 -07:00
Andy Miller
efd7726646 update packages 2023-02-19 13:27:52 -07:00
Rotzbua
4c762c0ac3 add php 8.2 to test (#3662)
now released https://www.php.net/releases/8.2/en.php
2023-02-19 13:27:19 -07:00
Andy Miller
81a911572c more PHP 8.2 fixes 2023-02-19 13:26:17 -07:00
Andy Miller
c56bb86b61 php 8.2 fixes 2023-02-19 12:07:58 -07:00
Andy Miller
ea010f19f0 Fix for bad rendering of modules 2023-02-17 16:00:46 -07:00
Andy Miller
1fae4504a2 move account info under account section 2023-02-15 15:24:03 -07:00
Andy Miller
d99c84d9f8 empty date to avoid confusion 2023-02-10 15:26:15 -07:00
Andy Miller
c732bfaeef Merge branch 'develop' of github.com:getgrav/grav into develop 2023-01-11 16:16:57 -07:00
Andy Miller
4f0fee684a fix for email validation 2023-01-11 16:16:52 -07:00
Daniel Mason
884faa91bb Update php-fpm socket file to use generic socket file instead of pinning to version (#3669) 2023-01-02 16:19:05 -07:00
Andy Miller
8c261a05cc Merge tag '1.7.38' into develop
Release v1.7.38
2023-01-02 11:24:06 -07:00
Andy Miller
95aa57ca50 Merge branch 'release/1.7.38' 2023-01-02 11:24:05 -07:00
Andy Miller
0bc0e58707 prepare for release 2023-01-02 11:23:56 -07:00
Andy Miller
a86e0d4b96 Update copyright date 2023-01-02 11:09:32 -07:00
Andy Miller
44c819b021 Added new onBeforeSessionStart() Event 2023-01-02 10:46:32 -07:00
Andy Miller
3f13d81c6f Get around a bug where messages were not always being set on session during redirect 2023-01-01 13:10:58 -07:00
Andy Miller
720a965c7e update changelog 2022-12-02 12:23:04 -07:00
Alex
f0e263a404 GitHub Workflows security hardening (#3624)
* build: harden build.yaml permissions

Signed-off-by: Alex <aleksandrosansan@gmail.com>

* build: harden trigger-skeletons.yml permissions

Signed-off-by: Alex <aleksandrosansan@gmail.com>

* build: harden tests.yaml permissions

Signed-off-by: Alex <aleksandrosansan@gmail.com>

Signed-off-by: Alex <aleksandrosansan@gmail.com>
2022-11-30 17:13:49 -08:00
Andy Miller
ad33a63ad2 Revert "dont’ fail hard if pages recurse with same path"
This reverts commit 9c5b8b6496.

# Conflicts:
#	system/src/Grav/Common/Page/Pages.php
2022-10-25 18:20:08 -06:00
Andy Miller
f7b7f3337d fix 2022-10-25 18:01:42 -06:00
Andy Miller
983fcc5e40 Merge branch 'develop' of github.com:getgrav/grav into develop 2022-10-25 17:47:08 -06:00
Andy Miller
9c5b8b6496 dont’ fail hard if pages recurse with same path 2022-10-25 17:47:03 -06:00
Djamil Legato
71fc4eb16b Added .env and .gravenv to gitignore, most likely you don't want them pushed 2022-10-10 14:32:25 -07:00
Andy Miller
ea2858ea2b Merge branch 'develop' of github.com:getgrav/grav into develop 2022-10-05 15:10:37 -06:00
Andy Miller
d080578e83 Upgrade composer to 2.4.2 - fixes #3627 2022-10-05 15:10:32 -06:00
Andy Miller
8427eb6d3e Upgrade composer to 2.4.2 - fixes #3637 2022-10-05 15:09:58 -06:00
Andy Miller
e3a342dabd Merge tag '1.7.37.1' into develop
Release v1.7.37.1
2022-10-05 15:06:23 -06:00
Matias Griese
10b15bedf2 Composer update 2022-08-18 13:27:58 +03:00
Matias Griese
8c14a9907e Merge branch 'develop' of github.com:getgrav/grav into feature/v1.8
 Conflicts:
	composer.lock
2022-08-18 13:27:06 +03:00
Matias Griese
f490d9a7e1 Fix phpstan error 2022-06-29 13:16:56 +03:00
Matias Griese
81ca0c2e25 Merge branch 'develop' of github.com:getgrav/grav into feature/v1.8
 Conflicts:
	CHANGELOG.md
	composer.json
	composer.lock
2022-06-29 13:14:06 +03:00
Matias Griese
fbfac9f8f4 Composer update 2022-06-29 13:12:11 +03:00
Matias Griese
d6e72708bf Composer update 2022-06-15 14:41:05 +03:00
Matias Griese
2aff274c31 Merge branch 'develop' of github.com:getgrav/grav into feature/v1.8
 Conflicts:
	composer.lock
	system/src/Grav/Common/GPM/Remote/AbstractPackageCollection.php
2022-06-15 14:39:38 +03:00
Matias Griese
74c1dfa433 Composer update 2022-05-20 16:48:41 +03:00
Matias Griese
f51a9d9d87 Merge branch 'develop' of github.com:getgrav/grav into feature/v1.8
 Conflicts:
	CHANGELOG.md
	composer.lock
2022-05-20 16:45:54 +03:00
Matias Griese
e5498f58e6 Composer update 2022-04-19 11:05:19 +03:00
Matias Griese
8f58a4494c Merge branch 'develop' of github.com:getgrav/grav into feature/v1.8
 Conflicts:
	composer.lock
2022-04-19 11:04:33 +03:00
Matias Griese
5bfd43256d Merge branch 'develop' of github.com:getgrav/grav into feature/v1.8 2022-03-31 11:31:04 +03:00
Matias Griese
69bc3f7f25 Composer update 2022-03-31 11:27:39 +03:00
Matias Griese
782ceada80 Merge branch 'develop' of github.com:getgrav/grav into feature/v1.8
 Conflicts:
	CHANGELOG.md
	composer.lock
2022-03-31 11:26:37 +03:00
Matias Griese
36392acbea Composer update 2022-03-23 13:00:19 +02:00
Matias Griese
4b564df38f Merge branch 'develop' of github.com:getgrav/grav into feature/v1.8
 Conflicts:
	CHANGELOG.md
2022-03-23 12:58:48 +02:00
Matias Griese
9d179e5b2a Composer update 2022-03-09 12:33:20 +02:00
Matias Griese
6032bd07dc Merge branch 'develop' of github.com:getgrav/grav into feature/v1.8
 Conflicts:
	composer.json
	composer.lock
2022-03-09 12:32:31 +02:00
Matias Griese
9a87a509b0 Merge branch 'develop' of github.com:getgrav/grav into feature/v1.8 2022-02-22 11:35:29 +02:00
Matias Griese
46f2a81b21 Phpstan fixes 2022-02-19 15:20:06 +02:00
Matias Griese
f5e21645f6 Support phpstan level 6 in Framework classes 2022-02-19 14:17:02 +02:00
Matias Griese
12c8cf9c40 Phpstan fixes 2022-02-19 13:47:29 +02:00
Matias Griese
93bb929b38 Phpstan updates 2022-02-19 13:17:34 +02:00
Matias Griese
85eaf308d5 Fixed FlexDirectory::getCache() after converting to Symfony Cache 2022-02-19 13:17:19 +02:00
Matias Griese
d9ede28b99 Composer update 2022-02-19 12:18:40 +02:00
Matias Griese
2e65b0eea4 Merge branch 'develop' of github.com:getgrav/grav into feature/v1.8
 Conflicts:
	composer.lock
2022-02-19 12:18:00 +02:00
Matias Griese
7660a80ef7 Use older monolog due to clockwork incompatibility 2022-02-16 09:51:09 +02:00
Matias Griese
6d0a436834 Changelog update (pt 2) 2022-02-12 16:58:07 +02:00
Matias Griese
176fd8f1d8 Changelog update 2022-02-12 16:52:25 +02:00
Matias Griese
2f85fe9c99 Move unmaintained/unused vendor dependencies to the end of the list 2022-02-12 16:49:09 +02:00
Matias Griese
d93d297dc4 Updated to **Monolog 2.3** 2022-02-12 16:36:58 +02:00
Matias Griese
fcd9093f84 Use **Symfony Cache** instead of unmaintaided **Doctrine Cache** (with backward compatibility layer) 2022-02-12 15:33:38 +02:00
Matias Griese
58b54a70bd Removed system.umask_fix setting for security reasons 2022-02-12 13:49:30 +02:00
Matias Griese
9daa0a9041 Merge branch 'develop' of github.com:getgrav/grav into feature/v1.8
 Conflicts:
	composer.lock
2022-02-12 13:08:23 +02:00
Matias Griese
965e03daf2 Update dependencies so that everything works again 2022-02-07 14:14:11 +02:00
Matias Griese
b6c3db082a Update composer dependencies 2022-02-07 14:03:05 +02:00
Matias Griese
26b68953c4 Composer update 2022-02-07 13:48:47 +02:00
Matias Griese
fba015c5d9 Merge branch 'develop' of github.com:getgrav/grav into feature/v1.8
 Conflicts:
	composer.json
	composer.lock
2022-02-07 13:47:41 +02:00
Matias Griese
7223c177c4 Merge branch 'develop' of github.com:getgrav/grav into feature/v1.8
 Conflicts:
	composer.json
	composer.lock
2021-12-08 10:08:34 +02:00
Matias Griese
a68bdd2b75 Fixed Toolbox Event 2021-11-25 14:17:13 +02:00
Matias Griese
38e4624506 Composer update 2021-11-25 11:51:40 +02:00
Matias Griese
ad9287ee0f Merge branch 'develop' of github.com:getgrav/grav into feature/v1.8
 Conflicts:
	composer.json
	composer.lock
2021-11-25 11:46:21 +02:00
Matias Griese
777ac119de Update all libraries (WIP) 2021-10-20 20:33:05 +03:00
Matias Griese
076c64841e Merge branch 'develop' of github.com:getgrav/grav into feature/v1.8 2021-10-20 20:28:50 +03:00
Matias Griese
62cb40fef5 Composer update 2021-10-20 20:28:24 +03:00
580 changed files with 14118 additions and 6731 deletions

View File

@@ -4,9 +4,14 @@ on:
release:
types: [published]
permissions: {}
jobs:
build:
if: "!github.event.release.prerelease"
permissions:
contents: write # for release creation (svenstaro/upload-release-action)
#if: "!github.event.release.prerelease"
runs-on: ubuntu-latest
steps:
@@ -18,7 +23,7 @@ jobs:
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: 7.3
php-version: 8.2
extensions: opcache, gd
tools: composer:v2
coverage: none
@@ -33,10 +38,10 @@ jobs:
- name: Retrieval of Builder Scripts
run: |
# Real Grav URL
curl --silent -H "Authorization: token ${{ secrets.GLOBAL_TOKEN }}" -H "Accept: application/vnd.github.v3.raw" ${{ secrets.BUILD_SCRIPT_URL }} --output build-grav.sh
curl --silent -H "Authorization: token ${{ secrets.GLOBAL_TOKEN }}" -H "Accept: application/vnd.github.v3.raw" ${{ secrets.BUILD_SCRIPT_URL_18 }} --output build-grav.sh
# Development Local URL
# curl ${{ secrets.BUILD_SCRIPT_URL }} --output build-grav.sh
# curl ${{ secrets.BUILD_SCRIPT_URL_18 }} --output build-grav.sh
- name: Grav Builder
run: |
@@ -52,6 +57,9 @@ jobs:
file_glob: true
slack:
permissions:
actions: read # to list jobs for workflow run (technote-space/workflow-conclusion-action)
name: Slack
needs: build
runs-on: ubuntu-latest

View File

@@ -2,25 +2,26 @@ name: PHP Tests
on:
push:
branches: [ develop ]
branches: [ develop, 1.8 ]
pull_request:
branches: [ develop ]
branches: [ develop, 1.8 ]
permissions:
contents: read # to fetch code (actions/checkout)
jobs:
unit-tests:
strategy:
matrix:
php: [8.4, 8.3, 8.2]
os: [ubuntu-latest]
runs-on: ${{ matrix.os }}
strategy:
matrix:
php: [ 8.1, 8.0, 7.4, 7.3]
os: [ubuntu-latest]
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4
- name: Setup PHP
- name: Setup PHP ${{ matrix.php }}
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php }}
@@ -28,20 +29,14 @@ jobs:
tools: composer:v2
coverage: none
env:
COMPOSER_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# - name: Update composer
# run: composer update
#
# - name: Validate composer.json and composer.lock
# run: composer validate
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Get composer cache directory
id: composer-cache
run: echo "::set-output name=dir::$(composer config cache-files-dir)"
run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT
- name: Cache dependencies
uses: actions/cache@v2
uses: actions/cache@v4
with:
path: ${{ steps.composer-cache.outputs.dir }}
key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}

View File

@@ -10,7 +10,10 @@ on:
admin:
description: 'Create also a package with Admin'
required: true
default: true
default: 'true'
permissions:
contents: read # to fetch code (actions/checkout)
jobs:
build:

8
.gitignore vendored
View File

@@ -25,8 +25,11 @@ user/plugins/*
!user/plugins/.*
user/themes/*
!user/themes/.*
user/localhost/config/security.yaml
user/config/security.yaml
user/**/config/security.yaml
# Environments
.env
.gravenv
# OS Generated
.DS_Store*
@@ -45,4 +48,3 @@ tests/cache/*
tests/error.log
system/templates/testing/*
/user/config/versions.yaml
/user/cli/config/security.yaml

View File

@@ -1,3 +1,365 @@
# v1.8.0-beta.8
## 10/14/2025
1. [](#improved)
* Upgraded to latest Symfony 7 (might cause issues with some plugins)
* `wordCount` twig filter (merged from 1.7 branch)
* More PHP 8.4 compatibility fixes
* Update all vendor libraries to latest
1. [](#bugfix)
* Fixed some CLI level bugs
* Fixed a Twig Sandbox bybpass issue
# v1.8.0-beta.7
## 09/22/2025
1. [](#bugfix)
* Changed `private` to `public` for YamlUpdater::get() and YamUpdater::set() methods
* Fixed a session cookie issue that manifested when logging-in to client side
# v1.8.0-beta.6
## 09/22/2025
1. [](#bugfix)
* Fixed a missing YamlUpdater::exists() method
# v1.8.0-beta.5
## 09/22/2025
1. [](#new)
* Deferred Extension support in Forked version of Twig 3
* Added separate `strict_mode.twig2_compat` and `strict_mode.twig3_compat` toggles to manage auto-escape behaviour and automatic Twig 3 compatible template rewrites
1. [](#bugfix)
* Fix for cache blowing up when upgrading from 1.7 to 1.8 via CLI
# v1.8.0-beta.4
## 01/27/2025
1. [](#bugfix)
* Fixed a PHP compatibility issue with `AbstractLazyCollection`
1. [](#improved)
* Global PHP 8.2 code optimizations
* More PHP 8.4 compatibility fixes
* Twig 2.x forked to getgrav/twig 2.x for PHP 8.4 compatibility
* Switch to cache@v4 + limit PHP version for Github actions
* Trigger testing Github action for Grav 1.8
* Merge latest Grav 1.7 fixes into Grav 1.8
# v1.8.0-beta.3
## 11/21/2024
1. [](#improved)
* Updated composer libraries to latest versions for compatibility fixes
# v1.8.0-beta.2
## 10/28/2024
1. [](#new)
* Use `dev-master` branch of Clockwork to support Monolog2 / Monolog3
* `AVIF` image support via updates to `getgrav/Image` library
* Upgraded to **Doctrine Collection 2.2**
1. [](#improved)
* Updated composer libraries
* Updated composer.php binary to `v2.8.1`
* Fixes for PHP 8.4 - Implicitly nullable parameter declarations deprecated
* Added back Missing `RocketTheme\Toolbox\Event\EventSubscriberInterface` for Gantry5
1. [](#bugfix)
* Various fixes to use `$log->debug()`, `$log->info()`, `$log->warning()` and `$log->error()` For Monolog2 support
# v1.8.0-beta.1
## 10/23/2024
1. [](#new)
* Set minimum requirements to **PHP 8.2**
* Updated to **Twig 2.14**
* Updated to **Symfony 6.4**
* Updated to **Monolog 2.3**
* Updated to **RocketTheme/Toolbox 2.0**
* Updated to **Composer/Semver 3.2**
* Use **Symfony Cache** instead of unmaintained **Doctrine Cache**
* Removed unsupported **APC**, **WinCache**, **XCache** and **Memcache**, use apcu or memcached instead
* Removed `system.umask_fix` setting for security reasons
* Support phpstan level 6 in Framework classes
# v1.7.49.5
## 09/10/2025
1. [](#bugfix)
* Backup not honoring ignored paths [#3952](https://github.com/getgrav/grav/issues/3952)
# v1.7.49.4
## 09/03/2025
1. [](#bugfix)
* Fixed cron force running jobs severy minute! [#3951](https://github.com/getgrav/grav/issues/3951)
# v1.7.49.3
## 09/02/2025
1. [](#bugfix)
* Fixed an error in ZipArchive that was causing issues on some systems
* Fixed namespace change for `Cron\Expression`
* Removed broken cron install field... use 'instructions' instead
* Fixed duplicate jobs listing in some CLI commands
# v1.7.49.2
## 08/28/2025
1. [](#bugfix)
* Fix translation of key for image adapter [#3944](https://github.com/getgrav/grav/pull/3944)
# v1.7.49.1
## 08/25/2025
1. [](#new)
* Rerelease to include all updated plugins/theme etc.
# v1.7.49
## 08/25/2025
1. [](#new)
* Revamped Grav Scheduler to support webhook to call call scheduler + concurrent jobs + jobs queue + logging, and other improvements
* Revamped Grav Cache purge capabilities to only clear obsolete old cache items
* Added full imagick support in Grav Image library
* Added support for Validate `match` and `match_any` in forms
1. [](#improved)
* Handle empty values on require with ignore fields in Forms
* Use `actions/cache@v4` in github workflows
* Use `actions/checkout@v4`in github workflows [#3867](https://github.com/getgrav/grav/pull/3867)
* Update code block in README.md [#3886](https://github.com/getgrav/grav/pull/3886)
* Updated vendor libs to latest
1. [](#bugfix)
* Bug in `exif_read_data` [#3878](https://github.com/getgrav/grav/pull/3878)
* Fix parser error in URI: [#3894](https://github.com/getgrav/grav/issues/3894)
>>>>>>> develop
# v1.7.48
## 10/28/2024
1. [](#new)
* New Trait for fetchPriority attribute on images [#3850](https://github.com/getgrav/grav/pull/3850)
1. [](#improved)
* Fix for #3164. Adds aliases as possible commands during lookup [#3863](https://github.com/getgrav/grav/pull/3863)
1. [](#bugfix)
* Fix style conflict with Clockwork and tooltips [#3861](https://github.com/getgrav/grav/pull/3861)
# v1.7.47
## 10/23/2024
1. [](#new)
* New `Utils::toAscii()` method
* Added support for Clockwork Debugger to allow web UI (requires new `clockwork-web` plugin)
1. [](#improved)
* Include modular sub-pages in last-modification date computation [#3562](https://github.com/getgrav/grav/pull/3562)
* Updated vendor libs to latest versions
* Updated JQuery to `3.7.1` [#3787](https://github.com/getgrav/grav/pull/3827)
* Updated vendor libraries to latest versions
* Support for Fediverse Creator meta tag [#3844](https://github.com/getgrav/grav/pull/3844)
1. [](#bugfix)
* Fixes deprecated for return type in Filesystem with PHP 8.3.6 [#3831](https://github.com/getgrav/grav/issues/3831)
* Fix for `exif_imagtetype()` throwing an exception when file doesn't exist
* Fix JSON output comments check with content type [#3859](https://github.com/getgrav/grav/pull/3859)
# v1.7.46
## 05/15/2024
1. [](#new)
* Added a new `Utils::toAscii()` method to remove UTF-8 characters from string
1. [](#improved)
* Removed unused `symfony/service-contracts` [#3828](https://github.com/getgrav/grav/pull/3828)
* Upgraded bundled legacy JQuery to `3.7.1` [#3727](https://github.com/getgrav/grav/pull/3827)
* Include modular pages in header `last-modified:` calculation [#3562](https://github.com/getgrav/grav/pull/3562)
* Updated vendor libs to latest versions
1. [](#bugfix)
* Fixed some deprecated issues in Filesystem [#3831](https://github.com/getgrav/grav/issues/3831)
# v1.7.46
## 05/15/2024
1. [](#improved)
* Better handling of external protocols in `Utils::url()` such as `mailto:`, `tel:`, etc.
* Handle `GRAV_ROOT` or `GRAV_WEBROOT` when `/` [#3667](https://github.com/getgrav/grav/pull/3667)
1. [](#bugfix)
* Fixes for multi-lang taxonomy when reinitializing the languages (e.g. LangSwitcher plugin)
* Ensure the full filepath is checked for invalid filename in `MediaUploadTrait::checkFileMetadata()`
* Fixed a bug in the `on_events` REGEX pattern of `Security::detectXss()` as it was not matching correctly.
* Fixed an issue where `read_file()` Twig function could be used nefariously in content [#GHSA-f8v5-jmfh-pr69](https://github.com/getgrav/grav/security/advisories/GHSA-f8v5-jmfh-pr69)
# v1.7.45
## 03/18/2024
1. [](#new)
* Added new Image trait for `decoding` attribute [#3796](https://github.com/getgrav/grav/pull/3796)
1. [](#bugfix)
* Fixed some multibyte issues in Inflector class [#732](https://github.com/getgrav/grav/issues/732)
* Fallback to page modified date if Page date provided is invalid and can't be parsed [getgrav/grav-plugin-admin#2394](https://github.com/getgrav/grav-plugin-admin/issues/2394)
* Fixed a path traversal vulnerability with file uploads [#GHSA-m7hx-hw6h-mqmc](https://github.com/getgrav/grav/security/advisories/GHSA-m7hx-hw6h-mqmc)
* Fixed a security issue with insecure Twig functions be processed [#GHSA-2m7x-c7px-hp58](https://github.com/getgrav/grav/security/advisories/GHSA-2m7x-c7px-hp58) [#GHSA-r6vw-8v8r-pmp4](https://github.com/getgrav/grav/security/advisories/GHSA-r6vw-8v8r-pmp4) [#GHSA-qfv4-q44r-g7rv](https://github.com/getgrav/grav/security/advisories/GHSA-qfv4-q44r-g7rv) [#GHSA-c9gp-64c4-2rrh](https://github.com/getgrav/grav/security/advisories/GHSA-c9gp-64c4-2rrh)
1. [](#improved)
* Updated composer packages
* Updated `bin/composer.phar` to latest `2.7.2`
# v1.7.44
## 01/05/2024
1. [](#new)
* Added PHP `8.3` to tests [#3782](https://github.com/getgrav/grav/pull/3782)
* Added debugger messages when Page routes conflict
* Added `ISO 8601` date format [#3721](https://github.com/getgrav/grav/pull/37210)
* Added support for `.vcf` (vCard) in media configuration [#3772](https://github.com/getgrav/grav/pull/3772)
1. [](#improved)
* Update jQuery to `v3.6.4` [#3713](https://github.com/getgrav/grav/pull/3713)
* Updated vendor libraries including Dom-Sanitizer `v1.0.7` that addresses an XSS issue
* Updated `bin/composer.phar` to latest `2.6.6`
* Updated vendor libraries to latest
* Updated language files
* Updated copyright year
1. [](#bugfix)
* Fixed a math rounding issue with number validation when using floating point steps [#3761](https://github.com/getgrav/grav/issues/3761)
* Fixed an issue with `Inflector::ordinalize()` not working as expected [#3759](https://github.com/getgrav/grav/pull/3759)
* Fixed various issues with file extension checking with dangerous extensions [#3756(https://github.com/getgrav/grav/pull/3756)]
* Fix for invalid input to foreach in `UserGroupObject` [#3724](https://github.com/getgrav/grav/pull/3724)
* Fixed exception: `Property 'jsmodule_pipeline_include_externals' does not exist in object` [#3661](https://github.com/getgrav/grav/pull/3661)
* Fixed `too few arguments exception` in FlexObjects [#3658](https://github.com/getgrav/grav/pull/3658)
# v1.7.43
## 10/02/2023
1. [](#new)
* Add the ability to programatically set a page's `modified` timestamp via a `modified:` frontmatter entry
2. [](#improved)
* Update vendor libraries
* Include `phar` in the list of `security.uploads_dangerous_extensions`
* When enabled `system.languages.debug` now dumps **Key -> Value** to debugger [#3752](https://github.com/getgrav/grav/issues/3752)
* Updated built-in composer to latest `2.6.4` [#3748](https://github.com/getgrav/grav/issues/3748)
* Added support for `@import` to ensure paths are rewritten correctly in CSS pipeline [#3750](https://github.com/getgrav/grav/pull/3750)
# v1.7.42.3
## 07/18/2023
2. [](#improved)
* Fixed a typo in `Utils::isDangerousFunction`
# v1.7.42.2
## 07/18/2023
2. [](#improved)
* In `Utils::isDangerousFunction`, handle double `\\` in `|map` twig filter to mitigate SSTI attack
* Better handle empty email in `Validatoin::typeEmail()`
# v1.7.42.1
## 06/15/2023
2. [](#improved)
* Quick fix for `isDangerousFunction` when `$name` was a closure [#3727](https://github.com/getgrav/grav/issues/3727)
# v1.7.42
## 06/14/2023
1. [](#new)
* Added a new `system.languages.debug` option that adds a `<span class="translate-debug"></span>` around strings translated with `|t`. This can be styled by the theme as needed.
1. [](#improved)
* More robust SSTI handling in `filter`, `map`, and `reduce` Twig filters and functions
* Various SSTI improvements `Utils::isDangerousFunction()`
1. [](#bugfix)
* Fixed Twig `|map()` allowing code execution
* Fixed Twig `|reduce()` allowing code execution
# v1.7.41.2
## 06/01/2023
1. [](#improved)
* Added the ability to set a configurable 'key' for the Twig Cache Tag: `{% cache 'my-key' 600 %}`
1. [](#bugfix)
* Fixed an issue with special characters in slug's would cause redirect loops
# v1.7.41.1
## 05/10/2023
1. [](#bugfix)
* Fixed certain UTF-8 characters breaking `Truncator` class [#3716](https://github.com/getgrav/grav/issues/3716)
# v1.7.41
## 05/09/2023
1. [](#improved)
* Removed `FILTER_SANITIZE_STRING` input filter in favor of `htmlspecialchars(strip_tags())` for PHP 8.2+
* Added `GRAV_SANITIZE_STRING` constant to replace `FILTER_SANITIZE_STRING` for PHP 8.2+
* Support non-deprecated style dynamic properties in `Parsedown` class via `ParseDownGravTrait` for PHP 8.2+
* Modified `Truncator` to not use deprecated `mb_convert_encoding()` for PHP 8.2+
* Fixed passing null into `mb_strpos()` deprecated for PHP 8.2+
* Updated internal `TwigDeferredExtension` to be PHP 8.2+ compatible
* Upgraded `getgrav/image` fork to take advantage of various PHP 8.2+ fixes
* Use `UserGroupObject::groupNames` method in blueprints for PHP 8.2+
* Comment out `files-upload` deprecated message as this is not going to be removed
* Added various public `Twig` class variables used by admin to address deprecated messages for PHP 8.2+
* Added `parse_url` to list of PHP functions supported in Twig Extension
* Added support for dynamic functions in `Parsedown` to stop deprecation messages in PHP 8.2+
# v1.7.40
## 03/22/2023
1. [](#new)
* Added a new `timestamp: true|false` option for individual assets
1. [](#improved)
* Removed outdated `xcache` setting [#3615](https://github.com/getgrav/grav/pull/3615)
* Updated `robots.txt` [#3625](https://github.com/getgrav/grav/pull/3625)
* Handle the situation when GRAV_ROOT or GRAV_WEBROOT are `/` [#3625](https://github.com/getgrav/grav/pull/3667)
1. [](#bugfix)
* Fixed `force_ssl` redirect in case of undefined hostname [#3702](https://github.com/getgrav/grav/pull/3702)
* Fixed an issue with duplicate identical page paths
* Fixed `BlueprintSchema:flattenData` to properly handle ignored fields
* Fixed LogViewer regex greediness [#3684](https://github.com/getgrav/grav/pull/3684)
* Fixed `whoami` command [#3695](https://github.com/getgrav/grav/pull/3695)
# v1.7.39.4
## 02/22/2023
1. [](#bugfix)
* Reverted a reorganization of `account.yaml` that caused username to be disabled [admin#2344](https://github.com/getgrav/grav-plugin-admin/issues/2344)
# v1.7.39.3
## 02/21/2023
1. [](#bugfix)
* Fix for overzealous modular page template rendering fix in 1.7.39 causing Feed plugin to break [#3689](https://github.com/getgrav/grav/issues/3689)
# v1.7.39.2
## 02/20/2023
1. [](#bugfix)
* Fix for invalid session breaking Flex Accounts (when switching from Regular to Flex)
# v1.7.39.1
## 02/20/2023
1. [](#bugfix)
* Fix for broken image CSS with the latest version of DebugBar
# v1.7.39
## 02/19/2023
1. [](#improved)
* Vendor library updates to latest versions
1. [](#bugfix)
* Various PHP 8.2 fixes
* Fixed an issue with modular pages rendering thew wrong template when dynamically changing the page
* Fixed an issue with `email` validation that was failing on UTF-8 characters. Following best practices and now only check for `@` and length.
* Fixed PHPUnit tests to remove deprecation warnings
# v1.7.38
## 01/02/2023
1. [](#new)
* New `onBeforeSessionStart()` event to be used to store data lost during session regeneration (e.g. login)
1. [](#improved)
* Vendor library updates to latest versions
* Updated `bin/composer.phar` to latest `2.4.4` version [#3627](https://github.com/getgrav/grav/issues/3627)
1. [](#bugfix)
* Don't fail hard if pages recurse with same path
* Github workflows security hardening [#3624](https://github.com/getgrav/grav/pull/3624)
# v1.7.37.1
## 10/05/2022

View File

@@ -20,7 +20,7 @@ The underlying architecture of Grav is designed to use well-established and _bes
# Requirements
- PHP 7.3.6 or higher. Check the [required modules list](https://learn.getgrav.org/basics/requirements#php-requirements)
- PHP 8.2 or higher. Check the [required modules list](https://learn.getgrav.org/basics/requirements#php-requirements)
- Check the [Apache](https://learn.getgrav.org/basics/requirements#apache-requirements) or [IIS](https://learn.getgrav.org/basics/requirements#iis-requirements) requirements
# Documentation
@@ -39,22 +39,22 @@ You can download a **ready-built** package from the [Downloads page on https://g
You can create a new project with the latest **stable** Grav release with the following command:
```
$ composer create-project getgrav/grav ~/webroot/grav
```bash
composer create-project getgrav/grav ~/webroot/grav
```
### From GitHub
1. Clone the Grav repository from [https://github.com/getgrav/grav]() to a folder in the webroot of your server, e.g. `~/webroot/grav`. Launch a **terminal** or **console** and navigate to the webroot folder:
```
$ cd ~/webroot
$ git clone https://github.com/getgrav/grav.git
```bash
cd ~/webroot
git clone https://github.com/getgrav/grav.git
```
2. Install the **plugin** and **theme dependencies** by using the [Grav CLI application](https://learn.getgrav.org/advanced/grav-cli) `bin/grav`:
```
$ cd ~/webroot/grav
$ bin/grav install
```bash
cd ~/webroot/grav
bin/grav install
```
Check out the [install procedures](https://learn.getgrav.org/basics/installation) for more information.
@@ -63,35 +63,36 @@ Check out the [install procedures](https://learn.getgrav.org/basics/installation
You can download [plugins](https://getgrav.org/downloads/plugins) or [themes](https://getgrav.org/downloads/themes) manually from the appropriate tab on the [Downloads page on https://getgrav.org](https://getgrav.org/downloads), but the preferred solution is to use the [Grav Package Manager](https://learn.getgrav.org/advanced/grav-gpm) or `GPM`:
```
$ bin/gpm index
```bash
bin/gpm index
```
This will display all the available plugins and then you can install one or more with:
```
$ bin/gpm install <plugin/theme>
```bash
bin/gpm install <plugin/theme>
```
# Updating
To update Grav you should use the [Grav Package Manager](https://learn.getgrav.org/advanced/grav-gpm) or `GPM`:
```
$ bin/gpm selfupgrade
```bash
bin/gpm selfupgrade
```
To update plugins and themes:
```
$ bin/gpm update
```bash
bin/gpm update
```
## Upgrading from older version
* [Upgrading to Grav 1.8](https://learn.getgrav.org/16/advanced/grav-development/grav-18-upgrade-guide)
* [Upgrading to Grav 1.7](https://learn.getgrav.org/16/advanced/grav-development/grav-17-upgrade-guide)
* [Upgrading to Grav 1.6](https://learn.getgrav.org/16/advanced/grav-development/grav-16-upgrade-guide)
* [Upgrading from Grav <1.6](https://learn.getgrav.org/16/advanced/grav-development/grav-15-upgrade-guide)
* [Upgrading from Grav before 1.6](https://learn.getgrav.org/16/advanced/grav-development/grav-15-upgrade-guide)
# Contributing
We appreciate any contribution to Grav, whether it is related to bugs, grammar, or simply a suggestion or improvement! Please refer to the [Contributing guide](CONTRIBUTING.md) for more guidance on this topic.

View File

@@ -7,15 +7,32 @@ We are focusing our security updates on the following versions
| Version | Supported |
| ------- | ------------------ |
| 1.7.x | :white_check_mark: |
| 1.6.x | :warning: |
| 1.6.x | :x: |
| < 1.6 | :x: |
## :pushpin: Note on Security Severity
> NOTE: Please use the following guidelines when selecting a **Severity**. Submitted advisories that are marked **High** or **Critical** that don't meet the guidelines below will be closed.
* **CRITICAL** - no account required, can modify content, or run malicious code or nefarious activity without any access.
* **HIGH** - publisher level account able to run malicious code or nefarious activity, or other high level security things.
* **MODERATE** - admin level account able to run malicious code or do nefarious things. other moderate security things.
* **LOW** - super admin level account able to run malicious code or do nefarious things. other minor security things.
## :warning: Versions
Versions with :warning: will be supported for security issues, however you won't be able to update to them, you will need to manually update through the [`direct-install` command](https://learn.getgrav.org/17/admin-panel/tools).
If you cannot update to the latest stable version available because, for example, your server does not meet the minimum PHP requirements, you can manually install a previous version by downloading the package from our Releases directory (https://github.com/getgrav/grav/releases).
## Reporting a Vulnerability
## :pencil: Reporting a Vulnerability
Please contact security@getgrav.org with a detailed explanation of the security issue found. If it appears to be a legitimate issues, please submit an **advisory via GitHub Security**: https://github.com/getgrav/grav/security/advisories
> NOTE: Please do not use 3rd party security issue reporting services, we like to keep everything in the GitHub ecosystem for easier manageability.
## :bug: Bug Bounties
We do greatly appreciate your efforts to improve Grav, but unfortunately because we are a small open source project, we **do not have the resources to offer bounties** for security issues found.
Please contact security@getgrav.org with a detailed explaination of the security issue found and we will work with you to get it resolved as fast as possible.

View File

@@ -1 +1 @@
/* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved. */
/* @copyright Copyright (c) 2015 - 2023 Trilby Media, LLC. All rights reserved. */

View File

@@ -1 +1 @@
/* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved. */
/* @copyright Copyright (c) 2015 - 2023 Trilby Media, LLC. All rights reserved. */

Binary file not shown.

View File

@@ -2,7 +2,7 @@
<?php
/**
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2025 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/

View File

@@ -2,7 +2,7 @@
<?php
/**
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2025 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/

View File

@@ -2,7 +2,7 @@
<?php
/**
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2025 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/

2
cache/.gitkeep vendored
View File

@@ -1 +1 @@
/* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved. */
/* @copyright Copyright (c) 2015 - 2023 Trilby Media, LLC. All rights reserved. */

View File

@@ -2,7 +2,7 @@ actor: Tester
bootstrap: _bootstrap.php
paths:
tests: tests
log: tests/_output
output: tests/_output
data: tests/_data
support: tests/_support
envs: tests/_envs

View File

@@ -12,7 +12,7 @@
"homepage": "https://getgrav.org",
"license": "MIT",
"require": {
"php": "^7.3.6 || ^8.0",
"php": "^8.2",
"ext-json": "*",
"ext-openssl": "*",
"ext-curl": "*",
@@ -20,62 +20,79 @@
"ext-dom": "*",
"ext-libxml": "*",
"ext-gd": "*",
"symfony/polyfill-mbstring": "~1.23",
"symfony/polyfill-iconv": "^1.23",
"symfony/polyfill-php74": "^1.23",
"symfony/polyfill-php80": "^1.23",
"symfony/polyfill-php81": "^1.23",
"psr/simple-cache": "^1.0",
"psr/http-message": "^1.0",
"symfony/polyfill-mbstring": "^1.24",
"symfony/polyfill-iconv": "^1.24",
"symfony/polyfill-php80": "^1.24",
"symfony/polyfill-php81": "^1.24",
"psr/simple-cache": "^1.0 || ^2.0 || ^3.0",
"psr/http-message": "^1.1 || ^2.0",
"psr/http-server-middleware": "^1.0",
"psr/container": "~1.1.0",
"nyholm/psr7-server": "^1.0",
"nyholm/psr7": "^1.3",
"twig/twig": "~v1.44",
"psr/container": "^1.1 || ^2.0",
"psr/log": "^1.1 || ^2.0 || ^3.0",
"symfony/cache": "^6.4 || ^7.0",
"symfony/yaml": "^6.4 || ^7.0",
"symfony/console": "^6.4 || ^7.0",
"symfony/event-dispatcher": "^6.4 || ^7.0",
"symfony/var-exporter": "^6.4 || ^7.0",
"symfony/var-dumper": "^6.4 || ^7.0",
"symfony/process": "^6.4 || ^7.0",
"symfony/http-client": "^6.4 || ^7.0",
"twig/twig": "3.x-dev",
"monolog/monolog": "^3.0",
"doctrine/cache": "^2.2",
"doctrine/collections": "^2.2",
"pimple/pimple": "~3.5.0",
"nyholm/psr7-server": "^1.1",
"nyholm/psr7": "^1.8",
"erusev/parsedown": "^1.7",
"erusev/parsedown-extra": "~0.8",
"symfony/contracts": "~1.1",
"symfony/yaml": "~4.4",
"symfony/console": "~4.4",
"symfony/event-dispatcher": "~4.4",
"symfony/var-dumper": "~4.4",
"symfony/process": "~4.4",
"doctrine/cache": "^1.10",
"doctrine/collections": "^1.6",
"guzzlehttp/psr7": "^1.7",
"filp/whoops": "~2.9",
"matthiasmullie/minify": "^1.3",
"monolog/monolog": "~1.25",
"getgrav/image": "^3.0",
"getgrav/cache": "^2.0",
"donatj/phpuseragentparser": "~1.1",
"pimple/pimple": "~3.5.0",
"rockettheme/toolbox": "~1.5",
"maximebf/debugbar": "~1.16",
"league/climate": "^3.6",
"miljar/php-exif": "^0.6",
"composer/ca-bundle": "^1.2",
"dragonmantank/cron-expression": "^1.2",
"willdurand/negotiation": "^3.0",
"itsgoingd/clockwork": "^5.0",
"symfony/http-client": "^4.4",
"composer/semver": "^1.4",
"rockettheme/toolbox": "v2.x-dev",
"composer/ca-bundle": "^1.5",
"composer/semver": "^3.4",
"dragonmantank/cron-expression": "^3.3",
"willdurand/negotiation": "^3.1",
"rhukster/dom-sanitizer": "^1.0",
"matthiasmullie/minify": "^1.3",
"donatj/phpuseragentparser": "~1.9",
"guzzlehttp/psr7": "^2.7",
"filp/whoops": "~2.16",
"itsgoingd/clockwork": "^5.3",
"php-debugbar/php-debugbar": "~2.1",
"getgrav/image": "^4.0",
"getgrav/cache": "^2.0",
"antoligy/dom-string-iterators": "^1.0",
"miljar/php-exif": "^0.6",
"league/climate": "^3.10",
"multiavatar/multiavatar-php": "^1.0"
},
"require-dev": {
"codeception/codeception": "^4.1",
"phpstan/phpstan": "^1.8",
"phpstan/phpstan-deprecation-rules": "^1.0",
"phpunit/php-code-coverage": "~9.2",
"codeception/codeception": "^5.1",
"phpstan/phpstan": "^2.1",
"phpstan/phpstan-deprecation-rules": "^2.0",
"phpunit/php-code-coverage": "^11.0",
"getgrav/markdowndocs": "^2.0",
"codeception/module-asserts": "^1.3",
"codeception/module-phpbrowser": "^1.0",
"symfony/service-contracts": "*"
"codeception/module-asserts": "*",
"codeception/module-phpbrowser": "*",
"rector/rector": "^2.1"
},
"repositories": [
{
"type": "vcs",
"url": "https://github.com/rockettheme/toolbox"
},
{
"type": "vcs",
"url": "https://github.com/getgrav/twig"
},
{
"type": "vcs",
"url": "https://github.com/getgrav/parsedown"
}
],
"replace": {
"symfony/polyfill-php72": "*",
"symfony/polyfill-php73": "*"
"symfony/polyfill-php73": "*",
"symfony/polyfill-php74": "*"
},
"suggest": {
"ext-mbstring": "Recommended for better performance",
@@ -90,12 +107,14 @@
"config": {
"apcu-autoloader": true,
"platform": {
"php": "7.3.6"
"php": "8.2"
}
},
"autoload": {
"psr-4": {
"Grav\\": "system/src/Grav",
"Doctrine\\": "system/src/Doctrine",
"RocketTheme\\": "system/src/RocketTheme",
"Twig\\": "system/src/Twig"
},
"files": [
@@ -115,10 +134,12 @@
]
},
"scripts": {
"api-17": "vendor/bin/phpdoc-md generate system/src > user/pages/14.api/default.17.md",
"api-18": "vendor/bin/phpdoc-md generate system/src > user/pages/14.api/default.18.md",
"post-create-project-cmd": "bin/grav install",
"rector": "vendor/bin/rector",
"rector:php-compat": "@php vendor/bin/rector process --config=system/rector.php --ansi --no-progress-bar",
"phpstan": "vendor/bin/phpstan analyse -l 2 -c ./tests/phpstan/phpstan.neon --memory-limit=720M system/src",
"phpstan-framework": "vendor/bin/phpstan analyse -l 5 -c ./tests/phpstan/phpstan.neon --memory-limit=480M system/src/Grav/Framework system/src/Grav/Events system/src/Grav/Installer",
"phpstan-framework": "vendor/bin/phpstan analyse -l 6 -c ./tests/phpstan/phpstan.neon --memory-limit=480M system/src/Grav/Framework system/src/Grav/Events system/src/Grav/Installer",
"phpstan-plugins": "vendor/bin/phpstan analyse -l 1 -c ./tests/phpstan/plugins.neon --memory-limit=400M user/plugins",
"test": "vendor/bin/codecept run unit",
"test-windows": "vendor\\bin\\codecept run unit"

4168
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -1 +1 @@
/* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved. */
/* @copyright Copyright (c) 2015 - 2023 Trilby Media, LLC. All rights reserved. */

View File

@@ -3,14 +3,14 @@
/**
* @package Grav.Core
*
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2024 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/
namespace Grav;
\define('GRAV_REQUEST_TIME', microtime(true));
\define('GRAV_PHP_MIN', '7.3.6');
\define('GRAV_PHP_MIN', '8.2.0');
if (PHP_SAPI === 'cli-server') {
$symfony_server = stripos(getenv('_'), 'symfony') !== false || stripos($_SERVER['SERVER_SOFTWARE'] ?? '', 'symfony') !== false || stripos($_ENV['SERVER_SOFTWARE'] ?? '', 'symfony') !== false;
@@ -40,12 +40,12 @@ use Grav\Common\Grav;
use RocketTheme\Toolbox\Event\Event;
// Get the Grav instance
$grav = Grav::instance(array('loader' => $loader));
$grav = Grav::instance(['loader' => $loader]);
// Process the page
try {
$grav->process();
} catch (\Error|\Exception $e) {
$grav->fireEvent('onFatalException', new Event(array('exception' => $e)));
$grav->fireEvent('onFatalException', new Event(['exception' => $e]));
throw $e;
}

View File

@@ -1 +1 @@
/* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved. */
/* @copyright Copyright (c) 2015 - 2023 Trilby Media, LLC. All rights reserved. */

505
needs_fixing.txt Normal file
View File

@@ -0,0 +1,505 @@
------ ----------------------------------------------------
Line src/Grav/Common/GPM/Response.php
------ ----------------------------------------------------
3 Class Grav\Common\GPM\Response not found.
🪪 class.notFound
💡 Learn more at
https://phpstan.org/user-guide/discovering-symbols
------ ----------------------------------------------------
------ -----------------------------------------------------------
Line src/Grav/Common/Grav.php
------ -----------------------------------------------------------
148 No error to ignore is reported on line 148.
681 Unsafe usage of new static().
🪪 new.static
💡 See:
https://phpstan.org/blog/solving-phpstan-error-unsafe-usa
ge-of-new-static
------ -----------------------------------------------------------
------ -----------------------------------------------------------
Line src/Grav/Common/Page/Collection.php
------ -----------------------------------------------------------
112 Unsafe usage of new static().
🪪 new.static
💡 See:
https://phpstan.org/blog/solving-phpstan-error-unsafe-usa
ge-of-new-static
209 Unsafe usage of new static().
🪪 new.static
💡 See:
https://phpstan.org/blog/solving-phpstan-error-unsafe-usa
ge-of-new-static
------ -----------------------------------------------------------
------ -----------------------------------------------------------
Line src/Grav/Common/Processors/InitializeProcessor.php
------ -----------------------------------------------------------
58 Unsafe usage of new static().
🪪 new.static
💡 See:
https://phpstan.org/blog/solving-phpstan-error-unsafe-usa
ge-of-new-static
------ -----------------------------------------------------------
------ -------------------------------------------------------
Line src/Grav/Common/Scheduler/Job.php
------ -------------------------------------------------------
574 Call to static method sendEmail() on an unknown class
Grav\Plugin\Email\Utils.
🪪 class.notFound
💡 Learn more at
https://phpstan.org/user-guide/discovering-symbols
------ -------------------------------------------------------
------ ----------------------------------------------------------
Line src/Grav/Common/Scheduler/SchedulerController.php
------ ----------------------------------------------------------
41 Class Grav\Common\Scheduler\ModernScheduler not found.
🪪 class.notFound
💡 Learn more at
https://phpstan.org/user-guide/discovering-symbols
45 Instantiated class Grav\Common\Scheduler\ModernScheduler
not found.
🪪 class.notFound
💡 Learn more at
https://phpstan.org/user-guide/discovering-symbols
------ ----------------------------------------------------------
------ --------------------------------------------------------
Line src/Grav/Common/Service/SchedulerServiceProvider.php
------ --------------------------------------------------------
55 Instantiated class Grav\Common\Scheduler\JobWorker not
found.
🪪 class.notFound
💡 Learn more at
https://phpstan.org/user-guide/discovering-symbols
------ --------------------------------------------------------
------ ---------------------------------------------
Line src/Grav/Common/Session.php
------ ---------------------------------------------
132 No error to ignore is reported on line 132.
137 No error to ignore is reported on line 137.
------ ---------------------------------------------
------ -----------------------------------------------------------
Line src/Grav/Common/Uri.php
------ -----------------------------------------------------------
1131 Unsafe usage of new static().
🪪 new.static
💡 See:
https://phpstan.org/blog/solving-phpstan-error-unsafe-usa
ge-of-new-static
------ -----------------------------------------------------------
------ --------------------------------------------------------
Line src/Grav/Console/Application/Application.php
------ --------------------------------------------------------
125 Return type mixed of method
Grav\Console\Application\Application::configureIO() is
not covariant with return type void of method
Symfony\Component\Console\Application::configureIO().
------ --------------------------------------------------------
------ ---------------------------------------------------------
Line src/Grav/Console/ConsoleCommand.php
------ ---------------------------------------------------------
29 Return type mixed of method
Grav\Console\ConsoleCommand::execute() is not covariant
with return type int of method
Symfony\Component\Console\Command\Command::execute().
------ ---------------------------------------------------------
------ -----------------------------------------------------------
Line src/Grav/Console/ConsoleTrait.php (in context of class
Grav\Console\ConsoleCommand)
------ -----------------------------------------------------------
89 Method Grav\Console\ConsoleCommand::addOption() overrides
method
Symfony\Component\Console\Command\Command::addOption()
but misses parameter #6 $suggestedValues.
------ -----------------------------------------------------------
------ --------------------------------------------------------
Line src/Grav/Console/ConsoleTrait.php (in context of class
Grav\Console\GpmCommand)
------ --------------------------------------------------------
89 Method Grav\Console\GpmCommand::addOption() overrides
method
Symfony\Component\Console\Command\Command::addOption()
but misses parameter #6 $suggestedValues.
------ --------------------------------------------------------
------ --------------------------------------------------------
Line src/Grav/Console/ConsoleTrait.php (in context of class
Grav\Console\GravCommand)
------ --------------------------------------------------------
89 Method Grav\Console\GravCommand::addOption() overrides
method
Symfony\Component\Console\Command\Command::addOption()
but misses parameter #6 $suggestedValues.
------ --------------------------------------------------------
------ ----------------------------------------------------------
Line src/Grav/Console/GpmCommand.php
------ ----------------------------------------------------------
31 Return type mixed of method
Grav\Console\GpmCommand::execute() is not covariant with
return type int of method
Symfony\Component\Console\Command\Command::execute().
39 No error to ignore is reported on line 39.
------ ----------------------------------------------------------
------ -----------------------------------------------------------
Line src/Grav/Console/GravCommand.php
------ -----------------------------------------------------------
29 Return type mixed of method
Grav\Console\GravCommand::execute() is not covariant with
return type int of method
Symfony\Component\Console\Command\Command::execute().
------ -----------------------------------------------------------
------ -----------------------------------------------------------
Line src/Grav/Framework/Acl/RecursiveActionIterator.php
------ -----------------------------------------------------------
62 Unsafe usage of new static().
🪪 new.static
💡 See:
https://phpstan.org/blog/solving-phpstan-error-unsafe-usa
ge-of-new-static
------ -----------------------------------------------------------
------ ----------------------------------------------------------
Line src/Grav/Framework/Cache/CacheTrait.php (in context of
class Grav\Framework\Cache\AbstractCache)
------ ----------------------------------------------------------
87 Return type mixed of method
Grav\Framework\Cache\AbstractCache::get() is not
covariant with return type mixed of method
Psr\SimpleCache\CacheInterface::get().
102 Return type mixed of method
Grav\Framework\Cache\AbstractCache::set() is not
covariant with return type bool of method
Psr\SimpleCache\CacheInterface::set().
117 Return type mixed of method
Grav\Framework\Cache\AbstractCache::delete() is not
covariant with return type bool of method
Psr\SimpleCache\CacheInterface::delete().
127 Return type mixed of method
Grav\Framework\Cache\AbstractCache::clear() is not
covariant with return type bool of method
Psr\SimpleCache\CacheInterface::clear().
138 Return type mixed of method
Grav\Framework\Cache\AbstractCache::getMultiple() is not
covariant with return type iterable of method
Psr\SimpleCache\CacheInterface::getMultiple().
181 Return type mixed of method
Grav\Framework\Cache\AbstractCache::setMultiple() is not
covariant with return type bool of method
Psr\SimpleCache\CacheInterface::setMultiple().
214 Return type mixed of method
Grav\Framework\Cache\AbstractCache::deleteMultiple() is
not covariant with return type bool of method
Psr\SimpleCache\CacheInterface::deleteMultiple().
242 Return type mixed of method
Grav\Framework\Cache\AbstractCache::has() is not
covariant with return type bool of method
Psr\SimpleCache\CacheInterface::has().
------ ----------------------------------------------------------
------ ----------------------------------------------------------
Line src/Grav/Framework/Collection/AbstractFileCollection.php
------ ----------------------------------------------------------
95 No error to ignore is reported on line 95.
------ ----------------------------------------------------------
------ -----------------------------------------------------------
Line src/Grav/Framework/Collection/AbstractIndexCollection.php
------ -----------------------------------------------------------
154 No error to ignore is reported on line 154.
168 No error to ignore is reported on line 168.
185 No error to ignore is reported on line 185.
201 No error to ignore is reported on line 201.
507 Unsafe usage of new static().
🪪 new.static
💡 See:
https://phpstan.org/blog/solving-phpstan-error-unsafe-usa
ge-of-new-static
------ -----------------------------------------------------------
------ -----------------------------------------------------------
Line src/Grav/Framework/Collection/AbstractLazyCollection.php
------ -----------------------------------------------------------
29 Property
Grav\Framework\Collection\AbstractLazyCollection::$collec
tion overriding property
Doctrine\Common\Collections\AbstractLazyCollection<TKey o
f (int|string),T>::$collection (Doctrine\Common\Collectio
ns\Collection|null) should also have native type
Doctrine\Common\Collections\Collection|null.
------ -----------------------------------------------------------
------ -----------------------------------------------------------
Line src/Grav/Framework/Contracts/Relationships/RelationshipIn
terface.php
------ -----------------------------------------------------------
80 Return type iterable of method
Grav\Framework\Contracts\Relationships\RelationshipInterf
ace::getIterator() is not covariant with tentative return
type Traversable of method IteratorAggregate<string,T of
Grav\Framework\Contracts\Object\IdentifierInterface>::get
Iterator().
💡 Make it covariant, or use the #[\ReturnTypeWillChange]
attribute to temporarily suppress the error.
------ -----------------------------------------------------------
------ -----------------------------------------------------------
Line src/Grav/Framework/Filesystem/Filesystem.php
------ -----------------------------------------------------------
51 Unsafe usage of new static().
🪪 new.static
💡 See:
https://phpstan.org/blog/solving-phpstan-error-unsafe-usa
ge-of-new-static
252 No error to ignore is reported on line 252.
------ -----------------------------------------------------------
------ ---------------------------------------------
Line src/Grav/Framework/Flex/FlexCollection.php
------ ---------------------------------------------
102 No error to ignore is reported on line 102.
------ ---------------------------------------------
------ -----------------------------------------------------------
Line src/Grav/Framework/Flex/FlexIdentifier.php
------ -----------------------------------------------------------
27 Unsafe usage of new static().
🪪 new.static
💡 See:
https://phpstan.org/blog/solving-phpstan-error-unsafe-usa
ge-of-new-static
------ -----------------------------------------------------------
------ ----------------------------------------------------------
Line src/Grav/Framework/Flex/FlexIndex.php
------ ----------------------------------------------------------
109 No error to ignore is reported on line 109.
934 Method Grav\Framework\Flex\FlexIndex::reduce() should
return TInitial|TReturn but return statement is missing.
🪪 return.missing
------ ----------------------------------------------------------
------ -----------------------------------------------------------
Line src/Grav/Framework/Form/FormFlashFile.php
------ -----------------------------------------------------------
62 Return type mixed of method
Grav\Framework\Form\FormFlashFile::getStream() is not
covariant with return type
Psr\Http\Message\StreamInterface of method
Psr\Http\Message\UploadedFileInterface::getStream().
83 Return type mixed of method
Grav\Framework\Form\FormFlashFile::moveTo() is not
covariant with return type void of method
Psr\Http\Message\UploadedFileInterface::moveTo().
123 Return type mixed of method
Grav\Framework\Form\FormFlashFile::getSize() is not
covariant with return type int|null of method
Psr\Http\Message\UploadedFileInterface::getSize().
131 Return type mixed of method
Grav\Framework\Form\FormFlashFile::getError() is not
covariant with return type int of method
Psr\Http\Message\UploadedFileInterface::getError().
139 Return type mixed of method
Grav\Framework\Form\FormFlashFile::getClientFilename() is
not covariant with return type string|null of method
Psr\Http\Message\UploadedFileInterface::getClientFilename
().
147 Return type mixed of method
Grav\Framework\Form\FormFlashFile::getClientMediaType()
is not covariant with return type string|null of method
Psr\Http\Message\UploadedFileInterface::getClientMediaTyp
e().
------ -----------------------------------------------------------
------ -----------------------------------------------------------
Line src/Grav/Framework/Logger/Processors/UserProcessor.php
------ -----------------------------------------------------------
24 Parameter #1 $record (array) of method
Grav\Framework\Logger\Processors\UserProcessor::__invoke(
) is not contravariant with parameter #1 $record
(Monolog\LogRecord) of method
Monolog\Processor\ProcessorInterface::__invoke().
------ -----------------------------------------------------------
------ -----------------------------------------------------------
Line src/Grav/Framework/Media/MediaIdentifier.php
------ -----------------------------------------------------------
30 Unsafe usage of new static().
🪪 new.static
💡 See:
https://phpstan.org/blog/solving-phpstan-error-unsafe-usa
ge-of-new-static
------ -----------------------------------------------------------
------ -----------------------------------------------------------
Line src/Grav/Framework/Media/UploadedMediaObject.php
------ -----------------------------------------------------------
36 Unsafe usage of new static().
🪪 new.static
💡 See:
https://phpstan.org/blog/solving-phpstan-error-unsafe-usa
ge-of-new-static
------ -----------------------------------------------------------
------ -----------------------------------------------------------
Line src/Grav/Framework/Mime/MimeTypes.php
------ -----------------------------------------------------------
42 Unsafe usage of new static().
🪪 new.static
💡 See:
https://phpstan.org/blog/solving-phpstan-error-unsafe-usa
ge-of-new-static
------ -----------------------------------------------------------
------ ------------------------------------------------
Line src/Grav/Framework/Object/ObjectCollection.php
------ ------------------------------------------------
96 No error to ignore is reported on line 96.
------ ------------------------------------------------
------ ---------------------------------------------
Line src/Grav/Framework/Object/ObjectIndex.php
------ ---------------------------------------------
193 No error to ignore is reported on line 193.
------ ---------------------------------------------
------ -----------------------------------------------------------
Line src/Grav/Framework/Psr7/Stream.php
------ -----------------------------------------------------------
31 Unsafe usage of new static().
🪪 new.static
💡 See:
https://phpstan.org/blog/solving-phpstan-error-unsafe-usa
ge-of-new-static
------ -----------------------------------------------------------
------ -----------------------------------------------------------
Line src/Grav/Framework/Psr7/Traits/ServerRequestDecoratorTrai
t.php (in context of class
Grav\Framework\Psr7\ServerRequest)
------ -----------------------------------------------------------
51 Return type mixed of method
Grav\Framework\Psr7\ServerRequest::getAttributes() is not
covariant with return type array of method
Psr\Http\Message\ServerRequestInterface::getAttributes().
60 Return type mixed of method
Grav\Framework\Psr7\ServerRequest::getCookieParams() is
not covariant with return type array of method
Psr\Http\Message\ServerRequestInterface::getCookieParams(
).
76 Return type mixed of method
Grav\Framework\Psr7\ServerRequest::getQueryParams() is
not covariant with return type array of method
Psr\Http\Message\ServerRequestInterface::getQueryParams()
.
84 Return type mixed of method
Grav\Framework\Psr7\ServerRequest::getServerParams() is
not covariant with return type array of method
Psr\Http\Message\ServerRequestInterface::getServerParams(
).
92 Return type mixed of method
Grav\Framework\Psr7\ServerRequest::getUploadedFiles() is
not covariant with return type array of method
Psr\Http\Message\ServerRequestInterface::getUploadedFiles
().
100 Return type mixed of method
Grav\Framework\Psr7\ServerRequest::withAttribute() is not
covariant with return type
Psr\Http\Message\ServerRequestInterface of method
Psr\Http\Message\ServerRequestInterface::withAttribute().
125 Return type mixed of method
Grav\Framework\Psr7\ServerRequest::withoutAttribute() is
not covariant with return type
Psr\Http\Message\ServerRequestInterface of method
Psr\Http\Message\ServerRequestInterface::withoutAttribute
().
136 Return type mixed of method
Grav\Framework\Psr7\ServerRequest::withCookieParams() is
not covariant with return type
Psr\Http\Message\ServerRequestInterface of method
Psr\Http\Message\ServerRequestInterface::withCookieParams
().
147 Return type mixed of method
Grav\Framework\Psr7\ServerRequest::withParsedBody() is
not covariant with return type
Psr\Http\Message\ServerRequestInterface of method
Psr\Http\Message\ServerRequestInterface::withParsedBody()
.
158 Return type mixed of method
Grav\Framework\Psr7\ServerRequest::withQueryParams() is
not covariant with return type
Psr\Http\Message\ServerRequestInterface of method
Psr\Http\Message\ServerRequestInterface::withQueryParams(
).
169 Return type mixed of method
Grav\Framework\Psr7\ServerRequest::withUploadedFiles() is
not covariant with return type
Psr\Http\Message\ServerRequestInterface of method
Psr\Http\Message\ServerRequestInterface::withUploadedFile
s().
------ -----------------------------------------------------------
------ -----------------------------------------------------------
Line src/Grav/Framework/Relationships/Relationships.php
------ -----------------------------------------------------------
107 Return type mixed of method
Grav\Framework\Relationships\Relationships::offsetSet()
is not covariant with tentative return type void of
method
ArrayAccess<string,Grav\Framework\Contracts\Relationships
\RelationshipInterface<T of Grav\Framework\Contracts\Obje
ct\IdentifierInterface, P of
Grav\Framework\Contracts\Object\IdentifierInterface>>::of
fsetSet().
💡 Make it covariant, or use the #[\ReturnTypeWillChange]
attribute to temporarily suppress the error.
116 Return type mixed of method
Grav\Framework\Relationships\Relationships::offsetUnset()
is not covariant with tentative return type void of
method
ArrayAccess<string,Grav\Framework\Contracts\Relationships
\RelationshipInterface<T of Grav\Framework\Contracts\Obje
ct\IdentifierInterface, P of
Grav\Framework\Contracts\Object\IdentifierInterface>>::of
fsetUnset().
💡 Make it covariant, or use the #[\ReturnTypeWillChange]
attribute to temporarily suppress the error.
------ -----------------------------------------------------------
------ -----------------------------------------------------------
Line src/Twig/DeferredExtension/DeferredNodeVisitorCompat.php
------ -----------------------------------------------------------
30 Parameter #1 $node (Twig_NodeInterface) of method
Twig\DeferredExtension\DeferredNodeVisitorCompat::enterNo
de() is not contravariant with parameter #1 $node
(Twig\Node\Node) of method
Twig\NodeVisitor\NodeVisitorInterface::enterNode().
30 Parameter $node of method
Twig\DeferredExtension\DeferredNodeVisitorCompat::enterNo
de() has invalid type Twig_NodeInterface.
🪪 class.notFound
46 Parameter #1 $node (Twig_NodeInterface) of method
Twig\DeferredExtension\DeferredNodeVisitorCompat::leaveNo
de() is not contravariant with parameter #1 $node
(Twig\Node\Node) of method
Twig\NodeVisitor\NodeVisitorInterface::leaveNode().
46 Parameter $node of method
Twig\DeferredExtension\DeferredNodeVisitorCompat::leaveNo
de() has invalid type Twig_NodeInterface.
🪪 class.notFound
------ -----------------------------------------------------------
[ERROR] Found 74 errors

View File

@@ -1,16 +1,21 @@
User-agent: *
Disallow: /.github/
Disallow: /.phan/
Disallow: /assets/
Disallow: /backup/
Disallow: /bin/
Disallow: /cache/
Disallow: /grav/
Disallow: /logs/
Disallow: /system/
Disallow: /vendor/
Disallow: /tests/
Disallow: /tmp/
Disallow: /user/
Disallow: /vendor/
Disallow: /webserver-configs/
Allow: /user/pages/
Allow: /user/themes/
Allow: /user/images/
Allow: /
Allow: *.css$
Allow: *.js$
Allow: /system/*.js$
Allow: /system/*.js$

View File

@@ -1,2 +1,61 @@
/** Clockwork Debugger CSS **/
.clockwork-badge{position:fixed;z-index:10;bottom:0;left:0;padding:2px 4px;background-color:#eee;border:1px solid #ccc;border-bottom:0;border-left:0;display:flex;align-items:center}.clockwork-badge:hover{width:auto}.clockwork-badge:hover:after{content:'Grav Clockwork debugger enabled. Install Clockwork Browser extension (Chrome or Firefox), open your Developer tools and then select the Clockwork tab.'}.clockwork-badge:after{margin-left:10px;font-family:Monaco,Consolas,"Lucida Console",monospace;font-size:12px;line-height:1.5;color:#666}.clockwork-badge i{display:block;float:left;height:22px;width:22px;min-width:22px;background-size:contain;background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAMAAACdt4HsAAAA/1BMVEUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeHh4AAAD///8EBAT7+/sLCwv29vYVFRUvLy/t7e3m5ubCwsKxsbE/Pz+mpqZMTEwcHBzy8vLp6emfn5+AgIA2Njbi4uLf39+rq6tzc3NWVlYhISHa2trW1tbS0tLMzMy7u7uZmZmUlJSMjIxvb29kZGRHR0c7Ozt5eXkqKiq1tbWQkJBqampbW1tSUlLHx8eHh4ckJCRDQ0M3wD42AAAAI3RSTlMA/PibTbQ0x76TVAlw4LhZLOuEYCAN9Hjx0a2ppGZEGYw97djhXHwAAATZSURBVFjDlVcHW+MwDO1eFCjj2McNOzvdpXTTXVbL/P+/5SQ7QSSX5Di1X1onfi/Sk+Q4sTDbKqWK+YuznZ2zi3wxVdqK/Zf92M1nT9gnO8rmd398GX6Z3xaoOFoiAQcx3E5efgmeSuN8F6Xg1x3G06l/wjNpMR1B0uif4EhnIuFb+0diIoFXk3IVfokisR+h52GO4JKgyjmfaMhAFNlSaPR7DpwI+lzn/E4QKIqmKIJirxCMP4izBPPZPXhgXwMBYgULw0nfg/BF5scDbslb7QeJ08yqqTEmGYoB95d4H8ETL8+n9wBqrLu6ao3bBsMwAnxISf/9BHcqxNB8Y7cWl3Zz7TAUfPrvAT6AoNEFFXvsjutL01yOuMrtBxnFXsmT/1wQHmdWAFNnI3uI48Yj0FUcHbKf62GfUfr8eeQt7Uk3mQZpZNoVRPEui5vtEz5zFEpgWnyqVBZMc6oaGNriH2hGVZ0OxEvInPeMaZWJBA7vmPbCr5jjws5HBnAUxvDMH40aCIf4G5BjRQSs8E8HFFYf8bGxgDvD55bzGhwWkoBcuIyHR/AMdaCagxXDhtL6tSqoWpd4BMnlIR+Or+rYTK/a3EAGcc6e4AWHISnWv20iCCojsHoVlQdjrMexFF2C7UMg2A2WEGWbQhXN6l3eXC6XGp4b9qxbuEB2EBGBwtocrK90cVG5mbRXm6vmx/0phq1sIAGKDgLOBiN1MrO5a9aDl+D0W6x0Ar9BCTRuIIANa90Y7LrLVRXzwVtDInCqMRWcf2bUOEAsa4wJqFowQALL9EiAtVRk8QC4OW+1pOM9jIaVASwYagyNXDj+W0NcfuZNzjtXOiL0Zzg30Llj+ptfxQs4+vBPNiL5PawFCBkgXpUaVtqGl+A8dgZHL34BcBUQrwPptToW+o37Ku+UH9eYByJIx3YkAeFnMFuGO7S5gEp7YhXxa5OOAM39RXDPXb0qmpROsswZe+twXdU55oUIZAiEv3bD1UFwIYKkmGqytPCDCwKFQCKK0yL7qtSAPX54UAbtsLuBHkb9zyLmPQSNjsSgmQwKUOIfEY8F8t4B34DvndJY9BA8tNBJq1Nev9axmaStFcQLhgYoCTo0salkIaW8OUDdWjMTR2sHPhrAFZqx6cqcKE4pl2BJJ4K6hfwvqNgAnXfKX/HU6X3Zrhnu0k7tLNZtTBRv1hkwTDBY1NzFU6doDYjJbWdQkQhWwuU7/LvhTh3SDoco4ECL4i5dwURbc8NdDZz2IwKicE8d0KIqWetLE3+lL4hvUuGSeRfVWNLfj/gpOw4smBJBkKQHCzlHGwvAj4woB1gq5NGGLSXtORBPnUQPV5/MPVkDMxbpwG7w4x0xL6Ltxka0A/4NBvV09UVk4DoSn/jl2+JQS9q9KYawisAD4CfhsZ4TH3htylsdEHARIQBusqCKyUpymycgbbkkXEXjT3z7/oKQFTFVuZD2FMJHZIDsO5x2d4aAr2jR+GLwZhtAb028/0yJ9J8dE87jQyKObcjtTXT8dH+fDuKF4/eiPwzH44wTf/yUi6wrpRIOZ9lM1EtXAifFI+CJn9+iX/t2xMQwOMth/UZbASi8btAwR9FHWSpJr75g9Oqbin3VDg+SpwlP6k6TB4ex/7JvmcJx8jydy6XPk8eFTKhyfwCgX71MSvaBHgAAAABJRU5ErkJggg==)}
.clockwork-badge {
position: fixed;
z-index: 1000; /* Increased z-index for better visibility */
bottom: 0; /* Added some spacing from the bottom */
left: 0; /* Added some spacing from the left */
padding: 5px;
background-color: #eee;
border: 1px solid #ccc;
border-bottom: 0;
border-left: 0;
display: flex;
align-items: center;
border-radius: 0 4px 0 0; /* Rounded top corners */
box-shadow: 0 2px 5px rgba(0,0,0,0.2);
font-size: 14px;
color: #333;
transition: background-color 0.3s ease;
}
.clockwork-badge:hover {
background-color: #ddd;
}
.clockwork-badge i {
display: block;
height: 24px;
width: 24px;
background-size: contain;
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAMAAACdt4HsAAAA/1BMVEUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeHh4AAAD///8EBAT7+/sLCwv29vYVFRUvLy/t7e3m5ubCwsKxsbE/Pz+mpqZMTEwcHBzy8vLp6emfn5+AgIA2Njbi4uLf39+rq6tzc3NWVlYhISHa2trW1tbS0tLMzMy7u7uZmZmUlJSMjIxvb29kZGRHR0c7Ozt5eXkqKiq1tbWQkJBqampbW1tSUlLHx8eHh4ckJCRDQ0M3wD42AAAAI3RSTlMA/PibTbQ0x76TVAlw4LhZLOuEYCAN9Hjx0a2ppGZEGYw97djhXHwAAATZSURBVFjDlVcHW+MwDO1eFCjj2McNOzvdpXTTXVbL/P+/5SQ7QSSX5Di1X1onfi/Sk+Q4sTDbKqWK+YuznZ2zi3wxVdqK/Zf92M1nT9gnO8rmd398GX6Z3xaoOFoiAQcx3E5efgmeSuN8F6Xg1x3G06l/wjNpMR1B0uif4EhnIuFb+0diIoFXk3IVfokisR+h52GO4JKgyjmfaMhAFNlSaPR7DpwI+lzn/E4QKIqmKIJirxCMP4izBPPZPXhgXwMBYgULw0nfg/BF5scDbslb7QeJ08yqqTEmGYoB95d4H8ETL8+n9wBqrLu6ao3bBsMwAnxISf/9BHcqxNB8Y7cWl3Zz7TAUfPrvAT6AoNEFFXvsjutL01yOuMrtBxnFXsmT/1wQHmdWAFNnI3uI48Yj0FUcHbKf62GfUfr8eeQt7Uk3mQZpZNoVRPEui5vtEz5zFEpgWnyqVBZMc6oaGNriH2hGVZ0OxEvInPeMaZWJBA7vmPbCr5jjws5HBnAUxvDMH40aCIf4G5BjRQSs8E8HFFYf8bGxgDvD55bzGhwWkoBcuIyHR/AMdaCagxXDhtL6tSqoWpd4BMnlIR+Or+rYTK/a3EAGcc6e4AWHISnWv20iCCojsHoVlQdjrMexFF2C7UMg2A2WEGWbQhXN6l3eXC6XGp4b9qxbuEB2EBGBwtocrK90cVG5mbRXm6vmx/0phq1sIAGKDgLOBiN1MrO5a9aDl+D0W6x0Ar9BCTRuIIANa90Y7LrLVRXzwVtDInCqMRWcf2bUOEAsa4wJqFowQALL9EiAtVRk8QC4OW+1pOM9jIaVASwYagyNXDj+W0NcfuZNzjtXOiL0Zzg30Llj+ptfxQs4+vBPNiL5PawFCBkgXpUaVtqGl+A8dgZHL34BcBUQrwPptToW+o37Ku+UH9eYByJIx3YkAeFnMFuGO7S5gEp7YhXxa5OOAM39RXDPXb0qmpROsswZe+twXdU55oUIZAiEv3bD1UFwIYKkmGqytPCDCwKFQCKK0yL7qtSAPX54UAbtsLuBHkb9zyLmPQSNjsSgmQwKUOIfEY8F8t4B34DvndJY9BA8tNBJq1Nev9axmaStFcQLhgYoCTo0salkIaW8OUDdWjMTR2sHPhrAFZqx6cqcKE4pl2BJJ4K6hfwvqNgAnXfKX/HU6X3Zrhnu0k7tLNZtTBRv1hkwTDBY1NzFU6doDYjJbWdQkQhWwuU7/LvhTh3SDoco4ECL4i5dwURbc8NdDZz2IwKicE8d0KIqWetLE3+lL4hvUuGSeRfVWNLfj/gpOw4smBJBkKQHCzlHGwvAj4woB1gq5NGGLSXtORBPnUQPV5/MPVkDMxbpwG7w4x0xL6Ltxka0A/4NBvV09UVk4DoSn/jl2+JQS9q9KYawisAD4CfhsZ4TH3htylsdEHARIQBusqCKyUpymycgbbkkXEXjT3z7/oKQFTFVuZD2FMJHZIDsO5x2d4aAr2jR+GLwZhtAb028/0yJ9J8dE87jQyKObcjtTXT8dH+fDuKF4/eiPwzH44wTf/yUi6wrpRIOZ9lM1EtXAifFI+CJn9+iX/t2xMQwOMth/UZbASi8btAwR9FHWSpJr75g9Oqbin3VDg+SpwlP6k6TB4ex/7JvmcJx8jydy6XPk8eFTKhyfwCgX71MSvaBHgAAAABJRU5ErkJggg==);
}
.clockwork-badge .tooltip {
display: none; /* Hidden by default */
position: absolute;
bottom: 35px; /* Position above the badge */
left: 0;
width: 450px;
padding: 20px;
background-color: #fff;
border: 1px solid #ccc;
border-radius: 4px;
font-size: 16px;
color: #666;
line-height: 1.5;
box-shadow: 0 2px 8px rgba(0,0,0,0.2);
z-index: 1001; /* Ensure it appears above other elements */
}
.clockwork-badge:hover .tooltip {
display: block; /* Show tooltip on hover */
}
.clockwork-badge .tooltip a {
color: #007BFF;
text-decoration: none;
}
.clockwork-badge .tooltip a:hover {
text-decoration: underline;
}

View File

@@ -1,3 +1,37 @@
/** Clockwork Debugger JS **/
document.addEventListener("DOMContentLoaded",function () {
var e=document.createElement("div");e.appendChild(document.createElement("i")),e.className="clockwork-badge",document.body.appendChild(e)});
document.addEventListener("DOMContentLoaded", function () {
// Directly select the script tag by its id
var currentScript = document.getElementById('clockwork-script');
if (!currentScript) {
console.error("Clockwork Debugger: Script tag with id 'clockwork-script' not found.");
return;
}
var route = currentScript.getAttribute('data-route') || '/clockwork'; // Default route if not specified
// Debugging: Log the route to verify
console.log("Clockwork Debugger Route:", route);
// Create the badge container
var badge = document.createElement("div");
badge.className = "clockwork-badge";
badge.setAttribute('aria-label', 'Clockwork Debugger Enabled');
badge.setAttribute('role', 'button');
// Create the icon element
var icon = document.createElement("i");
badge.appendChild(icon);
// Create the tooltip element
var tooltip = document.createElement("div");
tooltip.className = "tooltip";
tooltip.innerHTML = `
<b>Grav Clockwork Debugger Enabled.</b><br>
Install the <b>Clockwork Browser extension</b> (Chrome or Firefox) or use the <b>"Clockwork Web"</b> Grav plugin to <a href="${route}" target="_blank">View Debug Info 🔗</a>.
`;
badge.appendChild(tooltip);
// Append the badge to the body
document.body.appendChild(badge);
});

View File

@@ -1,70 +1,5 @@
div.phpdebugbar {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
div.phpdebugbar a.phpdebugbar-restore-btn::after {
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAMAAACdt4HsAAAA/1BMVEUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeHh4AAAD///8EBAT7+/sLCwv29vYVFRUvLy/t7e3m5ubCwsKxsbE/Pz+mpqZMTEwcHBzy8vLp6emfn5+AgIA2Njbi4uLf39+rq6tzc3NWVlYhISHa2trW1tbS0tLMzMy7u7uZmZmUlJSMjIxvb29kZGRHR0c7Ozt5eXkqKiq1tbWQkJBqampbW1tSUlLHx8eHh4ckJCRDQ0M3wD42AAAAI3RSTlMA/PibTbQ0x76TVAlw4LhZLOuEYCAN9Hjx0a2ppGZEGYw97djhXHwAAATZSURBVFjDlVcHW+MwDO1eFCjj2McNOzvdpXTTXVbL/P+/5SQ7QSSX5Di1X1onfi/Sk+Q4sTDbKqWK+YuznZ2zi3wxVdqK/Zf92M1nT9gnO8rmd398GX6Z3xaoOFoiAQcx3E5efgmeSuN8F6Xg1x3G06l/wjNpMR1B0uif4EhnIuFb+0diIoFXk3IVfokisR+h52GO4JKgyjmfaMhAFNlSaPR7DpwI+lzn/E4QKIqmKIJirxCMP4izBPPZPXhgXwMBYgULw0nfg/BF5scDbslb7QeJ08yqqTEmGYoB95d4H8ETL8+n9wBqrLu6ao3bBsMwAnxISf/9BHcqxNB8Y7cWl3Zz7TAUfPrvAT6AoNEFFXvsjutL01yOuMrtBxnFXsmT/1wQHmdWAFNnI3uI48Yj0FUcHbKf62GfUfr8eeQt7Uk3mQZpZNoVRPEui5vtEz5zFEpgWnyqVBZMc6oaGNriH2hGVZ0OxEvInPeMaZWJBA7vmPbCr5jjws5HBnAUxvDMH40aCIf4G5BjRQSs8E8HFFYf8bGxgDvD55bzGhwWkoBcuIyHR/AMdaCagxXDhtL6tSqoWpd4BMnlIR+Or+rYTK/a3EAGcc6e4AWHISnWv20iCCojsHoVlQdjrMexFF2C7UMg2A2WEGWbQhXN6l3eXC6XGp4b9qxbuEB2EBGBwtocrK90cVG5mbRXm6vmx/0phq1sIAGKDgLOBiN1MrO5a9aDl+D0W6x0Ar9BCTRuIIANa90Y7LrLVRXzwVtDInCqMRWcf2bUOEAsa4wJqFowQALL9EiAtVRk8QC4OW+1pOM9jIaVASwYagyNXDj+W0NcfuZNzjtXOiL0Zzg30Llj+ptfxQs4+vBPNiL5PawFCBkgXpUaVtqGl+A8dgZHL34BcBUQrwPptToW+o37Ku+UH9eYByJIx3YkAeFnMFuGO7S5gEp7YhXxa5OOAM39RXDPXb0qmpROsswZe+twXdU55oUIZAiEv3bD1UFwIYKkmGqytPCDCwKFQCKK0yL7qtSAPX54UAbtsLuBHkb9zyLmPQSNjsSgmQwKUOIfEY8F8t4B34DvndJY9BA8tNBJq1Nev9axmaStFcQLhgYoCTo0salkIaW8OUDdWjMTR2sHPhrAFZqx6cqcKE4pl2BJJ4K6hfwvqNgAnXfKX/HU6X3Zrhnu0k7tLNZtTBRv1hkwTDBY1NzFU6doDYjJbWdQkQhWwuU7/LvhTh3SDoco4ECL4i5dwURbc8NdDZz2IwKicE8d0KIqWetLE3+lL4hvUuGSeRfVWNLfj/gpOw4smBJBkKQHCzlHGwvAj4woB1gq5NGGLSXtORBPnUQPV5/MPVkDMxbpwG7w4x0xL6Ltxka0A/4NBvV09UVk4DoSn/jl2+JQS9q9KYawisAD4CfhsZ4TH3htylsdEHARIQBusqCKyUpymycgbbkkXEXjT3z7/oKQFTFVuZD2FMJHZIDsO5x2d4aAr2jR+GLwZhtAb028/0yJ9J8dE87jQyKObcjtTXT8dH+fDuKF4/eiPwzH44wTf/yUi6wrpRIOZ9lM1EtXAifFI+CJn9+iX/t2xMQwOMth/UZbASi8btAwR9FHWSpJr75g9Oqbin3VDg+SpwlP6k6TB4ex/7JvmcJx8jydy6XPk8eFTKhyfwCgX71MSvaBHgAAAABJRU5ErkJggg==) !important;
width: 32px;
}
.phpdebugbar pre {
padding: 1rem;
}
.phpdebugbar div.phpdebugbar-header > div > * {
padding: 5px 15px;
}
.phpdebugbar div.phpdebugbar-header > div.phpdebugbar-header-right > * {
padding: 5px 8px;
}
.phpdebugbar div.phpdebugbar-header, .phpdebugbar a.phpdebugbar-restore-btn {
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAMAAACdt4HsAAAA/1BMVEUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeHh4AAAD///8EBAT7+/sLCwv29vYVFRUvLy/t7e3m5ubCwsKxsbE/Pz+mpqZMTEwcHBzy8vLp6emfn5+AgIA2Njbi4uLf39+rq6tzc3NWVlYhISHa2trW1tbS0tLMzMy7u7uZmZmUlJSMjIxvb29kZGRHR0c7Ozt5eXkqKiq1tbWQkJBqampbW1tSUlLHx8eHh4ckJCRDQ0M3wD42AAAAI3RSTlMA/PibTbQ0x76TVAlw4LhZLOuEYCAN9Hjx0a2ppGZEGYw97djhXHwAAATZSURBVFjDlVcHW+MwDO1eFCjj2McNOzvdpXTTXVbL/P+/5SQ7QSSX5Di1X1onfi/Sk+Q4sTDbKqWK+YuznZ2zi3wxVdqK/Zf92M1nT9gnO8rmd398GX6Z3xaoOFoiAQcx3E5efgmeSuN8F6Xg1x3G06l/wjNpMR1B0uif4EhnIuFb+0diIoFXk3IVfokisR+h52GO4JKgyjmfaMhAFNlSaPR7DpwI+lzn/E4QKIqmKIJirxCMP4izBPPZPXhgXwMBYgULw0nfg/BF5scDbslb7QeJ08yqqTEmGYoB95d4H8ETL8+n9wBqrLu6ao3bBsMwAnxISf/9BHcqxNB8Y7cWl3Zz7TAUfPrvAT6AoNEFFXvsjutL01yOuMrtBxnFXsmT/1wQHmdWAFNnI3uI48Yj0FUcHbKf62GfUfr8eeQt7Uk3mQZpZNoVRPEui5vtEz5zFEpgWnyqVBZMc6oaGNriH2hGVZ0OxEvInPeMaZWJBA7vmPbCr5jjws5HBnAUxvDMH40aCIf4G5BjRQSs8E8HFFYf8bGxgDvD55bzGhwWkoBcuIyHR/AMdaCagxXDhtL6tSqoWpd4BMnlIR+Or+rYTK/a3EAGcc6e4AWHISnWv20iCCojsHoVlQdjrMexFF2C7UMg2A2WEGWbQhXN6l3eXC6XGp4b9qxbuEB2EBGBwtocrK90cVG5mbRXm6vmx/0phq1sIAGKDgLOBiN1MrO5a9aDl+D0W6x0Ar9BCTRuIIANa90Y7LrLVRXzwVtDInCqMRWcf2bUOEAsa4wJqFowQALL9EiAtVRk8QC4OW+1pOM9jIaVASwYagyNXDj+W0NcfuZNzjtXOiL0Zzg30Llj+ptfxQs4+vBPNiL5PawFCBkgXpUaVtqGl+A8dgZHL34BcBUQrwPptToW+o37Ku+UH9eYByJIx3YkAeFnMFuGO7S5gEp7YhXxa5OOAM39RXDPXb0qmpROsswZe+twXdU55oUIZAiEv3bD1UFwIYKkmGqytPCDCwKFQCKK0yL7qtSAPX54UAbtsLuBHkb9zyLmPQSNjsSgmQwKUOIfEY8F8t4B34DvndJY9BA8tNBJq1Nev9axmaStFcQLhgYoCTo0salkIaW8OUDdWjMTR2sHPhrAFZqx6cqcKE4pl2BJJ4K6hfwvqNgAnXfKX/HU6X3Zrhnu0k7tLNZtTBRv1hkwTDBY1NzFU6doDYjJbWdQkQhWwuU7/LvhTh3SDoco4ECL4i5dwURbc8NdDZz2IwKicE8d0KIqWetLE3+lL4hvUuGSeRfVWNLfj/gpOw4smBJBkKQHCzlHGwvAj4woB1gq5NGGLSXtORBPnUQPV5/MPVkDMxbpwG7w4x0xL6Ltxka0A/4NBvV09UVk4DoSn/jl2+JQS9q9KYawisAD4CfhsZ4TH3htylsdEHARIQBusqCKyUpymycgbbkkXEXjT3z7/oKQFTFVuZD2FMJHZIDsO5x2d4aAr2jR+GLwZhtAb028/0yJ9J8dE87jQyKObcjtTXT8dH+fDuKF4/eiPwzH44wTf/yUi6wrpRIOZ9lM1EtXAifFI+CJn9+iX/t2xMQwOMth/UZbASi8btAwR9FHWSpJr75g9Oqbin3VDg+SpwlP6k6TB4ex/7JvmcJx8jydy6XPk8eFTKhyfwCgX71MSvaBHgAAAABJRU5ErkJggg==);
}
.phpdebugbar a.phpdebugbar-restore-btn {
width: 13px;
}
.phpdebugbar a.phpdebugbar-tab.phpdebugbar-active {
background: #3DB9EC;
color: #fff;
margin-top: -1px;
padding-top: 6px;
}
.phpdebugbar .phpdebugbar-widgets-toolbar {
border-top: 1px solid #ddd;
padding-left: 5px;
padding-right: 2px;
padding-top: 2px;
background-color: #fafafa !important;
width: auto !important;
left: 0;
right: 0;
}
.phpdebugbar .phpdebugbar-widgets-toolbar input {
background: transparent !important;
}
.phpdebugbar .phpdebugbar-widgets-toolbar .phpdebugbar-widgets-filter {
}
.phpdebugbar input[type=text] {
padding: 0;
display: inline;
}
.phpdebugbar dl.phpdebugbar-widgets-varlist, ul.phpdebugbar-widgets-timeline li span.phpdebugbar-widgets-label {
font-family: "DejaVu Sans Mono", Menlo, Monaco, Consolas, Courier, monospace;
font-size: 12px;
}
ul.phpdebugbar-widgets-timeline li span.phpdebugbar-widgets-label {
text-shadow: -1px -1px 0 #fff, 1px -1px 0 #fff, -1px 1px 0 #fff, 1px 1px 0 #fff;
top: 0;
}
.phpdebugbar pre, .phpdebugbar code {
margin: 0;
font-size: 14px;
}

File diff suppressed because one or more lines are too long

View File

@@ -4,74 +4,788 @@ form:
validation: loose
fields:
scheduler_tabs:
type: tabs
active: 1
status_title:
type: section
title: PLUGIN_ADMIN.SCHEDULER_STATUS
underline: true
fields:
status_tab:
type: tab
title: PLUGIN_ADMIN.SCHEDULER_STATUS
status:
type: cronstatus
validate:
type: commalist
fields:
status_title:
type: section
title: PLUGIN_ADMIN.SCHEDULER_STATUS
underline: true
jobs_title:
type: section
title: PLUGIN_ADMIN.SCHEDULER_JOBS
underline: true
status:
type: cronstatus
validate:
type: commalist
webhook_status_override:
type: display
label:
content: |
<script>
(function() {
function updateSchedulerStatus() {
// Find all notice bars
var notices = document.querySelectorAll('.notice');
var webhookStatusChecked = false;
// Check for modern scheduler and webhook settings
fetch(window.location.origin + '/grav-editor-pro/scheduler/health')
.then(response => response.json())
.then(data => {
if (data.webhook_enabled) {
notices.forEach(function(notice) {
if (notice.textContent.includes('Not Enabled for user:')) {
// This is the cron status notice - replace it
notice.className = 'notice info';
notice.innerHTML = '<i class="fa fa-fw fa-check-circle"></i> <strong>Webhook Active</strong> - Scheduler can be triggered via webhook. Cron is not configured.';
}
});
// Also update the main status if it exists
var statusDiv = document.querySelector('.cronstatus-status');
if (statusDiv && statusDiv.textContent.includes('Not Enabled')) {
statusDiv.className = 'cronstatus-status success';
statusDiv.innerHTML = '<i class="fa fa-fw fa-check"></i> Webhook Ready';
}
}
})
.catch(error => {
console.log('Webhook status check failed:', error);
});
}
// Run on page load
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', updateSchedulerStatus);
} else {
updateSchedulerStatus();
}
// Also run after a short delay to catch any late-rendered elements
setTimeout(updateSchedulerStatus, 500);
})();
</script>
markdown: false
status_enhanced:
type: display
label:
content: |
<script>
document.addEventListener('DOMContentLoaded', function() {
// Check if webhook is enabled
var webhookEnabled = document.querySelector('[name="data[scheduler][modern][webhook][enabled]"]:checked');
var statusDiv = document.querySelector('.cronstatus-status');
// Also find the parent notice bar
var noticeBar = document.querySelector('.notice.alert');
if (statusDiv) {
var currentStatus = statusDiv.textContent || statusDiv.innerText;
var cronReady = currentStatus.includes('Ready');
var cronNotEnabled = currentStatus.includes('Not Enabled');
// Check if scheduler-webhook plugin exists
var webhookPluginInstalled = false;
fetch(window.location.origin + '/grav-editor-pro/scheduler/health')
.then(response => response.json())
.then(data => {
webhookPluginInstalled = true;
updateStatusDisplay(data);
})
.catch(error => {
updateStatusDisplay(null);
});
function updateStatusDisplay(healthData) {
var isWebhookEnabled = webhookEnabled && webhookEnabled.value == '1';
var isWebhookReady = webhookPluginInstalled && isWebhookEnabled && healthData && healthData.webhook_enabled;
// Update the main status text
var mainStatusText = '';
var mainStatusClass = '';
if (cronReady && isWebhookReady) {
mainStatusText = 'Cron and Webhook Ready';
mainStatusClass = 'success';
} else if (cronReady) {
mainStatusText = 'Cron Ready';
mainStatusClass = 'success';
} else if (isWebhookReady) {
mainStatusText = 'Webhook Ready (No Cron)';
mainStatusClass = 'success'; // Changed from warning to success
} else if (cronNotEnabled && !isWebhookReady) {
mainStatusText = 'Not Configured';
mainStatusClass = 'error';
} else {
mainStatusText = 'Configuration Pending';
mainStatusClass = 'warning';
}
// Update the notice bar if webhooks are ready
if (noticeBar && isWebhookReady) {
// Change from error (red) to success (green) or info (blue)
noticeBar.classList.remove('alert');
noticeBar.classList.add('info');
var noticeIcon = noticeBar.querySelector('i.fa');
if (noticeIcon) {
noticeIcon.classList.remove('fa-times-circle');
noticeIcon.classList.add('fa-check-circle');
}
var noticeText = noticeBar.querySelector('strong') || noticeBar;
var username = noticeText.textContent.match(/user:\s*(\w+)/);
if (username) {
noticeText.innerHTML = 'Webhook Ready for user: <b>' + username[1] + '</b> (Cron not configured)';
} else {
noticeText.innerHTML = mainStatusText;
}
}
// Update the main status div
if (statusDiv) {
statusDiv.innerHTML = '<i class="fa fa-fw fa-' +
(mainStatusClass === 'success' ? 'check' : mainStatusClass === 'warning' ? 'exclamation' : 'times') +
'"></i> ' + mainStatusText;
statusDiv.className = 'cronstatus-status ' + mainStatusClass;
}
// Update install instructions button/content
var installButton = document.querySelector('.cronstatus-install-button');
var installDiv = document.querySelector('.cronstatus-install');
if (installDiv) {
var installHtml = '<div class="alert alert-info">';
installHtml += '<h4>Setup Instructions:</h4>';
var hasInstructions = false;
// Cron setup
if (!cronReady) {
installHtml += '<p><strong>Option 1: Traditional Cron</strong><br>';
installHtml += 'Run: <code>bin/grav scheduler --install</code><br>';
installHtml += 'This will add a cron job that runs every minute.</p>';
hasInstructions = true;
}
// Webhook setup
if (!webhookPluginInstalled) {
installHtml += '<p><strong>Option 2: Webhook Support</strong><br>';
installHtml += '1. Install plugin: <code>bin/gpm install scheduler-webhook</code><br>';
installHtml += '2. Configure webhook token in Advanced Features tab<br>';
installHtml += '3. Use webhook URL in your CI/CD or cloud scheduler</p>';
hasInstructions = true;
} else if (!isWebhookEnabled) {
installHtml += '<p><strong>Webhook Plugin Installed</strong><br>';
installHtml += 'Enable webhooks in Advanced Features tab and set a secure token.</p>';
hasInstructions = true;
} else if (isWebhookReady) {
installHtml += '<p><strong>✅ Webhook is Active!</strong><br>';
installHtml += 'Trigger URL: <code>' + window.location.origin + '/grav-editor-pro/scheduler/webhook</code><br>';
installHtml += 'Use with Authorization header: <code>Bearer YOUR_TOKEN</code></p>';
if (!cronReady) {
installHtml += '<p class="text-muted"><small>Note: No cron job configured. Scheduler runs only via webhook triggers.</small></p>';
}
}
if (!hasInstructions && cronReady) {
installHtml += '<p><strong>✅ Cron is configured and ready!</strong><br>';
installHtml += 'The scheduler runs automatically every minute via system cron.</p>';
}
installHtml += '</div>';
installDiv.innerHTML = installHtml;
// Update button text based on status
if (installButton) {
if (cronReady && isWebhookReady) {
installButton.innerHTML = '<i class="fa fa-info-circle"></i> Configuration Details';
} else if (cronReady || isWebhookReady) {
installButton.innerHTML = '<i class="fa fa-plus-circle"></i> Add More Triggers';
} else {
installButton.innerHTML = '<i class="fa fa-exclamation-triangle"></i> Install Instructions';
}
}
}
}
}
});
</script>
custom_jobs:
type: list
style: vertical
label:
classes: cron-job-list compact
key: id
fields:
.id:
type: key
label: ID
placeholder: 'process-name'
validate:
required: true
pattern: '[a-zа-я0-9_\-]+'
max: 20
message: 'ID must be lowercase with dashes/underscores only and less than 20 characters'
.command:
type: text
label: PLUGIN_ADMIN.COMMAND
placeholder: 'ls'
validate:
required: true
.args:
type: text
label: PLUGIN_ADMIN.EXTRA_ARGUMENTS
placeholder: '-lah'
.at:
type: text
wrapper_classes: cron-selector
label: PLUGIN_ADMIN.SCHEDULER_RUNAT
help: PLUGIN_ADMIN.SCHEDULER_RUNAT_HELP
placeholder: '* * * * *'
validate:
required: true
.output:
type: text
label: PLUGIN_ADMIN.SCHEDULER_OUTPUT
help: PLUGIN_ADMIN.SCHEDULER_OUTPUT_HELP
placeholder: 'logs/ls-cron.out'
.output_mode:
type: select
label: PLUGIN_ADMIN.SCHEDULER_OUTPUT_TYPE
help: PLUGIN_ADMIN.SCHEDULER_OUTPUT_TYPE_HELP
default: append
options:
append: Append
overwrite: Overwrite
.email:
type: text
label: PLUGIN_ADMIN.SCHEDULER_EMAIL
help: PLUGIN_ADMIN.SCHEDULER_EMAIL_HELP
placeholder: 'notifications@yoursite.com'
modern_health:
type: display
label: Health Status
content: |
<div id="scheduler-health-status">
<div class="text-muted">Checking health...</div>
</div>
<script>
(function() {
function loadHealthStatus() {
fetch(window.location.origin + '/grav-editor-pro/scheduler/health')
.then(response => response.json())
.then(data => {
var statusEl = document.getElementById('scheduler-health-status');
if (!statusEl) return;
// Modern card-based layout
var statusColor = '#6c757d';
var statusLabel = data.status || 'unknown';
if (data.status === 'healthy') statusColor = '#28a745';
else if (data.status === 'warning') statusColor = '#ffc107';
else if (data.status === 'critical') statusColor = '#dc3545';
var html = '<div style="display: flex; flex-direction: column; gap: 1rem;">';
// Status card
html += '<div style="display: flex; align-items: center; justify-content: space-between; padding: 0.75rem 1rem; background: linear-gradient(135deg, #f8f9fa 0%, #fff 100%); border-radius: 6px; border: 1px solid #e9ecef; box-shadow: 0 1px 3px rgba(0,0,0,0.05);">';
html += '<span style="font-weight: 500; color: #495057;">Status:</span>';
html += '<span style="background: ' + statusColor + '; color: white; padding: 0.375rem 0.75rem; font-size: 0.875rem; font-weight: 500; border-radius: 4px; text-transform: uppercase; letter-spacing: 0.025em;">' + statusLabel + '</span>';
html += '</div>';
// Info grid
html += '<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 0.75rem;">';
// Last run card
html += '<div style="background: white; border: 1px solid #e9ecef; border-radius: 6px; padding: 0.75rem; box-shadow: 0 1px 2px rgba(0,0,0,0.03);">';
html += '<div style="color: #6c757d; font-size: 0.75rem; text-transform: uppercase; letter-spacing: 0.05em; margin-bottom: 0.25rem;">Last Run</div>';
if (data.last_run) {
var age = data.last_run_age;
var ageText = 'just now';
if (age > 86400) {
ageText = Math.floor(age / 86400) + ' day(s) ago';
} else if (age > 3600) {
ageText = Math.floor(age / 3600) + ' hour(s) ago';
} else if (age > 60) {
ageText = Math.floor(age / 60) + ' minute(s) ago';
} else if (age > 0) {
ageText = age + ' second(s) ago';
}
html += '<div style="font-size: 1rem; color: #212529; font-weight: 500;">' + ageText + '</div>';
} else {
html += '<div style="font-size: 1rem; color: #6c757d;">Never</div>';
}
html += '</div>';
// Jobs count card
html += '<div style="background: white; border: 1px solid #e9ecef; border-radius: 6px; padding: 0.75rem; box-shadow: 0 1px 2px rgba(0,0,0,0.03);">';
html += '<div style="color: #6c757d; font-size: 0.75rem; text-transform: uppercase; letter-spacing: 0.05em; margin-bottom: 0.25rem;">Scheduled Jobs</div>';
html += '<div style="font-size: 1rem; color: #212529; font-weight: 500;">' + (data.scheduled_jobs || 0) + '</div>';
html += '</div>';
html += '</div>'; // Close grid
// Additional info if available
if (data.modern_features && data.queue_size !== undefined) {
html += '<div style="background: white; border: 1px solid #e9ecef; border-radius: 6px; padding: 0.75rem; box-shadow: 0 1px 2px rgba(0,0,0,0.03);">';
html += '<span style="color: #6c757d; font-size: 0.875rem;">Queue Size: </span>';
html += '<span style="font-weight: 500;">' + data.queue_size + '</span>';
html += '</div>';
}
// Failed jobs warning
if (data.failed_jobs_24h > 0) {
html += '<div style="background: #fff5f5; border: 1px solid #feb2b2; border-radius: 6px; padding: 0.75rem; color: #c53030;">';
html += '<strong>⚠️ Failed Jobs (24h):</strong> ' + data.failed_jobs_24h;
html += '</div>';
}
html += '</div>'; // Close main container
statusEl.innerHTML = html;
})
.catch(error => {
var statusEl = document.getElementById('scheduler-health-status');
if (statusEl) {
statusEl.innerHTML = '<div class="alert alert-warning">Unable to fetch health status. Ensure scheduler-webhook plugin is installed.</div>';
}
});
}
// Load on page ready
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', loadHealthStatus);
} else {
loadHealthStatus();
}
// Refresh every 30 seconds
setInterval(loadHealthStatus, 30000);
})();
</script>
markdown: false
trigger_methods:
type: display
label: Active Triggers
content: |
<div id="scheduler-triggers">
<div class="text-muted">Checking triggers...</div>
</div>
<script>
(function() {
function loadTriggers() {
// Check cron status from the main status field
var cronReady = false;
var statusDiv = document.querySelector('.cronstatus-status');
if (statusDiv) {
var statusText = statusDiv.textContent || statusDiv.innerText;
cronReady = statusText.includes('Ready');
}
// Check webhook status
fetch(window.location.origin + '/grav-editor-pro/scheduler/health')
.then(response => response.json())
.then(data => {
var triggersEl = document.getElementById('scheduler-triggers');
if (!triggersEl) return;
var html = '<div style="display: flex; flex-direction: column; gap: 0.5rem;">';
// Cron trigger card
var cronIcon = cronReady ? '✅' : '❌';
var cronStatus = cronReady ? 'Active' : 'Not Configured';
var cronStatusColor = cronReady ? '#28a745' : '#6c757d';
var cardBg = cronReady ? '#f8f9fa' : '#fff';
html += '<div style="display: flex; align-items: center; justify-content: space-between; padding: 0.75rem 1rem; background: ' + cardBg + '; border: 1px solid #e9ecef; border-radius: 4px;">';
html += '<div style="display: flex; align-items: center; gap: 0.75rem;">';
html += '<span style="font-size: 1.25rem; line-height: 1;">' + cronIcon + '</span>';
html += '<span style="font-weight: 500; color: #212529; font-size: 1rem;">Cron:</span>';
html += '</div>';
html += '<span style="background: ' + cronStatusColor + '; color: white; padding: 0.25rem 0.75rem; font-size: 0.875rem; font-weight: 500; border-radius: 3px; text-transform: uppercase; letter-spacing: 0.025em;">' + cronStatus + '</span>';
html += '</div>';
// Webhook trigger card
if (data.webhook_enabled) {
html += '<div style="display: flex; align-items: center; justify-content: space-between; padding: 0.75rem 1rem; background: #f8f9fa; border: 1px solid #e9ecef; border-radius: 4px;">';
html += '<div style="display: flex; align-items: center; gap: 0.75rem;">';
html += '<span style="font-size: 1.25rem; line-height: 1;">✅</span>';
html += '<span style="font-weight: 500; color: #212529; font-size: 1rem;">Webhook:</span>';
html += '</div>';
html += '<span style="background: #28a745; color: white; padding: 0.25rem 0.75rem; font-size: 0.875rem; font-weight: 500; border-radius: 3px; text-transform: uppercase; letter-spacing: 0.025em;">ACTIVE</span>';
html += '</div>';
} else {
// Show webhook as not configured/disabled
html += '<div style="display: flex; align-items: center; justify-content: space-between; padding: 0.75rem 1rem; background: #fff; border: 1px solid #e9ecef; border-radius: 4px;">';
html += '<div style="display: flex; align-items: center; gap: 0.75rem;">';
html += '<span style="font-size: 1.25rem; line-height: 1;">⚠️</span>';
html += '<span style="font-weight: 500; color: #212529; font-size: 1rem;">Webhook:</span>';
html += '</div>';
html += '<span style="background: #ffc107; color: #212529; padding: 0.25rem 0.75rem; font-size: 0.875rem; font-weight: 500; border-radius: 3px; text-transform: uppercase; letter-spacing: 0.025em;">DISABLED</span>';
html += '</div>';
}
html += '</div>';
// Add warning if no triggers active
if (!cronReady && !data.webhook_enabled) {
html += '<div class="alert alert-warning" style="margin-top: 1rem;"><i class="fa fa-exclamation-triangle"></i> No triggers active! Configure cron or enable webhooks.</div>';
}
triggersEl.innerHTML = html;
})
.catch(error => {
var triggersEl = document.getElementById('scheduler-triggers');
if (triggersEl) {
// Show just cron status if health endpoint not available
var html = '<ul class="list-unstyled">';
if (cronReady) {
html += '<li>✅ <strong>Cron:</strong> <span class="badge badge-success">Active</span></li>';
} else {
html += '<li>❌ <strong>Cron:</strong> <span class="badge badge-secondary">Not Configured</span></li>';
}
html += '<li>⚠️ <strong>Webhook:</strong> <span class="badge badge-secondary">Plugin Not Installed</span></li>';
html += '</ul>';
triggersEl.innerHTML = html;
}
});
}
// Load on page ready
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', loadTriggers);
} else {
loadTriggers();
}
})();
</script>
markdown: false
jobs_tab:
type: tab
title: PLUGIN_ADMIN.SCHEDULER_JOBS
fields:
jobs_title:
type: section
title: PLUGIN_ADMIN.SCHEDULER_JOBS
underline: true
custom_jobs:
type: list
style: vertical
label:
classes: cron-job-list compact
key: id
fields:
.id:
type: key
label: ID
placeholder: 'process-name'
validate:
required: true
pattern: '[a-zа-я0-9_\-]+'
max: 20
message: 'ID must be lowercase with dashes/underscores only and less than 20 characters'
.command:
type: text
label: PLUGIN_ADMIN.COMMAND
placeholder: 'ls'
validate:
required: true
.args:
type: text
label: PLUGIN_ADMIN.EXTRA_ARGUMENTS
placeholder: '-lah'
.at:
type: text
wrapper_classes: cron-selector
label: PLUGIN_ADMIN.SCHEDULER_RUNAT
help: PLUGIN_ADMIN.SCHEDULER_RUNAT_HELP
placeholder: '* * * * *'
validate:
required: true
.output:
type: text
label: PLUGIN_ADMIN.SCHEDULER_OUTPUT
help: PLUGIN_ADMIN.SCHEDULER_OUTPUT_HELP
placeholder: 'logs/ls-cron.out'
.output_mode:
type: select
label: PLUGIN_ADMIN.SCHEDULER_OUTPUT_TYPE
help: PLUGIN_ADMIN.SCHEDULER_OUTPUT_TYPE_HELP
default: append
options:
append: Append
overwrite: Overwrite
.email:
type: text
label: PLUGIN_ADMIN.SCHEDULER_EMAIL
help: PLUGIN_ADMIN.SCHEDULER_EMAIL_HELP
placeholder: 'notifications@yoursite.com'
modern_tab:
type: tab
title: Advanced Features
fields:
workers_section:
type: section
title: Worker Configuration
underline: true
fields:
modern.workers:
type: number
label: Concurrent Workers
help: Number of jobs that can run simultaneously (1 = sequential)
default: 4
size: x-small
append: workers
validate:
type: int
min: 1
max: 10
retry_section:
type: section
title: Retry Configuration
underline: true
fields:
modern.retry.enabled:
type: toggle
label: Enable Job Retry
help: Automatically retry failed jobs
highlight: 1
default: 1
options:
1: PLUGIN_ADMIN.ENABLED
0: PLUGIN_ADMIN.DISABLED
validate:
type: bool
modern.retry.max_attempts:
type: number
label: Maximum Retry Attempts
help: Maximum number of times to retry a failed job
default: 3
size: x-small
append: retries
validate:
type: int
min: 1
max: 10
modern.retry.backoff:
type: select
label: Retry Backoff Strategy
help: How to calculate delay between retries
default: exponential
options:
linear: Linear (fixed delay)
exponential: Exponential (increasing delay)
queue_section:
type: section
title: Queue Configuration
underline: true
fields:
modern.queue.path:
type: text
label: Queue Storage Path
help: Where to store queued jobs
default: 'user-data://scheduler/queue'
placeholder: 'user-data://scheduler/queue'
modern.queue.max_size:
type: number
label: Maximum Queue Size
help: Maximum number of jobs that can be queued
default: 1000
size: x-small
append: jobs
validate:
type: int
min: 100
max: 10000
history_section:
type: section
title: Job History
underline: true
fields:
modern.history.enabled:
type: toggle
label: Enable Job History
help: Track execution history for all jobs
highlight: 1
default: 1
options:
1: PLUGIN_ADMIN.ENABLED
0: PLUGIN_ADMIN.DISABLED
validate:
type: bool
modern.history.retention_days:
type: number
label: History Retention (days)
help: How long to keep job history
default: 30
size: x-small
append: days
validate:
type: int
min: 1
max: 365
webhook_section:
type: section
title: Webhook Configuration
underline: true
fields:
webhook_plugin_status:
type: webhook-status
label:
modern.webhook.enabled:
type: toggle
label: Enable Webhook Triggers
help: Allow triggering scheduler via HTTP webhook
highlight: 0
default: 0
options:
1: PLUGIN_ADMIN.ENABLED
0: PLUGIN_ADMIN.DISABLED
validate:
type: bool
modern.webhook.token:
type: text
label: Webhook Security Token
help: Secret token for authenticating webhook requests. Keep this secret!
placeholder: 'Click Generate to create a secure token'
autocomplete: 'off'
webhook_token_generate:
type: display
label:
content: |
<div style="margin-top: -10px; margin-bottom: 15px;">
<button type="button" class="button button-primary" onclick="generateWebhookToken()">
<i class="fa fa-refresh"></i> Generate Token
</button>
</div>
<script>
function generateWebhookToken() {
try {
// Generate token
const array = new Uint8Array(32);
crypto.getRandomValues(array);
const token = Array.from(array, byte => byte.toString(16).padStart(2, '0')).join('');
// Try multiple selectors to find the field
let field = document.querySelector('[name="data[scheduler][modern][webhook][token]"]');
if (!field) {
field = document.querySelector('input[name*="webhook][token"]');
}
if (!field) {
field = document.getElementById('scheduler-modern-webhook-token');
}
if (!field) {
// Look for any text input in the webhook section
const webhookSection = document.querySelector('.webhook_section');
if (webhookSection) {
const inputs = webhookSection.querySelectorAll('input[type="text"]');
// Find the token field by checking for the placeholder
for (let input of inputs) {
if (input.placeholder && input.placeholder.includes('Generate')) {
field = input;
break;
}
}
}
}
if (field) {
field.value = token;
field.dispatchEvent(new Event('change', { bubbles: true }));
field.dispatchEvent(new Event('input', { bubbles: true }));
// Flash the field to show it was updated
field.style.backgroundColor = '#d4edda';
setTimeout(function() {
field.style.backgroundColor = '';
}, 500);
// Also try to trigger Grav's form change detection
if (window.jQuery) {
jQuery(field).trigger('change');
}
} else {
// Log more debugging info
console.error('Token field not found. Looking for input fields...');
console.log('All inputs:', document.querySelectorAll('input[type="text"]'));
alert('Could not find the token field. Please ensure you are in the Advanced Features tab and the Webhook Configuration section is visible.');
}
} catch (e) {
console.error('Error generating token:', e);
alert('Error generating token: ' + e.message);
}
}
</script>
markdown: false
modern.webhook.path:
type: text
label: Webhook Path
help: URL path for webhook endpoint
default: '/scheduler/webhook'
placeholder: '/scheduler/webhook'
health_section:
type: section
title: Health Check Configuration
underline: true
fields:
modern.health.enabled:
type: toggle
label: Enable Health Check
help: Provide health status endpoint for monitoring
highlight: 1
default: 1
options:
1: PLUGIN_ADMIN.ENABLED
0: PLUGIN_ADMIN.DISABLED
validate:
type: bool
modern.health.path:
type: text
label: Health Check Path
help: URL path for health check endpoint
default: '/scheduler/health'
placeholder: '/scheduler/health'
webhook_usage:
type: section
title: Usage Examples
underline: true
fields:
webhook_examples:
type: display
label:
content: |
<script src="{{ url('plugin://admin/themes/grav/js/clipboard-helper.js') }}"></script>
<div class="webhook-examples">
<script>
// Initialize webhook commands when page loads
document.addEventListener('DOMContentLoaded', function() {
if (typeof GravClipboard !== 'undefined') {
GravClipboard.initWebhookCommands();
}
});
</script>
<div class="alert alert-info">
<h4>How to use webhooks:</h4>
<div style="margin-bottom: 1rem;">
<label style="display: block; margin-bottom: 0.25rem; font-weight: 500;">Trigger all due jobs (respects schedule):</label>
<div class="form-input-wrapper form-input-addon-wrapper">
<textarea id="webhook-all-cmd" readonly rows="2" style="font-family: monospace; background: #f5f5f5; resize: none;">Loading...</textarea>
<div class="form-input-addon form-input-append" style="cursor: pointer;" onclick="GravClipboard.copy(this)"><i class="fa fa-copy"></i> Copy</div>
</div>
</div>
<div style="margin-bottom: 1rem;">
<label style="display: block; margin-bottom: 0.25rem; font-weight: 500;">Force-run specific job (ignores schedule):</label>
<div class="form-input-wrapper form-input-addon-wrapper">
<textarea id="webhook-job-cmd" readonly rows="2" style="font-family: monospace; background: #f5f5f5; resize: none;">Loading...</textarea>
<div class="form-input-addon form-input-append" style="cursor: pointer;" onclick="GravClipboard.copy(this)"><i class="fa fa-copy"></i> Copy</div>
</div>
</div>
<div style="margin-bottom: 1rem;">
<label style="display: block; margin-bottom: 0.25rem; font-weight: 500;">Check health status:</label>
<div class="form-input-wrapper form-input-addon-wrapper">
<input type="text" id="webhook-health-cmd" readonly value="Loading..." style="font-family: monospace; background: #f5f5f5;">
<div class="form-input-addon form-input-append" style="cursor: pointer;" onclick="GravClipboard.copy(this)"><i class="fa fa-copy"></i> Copy</div>
</div>
</div>
<div style="margin-top: 1rem;">
<p><strong>GitHub Actions example:</strong></p>
<pre>- name: Trigger Scheduler
run: |
curl -X POST ${{ secrets.SITE_URL }}/scheduler/webhook \
-H "Authorization: Bearer ${{ secrets.WEBHOOK_TOKEN }}"</pre>
</div>
</div>
</div>
markdown: false

View File

@@ -103,6 +103,7 @@ form:
"D, d M Y G:i:s": Date3
"d-m-y G:i": Date4
"jS M Y": Date5
"Y-m-d G:i": Date6
pages.dateformat.long:
type: dateformat
@@ -116,6 +117,7 @@ form:
"D, d M Y G:i:s": Date3
"d-m-y G:i": Date4
"jS M Y": Date5
"Y-m-d G:i:s": Date6
pages.order.by:
type: select
@@ -448,6 +450,17 @@ form:
validate:
type: bool
languages.debug:
type: toggle
label: PLUGIN_ADMIN.LANGUAGE_DEBUG
help: PLUGIN_ADMIN.LANGUAGE_DEBUG_HELP
highlight: 0
options:
1: PLUGIN_ADMIN.YES
0: PLUGIN_ADMIN.NO
validate:
type: bool
http_headers:
type: tab
title: PLUGIN_ADMIN.HTTP_HEADERS
@@ -597,6 +610,15 @@ form:
hash: All files timestamps
none: No timestamp checking
cache.check.interval:
type: number
size: x-small
label: Cache Check Interval
help: Seconds to reuse the previously computed filesystem hash before checking again. Zero keeps existing per-request checks.
validate:
type: int
min: 0
cache.driver:
type: select
size: small
@@ -606,12 +628,9 @@ form:
options:
auto: Auto detect
file: File
apc: APC
apcu: APCu
xcache: Xcache
memcache: Memcache
memcached: Memcached
wincache: WinCache
redis: Redis
cache.prefix:
@@ -621,6 +640,19 @@ form:
help: PLUGIN_ADMIN.CACHE_PREFIX_HELP
placeholder: PLUGIN_ADMIN.CACHE_PREFIX_PLACEHOLDER
cache.purge_max_age_days:
type: text
size: x-small
append: GRAV.NICETIME.DAY_PLURAL
label: PLUGIN_ADMIN.CACHE_PURGE_AGE
help: PLUGIN_ADMIN.CACHE_PURGE_AGE_HELP
validate:
type: number
min: 1
max: 365
step: 1
default: 30
cache.purge_at:
type: cron
label: PLUGIN_ADMIN.CACHE_PURGE_JOB
@@ -695,20 +727,6 @@ form:
validate:
type: bool
cache.memcache.server:
type: text
size: medium
label: PLUGIN_ADMIN.MEMCACHE_SERVER
help: PLUGIN_ADMIN.MEMCACHE_SERVER_HELP
placeholder: "localhost"
cache.memcache.port:
type: text
size: small
label: PLUGIN_ADMIN.MEMCACHE_PORT
help: PLUGIN_ADMIN.MEMCACHE_PORT_HELP
placeholder: "11211"
cache.memcached.server:
type: text
size: medium
@@ -766,8 +784,8 @@ form:
flex.cache.index.enabled:
type: toggle
label: PLUGIN_ADMIN.FLEX_INDEX_CACHE_ENABLED
highlight: 1
default: 1
highlight: 0
default: 0
options:
1: PLUGIN_ADMIN.ENABLED
0: PLUGIN_ADMIN.DISABLED
@@ -784,8 +802,8 @@ form:
flex.cache.object.enabled:
type: toggle
label: PLUGIN_ADMIN.FLEX_OBJECT_CACHE_ENABLED
highlight: 1
default: 1
highlight: 0
default: 0
options:
1: PLUGIN_ADMIN.ENABLED
0: PLUGIN_ADMIN.DISABLED
@@ -872,17 +890,6 @@ form:
validate:
type: bool
twig.umask_fix:
type: toggle
label: PLUGIN_ADMIN.TWIG_UMASK_FIX
help: PLUGIN_ADMIN.TWIG_UMASK_FIX_HELP
highlight: 0
options:
1: PLUGIN_ADMIN.YES
0: PLUGIN_ADMIN.NO
validate:
type: bool
assets:
type: tab
title: PLUGIN_ADMIN.ASSETS
@@ -1226,6 +1233,16 @@ form:
title: PLUGIN_ADMIN.MEDIA
underline: true
images.adapter:
type: select
size: small
label: PLUGIN_ADMIN.IMAGE_ADAPTER
help: PLUGIN_ADMIN.IMAGE_ADAPTER_HELP
highlight: gd
options:
gd: GD (PHP built-in)
imagick: Imagick
images.default_image_quality:
type: range
append: '%'
@@ -1288,6 +1305,28 @@ form:
auto: Auto
lazy: Lazy
eager: Eager
images.defaults.decoding:
type: select
size: small
label: PLUGIN_ADMIN.IMAGES_DECODING
help: PLUGIN_ADMIN.IMAGES_DECODING_HELP
highlight: auto
options:
auto: Auto
sync: Sync
async: Async
images.defaults.fetchpriority:
type: select
size: small
label: PLUGIN_ADMIN.IMAGES_FETCHPRIORITY
help: PLUGIN_ADMIN.IMAGES_FETCHPRIORITY_HELP
highlight: auto
options:
auto: Auto
high: High
low: Low
images.seofriendly:
type: toggle
@@ -1726,8 +1765,8 @@ form:
http_x_forwarded.host:
type: toggle
label: HTTP_X_FORWARDED_HOST Enabled
highlight: 0
default: 0
highlight: 1
default: 1
options:
1: PLUGIN_ADMIN.YES
0: PLUGIN_ADMIN.NO
@@ -1760,8 +1799,8 @@ form:
strict_mode.blueprint_compat:
type: toggle
label: PLUGIN_ADMIN.STRICT_BLUEPRINT_COMPAT
highlight: 0
default: 0
highlight: 1
default: 1
help: PLUGIN_ADMIN.STRICT_BLUEPRINT_COMPAT_HELP
options:
1: PLUGIN_ADMIN.YES
@@ -1781,7 +1820,7 @@ form:
validate:
type: bool
strict_mode.twig_compat:
strict_mode.twig2_compat:
type: toggle
label: PLUGIN_ADMIN.STRICT_TWIG_COMPAT
highlight: 0
@@ -1793,6 +1832,18 @@ form:
validate:
type: bool
strict_mode.twig3_compat:
type: toggle
label: Twig 3 Compatibility
highlight: 0
default: 0
help: Enable automatic rewrites for legacy Twig 1/2 syntax that breaks on Twig 3 (e.g. `for ... if ...` guards)
options:
1: PLUGIN_ADMIN.YES
0: PLUGIN_ADMIN.NO
validate:
type: bool
accounts:
type: tab
@@ -1855,6 +1906,3 @@ form:
#
# pages.type:
# type: hidden

View File

@@ -216,3 +216,8 @@ types:
type: file
thumb: media/thumb-json.png
mime: application/json
vcf:
type: file
thumb: media/thumb-vcf.png
mime: text/x-vcard

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,68 @@
# Grav Scheduler Configuration
# Default scheduler settings (backward compatible)
defaults:
output: true
output_type: file
email: null
# Status of individual jobs (enabled/disabled)
status: {}
# Custom scheduled jobs
custom_jobs: {}
# Modern scheduler features (disabled by default for backward compatibility)
modern:
# Enable modern scheduler features
enabled: false
# Number of concurrent workers (1 = sequential execution like legacy)
workers: 1
# Job retry configuration
retry:
enabled: true
max_attempts: 3
backoff: exponential # 'linear' or 'exponential'
# Job queue configuration
queue:
path: user-data://scheduler/queue
max_size: 1000
# Webhook trigger configuration
webhook:
enabled: false
token: null # Set a secure token to enable webhook triggers
path: /scheduler/webhook
# Health check endpoint
health:
enabled: true
path: /scheduler/health
# Job execution history
history:
enabled: true
retention_days: 30
path: user-data://scheduler/history
# Performance settings
performance:
job_timeout: 300 # Default timeout in seconds
lock_timeout: 10 # Lock acquisition timeout in seconds
# Monitoring and alerts
monitoring:
enabled: false
alert_on_failure: true
alert_email: null
webhook_url: null
# Trigger detection methods
triggers:
check_cron: true
check_systemd: true
check_webhook: true
check_external: true

View File

@@ -32,8 +32,16 @@ xss_dangerous_tags:
- base
uploads_dangerous_extensions:
- php
- php2
- php3
- php4
- php5
- phar
- phtml
- html
- htm
- shtml
- shtm
- js
- exe
sanitize_svg: true

View File

@@ -25,7 +25,7 @@ routes:
# '/new/(.*)': '/blog/$1' # Regex any /new/my-page URL to /blog/my-page Route
blog:
route: '/blog' # Custom value added (accessible via system.blog.route)
route: '/blog' # Custom value added (accessible via site.blog.route)
#menu: # Menu Example
# - text: Source

View File

@@ -28,6 +28,7 @@ languages:
override_locale: false # Override the default or system locale with language specific one
content_fallback: {} # Custom language fallbacks. eg: {fr: ['fr', 'en']}
pages_fallback_only: false # DEPRECATED: Use `content_fallback` instead
debug: false # Debug language detection
home:
alias: '/home' # Default path for home, ie /
@@ -92,14 +93,16 @@ cache:
enabled: true # Set to true to enable caching
check:
method: file # Method to check for updates in pages: file|folder|hash|none
driver: auto # One of: auto|file|apcu|memcache|wincache
interval: 0 # Seconds to reuse previous filesystem hash before rechecking (0 = every request)
driver: auto # One of: auto|file|apcu|memcached|redis
prefix: 'g' # Cache prefix string (prevents cache conflicts)
purge_at: '0 4 * * *' # How often to purge old file cache (using new scheduler)
clear_at: '0 3 * * *' # How often to clear cache (using new scheduler)
clear_job_type: 'standard' # Type to clear when processing the scheduled clear job `standard`|`all`
clear_images_by_default: false # By default grav does not include processed images in cache clear, this can be enabled
cli_compatibility: false # Ensures only non-volatile drivers are used (file, redis, memcache, etc.)
cli_compatibility: false # Ensures only non-volatile drivers are used (file, redis, memcached, etc.)
lifetime: 604800 # Lifetime of cached data in seconds (0 = infinite)
purge_max_age_days: 30 # Maximum age of cache items in days before they are purged
gzip: false # GZip compress the page output
allow_webserver_gzip: false # If true, `content-encoding: identity` but connection isn't closed before `onShutDown()` event
redis:
@@ -116,7 +119,6 @@ twig:
undefined_filters: true # Allow undefined filters
safe_functions: [] # List of PHP functions which are allowed to be used as Twig functions
safe_filters: [] # List of PHP functions which are allowed to be used as Twig filters
umask_fix: false # By default Twig creates cached files as 755, fix switches this to 775
assets: # Configuration for Assets Manager (JS, CSS)
css_pipeline: false # The CSS pipeline is the unification of multiple CSS resources into one file
@@ -155,6 +157,7 @@ debugger:
close_connection: true # Close the connection before calling onShutdown(). false for debugging
images:
adapter: gd # Image adapter to use: gd | imagick
default_image_quality: 85 # Default image quality to use when resampling images (85%)
cache_all: false # Cache all image by default
cache_perms: '0755' # MUST BE IN QUOTES!! Default cache folder perms. Usually '0755' or '0775'
@@ -167,6 +170,8 @@ images:
retina_scale: 1 # scale to adjust auto-sizes for better handling of HiDPI resolutions
defaults:
loading: auto # Let browser pick [auto|lazy|eager]
decoding: auto # Let browser pick [auto|sync|async]
fetchpriority: auto # Let browser pick [auto|high|low]
watermark:
image: 'system://images/watermark.png' # Path to a watermark image
position_y: 'center' # top|center|bottom
@@ -226,5 +231,6 @@ flex:
strict_mode:
yaml_compat: false # Set to true to enable YAML backwards compatibility
twig_compat: false # Set to true to enable deprecated Twig settings (autoescape: false)
twig2_compat: false # Set to true to enable deprecated Twig settings (autoescape: false)
twig3_compat: true # Set to true to enable automatic fixes for Twig 3 syntax changes
blueprint_compat: false # Set to true to enable backward compatible strict support for blueprints

View File

@@ -3,19 +3,19 @@
/**
* @package Grav\Core
*
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2025 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/
// Some standard defines
define('GRAV', true);
define('GRAV_VERSION', '1.7.37.1');
define('GRAV_SCHEMA', '1.7.0_2020-11-20_1');
define('GRAV_TESTING', false);
define('GRAV_VERSION', '1.8.0-beta.8');
define('GRAV_SCHEMA', '1.8.0_2025-09-21_0');
define('GRAV_TESTING', true);
// PHP minimum requirement
if (!defined('GRAV_PHP_MIN')) {
define('GRAV_PHP_MIN', '7.3.6');
define('GRAV_PHP_MIN', '8.2.0');
}
// Directory separator
@@ -26,12 +26,12 @@ if (!defined('DS')) {
// Absolute path to Grav root. This is where Grav is installed into.
if (!defined('GRAV_ROOT')) {
$path = rtrim(str_replace(DIRECTORY_SEPARATOR, DS, getenv('GRAV_ROOT') ?: getcwd()), DS);
define('GRAV_ROOT', $path);
define('GRAV_ROOT', $path ?: DS);
}
// Absolute path to Grav webroot. This is the path where your site is located in.
if (!defined('GRAV_WEBROOT')) {
$path = rtrim(getenv('GRAV_WEBROOT') ?: GRAV_ROOT, DS);
define('GRAV_WEBROOT', $path);
define('GRAV_WEBROOT', $path ?: DS);
}
// Relative path to user folder. This path needs to be located under GRAV_WEBROOT.
if (!defined('GRAV_USER_PATH')) {
@@ -99,3 +99,6 @@ define('RAW_CONTENT', 1);
define('TWIG_CONTENT', 2);
define('TWIG_CONTENT_LIST', 3);
define('TWIG_TEMPLATES', 4);
// Filters
define('GRAV_SANITIZE_STRING', 5001);

View File

@@ -2,7 +2,7 @@
/**
* @package Grav\Core
*
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2025 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/

View File

@@ -5,6 +5,7 @@ GRAV:
BAD_DATE: Невалидна дата
AGO: преди
FROM_NOW: от сега
JUST_NOW: току що
SECOND: секунда
MINUTE: минута
HOUR: час
@@ -60,3 +61,12 @@ GRAV:
- 'петък'
- 'събота'
- 'неделя'
YES: "Да"
NO: "Не"
CRON:
EVERY: всеки
EVERY_HOUR: Всеки час
EVERY_MINUTE: Всяка минута
EVERY_DAY_OF_WEEK: Всеки ден от седмицата
EVERY_DAY_OF_MONTH: Всеки ден от месеца
EVERY_MONTH: Всеки месец

View File

@@ -2,14 +2,14 @@
GRAV:
FRONTMATTER_ERROR_PAGE: "---\ntitle: %1$s\n---\n\n# S'ha produït un error: Frontmatter invàlid\n\nRuta: `%2$s`\n\n**%3$s**\n\n```\n%4$s\n```"
INFLECTOR_UNCOUNTABLE:
- 'equipment'
- ''
- 'informació'
- 'rice'
- 'money'
- 'species'
- 'series'
- 'fish'
- 'sheep'
- ''
- ''
- ''
- ''
- ''
- ''
NICETIME:
NO_DATE_PROVIDED: No s'ha proporcionat data
BAD_DATE: Data invàlida

View File

@@ -1,6 +1,6 @@
---
GRAV:
FRONTMATTER_ERROR_PAGE: "---\ntitle: %1$s\n---\n\n# Chyba: Chybný frontmatter\n\nPath: `%2$s`\n\n**%3$s**\n\n```\n%4$s\n```"
FRONTMATTER_ERROR_PAGE: "---\ntitle: %1$s\n---\n\n# Chyba: Chybná hlavička\n\nCesta: `%2$s`\n\n**%3$s**\n\n```\n%4$s\n```"
INFLECTOR_PLURALS:
'/(quiz)$/i': '\1zes'
'/^(ox)$/i': '\1en'

40
system/languages/eo.yaml Normal file
View File

@@ -0,0 +1,40 @@
---
GRAV:
FRONTMATTER_ERROR_PAGE: "---\ntitle: %1$s\n---\n\n# Eraro: Nevalida Frontmatter\n\nVojo: `%2$s`\n\n**%3$s**\n\n```\n%4$s\n```"
INFLECTOR_PLURALS:
'/sis$/i': 'j'
NICETIME:
FROM_NOW: ekde nun
JUST_NOW: Ĝuste nun
SECOND: sekundo
MINUTE: minuto
HOUR: horo
DAY: tago
WEEK: semajno
MONTH: monato
YEAR: jaro
DECADE: jardeko
SEC: sek.
MIN: min.
HR: horo
SECOND_PLURAL: sekundoj
MINUTE_PLURAL: minutoj
HOUR_PLURAL: horoj
DAY_PLURAL: tagoj
WEEK_PLURAL: semajnoj
MONTH_PLURAL: monatoj
YEAR_PLURAL: jaroj
DECADE_PLURAL: jardekoj
MONTHS_OF_THE_YEAR:
- 'januaro'
- 'februaro'
- 'marto'
- 'aprilo'
- ''
- ''
- ''
- ''
- ''
- ''
- ''
- ''

View File

@@ -21,9 +21,9 @@ GRAV:
'sex': 'sexos'
'move': 'movido'
INFLECTOR_ORDINALS:
'first': 'ro'
'second': 'do'
'third': 'ro'
'first': ''
'second': ''
'third': ''
NICETIME:
NO_DATE_PROVIDED: No se proporcionó fecha
BAD_DATE: Fecha errónea
@@ -101,7 +101,7 @@ GRAV:
TEXT_DOW: ' en <b />'
TEXT_MONTH: ' de<b />'
TEXT_DOM: ' en<b />'
ERROR1: '¡La etiqueta %s no está soportada!'
ERROR1: No se admite la etiqueta %s.
ERROR2: El número de elementos es erróneo
ERROR3: El jquery_element debería establecerse en la configuración del jqCron
ERROR4: Expresión no reconocida

View File

@@ -13,12 +13,12 @@ GRAV:
'/(tive)s$/i': '\1'
'/(hive)s$/i': '\1'
INFLECTOR_UNCOUNTABLE:
- 'equipment'
- ''
- 'informatsioon'
- 'riis'
- 'raha'
- 'species'
- 'series'
- ''
- ''
- 'kala'
- 'lammas'
INFLECTOR_IRREGULAR:
@@ -70,6 +70,7 @@ GRAV:
VALIDATION_FAIL: '<b>Kinnitamine nurjus:</b>'
INVALID_INPUT: 'Vigane sisend:'
MISSING_REQUIRED_FIELD: 'Nõutud väli puudub:'
XSS_ISSUES: "Tuvastasime '%s' väljal võimaliku XSS-riski"
MONTHS_OF_THE_YEAR:
- 'jaanuar'
- 'veebruar'
@@ -91,11 +92,14 @@ GRAV:
- 'reede'
- 'laupäev'
- 'pühapäev'
YES: "Jah"
NO: "Ei"
CRON:
EVERY: iga
EVERY_HOUR: iga tund
EVERY_MINUTE: iga minut
EVERY_DAY_OF_WEEK: iga nädala päev
EVERY_DAY_OF_WEEK: nädala igal päeval
EVERY_DAY_OF_MONTH: kuu igal päeval
EVERY_MONTH: iga kuu
TEXT_PERIOD: Iga <b />
ERROR1: Silt %s pole toetatud!

View File

@@ -45,12 +45,12 @@ GRAV:
'/([ti])a$/i': '\1um'
'/(n)ews$/i': '\1ews'
INFLECTOR_UNCOUNTABLE:
- 'equipment'
- 'information'
- ''
- ''
- 'riisi'
- 'raha'
- 'lajit'
- 'series'
- ''
- 'kala'
- 'lammas'
INFLECTOR_IRREGULAR:

View File

@@ -22,8 +22,27 @@ GRAV:
'/$/': 's'
INFLECTOR_SINGULAR:
'/(quiz)zes$/i': '\1'
'/(matr)ices$/i': '\1ix'
'/(vert|ind)ices$/i': '\1ex'
'/^(ox)en/i': '\1'
'/(alias|status)es$/i': '\1'
'/([octop|vir])i$/i': '\1us'
'/(cris|ax|test)es$/i': '\1is'
'/(shoe)s$/i': '\1'
'/(o)es$/i': '\1'
'/(bus)es$/i': '\1'
'/([m|l])ice$/i': '\1ouse'
'/(x|ch|ss|sh)es$/i': '\1'
'/(m)ovies$/i': '\1ovie'
'/(s)eries$/i': '\1eries'
'/([^aeiouy]|qu)ies$/i': '\1y'
'/([lr])ves$/i': '\1f'
'/(tive)s$/i': '\1'
'/(hive)s$/i': '\1'
'/([^f])ves$/i': '\1fe'
'/(^analy)ses$/i': '\1sis'
'/((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$/i': '\1\2sis'
'/([ti])a$/i': '\1um'
'/(n)ews$/i': '\1ouvelles'
INFLECTOR_UNCOUNTABLE:
- 'équipement'

View File

@@ -1,11 +1,27 @@
---
GRAV:
FRONTMATTER_ERROR_PAGE: "---\nכותרת: %1$s\n---\n# שגיאה: Fronmatter לא חוקי\nנתיב: `%2$s`\n**%3$s**\n```\n%4$s\n```"
INFLECTOR_UNCOUNTABLE:
- 'ציוד'
- 'מידע'
- 'אורז'
- 'כסף'
- 'מינים'
- 'סדרה'
- 'דג'
- 'כבשה'
INFLECTOR_IRREGULAR:
'person': 'אנשים'
'man': 'גברים'
'child': 'ילדים'
'sex': 'מינים'
'move': 'מהלכים'
NICETIME:
NO_DATE_PROVIDED: לא סופק תאריך
BAD_DATE: תאריך פגום
AGO: לפני
FROM_NOW: כרגע
JUST_NOW: כרגע
SECOND: שנייה
MINUTE: דקה
HOUR: שעה
@@ -40,6 +56,7 @@ GRAV:
VALIDATION_FAIL: '<b>האימות נכשל:</b>'
INVALID_INPUT: 'קלט לא חוקי'
MISSING_REQUIRED_FIELD: 'שדות חובה חסרים:'
XSS_ISSUES: "בעיות XSS פוטנציאליות זוהו בשדה '%s'"
MONTHS_OF_THE_YEAR:
- 'ינואר'
- 'פברואר'
@@ -61,3 +78,22 @@ GRAV:
- 'שישי'
- 'שבת'
- 'ראשון'
YES: "כן"
NO: "לא"
CRON:
EVERY: בכל
EVERY_HOUR: בכל שעה
EVERY_MINUTE: כל דקה
EVERY_DAY_OF_WEEK: כל יום בשבוע
EVERY_DAY_OF_MONTH: בכל יום בחודש
EVERY_MONTH: כל חודש
TEXT_PERIOD: כל <b />
TEXT_MINS: 'ב <b /> דקות אחרי השעה'
TEXT_TIME: 'ב <b />:<b />'
TEXT_DOW: 'ב <b />'
TEXT_MONTH: 'של <b />'
TEXT_DOM: 'ב <b />'
ERROR1: התגית %s אינו נתמכת
ERROR2: מספר לא חוקי של משתנים.
ERROR3: יש להגדיר את ה-jquery_element להגדרות jqCron
ERROR4: ביטוי לא מזוהה

View File

@@ -1,8 +1,9 @@
---
GRAV:
FRONTMATTER_ERROR_PAGE: "---\nnaslov: %1$s\n---\n\n# Pogreška: nevažeći frontmatter\n\nPutanja datoteke: `%2$s`\n\n**%3$s**\n\n```\n%4$s\n```"
INFLECTOR_UNCOUNTABLE:
- 'oprema'
- 'informacije'
- 'informacija'
- 'riža'
- 'novac'
- 'vrsta'
@@ -15,11 +16,17 @@ GRAV:
'child': 'djeca'
'sex': 'spolovi'
'move': 'Pomakni'
INFLECTOR_ORDINALS:
'default': '.'
'first': '.'
'second': '.'
'third': '.'
NICETIME:
NO_DATE_PROVIDED: Datum nije upisan
BAD_DATE: Pogrešan datum
AGO: prije
FROM_NOW: od sada
JUST_NOW: upravo sad
SECOND: sekunda
MINUTE: minuta
HOUR: sat
@@ -29,6 +36,7 @@ GRAV:
YEAR: godina
DECADE: desetljeće
SEC: sek
MIN: min
HR: sat
WK: t
MO: m
@@ -53,6 +61,7 @@ GRAV:
VALIDATION_FAIL: '<b>Validacija nije uspjela:</b>'
INVALID_INPUT: 'Pogrešan unos u'
MISSING_REQUIRED_FIELD: 'Nedostaje obavezno polje:'
XSS_ISSUES: "Potencijalni XSS problemi otkriveni u polju '%s'"
MONTHS_OF_THE_YEAR:
- 'Siječanj'
- 'Veljača'
@@ -74,3 +83,22 @@ GRAV:
- 'Petak'
- 'Subota'
- 'Nedjelja'
YES: "Da"
NO: "Ne"
CRON:
EVERY: svaki
EVERY_HOUR: svaki sat
EVERY_MINUTE: svake minute
EVERY_DAY_OF_WEEK: svaki dan u tjednu
EVERY_DAY_OF_MONTH: svaki dan u mjesecu
EVERY_MONTH: svaki mjesec
TEXT_PERIOD: Svakih <b />
TEXT_MINS: ' u <b /> minut(e) nakon sata'
TEXT_TIME: ' u <b />:<b />'
TEXT_DOW: ' na <b />'
TEXT_MONTH: ' <b />'
TEXT_DOM: ' na <b />'
ERROR1: Oznaka %s nije podržana!
ERROR2: Pogrešan broj elemenata.
ERROR3: jquery_element treba postaviti u postavke jqCron
ERROR4: Izraz nije prepoznat

View File

@@ -2,14 +2,14 @@
GRAV:
FRONTMATTER_ERROR_PAGE: "---\ntitill: %1$s\n---\n\n# Villa: Ógilt efni á forsíðu\n\nSlóð: `%2$s`\n\n**%3$s**\n\n```\n%4$s\n```"
INFLECTOR_UNCOUNTABLE:
- 'equipment'
- ''
- 'upplýsingar'
- 'rice'
- 'money'
- 'species'
- 'series'
- 'fish'
- 'sheep'
- ''
- ''
- ''
- ''
- ''
- ''
NICETIME:
NO_DATE_PROVIDED: Engin dagsetning gefin
BAD_DATE: Röng dagsetning

View File

@@ -1,12 +1,12 @@
---
GRAV:
INFLECTOR_UNCOUNTABLE:
- 'equipment'
- ''
- '情報'
- 'rice'
- ''
- 'お金'
- 'species'
- 'series'
- ''
- ''
- '魚'
- 'ヒツジ'
INFLECTOR_IRREGULAR:

View File

@@ -1,11 +1,23 @@
---
GRAV:
FRONTMATTER_ERROR_PAGE: "---\ntitle: %1$s\n---\n\n# 오류: 무효의 Frontmatter\n\n경로: `%2$s`\n\n**%3$s**\n\n```\n%4$s\n```"
INFLECTOR_UNCOUNTABLE:
- '장비'
- '정보'
- ''
- ''
- ''
- '시리즈'
- '물고기'
- ''
INFLECTOR_IRREGULAR:
'person': '사람들'
NICETIME:
NO_DATE_PROVIDED: 제공된 날짜가 없습니다
BAD_DATE: 잘못된 날짜
AGO:
FROM_NOW:
JUST_NOW: 방금
SECOND:
MINUTE:
HOUR: 시간
@@ -40,6 +52,7 @@ GRAV:
VALIDATION_FAIL: '<b>유효성 검사 실패:</b>'
INVALID_INPUT: '잘못된 입력'
MISSING_REQUIRED_FIELD: '누락 된 필수 필드:'
XSS_ISSUES: "'%s' 필드에서 잠재적인 XSS 문제가 감지되었습니다."
MONTHS_OF_THE_YEAR:
- '일월'
- '이월'
@@ -61,3 +74,17 @@ GRAV:
- '금요일'
- '토요일'
- '일요일'
YES: "네"
NO: "아니요"
CRON:
EVERY: 모두
EVERY_HOUR: 매 시간
EVERY_MINUTE: 매 분
EVERY_DAY_OF_WEEK: 일주일간 매일
EVERY_DAY_OF_MONTH: 일개월간 매일
EVERY_MONTH: 매달
TEXT_PERIOD: 모든 <b />
ERROR1: '%s 태그는 지원되지 않습니다. '
ERROR2: 잘못된 요소 수
ERROR3: jquery_element는 jqCron 설정에서 설정할 수 있습니다.
ERROR4: 인식할 수 없는 표현

View File

@@ -2,8 +2,8 @@
GRAV:
FRONTMATTER_ERROR_PAGE: "---\ntitle: %1$s\n---\n\n# Klaida: klaidinga įžanginė konfigūracija\n\nPath: `%2$s`\n\n**%3$s**\n\n```\n %4$s\n```"
INFLECTOR_UNCOUNTABLE:
- 'equipment'
- 'information'
- ''
- ''
- 'ryžiai'
- 'pinigai'
- 'prieskoniai'

84
system/languages/lv.yaml Normal file
View File

@@ -0,0 +1,84 @@
---
GRAV:
FRONTMATTER_ERROR_PAGE: "---\nNosaukums: %1$s\n---\n\n# Kļūda: Nederīgs Frontmatter\n\nCeļš: `%2$s`\n\n**%3$s**\n\n```\n%4$s\n```"
INFLECTOR_ORDINALS:
'default': '.'
'first': '.'
'second': '.'
'third': '.'
NICETIME:
NO_DATE_PROVIDED: Nav norādīts datums
BAD_DATE: Nederīgs datums
AGO: iepriekš
FROM_NOW: no šī brīža
JUST_NOW: tikko
SECOND: sekundes
MINUTE: minūte
HOUR: stunda
DAY: diena
WEEK: nedēļa
MONTH: mēnesis
YEAR: gads
DECADE: dekāde
SEC: s
MIN: m
HR: st
WK: ned
MO: mēn.
YR: g.
DEC: dec
SECOND_PLURAL: sekundes
MINUTE_PLURAL: minūtes
HOUR_PLURAL: stundas
DAY_PLURAL: dienas
WEEK_PLURAL: nedēļas
MONTH_PLURAL: mēneši
YEAR_PLURAL: gadi
DECADE_PLURAL: desmitgades
SEC_PLURAL: s
MIN_PLURAL: m
HR_PLURAL: st.
WK_PLURAL: ned.
MO_PLURAL: mēn.
YR_PLURAL: g.
DEC_PLURAL: d
FORM:
VALIDATION_FAIL: '<b>Validācija neizdevās:</b>'
INVALID_INPUT: 'Nederīga ievade'
MISSING_REQUIRED_FIELD: 'Laukā trūkst datu'
XSS_ISSUES: "Atrastas iespējamas XSS problēmas laukā '%s'"
MONTHS_OF_THE_YEAR:
- 'Janvāris'
- 'Februāris'
- 'Marts'
- 'Aprīlis'
- 'Maijs'
- 'Jūnijs'
- 'Jūlijs'
- 'Augusts'
- 'Septembris'
- 'Oktobris'
- 'Novembris'
- 'Decembris'
DAYS_OF_THE_WEEK:
- 'Pirmdiena'
- 'Otrdiena'
- 'Trešdiena'
- 'Ceturtdiena'
- 'Piektdiena'
- 'Sestdiena'
- 'Svētdiena'
YES: "Jā"
NO: "Nē"
CRON:
EVERY: katru
EVERY_HOUR: katru stundu
EVERY_MINUTE: katru minūti
EVERY_DAY_OF_WEEK: katru nedēļas dienu
EVERY_DAY_OF_MONTH: katru mēneša dienu
EVERY_MONTH: katru mēnesi
TEXT_PERIOD: Katru <b />
ERROR1: Marķieris %s nav atbalstīts!
ERROR2: Nederīgs elementu skaits
ERROR3: jquery_element nevajadzētu definēt jqCron iestatījumos
ERROR4: Neatpazīta izteiksme

147
system/languages/my.yaml Normal file
View File

@@ -0,0 +1,147 @@
---
GRAV:
FRONTMATTER_ERROR_PAGE: "---\nခေါင်းစဥ်: %1$s\n---\n\n# အမှား - Frontmatter မမှန်ကန်ပါ\n\nလမ်းကြောင်း `%2$s`\n\n**%3$s**\n\n```\n%4$s\n```"
INFLECTOR_PLURALS:
'/(quiz)$/i': '\1zes'
'/^(ox)$/i': '\1en'
'/([m|l])ouse$/i': '\1ice'
'/(matr|vert|ind)ix|ex$/i': '\1ices'
'/(x|ch|ss|sh)$/i': '\1es'
'/([^aeiouy]|qu)ies$/i': '\1y'
'/([^aeiouy]|qu)y$/i': '\1ies'
'/(hive)$/i': '\1s'
'/(?:([^f])fe|([lr])f)$/i': '\1\2ves'
'/sis$/i': 'ses'
'/([ti])um$/i': '\1a'
'/(buffal|tomat)o$/i': '\1oes'
'/(bu)s$/i': '\1ses'
'/(alias|status)/i': '\1es'
'/(octop|vir)us$/i': '\1i'
'/(ax|test)is$/i': '\1es'
'/s$/i': 's'
'/$/': 's'
INFLECTOR_SINGULAR:
'/(quiz)zes$/i': '\1'
'/(matr)ices$/i': '\1ix'
'/(vert|ind)ices$/i': '\1ex'
'/^(ox)en/i': '\1'
'/(alias|status)es$/i': '\1'
'/([octop|vir])i$/i': '\1us'
'/(cris|ax|test)es$/i': '\1is'
'/(shoe)s$/i': '\1'
'/(o)es$/i': '\1'
'/(bus)es$/i': '\1'
'/([m|l])ice$/i': '\1ouse'
'/(x|ch|ss|sh)es$/i': '\1'
'/(m)ovies$/i': '\1ovie'
'/(s)eries$/i': '\1eries'
'/([^aeiouy]|qu)ies$/i': '\1y'
'/([lr])ves$/i': '\1f'
'/(tive)s$/i': '\1'
'/(hive)s$/i': '\1'
'/([^f])ves$/i': '\1fe'
'/(^analy)ses$/i': '\1sis'
'/((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$/i': '\1\2sis'
'/([ti])a$/i': '\1um'
'/(n)ews$/i': '\1ews'
INFLECTOR_UNCOUNTABLE:
- 'ကိရိယာ'
- 'အချက်အလက်'
- 'ဆန်'
- 'ငွေ'
- 'မျိုးစိတ်'
- 'အတွဲများ'
- 'ငါး'
- 'သိုးများ'
INFLECTOR_IRREGULAR:
'person': 'လူ'
'man': 'ယောက်ျား'
'child': 'ကလေးများ'
'sex': 'လိင်'
'move': 'ရွှေ့ခြင်း'
INFLECTOR_ORDINALS:
'default': 'th'
'first': 'st'
'second': 'nd'
'third': 'rd'
NICETIME:
NO_DATE_PROVIDED: နေ့စွဲ မသတ်မှတ်ထား
BAD_DATE: ရက်စွဲမမှန်ပါ
AGO: လွန်ခဲ့တဲ့
FROM_NOW: ယခုမှ
JUST_NOW: အခုပဲ
SECOND: ဒုတိယ
MINUTE: မိနစ်
HOUR: နာရီ
DAY: နေ့
WEEK: တစ်ပတ်
MONTH:
YEAR: နှစ်
DECADE: ဆယ်စုနှစ်
SEC: စက္ကန့်
MIN: မိနစ်
HR: နာရီ
WK: တစ်ပတ်
MO:
YR: နှစ်
DEC: ဒီဇင်ဘာ
SECOND_PLURAL: စက္ကန့်
MINUTE_PLURAL: မိနစ်
HOUR_PLURAL: နာရီ
DAY_PLURAL: နေ့
WEEK_PLURAL: ရက်သတ္တပတ်
MONTH_PLURAL:
YEAR_PLURAL: နှစ်
DECADE_PLURAL: ဆယ်စုနှစ်များစွ
SEC_PLURAL: စက္ကန့်
MIN_PLURAL: မိနစ်
HR_PLURAL: နာရီ
WK_PLURAL: အပတ်
MO_PLURAL:
YR_PLURAL: နှစ်
DEC_PLURAL: ဆယ်စုနှစ်
FORM:
VALIDATION_FAIL: '<b> အတည်ပြုခြင်းမအောင်မြင်ပါ: </b>'
INVALID_INPUT: 'ထည့်သွင်းမှုမမှန်ပါ'
MISSING_REQUIRED_FIELD: 'လိုအပ်သောအကွက်ပျောက်နေသည်'
XSS_ISSUES: "XSS ပြဿနာ ဖြစ်နိုင်ချေ ကို '%s' အကွက်တွင် တွေ့"
MONTHS_OF_THE_YEAR:
- 'ဇန်နဝါရီ'
- 'ဖေဖော်ဝါရီ'
- 'မတ်'
- 'ဧပြီ'
- 'မေ'
- 'ဇွန်'
- 'ဇူလိုင်'
- 'သြဂုတ်'
- 'စက်တင်ဘာ'
- 'အောက်တိုဘာ'
- 'နိုဝင်ဘာ'
- 'ဒီဇင်ဘာ'
DAYS_OF_THE_WEEK:
- 'တနင်္လာ'
- ' အင်္ဂါ'
- 'ဗုဒ္ဓဟူး'
- 'ကြာသပတေး'
- 'သောကြာ'
- 'စနေ'
- 'တနင်္ဂနွေ'
YES: "လုပ်"
NO: "မလုပ်"
CRON:
EVERY: အမြဲတမ်း
EVERY_HOUR: နာရီတိုင်း
EVERY_MINUTE: မိနစ်တိုင်း
EVERY_DAY_OF_WEEK: တစ်ပတ်လုံး နေ့တိုင်း
EVERY_DAY_OF_MONTH: တစ်လလုံး နေ့တိုင်း
EVERY_MONTH: လစဉ်လတိုင်း
TEXT_PERIOD: </b>တိုင်း
TEXT_MINS: 'နာရီ ကျော်ပြီး <b /> မိနစ် တွင်'
TEXT_TIME: ' <b />:<b /> တွင် '
TEXT_DOW: '<b /> ပေါ်တွင် '
TEXT_MONTH: '<b />၏ '
TEXT_DOM: '<b /> တွင် '
ERROR1: ဤ %s တက် ကိုပံ့ပိုးမထားပါ။
ERROR2: လိုအပ်သောထည့်သွင်း နာပတ် အမှားဖြစ်နေသည်
ERROR3: jquery_element ကို jqCron ဆက်တင် တွင်ထားရမည်
ERROR4: အသိအမှတ်မပြုသော အသုံးအနှုန်း

View File

@@ -104,6 +104,7 @@ GRAV:
VALIDATION_FAIL: '<b>Validatie mislukt:</b>'
INVALID_INPUT: 'Ongeldige invoer in'
MISSING_REQUIRED_FIELD: 'Ontbrekend verplicht veld:'
XSS_ISSUES: "Mogelijke XSS-problemen ontdekt in '%s' veld"
MONTHS_OF_THE_YEAR:
- 'Januari'
- 'Februari'
@@ -125,6 +126,8 @@ GRAV:
- 'Vrijdag'
- 'Zaterdag'
- 'Zondag'
YES: "Ja"
NO: "Nee"
CRON:
EVERY: elke
EVERY_HOUR: elk uur

View File

@@ -6,10 +6,10 @@ GRAV:
INFLECTOR_UNCOUNTABLE:
- 'wyposażenie'
- 'informacja'
- 'rice'
- ''
- 'pieniądze'
- 'species'
- 'series'
- ''
- ''
- 'ryba'
- 'owca'
INFLECTOR_IRREGULAR:

View File

@@ -67,7 +67,7 @@ GRAV:
NICETIME:
NO_DATE_PROVIDED: Nenhuma data fornecida
BAD_DATE: Data inválida
AGO: atrás
AGO:
FROM_NOW: a partir de agora
JUST_NOW: mesmo agora
SECOND: segundo

View File

@@ -1,6 +1,16 @@
---
GRAV:
FRONTMATTER_ERROR_PAGE: "---\ntitle: %1$s\n---\n\n# Ошибка: недопустимое содержимое Frontmatter\n\nПуть: `%2$s`\n\n**%3$s**\n\n```\n%4$s\n```"
INFLECTOR_SINGULAR:
'/([octop|vir])i$/i': '\1us'
'/(cris|ax|test)es$/i': '\1is'
'/(shoe)s$/i': '\1'
'/([lr])ves$/i': '\1f'
'/(tive)s$/i': "\\1\n"
'/(hive)s$/i': '\1'
'/([^f])ves$/i': '\1fe'
'/(^analy)ses$/i': '\1sis'
'/((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$/i': '\1\2sis'
INFLECTOR_UNCOUNTABLE:
- 'экипировка'
- 'информация'

View File

@@ -1,9 +1,120 @@
---
GRAV:
FRONTMATTER_ERROR_PAGE: "---\nමාතෘකාව: %1$s\n---\n\n# දෝෂය: වලංගු නොවන ඉදිරිපස\n\nමාර්ගය: `%2$s`\n\n**%3$s**\n\n```\n%4$s\n```"
INFLECTOR_PLURALS:
'/([m|l])ouse$/i': '\1අයිස්'
'/(matr|vert|ind)ix|ex$/i': '\1අයිස්'
'/(?:([^f])fe|([lr])f)$/i': '\1\2වෙස්'
'/([ti])um$/i': '\1අ'
'/(buffal|tomat)o$/i': '\1ඕඑස්'
'/(bu)s$/i': '\1සෙස්'
INFLECTOR_SINGULAR:
'/(quiz)zes$/i': '\1'
'/^(ox)en/i': '\1'
'/(alias|status)es$/i': '\1'
'/([octop|vir])i$/i': '\1 අප'
'/(cris|ax|test)es$/i': '\1 වේ'
'/(o)es$/i': '\1'
'/(bus)es$/i': '\1'
'/([m|l])ice$/i': '\1 භාවිතා කරන්න'
'/(x|ch|ss|sh)es$/i': '\1'
'/(m)ovies$/i': '\1ඕවී'
'/(s)eries$/i': '\1මාලා'
'/(^analy)ses$/i': '\1සිස්'
'/((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$/i': '\1\2සිස්'
'/([ti])a$/i': '\1ම්'
INFLECTOR_UNCOUNTABLE:
- 'උපකරණ'
- 'විස්තර'
- 'සහල්'
- 'මුදල'
- 'විශේෂ'
- 'මාලාවක්'
- 'මාළු'
- 'බැටළුවන්'
INFLECTOR_IRREGULAR:
'person': 'මහජන'
'man': 'මිනිසුන්'
'child': 'දරුවන්'
'sex': 'ලිංගිකත්වය'
'move': 'චලනය කරයි'
INFLECTOR_ORDINALS:
'first': 'ශාන්ත'
NICETIME:
NO_DATE_PROVIDED: දිනයක් සපයා නැත
BAD_DATE: නරක දිනය
AGO: පෙර
FROM_NOW: මෙතැන් සිට
JUST_NOW: මේ දැන්
SECOND: දෙවැනි
MINUTE: මිනිත්තුව
HOUR: පැය
DAY: දින
WEEK: සතිය
MONTH: මස
YEAR: වර්ෂය
DECADE: දශකය
SEC: තත්පර
MIN: මිනි
HR: පැය
YR: වසර
DEC: දෙසැ
SECOND_PLURAL: තත්පර
MINUTE_PLURAL: මිනිත්තු
HOUR_PLURAL: පැය
DAY_PLURAL: දින
WEEK_PLURAL: සති
MONTH_PLURAL: මාස
YEAR_PLURAL: වසර
DECADE_PLURAL: දශක
SEC_PLURAL: තත්පර
MIN_PLURAL: මිනිත්තු
HR_PLURAL: පැය
WK_PLURAL: සති
YR_PLURAL: වසර
DEC_PLURAL: දෙසැ
FORM:
VALIDATION_FAIL: '<b>වලංගු කිරීම අසාර්ථක විය:</b>'
INVALID_INPUT: 'වලංගු නොවන ආදානය'
MISSING_REQUIRED_FIELD: 'අවශ්‍ය ක්ෂේත්‍රය අස්ථානගත වී ඇත:'
XSS_ISSUES: "විභව XSS ගැටළු '%s' ක්ෂේත්‍රයේ අනාවරණය විය"
MONTHS_OF_THE_YEAR:
- 'ජනවාරි'
- 'පෙබරවාරි'
- 'මාර්තු'
- 'අප්රේල්'
- 'මැයි'
- 'ජූනි'
- 'ජුලි'
- 'අගෝස්තු'
- 'සැප්තැම්බර්'
- 'ඔක්තෝම්බර්'
- 'නොවැම්බර්'
- 'දෙසැම්බර්'
DAYS_OF_THE_WEEK:
- 'සඳුදා'
- 'අඟහරුවාදා'
- 'බදාදා'
- 'බ්රහස්පතින්දා'
- 'සිකුරාදා'
- 'සෙනසුරාදා'
- 'ඉරිදා'
YES: "ඔව්"
NO: "නැත"
CRON:
EVERY: සෑම
EVERY_HOUR: සෑම පැයකටම
EVERY_MINUTE: සෑම විනාඩියකටම
EVERY_DAY_OF_WEEK: සතියේ සෑම දිනකම
EVERY_DAY_OF_MONTH: මාසයේ සෑම දිනකම
EVERY_MONTH: සෑම මාසයකම
TEXT_PERIOD: සෑම <b />
TEXT_MINS: ' පැයට පසු විනාඩි <b /> කින්'
TEXT_TIME: ' <b />:<b />ට'
TEXT_DOW: ' <b />මත'
TEXT_MONTH: ' <b />'
TEXT_DOM: ' <b />මත'
ERROR1: ටැගය %s සහාය නොදක්වයි!
ERROR2: නරක මූලද්රව්ය සංඛ්යාව
ERROR3: jquery_element jqCron සැකසුම් වලට සැකසිය යුතුය
ERROR4: හඳුනා නොගත් ප්‍රකාශනය

View File

@@ -1,6 +1,17 @@
---
GRAV:
FRONTMATTER_ERROR_PAGE: "---\ntitle: %1$s\n---\n\n# Napaka: Neveljavna Frontmatter\n\nPath: `%2$s`\n\n**%3$s ** \n\n```\n%4$s \n```"
INFLECTOR_UNCOUNTABLE:
- 'oprema'
- 'informacija'
- 'riž'
- 'denar'
- 'vrste'
- 'serija'
- 'riba'
- 'ovca'
INFLECTOR_IRREGULAR:
'person': 'ljudje'
NICETIME:
NO_DATE_PROVIDED: Datum ni na voljo
BAD_DATE: Neveljaven datum
@@ -43,15 +54,15 @@ GRAV:
- 'Januar'
- 'Februar'
- 'Marec'
- 'April'
- 'april'
- 'Maj'
- 'Junij'
- 'Julij'
- 'Avgust'
- 'September'
- 'september'
- 'Oktober'
- 'November'
- 'December'
- 'november'
- 'december'
DAYS_OF_THE_WEEK:
- 'Ponedeljek'
- 'Torek'
@@ -60,3 +71,15 @@ GRAV:
- 'Petek'
- 'Sobota'
- 'Nedelja'
YES: "Da"
NO: "Ne"
CRON:
EVERY: vsak
EVERY_HOUR: vsako uro
EVERY_MINUTE: vsako minuto
EVERY_DAY_OF_WEEK: vsak dan v tednu
EVERY_DAY_OF_MONTH: vsak dan v mesecu
EVERY_MONTH: vsak mesec
ERROR1: Oznaka %s ni podprta!
ERROR2: Napačno število elementov.
ERROR4: Neznan izraz

View File

@@ -104,6 +104,7 @@ GRAV:
VALIDATION_FAIL: '<b>Провера неуспела:</b>'
INVALID_INPUT: 'Неисправан унос у'
MISSING_REQUIRED_FIELD: 'Недостаје обавезн поље:'
XSS_ISSUES: "Потенцијална грешка у XSS-у детектована у пољу '%s' "
MONTHS_OF_THE_YEAR:
- 'Јануар'
- 'Фебруар'
@@ -125,6 +126,8 @@ GRAV:
- 'Петак'
- 'Субота'
- 'Недеља'
YES: "Да"
NO: "Не"
CRON:
EVERY: сваки
EVERY_HOUR: сваки сат

147
system/languages/sw.yaml Normal file
View File

@@ -0,0 +1,147 @@
---
GRAV:
FRONTMATTER_ERROR_PAGE: "---\nkichwa: %1$s\n---\n\n# Kosa: Mbele ya Mbele\n\nNjia: `%2$s`\n\n**%3$s**\n\n```\n%4$s\n```"
INFLECTOR_PLURALS:
'/(quiz)$/i': '\1zes'
'/^(ox)$/i': '\1en'
'/([m|l])ouse$/i': '\1ice'
'/(matr|vert|ind)ix|ex$/i': '\1ices'
'/(x|ch|ss|sh)$/i': '\1es'
'/([^aeiouy]|qu)ies$/i': '\1y'
'/([^aeiouy]|qu)y$/i': '\1ies'
'/(hive)$/i': '\1s'
'/(?:([^f])fe|([lr])f)$/i': '\1\2ves'
'/sis$/i': 'ses'
'/([ti])um$/i': '\1a'
'/(buffal|tomat)o$/i': '\1oes'
'/(bu)s$/i': '\1ses'
'/(alias|status)/i': '\1es'
'/(octop|vir)us$/i': '\1i'
'/(ax|test)is$/i': '\1es'
'/s$/i': 's'
'/$/': 's'
INFLECTOR_SINGULAR:
'/(quiz)zes$/i': '\1'
'/(matr)ices$/i': '\1ix'
'/(vert|ind)ices$/i': '\1ex'
'/^(ox)en/i': '\1'
'/(alias|status)es$/i': '\1'
'/([octop|vir])i$/i': '\1us'
'/(cris|ax|test)es$/i': '\1is'
'/(shoe)s$/i': '\1'
'/(o)es$/i': '\1'
'/(bus)es$/i': '\1'
'/([m|l])ice$/i': '\1ouse'
'/(x|ch|ss|sh)es$/i': '\1'
'/(m)ovies$/i': '\1ovie'
'/(s)eries$/i': '\1eries'
'/([^aeiouy]|qu)ies$/i': '\1y'
'/([lr])ves$/i': '\1f'
'/(tive)s$/i': '\1'
'/(hive)s$/i': '\1'
'/([^f])ves$/i': '\1fe'
'/(^analy)ses$/i': '\1sis'
'/((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$/i': '\1\2sis'
'/([ti])a$/i': '\1um'
'/(n)ews$/i': '\1ews'
INFLECTOR_UNCOUNTABLE:
- 'vifaa'
- 'habari'
- 'mchele'
- 'pesa'
- 'spishi'
- 'mfululizo'
- 'samaki'
- 'kondoo'
INFLECTOR_IRREGULAR:
'person': 'watu'
'man': 'wanaume'
'child': 'watoto'
'sex': 'jinsia'
'move': 'songa'
INFLECTOR_ORDINALS:
'default': 'th'
'first': 'st'
'second': 'nd'
'third': 'rd'
NICETIME:
NO_DATE_PROVIDED: Hakuna tarehe iliyotolewa
BAD_DATE: Tarehe mbaya
AGO: zilizopita
FROM_NOW: kuanzia sasa
JUST_NOW: sasa hivi
SECOND: pili
MINUTE: dakika
HOUR: saa
DAY: siku
WEEK: wiki
MONTH: mwezi
YEAR: mwaka
DECADE: muongo
SEC: sec
MIN: min
HR: hr
WK: wk
MO: mo
YR: yr
DEC: dec
SECOND_PLURAL: sekunde
MINUTE_PLURAL: dakika
HOUR_PLURAL: masaa
DAY_PLURAL: siku
WEEK_PLURAL: wiki
MONTH_PLURAL: miezi
YEAR_PLURAL: miaka
DECADE_PLURAL: miongo
SEC_PLURAL: secs
MIN_PLURAL: mins
HR_PLURAL: hrs
WK_PLURAL: wks
MO_PLURAL: mos
YR_PLURAL: yrs
DEC_PLURAL: decs
FORM:
VALIDATION_FAIL: '<b> Uthibitishaji umeshindwa: </b>'
INVALID_INPUT: 'Ingizo batili katika'
MISSING_REQUIRED_FIELD: 'Sehemu inayokosekana inahitajika:'
XSS_ISSUES: "Masuala yanayowezekana ya XSS yamegunduliwa katika uwanja wa '% s"
MONTHS_OF_THE_YEAR:
- 'Januari'
- 'Februari'
- 'Machi'
- 'Aprili'
- 'Mei'
- 'Juni'
- 'Julai'
- 'Agosti'
- 'Septemba'
- 'Oktoba'
- 'Novemba'
- 'Desemba'
DAYS_OF_THE_WEEK:
- 'Jumatatu'
- 'Jumanne'
- 'Jumatano'
- 'Alhamisi'
- 'Ijumaa'
- 'Jumamosi'
- 'Jumapili'
YES: "Ndiyo"
NO: "Hapana"
CRON:
EVERY: kila
EVERY_HOUR: kila saa
EVERY_MINUTE: kila dakika
EVERY_DAY_OF_WEEK: kila siku ya juma
EVERY_DAY_OF_MONTH: kila siku ya mwezi
EVERY_MONTH: kila mwezi
TEXT_PERIOD: Kila <b />
TEXT_MINS: ' saa <b /> dakika (saa) zilizopita saa'
TEXT_TIME: ' saa <b />: <b />'
TEXT_DOW: ' kwenye <b />'
TEXT_MONTH: ' ya <b />'
TEXT_DOM: ' kwenye <b />'
ERROR1: Lebo% s haitumiki!
ERROR2: Idadi mbaya ya vitu
ERROR3: Jquery_element inapaswa kuwekwa kwenye mipangilio ya jqCron
ERROR4: Maneno yasiyotambulika

View File

@@ -1,11 +1,75 @@
---
GRAV:
FRONTMATTER_ERROR_PAGE: "---\nชื่อเรื่อง: %1$s\n---\n\n# ข้อผิดพลาด: Invalid Frontmatter\n\nPath: `%2$s`\n\n**%3$s**\n\n```\n%4$s\n```"
FRONTMATTER_ERROR_PAGE: "---\ntitle: %1$s\n---\n\n# Error: Invalid Frontmatter\n\nPath: `%2$s`\n\n**%3$s**\n\n```\n%4$s\n```"
INFLECTOR_PLURALS:
'/(quiz)$/i': '\1zes'
'/^(ox)$/i': '\1en'
'/([m|l])ouse$/i': '\1ice'
'/(matr|vert|ind)ix|ex$/i': '\1ices'
'/(x|ch|ss|sh)$/i': '\1es'
'/([^aeiouy]|qu)ies$/i': '\1y'
'/([^aeiouy]|qu)y$/i': '\1ies'
'/(hive)$/i': '\1s'
'/(?:([^f])fe|([lr])f)$/i': '\1\2ves'
'/sis$/i': 'ses'
'/([ti])um$/i': '\1a'
'/(buffal|tomat)o$/i': '\1oes'
'/(bu)s$/i': '\1ses'
'/(alias|status)/i': '\1es'
'/(octop|vir)us$/i': '\1i'
'/(ax|test)is$/i': '\1es'
'/s$/i': 's'
'/$/': 's'
INFLECTOR_SINGULAR:
'/(quiz)zes$/i': '\1'
'/(matr)ices$/i': '\1ix'
'/(vert|ind)ices$/i': '\1ex'
'/^(ox)en/i': '\1'
'/(alias|status)es$/i': '\1'
'/([octop|vir])i$/i': '\1us'
'/(cris|ax|test)es$/i': '\1is'
'/(shoe)s$/i': '\1'
'/(o)es$/i': '\1'
'/(bus)es$/i': '\1'
'/([m|l])ice$/i': '\1ouse'
'/(x|ch|ss|sh)es$/i': '\1'
'/(m)ovies$/i': '\1ovie'
'/(s)eries$/i': '\1eries'
'/([^aeiouy]|qu)ies$/i': '\1y'
'/([lr])ves$/i': '\1f'
'/(tive)s$/i': '\1'
'/(hive)s$/i': '\1'
'/([^f])ves$/i': '\1fe'
'/(^analy)ses$/i': '\1sis'
'/((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$/i': '\1\2sis'
'/([ti])a$/i': '\1um'
'/(n)ews$/i': '\1ews'
INFLECTOR_UNCOUNTABLE:
- 'อุปกรณ์'
- 'ข้อมูล'
- 'ข้าว'
- 'เงิน'
- 'สายพันธุ์'
- 'ซีรีส์'
- 'ปลา'
- 'แกะ'
INFLECTOR_IRREGULAR:
'person': 'คน'
'man': 'ผู้ชาย'
'child': 'เด็กเด็ก'
'sex': 'เพศ'
'move': 'ย้าย'
INFLECTOR_ORDINALS:
'default': 'th'
'first': 'st'
'second': 'nd'
'third': 'rd'
NICETIME:
NO_DATE_PROVIDED: ไม่มีวันที่ให้
BAD_DATE: รูปแบบวันที่ผิด
AGO: ที่ผ่านมา
FROM_NOW: จากตอนนี้
JUST_NOW: เมื่อกี้
SECOND: วินาที
MINUTE: นาที
HOUR: ชั่วโมง
@@ -17,6 +81,10 @@ GRAV:
SEC: วิ
MIN: นาที
HR: ชม.
WK: wk
MO: mo
YR: yr
DEC: dec
SECOND_PLURAL: วินาที
MINUTE_PLURAL: นาที
HOUR_PLURAL: ชั่วโมง
@@ -28,11 +96,15 @@ GRAV:
SEC_PLURAL: วินาที
MIN_PLURAL: นาที
HR_PLURAL: ชั่วโมง
WK_PLURAL: wks
MO_PLURAL: mos
YR_PLURAL: ปี
DEC_PLURAL: decs
FORM:
VALIDATION_FAIL: '<b>ตรวจสอบล้มเหลว: </b>'
INVALID_INPUT: 'ป้อนข้อมูลไม่ถูกต้องใน'
MISSING_REQUIRED_FIELD: 'ขาดข้อมูลที่จำเป็น:'
XSS_ISSUES: "ตรวจพบปัญหา XSS ที่เป็นไปได้ในฟิลด์ '%s'"
MONTHS_OF_THE_YEAR:
- 'มกราคม'
- 'กุมภาพันธ์'
@@ -54,3 +126,22 @@ GRAV:
- 'ศุกร์'
- 'เสาร์'
- 'อาทิตย์'
YES: "ใช่"
NO: "ไม่"
CRON:
EVERY: ทุก ๆ
EVERY_HOUR: ทุกชั่วโมง
EVERY_MINUTE: ทุกนาที
EVERY_DAY_OF_WEEK: ทุกวันในสัปดาห์
EVERY_DAY_OF_MONTH: ทุกวันของเดือน
EVERY_MONTH: ทุกเดือน
TEXT_PERIOD: ทุก ๆ <b />
TEXT_MINS: ' ที่ <b /> นาทีที่ผ่านไปแล้ว'
TEXT_TIME: ' เวลา <b />:<b />'
TEXT_DOW: ' บน <b />'
TEXT_MONTH: ' จาก <b />'
TEXT_DOM: ' บน <b />'
ERROR1: ไม่รองรับแท็ก %s!
ERROR2: จำนวนองค์ประกอบไม่ดี
ERROR3: ควรตั้งค่า jquery_element เป็นการตั้งค่า jqCron
ERROR4: นิพจน์ที่ไม่รู้จัก

View File

@@ -125,6 +125,8 @@ GRAV:
- '星期五'
- '星期六'
- '星期日'
YES: "是"
NO: "否"
CRON:
EVERY: 每隔
EVERY_HOUR: 每小时

View File

@@ -62,6 +62,8 @@ GRAV:
- '星期五'
- '星期六'
- '星期日'
YES: "是"
NO: "否"
CRON:
EVERY:
EVERY_HOUR: 每小時

View File

@@ -125,6 +125,8 @@ GRAV:
- '星期五'
- '星期六'
- '星期日'
YES: "是"
NO: "否"
CRON:
EVERY: 每隔
EVERY_HOUR: 每小时

16
system/rector.php Normal file
View File

@@ -0,0 +1,16 @@
<?php
use Rector\Config\RectorConfig;
return RectorConfig::configure()
->withSkip([
__DIR__ . '/vendor',
])
->withPaths([
__DIR__
])
->withPhpSets(php82: true)
->withPhpVersion(Rector\ValueObject\PhpVersion::PHP_84)
->withRules([
Rector\Php84\Rector\Param\ExplicitNullableParamTypeRector::class,
]);

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Core
*
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2025 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/
@@ -18,17 +18,17 @@ $path = $_SERVER['SCRIPT_NAME'];
if ($path !== '/index.php' && is_file($root . $path)) {
if (!(
// Block all direct access to files and folders beginning with a dot
strpos($path, '/.') !== false
str_contains((string) $path, '/.')
// Block all direct access for these folders
|| preg_match('`^/(\.git|cache|bin|logs|backup|webserver-configs|tests)/`ui', $path)
|| preg_match('`^/(\.git|cache|bin|logs|backup|webserver-configs|tests)/`ui', (string) $path)
// Block access to specific file types for these system folders
|| preg_match('`^/(system|vendor)/(.*)\.(txt|xml|md|html|json|yaml|yml|php|pl|py|cgi|twig|sh|bat)$`ui', $path)
|| preg_match('`^/(system|vendor)/(.*)\.(txt|xml|md|html|json|yaml|yml|php|pl|py|cgi|twig|sh|bat)$`ui', (string) $path)
// Block access to specific file types for these user folders
|| preg_match('`^/(user)/(.*)\.(txt|md|json|yaml|yml|php|pl|py|cgi|twig|sh|bat)$`ui', $path)
|| preg_match('`^/(user)/(.*)\.(txt|md|json|yaml|yml|php|pl|py|cgi|twig|sh|bat)$`ui', (string) $path)
// Block all direct access to .md files
|| preg_match('`\.md$`ui', $path)
|| preg_match('`\.md$`ui', (string) $path)
// Block access to specific files in the root folder
|| preg_match('`^/(LICENSE\.txt|composer\.lock|composer\.json|\.htaccess)$`ui', $path)
|| preg_match('`^/(LICENSE\.txt|composer\.lock|composer\.json|\.htaccess)$`ui', (string) $path)
)) {
return false;
}

View File

@@ -0,0 +1,93 @@
<?php
namespace Doctrine\Common\Cache;
use Symfony\Component\Cache\Adapter\FilesystemAdapter;
/**
* Filesystem cache driver (backwards compatibility).
*/
class FilesystemCache extends CacheProvider
{
public const EXTENSION = '.doctrinecache.data';
/** @var FilesystemAdapter */
private $pool;
/**
* {@inheritdoc}
*/
public function __construct($directory, $extension = self::EXTENSION, $umask = 0002)
{
user_error(self::class . ' is deprecated since Grav 1.8, use Symfony cache instead', E_USER_DEPRECATED);
$this->pool = new FilesystemAdapter('', 0, $directory);
}
/**
* {@inheritdoc}
*/
protected function doFetch($id)
{
$item = $this->pool->getItem(rawurlencode($id));
return $item->isHit() ? $item->get() : false;
}
/**
* {@inheritdoc}
*
* @return bool
*/
protected function doContains($id)
{
return $this->pool->hasItem(rawurlencode($id));
}
/**
* {@inheritdoc}
*
* @return bool
*/
protected function doSave($id, $data, $lifeTime = 0)
{
$item = $this->pool->getItem(rawurlencode($id));
if (0 < $lifeTime) {
$item->expiresAfter($lifeTime);
}
return $this->pool->save($item->set($data));
}
/**
* {@inheritdoc}
*
* @return bool
*/
protected function doDelete($id)
{
return $this->pool->deleteItem(rawurlencode($id));
}
/**
* {@inheritdoc}
*
* @return bool
*/
protected function doFlush()
{
return $this->pool->clear();
}
/**
* {@inheritdoc}
*
* @return array|null
*/
protected function doGetStats()
{
return null;
}
}

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Common
*
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2025 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/
@@ -194,12 +194,12 @@ class Assets extends PropertyObject
}
$params = array_merge([$location], $params);
call_user_func_array([$this, 'add'], $params);
call_user_func_array($this->add(...), $params);
}
} elseif (isset($this->collections[$asset])) {
array_shift($args);
$args = array_merge([$this->collections[$asset]], $args);
call_user_func_array([$this, 'add'], $args);
call_user_func_array($this->add(...), $args);
} else {
// Get extension
$path = parse_url($asset, PHP_URL_PATH);
@@ -209,11 +209,11 @@ class Assets extends PropertyObject
if ($extension !== '') {
$extension = strtolower($extension);
if ($extension === 'css') {
call_user_func_array([$this, 'addCss'], $args);
call_user_func_array($this->addCss(...), $args);
} elseif ($extension === 'js') {
call_user_func_array([$this, 'addJs'], $args);
call_user_func_array($this->addJs(...), $args);
} elseif ($extension === 'mjs') {
call_user_func_array([$this, 'addJsModule'], $args);
call_user_func_array($this->addJsModule(...), $args);
}
}
}
@@ -261,14 +261,20 @@ class Assets extends PropertyObject
$default = 'before';
}
$options['position'] = $options['position'] ?? $default;
$options['position'] ??= $default;
}
unset($options['pipeline']);
}
// Add timestamp
$options['timestamp'] = $this->timestamp;
$timestamp_override = $options['timestamp'] ?? true;
if (filter_var($timestamp_override, FILTER_VALIDATE_BOOLEAN)) {
$options['timestamp'] = $this->timestamp;
} else {
$options['timestamp'] = null;
}
// Set order
$group = $options['group'] ?? 'head';
@@ -392,6 +398,9 @@ class Assets extends PropertyObject
if ($key === 'position' && $value === 'pipeline') {
$type = $asset->getType();
if ($type === 'jsmodule') {
$type = 'js_module';
}
if ($asset->getRemote() && $this->{strtolower($type) . '_pipeline_include_externals'} === false && $asset['position'] === 'pipeline') {
if ($this->{strtolower($type) . '_pipeline_before_excludes'}) {
@@ -423,9 +432,7 @@ class Assets extends PropertyObject
*/
protected function sortAssets($assets)
{
uasort($assets, static function ($a, $b) {
return $b['priority'] <=> $a['priority'] ?: $a['order'] <=> $b['order'];
});
uasort($assets, static fn($a, $b) => $b['priority'] <=> $a['priority'] ?: $a['order'] <=> $b['order']);
return $assets;
}
@@ -568,18 +575,11 @@ class Assets extends PropertyObject
*/
protected function getBaseType($type)
{
switch ($type) {
case $this::JS_TYPE:
case $this::INLINE_JS_TYPE:
$base_type = $this::JS;
break;
case $this::JS_MODULE_TYPE:
case $this::INLINE_JS_MODULE_TYPE:
$base_type = $this::JS_MODULE;
break;
default:
$base_type = $this::CSS;
}
$base_type = match ($type) {
$this::JS_TYPE, $this::INLINE_JS_TYPE => $this::JS,
$this::JS_MODULE_TYPE, $this::INLINE_JS_MODULE_TYPE => $this::JS_MODULE,
default => $this::CSS,
};
return $base_type;
}

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Common\Assets
*
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2025 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/
@@ -114,7 +114,7 @@ abstract class BaseAsset extends PropertyObject
// Do some special stuff for CSS/JS (not inline)
if (!Utils::startsWith($this->getType(), 'inline')) {
$this->base_url = rtrim($uri->rootUrl($config->get('system.absolute_urls')), '/') . '/';
$this->base_url = rtrim((string) $uri->rootUrl($config->get('system.absolute_urls')), '/') . '/';
$this->remote = static::isRemoteLink($asset);
// Move this to render?

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Common\Assets
*
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2025 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/
@@ -192,15 +192,15 @@ class BlockAssets
{
$grav = Grav::instance();
$base = rtrim($grav['base_url'], '/') ?: '/';
$base = rtrim((string) $grav['base_url'], '/') ?: '/';
if (strpos($url, $base) === 0) {
if (str_starts_with($url, $base)) {
if ($pipeline) {
// Remove file timestamp if CSS pipeline has been enabled.
$url = preg_replace('|[?#].*|', '', $url);
}
return substr($url, strlen($base) - 1);
return substr((string) $url, strlen($base) - 1);
}
return $url;
}

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Common\Assets
*
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2025 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Common\Assets
*
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2025 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Common\Assets
*
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2025 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Common\Assets
*
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2025 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Common\Assets
*
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2025 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Common\Assets
*
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2025 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Common\Assets
*
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2025 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Common\Assets
*
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2025 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/
@@ -34,7 +34,7 @@ class Pipeline extends PropertyObject
protected const JS_MODULE_ASSET = 3;
/** @const Regex to match CSS urls */
protected const CSS_URL_REGEX = '{url\(([\'\"]?)(.*?)\1\)}';
protected const CSS_URL_REGEX = '{url\(([\'\"]?)(.*?)\1\)|(@import)\s+([\'\"])(.*?)\4}';
/** @const Regex to match JS imports */
protected const JS_IMPORT_REGEX = '{import.+from\s?[\'|\"](.+?)[\'|\"]}';
@@ -257,9 +257,14 @@ class Pipeline extends PropertyObject
// Find any css url() elements, grab the URLs and calculate an absolute path
// Then replace the old url with the new one
$file = (string)preg_replace_callback(self::CSS_URL_REGEX, function ($matches) use ($dir, $local) {
$isImport = count($matches) > 3 && $matches[3] === '@import';
$old_url = $matches[2];
if ($isImport) {
$old_url = $matches[5];
} else {
$old_url = $matches[2];
}
// Ensure link is not rooted to web server, a data URL, or to a remote host
if (preg_match(self::FIRST_FORWARDSLASH_REGEX, $old_url) || Utils::startsWith($old_url, 'data:') || $this->isRemoteLink($old_url)) {
return $matches[0];
@@ -273,8 +278,12 @@ class Pipeline extends PropertyObject
$new_url = ($local ? $this->base_url : '') . $old_url;
return str_replace($matches[2], $new_url, $matches[0]);
}, $file);
if ($isImport) {
return str_replace($matches[5], $new_url, $matches[0]);
} else {
return str_replace($matches[2], $new_url, $matches[0]);
}
}, (string) $file);
return $file;
}

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Common\Assets\Traits
*
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2025 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/
@@ -55,7 +55,7 @@ trait AssetUtilsTrait
return false;
}
return (0 === strpos($link, 'http://') || 0 === strpos($link, 'https://') || 0 === strpos($link, '//'));
return (str_starts_with($link, 'http://') || str_starts_with($link, 'https://') || str_starts_with($link, '//'));
}
/**
@@ -76,18 +76,18 @@ trait AssetUtilsTrait
if (static::isRemoteLink($link)) {
$local = false;
if (0 === strpos($link, '//')) {
if (str_starts_with((string) $link, '//')) {
$link = 'http:' . $link;
}
$relative_dir = dirname($relative_path);
$relative_dir = dirname((string) $relative_path);
} else {
// Fix to remove relative dir if grav is in one
if (($this->base_url !== '/') && Utils::startsWith($relative_path, $this->base_url)) {
$base_url = '#' . preg_quote($this->base_url, '#') . '#';
$relative_path = ltrim(preg_replace($base_url, '/', $link, 1), '/');
$relative_path = ltrim((string) preg_replace($base_url, '/', (string) $link, 1), '/');
}
$relative_dir = dirname($relative_path);
$relative_dir = dirname((string) $relative_path);
$link = GRAV_ROOT . '/' . $relative_path;
}
@@ -101,7 +101,7 @@ trait AssetUtilsTrait
// Double check last character being
if ($type === self::JS_ASSET || $type === self::JS_MODULE_ASSET) {
$file = rtrim($file, ' ;') . ';';
$file = rtrim((string) $file, ' ;') . ';';
}
// If this is CSS + the file is local + rewrite enabled
@@ -113,7 +113,7 @@ trait AssetUtilsTrait
$file = $this->jsRewrite($file, $relative_dir, $local);
}
$file = rtrim($file) . PHP_EOL;
$file = rtrim((string) $file) . PHP_EOL;
$buffer .= $file;
}
@@ -170,9 +170,9 @@ trait AssetUtilsTrait
}
if (in_array($key, $no_key, true)) {
$element = htmlentities($value, ENT_QUOTES, 'UTF-8', false);
$element = htmlentities((string) $value, ENT_QUOTES, 'UTF-8', false);
} else {
$element = $key . '="' . htmlentities($value, ENT_QUOTES, 'UTF-8', false) . '"';
$element = $key . '="' . htmlentities((string) $value, ENT_QUOTES, 'UTF-8', false) . '"';
}
$html .= ' ' . $element;
@@ -191,7 +191,8 @@ trait AssetUtilsTrait
{
$querystring = '';
$asset = $asset ?? $this->asset;
$asset ??= $this->asset;
$attributes = $this->attributes;
if (!empty($this->query)) {
if (Utils::contains($asset, '?')) {

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Common\Assets\Traits
*
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2025 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/
@@ -113,7 +113,7 @@ trait LegacyAssetsTrait
*/
public function addAsyncJs($asset, $priority = 10, $pipeline = true, $group = 'head')
{
user_error(__CLASS__ . '::' . __FUNCTION__ . '() is deprecated since Grav 1.6, use dynamic method with [\'loading\' => \'async\']', E_USER_DEPRECATED);
user_error(self::class . '::' . __FUNCTION__ . '() is deprecated since Grav 1.6, use dynamic method with [\'loading\' => \'async\']', E_USER_DEPRECATED);
return $this->addJs($asset, $priority, $pipeline, 'async', $group);
}
@@ -130,7 +130,7 @@ trait LegacyAssetsTrait
*/
public function addDeferJs($asset, $priority = 10, $pipeline = true, $group = 'head')
{
user_error(__CLASS__ . '::' . __FUNCTION__ . '() is deprecated since Grav 1.6, use dynamic method with [\'loading\' => \'defer\']', E_USER_DEPRECATED);
user_error(self::class . '::' . __FUNCTION__ . '() is deprecated since Grav 1.6, use dynamic method with [\'loading\' => \'defer\']', E_USER_DEPRECATED);
return $this->addJs($asset, $priority, $pipeline, 'defer', $group);
}

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Common\Assets\Traits
*
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2025 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/
@@ -338,7 +338,7 @@ trait TestingAssetsTrait
$directory,
FilesystemIterator::SKIP_DOTS
)), $pattern);
$offset = strlen($ltrim);
$offset = strlen((string) $ltrim);
$files = [];
foreach ($iterator as $file) {

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Common\Backup
*
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2025 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/
@@ -54,7 +54,7 @@ class Backups
/** @var EventDispatcher $dispatcher */
$dispatcher = $grav['events'];
$dispatcher->addListener('onSchedulerInitialized', [$this, 'onSchedulerInitialized']);
$dispatcher->addListener('onSchedulerInitialized', $this->onSchedulerInitialized(...));
$grav->fireEvent('onBackupsInitialized', new Event(['backups' => $this]));
}
@@ -106,7 +106,7 @@ class Backups
{
$param_sep = Grav::instance()['config']->get('system.param_sep', ':');
$download = urlencode(base64_encode(Utils::basename($backup)));
$url = rtrim(Grav::instance()['uri']->rootUrl(true), '/') . '/' . trim(
$url = rtrim((string) Grav::instance()['uri']->rootUrl(true), '/') . '/' . trim(
$base_url,
'/'
) . '/task' . $param_sep . 'backup/download' . $param_sep . $download . '/admin-nonce' . $param_sep . Utils::getNonce('admin-form');
@@ -158,7 +158,7 @@ class Backups
static::$backups = [];
$grav = Grav::instance();
$backups_itr = new GlobIterator(static::$backup_dir . '/*.zip', FilesystemIterator::KEY_AS_FILENAME);
$backups_itr = new GlobIterator(static::$backup_dir . '/*.zip', FilesystemIterator::KEY_AS_FILENAME | \FilesystemIterator::SKIP_DOTS);
$inflector = $grav['inflector'];
$long_date_format = DATE_RFC2822;
@@ -194,7 +194,7 @@ class Backups
* @param callable|null $status
* @return string|null
*/
public static function backup($id = 0, callable $status = null)
public static function backup($id = 0, ?callable $status = null)
{
$grav = Grav::instance();
@@ -210,7 +210,7 @@ class Backups
$name = $grav['inflector']->underscorize($backup->name);
$date = date(static::BACKUP_DATE_FORMAT, time());
$filename = trim($name, '_') . '--' . $date . '.zip';
$filename = trim((string) $name, '_') . '--' . $date . '.zip';
$destination = static::$backup_dir . DS . $filename;
$max_execution_time = ini_set('max_execution_time', '600');
$backup_root = $backup->root;
@@ -218,7 +218,7 @@ class Backups
if ($locator->isStream($backup_root)) {
$backup_root = $locator->findResource($backup_root);
} else {
$backup_root = rtrim(GRAV_ROOT . $backup_root, '/');
$backup_root = rtrim(GRAV_ROOT . $backup_root, DS) ?: DS;
}
if (!$backup_root || !file_exists($backup_root)) {
@@ -315,7 +315,10 @@ class Backups
*/
protected static function convertExclude($exclude)
{
$lines = preg_split("/[\s,]+/", $exclude);
// Split by newlines, commas, or multiple spaces
$lines = preg_split("/[\r\n,]+|[\s]{2,}/", $exclude);
// Remove empty values and trim
$lines = array_filter(array_map('trim', $lines));
return array_map('trim', $lines, array_fill(0, count($lines), '/'));
}

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Common
*
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2025 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/
@@ -27,7 +27,7 @@ class Browser
{
try {
$this->useragent = parse_user_agent();
} catch (InvalidArgumentException $e) {
} catch (InvalidArgumentException) {
$this->useragent = parse_user_agent("Mozilla/5.0 (compatible; Unknown;)");
}
}

View File

@@ -3,14 +3,15 @@
/**
* @package Grav\Common
*
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2025 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/
namespace Grav\Common;
use DirectoryIterator;
use \Doctrine\Common\Cache as DoctrineCache;
use Doctrine\Common\Cache\CacheProvider;
use Doctrine\Common\Cache\Psr6\DoctrineProvider;
use Exception;
use Grav\Common\Config\Config;
use Grav\Common\Filesystem\Folder;
@@ -18,6 +19,12 @@ use Grav\Common\Scheduler\Scheduler;
use LogicException;
use Psr\SimpleCache\CacheInterface;
use RocketTheme\Toolbox\Event\Event;
use Symfony\Component\Cache\Adapter\AdapterInterface;
use Symfony\Component\Cache\Adapter\ApcuAdapter;
use Symfony\Component\Cache\Adapter\FilesystemAdapter;
use Symfony\Component\Cache\Adapter\MemcachedAdapter;
use Symfony\Component\Cache\Adapter\RedisAdapter;
use Symfony\Component\Cache\Psr16Cache;
use Symfony\Component\EventDispatcher\EventDispatcher;
use function dirname;
use function extension_loaded;
@@ -27,12 +34,11 @@ use function is_array;
/**
* The GravCache object is used throughout Grav to store and retrieve cached data.
* It uses DoctrineCache library and supports a variety of caching mechanisms. Those include:
* It uses Symfony library (adding backward compatibility to Doctrine Cache) and supports a variety of caching mechanisms. Those include:
*
* APCu
* RedisCache
* MemCache
* MemCacheD
* MemCached
* FileSystem
*/
class Cache extends Getters
@@ -49,7 +55,10 @@ class Cache extends Getters
/** @var Config $config */
protected $config;
/** @var DoctrineCache\CacheProvider */
/** @var AdapterInterface */
protected $adapter;
/** @var CacheProvider */
protected $driver;
/** @var CacheInterface */
@@ -70,6 +79,7 @@ class Cache extends Getters
protected static $standard_remove = [
'cache://twig/',
'cache://doctrine/',
'cache://grav/',
'cache://compiled/',
'cache://clockwork/',
'cache://validated-',
@@ -80,6 +90,7 @@ class Cache extends Getters
protected static $standard_remove_no_images = [
'cache://twig/',
'cache://doctrine/',
'cache://grav/',
'cache://compiled/',
'cache://clockwork/',
'cache://validated-',
@@ -142,14 +153,14 @@ class Cache extends Getters
// Cache key allows us to invalidate all cache on configuration changes.
$this->key = ($prefix ?: 'g') . '-' . $uniqueness;
$this->cache_dir = $grav['locator']->findResource('cache://doctrine/' . $uniqueness, true, true);
$this->cache_dir = $grav['locator']->findResource('cache://grav/' . $uniqueness, true, true);
$this->driver_setting = $this->config->get('system.cache.driver');
$this->driver = $this->getCacheDriver();
$this->driver->setNamespace($this->key);
$this->adapter = $this->getCacheAdapter();
$this->driver = $this->getCacheDriver($this->adapter);
/** @var EventDispatcher $dispatcher */
$dispatcher = Grav::instance()['events'];
$dispatcher->addListener('onSchedulerInitialized', [$this, 'onSchedulerInitialized']);
$dispatcher->addListener('onSchedulerInitialized', $this->onSchedulerInitialized(...));
}
/**
@@ -158,36 +169,82 @@ class Cache extends Getters
public function getSimpleCache()
{
if (null === $this->simpleCache) {
$cache = new \Grav\Framework\Cache\Adapter\DoctrineCache($this->driver, '', $this->getLifetime());
// Disable cache key validation.
$cache->setValidation(false);
$this->simpleCache = $cache;
$this->simpleCache = new Psr16Cache($this->adapter);
}
return $this->simpleCache;
}
/**
* Deletes the old out of date file-based caches
* Deletes old cache files based on age
*
* @return int
*/
public function purgeOldCache()
{
// Get the max age for cache files from config (default 30 days)
$max_age_days = $this->config->get('system.cache.purge_max_age_days', 30);
$max_age_seconds = $max_age_days * 86400; // Convert days to seconds
$now = time();
$count = 0;
// First, clean up old orphaned cache directories (not the current one)
$cache_dir = dirname($this->cache_dir);
$current = Utils::basename($this->cache_dir);
$count = 0;
foreach (new DirectoryIterator($cache_dir) as $file) {
$dir = $file->getBasename();
if ($dir === $current || $file->isDot() || $file->isFile()) {
continue;
}
Folder::delete($file->getPathname());
$count++;
// Check if directory is old and empty or very old (90+ days)
$dir_age = $now - $file->getMTime();
if ($dir_age > 7776000) { // 90 days
Folder::delete($file->getPathname());
$count++;
}
}
// Now clean up old cache files within the current cache directory
if (is_dir($this->cache_dir)) {
$iterator = new \RecursiveIteratorIterator(
new \RecursiveDirectoryIterator($this->cache_dir, \RecursiveDirectoryIterator::SKIP_DOTS),
\RecursiveIteratorIterator::CHILD_FIRST
);
foreach ($iterator as $file) {
if ($file->isFile()) {
$file_age = $now - $file->getMTime();
if ($file_age > $max_age_seconds) {
@unlink($file->getPathname());
$count++;
}
}
}
}
// Also clean up old files in compiled cache
$grav = Grav::instance();
$compiled_dir = $this->config->get('system.cache.compiled_dir', 'cache://compiled');
$compiled_path = $grav['locator']->findResource($compiled_dir, true);
if ($compiled_path && is_dir($compiled_path)) {
$iterator = new \RecursiveIteratorIterator(
new \RecursiveDirectoryIterator($compiled_path, \RecursiveDirectoryIterator::SKIP_DOTS),
\RecursiveIteratorIterator::CHILD_FIRST
);
foreach ($iterator as $file) {
if ($file->isFile()) {
$file_age = $now - $file->getMTime();
// Compiled files can be kept longer (60 days)
if ($file_age > ($max_age_seconds * 2)) {
@unlink($file->getPathname());
$count++;
}
}
}
}
return $count;
@@ -229,53 +286,42 @@ class Cache extends Getters
* If there is no config option for $driver in the config, or it's set to 'auto', it will
* pick the best option based on which cache extensions are installed.
*
* @return DoctrineCache\CacheProvider The cache driver to use
* @param string|null $namespace
* @param int|null $defaultLifetime
* @return AdapterInterface The cache driver to use
* @throws \RedisException
* @throws \Symfony\Component\Cache\Exception\CacheException
*/
public function getCacheDriver()
public function getCacheAdapter(?string $namespace = null, ?int $defaultLifetime = null): AdapterInterface
{
$setting = $this->driver_setting;
$setting = $this->driver_setting ?? 'auto';
$driver_name = 'file';
if (in_array($setting, ['apc', 'xcache', 'wincache', 'memcache'], true)) {
throw new LogicException(sprintf('Cache driver for %s has been removed, use auto, file, apcu or memcached instead!', $setting));
}
// CLI compatibility requires a non-volatile cache driver
if ($this->config->get('system.cache.cli_compatibility') && (
$setting === 'auto' || $this->isVolatileDriver($setting))) {
if ($this->config->get('system.cache.cli_compatibility') && ($setting === 'auto' || $this->isVolatileDriver($setting))) {
$setting = $driver_name;
}
if (!$setting || $setting === 'auto') {
if ($setting === 'auto' || $this->isVolatileDriver($setting)) {
if (extension_loaded('apcu')) {
$driver_name = 'apcu';
} elseif (extension_loaded('wincache')) {
$driver_name = 'wincache';
}
} else {
$driver_name = $setting;
}
$this->driver_name = $driver_name;
$namespace ??= $this->key;
$defaultLifetime ??= 0;
switch ($driver_name) {
case 'apc':
case 'apcu':
$driver = new DoctrineCache\ApcuCache();
break;
case 'wincache':
$driver = new DoctrineCache\WinCacheCache();
break;
case 'memcache':
if (extension_loaded('memcache')) {
$memcache = new \Memcache();
$memcache->connect(
$this->config->get('system.cache.memcache.server', 'localhost'),
$this->config->get('system.cache.memcache.port', 11211)
);
$driver = new DoctrineCache\MemcacheCache();
$driver->setMemcache($memcache);
} else {
throw new LogicException('Memcache PHP extension has not been installed');
}
$adapter = new ApcuAdapter($namespace, $defaultLifetime);
break;
case 'memcached':
@@ -285,8 +331,7 @@ class Cache extends Getters
$this->config->get('system.cache.memcached.server', 'localhost'),
$this->config->get('system.cache.memcached.port', 11211)
);
$driver = new DoctrineCache\MemcachedCache();
$driver->setMemcached($memcached);
$adapter = new MemcachedAdapter($memcached, $namespace, $defaultLifetime);
} else {
throw new LogicException('Memcached PHP extension has not been installed');
}
@@ -318,19 +363,39 @@ class Cache extends Getters
throw new \RedisException('Could not select alternate Redis database ID');
}
$driver = new DoctrineCache\RedisCache();
$driver->setRedis($redis);
$adapter = new RedisAdapter($redis, $namespace, $defaultLifetime);
} else {
throw new LogicException('Redis PHP extension has not been installed');
}
break;
default:
$driver = new DoctrineCache\FilesystemCache($this->cache_dir);
$adapter = new FilesystemAdapter($namespace, $defaultLifetime, $this->cache_dir);
break;
}
return $driver;
return $adapter;
}
/**
* Automatically picks the cache mechanism to use. If you pick one manually it will use that
* If there is no config option for $driver in the config, or it's set to 'auto', it will
* pick the best option based on which cache extensions are installed.
*
* @return CacheProvider The cache driver to use
*/
public function getCacheDriver(?AdapterInterface $adapter = null)
{
if (null === $adapter) {
$adapter = $this->getCacheAdapter();
}
$cache = DoctrineProvider::wrap($adapter);
if (!$cache instanceof CacheProvider) {
throw new \RuntimeException('Internal error');
}
return $cache;
}
/**
@@ -472,8 +537,17 @@ class Cache extends Getters
// Delete entries in the doctrine cache if required
if (in_array($remove, ['all', 'standard'])) {
$cache = Grav::instance()['cache'];
$cache->driver->deleteAll();
try {
$grav = Grav::instance();
if ($grav->offsetExists('cache')) {
$cache = $grav['cache'];
if (isset($cache->driver)) {
$cache->driver->deleteAll();
}
}
} catch (\Throwable $e) {
$output[] = 'cache: ' . $e->getMessage();
}
}
// Clearing cache event to add paths to clear
@@ -618,7 +692,7 @@ class Cache extends Getters
*/
public function isVolatileDriver($setting)
{
return in_array($setting, ['apc', 'apcu', 'xcache', 'wincache'], true);
return $setting === 'apcu';
}
/**
@@ -632,8 +706,10 @@ class Cache extends Getters
{
/** @var Cache $cache */
$cache = Grav::instance()['cache'];
$deleted_folders = $cache->purgeOldCache();
$msg = 'Purged ' . $deleted_folders . ' old cache folders...';
$deleted_items = $cache->purgeOldCache();
$max_age = $cache->config->get('system.cache.purge_max_age_days', 30);
$msg = 'Purged ' . $deleted_items . ' old cache items (files older than ' . $max_age . ' days)';
if ($echo) {
echo $msg;

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Common
*
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2025 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Common\Config
*
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2025 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/
@@ -13,7 +13,10 @@ use BadMethodCallException;
use Exception;
use RocketTheme\Toolbox\File\PhpFile;
use RuntimeException;
use function filter_var;
use function function_exists;
use function get_class;
use function ini_get;
use function is_array;
/**
@@ -202,7 +205,7 @@ abstract class CompiledBase
$cache = include $filename;
if (!is_array($cache)
|| !isset($cache['checksum'], $cache['data'], $cache['@class'])
|| $cache['@class'] !== get_class($this)
|| $cache['@class'] !== static::class
) {
return false;
}
@@ -235,7 +238,7 @@ abstract class CompiledBase
// Attempt to lock the file for writing.
try {
$file->lock(false);
} catch (Exception $e) {
} catch (Exception) {
// Another process has locked the file; we will check this in a bit.
}
@@ -245,7 +248,7 @@ abstract class CompiledBase
}
$cache = [
'@class' => get_class($this),
'@class' => static::class,
'timestamp' => time(),
'checksum' => $this->checksum(),
'files' => $this->files,
@@ -254,6 +257,9 @@ abstract class CompiledBase
$file->save($cache);
$file->unlock();
$this->preloadOpcodeCache($file);
$file->free();
$this->modified();
@@ -266,4 +272,40 @@ abstract class CompiledBase
{
return $this->object->toArray();
}
/**
* Ensure compiled cache file is primed into OPcache when available.
*/
protected function preloadOpcodeCache(PhpFile $file): void
{
if (!function_exists('opcache_invalidate') || !$this->isOpcacheEnabled()) {
return;
}
$filename = $file->filename();
if (!$filename) {
return;
}
// Silence errors for restricted functions while keeping best effort behavior.
@opcache_invalidate($filename, true);
if (function_exists('opcache_compile_file')) {
@opcache_compile_file($filename);
}
}
/**
* Detect if OPcache is active for current SAPI.
*/
protected function isOpcacheEnabled(): bool
{
$enabled = filter_var(ini_get('opcache.enable'), \FILTER_VALIDATE_BOOLEAN);
if (PHP_SAPI === 'cli') {
$enabled = $enabled || filter_var(ini_get('opcache.enable_cli'), \FILTER_VALIDATE_BOOLEAN);
}
return $enabled;
}
}

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Common\Config
*
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2025 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Common\Config
*
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2025 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Common\Config
*
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2025 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Common\Config
*
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2025 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/
@@ -149,7 +149,7 @@ class Config extends Data
*/
public function getLanguages()
{
user_error(__CLASS__ . '::' . __FUNCTION__ . '() is deprecated since Grav 1.5, use Grav::instance()[\'languages\'] instead', E_USER_DEPRECATED);
user_error(self::class . '::' . __FUNCTION__ . '() is deprecated since Grav 1.5, use Grav::instance()[\'languages\'] instead', E_USER_DEPRECATED);
return Grav::instance()['languages'];
}

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Common\Config
*
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2025 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/
@@ -178,9 +178,7 @@ class ConfigFileFinder
'filters' => [
'pre-key' => $this->base,
'key' => $pattern,
'value' => function (RecursiveDirectoryIterator $file) use ($path) {
return ['file' => "{$path}/{$file->getSubPathname()}", 'modified' => $file->getMTime()];
}
'value' => fn(RecursiveDirectoryIterator $file) => ['file' => "{$path}/{$file->getSubPathname()}", 'modified' => $file->getMTime()]
],
'key' => 'SubPathname'
];
@@ -254,9 +252,7 @@ class ConfigFileFinder
'filters' => [
'pre-key' => $this->base,
'key' => $pattern,
'value' => function (RecursiveDirectoryIterator $file) use ($path) {
return ["{$path}/{$file->getSubPathname()}" => $file->getMTime()];
}
'value' => fn(RecursiveDirectoryIterator $file) => ["{$path}/{$file->getSubPathname()}" => $file->getMTime()]
],
'key' => 'SubPathname'
];

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Common\Config
*
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2025 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Common\Config
*
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2025 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/
@@ -202,7 +202,7 @@ class Setup extends Data
$setupFile = defined('GRAV_SETUP_PATH') ? GRAV_SETUP_PATH : (getenv('GRAV_SETUP_PATH') ?: null);
if (null !== $setupFile) {
// Make sure that the custom setup file exists. Terminates the script if not.
if (!str_starts_with($setupFile, '/')) {
if (!str_starts_with((string) $setupFile, '/')) {
$setupFile = GRAV_WEBROOT . '/' . $setupFile;
}
if (!is_file($setupFile)) {

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Common\Data
*
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2025 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/
@@ -142,7 +142,7 @@ class Blueprint extends BlueprintForm
{
foreach ($this->dynamic as $key => $data) {
// Locate field.
$path = explode('/', $key);
$path = explode('/', (string) $key);
$current = &$this->items;
foreach ($path as $field) {
@@ -168,7 +168,7 @@ class Blueprint extends BlueprintForm
// Set dynamic property.
foreach ($data as $property => $call) {
$action = $call['action'];
$method = 'dynamic' . ucfirst($action);
$method = 'dynamic' . ucfirst((string) $action);
$call['object'] = $this->object;
if (isset($this->handlers[$action])) {
@@ -434,7 +434,7 @@ class Blueprint extends BlueprintForm
$params = [];
}
[$o, $f] = explode('::', $function, 2);
[$o, $f] = explode('::', (string) $function, 2);
$data = null;
if (!$f) {
@@ -574,10 +574,9 @@ class Blueprint extends BlueprintForm
/**
* @param array $field
* @param string $property
* @param mixed $value
* @return void
*/
public static function addPropertyRecursive(array &$field, $property, $value)
public static function addPropertyRecursive(array &$field, $property, mixed $value)
{
if (is_array($value) && isset($field[$property]) && is_array($field[$property])) {
$field[$property] = array_merge_recursive($field[$property], $value);

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Common\Data
*
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2025 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/
@@ -129,7 +129,8 @@ class BlueprintSchema extends BlueprintSchemaBase implements ExportInterface
$items = $name !== '' ? $this->getProperty($name)['fields'] ?? [] : $this->items;
foreach ($items as $key => $rules) {
$type = $rules['type'] ?? '';
if (!str_starts_with($type, '_') && !str_contains($key, '*')) {
$ignore = (bool) array_filter((array)($rules['validate']['ignore'] ?? [])) ?? false;
if (!str_starts_with((string) $type, '_') && !str_contains((string) $key, '*') && $ignore !== true) {
$list[$prefix . $key] = null;
}
}
@@ -195,6 +196,38 @@ class BlueprintSchema extends BlueprintSchemaBase implements ExportInterface
$messages += Validation::validate($child, $rule);
if (isset($rule['validate']['match']) || isset($rule['validate']['match_exact']) || isset($rule['validate']['match_any'])) {
$ruleKey = current(array_intersect(['match', 'match_exact', 'match_any'], array_keys($rule['validate'])));
$otherKey = $rule['validate'][$ruleKey] ?? null;
$otherVal = $data[$otherKey] ?? null;
$otherLabel = $this->items[$otherKey]['label'] ?? $otherKey;
$currentVal = $data[$key] ?? null;
$currentLabel = $this->items[$key]['label'] ?? $key;
// Determine comparison type (loose, strict, substring)
// Perform comparison:
$isValid = false;
if ($ruleKey === 'match') {
$isValid = ($currentVal == $otherVal);
} elseif ($ruleKey === 'match_exact') {
$isValid = ($currentVal === $otherVal);
} elseif ($ruleKey === 'match_any') {
// If strings:
if (is_string($currentVal) && is_string($otherVal)) {
$isValid = (strlen($currentVal) && strlen($otherVal) && (str_contains($currentVal,
$otherVal) || str_contains($otherVal, $currentVal)));
}
// If arrays:
if (is_array($currentVal) && is_array($otherVal)) {
$common = array_intersect($currentVal, $otherVal);
$isValid = !empty($common);
}
}
if (!$isValid) {
$messages[$rule['name']][] = sprintf(Grav::instance()['language']->translate('PLUGIN_FORM.VALIDATION_MATCH'), $currentLabel, $otherLabel);
}
}
} elseif (is_array($child) && is_array($val)) {
// Array has been defined in blueprints.
$messages += $this->validateArray($child, $val, $strict);

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Common\Data
*
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2025 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/
@@ -22,8 +22,6 @@ use function is_object;
*/
class Blueprints
{
/** @var array|string */
protected $search;
/** @var array */
protected $types;
/** @var array */
@@ -32,9 +30,8 @@ class Blueprints
/**
* @param string|array $search Search path.
*/
public function __construct($search = 'blueprints://')
public function __construct(protected $search = 'blueprints://')
{
$this->search = $search;
}
/**

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Common\Data
*
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2025 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/
@@ -103,7 +103,7 @@ class Data implements DataInterface, ArrayAccess, \Countable, JsonSerializable,
* @return $this
* @throws RuntimeException
*/
public function join($name, $value, $separator = '.')
public function join($name, mixed $value, $separator = '.')
{
$old = $this->get($name, null, $separator);
if ($old !== null) {
@@ -145,7 +145,7 @@ class Data implements DataInterface, ArrayAccess, \Countable, JsonSerializable,
* @param string $separator Separator, defaults to '.'
* @return $this
*/
public function joinDefaults($name, $value, $separator = '.')
public function joinDefaults($name, mixed $value, $separator = '.')
{
if (is_object($value)) {
$value = (array) $value;
@@ -323,7 +323,7 @@ class Data implements DataInterface, ArrayAccess, \Countable, JsonSerializable,
* @param FileInterface|null $storage Optionally enter a new storage.
* @return FileInterface|null
*/
public function file(FileInterface $storage = null)
public function file(?FileInterface $storage = null)
{
if ($storage) {
$this->storage = $storage;

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Common\Data
*
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2025 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/
@@ -28,7 +28,7 @@ interface DataInterface
* @param string $separator Separator, defaults to '.'
* @return mixed Value.
*/
public function value($name, $default = null, $separator = '.');
public function value($name, mixed $default = null, $separator = '.');
/**
* Merge external data.
@@ -80,5 +80,5 @@ interface DataInterface
* @param FileInterface|null $storage Optionally enter a new storage.
* @return FileInterface
*/
public function file(FileInterface $storage = null);
public function file(?FileInterface $storage = null);
}

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Common\Data
*
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2025 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/
@@ -37,23 +37,24 @@ class Validation
/**
* Validate value against a blueprint field definition.
*
* @param mixed $value
* @param array $field
* @return array
*/
public static function validate($value, array $field)
public static function validate(mixed $value, array $field)
{
if (!isset($field['type'])) {
$field['type'] = 'text';
}
$validate = (array)($field['validate'] ?? null);
$type = $validate['type'] ?? $field['type'];
$validate_type = $validate['type'] ?? null;
$required = $validate['required'] ?? false;
$type = $validate_type ?? $field['type'];
$required = $required && ($validate_type !== 'ignore');
// If value isn't required, we will stop validation if empty value is given.
if ($required !== true && ($value === null || $value === '' || (($field['type'] === 'checkbox' || $field['type'] === 'switch') && $value == false))
) {
if ($required !== true && ($value === null || $value === '' || empty($value) || (($field['type'] === 'checkbox' || $field['type'] === 'switch') && $value == false))) {
return [];
}
@@ -76,7 +77,7 @@ class Validation
$messages = [];
$success = method_exists(__CLASS__, $method) ? self::$method($value, $validate, $field) : true;
$success = method_exists(self::class, $method) ? self::$method($value, $validate, $field) : true;
if (!$success) {
$messages[$field['name']][] = $message;
}
@@ -85,7 +86,7 @@ class Validation
foreach ($validate as $rule => $params) {
$method = 'validate' . ucfirst(str_replace('-', '_', $rule));
if (method_exists(__CLASS__, $method)) {
if (method_exists(self::class, $method)) {
$success = self::$method($value, $params);
if (!$success) {
@@ -98,11 +99,10 @@ class Validation
}
/**
* @param mixed $value
* @param array $field
* @return array
*/
public static function checkSafety($value, array $field)
public static function checkSafety(mixed $value, array $field)
{
$messages = [];
@@ -115,7 +115,7 @@ class Validation
$options = [];
}
$name = ucfirst($field['label'] ?? $field['name'] ?? 'UNKNOWN');
$name = ucfirst((string) ($field['label'] ?? $field['name'] ?? 'UNKNOWN'));
/** @var UserInterface $user */
$user = Grav::instance()['user'] ?? null;
@@ -162,7 +162,7 @@ class Validation
* @param UserInterface|null $user
* @return bool
*/
public static function authorize($action, UserInterface $user = null)
public static function authorize($action, ?UserInterface $user = null)
{
if (!$user) {
return false;
@@ -186,11 +186,10 @@ class Validation
/**
* Filter value against a blueprint field definition.
*
* @param mixed $value
* @param array $field
* @return mixed Filtered value.
*/
public static function filter($value, array $field)
public static function filter(mixed $value, array $field)
{
$validate = (array)($field['filter'] ?? $field['validate'] ?? null);
@@ -211,7 +210,7 @@ class Validation
$method = 'filterYaml';
}
if (!method_exists(__CLASS__, $method)) {
if (!method_exists(self::class, $method)) {
$method = isset($field['array']) && $field['array'] === true ? 'filterArray' : 'filterText';
}
@@ -226,7 +225,7 @@ class Validation
* @param array $field Blueprint for the field.
* @return bool True if validation succeeded.
*/
public static function typeText($value, array $params, array $field)
public static function typeText(mixed $value, array $params, array $field)
{
if (!is_string($value) && !is_numeric($value)) {
return false;
@@ -239,7 +238,7 @@ class Validation
}
$value = preg_replace("/\r\n|\r/um", "\n", $value);
$len = mb_strlen($value);
$len = mb_strlen((string) $value);
$min = (int)($params['min'] ?? 0);
if ($min && $len < $min) {
@@ -258,7 +257,7 @@ class Validation
return false;
}
if (!$multiline && preg_match('/\R/um', $value)) {
if (!$multiline && preg_match('/\R/um', (string) $value)) {
return false;
}
@@ -266,12 +265,11 @@ class Validation
}
/**
* @param mixed $value
* @param array $params
* @param array $field
* @return string
*/
protected static function filterText($value, array $params, array $field)
protected static function filterText(mixed $value, array $params, array $field)
{
if (!is_string($value) && !is_numeric($value)) {
return '';
@@ -287,12 +285,11 @@ class Validation
}
/**
* @param mixed $value
* @param array $params
* @param array $field
* @return string|null
*/
protected static function filterCheckbox($value, array $params, array $field)
protected static function filterCheckbox(mixed $value, array $params, array $field)
{
$value = (string)$value;
$field_value = (string)($field['value'] ?? '1');
@@ -301,23 +298,21 @@ class Validation
}
/**
* @param mixed $value
* @param array $params
* @param array $field
* @return array|array[]|false|string[]
*/
protected static function filterCommaList($value, array $params, array $field)
protected static function filterCommaList(mixed $value, array $params, array $field)
{
return is_array($value) ? $value : preg_split('/\s*,\s*/', $value, -1, PREG_SPLIT_NO_EMPTY);
return is_array($value) ? $value : preg_split('/\s*,\s*/', (string) $value, -1, PREG_SPLIT_NO_EMPTY);
}
/**
* @param mixed $value
* @param array $params
* @param array $field
* @return bool
*/
public static function typeCommaList($value, array $params, array $field)
public static function typeCommaList(mixed $value, array $params, array $field)
{
if (!isset($params['max'])) {
$params['max'] = 2048;
@@ -327,34 +322,31 @@ class Validation
}
/**
* @param mixed $value
* @param array $params
* @param array $field
* @return array|array[]|false|string[]
*/
protected static function filterLines($value, array $params, array $field)
protected static function filterLines(mixed $value, array $params, array $field)
{
return is_array($value) ? $value : preg_split('/\s*[\r\n]+\s*/', $value, -1, PREG_SPLIT_NO_EMPTY);
return is_array($value) ? $value : preg_split('/\s*[\r\n]+\s*/', (string) $value, -1, PREG_SPLIT_NO_EMPTY);
}
/**
* @param mixed $value
* @param array $params
* @return string
*/
protected static function filterLower($value, array $params)
protected static function filterLower(mixed $value, array $params)
{
return mb_strtolower($value);
return mb_strtolower((string) $value);
}
/**
* @param mixed $value
* @param array $params
* @return string
*/
protected static function filterUpper($value, array $params)
protected static function filterUpper(mixed $value, array $params)
{
return mb_strtoupper($value);
return mb_strtoupper((string) $value);
}
@@ -366,7 +358,7 @@ class Validation
* @param array $field Blueprint for the field.
* @return bool True if validation succeeded.
*/
public static function typeTextarea($value, array $params, array $field)
public static function typeTextarea(mixed $value, array $params, array $field)
{
if (!isset($params['multiline'])) {
$params['multiline'] = true;
@@ -383,7 +375,7 @@ class Validation
* @param array $field Blueprint for the field.
* @return bool True if validation succeeded.
*/
public static function typePassword($value, array $params, array $field)
public static function typePassword(mixed $value, array $params, array $field)
{
if (!isset($params['max'])) {
$params['max'] = 256;
@@ -400,7 +392,7 @@ class Validation
* @param array $field Blueprint for the field.
* @return bool True if validation succeeded.
*/
public static function typeHidden($value, array $params, array $field)
public static function typeHidden(mixed $value, array $params, array $field)
{
return self::typeText($value, $params, $field);
}
@@ -413,7 +405,7 @@ class Validation
* @param array $field Blueprint for the field.
* @return bool True if validation succeeded.
*/
public static function typeCheckboxes($value, array $params, array $field)
public static function typeCheckboxes(mixed $value, array $params, array $field)
{
// Set multiple: true so checkboxes can easily use min/max counts to control number of options required
$field['multiple'] = true;
@@ -422,12 +414,11 @@ class Validation
}
/**
* @param mixed $value
* @param array $params
* @param array $field
* @return array|null
*/
protected static function filterCheckboxes($value, array $params, array $field)
protected static function filterCheckboxes(mixed $value, array $params, array $field)
{
return self::filterArray($value, $params, $field);
}
@@ -440,7 +431,7 @@ class Validation
* @param array $field Blueprint for the field.
* @return bool True if validation succeeded.
*/
public static function typeCheckbox($value, array $params, array $field)
public static function typeCheckbox(mixed $value, array $params, array $field)
{
$value = (string)$value;
$field_value = (string)($field['value'] ?? '1');
@@ -456,7 +447,7 @@ class Validation
* @param array $field Blueprint for the field.
* @return bool True if validation succeeded.
*/
public static function typeRadio($value, array $params, array $field)
public static function typeRadio(mixed $value, array $params, array $field)
{
return self::typeArray((array) $value, $params, $field);
}
@@ -469,7 +460,7 @@ class Validation
* @param array $field Blueprint for the field.
* @return bool True if validation succeeded.
*/
public static function typeToggle($value, array $params, array $field)
public static function typeToggle(mixed $value, array $params, array $field)
{
if (is_bool($value)) {
$value = (int)$value;
@@ -486,18 +477,17 @@ class Validation
* @param array $field Blueprint for the field.
* @return bool True if validation succeeded.
*/
public static function typeFile($value, array $params, array $field)
public static function typeFile(mixed $value, array $params, array $field)
{
return self::typeArray((array)$value, $params, $field);
}
/**
* @param mixed $value
* @param array $params
* @param array $field
* @return array
*/
protected static function filterFile($value, array $params, array $field)
protected static function filterFile(mixed $value, array $params, array $field)
{
return (array)$value;
}
@@ -510,7 +500,7 @@ class Validation
* @param array $field Blueprint for the field.
* @return bool True if validation succeeded.
*/
public static function typeSelect($value, array $params, array $field)
public static function typeSelect(mixed $value, array $params, array $field)
{
return self::typeArray((array) $value, $params, $field);
}
@@ -523,7 +513,7 @@ class Validation
* @param array $field Blueprint for the field.
* @return bool True if validation succeeded.
*/
public static function typeNumber($value, array $params, array $field)
public static function typeNumber(mixed $value, array $params, array $field)
{
if (!is_numeric($value)) {
return false;
@@ -550,7 +540,7 @@ class Validation
$step = (float)$params['step'];
// Count of how many steps we are above/below the minimum value.
$pos = ($value - $min) / $step;
$pos = round($pos, 10);
return is_int(static::filterNumber($pos, $params, $field));
}
@@ -558,23 +548,21 @@ class Validation
}
/**
* @param mixed $value
* @param array $params
* @param array $field
* @return float|int
*/
protected static function filterNumber($value, array $params, array $field)
protected static function filterNumber(mixed $value, array $params, array $field)
{
return (string)(int)$value !== (string)(float)$value ? (float)$value : (int)$value;
}
/**
* @param mixed $value
* @param array $params
* @param array $field
* @return string
*/
protected static function filterDateTime($value, array $params, array $field)
protected static function filterDateTime(mixed $value, array $params, array $field)
{
$format = Grav::instance()['config']->get('system.pages.dateformat.default');
if ($format) {
@@ -592,18 +580,17 @@ class Validation
* @param array $field Blueprint for the field.
* @return bool True if validation succeeded.
*/
public static function typeRange($value, array $params, array $field)
public static function typeRange(mixed $value, array $params, array $field)
{
return self::typeNumber($value, $params, $field);
}
/**
* @param mixed $value
* @param array $params
* @param array $field
* @return float|int
*/
protected static function filterRange($value, array $params, array $field)
protected static function filterRange(mixed $value, array $params, array $field)
{
return self::filterNumber($value, $params, $field);
}
@@ -616,9 +603,9 @@ class Validation
* @param array $field Blueprint for the field.
* @return bool True if validation succeeded.
*/
public static function typeColor($value, array $params, array $field)
public static function typeColor(mixed $value, array $params, array $field)
{
return (bool)preg_match('/^\#[0-9a-fA-F]{3}[0-9a-fA-F]{3}?$/u', $value);
return (bool)preg_match('/^\#[0-9a-fA-F]{3}[0-9a-fA-F]{3}?$/u', (string) $value);
}
/**
@@ -629,16 +616,20 @@ class Validation
* @param array $field Blueprint for the field.
* @return bool True if validation succeeded.
*/
public static function typeEmail($value, array $params, array $field)
public static function typeEmail(mixed $value, array $params, array $field)
{
if (empty($value)) {
return false;
}
if (!isset($params['max'])) {
$params['max'] = 320;
}
$values = !is_array($value) ? explode(',', preg_replace('/\s+/', '', $value)) : $value;
$values = !is_array($value) ? explode(',', (string) preg_replace('/\s+/', '', (string) $value)) : $value;
foreach ($values as $val) {
if (!(self::typeText($val, $params, $field) && filter_var($val, FILTER_VALIDATE_EMAIL))) {
if (!(self::typeText($val, $params, $field) && strpos((string) $val, '@', 1))) {
return false;
}
}
@@ -654,7 +645,7 @@ class Validation
* @param array $field Blueprint for the field.
* @return bool True if validation succeeded.
*/
public static function typeUrl($value, array $params, array $field)
public static function typeUrl(mixed $value, array $params, array $field)
{
if (!isset($params['max'])) {
$params['max'] = 2048;
@@ -671,7 +662,7 @@ class Validation
* @param array $field Blueprint for the field.
* @return bool True if validation succeeded.
*/
public static function typeDatetime($value, array $params, array $field)
public static function typeDatetime(mixed $value, array $params, array $field)
{
if ($value instanceof DateTime) {
return true;
@@ -696,7 +687,7 @@ class Validation
* @param array $field Blueprint for the field.
* @return bool True if validation succeeded.
*/
public static function typeDatetimeLocal($value, array $params, array $field)
public static function typeDatetimeLocal(mixed $value, array $params, array $field)
{
return self::typeDatetime($value, $params, $field);
}
@@ -709,7 +700,7 @@ class Validation
* @param array $field Blueprint for the field.
* @return bool True if validation succeeded.
*/
public static function typeDate($value, array $params, array $field)
public static function typeDate(mixed $value, array $params, array $field)
{
if (!isset($params['format'])) {
$params['format'] = 'Y-m-d';
@@ -726,7 +717,7 @@ class Validation
* @param array $field Blueprint for the field.
* @return bool True if validation succeeded.
*/
public static function typeTime($value, array $params, array $field)
public static function typeTime(mixed $value, array $params, array $field)
{
if (!isset($params['format'])) {
$params['format'] = 'H:i';
@@ -743,7 +734,7 @@ class Validation
* @param array $field Blueprint for the field.
* @return bool True if validation succeeded.
*/
public static function typeMonth($value, array $params, array $field)
public static function typeMonth(mixed $value, array $params, array $field)
{
if (!isset($params['format'])) {
$params['format'] = 'Y-m';
@@ -760,9 +751,9 @@ class Validation
* @param array $field Blueprint for the field.
* @return bool True if validation succeeded.
*/
public static function typeWeek($value, array $params, array $field)
public static function typeWeek(mixed $value, array $params, array $field)
{
if (!isset($params['format']) && !preg_match('/^\d{4}-W\d{2}$/u', $value)) {
if (!isset($params['format']) && !preg_match('/^\d{4}-W\d{2}$/u', (string) $value)) {
return false;
}
@@ -777,7 +768,7 @@ class Validation
* @param array $field Blueprint for the field.
* @return bool True if validation succeeded.
*/
public static function typeArray($value, array $params, array $field)
public static function typeArray(mixed $value, array $params, array $field)
{
if (!is_array($value)) {
return false;
@@ -825,12 +816,11 @@ class Validation
}
/**
* @param mixed $value
* @param array $params
* @param array $field
* @return array|null
*/
protected static function filterFlatten_array($value, $params, $field)
protected static function filterFlatten_array(mixed $value, $params, $field)
{
$value = static::filterArray($value, $params, $field);
@@ -838,12 +828,11 @@ class Validation
}
/**
* @param mixed $value
* @param array $params
* @param array $field
* @return array|null
*/
protected static function filterArray($value, $params, $field)
protected static function filterArray(mixed $value, $params, $field)
{
$values = (array) $value;
$options = isset($field['options']) ? array_keys($field['options']) : [];
@@ -867,7 +856,7 @@ class Validation
$val = implode(',', $val);
$values[$key] = array_map('trim', explode(',', $val));
} else {
$values[$key] = trim($val);
$values[$key] = trim((string) $val);
}
}
}
@@ -891,16 +880,11 @@ class Validation
{
foreach ($values as $key => &$val) {
if ($params['key_type']) {
switch ($params['key_type']) {
case 'int':
$result = is_int($key);
break;
case 'string':
$result = is_string($key);
break;
default:
$result = false;
}
$result = match ($params['key_type']) {
'int' => is_int($key),
'string' => is_string($key),
default => false,
};
if (!$result) {
unset($values[$key]);
}
@@ -933,7 +917,7 @@ class Validation
$val = (string)$val;
break;
case 'trim':
$val = trim($val);
$val = trim((string) $val);
break;
}
}
@@ -948,12 +932,11 @@ class Validation
}
/**
* @param mixed $value
* @param array $params
* @param array $field
* @return bool
*/
public static function typeList($value, array $params, array $field)
public static function typeList(mixed $value, array $params, array $field)
{
if (!is_array($value)) {
return false;
@@ -962,7 +945,7 @@ class Validation
if (isset($field['fields'])) {
foreach ($value as $key => $item) {
foreach ($field['fields'] as $subKey => $subField) {
$subKey = trim($subKey, '.');
$subKey = trim((string) $subKey, '.');
$subValue = $item[$subKey] ?? null;
self::validate($subValue, $subField);
}
@@ -973,22 +956,20 @@ class Validation
}
/**
* @param mixed $value
* @param array $params
* @param array $field
* @return array
*/
protected static function filterList($value, array $params, array $field)
protected static function filterList(mixed $value, array $params, array $field)
{
return (array) $value;
}
/**
* @param mixed $value
* @param array $params
* @return array
*/
public static function filterYaml($value, $params)
public static function filterYaml(mixed $value, $params)
{
if (!is_string($value)) {
return $value;
@@ -1005,18 +986,17 @@ class Validation
* @param array $field Blueprint for the field.
* @return bool True if validation succeeded.
*/
public static function typeIgnore($value, array $params, array $field)
public static function typeIgnore(mixed $value, array $params, array $field)
{
return true;
}
/**
* @param mixed $value
* @param array $params
* @param array $field
* @return mixed
*/
public static function filterIgnore($value, array $params, array $field)
public static function filterIgnore(mixed $value, array $params, array $field)
{
return $value;
}
@@ -1029,30 +1009,27 @@ class Validation
* @param array $field Blueprint for the field.
* @return bool True if validation succeeded.
*/
public static function typeUnset($value, array $params, array $field)
public static function typeUnset(mixed $value, array $params, array $field)
{
return true;
}
/**
* @param mixed $value
* @param array $params
* @param array $field
* @return null
*/
public static function filterUnset($value, array $params, array $field)
public static function filterUnset(mixed $value, array $params, array $field)
{
return null;
}
// HTML5 attributes (min, max and range are handled inside the types)
/**
* @param mixed $value
* @param bool $params
* @return bool
*/
public static function validateRequired($value, $params)
public static function validateRequired(mixed $value, $params)
{
if (is_scalar($value)) {
return (bool) $params !== true || $value !== '';
@@ -1062,105 +1039,85 @@ class Validation
}
/**
* @param mixed $value
* @param string $params
* @return bool
*/
public static function validatePattern($value, $params)
public static function validatePattern(mixed $value, $params)
{
return (bool) preg_match("`^{$params}$`u", $value);
return (bool) preg_match("`^{$params}$`u", (string) $value);
}
// Internal types
/**
* @param mixed $value
* @param mixed $params
* @return bool
*/
public static function validateAlpha($value, $params)
public static function validateAlpha(mixed $value, mixed $params)
{
return ctype_alpha($value);
return ctype_alpha((string) $value);
}
/**
* @param mixed $value
* @param mixed $params
* @return bool
*/
public static function validateAlnum($value, $params)
public static function validateAlnum(mixed $value, mixed $params)
{
return ctype_alnum($value);
return ctype_alnum((string) $value);
}
/**
* @param mixed $value
* @param mixed $params
* @return bool
*/
public static function typeBool($value, $params)
public static function typeBool(mixed $value, mixed $params)
{
return is_bool($value) || $value == 1 || $value == 0;
}
/**
* @param mixed $value
* @param mixed $params
* @return bool
*/
public static function validateBool($value, $params)
public static function validateBool(mixed $value, mixed $params)
{
return is_bool($value) || $value == 1 || $value == 0;
}
/**
* @param mixed $value
* @param mixed $params
* @return bool
*/
protected static function filterBool($value, $params)
protected static function filterBool(mixed $value, mixed $params)
{
return (bool) $value;
}
/**
* @param mixed $value
* @param mixed $params
* @return bool
*/
public static function validateDigit($value, $params)
public static function validateDigit(mixed $value, mixed $params)
{
return ctype_digit($value);
return ctype_digit((string) $value);
}
/**
* @param mixed $value
* @param mixed $params
* @return bool
*/
public static function validateFloat($value, $params)
public static function validateFloat(mixed $value, mixed $params)
{
return is_float(filter_var($value, FILTER_VALIDATE_FLOAT));
}
/**
* @param mixed $value
* @param mixed $params
* @return float
*/
protected static function filterFloat($value, $params)
protected static function filterFloat(mixed $value, mixed $params)
{
return (float) $value;
}
/**
* @param mixed $value
* @param mixed $params
* @return bool
*/
public static function validateHex($value, $params)
public static function validateHex(mixed $value, mixed $params)
{
return ctype_xdigit($value);
return ctype_xdigit((string) $value);
}
/**
@@ -1171,7 +1128,7 @@ class Validation
* @param array $field Blueprint for the field.
* @return bool True if validation succeeded.
*/
public static function typeInt($value, array $params, array $field)
public static function typeInt(mixed $value, array $params, array $field)
{
$params['step'] = max(1, (int)($params['step'] ?? 0));
@@ -1179,54 +1136,42 @@ class Validation
}
/**
* @param mixed $value
* @param mixed $params
* @return bool
*/
public static function validateInt($value, $params)
public static function validateInt(mixed $value, mixed $params)
{
return is_numeric($value) && (int)$value == $value;
}
/**
* @param mixed $value
* @param mixed $params
* @return int
*/
protected static function filterInt($value, $params)
protected static function filterInt(mixed $value, mixed $params)
{
return (int)$value;
}
/**
* @param mixed $value
* @param mixed $params
* @return bool
*/
public static function validateArray($value, $params)
public static function validateArray(mixed $value, mixed $params)
{
return is_array($value) || ($value instanceof ArrayAccess && $value instanceof Traversable && $value instanceof Countable);
}
/**
* @param mixed $value
* @param mixed $params
* @return array
*/
public static function filterItem_List($value, $params)
public static function filterItem_List(mixed $value, mixed $params)
{
return array_values(array_filter($value, static function ($v) {
return !empty($v);
}));
return array_values(array_filter($value, static fn($v) => !empty($v)));
}
/**
* @param mixed $value
* @param mixed $params
* @return bool
*/
public static function validateJson($value, $params)
public static function validateJson(mixed $value, mixed $params)
{
return (bool) (@json_decode($value));
return (bool) (@json_decode((string) $value));
}
}

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Common\Data
*
* @copyright Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2025 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/
@@ -37,7 +37,7 @@ class ValidationException extends RuntimeException implements JsonSerializable
foreach ($messages as $list) {
$list = array_unique($list);
foreach ($list as $message) {
$this->message .= '<br/>' . htmlspecialchars($message, ENT_QUOTES | ENT_HTML5, 'UTF-8');
$this->message .= '<br/>' . htmlspecialchars((string) $message, ENT_QUOTES | ENT_HTML5, 'UTF-8');
}
}
@@ -49,7 +49,7 @@ class ValidationException extends RuntimeException implements JsonSerializable
$first = reset($this->messages);
$message = reset($first);
$this->message = $escape ? htmlspecialchars($message, ENT_QUOTES | ENT_HTML5, 'UTF-8') : $message;
$this->message = $escape ? htmlspecialchars((string) $message, ENT_QUOTES | ENT_HTML5, 'UTF-8') : $message;
}
/**

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