Last active
December 10, 2015 00:29
-
-
Save k-holy/4351672 to your computer and use it in GitHub Desktop.
Symfony-HttpFoundationで条件付きGET
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace Acme; | |
/* | |
* 【Symfony-HttpFoundationで条件付きGET】 | |
* | |
* @copyright 2012 k-holy <[email protected]> | |
* @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