条件は「ログインしていないと」に限らず、「夜しか見れない」とかでもなんでもよく、ある条件のときだけ閲覧できる仕組みです。
こんなこともできるんだー的な紹介であって、一般的なプロダクトで有用な手法ではありませんので、何らかの理由でこの記事のような機能を必要としている場合、別の方法を検討することをおすすめします。
(例えば、画像URLを予測不能なものにする、「画像自体」ではなくHTMLで制御する、など)
仕組み
- 画像ファイル本体はWebからアクセスできないディレクトリに置く。
- ログインチェックし、ログインしていないなら403を返す。
- ログインしているなら対応する画像データを(レスポンスヘッダでContent-typeを指定したうえで)返す。
- ログインしていても、対応する画像がなければ404を返す。
という感じです。
Goで実装
ginというWAFを使ってリクエストとレスポンスを制御していますが、そこは重要ではないので好きに置き換えて大丈夫です。
package main
import (
"github.com/gin-gonic/gin"
"os"
"mime"
"strings"
"io/ioutil"
)
func main() {
router := gin.Default()
router.GET("/img/:filename", getImage)
router.Run(":8080")
}
// ログインしているときだけ画像を表示
func getImage(c *gin.Context) {
if isLoggedin() {
// ログインしている
dir := "./img"
filename := c.Param("filename")
file, e := os.Open(dir+"/"+filename)
if e == nil {
// 画像が存在する
contentType := getContentType(filename)
fileData, _ := ioutil.ReadAll(file)
c.Data(200, contentType, fileData)
} else {
// 画像が存在しない
c.Status(404)
}
} else {
// ログインしていない
c.Status(403)
}
}
// ファイル名からcontentTypeを取得
func getContentType(filename string) string {
pos := strings.LastIndex(filename, ".")
contentType := mime.TypeByExtension(filename[pos:])
return contentType
}
// ログインしているかどうか
func isLoggedin() bool {
return true // ログインしている
// return false // ログインしていない
}
画像は以下のように配置しておく。
project/
├ main.go
└ img
└ hoge.png
確認
実行後、http://localhost:8080/img/hoge.png
にアクセスして画像が表示されることを確認してください。
次に、isLoggedin()
の結果をfalseに変更した上でもう一度アクセスし、403エラーが返ってくることを確認してください。
実際のファイルの閲覧権限を弄ったりしているわけではないので、./img/
ディレクトリがウェブから見える位置にあれば当然見えてしまうので注意してください。
PHP版
<?php
define('DIR', '../img/');
function main() {
if(isLoggedin()) {
// ログインしている
$filePath = DIR.basename($_GET['filename']);
if(file_exists($filePath)) {
// 画像が存在する
$contentType = mime_content_type($filePath);
header('Content-Type: Content-type: '.$contentType);
readfile($filePath);
} else {
// 画像が存在しない
header('HTTP/1.1 404 Not Found');
}
} else {
// ログインしていない
header('HTTP/1.1 403 Forbidden');
}
}
function isLoggedin() {
return true; // ログインしている
// return false; // ログインしていない
}
main();
画像は以下のようにドキュメントルートの外に配置しておく。
project/
├ htdocs
│ └ index.php
└ img
└ hoge.png
確認
http://xxx/index.php?filename=hoge.png
へアクセスし、Goのときと同様にisLoggedin()
がtrueのときだけ見れることを確認して下さい。
ルーティングはhtaccessなりで変更し、http://xxx/img/hoge.png
で実行できるようにしたらいいかと思います。