> > Before I have a go at putting together a solution for this 
> >myself, has anyone else already been there done that?
> 
> That would be a valuable addition to JHP.

Well I've put something together that seems to work. It is very verbose
and certainly not as elegant as the rest of JHP, but hopefully it can
act as a starting point. Please feel free to tear it apart - I'm happy
to learn! 

In its present form, uploaded files are parsed from stdin and saved into
the ~CGI/tmp folder. I'm not certain how I'd present this to the "user"
differently. Oleg, when you were talking about "presenting info to the
'user'"  is the user the web-page designer, the web-page viewer, or the
JHP server administrator?

The changes I made to jhp.ijs were to extended qkeys yet further and to
add the verb qmparse:

qkeys=: 3 : 0
  if. -.isnoun 'CGIKEYS' do.
    select. env 'REQUEST_METHOD'
      case. 'GET'  do.
        q=. env 'QUERY_STRING'
        'CGIKEYS CGIVALS'=: a:"_`(<"1@|:)@.(0<#) qsparse q
      case. 'POST' do.
        q=. stdin ''
      select. (]{.~';'i.~]) env 'CONTENT_TYPE'
        case. 'application/x-www-form-urlencoded' do.
          'CGIKEYS CGIVALS'=: a:"_`(<"1@|:)@.(0<#) qsparse q
        case. 'multipart/form-data' do.
          'CGIKEYS CGIVALS CGIISFL CGIFNMS CGICTPS'=:
a:"_`(<"1@|:)@.(0<#) qmparse q
        case. do.
    NB. signal invalid CONTENT_TYPE
      end.
    case. do.
  NB. signal invalid Method
    end.
  end.
  CGIKEYS
)

qmparse=: 3 : 0
  (env 'CONTENT_TYPE') qmparse y
  :
  bd=.  x ([}.~[:>:i.) '='  NB. get boundary
  dat=. (#bd)}.each (bd E. y) <;.1 y NB. box each section
  
  ndx=. {.each I. each (<CRLF,CRLF) E. each dat NB. find header/body
split
  dat=. (0&<@:>ndx)#dat     NB. drop out non-fields
  ndx=.  (0&<@:>ndx)# ndx
  dat=. ndx split each dat  NB. split header/body
  hdrs=. 0{::each dat
  dat=. 1{::each dat
  
  s=. 'name='
  ndx=. {.each I. each (<s) E. each hdrs NB. find string starts
  ndx=. (<#s) + each ndx                 NB. add string lengths
  keys=. ndx }.each hdrs                 NB. drop til after
  keys=. (*./\each -. each keys e. each <';',CR)# each keys  NB. drop
everything from ; or CR
  keys=. keys-.each <'"'                 NB. remove "s
  
  s=. 'filename='
  ndx=. {.each I. each (<s) E. each hdrs
  isfile=. 0&<@:>ndx                 NB. is section a file?
  ndx=. (<#s) + each isfile#ndx
  fnmes=. ndx }. each isfile#hdrs
  fnmes=. (*./\each -. each fnmes e. each <';',CR)# each fnmes
  fnmes=. fnmes-.each <'"'
  
  s=. 'Content-Type: '
  ndx=. {.each I. each (<s) E. each isfile#hdrs
  ndx=. (<#s)+each ndx
  contypes=. ndx }. each isfile#hdrs
  contypes=. (*./\each -. each contypes e. each <';',CR)# each contypes
  contypes=. contypes-.each <'" '
  
  dat=. _4}.each 4}.each dat      NB. drop 2CRLFs at start and CRLF-- at
end
  fdat=. isfile#dat
  
  dat=. fnmes (I.isfile) }dat     NB. for files replace value with
filename
  isfull=. 0&<@:>#each fdat
  if. +./isfull do.               NB. write files if data exists
    tp=. jpath '~CGI/tmp/'        NB. path for temp folder
    NB. *** add handling of multiple users uploading similar filenames
    fnmes=. (<tp), each isfull#fnmes         NB. new filenames to write
    b=. (isfull#fdat) fwrite each isfull#fnmes   NB. write files to temp
folder
    dat=. fnmes (isfull#I.isfile) }dat       NB. if file data not empty,
replace dat with written filename
  end.
  fnmes=. isfile expand ,.fnmes
  contypes=. isfile expand ,.contypes
  keys,.dat,.(<@>isfile),.fnmes,.contypes
)
----------------------------------------------------------------------
For information about J forums see http://www.jsoftware.com/forums.htm

Reply via email to