1. Get images or binary files from web form
- Posted by achury Jul 29, 2022
- 2763 views
Hello all!
I am trying to do an web form where the people send me some text fields and 2 or 3 photos.
How can a cgi-bin to process this? I can get successly text files, but binary files don't work. (XAMPP on Windows 7 machine).
Any hint?
This is my first experiment:
<html><head></head><body> <form method="post" action="/cgi-bin/prueba.cgi" enctype="multipart/form-data"> Your text: <input name="primero" /> <br> Your file: <input type="file" name="imagen" accept="image/png, .jpeg, .jpg, image/gif"> <br> <input type="submit" /> </form> </body></html>
This is the prueba.cgi, based on cgitest file I have take and modified from examples on the archive:
#!eui -- test program for euphoria cgi -- comment/uncomment the following to test the EUINC variable with batch include std/io.e include std/pretty.e sequence cmd -- if val is a string, return it, otherwise "Undefined" function test_val(object val) if atom(val) then return "Undefined" elsif object(val) then for i = 1 to length(val) do if not atom(val[i]) then return "Invalid string sequence" end if end for return val else return "Invalid type for string" end if return "foozle" -- never reached end function procedure env_dump(sequence val) printf(1, "%s: %s\n", {val, test_val(getenv(val))} ) end procedure puts(1, "Content-Type: text/plain\n\n") puts(1, "Hello!\n\n") puts(1, "COMMAND LINE\n============\n\n") cmd = command_line() for i = 1 to length(cmd) do printf(1, "%d: %s\n", {i, cmd[i]} ) end for puts(1, "\n\nREMOTE INFO\n===========\n") env_dump("REMOTE_IDENT") env_dump("REMOTE_USER") env_dump("REMOTE_HOST") env_dump("REMOTE_ADDR") puts(1, "\n\nSERVER INFO\n===========\n") env_dump("SERVER_SOFTWARE") env_dump("SERVER_NAME") env_dump("GATEWAY_INTERFACE") env_dump("SERVER_PROTOCOL") env_dump("SERVER_PORT") env_dump("REQUEST_METHOD") env_dump("PATH_INFO") env_dump("PATH_TRANSLATED") env_dump("SCRIPT_NAME") env_dump("QUERY_STRING") env_dump("AUTH_TYPE") env_dump("CONTENT_TYPE") env_dump("CONTENT_LENGTH") puts(1, "\n\nBROWSER INFO\n============\n") env_dump("HTTP_ACCEPT") env_dump("HTTP_USER_AGENT") puts(1, "\n\nSTANDAR INPUT\n=============\n") sequence whole_file whole_file = {} sequence chunk while 1 do chunk = get_bytes(0, 1024) -- read 100 bytes at a time whole_file &= chunk -- chunk might be empty, that's ok if length(chunk) < 1024 then exit end if end while print(1, whole_file) printf(1, "\n\nEl archivo recibido tiene %d bytes\n\n", {length(whole_file)}) -- should match DIR size of "temp" puts(1, whole_file)
2. Re: Get images or binary files from web form
- Posted by achury Jul 31, 2022
- 2681 views
I have a question for the people involved on the interpreter design.
To get files in the POST method. The file is received trough the standar input.
Can the interpreter to manage if the standar input has "binary" info. Like 00 bytes? Or is the information filtered by the interpreter prior to arrive to my app?
3. Re: Get images or binary files from web form
- Posted by achury Aug 02, 2022
- 2643 views
After more testing, on linux hosting appear to work OK.
Appear to be a bug on the windows. Not sure if from Windows itself, or our interpreter, or the C libraries used to compile it ¿¿Who knows??
But PHP on windows without problems to get binaries, so is possible to workaround.
I upload the same image at my windows localhost and at linux remote hosting. Noted that the standar input stream breaks when Windows received a character 001A (Ctrl-Z) So the windows interpreter take it as the end of the stream.
Screeshot comparing WINDOWS and Linux output: https://www.facebook.com/photo?fbid=10228785197921746
You can test at: http://quienfabrica.co/formulario.html
The same is reported for other languages: https://stackoverflow.com/questions/61460004/why-ascii-sub-u001a-is-ignored-in-java
My current code:
#!eui -- test program for euphoria cgi -- comment/uncomment the following to test the EUINC variable with batch include std/io.e include std/pretty.e include std/get.e sequence cmd -- if val is a string, return it, otherwise "Undefined" function test_val(object val) if atom(val) then return "Undefined" elsif object(val) then for i = 1 to length(val) do if not atom(val[i]) then return "Invalid string sequence" end if end for return val else return "Invalid type for string" end if return "foozle" -- never reached end function procedure env_dump(sequence val) printf(1, "%s: %s\n", {val, test_val(getenv(val))} ) end procedure puts(1, "Content-Type: text/plain\n\n") puts(1, "Hello!\n\n") puts(1, "COMMAND LINE\n============\n\n") cmd = command_line() for i = 1 to length(cmd) do printf(1, "%d: %s\n", {i, cmd[i]} ) end for puts(1, "\n\nREMOTE INFO\n===========\n") env_dump("REMOTE_IDENT") env_dump("REMOTE_USER") env_dump("REMOTE_HOST") env_dump("REMOTE_ADDR") puts(1, "\n\nSERVER INFO\n===========\n") env_dump("SERVER_SOFTWARE") env_dump("SERVER_NAME") env_dump("GATEWAY_INTERFACE") env_dump("SERVER_PROTOCOL") env_dump("SERVER_PORT") env_dump("REQUEST_METHOD") env_dump("PATH_INFO") env_dump("PATH_TRANSLATED") env_dump("SCRIPT_NAME") env_dump("QUERY_STRING") env_dump("AUTH_TYPE") env_dump("CONTENT_TYPE") env_dump("CONTENT_LENGTH") puts(1, "\n\nBROWSER INFO\n============\n") env_dump("HTTP_ACCEPT") env_dump("HTTP_USER_AGENT") flush(1) puts(1, "\n\nSTANDAR INPUT\n=============\n") object content_size sequence std_input = {} object char content_size = getenv("CONTENT_LENGTH") puts(1, "Content_size: ") print(1, content_size) if atom(content_size) then -- content length no definido puts(1, "\nNo standar input\n\n") abort(0) elsif sequence(content_size) then object j = value(content_size) puts(1, "\nj= ")? j if j[1] = 0 then --value() => GET_SUCESS puts(1, "CONTENT_LENGTH: ") ? j[2] for i=1 to j[2] do char = getc(0) std_input = append(std_input, char) puts(1, char) end for puts(1,"\n\n") print(1, std_input) --puts(1, "\n") end if else -- Unexpected error puts(1, "There is something strange about CONTENT_LENGTH\n\n") abort(0) end if print(1, std_input) --puts(1, "\n") printf(1, "\nEntrada estandar recibida tiene %d bytes", {content_size})
4. Re: Get images or binary files from web form
- Posted by achury Aug 04, 2022
- 2565 views
On Euphoria 3.1 for windows works!
But the Ctrl-Z character are replace with -1, but the stream continues. So you can simply search for -1 and replace with 26 on the sequence.
Anyway, this code is painfully slow.
Really someone use euphoria for cgi-bin? How use POST method?
5. Re: Get images or binary files from web form
- Posted by jmduro Aug 08, 2022
- 2434 views
Wouldn't allow_break(0) do the job (in std/console.e)?
Jean-Marc
6. Re: Get images or binary files from web form
- Posted by jmduro Aug 08, 2022
- 2438 views
Maybe also:
sequence nBytes = getenv("CONTENT_LENGTH") sequence query = get_bytes(0, to_number(nBytes))
7. Re: Get images or binary files from web form
- Posted by achury Aug 08, 2022
- 2403 views
Thanks for your reply.
I have just tested. But the output is the same. No matter the size of the archive, is trunked when received the EOF character.
8. Re: Get images or binary files from web form
- Posted by jmduro Aug 09, 2022
- 2392 views
Here is my test program that works:
-- test program for euphoria cgi include std/filesys.e include std/convert.e include std/io.e include std/net/url.e function test_variable(sequence variable) object val = getenv(variable) -- if val is a string, return it, otherwise "Undefined" if atom(val) then return "Undefined" elsif object(val) then for i = 1 to length(val) do if not atom(val[i]) then return "Invalid string sequence" end if end for return val else return "Invalid type for string" end if return "foozle" -- never reached end function procedure print_variable(sequence val) printf(1, "%s: %s\n", {val, test_variable(val)} ) end procedure procedure main(sequence cmd) sequence dt = date() sequence path = test_variable("SCRIPT_FILENAME") -- PATH_TRANSLATED on Apache2 sequence webDir = dirname(path) sequence script = filebase(path) sequence query, method object nBytes puts(1, "Content-Type: text/plain\n\n") puts(1, "COMMAND LINE\n============\n\n") for i = 1 to length(cmd) do printf(1, "%d: %s\n", {i, cmd[i]} ) end for puts(1, "\n\nREMOTE INFO\n===========\n") print_variable("REMOTE_ADDR") print_variable("REMOTE_HOST") print_variable("REMOTE_HOST") print_variable("REMOTE_PORT") print_variable("REMOTE_IDENT") puts(1, "\n\nSERVER INFO\n===========\n") print_variable("SERVER_ADMIN") print_variable("SERVER_NAME") print_variable("GATEWAY_INTERFACE") print_variable("SERVER_PROTOCOL") print_variable("SERVER_PORT") print_variable("SERVER_SOFTWARE") print_variable("SERVER_SIGNATURE") method = test_variable("REQUEST_METHOD") printf(1, "%s: %s\n", {"REQUEST_METHOD", method} ) print_variable("SESSION_PATH") print_variable("PATH") print_variable("PATH_INFO") print_variable("REQUEST_SCHEME") print_variable("REQUEST_URI") print_variable("DOCUMENT_URI") print_variable("PATH_TRANSLATED") print_variable("SCRIPT_NAME") print_variable("SCRIPT_FILENAME") if equal(method, "GET") then -- print_variable("QUERY_STRING") query = decode(test_variable("QUERY_STRING")) printf(1, "%s: %s\n", {"QUERY_STRING", query} ) else nBytes = getenv("CONTENT_LENGTH") query = get_bytes(0, to_number(nBytes)) printf(1, "%s: %s\n", {"BODY", query} ) end if print_variable("AUTH_TYPE") print_variable("CONTENT_TYPE") print_variable("CONTENT_LENGTH") print_variable("DOCUMENT_ROOT") puts(1, "\n\nBROWSER INFO\n=============\n") print_variable("HTTP_ACCEPT") print_variable("HTTP_USER_AGENT") print_variable("HTTP_COOKIE") print_variable("HTTP_HOST") print_variable("HTTP_REFERER") print_variable("HTTPS") end procedure main(command_line())
Here is the answer to a POST request when sending a Zip file:
COMMAND LINE ============ 1: C:\My Program Files\euphoria4.1\bin\eui.exe 2: C:/Data/Euphoria/transfer/server/www/test.ex REMOTE INFO =========== REMOTE_ADDR: 127.0.0.1 REMOTE_HOST: Undefined REMOTE_HOST: Undefined REMOTE_PORT: 55454 REMOTE_IDENT: Undefined SERVER INFO =========== SERVER_ADMIN: Undefined SERVER_NAME: 127.0.0.1 GATEWAY_INTERFACE: CGI/1.1 SERVER_PROTOCOL: HTTP/1.1 SERVER_PORT: 80 SERVER_SOFTWARE: lighttpd/1.4.49 SERVER_SIGNATURE: Undefined REQUEST_METHOD: POST SESSION_PATH: Undefined PATH: C:\My Program Files\lighttpd PATH_INFO: Undefined REQUEST_SCHEME: http REQUEST_URI: /test.ex DOCUMENT_URI: Undefined PATH_TRANSLATED: Undefined SCRIPT_NAME: /test.ex SCRIPT_FILENAME: C:/Data/Euphoria/transfer/server/www/test.ex BODY: ------WebKitFormBoundaryXeARN8nzBv8gcjaM Content-Disposition: form-data; name="File"; filename="vt100_v0.1.9.zip" Content-Type: application/x-zip-compressed PK AUTH_TYPE: Undefined CONTENT_TYPE: multipart/form-data; boundary=----WebKitFormBoundaryXeARN8nzBv8gcjaM CONTENT_LENGTH: 1159310 DOCUMENT_ROOT: C:/Data/Euphoria/transfer/server/www BROWSER INFO ============= HTTP_ACCEPT: */* HTTP_USER_AGENT: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.5005.134 Safari/537.36 Edg/102.0.1245.50 HTTP_COOKIE: Undefined HTTP_HOST: 127.0.0.1 HTTP_REFERER: Undefined HTTPS: Undefined
I use lighttpd on Windows 10.
Jean-Marc
9. Re: Get images or binary files from web form
- Posted by jmduro Aug 09, 2022
- 2378 views
Sorry, I was too quick. When displaying the real length of the received file the error appears:
nBytes = getenv("CONTENT_LENGTH") query = get_bytes(0, to_number(nBytes)) printf(1, "%s: %d\n", {"%d bytes received", length(query)} )
%d bytes received: 482 AUTH_TYPE: Undefined CONTENT_TYPE: multipart/form-data; boundary=----WebKitFormBoundary8MhqlWPqRLSpCl9f CONTENT_LENGTH: 1159310
allow_break(0) doesn't change anything to the result.
Jean-Marc
10. Re: Get images or binary files from web form
- Posted by jmduro Aug 09, 2022
- 2396 views
getc is not affected by the problem so here is the work-around:
nBytes = getenv("CONTENT_LENGTH") query = {} for n = 1 to to_integer(nBytes) do integer c = getc(0) query = append(query, c) end for -- query = get_bytes(0, to_number(nBytes)) printf(1, "%d bytes received\n", {length(query)} )
1159310 bytes received AUTH_TYPE: Undefined CONTENT_TYPE: multipart/form-data; boundary=----WebKitFormBoundaryba4L3niknxAhwapL CONTENT_LENGTH: 1159310
Jean-Marc
11. Re: Get images or binary files from web form
- Posted by jmduro Aug 09, 2022
- 2391 views
Here is your code reviewed. It writes the received file in place. Just add a header FILE_NAME in the post request. It will bee seen by the CGI script as HTTP_FILE_NAME.
#!eui -- test program for euphoria cgi -- comment/uncomment the following to test the EUINC variable with batch include std/io.e include std/pretty.e include std/get.e include std/convert.e include std/io.e sequence cmd -- if val is a string, return it, otherwise "Undefined" function test_val(object val) if atom(val) then return "Undefined" elsif object(val) then for i = 1 to length(val) do if not atom(val[i]) then return "Invalid string sequence" end if end for return val else return "Invalid type for string" end if return "foozle" -- never reached end function procedure env_dump(sequence val) printf(1, "%s: %s\n", {val, test_val(getenv(val))} ) end procedure puts(1, "Content-Type: text/plain\n\n") puts(1, "Hello!\n\n") puts(1, "COMMAND LINE\n============\n\n") cmd = command_line() for i = 1 to length(cmd) do printf(1, "%d: %s\n", {i, cmd[i]} ) end for puts(1, "\n\nREMOTE INFO\n===========\n") env_dump("REMOTE_IDENT") env_dump("REMOTE_USER") env_dump("REMOTE_HOST") env_dump("REMOTE_ADDR") puts(1, "\n\nSERVER INFO\n===========\n") env_dump("SERVER_SOFTWARE") env_dump("SERVER_NAME") env_dump("GATEWAY_INTERFACE") env_dump("SERVER_PROTOCOL") env_dump("SERVER_PORT") env_dump("REQUEST_METHOD") env_dump("PATH_INFO") env_dump("PATH_TRANSLATED") env_dump("SCRIPT_NAME") env_dump("QUERY_STRING") env_dump("AUTH_TYPE") env_dump("CONTENT_TYPE") env_dump("CONTENT_LENGTH") puts(1, "\n\nBROWSER INFO\n============\n") env_dump("HTTP_ACCEPT") env_dump("HTTP_USER_AGENT") puts(1, "\n\nFILE NAME\n============\n") sequence fname = test_val(getenv("HTTP_FILE_NAME")) flush(1) puts(1, "\n\nSTANDARD INPUT\n=============\n") object content_size sequence std_input = {} object char content_size = getenv("CONTENT_LENGTH") puts(1, "Content_size: ") print(1, content_size) if atom(content_size) then -- content length no definido puts(1, "\nNo standard input\n\n") abort(0) elsif sequence(content_size) then std_input = {} for n = 1 to to_integer(content_size) do integer c = getc(0) std_input = append(std_input, c) end for else -- Unexpected error puts(1, "There is something strange about CONTENT_LENGTH\n\n") abort(0) end if write_file(fname, std_input) printf(1, "\nStandard input received %s bytes", {content_size})
Jean-Marc
12. Re: Get images or binary files from web form
- Posted by jmduro Aug 09, 2022
- 2380 views
I forgot to print the file name:
printf(1, "%s: %s\n", {"HTTP_FILE_NAME", fname} )
13. Re: Get images or binary files from web form
- Posted by achury Aug 09, 2022
- 2357 views
What version are you using?
I tested your last code, and I have the same problem.
I am using: Euphoria Interpreter v4.1.0 development 64-bit Windows, Using System Memory Revision Date: 2015-02-02 14:18:53, Id: 6300:57179171dbed
On linux works well, but not on windows
The data received is somethink like
{45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45, 45,45,45,45,51,57,57,52,48,54,52,49,55,48,49,56,51,53,57,52,49,54,57,52,50,54, 57,48,49,48,51,49,56,50,10,67,111,110,116,101,110,116,45,68,105,115,112,111, 115,105,116,105,111,110,58,32,102,111,114,109,45,100,97,116,97,59,32,110,97,109,101,61,34,112,114,105,109,101,114,111,34,10,10,102,103,104,106,102,103,104,106,10,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,51,57,57,52,48,54,52,49,55,48,49,56,51,53,57,52,49,54,57,52,50,54,57,48,49,48,51,49,56,50,10,67,111,110,116,101,110,116,45,68,105,115,112,111,115,105,116,105,111,110,58,32,102,111,114,109,45,100,97,116,97,59,32,110,97,109,101,61,34,102,105,108,101,84,111,85,112,108,111,97,100,34,59,32,102,105,108,101,110,97,109,101,61,34,116,117,120,46,106,112,103,34,10,67,111,110,116,101,110,116,45,84,121,112,101,58,32,105,109,97,103,101,47,106,112,101,103,10,10,255,216,255,224,0,16,74,70,73,70,0,1,1,0,0,1,0,1,0,0,255,219,0,67,0,4,2,3,3,3,2,4,3,3,3,4,4,4,4,5,9,6,5,5,5,5,11,8,8,6,9,13,11,13,13,13,11,12,12,14,16,20,17,14,15,19,15,12,12,18,24,18,19,21,22,23,23,23,14,17,25,27,25,22,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, ....
When detected an EOF character (number 26), the EOF and any subsequent data is converted to -1.
14. Re: Get images or binary files from web form
- Posted by jmduro Aug 10, 2022
- 2346 views
Here s what I'm using:
Microsoft Windows [version 10.0.19042.1826] (c) Microsoft Corporation. Tous droits réservés. Euphoria Interpreter v4.1.0 development 32-bit Windows, Using System Memory Revision Date: 2015-02-02 14:18:53, Id: 6300:57179171dbed lighttpd/1.4.49 (ssl) - a light and fast webserver This version is built by dtech(.hu), http://lighttpd.dtech.hu/ Binary package is compiled with GCC v6.4.0 under Cygwin environment.
Avoid using EU4.1 64 bits when problems occur. 32 bits version is more safe.
Jean-Marc
15. Re: Get images or binary files from web form
- Posted by jmduro Aug 10, 2022
- 2344 views
I have put Lighttpd and the project folder on my personal site:
- http://jean-marc.duro.pagesperso-orange.fr/transfer.zip
- http://jean-marc.duro.pagesperso-orange.fr/lighttpd.zip
Unarchive lighttpd.zip anywhere and don't change it.
Unarchive transfer.zip anywhere. Change directory to transfer\server. You will have to update:
- lighttpd.bat to tell it where to find lighttpd. Default command is "C:\My Program Files\lighttpd\lighttpd.exe" -D
- conf/lighttpd.conf, lines 178 and 180, to tell lighttpd where to find openeuphoria. Defaults are:
- ".ex" => "C:/My Program Files/euphoria4.1/bin/eui",
- ".il" => "C:/My Program Files/euphoria4.1/bin/eub",
The way it is done, you can have one lighttpd configuration per project.
Jean-Marc
16. Re: Get images or binary files from web form
- Posted by jmduro Aug 10, 2022
- 2326 views
Failed! The file received has been modified at the first ESC char! This old Windows EU4 bug is still relevant as you wrote since the beginning of this thread.
17. Re: Get images or binary files from web form
- Posted by achury Aug 10, 2022
- 2312 views
Yes, but the problem is on windows version only.
Check it working on linux server:
18. Re: Get images or binary files from web form
- Posted by irv Aug 10, 2022
- 2296 views
For a test, I sent a .png file, 4,675 bytes Can you successfully reconstruct the image from that?
19. Re: Get images or binary files from web form
- Posted by achury Aug 10, 2022
- 2315 views
My page don't save any file, is just a test!
But you can go down, after the binary dump, copy the sequence and paste on Eu code to save the file.
I had not tried. I'll do it and inform you.
Marco A
20. Re: Get images or binary files from web form
- Posted by irv Aug 10, 2022
- 2290 views
Copied the sequence, which is 35,331 bytes. How to convert that back to an image?
21. Re: Get images or binary files from web form
- Posted by achury Aug 10, 2022
- 2303 views
I did it by hand and worked well.
- Upload jpg file to the web.
- Wait a lot, the program is slow because use getc, I'll modify later.
- Go down, after the binary dump, appear twice the sequence dump.
- Copy the sequence.
- Search for 13,10,13,10 After The second time appears is the first byte of your file.
- Search for 13,10,45,45 near the end. This is the last separator, your file ends just before that.
include std/io.e sequence filedata={255,216,255,224,0,16,74,70,73,70,0,1,1,0,0,1,0,1,0,0,255, ... ,2,34,32,63,255,217} print (1,length(filedata)) write_file("file2.jpg", filedata)
22. Re: Get images or binary files from web form
- Posted by jmduro Aug 10, 2022
- 2282 views
This is the way I do:
std_input = get_bytes(0, to_integer(content_size)) sequence boundary = {} for n = 1 to length(std_input) do if (std_input[n] = '\n') and (std_input[n+1] = '\n') then sequence s = std_input[1..n-1] boundary = split(s, '\n') std_input = remove(std_input, 1, n+1) exit end if end for write_file(fname, std_input)
Within the boundary part you can extract the filename.
Jean-Marc
23. Re: Get images or binary files from web form
- Posted by jmduro Aug 10, 2022
- 2282 views
Following code works with files containing no ESC char, so it should work on Linux for all files:
with batch include std/io.e include std/pretty.e include std/get.e include std/convert.e include std/sequence.e -- split include std/text.e -- dequote -- if val is a string, return it, otherwise "Undefined" function test_val(object val) if atom(val) then return "Undefined" elsif object(val) then for i = 1 to length(val) do if not atom(val[i]) then return "Invalid string sequence" end if end for return val else return "Invalid type for string" end if return "foozle" -- never reached end function puts(1, "Content-Type: text/plain\n\n") sequence fname = "" sequence content_size = test_val(getenv("CONTENT_LENGTH")) sequence std_input = get_bytes(0, to_integer(content_size)) sequence boundary = {} for n = 1 to length(std_input) do if (std_input[n] = '\n') and (std_input[n+1] = '\n') then sequence s = std_input[1..n-1] boundary = split(s, '\n') std_input = remove(std_input, 1, n+1) s = split(boundary[2], "filename=") fname = dequote(s[2]) exit end if end for write_file(fname, std_input) printf(1, "Received %s bytes\n", {content_size}) printf(1, "Written %s (%d bytes)", {fname, length(std_input)})
Received 29044 bytes Written bloatbox.zip (64 bytes)
Unfortunately, there is no solution for Windows when the file contains ESC chars.
Jean-Marc
24. Re: Get images or binary files from web form
- Posted by achury Aug 10, 2022
- 2283 views
Thanks for share. I'll use that.
By now I'll be forced to use PHP
I hope this problem may become solved. I put a ticket.
I am not sure if the problem is in the interpreter or in the standar library.
25. Re: Get images or binary files from web form
- Posted by jmduro Aug 11, 2022
- 2264 views
It looks like STDIN is allways in text mode and cannot be put in binary mode. In OE 4 Windows, STDIN seems to be closely tied to the keyboard.
I tried to force binary mode with a wrapper on _setmode (msvcrt.dll), but this cannot work with CGI because of browser restrictions. Maybe this could work witn a self made server.
Jean-Marc
26. Re: Get images or binary files from web form
- Posted by SDPringle Aug 11, 2022
- 2241 views
I wonder if it fails the same way translated?
27. Re: Get images or binary files from web form
- Posted by jmduro Aug 12, 2022
- 2243 views
If you mean by using James Cook's translated eui, the answer is yes. STDIN is still in text mode.
Jean-Marc
28. Re: Get images or binary files from web form
- Posted by jmduro Aug 12, 2022
- 2213 views
Tried with EU 3.11. CTRL-Z (and not ESC as written before) is still replaced by -1 but following chars remain as is: it's better but still wrong. Some chars as #0D are even left out.
So prefer Linux if you need to upload files via CGI.
Jean-Marc
29. Re: Get images or binary files from web form
- Posted by ghaberek (admin) Aug 12, 2022
- 2213 views
Using _setmode() seems to work for me, running xampp-portable-windows-x64-7.4.29-0-VC15 on Windows 10 64-bit with Euphoria 4.1 64-bit. Here's the code I used to test. (Including an override for getenv() that returns a default value and converts strings to atoms.)
#!"C:\Euphoria\bin\eui.exe" include std/io.e include std/convert.e include std/dll.e without warning += { override } with batch constant msvcrt = open_dll( "msvcrt.dll" ) constant _setmode = define_c_func( msvcrt, "_setmode", {C_INT,C_INT}, C_INT ) constant O_BINARY = 0x008000 function set_mode( integer fn, integer mode ) return c_func( _setmode, {fn,mode} ) end function override function getenv( sequence name, object default="" ) object value = eu:getenv( name ) if equal( value, -1 ) then return default end if if atom( default ) then value = to_number( value ) end if return value end function printf( STDOUT, "Content-type: text/html\n\n" ) printf( STDOUT, "<html><head></head><body>\n" ) printf( STDOUT, "<form method=\"post\" action=\"/cgi-bin/upload.esp\" enctype=\"multipart/form-data\">\n" ) printf( STDOUT, "Your text: <input name=\"text\" /><br>\n" ) printf( STDOUT, "Your file: <input type=\"file\" name=\"file\" accept=\"image/png, .jpeg, .jpg, image/gif\"><br>\n" ) printf( STDOUT, "<input type=\"submit\" /></form>\n" ) sequence request_method = getenv( "REQUEST_METHOD" ) if equal( request_method, "POST" ) then sequence content_type = getenv( "CONTENT_TYPE" ) integer content_length = getenv( "CONTENT_LENGTH", 0 ) printf( STDOUT, "<pre><code>\n" ) printf( STDOUT, "CONTENT_TYPE = \"%s\"\n", {content_type} ) printf( STDOUT, "CONTENT_LENGTH = %d\n", {content_length} ) printf( STDOUT, "REQUEST_METHOD = \"%s\"\n", {request_method} ) printf( STDOUT, "</code></pre>\n" ) set_mode( STDIN, O_BINARY ) sequence bytes = get_bytes( STDIN, content_length ) printf( STDOUT, "<p>Received %d bytes!</p>\n", {length(bytes)} ) end if printf( 1, "</body></html>\n" )
I still need to include multipart form handling in Euphoria MVC, but if I recall, last time I looked at it I was stuck on this problem and I believe this corrects it. I will also look at what it takes to do this in the back end.
-Greg
30. Re: Get images or binary files from web form
- Posted by jmduro Aug 16, 2022
- 2130 views
Thanks Greg,
I have not been able to get it work. However, following code works on Linux:
with batch include std/io.e include std/pretty.e include std/get.e include std/convert.e include std/sequence.e -- split include std/text.e -- dequote -- if val is a string, return it, otherwise "Undefined" function test_val(object val) if atom(val) then return "Undefined" elsif object(val) then for i = 1 to length(val) do if not atom(val[i]) then return "Invalid string sequence" end if end for return val else return "Invalid type for string" end if return "foozle" -- never reached end function puts(1, "Content-Type: text/plain\n\n") sequence fname = "" sequence content_size = test_val(getenv("CONTENT_LENGTH")) sequence std_input = get_bytes(0, to_integer(content_size)) sequence boundary = {} for n = 1 to length(std_input) do if equal(std_input[n..n+3], "\r\n\r\n") then sequence s = std_input[1..n-1] boundary = split(s, "\r\n") std_input = remove(std_input, 1, n+3) s = split(boundary[2], "filename=") fname = dequote(s[2]) exit end if end for integer p = match("\r\n" & boundary[1], std_input) write_file("/tmp/" & fname, std_input[1..p-1]) printf(1, "Received %s bytes\n", {content_size}) printf(1, "Written %s (%d bytes)", {fname, length(std_input[1..p-1])})
POST response is:
Received 29044 bytes Written bloatbox.zip (28840 bytes)
File is correctly written in /tmp:
root@cpe-tests-tool-JM:/var/www/html# ls -l /tmp/bloatbox.zip -rw-r--r-- 1 www-data www-data 28840 Aug 16 11:14 /tmp/bloatbox.zip root@cpe-tests-tool-JM:/var/www/html# unzip -l /tmp/bloatbox.zip Archive: /tmp/bloatbox.zip Length Date Time Name --------- ---------- ----- ---- 159744 2021-05-24 11:50 Bloatbox.exe 0 2021-05-24 11:50 de/ 8192 2021-05-24 11:50 de/Bloatbox.resources.dll --------- ------- 167936 3 files
Jean-Marc
31. Re: Get images or binary files from web form
- Posted by achury Oct 08, 2022
- 1777 views
Just this week I come back with this
Your code works well to me (Windows 7) Just needed to add platform(), so don't try to run windows specific code on linux machines.
I am also learning about how to parse form response.
https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition
Would be nice to have on standar lib a clever function may scan the binary input, from any web form, separate chunks using boundary, read the Content-Disposition on each section to define how to scan it. Usual form inputs are simply plain text, and files are binary blobs. Then return one simple sequence, something like.
{ {FORMTEXT, "FormName", "Bill Gates"}, {FORMTEXT, "FormCompany", "Microsoft"} {FORMFILE, "FormPhoto", {"myphoto.jpg", "Long Binary sequence here......"} } }
Marco Achury
32. Re: Get images or binary files from web form
- Posted by ghaberek (admin) Oct 08, 2022
- 1779 views
Just needed to add platform(), so don't try to run windows specific code on linux machines.
You should be using ifdef instead of platform(). Here's an updated example that uses ifdef to only provide set_mode() on Windows.
#!"C:\Euphoria\bin\eui.exe" include std/io.e include std/convert.e include std/dll.e without warning += { override } with batch ifdef WINDOWS then constant msvcrt = open_dll( "msvcrt.dll" ) constant _setmode = define_c_func( msvcrt, "_setmode", {C_INT,C_INT}, C_INT ) constant O_BINARY = 0x008000 function set_mode( integer fn, integer mode ) return c_func( _setmode, {fn,mode} ) end function end ifdef override function getenv( sequence name, object default="" ) object value = eu:getenv( name ) if equal( value, -1 ) then return default end if if atom( default ) then value = to_number( value ) end if return value end function printf( STDOUT, "Content-type: text/html\n\n" ) printf( STDOUT, "<html><head></head><body>\n" ) printf( STDOUT, "<form method=\"post\" action=\"/cgi-bin/upload.esp\" enctype=\"multipart/form-data\">\n" ) printf( STDOUT, "Your text: <input name=\"text\" /><br>\n" ) printf( STDOUT, "Your file: <input type=\"file\" name=\"file\" accept=\"image/png, .jpeg, .jpg, image/gif\"><br>\n" ) printf( STDOUT, "<input type=\"submit\" /></form>\n" ) sequence request_method = getenv( "REQUEST_METHOD" ) if equal( request_method, "POST" ) then sequence content_type = getenv( "CONTENT_TYPE" ) integer content_length = getenv( "CONTENT_LENGTH", 0 ) printf( STDOUT, "<pre><code>\n" ) printf( STDOUT, "CONTENT_TYPE = \"%s\"\n", {content_type} ) printf( STDOUT, "CONTENT_LENGTH = %d\n", {content_length} ) printf( STDOUT, "REQUEST_METHOD = \"%s\"\n", {request_method} ) printf( STDOUT, "</code></pre>\n" ) ifdef WINDOWS then set_mode( STDIN, O_BINARY ) end ifdef sequence bytes = get_bytes( STDIN, content_length ) printf( STDOUT, "<p>Received %d bytes!</p>\n", {length(bytes)} ) end if printf( 1, "</body></html>\n" )
I am also learning about how to parse form response.
https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition
Would be nice to have on standar lib a clever function may scan the binary input, from any web form, separate chunks using boundary, read the Content-Disposition on each section to define how to scan it.
I do plan to add this to Euphoria MVC, although in time I may end up ingesting that entire project into Euphoria standard library.
-Greg
33. Re: Get images or binary files from web form
- Posted by achury Oct 19, 2022
- 1618 views
I want to have a very simple library for CGI bin. Please check this and guide me how to follow. May be later you can include some from this on your MVC
Note, the 3 example forms point to the same CGI script.