The script Oppaitime uses to serve and manage images
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

index.php 3.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. <?php
  2. // Location where hosted images will be stored
  3. define('IMG_ROOT', '/var/images/');
  4. // Pre-shared key - must match IMAGE_PSK in gazelle config
  5. define('PSK', 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA');
  6. // User agent to use when downloading files
  7. define('USER_AGENT', 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36');
  8. ini_set('memory_limit', '256M');
  9. function content_type($data) {
  10. if (!strncmp($data, pack('H*', '89504E47'), 4)) return 'image/png';
  11. if (!strncmp($data, pack('H*', 'FFD8'), 2)) return 'image/jpeg';
  12. if (!strncmp($data, 'GIF', 3)) return 'image/gif';
  13. if (strlen($data) > 35 && !substr_compare($data, 'webm', 31, 4)) return 'video/webm';
  14. if (!strncmp($data, 'BM', 2)) return 'image/bmp';
  15. if (!strncmp($data, 'II', 2) || !strncmp($data, 'MM', 2)) return 'image/tiff';
  16. return 'application/octet-stream';
  17. }
  18. function serve($path, $rescode = 200) {
  19. $filesize = filesize($path);
  20. $handle = fopen($path, "r");
  21. $content_type = content_type(fread($handle, 100));
  22. fclose($handle);
  23. header('Accept-Ranges: bytes');
  24. header("Content-Type: $content_type");
  25. if (isset($_SERVER['HTTP_RANGE'])) {
  26. preg_match('/bytes=(\d+)-(\d+)?/', $_SERVER['HTTP_RANGE'], $matches);
  27. if ($matches[1] == "") {
  28. $matches[1] = $filesize - intval($matches[2] ?? 0);
  29. $matches[2] = $filesize;
  30. }
  31. $start = intval($matches[1] ?? 0);
  32. $end = min(intval($matches[2] ?? $filesize), $filesize);
  33. http_response_code(206);
  34. header("Content-Range: bytes $start-$end/$filesize");
  35. echo file_get_contents($path, false, null, $start, $end-$start);
  36. } else {
  37. http_response_code($rescode);
  38. header("Content-Length: $filesize");
  39. readfile($path);
  40. }
  41. }
  42. if (empty($_GET['i'])) die();
  43. $img_url = $_GET['i'];
  44. $auth = rawurldecode($_GET['h']);
  45. $img_url_hash = hash('sha256', $img_url);
  46. $debug = !empty($_GET['debug']);
  47. $img_dir = IMG_ROOT.substr($img_url_hash, 0, 2);
  48. $img_path = $img_dir.'/'.$img_url_hash;
  49. // Deletion
  50. if (!empty($_GET['d'])) {
  51. $img_url = $_GET['d'];
  52. $img_url_hash = hash('sha256', $img_url);
  53. if (base64_encode(hash_hmac('sha256', $img_url, strrev(PSK), true)) != $auth) {
  54. http_response_code(401);
  55. echo 'Auth failure';
  56. die();
  57. }
  58. if (file_exists($img_path)) {
  59. unlink($img_path);
  60. http_response_code(200);
  61. echo 'Success';
  62. } else {
  63. http_response_code(404);
  64. echo 'File does not exist';
  65. }
  66. die();
  67. }
  68. // Normal use
  69. if (base64_encode(hash_hmac('sha256', $img_url, PSK, true)) != $auth) {
  70. // Authentication is incorrect. Something other than the paired Gazelle instance is attempting to use the host.
  71. serve('imgs/unauthorized.png', 401);
  72. die();
  73. }
  74. if (file_exists($img_path)) {
  75. serve($img_path);
  76. } else {
  77. // The file is not cached. Fetch it, cache it, and serve it.
  78. $img_data = @file_get_contents($img_url, 0, stream_context_create([
  79. 'http' => ['user_agent' => USER_AGENT],
  80. 'ssl' => ['verify_peer' => false]
  81. ]), 0, 134217728);
  82. $content_type = content_type($img_data);
  83. if ($content_type != 'application/octet-stream') {
  84. if (!file_exists($img_dir)) mkdir($img_dir);
  85. file_put_contents($img_path, $img_data);
  86. serve($img_path);
  87. } else {
  88. serve('imgs/invalid.png', 415);
  89. }
  90. }
  91. ?>