diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml
index 53cd5f1..b888abf 100644
--- a/.github/workflows/continuous-integration.yml
+++ b/.github/workflows/continuous-integration.yml
@@ -42,6 +42,12 @@ jobs:
matrix:
arch: [amd64, arm64]
image: &images
+ - path: '8.6'
+ tags: silarhi/php-apache:8.6
+ - path: '8.6-ci'
+ tags: silarhi/php-apache:8.6-ci
+ - path: '8.6-symfony'
+ tags: silarhi/php-apache:8.6-symfony
- path: '8.5'
tags: |
silarhi/php-apache:latest
diff --git a/8.6-ci/Dockerfile b/8.6-ci/Dockerfile
new file mode 100644
index 0000000..0a125e3
--- /dev/null
+++ b/8.6-ci/Dockerfile
@@ -0,0 +1,18 @@
+FROM mlocati/php-extension-installer:latest AS php-extension-installer
+FROM php:8.6-rc-alpine
+
+ENV COMPOSER_ALLOW_SUPERUSER=1
+
+WORKDIR /app
+
+SHELL ["/bin/ash", "-o", "pipefail", "-c"]
+
+# Install dependencies
+RUN apk add --no-cache \
+ bash \
+ git \
+ icu
+
+# PHP Extensions
+COPY --from=php-extension-installer /usr/bin/install-php-extensions /usr/local/bin/
+RUN install-php-extensions @composer intl opcache zip
diff --git a/8.6-symfony/Dockerfile b/8.6-symfony/Dockerfile
new file mode 100644
index 0000000..f838d8d
--- /dev/null
+++ b/8.6-symfony/Dockerfile
@@ -0,0 +1,37 @@
+FROM mlocati/php-extension-installer:latest AS php-extension-installer
+FROM php:8.6-rc-apache
+
+ENV COMPOSER_ALLOW_SUPERUSER=1
+ENV PHP_OPCACHE_VALIDATE_TIMESTAMPS=0
+
+EXPOSE 80
+WORKDIR /app
+
+HEALTHCHECK --interval=1m --timeout=3s --start-period=5s --start-interval=1s --retries=3 \
+ CMD ["/bin/sh", "-c", "curl -f http://localhost/_health || exit 1"]
+
+SHELL ["/bin/bash", "-o", "pipefail", "-c"]
+
+RUN apt-get update -qq && \
+ apt-get install -qy \
+ git \
+ gnupg \
+ unzip \
+ zip && \
+ apt-get clean && rm -rf /var/lib/apt/lists/*
+
+# PHP Extensions
+COPY --from=php-extension-installer /usr/bin/install-php-extensions /usr/local/bin/
+RUN install-php-extensions @composer intl opcache pdo_mysql zip
+RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini"
+COPY --link conf/php.ini $PHP_INI_DIR/conf.d/app.ini
+
+# Apache
+COPY --link errors /errors
+COPY --link health.php /health/index.php
+COPY --link conf/vhost.conf /etc/apache2/sites-available/000-default.conf
+COPY --link conf/apache.conf /etc/apache2/conf-available/z-app.conf
+COPY --link index.php /app/index.php
+
+RUN a2enmod rewrite remoteip && \
+ a2enconf z-app
diff --git a/8.6-symfony/conf/apache.conf b/8.6-symfony/conf/apache.conf
new file mode 100644
index 0000000..142ec3c
--- /dev/null
+++ b/8.6-symfony/conf/apache.conf
@@ -0,0 +1,64 @@
+
+ Options -Indexes +FollowSymLinks
+ AllowOverride None
+ Require all granted
+
+ SetEnvIf X-Forwarded-Proto "^https$" HTTPS=on
+
+
+ServerTokens Prod
+ServerSignature Off
+
+LogFormat "%a %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" combined
+
+RemoteIPHeader X-Forwarded-For
+RemoteIPInternalProxy 10.0.0.0/8
+RemoteIPInternalProxy 172.16.0.0/12
+RemoteIPInternalProxy 192.168.0.0/16
+RemoteIPInternalProxy 169.254.0.0/16
+RemoteIPInternalProxy 127.0.0.0/8
+RemoteIPInternalProxy ::1
+
+# Add Cloudflare IP ranges
+RemoteIPTrustedProxy 173.245.48.0/20
+RemoteIPTrustedProxy 103.21.244.0/22
+RemoteIPTrustedProxy 103.22.200.0/22
+RemoteIPTrustedProxy 103.31.4.0/22
+RemoteIPTrustedProxy 141.101.64.0/18
+RemoteIPTrustedProxy 108.162.192.0/18
+RemoteIPTrustedProxy 190.93.240.0/20
+RemoteIPTrustedProxy 188.114.96.0/20
+RemoteIPTrustedProxy 197.234.240.0/22
+RemoteIPTrustedProxy 198.41.128.0/17
+RemoteIPTrustedProxy 162.158.0.0/15
+RemoteIPTrustedProxy 104.16.0.0/13
+RemoteIPTrustedProxy 104.24.0.0/14
+RemoteIPTrustedProxy 172.64.0.0/13
+RemoteIPTrustedProxy 131.0.72.0/22
+RemoteIPTrustedProxy 2400:cb00::/32
+RemoteIPTrustedProxy 2606:4700::/32
+RemoteIPTrustedProxy 2803:f800::/32
+RemoteIPTrustedProxy 2405:b500::/32
+RemoteIPTrustedProxy 2405:8100::/32
+RemoteIPTrustedProxy 2a06:98c0::/29
+RemoteIPTrustedProxy 2c0f:f248::/32
+
+
+ Options -Indexes
+ AllowOverride None
+ Require all granted
+
+
+
+ Options -Indexes
+ AllowOverride None
+ Require local
+
+
+Alias /_errors/ /errors/
+
+ Alias "/health/index.php"
+
+ErrorDocument 404 /_errors/404.html
+ErrorDocument 403 /_errors/403.html
+ErrorDocument 500 /_errors/500.html
diff --git a/8.6-symfony/conf/php.ini b/8.6-symfony/conf/php.ini
new file mode 100644
index 0000000..81f7cde
--- /dev/null
+++ b/8.6-symfony/conf/php.ini
@@ -0,0 +1,23 @@
+date.timezone = Europe/Paris
+
+opcache.enable = 1
+opcache.enable_cli = 1
+opcache.memory_consumption = 256
+opcache.interned_strings_buffer = 16
+opcache.max_accelerated_files = 20000
+; Files are compiled once and never checked again: restart PHP to deploy new code, or set
+; PHP_OPCACHE_VALIDATE_TIMESTAMPS=1 when the sources are mounted and edited in place.
+opcache.validate_timestamps = ${PHP_OPCACHE_VALIDATE_TIMESTAMPS}
+opcache.revalidate_freq = 0
+apc.enable_cli = On
+
+upload_max_filesize = 16M
+post_max_size = 16M
+
+realpath_cache_size = 4096k
+realpath_cache_ttl = 7200
+
+expose_php = Off
+display_errors = Off
+display_startup_errors = Off
+error_log = /proc/self/fd/2
diff --git a/8.6-symfony/conf/vhost.conf b/8.6-symfony/conf/vhost.conf
new file mode 100644
index 0000000..4295c31
--- /dev/null
+++ b/8.6-symfony/conf/vhost.conf
@@ -0,0 +1,23 @@
+
+ ServerAdmin hello@silarhi.fr
+
+ DocumentRoot /app/public
+
+
+
+ Options -MultiViews
+ RewriteEngine On
+ RewriteCond %{REQUEST_FILENAME} !-f
+ RewriteRule ^(.*)$ index.php [QSA,L]
+
+
+
+
+ RedirectMatch 302 ^/$ /index.php/
+
+
+
+
+ ErrorLog ${APACHE_LOG_DIR}/error.log
+ CustomLog ${APACHE_LOG_DIR}/access.log combined
+
diff --git a/8.6-symfony/errors/403.html b/8.6-symfony/errors/403.html
new file mode 100644
index 0000000..97890d1
--- /dev/null
+++ b/8.6-symfony/errors/403.html
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+ Erreur 403 (Interdit)
+
+
+
+
+
+
+
diff --git a/8.6-symfony/errors/404.html b/8.6-symfony/errors/404.html
new file mode 100644
index 0000000..f0b6399
--- /dev/null
+++ b/8.6-symfony/errors/404.html
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+ Erreur 404 (Introuvable)
+
+
+
+
+
+
+
404
+
Oops! Vous êtes perdu.
+
La page que vous demandez est introuvable. Elle a peut-être été supprimée ou déplacée.
+
Retour à la page d'accueil
+
+
+
diff --git a/8.6-symfony/errors/500.html b/8.6-symfony/errors/500.html
new file mode 100644
index 0000000..b34c2d7
--- /dev/null
+++ b/8.6-symfony/errors/500.html
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+ Erreur 500 (Inaccessible)
+
+
+
+
+
+
+
diff --git a/8.6-symfony/errors/css/style.css b/8.6-symfony/errors/css/style.css
new file mode 100644
index 0000000..6be89a5
--- /dev/null
+++ b/8.6-symfony/errors/css/style.css
@@ -0,0 +1,102 @@
+html {
+ box-sizing: border-box;
+ font-size: 16px;
+}
+
+*, *:before, *:after {
+ box-sizing: inherit;
+}
+
+body, h1, h2, h3, h4, h5, h6, p, ol, ul {
+ margin: 0;
+ padding: 0;
+ font-weight: normal;
+}
+
+ol, ul {
+ list-style: none;
+}
+
+html, body {
+ height: 100%;
+}
+
+body {
+ font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", "Liberation Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+}
+
+#error-box {
+ position: relative;
+ max-width: 560px;
+ width: 100%;
+ padding-left: 160px;
+ line-height: 1.1;
+}
+
+#error-box #error-image {
+ position: absolute;
+ left: 0;
+ top: 0;
+ display: inline-block;
+ width: 140px;
+ height: 140px;
+ background-image: url('/_errors/img/emoji.png');
+ background-size: cover;
+}
+
+#error-box #error-image:before {
+ content: '';
+ position: absolute;
+ width: 100%;
+ height: 100%;
+ transform: scale(2.4);
+ border-radius: 50%;
+ background-color: #f2f5f8;
+ z-index: -1;
+}
+
+#error-box h1 {
+ font-size: 65px;
+ font-weight: 700;
+ margin-top: 0;
+ margin-bottom: 10px;
+ color: #151723;
+ text-transform: uppercase;
+}
+
+#error-box h2 {
+ font-size: 21px;
+ font-weight: 400;
+ margin: 0 0 1rem 0;
+ text-transform: uppercase;
+ color: #151723;
+}
+
+#error-box p {
+ color: #999fa5;
+ font-weight: 400;
+ margin-bottom: 1rem;
+}
+
+#error-box a {
+ font-weight: 500;
+ text-decoration: none;
+ color: #388dbc;
+}
+
+@media only screen and (max-width: 767px) {
+ #error-box #error-image {
+ width: 110px;
+ height: 110px;
+ }
+
+ #error-box {
+ padding-left: 15px;
+ padding-right: 15px;
+ padding-top: 110px;
+ }
+}
diff --git a/8.6-symfony/errors/img/emoji.png b/8.6-symfony/errors/img/emoji.png
new file mode 100644
index 0000000..7cd4942
Binary files /dev/null and b/8.6-symfony/errors/img/emoji.png differ
diff --git a/8.6-symfony/health.php b/8.6-symfony/health.php
new file mode 100644
index 0000000..d6bd4dc
--- /dev/null
+++ b/8.6-symfony/health.php
@@ -0,0 +1,3 @@
+
+ Options -Indexes +FollowSymLinks
+ AllowOverride None
+ Require all granted
+
+ SetEnvIf X-Forwarded-Proto "^https$" HTTPS=on
+
+
+ServerTokens Prod
+ServerSignature Off
+
+LogFormat "%a %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" combined
+
+RemoteIPHeader X-Forwarded-For
+RemoteIPInternalProxy 10.0.0.0/8
+RemoteIPInternalProxy 172.16.0.0/12
+RemoteIPInternalProxy 192.168.0.0/16
+RemoteIPInternalProxy 169.254.0.0/16
+RemoteIPInternalProxy 127.0.0.0/8
+RemoteIPInternalProxy ::1
+
+# Add Cloudflare IP ranges
+RemoteIPTrustedProxy 173.245.48.0/20
+RemoteIPTrustedProxy 103.21.244.0/22
+RemoteIPTrustedProxy 103.22.200.0/22
+RemoteIPTrustedProxy 103.31.4.0/22
+RemoteIPTrustedProxy 141.101.64.0/18
+RemoteIPTrustedProxy 108.162.192.0/18
+RemoteIPTrustedProxy 190.93.240.0/20
+RemoteIPTrustedProxy 188.114.96.0/20
+RemoteIPTrustedProxy 197.234.240.0/22
+RemoteIPTrustedProxy 198.41.128.0/17
+RemoteIPTrustedProxy 162.158.0.0/15
+RemoteIPTrustedProxy 104.16.0.0/13
+RemoteIPTrustedProxy 104.24.0.0/14
+RemoteIPTrustedProxy 172.64.0.0/13
+RemoteIPTrustedProxy 131.0.72.0/22
+RemoteIPTrustedProxy 2400:cb00::/32
+RemoteIPTrustedProxy 2606:4700::/32
+RemoteIPTrustedProxy 2803:f800::/32
+RemoteIPTrustedProxy 2405:b500::/32
+RemoteIPTrustedProxy 2405:8100::/32
+RemoteIPTrustedProxy 2a06:98c0::/29
+RemoteIPTrustedProxy 2c0f:f248::/32
+
+
+ Options -Indexes
+ AllowOverride None
+ Require all granted
+
+
+
+ Options -Indexes
+ AllowOverride None
+ Require local
+
+
+Alias /_errors/ /errors/
+
+ Alias "/health/index.php"
+
+ErrorDocument 404 /_errors/404.html
+ErrorDocument 403 /_errors/403.html
+ErrorDocument 500 /_errors/500.html
diff --git a/8.6/conf/php.ini b/8.6/conf/php.ini
new file mode 100644
index 0000000..81f7cde
--- /dev/null
+++ b/8.6/conf/php.ini
@@ -0,0 +1,23 @@
+date.timezone = Europe/Paris
+
+opcache.enable = 1
+opcache.enable_cli = 1
+opcache.memory_consumption = 256
+opcache.interned_strings_buffer = 16
+opcache.max_accelerated_files = 20000
+; Files are compiled once and never checked again: restart PHP to deploy new code, or set
+; PHP_OPCACHE_VALIDATE_TIMESTAMPS=1 when the sources are mounted and edited in place.
+opcache.validate_timestamps = ${PHP_OPCACHE_VALIDATE_TIMESTAMPS}
+opcache.revalidate_freq = 0
+apc.enable_cli = On
+
+upload_max_filesize = 16M
+post_max_size = 16M
+
+realpath_cache_size = 4096k
+realpath_cache_ttl = 7200
+
+expose_php = Off
+display_errors = Off
+display_startup_errors = Off
+error_log = /proc/self/fd/2
diff --git a/8.6/conf/vhost.conf b/8.6/conf/vhost.conf
new file mode 100644
index 0000000..a16c65c
--- /dev/null
+++ b/8.6/conf/vhost.conf
@@ -0,0 +1,8 @@
+
+ ServerAdmin hello@silarhi.fr
+
+ DocumentRoot /app
+
+ ErrorLog ${APACHE_LOG_DIR}/error.log
+ CustomLog ${APACHE_LOG_DIR}/access.log combined
+
diff --git a/8.6/errors/403.html b/8.6/errors/403.html
new file mode 100644
index 0000000..97890d1
--- /dev/null
+++ b/8.6/errors/403.html
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+ Erreur 403 (Interdit)
+
+
+
+
+
+
+
diff --git a/8.6/errors/404.html b/8.6/errors/404.html
new file mode 100644
index 0000000..f0b6399
--- /dev/null
+++ b/8.6/errors/404.html
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+ Erreur 404 (Introuvable)
+
+
+
+
+
+
+
404
+
Oops! Vous êtes perdu.
+
La page que vous demandez est introuvable. Elle a peut-être été supprimée ou déplacée.
+
Retour à la page d'accueil
+
+
+
diff --git a/8.6/errors/500.html b/8.6/errors/500.html
new file mode 100644
index 0000000..b34c2d7
--- /dev/null
+++ b/8.6/errors/500.html
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+ Erreur 500 (Inaccessible)
+
+
+
+
+
+
+
diff --git a/8.6/errors/css/style.css b/8.6/errors/css/style.css
new file mode 100644
index 0000000..6be89a5
--- /dev/null
+++ b/8.6/errors/css/style.css
@@ -0,0 +1,102 @@
+html {
+ box-sizing: border-box;
+ font-size: 16px;
+}
+
+*, *:before, *:after {
+ box-sizing: inherit;
+}
+
+body, h1, h2, h3, h4, h5, h6, p, ol, ul {
+ margin: 0;
+ padding: 0;
+ font-weight: normal;
+}
+
+ol, ul {
+ list-style: none;
+}
+
+html, body {
+ height: 100%;
+}
+
+body {
+ font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", "Liberation Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+}
+
+#error-box {
+ position: relative;
+ max-width: 560px;
+ width: 100%;
+ padding-left: 160px;
+ line-height: 1.1;
+}
+
+#error-box #error-image {
+ position: absolute;
+ left: 0;
+ top: 0;
+ display: inline-block;
+ width: 140px;
+ height: 140px;
+ background-image: url('/_errors/img/emoji.png');
+ background-size: cover;
+}
+
+#error-box #error-image:before {
+ content: '';
+ position: absolute;
+ width: 100%;
+ height: 100%;
+ transform: scale(2.4);
+ border-radius: 50%;
+ background-color: #f2f5f8;
+ z-index: -1;
+}
+
+#error-box h1 {
+ font-size: 65px;
+ font-weight: 700;
+ margin-top: 0;
+ margin-bottom: 10px;
+ color: #151723;
+ text-transform: uppercase;
+}
+
+#error-box h2 {
+ font-size: 21px;
+ font-weight: 400;
+ margin: 0 0 1rem 0;
+ text-transform: uppercase;
+ color: #151723;
+}
+
+#error-box p {
+ color: #999fa5;
+ font-weight: 400;
+ margin-bottom: 1rem;
+}
+
+#error-box a {
+ font-weight: 500;
+ text-decoration: none;
+ color: #388dbc;
+}
+
+@media only screen and (max-width: 767px) {
+ #error-box #error-image {
+ width: 110px;
+ height: 110px;
+ }
+
+ #error-box {
+ padding-left: 15px;
+ padding-right: 15px;
+ padding-top: 110px;
+ }
+}
diff --git a/8.6/errors/img/emoji.png b/8.6/errors/img/emoji.png
new file mode 100644
index 0000000..7cd4942
Binary files /dev/null and b/8.6/errors/img/emoji.png differ
diff --git a/8.6/health.php b/8.6/health.php
new file mode 100644
index 0000000..d6bd4dc
--- /dev/null
+++ b/8.6/health.php
@@ -0,0 +1,3 @@
+