PHP ファイルのアップロード 勉強メモ
フォーム側のお約束事はこれだけ
- form要素に「enctype="multipart/form-data"」を追加する。
- inputのtype属性には「file」を指定。
- 必ずPOSTメソッドを指定。
アップロード処理の流れ
- フォームに入力→送信
- テンポラリファイルとしてアップロードされる
- ディレクトリにコピーして保存
テンポラリファイルとしてアップロードされたままにしておくと処理完了と同時に削除されてしまうので、ファイルを保存するために書き込み権限のあるディレクトリにコピーする。
$_FILES
アップロードされたデータの内容は「$_FILES」に入る。
- $_FILES['userfile']['name']
- クライアントマシンの元のファイル名。
- $_FILES['userfile']['type']
- ファイルの MIME 型。ただし、ブラウザがこの情報を提供する場合。 例えば、"image/gif" のようになります。 この MIME 型は PHP 側ではチェックされません。そのため、 この値は信用できません。
- $_FILES['userfile']['size']
- アップロードされたファイルのバイト単位のサイズ。
- $_FILES['userfile']['tmp_name']
- アップロードされたファイルがサーバー上で保存されているテンポラリファイルの名前。
- $_FILES['userfile']['error']
- エラーコード(PHP: エラーメッセージの説明 - Manual)
ということで、アップロードしたファイルをサーバー上で保存する時は、$_FILES['userfile']['tmp_name']を適当な場所にコピーすればいいってことですね。
手順
- ファイルを保存するディリクトリを決める(どっかのディレクトリに入れたい場合は)
- アップされたテンポラリファイルファイル名を取得
- move_uploaded_file関数を使って、1で決めたディレクトリへコピー
move_uploaded_file アップロードされたファイルを新しい位置に移動する
「move_uploaded_file (アップロードしたファイル名,ファイルのコピー先)」という書き方。
簡単なサンプル
<form action="<?= $_SERVER["PHP_SELF"]; ?>" method="post" enctype="multipart/form-data">
<p><input type="file" name="data" /> <input type="submit" value="アップロード"></p>
</form>
<?php
$updir = "./data";
$tmp_file = @$_FILES['data']['tmp_name'];
$copy_file = @$_FILES['data']['name'];
move_uploaded_file($tmp_file,"$updir/$copy_file");
?>
ファイル名を変更して保存する場合 その1
ファイル名が重複しないようにするにはどうしたらいいんかなって考えたとき日付と時間にしちゃえばいいじゃんっていう安易な発想からアップした日時をファイルの名にしたサンプル。
<?php
$updir = "./data";
$tmp_file = @$_FILES['data']['tmp_name'];
@list($file_name,$file_type) = explode(".",@$_FILES['data']['name']);
$copy_file = date("Ymd-His") . "." . $file_type;
move_uploaded_file($tmp_file,"$updir/$copy_file");
?>
リネームするファイル名の拡張子の部分、typeを取得してswitch振り分けとかいろいろ迷ったけど一番短く書けそうなのを採用。元のファイル名を「.」で分割して最後の部分をゲットする方法にしてみた。もっといいやり方があるんかもしれないけど・・・。
ファイル名を変更して保存する場合 その2
連番をつけるサンプル。ファイルを保存するディレクトリ内のファイル数を取得して1ずつ増やすっていうやり方にしたいと思ったんだけど、マニュアルを探しまくってもそれを一発でなんとかする関数が見つけられなかったので2段階方式でやってみた。この関数使ってみる。
scandir(PHP5) 指定されたパスのファイルとディレクトリのリストを取得する
scandirで返ってくる値は配列になってるので、その数をcountで取得したい。で、なんかこれで取得すると見知らぬものがもれなくついてくる。「.」と「..」この人達は何だろう。どっかで読んだ事ある気がするけど思い出せない・・・カレントと上のディレクトリの事かな。まぁいいや。
とりあえず数が欲しいだけなので無視して、それらを含めて取得した数から1引いたものを使う事にした。気持ち的には2引いた数にするのがスッキリだけど、2引くと最初の番号が0になっちゃう。なんとなく1から始めたかったので1引いた数にしてみた。「data-番号.拡張子」の形で保存してみる。
<?php
$updir = "./data";
$array_file = scandir($updir);
$count_file = count($array_file) -1;
$tmp_file = @$_FILES['data']['tmp_name'];
@list($file_name,$file_type) = explode(".",@$_FILES['data']['name']);
$copy_file = "data-" . $count_file . "." .$file_type;
move_uploaded_file($tmp_file,"$updir/$copy_file");
?>
もちろんそのディリクトリの中に他のファイルやディレクトリがあったらアップロードしたファイルに対しての連番が飛んだりするんかもしれんけど、まぁ重複はしないってことで・・・。
ファイル名を変更して保存する場合 その3
連番の形をもうちょい整えるサンプル。整えるっていうか、上のサンプルだと桁が上がると「1.11.12・・・2.3.4.5.6.7.8.9」みたいな並び方になるのが私はあまり好きじゃないので番号をsprintf関数で5桁にした。「data-00001.拡張子」みたいな形にする。
<?php
$updir = "./data";
$array_file = scandir($updir);
$count_file = count($array_file) -1;
$count_file = sprintf('%05d',$count_file);
$tmp_file = @$_FILES['data']['tmp_name'];
@list($file_name,$file_type) = explode(".",@$_FILES['data']['name']);
$copy_file = "data-" . $count_file . "." .$file_type;
move_uploaded_file($tmp_file,"$updir/$copy_file");
?>
php.iniの設定
ファイルのアップロードに関連するphp.iniの設定はこの辺り。うまくアップできない時は設定を確認。file_uploads、upload_max_filesize、upload_tmp_dir、post_max_size、max_input_time
<< dat から1行ずつ抜き出して xml 書き出し | PHP ランダム表示機能付きバナーリンク集 >>
トラックバック
このエントリーのトラックバックURL:
http://redline.hippy.jp/cgi/mt/mt-tb.cgi/239
コメント (4)
PHPコード内での@によるエラー抑制はパフォーマンス的によくないですよ。
またエラーメッセージ拾えないと困る場合もあるだろうし。
投稿者: atsushi | 2009年03月09日 10:08
>atsushiさん
コメントありがとうございますー!
そういえば、それ以前もアドバイス頂いたんでした・・・><
$tmp_file = @$_FILES['data']['tmp_name'];
こういうのを
$tmp_file = isset($_FILES['data']['tmp_name']) ? $_FILES['data']['tmp_name'] : NULL;
こうしたらいいんですよね。
勉強になります。ありがとうございます(n'∀')η
投稿者: Red | 2009年03月09日 10:44
$tmp_fileとするより$_FILES['userfile']['tmp_name']の方が解りやすかったりしますよ。
時と場合によりますけど。
投稿者: res | 2009年04月02日 16:57
>resさん
コメントありがとうございましたー。
いつもいつも一旦変数に入れないほうがいい場合ってのも考えた方がいいんですね。勉強になりますー。ありがとうございました。
投稿者: Red | 2009年04月03日 19:23