Re: foreach routine
- Posted by Chris Bensler <bensler at nt.net> Dec 23, 2006
- 690 views
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