Skip to content

Instantly share code, notes, and snippets.

@hakuno
Created March 28, 2019 12:55
Show Gist options
  • Save hakuno/ff66d9b802d560570d031c347f7c5ce1 to your computer and use it in GitHub Desktop.
Save hakuno/ff66d9b802d560570d031c347f7c5ce1 to your computer and use it in GitHub Desktop.
Exemplo cURL
<?php
namespace App\Http\Controllers;
use Symfony\Component\HttpFoundation\BinaryFileResponse; // http://api.symfony.com/4.0/Symfony/Component/HttpFoundation/BinaryFileResponse.html
use Symfony\Component\HttpFoundation\File\Stream; // https://api.symfony.com/3.4/Symfony/Component/HttpFoundation/File/Stream.html
use SplFileObject;
use Exception;
// https://symfony.com/doc/current/components/http_foundation.html
// https://api.symfony.com/2.3/Symfony/Component/HttpFoundation/StreamedResponse.html
// https://coderwall.com/p/rl6v7a/http-caching-in-symfony2-max-age-etag-gzip
// use Symfony\Component\HttpFoundation\StreamedResponse;
// use Symfony\Component\HttpFoundation\ResponseHeaderBag;
class StorageController
{
protected $host = 'http://cdn.example.com/test/%s';
protected $volumeReceiver = "public";
protected $stream;
private $fileHash = '';
private $fileModified = 0;
private $filePath = "";
private $fileTimestamp;
public function __destruct()
{
if (is_null($this->stream)) {
//
} elseif (is_resource($this->stream)) {
fclose($this->stream);
} elseif ($this->stream instanceof SplFileObject) {
$this->stream = null;
} else {
//
}
}
public function index()
{
return view('default');
}
public function show($id)
{
// Clear cache
// php artisan flush:public --age=4|--force
if (preg_match('/^([a-z0-9]{64})(\.[a-z0-9]{3,4})?$/', strtolower($id), $matches)) {
$identifier = $matches[1];
$extension = isset($matches[2]) ? $matches[2] : null;
$locker = $this->cache_directory($identifier.'.lock');
} else {
abort(404);
}
if (!is_null($extension)) {
$filename = $this->cache_directory("{$identifier}.{$extension}");
if (file_exists($filename)) {
$this->filePath = $filename;
$this->fileTimestamp = filemtime($filename);
$this->fileModified = gmdate('D, d M Y H:i:s \G\M\T', $this->fileTimestamp);
$this->fileHash = hash_file("sha512/256", $filename);
}
} else {
$filenames = [
$this->cache_directory("{$identifier}.jpg"),
$this->cache_directory("{$identifier}.pdf")
];
foreach ($filenames as $filename) {
if (file_exists($filename)) {
$this->filePath = $filename;
$this->fileTimestamp = filemtime($filename);
$this->fileModified = gmdate('D, d M Y H:i:s \G\M\T', $this->fileTimestamp);
$this->fileHash = hash_file("sha512/256", $filename);
break;
}
}
}
$ifmod = isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) ? $_SERVER['HTTP_IF_MODIFIED_SINCE'] == $this->fileModified : null;
$iftag = isset($_SERVER['HTTP_IF_NONE_MATCH']) ? $_SERVER['HTTP_IF_NONE_MATCH'] == "\"{$this->fileHash}\"" : null;
$headers = ['ETag' => "\"{$this->fileHash}\""];
if ($this->filePath && ($ifmod || $iftag) && ($ifmod !== false && $iftag !== false)) {
if ($identifier === $this->fileHash || $identifier === hash_file("sha256", $this->filePath)) {
abort(304, 'Not Modified', $headers);
}
}
if ($this->filePath && file_exists($locker)) {
$now = time();
$popular = strtotime('+1 day', $this->fileTimestamp);
$revisited = $now > $popular;
if ($revisited) {
touch($this->filePath);
}
return $this->render($this->filePath);
}
$database = app('db');
$cache = app('cache');
$arquivo = $cache->remember(substr($identifier, 0, 12), 5, function () use ($database, $identifier) {
return $database->table("arquivos")->where('sha256', '=', $identifier)->first();
});
if (is_null($arquivo)) {
return response(null, 404);
}
$volume = $database->table('volumes')->where('id', $arquivo->volume_id)->first();
$caminho = $arquivo->unidade.'/'.$volume->volume.'/'.$arquivo->id.".".$arquivo->extensao;
$destino = mb_strtolower($arquivo->sha256.'.'.$arquivo->extensao);
$storage = app('filesystem');
$input = $storage->disk($volume->disco)->getDriver();
if (! $input->has($caminho)) {
$response = $this->download($arquivo, $caminho);
} else {
$this->stream = $input->readStream($caminho);
// Caching
$this->writeDown($destino);
$identical = hash("sha512/256", $input->read($caminho)) === $this->fileHash;
if ($identical) {
file_put_contents($locker, time());
}
$response = $this->render($this->cache_directory($destino));
}
return $response;
}
private function render($path, $forceStream = false)
{
if ($forceStream) {
$path = new Stream($path);
$mimetype = $path->getMimeType();
} else {
$mimetype = mime_content_type($path);
}
$response = new BinaryFileResponse($path);
$response->setPrivate();
$response->setMaxAge(0);
$response->headers->addCacheControlDirective('must-revalidate', true);
$response->headers->set('Content-Type', $mimetype);
$response->setAutoLastModified();
$response->headers->set('ETag', "\"{$this->fileHash}\"");
return $response;
}
private function showUp()
{
$browser = fopen('php://output', 'w');
$working = false;
while (feof($this->stream) === false) {
stream_copy_to_stream($this->stream, $browser, 1024*1024);
if (connection_status() !== 0) {
break;
} else {
if ($working === false) {
$working = true;
set_time_limit(180);
}
}
}
if (is_resource($browser)) {
fclose($browser);
}
}
protected function writeDown($destino, $host = "public", $contents = null)
{
$storage = app('filesystem');
$output = $storage->disk($host)->getDriver();
$contents = is_null($contents)
? (is_null($this->stream) ? "" : $this->stream)
: $contents;
if (! $output->has($destino)) {
if ($contents instanceof SplFileObject) {
$contents->fseek(0);
return $output->write($destino, $contents->fread($contents->getSize()));
} elseif (is_resource($contents)) {
return $output->writeStream($destino, $this->stream);
} else {
return $output->write($destino, $contents);
}
}
}
private function cache_directory($filename = null)
{
$directory = ($filename) ? storage_path("app/public/{$filename}") : storage_path('app/public');
return $directory;
}
protected function download($arquivo, $allocation = "", $filesystem = "public")
{
try {
$filename = $arquivo->sha256.'.'.$arquivo->extensao;
$fileUrl = sprintf($this->host, $filename);
$cache = $this->cache_directory($filename);
$file = new Stream($cache, false);
$writing = false;
if ($file->isFile()) {
$this->stream = $file->openFile('r');
$wouldblock = true;
if ($this->stream->flock(LOCK_SH, $wouldblock) === false) {
throw new Exception;
}
$response = new BinaryFileResponse($file);
$response->headers->set('Content-Type', $arquivo->mimetype);
$this->stream->flock(LOCK_UN);
$this->stream = null;
return $response;
}
$this->stream = $file->openFile('a+');
if ($this->stream->flock(LOCK_EX)) {
$this->stream->ftruncate(0);
$this->fileRetriever($fileUrl, $this->stream);
// Release
if ($this->stream->flock(LOCK_UN)) {
$storage = app('filesystem');
$repository = $storage->disk($filesystem)->getDriver();
if (! $repository->has($allocation)) {
$this->writeDown($allocation, $filesystem, $this->stream);
}
}
$this->stream = null;
}
$response = new BinaryFileResponse($file);
$response->headers->set('Content-Type', $arquivo->mimetype);
return $response;
} catch (Exception $issue) {
// Issue
// dd([$issue->getLine(), $issue->getMessage()]);
return response(null, 500);
}
}
protected function fileRetriever($fileUrl, $stream, $timeOut = 30)
{
try {
$ch = curl_init($fileUrl);
curl_setopt($ch, CURLOPT_TIMEOUT, $timeOut);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($ch, CURLOPT_WRITEFUNCTION, function ($ch, $data) {
$length = $this->stream->fwrite($data);
return $length;
});
curl_exec($ch);
// Get the HTTP status code.
$statusCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
// If there was an error, throw an Exception
if (curl_errno($ch)) {
throw new Exception("Error Processing Request", 500);
}
} catch (Exception $issue) {
$statusCode = 500;
} finally {
curl_close($ch);
return (int) $statusCode;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment