自作のCGIライブラリ。Lua の勉強を兼ねて、PHP ライクに使えるCGIライブラリを作ってみた。
以下は、そのライブラリのメイン部分。実際には、もう一つファイルが必要
file:kucgi.lua
--[[ kucgi.lua is CGI library Like PHP @author kujirahand.com set variables (_GET | _POST | _FILES | _SERVER) [WARNING] _FILES ... Could not upload Binary file because Lua's stdin is Text mode. @see http://lua-users.org/lists/lua-l/2006-10/msg00651.html --]] local modname = "kucgi" local kucgi = {} _G[modname] = kucgi require "ku" -- register global like PHP -- _SERVER _SERVER = {} if (_G.arg) then _SERVER["LUA_SELF"] = _G.arg[0] end do local env_list = { "REMOTE_ADDR","PATH_INFO","SCRIPT_FILENAME", "SCRIPT_NAME","HTTP_HOST","HTTP_USER_AGENT","OS","PATH_TRANSLATED", "QUERY_STRING","REMOTE_HOST","REMOTE_PORT","REQUEST_METHOD", "REQUEST_URI","SERVER_PORT","SERVER_PROTOCOL","SERVER_SOFTWARE" } for i,v in ipairs(env_list) do _SERVER[v] = os.getenv(v) end end -- _GET --[=[= parse query _GET @param query_string os.getenv("QUERY_STRING") @return query table @example > a=kucgi.parse_query("a=1&b=2&c=3");return a["a"]..a["b"]..a["c"] 123 > a=kucgi.parse_query("a=&b=2&c=3");return a["a"]..a["b"]..a["c"] 23 > a=kucgi.parse_query("a=test&b=hoge");return a["b"] hoge =]=] kucgi.parse_query = function (query_string) if type(query_string) ~= "string" then return {} end local v = {} query_string:gsub("([^%=]+)%=([^%&]*)&?", function(key,val) key = ku.urldecode(key) val = ku.urldecode(val) v[key] = val end) return v end _GET = kucgi.parse_query(_SERVER["QUERY_STRING"]) --[=[= get request method @return GET or POST =]=] kucgi.method = os.getenv("REQUEST_METHOD") do if not kucgi.method then kucgi.method = "GET" end kucgi.method = string.upper(kucgi.method) end --[=[= parse multipart/form header > a=kucgi.parse_header([[Content-Disposition: form-data; name="hoge2"]]) > =a["Content-Disposition"] form-data; name="hoge2" > =a["name"] hoge2 > a=kucgi.parse_header([[Content-Disposition: form-data; name="a"; filename="b" ]]) > =a["filename"] b =]=] kucgi.parse_header = function (head, EOL) if EOL == nil then EOL = "\r\n" end local res = {} local lines = ku.split(head, EOL) for i, line in ipairs(lines) do local key, val = line:match("([^%:]+)%:(.+)$") if key and val then key = ku.trim(key) val = ku.trim(val) res[key] = val end end -- other parameter if res["Content-Disposition"] then local tok = ku.Tokenizer:new(res["Content-Disposition"]) while tok.src ~= "" do local line = tok:getToken(";") local key, val = ku.splitToken(line, "=") key = ku.trim(key) val = ku.trim(val) if type(val) == "string" then if (val:sub(1,1) == '"' and val:sub(-1) == '"') or (val:sub(1,1) == "'" and val:sub(-1) == "'") then val = string.sub(val, 2, val:len()-1) end res[key] = val end end end return res end -- _POST and _FILES --[=[= parse post method @param content_type @param contents @return _POST, _FILES > c = "\r\n--hoge\r\nContent-Disposition: form-data; name=\"hoge1\"\r\n\r\ntest\r\n--hoge--" > a = kucgi.parse_post("multipart/form-data;boundary=hoge",c) > =a["hoge1"] test > c = "\r\n--hoge\r\nContent-Disposition: form-data; name=\"hoge1\"; filename=\"a.txt\"\r\n\r\ntest\r\n--hoge--" > a,b = kucgi.parse_post("multipart/form-data;boundary=hoge",c) > =b["hoge1"]["body"] test =]=] kucgi.parse_post = function (content_type, contents) -- print("<pre>"..contents.."</pre>") -- check x-www-form-urlencoded if content_type == "application/x-www-form-urlencoded" then return kucgi.parse_query(contents), {} end -- check multipart/form local post = {} local files = {} local type1 = string.match(content_type, "^[^%;]+") if (type1 == "multipart/form-data") then -- multipart local boundary = string.match(content_type,"boundary=(.+)%S*") if not boundary then return {}, {} end local EOL = "\r\n" local sep = "--"..boundary contents = ku.trim(contents) local s1, s2 = ku.splitToken(contents, sep) s2 = s2 or " " if s2:sub(1,1) == "\n" then EOL = "\n" else EOL = "\r\n" end parts = ku.Tokenizer:new(contents) while parts.src ~= "" do local pat = parts:getToken(sep) pat = ku.trim(pat) if pat == "--" then break end if pat ~= "" then local head, body = ku.splitToken(pat, EOL..EOL) local heads = kucgi.parse_header(head, EOL) if heads["filename"] then if heads["filename"] ~= "" then files[ heads["name"] ] = { name = heads["filename"], size = string.len(body), ["body"] = body } end else if heads["name"] then post[heads["name"]] = body end end end end end return post, files end _POST = {} _FILES = {} if kucgi.method == "POST" then local content_type = os.getenv("CONTENT_TYPE") local len_str = os.getenv("CONTENT_LENGTH") if len_str then local len = tonumber(len_str) local src = io.read(len) -- todo: "io.read()" is text mode fp = io.open("test.txt","w") fp:write(src) _POST, _FILES = kucgi.parse_post(content_type, src) end end -- shortcut echo = io.write