package php; /** This class is used for accessing the local Web server and the current client request and informations. **/ class Web { /** Returns the GET and POST parameters. **/ public static function getParams() { #if force_std_separator var h = Lib.hashOfAssociativeArray(untyped __php__("$_POST")); for( p in getParamsString().split(";") ) { var a = p.split("="); var n = a.shift(); h.set(StringTools.urlDecode(n),StringTools.urlDecode(a.join("="))); } return h; #else var a : Array = untyped __php__("array_merge($_GET, $_POST)"); if(untyped __call__("get_magic_quotes_gpc")) untyped __php__("foreach($a as $k => $v) $a[$k] = stripslashes($v)"); return Lib.hashOfAssociativeArray(a); #end } /** Returns an Array of Strings built using GET / POST values. If you have in your URL the parameters [a[]=foo;a[]=hello;a[5]=bar;a[3]=baz] then [php.Web.getParamValues("a")] will return [["foo","hello",null,"baz",null,"bar"]] **/ public static function getParamValues( param : String ) : Array { var reg = new EReg("^"+param+"(\\[|%5B)([0-9]*?)(\\]|%5D)=(.*?)$", ""); var res = new Array(); var explore = function(data:String){ if (data == null || data.length == 0) return; for (part in data.split("&")){ if (reg.match(part)){ var idx = reg.matched(2); var val = StringTools.urlDecode(reg.matched(4)); if (idx == "") res.push(val); else res[Std.parseInt(idx)] = val; } } } explore(StringTools.replace(getParamsString(), ";", "&")); explore(getPostData()); if (res.length == 0) return null; return res; } /** Returns the local server host name **/ public static inline function getHostName() : String { return untyped __php__("$_SERVER['SERVER_NAME']"); } /** Surprisingly returns the client IP address. **/ public static inline function getClientIP() : String { return untyped __php__("$_SERVER['REMOTE_ADDR']"); } /** Returns the original request URL (before any server internal redirections) **/ public static function getURI() : String { var s : String = untyped __php__("$_SERVER['REQUEST_URI']"); return s.split("?")[0]; } /** Tell the client to redirect to the given url ("Location" header) **/ public static function redirect( url : String ) { untyped __call__('header', "Location: " + url); } /** Set an output header value. If some data have been printed, the headers have already been sent so this will raise an exception. **/ public static inline function setHeader( h : String, v : String ) { untyped __call__('header', h+": "+v); } /** Set the HTTP return code. Same remark as setHeader. See status code explanation here: http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html **/ public static function setReturnCode( r : Int ) { var code : String; switch(r) { case 100: code = "100 Continue"; case 101: code = "101 Switching Protocols"; case 200: code = "200 Continue"; case 201: code = "201 Created"; case 202: code = "202 Accepted"; case 203: code = "203 Non-Authoritative Information"; case 204: code = "204 No Content"; case 205: code = "205 Reset Content"; case 206: code = "206 Partial Content"; case 300: code = "300 Multiple Choices"; case 301: code = "301 Moved Permanently"; case 302: code = "302 Found"; case 303: code = "303 See Other"; case 304: code = "304 Not Modified"; case 305: code = "305 Use Proxy"; case 307: code = "307 Temporary Redirect"; case 400: code = "400 Bad Request"; case 401: code = "401 Unauthorized"; case 402: code = "402 Payment Required"; case 403: code = "403 Forbidden"; case 404: code = "404 Not Found"; case 405: code = "405 Method Not Allowed"; case 406: code = "406 Not Acceptable"; case 407: code = "407 Proxy Authentication Required"; case 408: code = "408 Request Timeout"; case 409: code = "409 Conflict"; case 410: code = "410 Gone"; case 411: code = "411 Length Required"; case 412: code = "412 Precondition Failed"; case 413: code = "413 Request Entity Too Large"; case 414: code = "414 Request-URI Too Long"; case 415: code = "415 Unsupported Media Type"; case 416: code = "416 Requested Range Not Satisfiable"; case 417: code = "417 Expectation Failed"; case 500: code = "500 Internal Server Error"; case 501: code = "501 Not Implemented"; case 502: code = "502 Bad Gateway"; case 503: code = "503 Service Unavailable"; case 504: code = "504 Gateway Timeout"; case 505: code = "505 HTTP Version Not Supported"; default: code = Std.string(r); } untyped __call__('header', "HTTP/1.1 " + code, true, r); } /** Retrieve a client header value sent with the request. **/ public static function getClientHeader( k : String ) : String { //Remark : PHP puts all headers in uppercase and replaces - with _, we deal with that here for(i in getClientHeaders()) if(i.header == StringTools.replace(k.toUpperCase(),"-","_")) return i.value; return null; } private static var _client_headers : List<{header : String, value : String}>; /** Retrieve all the client headers. **/ public static function getClientHeaders() { if(_client_headers == null) { _client_headers = new List(); var h = Lib.hashOfAssociativeArray(untyped __php__("$_SERVER")); for(k in h.keys()) { if(k.substr(0,5) == "HTTP_") { _client_headers.add({ header : k.substr(5), value : h.get(k)}); } } } return _client_headers; } /** Returns all the GET parameters String **/ public static inline function getParamsString() : String { return untyped __php__("$_SERVER['QUERY_STRING']"); } /** Returns all the POST data. POST Data is always parsed as being application/x-www-form-urlencoded and is stored into the getParams hashtable. POST Data is maximimized to 256K unless the content type is multipart/form-data. In that case, you will have to use [getMultipart] or [parseMultipart] methods. **/ public static function getPostData() { var h = untyped __call__("fopen", "php://input", "r"); var bsize = 8192; var max = 32; var data : String = null; var counter = 0; while (!untyped __call__("feof", h) && counter < max) { data += untyped __call__("fread", h, bsize); counter++; } untyped __call__("fclose", h); return data; } /** Returns an hashtable of all Cookies sent by the client. Modifying the hashtable will not modify the cookie, use setCookie instead. **/ public static function getCookies() { var h = new Hash(); var k = ""; var h1 = Lib.hashOfAssociativeArray(untyped __php__("$_COOKIE")); for( k in h1.keys() ) { h.set(k,h1.get(k)); } return h; } /** Set a Cookie value in the HTTP headers. Same remark as setHeader. **/ public static function setCookie( key : String, value : String, ?expire: Date, ?domain: String, ?path: String, ?secure: Bool ) { var t = expire == null ? 0 : (expire.getTime()/1000.0); if(path == null) path = ''; if(domain == null) domain = ''; if(secure == null) secure = false; untyped __call__("setcookie", key, value, t, path, domain, secure); } static function addPair( name, value ) : String { if( value == null ) return ""; return "; " + name + value; } /** Returns an object with the authorization sent by the client (Basic scheme only). **/ public static function getAuthorization() : { user : String, pass : String } { if(!untyped __php__("isset($_SERVER['PHP_AUTH_USER'])")) return null; return untyped {user: __php__("$_SERVER['PHP_AUTH_USER']"), pass: __php__("$_SERVER['PHP_AUTH_PW']")}; } /** Get the current script directory in the local filesystem. **/ public static inline function getCwd() : String { return untyped __php__('dirname($_SERVER["SCRIPT_FILENAME"])') + "/"; } /** Get the multipart parameters as an hashtable. The data cannot exceed the maximum size specified. **/ public static function getMultipart( maxSize : Int ) : Hash { var h = new Hash(); var buf : StringBuf = null; var curname = null; parseMultipart(function(p,_) { if( curname != null ) h.set(curname,buf.toString()); curname = p; buf = new StringBuf(); maxSize -= p.length; if( maxSize < 0 ) throw "Maximum size reached"; }, function(str,pos,len) { maxSize -= len; if( maxSize < 0 ) throw "Maximum size reached"; buf.addSub(str,pos,len); }); if( curname != null ) h.set(curname,buf.toString()); return h; } /** Parse the multipart data. Call [onPart] when a new part is found with the part name and the filename if present and [onData] when some part data is readed. You can this way directly save the data on hard drive in the case of a file upload. **/ public static function parseMultipart( onPart : String -> String -> Void, onData : String -> Int -> Int -> Void ) : Void { if(!untyped __call__("isset", __php__("$_FILES"))) return; var parts : Array = untyped __call__("array_keys", __php__("$_FILES")); for(part in parts) { var info : Dynamic = untyped __php__("$_FILES[$part]"); var tmp : String = untyped info['tmp_name']; var file : String = untyped info['name']; var err : Int = untyped info['error']; if(err > 0) { switch(err) { case 1: throw "The uploaded file exceeds the max size of " + untyped __call__('ini_get', 'upload_max_filesize'); case 2: throw "The uploaded file exceeds the max file size directive specified in the HTML form (max is" + untyped __call__('ini_get', 'post_max_size') + ")"; case 3: throw "The uploaded file was only partially uploaded"; case 4: throw "No file was uploaded"; case 6: throw "Missing a temporary folder"; case 7: throw "Failed to write file to disk"; case 8: throw "File upload stopped by extension"; } } onPart(part, file); var h = untyped __call__("fopen", tmp, "r"); // var pos = 0; var bsize = 8192; while (!untyped __call__("feof", h)) { var buf : String = untyped __call__("fread", h, bsize); var size : Int = untyped __call__("strlen", buf); onData(buf, 0, size); // onData(buf, pos, size); // pos += size; } untyped __call__("fclose", h); } } /** Flush the data sent to the client. By default on Apache, outgoing data is buffered so this can be useful for displaying some long operation progress. **/ public static inline function flush() : Void { untyped __call__("flush"); } /** Get the HTTP method used by the client. **/ public static function getMethod() : String { if(untyped __php__("isset($_SERVER['REQUEST_METHOD'])")) return untyped __php__("$_SERVER['REQUEST_METHOD']"); else return null; } public static var isModNeko(default,null) : Bool; static function __init__() { isModNeko = !php.Lib.isCli(); } }