質問するログイン新規登録

回答編集履歴

1

追記

2017/01/17 12:20

投稿

退会済みユーザー
answer CHANGED
@@ -12,4 +12,154 @@
12
12
  そもそも $tmp_name には拡張子に当たる文字列は存在しない。
13
13
  preg_match でファイルタイプを判定することがバッドノウハウです。
14
14
 
15
- [finfo_file](http://php.net/manual/ja/function.finfo-file.php) で判定しましょう。
15
+ [finfo_file](http://php.net/manual/ja/function.finfo-file.php) で判定しましょう。
16
+
17
+ #サンプルコード
18
+
19
+ ```html
20
+ <?php
21
+ ini_set('display_errors', true);
22
+ error_reporting(E_ALL);
23
+
24
+ define('UP_DIR', 'updir');
25
+
26
+ function h($string)
27
+ {
28
+ return htmlspecialchars($string, ENT_QUOTES, 'utf-8');
29
+ }
30
+
31
+ /**
32
+ * ファイルアップロードエラーを判定する
33
+ * @param type $upfile
34
+ * @return bool
35
+ * @throws Exception
36
+ */
37
+ function check_error($upfile)
38
+ {
39
+ switch ($upfile['error']) {
40
+ case UPLOAD_ERR_OK:
41
+ return true;
42
+ case UPLOAD_ERR_INI_SIZE:
43
+ $err = 'アップロードされたファイルは、php.ini の upload_max_filesize ディレクティブの値を超えています。';
44
+ break;
45
+ case UPLOAD_ERR_FORM_SIZE:
46
+ $err = 'アップロードされたファイルは、HTML フォームで指定された MAX_FILE_SIZE を超えています。';
47
+ break;
48
+ case UPLOAD_ERR_PARTIAL:
49
+ $err = 'アップロードされたファイルは一部のみしかアップロードされていません。';
50
+ break;
51
+ case UPLOAD_ERR_NO_FILE:
52
+ $err = 'ファイルはアップロードされませんでした。';
53
+ break;
54
+ case UPLOAD_ERR_NO_TMP_DIR:
55
+ $err = 'テンポラリフォルダがありません。';
56
+ break;
57
+ case UPLOAD_ERR_CANT_WRITE:
58
+ $err = 'ディスクへの書き込みに失敗しました。';
59
+ break;
60
+ case UPLOAD_ERR_EXTENSION:
61
+ $err = 'PHP の拡張モジュールがファイルのアップロードを中止しました。';
62
+ break;
63
+ }
64
+
65
+ if (!empty($err)) {
66
+ throw new Exception($err);
67
+ }
68
+ }
69
+
70
+ /**
71
+ * ファイルタイプをチェックし、拡張子を返す
72
+ * @param type $upfile
73
+ * @return bool
74
+ */
75
+ function check_extension($upfile)
76
+ {
77
+ $arr_accept_mimes = [
78
+ 'jpg' => 'image/jpeg'
79
+ , 'png' => 'image/png'
80
+ , 'gif' => 'image/gif'
81
+ ];
82
+
83
+ $finfo = finfo_open(FILEINFO_MIME_TYPE);
84
+ $mime_type = finfo_file($finfo, $upfile['tmp_name']);
85
+
86
+ if (in_array($mime_type, $arr_accept_mimes)) {
87
+ return array_search($mime_type, $arr_accept_mimes);
88
+ }
89
+
90
+ $msg = '許可されていないファイルタイプです。';
91
+ throw new Exception($msg);
92
+ }
93
+
94
+ if (filter_input(INPUT_SERVER, 'REQUEST_METHOD') === 'POST') {
95
+
96
+ try {
97
+
98
+ $upfile = $_FILES['upfile'];
99
+
100
+ // エラーチェック
101
+ check_error($upfile);
102
+
103
+ // ファイルタイプチェック
104
+ $extension = check_extension($upfile);
105
+
106
+ $tmp_name = $upfile['tmp_name'];
107
+
108
+ // ファイル保存先 + ファイル名
109
+ $base_name = sha1_file($tmp_name) . '.' . $extension;
110
+
111
+ if (!file_exists(UP_DIR)) {
112
+ $msg = sprintf('%s ディレクトリが存在しません。', UP_DIR);
113
+ throw new Exception($msg);
114
+ }
115
+ if (!is_writable(UP_DIR)) {
116
+ $msg = sprintf('%s に書き込み権限がありません。', UP_DIR);
117
+ throw new Exception($msg);
118
+ }
119
+
120
+ $destination = UP_DIR . DIRECTORY_SEPARATOR . $base_name;
121
+ if (file_exists($destination)) {
122
+ $msg = sprintf('同一のファイルがすでにアップロードされています。', UP_DIR);
123
+ throw new Exception($msg);
124
+ }
125
+
126
+ move_uploaded_file($tmp_name, $destination);
127
+ } catch (Exception $e) {
128
+ $err = $e->getMessage();
129
+ }
130
+ }
131
+ ?><!DOCTYPE HTML>
132
+ <html lang="ja">
133
+ <head>
134
+ <meta charset="UTF-8">
135
+ <title></title>
136
+ <style type="text/css">
137
+ .error {
138
+ color: red;
139
+ }
140
+ </style>
141
+ </head>
142
+ <body>
143
+ <form action="" enctype="multipart/form-data" method="post">
144
+ <?php if (isset($err)) : ?>
145
+ <p class="error">エラー: <?= h($err); ?></p>
146
+ <?php endif; ?>
147
+
148
+ <p>
149
+ <label for="upfile">画像ファイル</label>
150
+ <input type="file" name="upfile" id="upfile" />
151
+ </p>
152
+ <p>
153
+ <button type="submit">アップロード</button>
154
+ </p>
155
+ </form>
156
+ </body>
157
+ </html>
158
+ ```
159
+
160
+ #おまけ
161
+
162
+ このサンプルコードを書く様子を動画でキャプチャしてみました。
163
+ 三流プログラマのもので申し訳ないが、デバッグの様子など見ると参考になるかも。
164
+
165
+ [https://www.youtube.com/watch?v=PEDERfokvPU](https://www.youtube.com/watch?v=PEDERfokvPU)