![]()
Cannot retrieve contributors at this time
| <?php | |
| /** | |
| * This is a lightweight proxy for serving images, generally meant to be used alongside SSL | |
| * | |
| * Simple Machines Forum (SMF) | |
| * | |
| * @package SMF | |
| * @author Simple Machines http://www.simplemachines.org | |
| * @copyright 2015 Simple Machines and individual contributors | |
| * @license http://www.simplemachines.org/about/smf/license.php BSD | |
| * | |
| * @version 2.1 Beta 2 | |
| */ | |
| define('SMF', 'proxy'); | |
| /** | |
| * Class ProxyServer | |
| */ | |
| class ProxyServer | |
| { | |
| /** | |
| * @var bool $enabled Whether or not this is enabled | |
| */ | |
| protected $enabled; | |
| /** | |
| * @var int $maxSize The maximum size for files to cache | |
| */ | |
| protected $maxSize; | |
| /** | |
| * @var string $secret A secret code used for hashing | |
| */ | |
| protected $secret; | |
| /** | |
| * @var string The cache directory | |
| */ | |
| protected $cache; | |
| /** | |
| * Constructor, loads up the Settings for the proxy | |
| * | |
| * @access public | |
| */ | |
| public function __construct() | |
| { | |
| global $image_proxy_enabled, $image_proxy_maxsize, $image_proxy_secret, $cachedir, $sourcedir; | |
| require_once(dirname(__FILE__) . '/Settings.php'); | |
| require_once($sourcedir . '/Class-CurlFetchWeb.php'); | |
| $this->enabled = (bool) $image_proxy_enabled; | |
| $this->maxSize = (int) $image_proxy_maxsize; | |
| $this->secret = (string) $image_proxy_secret; | |
| $this->cache = $cachedir . '/images'; | |
| } | |
| /** | |
| * Checks whether the request is valid or not | |
| * | |
| * @access public | |
| * @return bool Whether the request is valid | |
| */ | |
| public function checkRequest() | |
| { | |
| if (!$this->enabled) | |
| return false; | |
| // Try to create the image cache directory if it doesn't exist | |
| if (!file_exists($this->cache)) | |
| if (!mkdir($this->cache) || !copy(dirname($this->cache) . '/index.php', $this->cache . '/index.php')) | |
| return false; | |
| if (empty($_GET['hash']) || empty($_GET['request'])) | |
| return false; | |
| $hash = $_GET['hash']; | |
| $request = $_GET['request']; | |
| if (md5($request . $this->secret) != $hash) | |
| return false; | |
| // Attempt to cache the request if it doesn't exist | |
| if (!$this->isCached($request)) | |
| return $this->cacheImage($request); | |
| return true; | |
| } | |
| /** | |
| * Serves the request | |
| * | |
| * @access public | |
| * @return void | |
| */ | |
| public function serve() | |
| { | |
| $request = $_GET['request']; | |
| $cached_file = $this->getCachedPath($request); | |
| $cached = json_decode(file_get_contents($cached_file), true); | |
| // Is the cache expired? | |
| if (!$cached || time() - $cached['time'] > (5 * 86400)) | |
| { | |
| @unlink($cached_file); | |
| if ($this->checkRequest()) | |
| $this->serve(); | |
| exit; | |
| } | |
| // Make sure we're serving an image | |
| $contentParts = explode('/', !empty($cached['content-type']) ? $cached['content-type'] : ''); | |
| if ($contentParts[0] != 'image') | |
| exit; | |
| header('Content-type: ' . $cached['content_type']); | |
| header('Content-length: ' . $cached['size']); | |
| echo base64_decode($cached['body']); | |
| } | |
| /** | |
| * Returns the request's hashed filepath | |
| * | |
| * @access public | |
| * @param string $request The request to get the path for | |
| * @return string The hashed filepath for the specified request | |
| */ | |
| protected function getCachedPath($request) | |
| { | |
| return $this->cache . '/' . sha1($request . $this->secret); | |
| } | |
| /** | |
| * Check whether the image exists in local cache or not | |
| * | |
| * @access protected | |
| * @param string $request The image to check for in the cache | |
| * @return bool Whether or not the requested image is cached | |
| */ | |
| protected function isCached($request) | |
| { | |
| return file_exists($this->getCachedPath($request)); | |
| } | |
| /** | |
| * Attempts to cache the image while validating it | |
| * | |
| * @access protected | |
| * @param string $request The image to cache/validate | |
| * @return bool Whether the specified image was cached | |
| */ | |
| protected function cacheImage($request) | |
| { | |
| $dest = $this->getCachedPath($request); | |
| $curl = new curl_fetch_web_data(array(CURLOPT_BINARYTRANSFER => 1)); | |
| $request = $curl->get_url_data($request); | |
| $response = $request->result(); | |
| if (empty($response)) | |
| return false; | |
| $headers = $response['headers']; | |
| // Make sure the url is returning an image | |
| $contentParts = explode('/', !empty($headers['content-type']) ? $headers['content-type'] : ''); | |
| if ($contentParts[0] != 'image') | |
| return false; | |
| // Validate the filesize | |
| if ($response['size'] > ($this->maxSize * 1024)) | |
| return false; | |
| return file_put_contents($dest, json_encode(array( | |
| 'content_type' => $headers['content-type'], | |
| 'size' => $response['size'], | |
| 'time' => time(), | |
| 'body' => base64_encode($response['body']), | |
| ))); | |
| } | |
| } | |
| $proxy = new ProxyServer(); | |
| if ($proxy->checkRequest()) | |
| $proxy->serve(); | |
| exit; |