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】から貼り付けられています.上の段落は問題のないログで、下の段落は間違った後のログです. 

  
  
  
  
  1. Started POST "/posts" for 106.3.102.43 at 2012-10-29 21:16:26 +0800 
  2. Processing by PostsController#create as HTML 
  3.   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"} 
  4. Redirected to http://42.121.5.68/posts 
  5. Completed 302 Found in 36ms (ActiveRecord: 30.1ms) 

 

  
  
  
  
  1. Started POST "/posts" for 123.114.36.100 at 2012-10-30 08:58:13 +0800 
  2. Processing by PostsController#create as HTML 
  3.   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"} 
  4. Completed 500 Internal Server Error in 45ms 
  5.  
  6. Encoding::UndefinedConversionError ("\xE2" from ASCII-8BIT to UTF-8): 
  7.   app/controllers/posts_controller.rb:60:in `write' 
  8.   app/controllers/posts_controller.rb:60:in `block (2 levels) in create' 
  9.   app/controllers/posts_controller.rb:59:in `open' 
  10.   app/controllers/posts_controller.rb:59:in `block in create' 
  11.   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". この部分の原因、すなわち符号化であることが判明したため、符号化エラーが報告され、符号化変換が定義されていない.
アップロード部分のコードは以下の通りです.
 

  
  
  
  
  1. uploaded_io = params[:post][:picture] 
  2.         if uploaded_io != nil and uploaded_io.content_type.match('image') 
  3.  
  4.           File.open(Rails.root.join('public','uploads',uploaded_io.original_filename),'w') do |f| 
  5.  
  6.             f.write(uploaded_io.read) 
  7.           end 
  8.  
  9.         else 
  10. end 

検索してみると、深い原因が見つかりました.もともとバイナリファイルのため、rubyは読み取りと保存時にバイナリファイルを自動的に処理し、特別な方法は必要ありません.
しかしwindowsでは、バイナリとテキストファイルが異なり、バイナリmodeでは、終了行は単独の改行に変換されるのではなく、1つのリターンと1つの改行に保存されます.したがって、バイナリファイルを読み取る場合は、openのときにバイナリファイルwbを読み取ることを示す必要があります.bはバイナリの意味です.
画像はデフォルトでバイナリファイルで処理されるので、ヒットしました.実はwをwbに変えるだけでいいのです.
 
次はこの問題がありません.

  
  
  
  
  1. uploaded_io = params[:post][:picture] 
  2.         if uploaded_io != nil and uploaded_io.content_type.match('image') 
  3.  
  4.           File.open(Rails.root.join('public','uploads',uploaded_io.original_filename),'wb') do |f| 
  5.  
  6.             f.write(uploaded_io.read) 
  7.           end 
  8.  
  9.         else 
  10. end

 
 

  
  
  
  
  1. <div class="field"> 
  2.   <%= f.label :picture %><br/> 
  3.   <%= f.file_field :picture %> 
  4. </div> 

セキュリティの観点から、ファイルのアップロードはパス、権限、およびアップロードのタイプを厳格に制御します. 
  • パスは、ファイルがサーバーに保存されるパスであり、単独のパスが望ましい.ルートディレクトリに置かないで、フォルダを計画し、名前を変更しなければならない.アップロードした人はサーバーに同名のファイルがあるかどうか分からないため、ファイルの実際の名前とユーザーが見る必要があるファイル名のマッピングに関連している.

  •  
  • 権限とは、ユーザーにパスをアップロードする権限です.実行権限は持たないほうがいいです.読み書き権限だけでいいです.必要であれば、ユーザーフォルダを分けて権限を区別する必要があります.共通フォルダを保持します.など、場合によって異なります.

  •  
  • アップロードのタイプで、アップロードファイルは必ず1つのシーンに関連しています.1つのシーンには、ドキュメントシーン、ピクチャシーンなどのファイルしか必要ありません.異なるシーンで異なるファイルタイプを制御することが望ましい.実行ファイルは厳格に制御しなければならない.