メインコンテンツに移動

ファイルアップロードでのエラー

事象

自作の動画ファイルをアップロードしているときのことです。
数十記事(数十ファイル)目くらいアップロードしたころでしょうか、アップロード中にエラーが発生し、アップロード不可になりました。
その前から アップロードボタンを押した直後にまれに”HTTP エラー 0"というメッセージが出ていましたが、再度アップロードボタンを押せば正常に完了していたので気にはしていませんでした。

原因

今回の原因を先にいうと
・ファイルアップロード時にテンポラリとして使用される/var/tmpの使用可能ファイルサイズをオーバーしていたためでした。

調査過程

まず[最近のログ]でエラーの内容を確認しました。

場所:[drupalサイトURL]/filefield/ahah/video/field_video_upload/0
メッセージ:ファイルのアップロードに失敗しました。 field_[ファイルフィールド名]_0


となっており、さらに場所のリンクを表示してみると以下のメッセージが表示されていました。

{ "data": "\x3cdiv class=\"messages error\"\x3e\nAn unrecoverable error occurred. 
The uploaded file likely exceeded the maximum file size (256 MB) that this server supports.\x3c/div\x3e\n" }

これからすると、アップロードしたファイルサイズが最大の256MBを超えているようです。
しかし、アップロードしたファイルは、192MBしかありません。

バイト計算は1K=1024バイトだと思いますが、念のため最大サイズを512MBまで一時的に変更してみましたが、症状は変わりませんでした。
また、わざと制限を越えるサイズのファイルをアップロードしてみましたが、制限付近でエラーが発生し上記エラー内容と変わりありませんでした。
ということは、やはり上限を超えているということになります。

何度か再アップロードしていると、エラーが発生するタイミングが必ず106MB前後送信が完了しているあたりでした。
しかし100MBを制限にしたような記憶は一切ありません。

次に、新しい記事で上限値の半分である動画ファイルで試しました。
上限値の半分である100MB程度の動画ファイルでアップロードを試しましたが、同じく途中で全く同じエラーが発生しました。
これにより、php.iniに指定しているファイルアップロード関連のディレクティブ(post_max_size、upload_file_size、memory_limit)が関係しているのではないと判断しました。
そうなるとあとは、アカウントごとの制限があるのかも?という疑いがわきました。

さらに、別のユーザでアップロードを試しました。
IMCモジュールでユーザごとのアップロードサイズ制限がされていたので、念のためすべて制限なしに設定しphp.iniの制限を最大値にしています。

結果は、変わらず同じエラー内容でした。

アップロードの際に何かが起こっていてそこで何らかのエラーが発生しているのだと疑いました
そこで、アップロードがどのように行われているのか調べました。

アップロードの内部動作を調査

調査は、それぞれの段階でファイルが作成される場所について行ないました。

ファイルは以下の順序で作成され、次の処理が正常に完了すると前の処理で作成したファイルは削除されます。

①アップロード中 PC⇒サーバのテンポラリ(/var/tmp)
②アップロード中(完了直後) サーバのテンポラリ(/var/tmp)⇒drupalファイルシステムパス直下
※約90%完了でStarting Uploadといったようなメッセージが一瞬表示されるタイミングです。
③アップロード完了時 drupalファイルシステムパス直下
④記事の保存中 drupalファイルシステムパス直下⇒指定ファイルパス
⑤保存完了 指定ファイルパス

サーバのテンポラリ(/var/tmp)やdrupalファイルシステムパス直下にこれまでにアップロードしたファイルのゴミが残っていました。
これらを削除し、正常にアップロードできることを確認しました。

drupalファイルシステムパス直下は、さくらインターネットのレンタルサーバの場合はユーザのホームディレクトリ以下になりますので、総使用可能ディスク容量以内であれば問題ありません。
そうすると、サーバのテンポラリ(/var/tmp)の容量制限によりエラーが発生していたと推測されます。

共有サーバですので、/var/tmpのような共有スペースにそういった制限があるのは当然です。
※今回、drupalファイルシステムパス直下の不要なファイルも削除しましたが、これを削除しておかないと同じファイル名だった場合にXXX_0といったようにファイル名に数字が付与されます。
※上書き設定なら問題ありません。

原因が判明したので、データベースにもゴミが残っていたのできれいにしておきました。

原因がわかったのでよかったのですが、サーバのテンポラリ(/var/tmp)を使用したくないというのが正直なところです。
そもそも、drupalファイルシステム設定でテンポラリを設定していたはずなのです。
そこにもファイルアップロードなどで使用されるパスと説明がありました。
develモジュールでもそのテンポラリが使用されていたのでまさかサーバのテンポラリ(/var/tmp)が使用されているとは思っていませんでした。

php.iniではファイルアップロードのテンポラリディレクトリを指定していないので、システムのデフォルトが設定されたようです。

ファイルアップロードに関連するディレクティブ

file_uploads
upload_tmp_dir
upload_max_filesize

post_max_size
memory_limit


それぞれのデフォルト値は、phpinfo()コマンドで表示できるので以下のようなPHPファイルを作成してブラウザで表示させれば確認できます。

<?php
print phpinfo();
?>

さくらインターネットのレンタルサーバのデフォルト値は、以下の通りです。

file_uploads=On
upload_tmp_dir=NULL
upload_max_filesize=2MB

post_max_size=8MB
memory_limit=128M

※-1とすると無制限ですが、推奨しません。特に、memory_limitの値は無制限にすべきではないと思います。
upload_tmp_dirで設定するディレクトリは、そのユーザに書き込み権限がないとダメです。


値を変更する場合は、以下の関係になるようにしてください。

memory_limit >= post_max_size >= upload_file_size

その他、max_execution_timeやmax_input_timeなども場合によっては設定したほうがよいかもしれません。

上限と使用量の確認

簡単に確認するにはquotaコマンドを実行すればよいと思います。

%quota -v
Disk quotas for user USERNAME (uid XXXX):
     Filesystem   usage     quota    limit   grace   files    quota   limit   grace
          /home 6005166  10485760 10485760           78688  3000000 3000000
           /var       0   1048576  1048576               0   100000  100000

※usageが現在の使用量、filesがi-node数、quotaがソフトウェアリミット、limitがハードウェアリミットです。
※quotaとlimitが同じなのでquotaの値を一瞬でも越えることはできませんし、猶予期間もありません。

私が使用しているさくらインターネットの制限は以下の様になります。
・ホームディレクトリは容量10GB,i-node数3000000
・テンポラリディレクトリは容量1GB,i-node数100000
※i-nodeは、例えばファイルサイズが0バイトのファイルを多数作成していると使用量は増えませんがi-node数が増えます。0バイトのファイルは一部アプリケーションで作成されるケースがあります。
フラグファイルとして利用しているのでしょうか、この数が多すぎるといろいろと問題が発生します。私も以前、バックアップで困った記憶があります。

追記

upload_tmp_dirを設定して$HOMR/tmpを指定するように変更しましたが、まだupt_[upload_id].txtというファイルが/var/tmpに一時的に作成されます。
そもそもファイルシステムのテンポラリパスの指定がうまくできていないのか、filefieldモジュールがDrupalテンポラリディレクトリの設定を使用しないのかどちらかでしょう。

Drupalバージョン
モジュール