WebOrbiton
v3.0.0.2

FlatlyPage

197 lines · 5.0 KB
  1. <?php
  2. $configPath = __DIR__ . '/data/sitemap-config.php';
  3. if (!is_file($configPath)) {
  4. $configPath = __DIR__ . '/data/default-sitemap-config.php';
  5. }
  6. $config = require $configPath;
  7. ​
  8. if (!isset($config['sitemap']) || $config['sitemap'] !== true) {
  9. http_response_code(404);
  10. exit('Sitemap disabled');
  11. }
  12. ​
  13. @ini_set('display_errors', '0');
  14. @error_reporting(0);
  15. ​
  16. if (function_exists('ob_get_level')) {
  17. while (@ob_get_level()) @ob_end_clean();
  18. }
  19. ​
  20. ob_start();
  21. ​
  22. @header('Content-Type: application/xml; charset=utf-8');
  23. @header('X-Content-Type-Options: nosniff');
  24. @header('X-Frame-Options: DENY');
  25. ​
  26. $rate_limit_file = sys_get_temp_dir() . '/sitemap_rate_' . md5($_SERVER['REMOTE_ADDR'] ?? 'unknown');
  27. $now = time();
  28. $max_requests = 10;
  29. $time_window = 60;
  30. $access_times = [];
  31. ​
  32. if (@file_exists($rate_limit_file)) {
  33. $content = @file_get_contents($rate_limit_file);
  34. $access_times = $content ? @unserialize($content) : [];
  35. if (!is_array($access_times)) {
  36. $access_times = [];
  37. }
  38. }
  39. ​
  40. $access_times = array_filter($access_times, function($timestamp) use ($now, $time_window) {
  41. return ($now - $timestamp) < $time_window;
  42. });
  43. ​
  44. if (count($access_times) >= $max_requests) {
  45. http_response_code(429);
  46. exit('Too many requests');
  47. }
  48. ​
  49. $access_times[] = $now;
  50. ​
  51. @file_put_contents($rate_limit_file, @serialize($access_times));
  52. ​
  53. ​
  54. function safe_xml($str) {
  55. return htmlspecialchars((string)$str, ENT_XML1 | ENT_QUOTES, 'UTF-8');
  56. }
  57. ​
  58. function safe_slug($slug) {
  59. $slug = strtolower(trim((string)$slug, '/'));
  60. $slug = preg_replace('/[^a-z0-9\-_]/', '', $slug);
  61. return substr($slug, 0, 100);
  62. }
  63. ​
  64. function safe_date($file, $base_dir) {
  65. $real_file = @realpath($file);
  66. $real_base = @realpath($base_dir);
  67. if (!$real_file || !$real_base || strpos($real_file, $real_base) !== 0) {
  68. return gmdate('Y-m-d');
  69. }
  70. if (@file_exists($real_file)) {
  71. return gmdate('Y-m-d', @filemtime($real_file));
  72. }
  73. return gmdate('Y-m-d');
  74. }
  75. ​
  76. function validate_url($url, $allowed_domain) {
  77. $parsed = @parse_url($url);
  78. if (!$parsed || !isset($parsed['host'])) {
  79. return false;
  80. }
  81. if ($parsed['host'] !== $allowed_domain) {
  82. return false;
  83. }
  84. if (!in_array($parsed['scheme'] ?? '', ['http', 'https'])) {
  85. return false;
  86. }
  87. return true;
  88. }
  89. ​
  90. $configured_host = strtolower((string) parse_url(preg_match('#^https?://#i', (string) $config['website_domain']) ? $config['website_domain'] : 'https://' . $config['website_domain'], PHP_URL_HOST));
  91. $allowed_hosts = [
  92. $configured_host,
  93. 'www.' . $configured_host
  94. ];
  95. ​
  96. $host = isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : '';
  97. $host = preg_replace('/:\d+$/', '', $host);
  98. ​
  99. if (!in_array($host, $allowed_hosts)) {
  100. http_response_code(400);
  101. exit('Invalid host');
  102. }
  103. ​
  104. $protocol = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on') ? 'https' : 'http';
  105. $install_base = rtrim(str_replace(chr(92), "/", dirname($_SERVER["SCRIPT_NAME"] ?? "")), "/");
  106. $base_url = $protocol . '://' . $host . $install_base;
  107. ​
  108. ​
  109. $pages = [];
  110. $base_dir = __DIR__;
  111. ​
  112. $pages[] = [
  113. 'loc' => $base_url . '/',
  114. 'lastmod' => gmdate('Y-m-d'),
  115. 'priority' => '1.0'
  116. ];
  117. ​
  118. $data_dir = $base_dir . '/data/';
  119. $real_data_dir = @realpath($data_dir);
  120. $real_base_dir = @realpath($base_dir);
  121. ​
  122. if ($real_data_dir && $real_base_dir &&
  123. strpos($real_data_dir, $real_base_dir) === 0 &&
  124. @is_dir($real_data_dir)) {
  125. $pattern = $real_data_dir . '/product-*.php';
  126. $files = @glob($pattern);
  127. if (is_array($files)) {
  128. $count = 0;
  129. foreach ($files as $file) {
  130. $real_file = @realpath($file);
  131. if (!$real_file || strpos($real_file, $real_data_dir) !== 0) {
  132. continue;
  133. }
  134. $name = basename($real_file, '.php');
  135. if (!preg_match('/^product-[a-z0-9\-]{1,50}$/', $name)) {
  136. continue;
  137. }
  138. $slug = str_replace('product-', '', $name);
  139. $slug = safe_slug($slug);
  140. if (!$slug) {
  141. continue;
  142. }
  143. $url = $base_url . '/' . $slug;
  144. if (!validate_url($url, $host)) {
  145. continue;
  146. }
  147. $pages[] = [
  148. 'loc' => $url,
  149. 'lastmod' => safe_date($real_file, $real_data_dir),
  150. 'priority' => '0.8'
  151. ];
  152. $count++;
  153. if ($count >= 500) {
  154. break;
  155. }
  156. }
  157. }
  158. }
  159. ​
  160. ​
  161. echo '<?xml version="1.0" encoding="UTF-8"?>';
  162. echo "\n";
  163. echo '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">', "\n";
  164. ​
  165. foreach ($pages as $p) {
  166. echo '<url>';
  167. echo '<loc>' . safe_xml($p['loc']) . '</loc>';
  168. echo '<lastmod>' . safe_xml($p['lastmod']) . '</lastmod>';
  169. echo '<changefreq>weekly</changefreq>';
  170. echo '<priority>' . safe_xml($p['priority']) . '</priority>';
  171. echo '</url>', "\n";
  172. }
  173. ​
  174. echo '</urlset>';
  175. ​
  176. ob_end_flush();
  177. exit;
  178. ?>