Re: foreach routine

new topic     » goto parent     » topic index » view thread      » older message » newer message

duke normandin wrote:
> 
> Derek Parnell wrote:
> > 
> > duke normandin wrote:
> > > 
> > > Chris Bensler wrote:
> > > > The getenv() routine will return -1 if the environment variable
> > > > CONTENT_LENGTH
> > > > doesn't exist. If it does exist, a string will be returned.
> > > 
> > > Are you sure? I've never proven this to myself, but it has always been my
> > > understanding that with respect the method=POST, the ENV. VAR.
> > > CONTENT_LENGTH
> > > would be set to the amount of bytes sent out. THEREFORE, this is why we
> > > "read"
> > > that many bytes from STDIN, and only that many. So my point is that
> > > CONTENT_LENGTH
> > > will in one case be a positive number or a -1 -- both atoms. No?
> > 
> > Yes and no. The Euphoria function getenv() always returns a string if the
> > environment
> > variable exists, and -1 if it doesn't exist. In your case, CONTENT_LENGTH
> > will
> > most likely always be there due to the CGI environment, but when getenv()
> > returns
> > its content, it is a string representation of a number and not the number
> > itself.
> > So if the number of characters to read in from STDIN is 59,
> > getenv("CONTENT_LENGTH")
> > will return "59" and not 59. Thus you have to convert the string "59" to its
> > number form. 
> 
> I got it! Damn! I've got to watch the data types more carefully. Not used to
> it. ;)
> To recap, getenv returns the atom -1 if the ENV.VAR. is unset OR a string
> containing
> whatever. In the case of CONTENT_LENGTH I was expecting an integer. I now know
> to
> convert CONTENT_LENGTH *to* an integer.
> 
> >   res = value( "59" )
> 
> [snip]
> 
> I really don't need to do all that testing.
> 
> What the Perl/PHP etc world has done all this time is:
> 
> 1. getenv("REQUEST_METHOD")
> 2. if == "POST"
>    2.a value_array = value(getenv("CONTENT_LENGTH")
>    2.b stash get_bytes(0, value_array[2])
> 3. if == "GET"
>    3.a stash getenv("QUERY_STRING")
> 4. if == "some_bogus_method"
>    4.a cgi_die("gracefully")
> 5. amen
> 
> That is what I want to reproduce in Euphoria come "hell or high water" ;)
> 
> Once I have the above "stash", then we use your "foreach" and "split" code to
> massage the FORM[key]=values
> I love it !! Thanks you all for the mini EU tutorials!!
> --
> duke

Good programming practice is to always trap error conditions whenever you can.

I get the impression though, that you meant that you don't want to have to do
the error testing all the time. Make a routine that takes care of it for you
instead.

I use this routine..
This avoids the error by making it default to an empty string.
This routine will always return a valid string or "".

global function cgi_getenv(string name)
 object tmp
  tmp = getenv(name)
  if atom(tmp) then return "" end if
  return tmp
end function


Similarly for value(), I have..
This avoids the error by making it default to 0.
This always returns the converted number, or 0.

global function get_value(object x)
 sequence ret
  ret = value(x)
  if ret[1] = GET_SUCCESS then
    return ret[2]
  else
    return 0
  end if
end function


The above routines are not generally a good way to deal with error cases, but
for specific purposes such as this situation, it should be fine.

Using those two routines, I could make a new routine specifically to return the
content_length..
This routine returns the number value of the content length.

global function cgi_content_length()
 integer len
  len = cgi_getenv("CONTENT_LENGTH")
  return get_value(len)
end function


And a routine to handle the request method...
global function cgi_request_method()
  return cgi_getenv("REQUEST_METHOD")
end function


For further processing of the POST or QUERY, you will need some code like the
following, to convert url-encoded strings to plain text.

function replace_hex(sequence s)
 sequence f,hex
  -- find and store the index of all instances of '%' in s
  f = {}
  for i = 1 to length(s) do
    if s[i] = '%' then
      f &= i
    end if
  end for
  if length(f) then
    for i = length(f) to 1 by -1 do
hex = get_value("#"&s[f[i]+1..f[i]+2]) -- convert the string code to a
      character code
      s = s[1..f[i]-1] & hex & s[f[i]+3..length(s)]
    end for
  end if
  return s
end function

------------------------------------------------
-- This is the function that you are mostly after
-- cgi_parse_request() will convert a url-encoded string to key/value pairs
-- in the form of {{key1,key2,...},{val1,val2,...}}
-- EG. "firstname=Duke&lastname=Normandin"
--  becomes {{"firstname","lastname"},{"Duke","Normandin"}}

global function cgi_parse_request(sequence s)  
  s ={ s , {} }
  s[1] = join(split(s[1],'+'),' ') -- convert '+' to ' '
  s[1] = join(split(s[1],'&'),';') -- convert '&' to ';'
  s[1] = split(s[1],';')

  if length(s[1]) then s[2] = repeat("",length(s[1])) end if
  for i = 1 to length(s[1]) do
    s[1][i] = split(s[1][i],'=')
    s[1][i][1] = replace_hex(s[1][i][1])
    if length(s[1][i]) > 1 then
      s[2][i] = replace_hex(s[1][i][2])
    end if
    s[1][i] = s[1][i][1]
  end for
  return s
end function


Here is a routine to handle fetching the post data.
It will return a sequence of key/values as described for cgi_parse_request()
global function cgi_get_post()
 sequence buf
 integer len
  len = cgi_content_length()
  buf = get_bytes(STDIN,len)
  return cgi_parse_request(buf)
end function


Here is the routine to handle QUERY data.
global function cgi_get_query()
 sequence buf
  buf = cgi_getenv("QUERY_STRING")
  return cgi_parse_request(buf)
end function


Now you can make a routine to actually do the whole thing for you..
global function cgi_get_request()
 sequence req
  req = cgi_request_method()
  if equal(req,"POST") then
    return cgi_get_post()
  elsif equal(req,"GET") then
    return cgi_get_query()
  else
    -- error, invalid request method
  end if
end function



Buene?


You may be wondering why the pairs are stored as {key_list,data_list} instead of
{{key1,data1},{key2,data2}}. The reason is because it's easier to search for a
key that way.

EG.
sequence pairs
integer f
pairs = cgi_get_request()
f = find("firstname",pairs[1])
if f then
 puts(STDOUT,"Your firstname is: " & pairs[2][f] & "\n")
end if


Chris Bensler
~ The difference between ordinary and extraordinary is that little extra ~
http://empire.iwireweb.com - Empire for Euphoria

new topic     » goto parent     » topic index » view thread      » older message » newer message

Search



Quick Links

User menu

Not signed in.

Misc Menu