Railsファイルファイルのfile_アップロードFieldエラーEncoding::UndefinedConversionError
9640 ワード
サーバはubuntu 12 64 bit、環境はruby 1を使用する.9.3+rails 3+mysql、テストはwindows 2003です.【.gitconfig】ファイルをアップロードします.問題はありません.【新浪微博データマイニング.pdf】をアップロードします.【back.jpg】をアップロードします.次は2つのメッセージで、【log/production.log】から貼り付けられています.上の段落は問題のないログで、下の段落は間違った後のログです.
比較してみると、2段のpicture部分の@content_typeが違って成功したのは@content_type=「アプリケーション/octet-stream」で失敗したのは@content_type="binary/octet-stream". txtファイルをアップロードしようとしましたが、成功しました.@content_type部分は@content_type="text/plain". この部分の原因、すなわち符号化であることが判明したため、符号化エラーが報告され、符号化変換が定義されていない.
アップロード部分のコードは以下の通りです.
検索してみると、深い原因が見つかりました.もともとバイナリファイルのため、rubyは読み取りと保存時にバイナリファイルを自動的に処理し、特別な方法は必要ありません.
しかしwindowsでは、バイナリとテキストファイルが異なり、バイナリmodeでは、終了行は単独の改行に変換されるのではなく、1つのリターンと1つの改行に保存されます.したがって、バイナリファイルを読み取る場合は、openのときにバイナリファイルwbを読み取ることを示す必要があります.bはバイナリの意味です.
画像はデフォルトでバイナリファイルで処理されるので、ヒットしました.実はwをwbに変えるだけでいいのです.
次はこの問題がありません.
セキュリティの観点から、ファイルのアップロードはパス、権限、およびアップロードのタイプを厳格に制御します.パスは、ファイルがサーバーに保存されるパスであり、単独のパスが望ましい.ルートディレクトリに置かないで、フォルダを計画し、名前を変更しなければならない.アップロードした人はサーバーに同名のファイルがあるかどうか分からないため、ファイルの実際の名前とユーザーが見る必要があるファイル名のマッピングに関連している.
権限とは、ユーザーにパスをアップロードする権限です.実行権限は持たないほうがいいです.読み書き権限だけでいいです.必要であれば、ユーザーフォルダを分けて権限を区別する必要があります.共通フォルダを保持します.など、場合によって異なります.
アップロードのタイプで、アップロードファイルは必ず1つのシーンに関連しています.1つのシーンには、ドキュメントシーン、ピクチャシーンなどのファイルしか必要ありません.異なるシーンで異なるファイルタイプを制御することが望ましい.実行ファイルは厳格に制御しなければならない.
- Started POST "/posts" for 106.3.102.43 at 2012-10-29 21:16:26 +0800
- Processing by PostsController#create as HTML
- Parameters: {"utf8"=>"✓", "authenticity_token"=>"QG8aU6/VW5ZMagzyGhjdbm7fSzr4MB5CKdJeGBIeOa4=", "post"=>{"category_id"=>"1", "title"=>"666666666666", "url"=>"6666666", "picture"=>#<ActionDispatch::Http::UploadedFile:0x000000032fb838 @original_filename=".gitconfig", @content_type="application/octet-stream", @headers="Content-Disposition: form-data; name=\"post[picture]\"; filename=\".gitconfig\"\r
Content-Type: application/octet-stream\r
", @tempfile=#<File:/tmp/RackMultipart20121029-2609-1lrmc9o>>, "content"=>"6666", "tags_attributes"=>{"0"=>{"title"=>""}}}, "commit"=>"Create Post"}
- Redirected to http://42.121.5.68/posts
- Completed 302 Found in 36ms (ActiveRecord: 30.1ms)
- Started POST "/posts" for 123.114.36.100 at 2012-10-30 08:58:13 +0800
- Processing by PostsController#create as HTML
- Parameters: {"utf8"=>"✓", "authenticity_token"=>"rRnhcDWYDn+OntxxC2LmIEHpSpjWI5glrs6JlprG1Ho=", "post"=>{"category_id"=>"1", "title"=>" ", "url"=>"post7", "picture"=>#<ActionDispatch::Http::UploadedFile:0x000000030df9a0 @original_filename=" .pdf", @content_type="binary/octet-stream", @headers="Content-Disposition: form-data; name=\"post[picture]\"; filename=\"\xE6\x96\xB0\xE6\xB5\xAA\xE5\xBE\xAE\xE5\x8D\x9A\xE6\x95\xB0\xE6\x8D\xAE\xE6\x8C\x96\xE6\x8E\x98\xE6\x96\xB9\xE6\xA1\x88.pdf\"\r
Content-Type: binary/octet-stream\r
", @tempfile=#<File:/tmp/RackMultipart20121030-16129-15agvlb>>, "content"=>" > ", "tags_attributes"=>{"0"=>{"title"=>" "}}}, "commit"=>"Create Post"}
- Completed 500 Internal Server Error in 45ms
-
- Encoding::UndefinedConversionError ("\xE2" from ASCII-8BIT to UTF-8):
- app/controllers/posts_controller.rb:60:in `write'
- app/controllers/posts_controller.rb:60:in `block (2 levels) in create'
- app/controllers/posts_controller.rb:59:in `open'
- app/controllers/posts_controller.rb:59:in `block in create'
- app/controllers/posts_controller.rb:56:in `create'
比較してみると、2段のpicture部分の@content_typeが違って成功したのは@content_type=「アプリケーション/octet-stream」で失敗したのは@content_type="binary/octet-stream". txtファイルをアップロードしようとしましたが、成功しました.@content_type部分は@content_type="text/plain". この部分の原因、すなわち符号化であることが判明したため、符号化エラーが報告され、符号化変換が定義されていない.
アップロード部分のコードは以下の通りです.
- uploaded_io = params[:post][:picture]
- if uploaded_io != nil and uploaded_io.content_type.match('image')
-
- File.open(Rails.root.join('public','uploads',uploaded_io.original_filename),'w') do |f|
-
- f.write(uploaded_io.read)
- end
-
- else
- end
検索してみると、深い原因が見つかりました.もともとバイナリファイルのため、rubyは読み取りと保存時にバイナリファイルを自動的に処理し、特別な方法は必要ありません.
しかしwindowsでは、バイナリとテキストファイルが異なり、バイナリmodeでは、終了行は単独の改行に変換されるのではなく、1つのリターンと1つの改行に保存されます.したがって、バイナリファイルを読み取る場合は、openのときにバイナリファイルwbを読み取ることを示す必要があります.bはバイナリの意味です.
画像はデフォルトでバイナリファイルで処理されるので、ヒットしました.実はwをwbに変えるだけでいいのです.
次はこの問題がありません.
- uploaded_io = params[:post][:picture]
- if uploaded_io != nil and uploaded_io.content_type.match('image')
-
- File.open(Rails.root.join('public','uploads',uploaded_io.original_filename),'wb') do |f|
-
- f.write(uploaded_io.read)
- end
-
- else
- end
- <div class="field">
- <%= f.label :picture %><br/>
- <%= f.file_field :picture %>
- </div>
セキュリティの観点から、ファイルのアップロードはパス、権限、およびアップロードのタイプを厳格に制御します.