2014-09-07 00:33:46 +02:00
|
|
|
<?php
|
|
|
|
namespace Szurubooru\Services;
|
|
|
|
|
|
|
|
class FileService
|
|
|
|
{
|
|
|
|
private $dataDirectory;
|
|
|
|
private $httpHelper;
|
|
|
|
|
2014-09-10 17:41:47 +02:00
|
|
|
public function __construct(\Szurubooru\Config $config, \Szurubooru\Helpers\HttpHelper $httpHelper)
|
2014-09-07 00:33:46 +02:00
|
|
|
{
|
2014-09-10 17:41:47 +02:00
|
|
|
$this->dataDirectory = $config->getDataDirectory();
|
2014-09-07 00:33:46 +02:00
|
|
|
$this->httpHelper = $httpHelper;
|
|
|
|
}
|
|
|
|
|
2014-09-15 17:09:42 +02:00
|
|
|
public function serve($target, $options = [])
|
2014-09-07 00:33:46 +02:00
|
|
|
{
|
2014-09-15 17:09:42 +02:00
|
|
|
$fullPath = $this->getFullPath($target);
|
2014-09-07 00:33:46 +02:00
|
|
|
|
|
|
|
$daysToLive = isset($options->daysToLive)
|
2014-09-09 12:34:57 +02:00
|
|
|
? $options->daysToLive
|
|
|
|
: 7;
|
|
|
|
|
2014-09-07 00:33:46 +02:00
|
|
|
$secondsToLive = $daysToLive * 24 * 60 * 60;
|
2014-09-15 17:09:42 +02:00
|
|
|
$lastModified = filemtime($fullPath);
|
|
|
|
$eTag = md5(file_get_contents($fullPath)); //todo: faster
|
2014-09-07 00:33:46 +02:00
|
|
|
|
|
|
|
$ifModifiedSince = isset($_SERVER['HTTP_IF_MODIFIED_SINCE'])
|
|
|
|
? $_SERVER['HTTP_IF_MODIFIED_SINCE']
|
|
|
|
: false;
|
|
|
|
|
|
|
|
$eTagHeader = isset($_SERVER['HTTP_IF_NONE_MATCH'])
|
|
|
|
? trim($_SERVER['HTTP_IF_NONE_MATCH'], "\" \t\r\n")
|
2014-09-09 12:34:57 +02:00
|
|
|
: null;
|
2014-09-07 00:33:46 +02:00
|
|
|
|
|
|
|
$this->httpHelper->setHeader('ETag', '"' . $eTag . '"');
|
|
|
|
$this->httpHelper->setHeader('Last-Modified', gmdate('D, d M Y H:i:s \G\M\T', $lastModified));
|
|
|
|
$this->httpHelper->setHeader('Pragma', 'public');
|
|
|
|
$this->httpHelper->setHeader('Cache-Control', 'public, max-age=' . $secondsToLive);
|
|
|
|
$this->httpHelper->setHeader('Expires', gmdate('D, d M Y H:i:s \G\M\T', time() + $secondsToLive));
|
|
|
|
|
|
|
|
if (isset($options->customFileName))
|
|
|
|
$this->httpHelper->setHeader('Content-Disposition', 'inline; filename="' . $options->customFileName . '"');
|
|
|
|
|
2014-09-09 12:34:57 +02:00
|
|
|
$this->httpHelper->setHeader(
|
|
|
|
'Content-Type',
|
|
|
|
isset($options->mimeType)
|
|
|
|
? $options->mimeType
|
2014-09-15 17:09:42 +02:00
|
|
|
: mime_content_type($fullPath));
|
2014-09-07 00:33:46 +02:00
|
|
|
|
2014-09-09 12:34:57 +02:00
|
|
|
if (strtotime($ifModifiedSince) === $lastModified or $eTagHeader === $eTag)
|
2014-09-07 00:33:46 +02:00
|
|
|
{
|
|
|
|
$this->httpHelper->setResponseCode(304);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
$this->httpHelper->setResponseCode(200);
|
2014-09-15 17:09:42 +02:00
|
|
|
readfile($fullPath);
|
2014-09-07 00:33:46 +02:00
|
|
|
}
|
|
|
|
exit;
|
|
|
|
}
|
|
|
|
|
2014-09-09 17:49:19 +02:00
|
|
|
public function createFolders($target)
|
|
|
|
{
|
2014-09-15 11:38:24 +02:00
|
|
|
$fullPath = $this->getFullPath(dirname($target));
|
2014-09-15 17:09:42 +02:00
|
|
|
if (!file_exists($fullPath))
|
|
|
|
mkdir($fullPath, 0777, true);
|
2014-09-09 17:49:19 +02:00
|
|
|
}
|
|
|
|
|
2014-09-15 17:09:42 +02:00
|
|
|
public function exists($target)
|
2014-09-07 00:33:46 +02:00
|
|
|
{
|
2014-09-15 17:09:42 +02:00
|
|
|
$fullPath = $this->getFullPath($target);
|
|
|
|
return $target and file_exists($fullPath);
|
2014-09-07 00:33:46 +02:00
|
|
|
}
|
|
|
|
|
2014-09-15 17:09:42 +02:00
|
|
|
public function delete($target)
|
2014-09-07 00:33:46 +02:00
|
|
|
{
|
2014-09-15 17:09:42 +02:00
|
|
|
$fullPath = $this->getFullPath($target);
|
|
|
|
if (file_exists($fullPath))
|
|
|
|
unlink($fullPath);
|
2014-09-07 00:33:46 +02:00
|
|
|
}
|
|
|
|
|
2014-09-15 17:09:42 +02:00
|
|
|
public function save($destination, $data)
|
2014-09-07 00:33:46 +02:00
|
|
|
{
|
2014-09-15 11:38:24 +02:00
|
|
|
$this->createFolders($destination);
|
2014-09-07 00:33:46 +02:00
|
|
|
$finalDestination = $this->getFullPath($destination);
|
|
|
|
file_put_contents($finalDestination, $data);
|
|
|
|
}
|
|
|
|
|
|
|
|
public function getFullPath($destination)
|
|
|
|
{
|
|
|
|
return $this->dataDirectory . DIRECTORY_SEPARATOR . $destination;
|
|
|
|
}
|
2014-09-15 11:38:24 +02:00
|
|
|
|
|
|
|
public function download($url, $maxBytes = null)
|
|
|
|
{
|
|
|
|
set_time_limit(60);
|
|
|
|
try
|
|
|
|
{
|
|
|
|
$srcHandle = fopen($url, 'rb');
|
|
|
|
}
|
|
|
|
catch (Exception $e)
|
|
|
|
{
|
|
|
|
throw new \Exception('Cannot open URL for reading: ' . $e->getMessage());
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!$srcHandle)
|
|
|
|
throw new \Exception('Cannot open URL for reading');
|
|
|
|
|
|
|
|
$result = '';
|
|
|
|
try
|
|
|
|
{
|
|
|
|
while (!feof($srcHandle))
|
|
|
|
{
|
|
|
|
$buffer = fread($srcHandle, 4 * 1024);
|
2014-09-16 18:09:14 +02:00
|
|
|
if ($maxBytes !== null and strlen($result) > $maxBytes)
|
2014-09-15 11:38:24 +02:00
|
|
|
{
|
|
|
|
throw new \Exception(
|
|
|
|
'File is too big (maximum size: %s)',
|
|
|
|
TextHelper::useBytesUnits($maxBytes));
|
|
|
|
}
|
|
|
|
$result .= $buffer;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
finally
|
|
|
|
{
|
|
|
|
fclose($srcHandle);
|
|
|
|
}
|
|
|
|
|
|
|
|
return $result;
|
|
|
|
}
|
2014-09-07 00:33:46 +02:00
|
|
|
}
|