From: Paul Vudmaska Date: 2004-02-27T06:15:16+09:00 Subject: Re: CGI and multipart data Martin Hart wrote: >Hi all, > >I have a single HTML form which contains simple text controls as well as file >upload controls. I had assumed that the CGI library would return me items of >type String for the text boxes and items of type Tempfile for the file upload >boxes.... > >However, it appears (after searching the archives) that StringIO is used >instead of Tempfile on ruby 1.8 (in some cases and not others?), and that as >soon as you specify an enctype of multipart you never? receive Strings but >always receive either Tempfile or StringIO. > >This is what i really want from the CGI library: >* CGI returns *everything* as a string except for file uploads - which are >returned as Tempfiles > >Assuming that I cannot have that :-) can somebody in the know please tell me >(or point me to some documentation)... > >1. how can I tell whether or not the supplied parameter was a file upload or >simple text that has been passed to me as a Tempfile/StringIO? At the moment >I don't know whether to copy the file or not - because I don't know if it is >a valid file or just another parameter. > >2. do hidden controls work with multi-part forms? there is some discussion of >them not working on the mailing list dating back to last November but I don't >know if that has been fixed or not. My limited testing here indicates that >hidden parameters are ignored on multipart forms? > >3. why are all values expressed as Tempfile/StringIO when using a multipart >form? Why not just have the file uploads as tempfiles? > >4. how does the CGI library determine whether or not to switch between >Tempfile/StringIO > >5. do I have to specifically close the IO object (assuming that one is >returned?) - or perhaps I do not have to close the StringIO but I do have to >close the Tempfile? > >6. are all of the form parameters in different tempfiles or are they all in >one? Say i close the file after reading 1 argument ... does this mean that I >cannot read any more? > >Thanks for any help you can give me - I am pretty stuck on this. If I get >code working with StringIO objects it seems to break when I submit large >files, and if I get code working with Tempfile it seems to break when I >submit small files :-) > >Cheers, >Martin > > > > Here is the code that i use. Prob not the best but has worked for me so far. class Upload #{{{ -----------------------Uploads file to server from html form-------------------------- #max size of file in bytes MAX_SIZE = 100000 #where the file goes / MUST HAVE WRITE PRIVS HERE PATH = "/home/paul/web/" #how many file inputs - you can upload multiple files at once FILE_COUNT = 3 #what file types do we allow? CONTENT_TYPES= ['image/jpg','image/jpeg','image/gif','image/png'] def initialize #how are things going? @status = [] if $form.isPost post print @status.join('
') form else form end end def form #{{{ puts '
' FILE_COUNT.times do puts '

' end puts '

' puts '
Overwrite?' puts '
' puts '

' end#}}} def post #{{{ oOverwrite = $cgi['overwrite'][0] bOverwrite = false overwrite = '' if oOverwrite overwrite = oOverwrite.read.chomp if overwrite == 'on' then bOverwrite = true end end $cgi['myfile'].each do |incoming| if incoming.size == 0 @status<< "Ignoring empty field" next end if incoming.size > MAX_SIZE @status<< "Data too large for #{incoming.original_filename}(#{incoming.size} > #{MAX_SIZE})" next end #need to strip :)...trailing space...ouch if not CONTENT_TYPES.include? incoming.content_type.strip @status<< "Type not allowed(type = #{incoming.content_type}) allowed content = #{CONTENT_TYPES.join(' | ')}" next end #puts incoming.filename # all should be ok to upload sfilename = incoming.original_filename.untaint #see if name has whacks...ie? rdash = sfilename.rindex('\\') if rdash sfilename = sfilename[rdash+1,sfilename.length] end #physical path path = PATH + $Domain + '/img/' + sfilename if File.exist? path if bOverwrite File.delete path else @status<< "File already exists (#{incoming.original_filename})" next end end #write to file file = File.new(path.untaint,'w') file << incoming.read file.close #path to link from web httpPath = "http://#{$Domain}/img/#{sfilename}" @status<< "Completed upload of #{httpPath}" end end#}}} end#}}} Upload.new