Skip to content

Commit fd9f363

Browse files
committed
refactor: migrated gzipped sitemap routes (#3834)
1 parent 16e8237 commit fd9f363

File tree

7 files changed

+90
-35
lines changed

7 files changed

+90
-35
lines changed

.docker/frankenphp/Caddyfile

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,6 @@
2828
php_server
2929
}
3030

31-
# Google sitemap
32-
rewrite /sitemap.xml /index.php
33-
rewrite /sitemap.gz /index.php
34-
rewrite /sitemap.xml.gz /index.php
35-
3631
# Setup and update pages
3732
@setup path /setup*
3833
rewrite @setup /setup/index.php
@@ -94,11 +89,6 @@
9489
php_server
9590
}
9691

97-
# Google sitemap
98-
rewrite /sitemap.xml /index.php
99-
rewrite /sitemap.gz /index.php
100-
rewrite /sitemap.xml.gz /index.php
101-
10292
@setup path /setup*
10393
rewrite @setup /setup/index.php
10494

.docker/nginx/default.conf

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -77,11 +77,6 @@ server {
7777
# a solution id page
7878
rewrite ^/solution_id_([0-9]+)\.html$ /index.php?solution_id=$1 last;
7979

80-
# PMF Google sitemap
81-
rewrite ^/sitemap\.xml$ /index.php last;
82-
rewrite ^/sitemap\.gz$ /index.php last;
83-
rewrite ^/sitemap\.xml\.gz$ /index.php last;
84-
8580
# Administration API
8681
rewrite ^/admin/api/(.*)$ /admin/api/index.php last;
8782

@@ -211,11 +206,6 @@ server {
211206

212207
location @rewriteapp {
213208

214-
# PMF Google sitemap
215-
rewrite ^/sitemap\.xml$ /index.php last;
216-
rewrite ^/sitemap\.gz$ /index.php last;
217-
rewrite ^/sitemap\.xml\.gz$ /index.php last;
218-
219209
# Administration API
220210
rewrite ^/admin/api/(.*)$ /admin/api/index.php last;
221211

docs/installation.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,11 @@ To install it, you will need a web server that meets the following requirements:
2020
- Sodium support
2121
- intl support
2222

23+
Suggested PHP extensions:
24+
25+
- mbstring
26+
- zlib
27+
2328
### Web server requirements
2429

2530
You can use phpMyFAQ with the following web servers:

nginx.conf

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -88,11 +88,6 @@ server {
8888

8989
location @rewriteapp {
9090

91-
# PMF Google sitemap
92-
rewrite ^/sitemap\.xml$ /index.php last;
93-
rewrite ^/sitemap\.gz$ /index.php last;
94-
rewrite ^/sitemap\.xml\.gz$ /index.php last;
95-
9691
# Administration API
9792
rewrite ^/admin/api/(.*)$ /admin/api/index.php last;
9893

phpmyfaq/.htaccess

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -104,10 +104,6 @@ Header set Access-Control-Allow-Headers "Content-Type, Authorization"
104104
RewriteRule ^(admin/assets)($|/) - [L]
105105
# Error pages
106106
ErrorDocument 404 /404.html
107-
# phpMyFAQ Google sitemap
108-
RewriteRule ^sitemap.xml$ index.php [L,QSA]
109-
RewriteRule ^sitemap.gz$ index.php [L,QSA]
110-
RewriteRule ^sitemap.xml.gz$ index.php [L,QSA]
111107
# Administration API
112108
RewriteRule ^admin/api/(.*) admin/api/index.php [L,QSA]
113109
# Administration pages

phpmyfaq/src/phpMyFAQ/Controller/SitemapController.php

Lines changed: 75 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,36 @@
2121

2222
use phpMyFAQ\Core\Exception;
2323
use phpMyFAQ\Twig\TemplateException;
24+
use Symfony\Component\HttpFoundation\RedirectResponse;
2425
use Symfony\Component\HttpFoundation\Response;
2526
use Symfony\Component\Routing\Attribute\Route;
2627

2728
final class SitemapController extends AbstractController
2829
{
2930
private const int PMF_SITEMAP_GOOGLE_MAX_URLS = 50000;
3031

32+
/**
33+
* Returns gzipped sitemap.xml or redirects to plain XML if zlib is not available
34+
*
35+
* @throws TemplateException|Exception|\Exception
36+
*/
37+
#[Route(path: '/sitemap.gz', name: 'public.sitemap.gz')]
38+
public function sitemapGz(): Response
39+
{
40+
return $this->generateGzippedSitemap();
41+
}
42+
43+
/**
44+
* Returns gzipped sitemap.xml or redirects to plain XML if zlib is not available
45+
*
46+
* @throws TemplateException|Exception|\Exception
47+
*/
48+
#[Route(path: '/sitemap.xml.gz', name: 'public.sitemap.xml.gz')]
49+
public function sitemapXmlGz(): Response
50+
{
51+
return $this->generateGzippedSitemap();
52+
}
53+
3154
/**
3255
* @throws TemplateException|Exception|\Exception
3356
*/
@@ -36,15 +59,35 @@ public function index(): Response
3659
{
3760
$response = new Response();
3861

39-
$siteMapEnabled = $this->configuration->get(item: 'seo.enableXMLSitemap');
40-
if (!$siteMapEnabled) {
62+
$xml = $this->generateSitemapXml();
63+
64+
if ($xml === null) {
4165
$response->setStatusCode(Response::HTTP_NOT_FOUND);
4266
$response->setContent('XML Sitemap is disabled.');
4367
return $response;
4468
}
4569

46-
$faqStatistics = $this->container->get(id: 'phpmyfaq.faq.statistics');
70+
$response->headers->set('Content-Type', 'text/xml');
71+
$response->setStatusCode(Response::HTTP_OK);
72+
$response->setContent($xml);
4773

74+
return $response;
75+
}
76+
77+
/**
78+
* Generates the sitemap XML content
79+
*
80+
* @throws TemplateException|Exception|\Exception
81+
* @return string|null Returns XML content or null if sitemap is disabled
82+
*/
83+
private function generateSitemapXml(): ?string
84+
{
85+
$siteMapEnabled = $this->configuration->get(item: 'seo.enableXMLSitemap');
86+
if (!$siteMapEnabled) {
87+
return null;
88+
}
89+
90+
$faqStatistics = $this->container->get(id: 'phpmyfaq.faq.statistics');
4891
$items = $faqStatistics->getTopTenData(self::PMF_SITEMAP_GOOGLE_MAX_URLS - 1);
4992

5093
$urls = [];
@@ -56,11 +99,37 @@ public function index(): Response
5699
];
57100
}
58101

59-
$xml = $this->renderView(pathToTwigFile: './sitemap.xml.twig', templateVars: ['urls' => $urls]);
102+
return $this->renderView(pathToTwigFile: './sitemap.xml.twig', templateVars: ['urls' => $urls]);
103+
}
104+
105+
/**
106+
* Generates a gzipped sitemap response or redirects if zlib is unavailable
107+
*
108+
* @throws TemplateException|Exception|\Exception
109+
*/
110+
private function generateGzippedSitemap(): Response
111+
{
112+
// Fallback to plain XML if zlib extension is not available
113+
if (!extension_loaded('zlib')) {
114+
return new RedirectResponse('/sitemap.xml', Response::HTTP_MOVED_PERMANENTLY);
115+
}
116+
117+
$xml = $this->generateSitemapXml();
60118

61-
$response->headers->set(key: 'Content-Type', values: 'text/xml');
119+
if ($xml === null) {
120+
$response = new Response();
121+
$response->setStatusCode(Response::HTTP_NOT_FOUND);
122+
$response->setContent('XML Sitemap is disabled.');
123+
return $response;
124+
}
125+
126+
$gzipped = gzencode($xml, 9);
127+
128+
$response = new Response($gzipped);
129+
$response->headers->set('Content-Type', 'application/x-gzip');
130+
$response->headers->set('Content-Encoding', 'gzip');
131+
$response->headers->set('Content-Disposition', 'attachment; filename="sitemap.xml.gz"');
62132
$response->setStatusCode(Response::HTTP_OK);
63-
$response->setContent($xml);
64133

65134
return $response;
66135
}

phpmyfaq/src/public-routes.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,16 @@
214214
'controller' => [SitemapController::class, 'index'],
215215
'methods' => 'GET',
216216
],
217+
'public.sitemap.gz' => [
218+
'path' => '/sitemap.gz',
219+
'controller' => [SitemapController::class, 'sitemapGz'],
220+
'methods' => 'GET',
221+
],
222+
'public.sitemap.xml.gz' => [
223+
'path' => '/sitemap.xml.gz',
224+
'controller' => [SitemapController::class, 'sitemapXmlGz'],
225+
'methods' => 'GET',
226+
],
217227
'public.webauthn.index' => [
218228
'path' => '/services/webauthn/',
219229
'controller' => [WebAuthnController::class, 'index'],

0 commit comments

Comments
 (0)