Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
61
Help us understand the problem. What is going on with this article?
@ShibuyaKosuke

[PHP]ファイルアップロードサンプル(PHP → DB → HTML)

More than 3 years have passed since last update.

アップロードされた画像をデータベースに登録して、表示するサンプル です。
出典はわかりませんが、何らかの初心者向け参考書があるのか、 画像データをバイナリでデータベースに登録してしまい、表示部分で詰んでしまう 初心者が多発しているようなので、シンプルに画像のパスを保存するサンプルを書いておきました。

「しかし、何でバイナリでDBに突っ込むんだ?」と思っていたけど、「ファイルアップロード」と「DBへの保存」が一緒に書かれている記事自体がネット上に少ないという理由もあるように見受けられます。

また、 Exif情報を削除する ことに言及している記事もなかなか見つからなかった。最近のスマホカメラでは位置情報の画像への埋め込みはデフォルトでOFFになっていることが多いですが、知らずにONになっているケースもあります。 投稿された写真から自宅が特定される といった事態を事前に防ぐ必要もありますので、ご注意を。

テーブル定義

CREATE TABLE `images` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `title` varchar(32) DEFAULT NULL,
  `path` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

ディレクトリ構造

画像保存先ディレクトリ upfiles を作成し、以下のように配置する。

ドキュメントルート
┣ upfile/
┣ common.php
┣ image.php
┗ index.php

common.php

<?php

/**
 * common.php
 */

/**
 * connect_db
 * @return \PDO
 */
function connect_db()
{
    $dsn = 'mysql:host=localhost;dbname=sample;charset=utf8';
    $username = 'root';
    $password = 'password';
    $options = [
        PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
        , PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
    ];
    return new PDO($dsn, $username, $password, $options);
}

/**
 * insert
 * @param string $sql
 * @param array $arr
 * @return int lastInsertId
 */
function insert($sql, $arr = [])
{
    $pdo = connect_db();
    $stmt = $pdo->prepare($sql);
    $stmt->execute($arr);
    return $pdo->lastInsertId();
}

/**
 * select
 * @param string $sql
 * @param array $arr
 * @return array $rows
 */
function select($sql, $arr = [])
{
    $pdo = connect_db();
    $stmt = $pdo->prepare($sql);
    $stmt->execute($arr);
    return $stmt->fetchAll();
}

/**
 * htmlspecialchars
 * @param string $string
 * @return $string
 */
function h($string)
{
    return htmlspecialchars($string, ENT_QUOTES, 'utf-8');
}

index.php

<?php
/**
 * index.php
 */
/**
 * 共通関数読み込み
 */
require 'common.php';

/**
 * file_upload
 */
function file_upload()
{
    // POSTではないとき何もしない
    if (filter_input(INPUT_SERVER, 'REQUEST_METHOD') !== 'POST') {
        return;
    }

    // タイトル
    $title = filter_input(INPUT_POST, 'title');
    if ('' === $title) {
        throw new Exception('タイトルは入力必須です。');
    }

    // アップロードファイル
    $upfile = $_FILES['upfile'];

    /**
     * @see http://php.net/manual/ja/features.file-upload.post-method.php
     */
    if ($upfile['error'] > 0) {
        throw new Exception('ファイルアップロードに失敗しました。');
    }

    $tmp_name = $upfile['tmp_name'];

    // ファイルタイプチェック
    $finfo = finfo_open(FILEINFO_MIME_TYPE);
    $mimetype = finfo_file($finfo, $tmp_name);

    // 許可するMIMETYPE
    $allowed_types = [
        'jpg' => 'image/jpeg'
        , 'png' => 'image/png'
        , 'gif' => 'image/gif'
    ];
    if (!in_array($mimetype, $allowed_types)) {
        throw new Exception('許可されていないファイルタイプです。');
    }

    // ファイル名(ハッシュ値でファイル名を決定するため、同一ファイルは同盟で上書きされる)
    $filename = sha1_file($tmp_name);

    // 拡張子
    $ext = array_search($mimetype, $allowed_types);

    // 保存作ファイルパス
    $destination = sprintf('%s/%s.%s'
        , 'upfiles'
        , $filename
        , $ext
    );

    // アップロードディレクトリに移動
    if (!move_uploaded_file($tmp_name, $destination)) {
        throw new Exception('ファイルの保存に失敗しました。');
    }

    // Exif 情報の削除
    $imagick = new Imagick($destination);
    $imagick->stripimage();
    $imagick->writeimage($destination);

    // データベースに登録
    $sql = 'INSERT INTO `images` (`id`, `title`, `path`) VALUES (NULL, :title, :path) ';
    $arr = [];
    $arr[':title'] = $title;
    $arr[':path'] = $destination;
    $lastInsertId = insert($sql, $arr);

    // 成功時にページを移動する
    header(sprintf('Location: image.php?id=%d', $lastInsertId));
}

try {
    // ファイルアップロード
    file_upload();
} catch (Exception $e) {
    $error = $e->getMessage();
}
?>
<!DOCTYPE HTML>
<html lang="ja">
    <head>
        <meta charset="UTF-8">
        <title></title>
        <style type="text/css">
            .error {
                color: red;
            }
        </style>
    </head>
    <body>
        <div id="wrap">
            <?php if (isset($error)) : ?>
                <p class="error"><?= h($error); ?></p>
            <?php endif; ?>
            <form action="" method="post" enctype="multipart/form-data">
                <p>
                    <label for="title">タイトル</label>
                    <input type="text" name="title" id="title" />
                </p>
                <p>
                    <label for="upfile">画像ファイル</label>
                    <input type="file" name="upfile" id="upfile" />
                </p>
                <p>
                    <button type="submit">送信</button>
                </p>
            </form>
        </div>
    </body>
</html>

image.php

<?php
/**
 * image.php
 */
require 'common.php';

try {
    $id = filter_input(INPUT_GET, 'id');

    // データベースからレコードを取得
    $sql = 'SELECT `id`, `title`, `path` FROM `images` WHERE `id` = :id';
    $arr = [];
    $arr[':id'] = $id;
    $rows = select($sql, $arr);
    $row = reset($rows);
} catch (Exception $e) {
    $error = $e->getMessage();
}
?>
<!DOCTYPE HTML>
<html lang="ja">
    <head>
        <meta charset="UTF-8">
        <title></title>
        <style type="text/css">
            .error {
                color: red;
            }
        </style>
    </head>
    <body>
        <div id="wrap">
            <?php if (isset($error)) : ?>
                <p class="error"><?= h($error); ?></p>
            <?php endif; ?>

            <p><?= h($row['title']); ?></p>
            <p>
                <img src="<?= h($row['path']); ?>" alt="<?= h($row['title']); ?>" />
            </p>
        </div>
    </body>
</html>
61
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
61
Help us understand the problem. What is going on with this article?