PHP によるファイルアップロードの例

このページは、PHP で ファイルアップロードを行う例を記載したページです。

注意

  • コードのライセンスは CC0 (クレジット表示不要、改変可、商用可) です。

コード

<?php
/**
 * ファイルをアップロードします。
 *
 * @param string $name <input> の name 属性
 * @param string $uploadDir アップロードフォルダのパス
 * @param array $options {
 *     オプション配列
 *
 *     @type array $allows 許可するファイルのMIMEタイプの配列 (array('image/gif', 'image/png', 'image/jpeg') 等)
 *     @type callable $filename_callback ファイル名を生成するための関数 (指定されていない場合はアップロードされたファイル名を使用します)
 * }
 * @return 'success' (成功した場合 true), 'message' (結果メッセージ), 'files' (ファイルアップロード情報) のキーからなる array
 */
function file_upload($name, $uploadDir, $options = array()) {
    $allows = isset($options['allows']) ? $options['allows'] : array(); // 許可するMIMEタイプ
    $allowsMap = array_fill_keys($allows, true);
    $filenameCallback = isset($options['filename_callback']) ? $options['filename_callback'] : null; // ファイル名生成用コールバック
    
    if (isset($_FILES[$name]['tmp_name'])) {
        // 複数アップロードでも単一アップロードでも対応できるようにデータを同じ構造にまとめます。
        $files = array();
        if (is_array($_FILES[$name]['tmp_name'])) {
            for ($i = 0; $i < count($_FILES[$name]['tmp_name']); $i++) {
                $file = array();
                foreach ($_FILES[$name] as $key => $value) { $file[$key] = $_FILES[$name][$key][$i]; }
                $files[] = $file;
            }
        }
        else {
            $files[] = $_FILES[$name];
        }

        foreach ($files as $i => $file) {
            // 一時フォルダへのアップロード成功
            if ($file['error'] == UPLOAD_ERR_OK) {
                // MIMEタイプの確認
                $mime = mime_content_type($file['tmp_name']);
                if (!isset($allowsMap[$mime])) {
                    return array('success' => false, 'message' => 'アップロードされた形式のファイルは許可されていません。', 'files' => $files);
                }
                // ファイル名取得
                $filename = '';
                if (is_callable($filenameCallback)) $filename = call_user_func($filenameCallback, $file); // ファイル名生成
                if (strlen($filename) == 0) { // コールバックでファイル名が得られなければアップロードされたファイル名 (使用できない文字を除去)
                    $filename = trim(preg_replace('#[\x00-\x20\x7f\\\\/:*?\"<>|]#', '', basename($file['name'])), '.');
                }
                // ファイル移動
                $dest = $uploadDir . DIRECTORY_SEPARATOR . $filename;
                $move = @move_uploaded_file($file['tmp_name'], $dest);
                if (!$move) return array('success' => false, 'message' => 'アップロードに失敗しました。', 'files' => $files);

                $files[$i]['dest'] = $dest; // 関数の呼び出し側で必要になる場合がある可能性に備え、配置先をセットしておきます。
            }
            // 一時フォルダへのアップロード失敗
            else {
                switch ($file['error']) {
                    case UPLOAD_ERR_INI_SIZE:
                    case UPLOAD_ERR_FORM_SIZE:
                        return array('success' => false, 'message' => 'アップロードの最大容量を超えています。', 'files' => $files);
                    default:
                        return array('success' => false, 'message' => 'アップロードに失敗しました。', 'files' => $files);
                }
            }
        }
        // アップロード処理成功
        return array('success' => true, 'message' => 'アップロードに成功しました。', 'files' => $files);
    }
    // tmp_name が無い
    else {
        return array('success' => false, 'message' => 'アップロードに失敗しました。', 'files' => array());
    }
}
/**
 * ファイル名を生成します。
 * @param array $file 単一のファイル情報
 * @return string ファイル名
 */
function file_upload_filename_callback($file) {
    // 例として一意(UUID v4)のファイル名を生成します。
    $extMap = array('image/gif' => 'gif', 'image/png' => 'png', 'image/jpeg' => 'jpg');
    $ext = $extMap[ mime_content_type($file['tmp_name']) ];
    return sprintf('%04x%04x-%04x-%04x-%04x-%04x%04x%04x.%s',
        mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0xffff),
        mt_rand(0, 0x0fff) | 0x4000, mt_rand(0, 0x3fff) | 0x8000,
        mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0xffff),
        $ext
    );
}

$result = null;
// POST されている場合、アップロード処理
if (strtoupper($_SERVER['REQUEST_METHOD']) == 'POST') {
    $name = 'file1'; // <input> の name 属性
    $uploadDir = dirname(__FILE__) . '/uploads'; // アップロードするフォルダ
    $options = array(
        'allows' => array('image/gif', 'image/png', 'image/jpeg'), // ファイル形式の制限が必要な場合、許可するファイルのMIMEタイプ。不要な場合コメントアウト
        'filename_callback' => 'file_upload_filename_callback' // ファイル名のカスタマイズが必要な場合の処理。不要な場合コメントアウト
    );
    $result = file_upload($name, $uploadDir, $options);
}
?>
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>PHP によるファイルアップロードの例</title>
</head>
<body>
<h1>PHP によるファイルアップロードの例</h1>
<!-- enctype は必ず "multipart/form-data" にしてください。PHPの仕組み上、していない場合はアップロードができません。 -->
<form method="post" enctype="multipart/form-data">
    <input type="file" name="file1">
    <!-- 複数の場合は下記のようなタグになります。
    <input type="file" name="file1[]">
    <input type="file" name="file1[]">
    -->
    <input type="submit" value="送信">
</form>

<?php if ($result) echo($result['message']) ?> 
</body>
</html>

結果

※下記は画像のためクリックしても動作しません。

結果