LoginSignup
4
4

More than 3 years have passed since last update.

【Go言語/PHP】「ログインしていないと見れない画像」を実装

Last updated at Posted at 2017-06-21

条件は「ログインしていないと」に限らず、「夜しか見れない」とかでもなんでもよく、ある条件のときだけ閲覧できる仕組みです。

こんなこともできるんだー的な紹介であって、一般的なプロダクトで有用な手法ではありませんので、何らかの理由でこの記事のような機能を必要としている場合、別の方法を検討することをおすすめします。
(例えば、画像URLを予測不能なものにする、「画像自体」ではなくHTMLで制御する、など)

仕組み

  • 画像ファイル本体はWebからアクセスできないディレクトリに置く。
  • ログインチェックし、ログインしていないなら403を返す。
  • ログインしているなら対応する画像データを(レスポンスヘッダでContent-typeを指定したうえで)返す。
  • ログインしていても、対応する画像がなければ404を返す。

という感じです。

Goで実装

ginというWAFを使ってリクエストとレスポンスを制御していますが、そこは重要ではないので好きに置き換えて大丈夫です。

main.go
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版

index.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で実行できるようにしたらいいかと思います。

4
4
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
4