Skip to content

Instantly share code, notes, and snippets.

@k-holy
Last active December 10, 2015 00:29
Show Gist options
  • Save k-holy/4351672 to your computer and use it in GitHub Desktop.
Save k-holy/4351672 to your computer and use it in GitHub Desktop.
Symfony-HttpFoundationで条件付きGET
<?php
namespace Acme;
/*
* 【Symfony-HttpFoundationで条件付きGET】
*
* @copyright 2012 k-holy <k.holy74@gmail.com>
* @license The MIT License (MIT)
*/
$loader = include __DIR__ . '/../../../vendor/autoload.php';
use Silex\Application;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\StreamedResponse;
$app = new Application();
$app->register(new \Silex\Provider\UrlGeneratorServiceProvider());
// 以後、$app['url_generator'] で共有の Symfony\Component\Routing\Generator\UrlGenerator インスタンスを取得できる
class UrlGeneratorForSmarty
{
private $generator;
public function __construct(\Symfony\Component\Routing\Generator\UrlGenerator $generator)
{
$this->generator = $generator;
}
public function path($params, $smarty)
{
if (isset($params['route'])) {
$route = $params['route'];
unset($params['route']);
return $this->generator->generate($route, $params, false);
}
}
}
//------------------------------------------------------------------------------
// 画像のキャッシュとダウンロード(テンプレート)
$app->get('/', function(Application $app, Request $request) {
$smarty = new \Smarty();
$smarty->template_dir = realpath(__DIR__ . '/templates');
$smarty->compile_dir = sys_get_temp_dir();
$smarty->force_compile = true;
$smarty->escape_html = true;
$urlGenerator = new UrlGeneratorForSmarty($app['url_generator']);
$smarty->registerPlugin('function', 'build_path', array($urlGenerator, 'path'));
$data = new \StdClass();
$data->source = highlight_file(__FILE__, true);
$response = new Response();
$smarty->assign('this', $data);
$content = $smarty->fetch(sprintf('string:%s', <<<'TEMPLATE'
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8" />
<style type="text/css">
pre { font-family:monospace; font-size:large; }
</style>
<title>Silex + HttpFoundationで画像の条件付きGET</title>
</head>
<body>
<h1>Silex + HttpFoundationで画像の条件付きGET</h1>
<h2>キャッシュしない</h2>
<p><img src="{build_path route="image" no-cache="1"}" /></p>
<h2>更新日付でキャッシュ</h2>
<p><img src="{build_path route="image" last-modified="1"}" /></p>
<h2>Etagでキャッシュ</h2>
<p><img src="{build_path route="image" etag="1"}" /></p>
<h2>ダウンロード</h2>
<p><a href="{build_path route="image" download="1"}" />ダウンロード</a></p>
<h2>ソース</h2>
<pre>{$this->source nofilter}</pre>
</body>
</html>
TEMPLATE
));
$response->headers->set('Content-Length', strlen($content));
$response->setContent($content);
return $response;
})->bind('enable-caching');
//------------------------------------------------------------------------------
// 画像のキャッシュとダウンロード(画像)
$app->get('/image', function(Application $app, Request $request) {
// 画像ファイル
$file = new \SplFileInfo(__DIR__ . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR . 'sunset.jpg');
$no_cache = $request->get('no-cache', 0);
$validate_last_modified = $request->get('last-modified', 0);
$validate_etag = $request->get('etag', 0);
$download = $request->get('download', 0);
$response = new Response();
// キャッシュ禁止ではない場合、レスポンスに Last-Modified と Etag をセットし、リクエストと検証
if (!$no_cache) {
if ($validate_last_modified) {
$lastModified = new \DateTime();
$lastModified->setTimestamp($file->getMTime());
$response->setLastModified($lastModified);
}
if ($validate_etag) {
$etag = sha1(serialize(array(
'file' => $file->getRealPath(),
'size' => $file->getSize(),
'mtime' => $file->getMTime(),
)));
$response->setEtag($etag);
}
// Response::isNotModified() で検証に成功した場合はステータス 304 がセットされるので、そのまま返せばOK
if ($response->isNotModified($request)) {
return $response;
}
}
// キャッシュしない場合は StreamedResponse で返す
if ($no_cache) {
$response = new StreamedResponse();
$response->setPrivate();
$response->setCallback(function() use ($file) {
$file->openFile('r')->fpassthru();
});
} else {
$response->setPublic();
$response->setContent(file_get_contents($file->getRealPath()));
}
// 画像ファイルの情報を元にレスポンスヘッダをセット
$mimeType = new \Finfo(FILEINFO_MIME_TYPE);
$response->headers->set('Content-Type', $mimeType->file($file->getRealPath()));
$response->headers->set('Content-Disposition',
$response->headers->makeDisposition(
$download ? 'attachment' : 'inline',
$file->getBasename()
)
);
$response->headers->set('Content-Length', $file->getSize());
// IE8+用
if ($download) {
$response->headers->set('X-Download-Options', 'noopen');
}
$response->headers->set('X-Content-Type-Options', 'nosniff');
// Date, Expires
$currentDate = new \DateTime(null, new \DateTimeZone('UTC'));
$response->setDate($currentDate);
if ($no_cache) {
$response->setExpires($currentDate);
}
return $response;
})->bind('image');
$app->run();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment