2
0
Franco Ponticelli 17 жил өмнө
parent
commit
79d3faf13a
68 өөрчлөгдсөн 7636 нэмэгдсэн , 149 устгасан
  1. 1 1
      codegen.ml
  2. 2 0
      common.ml
  3. 1990 0
      genphp.ml
  4. 9 1
      main.ml
  5. 2 0
      std/Date.hx
  6. 2 0
      std/DateTools.hx
  7. 36 1
      std/EReg.hx
  8. 23 1
      std/Hash.hx
  9. 16 1
      std/IntHash.hx
  10. 45 2
      std/List.hx
  11. 4 1
      std/Math.hx
  12. 115 3
      std/Reflect.hx
  13. 14 1
      std/Std.hx
  14. 1 1
      std/StringBuf.hx
  15. 41 9
      std/StringTools.hx
  16. 174 15
      std/Type.hx
  17. 2 0
      std/Xml.hx
  18. 5 1
      std/haxe/Firebug.hx
  19. 37 10
      std/haxe/Http.hx
  20. 2 0
      std/haxe/Log.hx
  21. 3 1
      std/haxe/Md5.hx
  22. 30 0
      std/haxe/Resource.hx
  23. 16 1
      std/haxe/Serializer.hx
  24. 4 2
      std/haxe/Timer.hx
  25. 7 0
      std/haxe/io/Bytes.hx
  26. 4 0
      std/haxe/io/BytesBuffer.hx
  27. 4 0
      std/haxe/io/Input.hx
  28. 4 0
      std/haxe/io/Output.hx
  29. 5 0
      std/haxe/remoting/ContextAll.hx
  30. 1 1
      std/haxe/remoting/HttpConnection.hx
  31. 4 2
      std/haxe/remoting/SocketProtocol.hx
  32. 2 0
      std/haxe/unit/TestRunner.hx
  33. 645 0
      std/php/Boot.hx
  34. 945 0
      std/php/Curl.hx
  35. 19 0
      std/php/Exception.hx
  36. 112 0
      std/php/FileSystem.hx
  37. 9 0
      std/php/HException.hx
  38. 9 0
      std/php/IniHash.hx
  39. 60 0
      std/php/Lib.hx
  40. 97 0
      std/php/PhpDate__.hx
  41. 64 0
      std/php/PhpMath__.hx
  42. 374 0
      std/php/PhpXml__.hx
  43. 139 0
      std/php/Session.hx
  44. 86 0
      std/php/Sys.hx
  45. 87 0
      std/php/Utf8.hx
  46. 333 0
      std/php/Web.hx
  47. 38 0
      std/php/db/Connection.hx
  48. 158 0
      std/php/db/DBase.hx
  49. 492 0
      std/php/db/Manager.hx
  50. 153 0
      std/php/db/Mysql.hx
  51. 89 0
      std/php/db/Object.hx
  52. 40 0
      std/php/db/ResultSet.hx
  53. 172 0
      std/php/db/Sqlite.hx
  54. 86 0
      std/php/io/File.hx
  55. 77 0
      std/php/io/FileInput.hx
  56. 82 0
      std/php/io/FileOutput.hx
  57. 87 0
      std/php/io/Path.hx
  58. 108 0
      std/php/io/Process.hx
  59. 59 0
      std/php/net/Host.hx
  60. 167 0
      std/php/net/Socket.hx
  61. 62 0
      std/php/net/SocketInput.hx
  62. 57 0
      std/php/net/SocketOutput.hx
  63. 5 1
      tests/unit/Test.hx
  64. 2 2
      tests/unit/TestIO.hx
  65. 11 2
      tests/unit/TestRemoting.hx
  66. 1 1
      tests/unit/TestResource.hx
  67. 98 88
      tests/unit/unit.html
  68. 8 0
      tests/unit/unit.hxp

+ 1 - 1
codegen.ml

@@ -532,7 +532,7 @@ let block_vars ctx e =
 			map_expr out_loop e
 	in
 	match ctx.platform with
-	| Neko | Cross -> e
+	| Neko | Php | Cross -> e
 	| _ -> out_loop e
 
 (* -------------------------------------------------------------------------- *)

+ 2 - 0
common.ml

@@ -64,6 +64,7 @@ type context = {
 	mutable flash_version : int;
 	mutable types : Type.module_type list;
 	mutable resources : (string,string) Hashtbl.t;
+	mutable php_front : string option;
 	(* typing *)
 	mutable type_api : context_type_api;
 }
@@ -84,6 +85,7 @@ let create() =
 		types = [];
 		flash_version = 8;
 		resources = Hashtbl.create 0;
+		php_front = None;
 		warning = (fun _ _ -> assert false);
 		error = (fun _ _ -> assert false);
 		type_api = {

+ 1990 - 0
genphp.ml

@@ -0,0 +1,1990 @@
+(*
+ *  haXe/PHP Compiler
+ *  Copyright (c)2008 Franco Ponticelli
+ *  based on and including code by (c)2005-2008 Nicolas Cannasse
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *)
+open Type
+open Common
+
+type method_name = {
+	mutable mpath : path;
+	mutable mname : string;
+}
+
+type context = {
+	com : Common.context;
+	ch : out_channel;
+	buf : Buffer.t;
+	path : path;
+	mutable get_sets : (string * bool,string) Hashtbl.t;
+	mutable curclass : tclass;
+	mutable tabs : string;
+	mutable in_value : string option;
+	mutable in_static : bool;
+	mutable handle_break : bool;
+	mutable imports : (string,string list list) Hashtbl.t;
+(*	mutable required_paths : (string list * string) list;  *)
+	mutable locals : (string,string) PMap.t;
+	mutable inv_locals : (string,string) PMap.t;
+	mutable local_types : t list;
+	mutable inits : texpr list;
+	mutable constructor_block : bool;
+	mutable quotes : int;
+	mutable all_dynamic_methods: method_name list;
+	mutable dynamic_methods: tclass_field list;
+	mutable is_call : bool;
+	mutable cwd : string;
+}
+
+let rec escphp n =
+	if n = 0 then "" else if n = 1 then "\\" else ("\\\\" ^ escphp (n-1))
+
+let inc_path ctx path =
+	let rec slashes n =
+		if n = 0 then "" else ("../" ^ slashes (n-1))
+	in
+	let pre = if ctx.cwd = "" then "lib/" else "" in
+	match path with
+		| ([],name) ->
+		pre ^ (slashes (List.length (fst ctx.path))) ^ name ^ ".php"
+		| (pack,name) ->
+		pre ^ (slashes (List.length (fst ctx.path))) ^ String.concat "/" pack ^ "/" ^ name ^ ".php"
+
+(*
+let rec register_required_path ctx path = match path with
+	| [], "Float"
+	| [], "Int"
+	| [], "Array"
+	| [], "Void"
+	| [], "Class"
+	| [], "Enum"
+	| [], "Dynamic"
+	| ["php"], "PhpMath__"
+	| ["php"], "PhpDate__"
+	| ["php"], "PhpXml__"
+	| ["php"], "HException"
+	| [], "String"
+	| [], "Bool" -> ()
+	| _, _ -> if not (List.exists(fun p -> p = path) ctx.required_paths) then
+		ctx.required_paths <- path :: ctx.required_paths
+*)
+
+let s_expr_expr e =
+	match e.eexpr with
+	| TConst _ -> "TConst"
+	| TLocal _ -> "TLocal"
+	| TEnumField _ -> "TEnumField"
+	| TArray (_,_) -> "TArray"
+	| TBinop (_,_,_) -> "TBinop"
+	| TField (_,_) -> "TField"
+	| TTypeExpr _ -> "TTypeExpr"
+	| TParenthesis _ -> "TParenthesis"
+	| TObjectDecl _ -> "TObjectDecl"
+	| TArrayDecl _ -> "TArrayDecl"
+	| TCall (_,_) -> "TCall"
+	| TNew (_,_,_) -> "TNew"
+	| TUnop (_,_,_) -> "TUnop"
+	| TFunction _ -> "TFunction"
+	| TVars _ -> "TVars"
+	| TBlock _ -> "TBlock"
+	| TFor (_,_,_,_) -> "TFor"
+	| TIf (_,_,_) -> "TIf"
+	| TWhile (_,_,_) -> "TWhile"
+	| TSwitch (_,_,_) -> "TSwitch"
+	| TMatch (_,_,_,_) -> "TMatch"
+	| TTry (_,_) -> "TTry"
+	| TReturn _ -> "TReturn"
+	| TBreak -> "TBreak"
+	| TContinue -> "TContinue"
+	| TThrow _ -> "TThrow"
+
+let s_expr_name e =
+	s_type (print_context()) e.etype
+
+let s_type_name t =
+	s_type (print_context()) t
+
+let rec is_uncertain_type t =
+	match follow t with
+	| TInst (c, _) -> c.cl_interface
+	| TMono _ -> true
+	| TAnon a ->
+	  (match !(a.a_status) with
+	  | Statics _
+	  | EnumStatics _ -> false
+	  | _ -> true)
+	| TDynamic _ -> true
+	| _ -> false
+  
+let is_uncertain_expr e =
+	is_uncertain_type e.etype
+
+let rec is_anonym_type t =
+	match follow t with
+	| TAnon a ->
+	  (match !(a.a_status) with
+	  | Statics _
+	  | EnumStatics _ -> false
+	  | _ -> true)
+	| TDynamic _ -> true
+	| _ -> false
+	
+let is_anonym_expr e = is_anonym_type e.etype
+
+let rec is_unknown_type t =
+	match follow t with
+	| TMono r ->
+		(match !r with
+		| None -> true
+		| Some t -> is_unknown_type t)
+	| _ -> false
+
+let is_unknown_expr e =	is_unknown_type e.etype
+
+let rec is_array_type t =
+	match follow t with
+	| TInst ({cl_path = ([], "Array")}, _) -> true
+	| TAnon a ->
+	   (match !(a.a_status) with 
+	   | Statics ({cl_path = ([], "Array")}) -> true
+	   | _ -> false)
+	| _ -> false
+
+let is_array_expr e =  is_array_type e.etype
+
+
+let rec is_array_ref e =
+	match e.eexpr with
+	| TNew (c,_,_) when c.cl_path = ([], "Array") -> false
+	| TArrayDecl _
+	| TIf (_,_,_) 
+	| TConst _ -> false
+	| TParenthesis e -> is_array_ref e
+	| _ -> is_array_expr e
+(*
+	let s = s_expr_name e in
+	if (String.length s > 11 && String.sub s 0 12 = "#Null<Array<") || (String.length s > 10 && String.sub s 0 11 = "Null<Array<") || (String.length s > 6 && String.sub s 0 7 = "#Array<") || (String.length s > 5 && String.sub s 0 6 = "Array<") then true else false
+*)
+
+let rec is_string_type t =
+	match follow t with
+	| TInst ({cl_path = ([], "String")}, _) -> true
+	| TAnon a ->
+	   (match !(a.a_status) with 
+	   | Statics ({cl_path = ([], "String")}) -> true
+	   | _ -> false)
+	| _ -> false
+
+let is_string_expr e = is_string_type e.etype (* match follow e.etype with TInst ({ cl_path = [],"String" },_) -> true | _ -> false *)
+(*
+	let s = s_expr_name e in
+	if s = "#Null<String>" || s = "Null<String>" || s = "#String" || s = "String" then true else false
+*)
+
+let spr ctx s = Buffer.add_string ctx.buf s
+let print ctx = Printf.kprintf (fun s -> Buffer.add_string ctx.buf s)
+
+let s_path ctx path isextern p =
+	if isextern then 
+		snd path
+	else begin
+(*		register_required_path ctx path; *)
+		(match path with
+		| ([],"List")			-> "HList"
+		| ([],name)				-> name
+		| (["php"],"PhpXml__")	-> "Xml"
+		| (["php"],"PhpDate__")	-> "Date"
+		| (["php"],"PhpMath__")	-> "Math"
+		| (pack,name) ->
+			try
+				(match Hashtbl.find ctx.imports name with
+				| [p] when p = pack ->
+					String.concat "_" pack ^ "_" ^ name
+				| packs ->
+					if not (List.mem pack packs) then Hashtbl.replace ctx.imports name (pack :: packs);
+					Ast.s_type_path path)
+			with Not_found ->
+				Hashtbl.add ctx.imports name [pack];
+				String.concat "_" pack ^ "_" ^ name);
+	end
+
+let s_path_haxe path =
+	match fst path, snd path with
+	| [], s -> s
+	| el, s -> String.concat "." el ^ "." ^ s
+	
+let s_ident n =
+	let suf = "h" in
+(*
+haxe reserved words that match php ones: break, case, class, continue, default, do, else, extends, for, function, if, new, return, static, switch, var, while, interface, implements, public, private, try, catch, throw
+ *)
+(* PHP only (for future use): cfunction, old_function *)
+	match n with
+	| "and" | "or" | "xor" | "__FILE__" | "exception" (* PHP 5 *) | "__LINE__" | "array"
+	| "as" | "const" | "declare" | "die" | "echo"| "elseif" | "empty"
+	| "enddeclare" | "endfor" | "endforeach" | "endif" | "endswitch"
+	| "endwhile" | "eval" | "exit" | "foreach"| "global" | "include"
+	| "include_once" | "isset" | "list" | "print" | "require" | "require_once"
+	| "unset" | "use" | "__FUNCTION__" | "__CLASS__" | "__METHOD__" | "final" (* PHP 5 *)
+	| "php_user_filter" (* PHP 5 *) | "protected" (* PHP 5 *) | "abstract" (* PHP 5 *)
+	| "clone" (* PHP 5 *) -> suf ^ n
+	| _ -> n
+
+let write_resource dir name data =
+	let i = ref 0 in
+	String.iter (fun c -> 
+		if c = '\\' || c = '/' || c = ':' || c = '*' || c = '?' || c = '"' || c = '<' || c = '>' || c = '|' then String.blit "_" 0 name !i 1;
+		incr i
+	) name;
+	let rdir = dir ^ "/res" in
+	if not (Sys.file_exists dir) then Unix.mkdir dir 0o755;
+	if not (Sys.file_exists rdir) then Unix.mkdir rdir 0o755;
+	let ch = open_out (rdir ^ "/" ^ name) in
+	output_string ch data;
+	close_out ch
+	
+let init com cwd path def_type =
+	let rec create acc = function
+		| [] -> ()
+		| d :: l ->
+			let pdir = String.concat "/" (List.rev (d :: acc)) in
+			if not (Sys.file_exists pdir) then Unix.mkdir pdir 0o755;
+			create (d :: acc) l
+	in
+	let dir = if cwd <> "" then com.file :: (cwd :: fst path) else com.file :: fst path; in
+	create [] dir;
+	let filename path = 
+		(match snd path with
+		| "List" -> "HList";
+		| s -> s) in
+	let ch = open_out (String.concat "/" dir ^ "/" ^ (filename path) ^ (if def_type = 0 then ".class" else if def_type = 1 then ".enum" else ".interface") ^ ".php") in
+	let imports = Hashtbl.create 0 in
+	Hashtbl.add imports (snd path) [fst path];
+	{
+		com = com;
+		tabs = "";
+		ch = ch;
+		path = path;
+		buf = Buffer.create (1 lsl 14);
+		in_value = None;
+		in_static = false;
+		handle_break = false;
+		imports = imports;
+		curclass = null_class;
+		locals = PMap.empty;
+		inv_locals = PMap.empty;
+		local_types = [];
+(*		required_paths = []; *)
+		inits = [];
+		get_sets = Hashtbl.create 0;
+		constructor_block = false;
+		quotes = 0;
+		dynamic_methods = [];
+		all_dynamic_methods = [];
+		is_call = false;
+		cwd = cwd;
+	}
+
+let unsupported p = error "This expression cannot be generated to PHP" p
+
+let newline ctx =
+	match Buffer.nth ctx.buf (Buffer.length ctx.buf - 1) with
+	| '}' | '{' | ':' -> print ctx "\n%s" ctx.tabs
+	| _ -> print ctx ";\n%s" ctx.tabs
+
+let rec concat ctx s f = function
+	| [] -> ()
+	| [x] -> f x
+	| x :: l ->
+		f x;
+		spr ctx s;
+		concat ctx s f l
+
+let open_block ctx =
+	let oldt = ctx.tabs in
+	ctx.tabs <- "\t" ^ ctx.tabs;
+	(fun() -> ctx.tabs <- oldt)
+
+let parent e =
+	match e.eexpr with
+	| TParenthesis _ -> e
+	| _ -> mk (TParenthesis e) e.etype e.epos
+
+let close ctx =
+	output_string ctx.ch "<?php\n";
+(*
+	Hashtbl.iter (fun name paths ->
+		List.iter (fun pack ->
+			let path = pack, name in
+			register_required_path ctx path
+		) paths
+	) ctx.imports;
+*)
+(*
+	List.iter (fun path ->
+		if path <> ctx.path then output_string ctx.ch ("// require_once dirname(__FILE__).'/" ^ inc_path ctx path ^ "';\n");
+	) (List.rev ctx.required_paths);
+*)
+	output_string ctx.ch "\n";
+	output_string ctx.ch (Buffer.contents ctx.buf);
+	close_out ctx.ch
+
+let save_locals ctx =
+	let old = ctx.locals in
+	(fun() -> ctx.locals <- old)
+
+let define_local ctx l =
+	let rec loop n =
+	let name = (if n = 1 then s_ident l else l ^ string_of_int n) in
+	if PMap.mem name ctx.inv_locals then
+		loop (n+1)
+	else begin
+		ctx.locals <- PMap.add l name ctx.locals;
+		ctx.inv_locals <- PMap.add name l ctx.inv_locals;
+		name
+	end
+	in
+	loop 1
+
+let rec iter_switch_break in_switch e =
+	match e.eexpr with
+	| TFunction _ | TWhile _ | TFor _ -> ()
+	| TSwitch _ | TMatch _ when not in_switch -> iter_switch_break true e
+	| TBreak when in_switch -> raise Exit
+	| _ -> iter (iter_switch_break in_switch) e
+
+let handle_break ctx e =
+	let old_handle = ctx.handle_break in
+	try
+		iter_switch_break false e;
+		ctx.handle_break <- false;
+		(fun() -> ctx.handle_break <- old_handle)
+	with
+		Exit ->
+			spr ctx "try {";
+			let b = open_block ctx in
+			newline ctx;
+			ctx.handle_break <- true;
+			(fun() ->
+				b();
+				ctx.handle_break <- old_handle;
+				newline ctx;
+				let p = escphp ctx.quotes in
+				print ctx "} catch(Exception %s$e) { if( %s$e->getMessage() != \"__break__\" ) throw %s$e; }" p p p;
+			)
+
+let this ctx =
+	let p = escphp ctx.quotes in
+	if ctx.in_value <> None then (p ^ "$__this") else (p ^ "$this")
+	
+let escape_bin s quotes =
+	let b = Buffer.create 0 in
+	for i = 0 to String.length s - 1 do
+		match Char.code (String.unsafe_get s i) with
+		| c when c < 32 -> Buffer.add_string b (Printf.sprintf "\\x%.2X" c)
+		| c when c = Char.code('$') ->
+			Buffer.add_string b (escphp quotes);
+			Buffer.add_char b (Char.chr c)
+		| c -> Buffer.add_char b (Char.chr c)
+	done;
+	Buffer.contents b
+
+let gen_constant ctx p = function
+	| TInt i -> print ctx "%ld" i
+	| TFloat s -> spr ctx s
+	| TString s -> 
+		print ctx "%s\"%s%s\"" (escphp ctx.quotes) (escape_bin (Ast.s_escape s) (ctx.quotes+1)) (escphp ctx.quotes)
+	| TBool b -> spr ctx (if b then "true" else "false")
+	| TNull -> spr ctx "null"
+	| TThis -> spr ctx (this ctx)
+	| TSuper -> spr ctx "ERROR /* unexpected call to super in gen_constant */"
+	
+let s_funarg ctx arg t p c = 
+(*
+	let arg_default p c =
+		match c with
+		| None | Some TNull -> e
+		| Some c -> Codegen.concat (Codegen.set_default ctx.com arg c t p) e in
+		(*
+		match c with
+		| None -> ()
+		| Some c -> 
+			spr ctx " = ";
+			gen_constant ctx p c in*) *)
+	let byref = if is_array_type t || (String.length arg > 7 && String.sub arg 0 7 = "byref__") then "&" else "" in
+	(match t with
+	| TInst (cl,_) -> 
+		(match cl.cl_path with
+		| ([], "Float")
+		| ([], "String")
+		| ([], "Array")
+		| ([], "Int") 
+		| ([], "Enum") 
+		| ([], "Class") 
+		| ([], "Bool") -> 
+			print ctx "%s%s$%s" byref (escphp ctx.quotes) arg;
+			
+(*			arg_default p c *)
+			
+(*			if o then spr ctx " = null" *)
+		| _ ->
+			if cl.cl_kind = KNormal && not cl.cl_extern then
+				print ctx "/*%s*/ %s%s$%s" (s_path ctx cl.cl_path cl.cl_extern p) byref (escphp ctx.quotes) arg
+				(* was: print ctx "%s %s%s$%s = null" (s_path ctx c.cl_path c.cl_extern p) byref (escphp ctx.quotes) arg *)
+			else begin
+				print ctx "%s%s$%s" byref (escphp ctx.quotes) arg;
+
+(*				arg_default p c *)
+				
+(*				if o then spr ctx " = null" *)
+			end)
+	| _ -> 
+		print ctx "%s%s$%s" byref (escphp ctx.quotes) arg;
+(*		arg_default p c *)
+	)
+
+let is_in_dynamic_methods ctx e s =
+	List.exists (fun dm ->
+		(* TODO: I agree, this is a mess ... but after hours of trials and errors I gave up; maybe in a calmer day *)
+		((String.concat "." ((fst dm.mpath) @ ["#" ^ (snd dm.mpath)])) ^ "." ^ dm.mname) = (s_type_name e.etype ^ "." ^ s)
+	) ctx.all_dynamic_methods
+
+let is_dynamic_method f =
+	match follow f.cf_type with
+	| TFun _ when f.cf_expr = None -> true
+	| _ ->
+		(match f.cf_expr with
+		| Some { eexpr = TFunction fd } -> f.cf_set = NormalAccess
+		| _ -> false)
+		
+let fun_block ctx f p =
+	let e = (match f.tf_expr with { eexpr = TBlock [{ eexpr = TBlock _ } as e] } -> e | e -> e) in
+	let e = List.fold_left (fun e (a,c,t) ->
+		match c with
+		| None | Some TNull -> e
+		| Some c -> Codegen.concat (Codegen.set_default ctx.com a c t p) e
+	) e f.tf_args in
+	(*
+	if ctx.com.debug then
+		Codegen.stack_block ctx.stack ctx.current (fst ctx.curmethod) e
+	else *)
+		mk_block e
+
+let gen_function_header ctx name f params p =
+	let old = ctx.in_value in
+	let old_l = ctx.locals in
+	let old_li = ctx.inv_locals in
+	let old_t = ctx.local_types in
+	ctx.in_value <- None;
+	ctx.local_types <- List.map snd params @ ctx.local_types;
+	(match name with
+	| None ->
+		spr ctx "create_function('";
+		concat ctx ", " (fun (arg,o,t) ->
+		let arg = define_local ctx arg in
+			s_funarg ctx arg t p o;
+		) f.tf_args;
+		print ctx "', '') "
+	| Some n ->
+		let byref = if is_array_expr f.tf_expr || (String.length n > 9 && String.sub n 0 9 = "__byref__") then "&" else "" in
+		print ctx "function %s%s(" byref n;
+		concat ctx ", " (fun (arg,o,t) ->
+		let arg = define_local ctx arg in
+			s_funarg ctx arg t p o;
+		) f.tf_args;
+		print ctx ") ");
+	(fun () ->
+		ctx.in_value <- old;
+		ctx.locals <- old_l;
+		ctx.inv_locals <- old_li;
+		ctx.local_types <- old_t;
+	)
+
+let rec gen_call ctx e el =
+	match e.eexpr , el with
+	| TConst TSuper , params ->
+		(match ctx.curclass.cl_super with
+		| None -> assert false
+		| Some (c,_) ->
+			spr ctx "parent::__construct(";
+			concat ctx "," (gen_call_value ctx) params;
+			spr ctx ")";
+		);
+	| TField ({ eexpr = TConst TSuper },name) , params ->
+		(match ctx.curclass.cl_super with
+		| None -> assert false
+		| Some (c,_) ->
+			print ctx "parent::%s(" (name);
+			concat ctx "," (gen_call_value ctx) params;
+			spr ctx ")";
+		);
+	| TLocal "__set__" , { eexpr = TConst (TString code) } :: [] ->
+		unsupported e.epos;
+	| TLocal "__set__" , { eexpr = TConst (TString code) } :: [el] ->
+		print ctx "%s$%s = " (escphp ctx.quotes) code;
+		gen_value ctx el;
+	| TLocal "__set__" , { eexpr = TConst (TString code) } :: el ->
+		let rec genargs lst =
+			(match lst with
+			| [] -> ()
+			| h :: [t] -> 
+				gen_value ctx h;
+				spr ctx "] = ";
+				gen_value ctx t
+			| h :: t -> 
+				gen_value ctx h;
+				spr ctx "][";
+				genargs t)
+		in
+		print ctx "%s$%s[" (escphp ctx.quotes) code;
+		genargs el;
+	| TLocal "__var__" , { eexpr = TConst (TString code) } :: [] ->
+		print ctx "%s$%s" (escphp ctx.quotes) code;
+	| TLocal "__var__" , { eexpr = TConst (TString code) } :: el ->
+		print ctx "%s$%s[" (escphp ctx.quotes) code;
+		concat ctx "][" (gen_value ctx) el;
+		spr ctx "]";
+	| TLocal "__call__" , { eexpr = TConst (TString code) } :: el ->
+		spr ctx code;
+		spr ctx "(";
+		concat ctx ", " (gen_value ctx) el;
+		spr ctx ")";
+	| TLocal "__php__", [{ eexpr = TConst (TString code) }] ->
+		spr ctx code
+	| TLocal "__physeq__" ,  [e1;e2] ->
+		gen_value ctx e1;
+		spr ctx " === ";
+		gen_value ctx e2
+	| TLocal _, el
+	| TFunction _, el ->
+		ctx.is_call <- true;
+		spr ctx "call_user_func_array(";
+		gen_value ctx e;
+		ctx.is_call <- false;
+		spr ctx ", array(";
+		concat ctx ", " (gen_call_ref ctx) el;
+		spr ctx "))"	
+	| TCall (x,_), el when (match x.eexpr with | TLocal _ -> false | _ -> true) ->
+		ctx.is_call <- true;
+		spr ctx "call_user_func_array(";
+		gen_value ctx e;
+		ctx.is_call <- false;
+		spr ctx ", array(";
+		concat ctx ", " (gen_call_ref ctx) el;
+		spr ctx "))"	
+	| _ ->
+		ctx.is_call <- true;
+		gen_value ctx e;
+		ctx.is_call <- false;
+		spr ctx "(";
+		concat ctx ", " (gen_call_value ctx) el;
+		spr ctx ")";
+		
+and gen_call_value ctx e =
+	match e.eexpr with
+	| TConst TNull -> spr ctx "php_Boot::__array_null()";
+	| _ -> gen_value ctx e
+	
+and gen_call_ref ctx e =
+	if is_array_ref e then spr ctx "&";
+	gen_call_value ctx e
+
+and could_be_string_or_array_var s =
+	s = "length"
+		
+and gen_uncertain_string_or_array_var ctx s e =
+	match s with
+	| "length" ->
+		spr ctx "php_Boot::__len(";
+		gen_value ctx e;
+		spr ctx ")"
+	| _ ->
+		gen_field_access ctx true e s;
+		
+and gen_string_var ctx s e =
+	match s with
+	| "length" ->
+		spr ctx "strlen(";
+		gen_value ctx e;
+		spr ctx ")"
+	| _ ->
+		unsupported e.epos;
+
+and gen_array_var ctx s e =
+	match s with
+	| "length" ->
+		spr ctx "count(";
+		gen_value ctx e;
+		spr ctx ")"
+	| _ ->
+		unsupported e.epos;
+
+and gen_string_static_call ctx s e el =
+	match s with
+	| "fromCharCode" ->
+		spr ctx "chr(";
+		concat ctx ", " (gen_value ctx) el;
+		spr ctx ")";
+	| _ -> unsupported e.epos;
+
+and could_be_string_or_array_call s =
+	s = "toString"
+	
+and could_be_string_call s =
+	s = "substr" || s = "charAt" || s = "charCodeAt" || s = "indexOf" || 
+	s = "lastIndexOf" || s = "split" || s = "toLowerCase" || s = "toUpperCase"
+	
+and gen_string_call ctx s e el =
+	match s with
+	| "substr" ->
+		spr ctx "php_Boot::__substr(";
+		gen_value ctx e;
+		spr ctx ", ";
+		concat ctx ", " (gen_value ctx) el;
+		spr ctx ")"
+	| "charAt" ->
+		spr ctx "substr(";
+		gen_value ctx e;
+		spr ctx ", ";
+		concat ctx ", " (gen_value ctx) el;
+		spr ctx ", 1)"
+	| "cca" ->
+		spr ctx "ord(";
+		gen_value ctx e;
+		spr ctx "{";
+		concat ctx ", " (gen_value ctx) el;
+		spr ctx "})"
+	| "charCodeAt" ->
+		spr ctx "php_Boot::__char_code_at(";
+		gen_value ctx e;
+		spr ctx ", ";
+		concat ctx ", " (gen_value ctx) el;
+		spr ctx ")"
+	| "indexOf" ->
+		spr ctx "php_Boot::__index_of(";
+		gen_value ctx e;
+		spr ctx ", ";
+		concat ctx ", " (gen_value ctx) el;
+		spr ctx ")"
+	| "lastIndexOf" ->
+		spr ctx "php_Boot::__last_index_of(";
+		gen_value ctx e;
+		spr ctx ", ";
+		concat ctx ", " (gen_value ctx) el;
+		spr ctx ")"
+	| "split" ->
+		spr ctx "explode(";
+		concat ctx ", " (gen_value ctx) el;
+		spr ctx ", ";
+		gen_value ctx e;
+		spr ctx ")"
+	| "toLowerCase" ->
+		spr ctx "strtolower(";
+		gen_value ctx e;
+		spr ctx ")"
+	| "toUpperCase" ->
+		spr ctx "strtoupper(";
+		gen_value ctx e;
+		spr ctx ")"
+	| "toString" ->
+		gen_value ctx e;
+	| _ ->
+		unsupported e.epos;
+
+and could_be_array_call s =
+	s = "push" || s = "concat" || s = "join" || s = "pop" || s = "reverse" || 
+	s = "shift" || s = "slice" || s = "sort" || s = "splice" ||
+	s = "copy" || s = "unshift" || s = "insert" || s = "remove" || s = "iterator"
+
+and gen_uncertain_string_or_array_call ctx s e el =
+(* only toString so far *)
+	spr ctx "php_Boot::__string_rec(";
+	gen_value ctx e;
+	print ctx ")"
+	
+and gen_uncertain_string_call ctx s e el =
+	let p = escphp ctx.quotes in
+	spr ctx "php_Boot::__string_call(";
+	gen_value ctx e;
+	print ctx ", %s\"%s%s\", array(" p s p;
+	concat ctx ", " (gen_value ctx) el;
+	spr ctx "))"
+	
+and gen_uncertain_array_call ctx s e el =
+	let p = escphp ctx.quotes in
+	spr ctx "php_Boot::__array_call(";
+	gen_value ctx e;
+	print ctx ", %s\"%s%s\", array(" p s p;
+	concat ctx ", " (gen_value ctx) el;
+	spr ctx "))"
+	
+and gen_array_call ctx s e el =
+	match s with
+	| "push" ->
+		spr ctx "array_push(";
+		gen_value ctx e;
+		spr ctx ", ";
+		concat ctx ", " (gen_value ctx) el;
+		spr ctx ")"
+	| "concat" ->
+		spr ctx "array_merge(";
+		gen_value ctx e;
+		spr ctx ", ";
+		concat ctx ", " (gen_value ctx) el;
+		spr ctx ")"
+	| "join" ->
+		spr ctx "join(";
+		concat ctx ", " (gen_value ctx) el;
+		spr ctx ", ";
+		gen_value ctx e;
+		spr ctx ")"
+	| "pop" ->
+		spr ctx "array_pop(";
+		gen_value ctx e;
+		spr ctx ")"
+	| "reverse" ->
+		spr ctx "rsort(";
+		gen_value ctx e;
+		spr ctx ")"
+	| "shift" ->
+		spr ctx "array_shift(";
+		gen_value ctx e;
+		spr ctx ")"
+	| "slice" ->
+		spr ctx "php_Boot::__array_slice(";
+		gen_value ctx e;
+		spr ctx ", ";
+		concat ctx ", " (gen_value ctx) el;
+		spr ctx ")"
+	| "sort" ->
+		spr ctx "php_Boot::__array_sort(";
+		gen_value ctx e;
+		spr ctx ", ";
+		concat ctx ", " (gen_value ctx) el;
+		spr ctx ")"
+	| "splice" ->
+		spr ctx "php_Boot::__array_splice(";
+		gen_value ctx e;
+		spr ctx ", ";
+		concat ctx ", " (gen_value ctx) el;
+		spr ctx ")"
+	| "toString" ->
+		spr ctx "'['.join(', ', ";
+		gen_value ctx e;
+		spr ctx ").']'"
+	| "copy" ->
+		spr ctx "php_Boot::__array_copy(";
+		gen_value ctx e;
+		spr ctx ")"
+	| "unshift" ->
+		spr ctx "array_unshift(";
+		gen_value ctx e;
+		spr ctx ", ";
+		concat ctx ", " (gen_value ctx) el;
+		spr ctx ")"
+	| "insert" ->
+		spr ctx "php_Boot::__array_insert(";
+		gen_value ctx e;
+		spr ctx ", ";
+		concat ctx ", " (gen_value ctx) el;
+		spr ctx ")"
+	| "remove" ->
+		spr ctx "php_Boot::__array_remove(";
+		gen_value ctx e;
+		spr ctx ", ";
+		concat ctx ", " (gen_value ctx) el;
+		spr ctx ")"
+	| "iterator" ->
+		spr ctx "new HArrayIterator(";
+		gen_value ctx e;
+		spr ctx ")"
+	| _ ->
+		unsupported e.epos;
+	
+and gen_field_op ctx e = 
+	match e.eexpr with
+	| TField (f,s) ->
+		(match follow e.etype with
+		| TFun _ ->
+			gen_field_access ctx true f s
+		| _ ->
+			gen_value_op ctx e)
+	| _ ->
+		gen_value_op ctx e
+
+and gen_value_op ctx e =
+	match e.eexpr with
+	| TBinop (op,_,_) when op = Ast.OpAnd || op = Ast.OpOr || op = Ast.OpXor ->
+		spr ctx "(";
+		gen_value ctx e;
+		spr ctx ")";
+	| _ ->
+		gen_value ctx e
+
+and is_static t =
+	match follow t with
+	| TAnon a -> (match !(a.a_status) with
+		| Statics c -> true
+		| _ -> false)
+	| _ -> false
+
+and gen_member_access ctx isvar e s =
+	match follow e.etype with
+	| TAnon a -> 
+		(match !(a.a_status) with
+		| EnumStatics _
+		| Statics _ -> print ctx "::%s%s" (if isvar then ((escphp ctx.quotes) ^ "$") else "") (s_ident s)
+		| _ -> print ctx "->%s" (s_ident s))
+	| _ -> print ctx "->%s" (s_ident s)
+	
+(*
+let isunc = is_uncertain_expr e1 in
+if isunc then print ctx "/* %s */" (s_type_name (follow e1.etype));
+*)
+and gen_field_access ctx isvar e s =
+	match e.eexpr with
+	| TTypeExpr t ->
+		spr ctx (s_path ctx (t_path t) false e.epos);
+		gen_member_access ctx isvar e s
+	| TLocal _ ->
+		gen_expr ctx e;
+		print ctx "->%s" (s_ident s)
+	| TArray (e1,e2) ->
+		spr ctx "php_Boot::__byref__array_get(";
+		gen_value ctx e1;
+		spr ctx ", ";
+		gen_value ctx e2;
+		spr ctx ")";
+		gen_member_access ctx isvar e s
+	| TBlock _
+	| TParenthesis _
+	| TNew _ ->
+		spr ctx "php_Boot::__deref(";
+		ctx.is_call <- true;
+		gen_value ctx e;
+		ctx.is_call <- false;
+		spr ctx ")";
+		gen_member_access ctx isvar e s
+	| _ -> 
+		gen_expr ctx e;
+		gen_member_access ctx isvar e s
+
+and gen_dynamic_function ctx isstatic name f params p =
+	let old = ctx.in_value in
+	let old_l = ctx.locals in
+	let old_li = ctx.inv_locals in
+	let old_t = ctx.local_types in
+	ctx.in_value <- None;
+	ctx.local_types <- List.map snd params @ ctx.local_types;
+	let byref = if is_array_expr f.tf_expr || (String.length name > 9 && String.sub name 0 9 = "__byref__") then "&" else "" in
+	print ctx "function %s%s(" byref name;
+	concat ctx ", " (fun (arg,o,t) ->
+	let arg = define_local ctx arg in
+		s_funarg ctx arg t p o;
+		) f.tf_args;
+	spr ctx ") {";
+	
+	(* TODO: check me *)
+(*	gen_expr ctx (fun_block ctx f e.epos); *)
+
+	if (List.length f.tf_args) > 0 then begin
+		if isstatic then
+			print ctx " return call_user_func_array(self::$%s, array("  name
+		else
+			print ctx " return call_user_func_array($this->%s, array("  name;
+		concat ctx ", " (fun (arg,o,t) ->
+			if is_array_type t then spr ctx "&";
+			spr ctx ((escphp ctx.quotes) ^ "$" ^ arg)
+		) f.tf_args;
+		print ctx ")); }";
+	end else if isstatic then
+		print ctx " return call_user_func(self::$%s); }"  name
+	else
+		print ctx " return call_user_func($this->%s); }"  name;
+
+	newline ctx;
+	if isstatic then
+		print ctx "public static $%s = null" name
+	else
+		print ctx "public $%s = null" name;
+	ctx.in_value <- old;
+	ctx.locals <- old_l;
+	ctx.inv_locals <- old_li;
+	ctx.local_types <- old_t
+
+and gen_function ctx name f params p =
+	let old = ctx.in_value in
+	let old_l = ctx.locals in
+	let old_li = ctx.inv_locals in
+	let old_t = ctx.local_types in
+	ctx.in_value <- None;
+	ctx.local_types <- List.map snd params @ ctx.local_types;
+	let byref = if is_array_type f.tf_type || (String.length name > 9 && String.sub name 0 9 = "__byref__") then "&" else "" in
+	print ctx "function %s%s(" byref name;
+	concat ctx ", " (fun (arg,o,t) ->
+		let arg = define_local ctx arg in
+		s_funarg ctx arg t p o;
+	) f.tf_args;
+	print ctx ") ";
+	
+	
+	(* TODO: check me *)
+	gen_expr ctx (fun_block ctx f p);
+	
+	
+(*	gen_expr ctx (mk_block f.tf_expr); *)
+	ctx.in_value <- old;
+	ctx.locals <- old_l;
+	ctx.inv_locals <- old_li;
+	ctx.local_types <- old_t
+
+and gen_inline_function ctx f params p =
+	let old = ctx.in_value in
+	let old_l = ctx.locals in
+	let old_li = ctx.inv_locals in
+	let old_t = ctx.local_types in
+	ctx.in_value <- Some "closure";
+	ctx.local_types <- List.map snd params @ ctx.local_types;
+	spr ctx "php_Boot::__closure(array(";
+
+	let pq = escphp ctx.quotes in
+	let c = ref 0 in
+	
+	PMap.iter (fun n _ ->
+		if !c > 0 then spr ctx ", ";
+		incr c;
+		print ctx "%s\"%s%s\" => &%s$%s" pq n pq pq n;
+	) old_li;
+	(*
+	PMap.iter (fun n _ ->
+		if not (PMap.exists n old_l) then begin
+		if !c > 0 then spr ctx ", ";
+		incr c;
+		print ctx "%s\"%s%s\" => &%s$%s" pq n pq pq n;
+		end
+	) old_li;
+*)
+	print ctx "), %s\"" pq;
+	ctx.quotes <- ctx.quotes + 1;
+	concat ctx "," (fun (arg,o,t) ->
+		let arg = define_local ctx arg in
+		s_funarg ctx arg t p o;
+	) f.tf_args;
+	ctx.quotes <- ctx.quotes - 1;
+	print ctx "%s\", %s\"" pq pq;
+	ctx.quotes <- ctx.quotes + 1;
+	(* TODO: check me *)
+	gen_expr ctx (fun_block ctx f p);
+(*	gen_expr ctx (mk_block f.tf_expr); *)
+	ctx.quotes <- ctx.quotes - 1;
+	print ctx "%s\")" pq;
+	ctx.in_value <- old;
+	ctx.locals <- old_l;
+	ctx.inv_locals <- old_li;
+	ctx.local_types <- old_t
+
+and gen_while_expr ctx e =
+	match e.eexpr with
+	| TBlock (el) ->
+		let old_l = ctx.inv_locals in
+		let b = save_locals ctx in
+		print ctx "{";
+		let bend = open_block ctx in
+		List.iter (fun e -> newline ctx; gen_expr ctx e) el;
+		newline ctx;		
+		let c = ref 0 in
+		PMap.iter (fun n _ ->
+		    if not (PMap.exists n old_l) then begin
+			if !c > 0 then spr ctx "; ";
+			incr c;
+			print ctx "unset(%s$%s)" (escphp ctx.quotes) n
+			end
+		) ctx.inv_locals;
+		bend();
+		newline ctx;
+		print ctx "}";
+		b();
+	| _ ->
+		gen_expr ctx e
+
+and gen_expr ctx e =
+	match e.eexpr with
+	| TConst c ->
+		gen_constant ctx e.epos c
+	| TLocal s ->
+		spr ctx ((escphp ctx.quotes) ^ "$" ^ (try PMap.find s ctx.locals with Not_found -> error ("Unknown local " ^ s) e.epos))
+	| TEnumField (en,s) ->
+(*		register_required_path ctx en.e_path; *)
+		(match (try PMap.find s en.e_constrs with Not_found -> error ("Unknown local " ^ s) e.epos).ef_type with
+		| TFun (args,_) -> print ctx "%s::%s" (s_path ctx en.e_path en.e_extern e.epos) (s_ident s)
+		| _ -> print ctx "%s::%s$%s" (s_path ctx en.e_path en.e_extern e.epos) (escphp ctx.quotes) (s_ident s))
+	| TArray (e1,e2) ->
+		(match e1.eexpr with
+		| TCall _ ->
+			spr ctx "php_Boot::__byref__array_get(";
+			gen_value ctx e1;
+			spr ctx ", ";
+			gen_value ctx e2;
+			spr ctx ")";
+		| _ ->
+			gen_value ctx e1;
+			spr ctx "[";
+			gen_value ctx e2;
+			spr ctx "]");
+	| TBinop (op,e1,e2) ->
+		(match op with
+		| Ast.OpAssign ->
+			(match e1.eexpr with
+			| TArray(te1, te2) ->
+				spr ctx "php_Boot::__array_set(";
+				gen_value ctx te1;
+				spr ctx ", ";
+				gen_value ctx te2;
+				spr ctx ", ";
+				gen_value ctx e2;
+				spr ctx ")";
+			| _ ->
+				gen_field_op ctx e1;
+				if is_array_ref e2 then
+					spr ctx " =& "
+				else
+					spr ctx " = ";
+				gen_value_op ctx e2;)
+		| Ast.OpAssignOp(Ast.OpAdd) when (is_string_expr e1 || is_string_expr e2) ->
+			gen_value_op ctx e1;
+			spr ctx " .= ";
+			if is_uncertain_expr e2 then begin
+				spr ctx "php_Boot::__string(";
+				gen_value_op ctx e2;
+				spr ctx ")";
+			end else
+				gen_value_op ctx e2;
+		| Ast.OpAdd when (is_string_expr e1 || is_string_expr e2) ->
+			if is_uncertain_expr e1 then begin
+				spr ctx "php_Boot::__string(";
+				gen_value_op ctx e1;
+				spr ctx ")";
+			end else 		
+				gen_value_op ctx e1;
+			spr ctx " . ";
+			if is_uncertain_expr e2 then begin
+				spr ctx "php_Boot::__string(";
+				gen_value_op ctx e2;
+				spr ctx ")";
+			end else 		
+				gen_value_op ctx e2;
+		| Ast.OpAssignOp(Ast.OpShl) ->
+			gen_value_op ctx e1;
+			spr ctx " <<= ";
+			gen_value_op ctx e2;
+		| Ast.OpShl ->
+			gen_value_op ctx e1;
+			spr ctx " << ";
+			gen_value_op ctx e2;
+		| Ast.OpAssignOp(Ast.OpUShr) ->
+			gen_value_op ctx e1;
+			spr ctx " = ";
+			spr ctx "php_Boot::__shift_right(";
+			gen_value_op ctx e1;
+			spr ctx ", ";
+			gen_value_op ctx e2;
+			spr ctx ")";
+		| Ast.OpUShr ->
+			spr ctx "php_Boot::__shift_right(";
+			gen_value_op ctx e1;
+			spr ctx ", ";
+			gen_value_op ctx e2;
+			spr ctx ")";
+		| Ast.OpNotEq
+		| Ast.OpEq ->
+			let s_op = if op = Ast.OpNotEq then " != " else " == " in
+			let s_phop = if op = Ast.OpNotEq then " !== " else " === " in
+			let se1 = s_expr_name e1 in
+			let se2 = s_expr_name e2 in
+			if
+				e1.eexpr = TConst (TNull)
+				|| e2.eexpr = TConst (TNull)
+			then begin	
+				(match e1.eexpr with 
+				| TField (f, s) when is_anonym_expr e1 || is_unknown_expr e1 ->
+(*					register_required_path ctx ([], "Reflect"); *)
+					spr ctx "Reflect::field(";
+					gen_value ctx f;
+					print ctx ", \"%s\")" s;
+				| _ ->
+					gen_field_op ctx e1);
+				
+				spr ctx s_phop;			
+				
+				(match e2.eexpr with 
+				| TField (f, s) when is_anonym_expr e2 || is_unknown_expr e2 ->
+(*					register_required_path ctx ([], "Reflect"); *)
+					spr ctx "Reflect::field(";
+					gen_value ctx f;
+					print ctx ", \"%s\")" s;
+				| _ ->
+					gen_field_op ctx e2);
+			end else if
+					((se1 = "Int" || se1 = "Null<Int>") && (se2 = "Int" || se2 = "Null<Int>"))
+					|| ((se1 = "Float" || se1 = "Null<Float>") && (se2 = "Float" || se2 = "Null<Float>"))
+			then begin
+				gen_field_op ctx e1;
+				spr ctx s_phop;
+				gen_field_op ctx e2;
+			end else if
+				   ((se1 = "Int" || se1 = "Float" || se1 = "Null<Int>" || se1 = "Null<Float>")
+				   && (se1 = "Int" || se1 = "Float" || se1 = "Null<Int>" || se1 = "Null<Float>"))
+				|| (is_unknown_expr e1 && is_unknown_expr e2)
+				|| is_anonym_expr e1
+				|| is_anonym_expr e2
+			then begin
+				if op = Ast.OpNotEq then spr ctx "!";
+				spr ctx "php_Boot::__equal(";
+				gen_field_op ctx e1;
+				spr ctx ", ";
+				gen_field_op ctx e2;
+				spr ctx ")";
+			end else if
+				   is_string_expr e1
+				&& is_string_expr e2
+			then begin
+				gen_field_op ctx e1;
+				spr ctx s_op;
+				gen_field_op ctx e2;
+			end else if
+				   se1 == se2
+				|| (match e1.eexpr with | TConst _ | TLocal _ | TArray _  | TNew _ -> true | _ -> false)
+				|| (match e2.eexpr with | TConst _ | TLocal _ | TArray _  | TNew _ -> true | _ -> false) 
+				|| is_string_expr e1
+				|| is_string_expr e2
+				|| is_array_expr e1
+				|| is_array_expr e2
+				|| is_anonym_expr e1
+				|| is_anonym_expr e2
+				|| is_unknown_expr e1
+				|| is_unknown_expr e2
+			then begin
+				gen_field_op ctx e1;
+				spr ctx s_phop;
+				gen_field_op ctx e2;
+			end else begin
+				gen_field_op ctx e1;
+				spr ctx s_op;
+				gen_field_op ctx e2;
+			end
+		| _ ->
+			gen_value_op ctx e1;
+			print ctx " %s " (Ast.s_binop op);
+			gen_value_op ctx e2;
+		);	
+	| TField (e1,s) ->
+		(match follow e.etype with
+		| TFun _ ->
+			let p = escphp ctx.quotes in
+			(if ctx.is_call then
+				gen_field_access ctx false e1 s
+	  		else if is_in_dynamic_methods ctx e1 s then
+	  			gen_field_access ctx true e1 s
+	  		else begin
+				spr ctx "array(";
+				(match e1.eexpr with
+				| TTypeExpr t ->
+					print ctx "%s\"" p;
+					spr ctx (s_path ctx (t_path t) false e1.epos);
+					print ctx "%s\"" p
+				| _ -> gen_expr ctx e1);
+				print ctx ", %s\"%s%s\")" p s p;
+			end)
+		| TMono _ ->
+			if ctx.is_call then
+				gen_field_access ctx false e1 s 
+			else
+				gen_uncertain_string_or_array_var ctx s e1
+		| _ ->
+			if is_string_expr e1 then
+				gen_string_var ctx s e1
+			else if is_array_expr e1 then
+				gen_array_var ctx s e1
+			else if is_uncertain_expr e1 then
+				gen_uncertain_string_or_array_var ctx s e1
+			else
+				gen_field_access ctx true e1 s
+		)
+
+	| TTypeExpr t ->
+		let p = escphp ctx.quotes in
+(*		register_required_path ctx (t_path t); *)
+		print ctx "php_Boot::__qtype(%s\"%s%s\")" p (s_path_haxe (t_path t)) p
+	| TParenthesis e ->
+		spr ctx "(";
+		gen_value ctx e;
+		spr ctx ")";
+	| TReturn eo ->
+		(match eo with
+		| None ->
+			spr ctx "return"
+		| Some e when (match follow e.etype with TEnum({ e_path = [],"Void" },[]) -> true | _ -> false) ->
+			gen_value ctx e;
+			newline ctx;
+			spr ctx "return"
+		| Some e when (is_array_expr e && (match e.eexpr with TLocal _ -> false | _ -> true)) ->
+			spr ctx "{";
+			newline ctx;
+			let tmp = define_local ctx "__r__" in
+			let byref = if is_array_ref e then "&" else "" in
+			print ctx "%s$%s =%s " (escphp ctx.quotes) tmp byref;
+			gen_value ctx e;
+			newline ctx;
+			print ctx "return %s$%s" (escphp ctx.quotes) tmp;
+			newline ctx;
+			spr ctx "}"
+		| Some e ->
+			spr ctx "return ";
+			gen_value ctx e;
+			);
+	| TBreak ->
+		if ctx.in_value <> None then unsupported e.epos;
+		if ctx.handle_break then spr ctx "throw new Exception(\"__break__\")" else spr ctx "break"
+	| TContinue ->
+		if ctx.in_value <> None then unsupported e.epos;
+		spr ctx "continue"
+	| TBlock [] ->
+		spr ctx ""
+	| TBlock el ->
+		let b = save_locals ctx in
+		print ctx "{";
+		let bend = open_block ctx in
+		let cb = (
+			if not ctx.constructor_block then
+				(fun () -> ())
+			else begin
+				ctx.constructor_block <- false;
+			if List.length ctx.dynamic_methods > 0 then newline ctx else spr ctx " ";
+			List.iter (fun (f) ->
+				let name = f.cf_name in
+				match f.cf_expr with
+				| Some { eexpr = TFunction fd } ->
+					print ctx "$this->%s = php_Boot::__closure(array(\"__this\" => &$this), \"" name;
+					ctx.quotes <- ctx.quotes + 1;
+					concat ctx "," (fun (arg,o,t) ->
+					let arg = define_local ctx arg in
+					  s_funarg ctx arg t e.epos o;
+					) fd.tf_args;
+					ctx.quotes <- ctx.quotes - 1;
+					
+					print ctx "\", \"";
+					let old = ctx.in_value in
+					ctx.in_value <- Some name;
+					ctx.quotes <- ctx.quotes + 1;
+					
+					(* TODO: check me *)
+					gen_expr ctx (fun_block ctx fd e.epos);
+					
+					
+(*					gen_expr ctx (mk_block fd.tf_expr); *)
+					ctx.quotes <- ctx.quotes - 1;
+					ctx.in_value <- old;
+					print ctx "\")";
+					newline ctx;
+				| _ -> ()
+			) ctx.dynamic_methods;
+			print ctx "if( !%s::$skip_constructor ) {" (s_path ctx (["php"],"Boot") false e.epos);
+			(fun() -> print ctx "}")
+			end) in
+		List.iter (fun e -> newline ctx; gen_expr ctx e) el;
+		bend();
+		newline ctx;
+		cb();
+		print ctx "}";
+		b();
+	| TFunction f ->
+		let old = ctx.in_static in
+		ctx.in_static <- true;
+		gen_inline_function ctx f [] e.epos;
+		ctx.in_static <- old
+	| TCall (ec,el) ->
+		(match ec.eexpr with
+		| TField (ef,s) when is_array_expr ef -> 
+			gen_array_call ctx s ef el
+		| TField (ef,s) when is_static ef.etype && is_string_expr ef -> 
+			gen_string_static_call ctx s ef el
+		| TField (ef,s) when is_string_expr ef -> 
+			gen_string_call ctx s ef el
+		| TField (ef,s) when is_anonym_expr ef -> 
+			if could_be_string_or_array_call s then begin
+				gen_uncertain_string_or_array_call ctx s ef el
+			end else if could_be_string_call s then begin
+				gen_uncertain_string_call ctx s ef el
+			end else if could_be_array_call s then begin
+				gen_uncertain_array_call ctx s ef el
+			end else
+				gen_call ctx ec el
+		| TCall _ ->
+			gen_call ctx ec el
+		| _ -> 
+			gen_call ctx ec el);
+	| TArrayDecl [] ->
+		spr ctx "php_Boot::__array_empty()";
+	| TArrayDecl el ->
+		spr ctx "php_Boot::__array(";
+		concat ctx ", " (gen_value ctx) el;
+		spr ctx ")";
+	| TThrow e ->
+		spr ctx "throw new HException(";
+		gen_value ctx e;
+(* TODO: add POS here *)
+		spr ctx ")";
+	| TVars [] ->
+		()
+	| TVars vl ->
+		spr ctx ((escphp ctx.quotes) ^ "$");
+		concat ctx ("; " ^ (escphp ctx.quotes) ^ "$") (fun (n,t,v) ->
+			let n = define_local ctx n in
+			match v with
+			| None -> print ctx "%s = null" n
+			| Some e ->
+				print ctx "%s %s " n (if is_array_ref e then "=&" else "=");
+				gen_value ctx e
+		) vl;
+	| TNew (c,_,el) ->
+		(match c.cl_path, el with
+		| ([], "String"), _ -> 
+			concat ctx "" (gen_value ctx) el
+		| ([], "Array"), [] -> 
+			spr ctx "php_Boot::__array_empty()";
+		| ([], "Array"), el -> 
+			spr ctx "php_Boot::__array(";
+			concat ctx ", " (gen_value ctx) el;
+			spr ctx ")"
+		| (_, _), _ ->
+			print ctx "new %s(" (s_path ctx c.cl_path c.cl_extern e.epos);
+			concat ctx ", " (gen_value ctx) el;
+			spr ctx ")")
+	| TIf (cond,e,eelse) ->
+		spr ctx "if";
+		gen_value ctx (parent cond);
+		spr ctx " ";
+		gen_expr ctx e;
+		(match eelse with
+		| None -> ()
+		| Some e when e.eexpr = TConst(TNull) -> ()
+		| Some e ->
+			newline ctx;
+			spr ctx "else ";
+			gen_expr ctx e);
+	| TUnop (op,Ast.Prefix,e) ->
+		spr ctx (Ast.s_unop op);
+		gen_value ctx e
+	| TUnop (op,Ast.Postfix,e) ->
+		gen_value ctx e;
+		spr ctx (Ast.s_unop op)
+	| TWhile (cond,e,Ast.NormalWhile) ->
+		let handle_break = handle_break ctx e in
+		spr ctx "while";
+		gen_value ctx (parent cond);
+		spr ctx " ";
+		gen_while_expr ctx e;
+		handle_break();
+	| TWhile (cond,e,Ast.DoWhile) ->
+		let handle_break = handle_break ctx e in
+		spr ctx "do ";
+		gen_while_expr ctx e;
+		spr ctx " while";
+		gen_value ctx (parent cond);
+		handle_break();
+	| TObjectDecl fields ->
+		spr ctx "php_Boot::__anonymous(array(";
+		let p = escphp ctx.quotes in
+		concat ctx ", " (fun (f,e) -> print ctx "%s\"%s%s\" => " p f p; gen_value ctx e) fields;
+		spr ctx "))"
+	| TFor (v,t,it,e) ->
+		let handle_break = handle_break ctx e in
+		let b = save_locals ctx in
+		let tmp = define_local ctx "__it__" in
+		let v = define_local ctx v in
+		let p = escphp ctx.quotes in
+		print ctx "%s$%s = " p tmp;
+		gen_value ctx it;
+		newline ctx;
+		print ctx "while(%s$%s->hasNext()) {" p tmp;
+		newline ctx;
+		print ctx "%s$%s = %s$%s->next()" p v p tmp;
+		newline ctx;
+		gen_expr ctx e;
+		newline ctx;
+		spr ctx "}";
+		b();
+		handle_break();
+	| TTry (e,catchs) ->
+		spr ctx "try ";
+		gen_expr ctx (mk_block e);
+		let ex = define_local ctx "__e__" in
+		print ctx "catch(HException %s$%s) {" (escphp ctx.quotes) ex;
+		let p = escphp ctx.quotes in
+		let first = ref true in
+		List.iter (fun (v,t,e) ->
+			let ev = define_local ctx v in
+			newline ctx;
+			let b = save_locals ctx in
+			if not !first then spr ctx "else ";
+			(match follow t with
+			| TEnum (te,_) -> (match snd te.e_path with
+				| "Bool"   -> print ctx "if(is_bool(%s$%s = %s$%s->e))"		p ev p ex
+				| _ -> print ctx "if((%s$%s = %s$%s->e) instanceof %s)"		p ev p ex (s_path ctx te.e_path te.e_extern e.epos));
+				gen_expr ctx (mk_block e);
+			| TInst (tc,_) -> (match snd tc.cl_path with
+				| "Int"	-> print ctx "if(is_int(%s$%s = %s$%s->e))"		 p ev p ex
+				| "Float"  -> print ctx "if(is_numeric(%s$%s = %s$%s->e))"	 p ev p ex
+				| "String" -> print ctx "if(is_string(%s$%s = %s$%s->e))"	  p ev p ex
+				| "Array"  -> print ctx "if(is_array(%s$%s = %s$%s->e))"	   p ev p ex
+				| _		-> print ctx "if((%s$%s = %s$%s->e) instanceof %s)" p ev p ex (s_path ctx tc.cl_path tc.cl_extern e.epos));
+				gen_expr ctx (mk_block e);
+			| TFun _
+			| TLazy _
+			| TType _
+			| TAnon _ ->
+				assert false
+			| TMono _
+			| TDynamic _ ->
+				print ctx "{ %s$%s = %s$%s->e" p ev p ex;
+				newline ctx;
+				gen_expr ctx (mk_block e);
+				spr ctx "}");
+			b();
+			first := false;
+		) catchs;
+		spr ctx "}";
+	| TMatch (e,_,cases,def) ->
+		let b = save_locals ctx in
+		let tmp = define_local ctx "__t__" in
+		print ctx "%s$%s = " (escphp ctx.quotes) tmp;
+		gen_value ctx e;
+		newline ctx;
+		print ctx "switch(%s$%s->index) {" (escphp ctx.quotes) tmp;
+		newline ctx;
+		List.iter (fun (cl,params,e) ->
+			List.iter (fun c ->
+				print ctx "case %d:" c;
+				newline ctx;
+			) cl;
+			let b = save_locals ctx in
+			(match params with
+			| None | Some [] -> ()
+			| Some l ->
+				let n = ref (-1) in
+				let l = List.fold_left (fun acc (v,t) -> incr n; match v with None -> acc | Some v -> (v,t,!n) :: acc) [] l in
+				match l with
+				| [] -> ()
+				| l ->
+					concat ctx "; " (fun (v,t,n) ->
+						let v = define_local ctx v in
+						print ctx "%s$%s = %s$%s->params[%d]" (escphp ctx.quotes) v (escphp ctx.quotes) tmp n;
+					) l;
+					newline ctx);
+			gen_expr ctx (mk_block e);
+			print ctx "break";
+			newline ctx;
+			b()
+		) cases;
+		(match def with
+		| None -> ()
+		| Some e ->
+			spr ctx "default:";
+			gen_expr ctx (mk_block e);
+			print ctx "break";
+			newline ctx;
+		);
+		spr ctx "}";
+		b()
+	| TSwitch (e,cases,def) ->
+		spr ctx "switch";
+		gen_value ctx (parent e);
+		spr ctx " {";
+		newline ctx;
+		List.iter (fun (el,e2) ->
+			List.iter (fun e ->
+				spr ctx "case ";
+				gen_value ctx e;
+				spr ctx ":";
+			) el;
+			gen_expr ctx (mk_block e2);
+			print ctx "break";
+			newline ctx;
+		) cases;
+		(match def with
+		| None -> ()
+		| Some e ->
+			spr ctx "default:";
+			gen_expr ctx (mk_block e);
+			print ctx "break";
+			newline ctx;
+		);
+		spr ctx "}"
+
+and gen_value ctx e =
+	let assign e =
+		mk (TBinop (Ast.OpAssign,
+			mk (TLocal (match ctx.in_value with None -> assert false | Some v -> "__r__")) t_dynamic e.epos,
+			e
+		)) e.etype e.epos
+	in
+	let value bl =
+		let old = ctx.in_value in
+		let locs = save_locals ctx in
+		let tmp = define_local ctx "__r__" in
+		ctx.in_value <- Some tmp;
+		let b = 
+		if bl then begin
+			print ctx "eval(%s\"" (escphp ctx.quotes);
+			ctx.quotes <- (ctx.quotes + 1);
+			let p = (escphp ctx.quotes) in
+			print ctx "if(isset(%s$this)) %s$__this =& %s$this;" p p p;
+			let b = open_block ctx in
+			b
+		end else
+			(fun() -> ())
+		in
+		(fun() ->
+			if bl then begin
+				newline ctx;
+				print ctx "return %s$%s" (escphp ctx.quotes) tmp;
+				b();
+				newline ctx;
+				ctx.quotes <- (ctx.quotes - 1);
+				print ctx "%s\")" (escphp ctx.quotes);
+			end;
+			ctx.in_value <- old;
+			locs();
+		)
+	in
+	match e.eexpr with
+	| TTypeExpr _
+	| TConst _
+	| TLocal _
+	| TEnumField _
+	| TArray _
+	| TBinop _
+	| TField _
+	| TParenthesis _
+	| TObjectDecl _
+	| TArrayDecl _
+	| TCall _
+	| TUnop _
+	| TNew _
+	| TFunction _ ->
+		gen_expr ctx e
+	| TReturn _
+	| TBreak
+	| TContinue ->
+		unsupported e.epos
+	| TVars _
+	| TFor _
+	| TWhile _
+	| TThrow _ ->
+		(* value is discarded anyway *)
+		let v = value true in
+		gen_expr ctx e;
+		v()
+	| TBlock [e] ->
+		gen_value ctx e
+	| TBlock el ->
+		let v = value true in
+		let rec loop = function
+		| [] ->
+			spr ctx "return null";
+		| [e] ->
+			gen_expr ctx (assign e);
+		| e :: l ->
+			gen_expr ctx e;
+			newline ctx;
+			loop l
+		in
+		loop el;
+		v();
+	| TIf (cond,e,eo) ->
+		spr ctx "(";
+		gen_value ctx cond;
+		spr ctx " ? ";
+		gen_value ctx e;
+		spr ctx " : ";
+		(match eo with
+		| None -> spr ctx "null"
+		| Some e -> gen_value ctx e);
+		spr ctx ")"
+	| TSwitch (cond,cases,def) ->
+		let v = value true in
+		gen_expr ctx (mk (TSwitch (cond,
+			List.map (fun (e1,e2) -> (e1,assign e2)) cases,
+			match def with None -> None | Some e -> Some (assign e)
+		)) e.etype e.epos);
+		v()
+	| TMatch (cond,enum,cases,def) ->
+		let v = value true in
+		gen_expr ctx (mk (TMatch (cond,enum,
+		List.map (fun (constr,params,e) -> (constr,params,assign e)) cases,
+			match def with None -> None | Some e -> Some (assign e)
+		)) e.etype e.epos);
+		v()
+	| TTry (b,catchs) ->
+	let v = value true in
+	gen_expr ctx (mk (TTry (assign b,
+		List.map (fun (v,t,e) -> v, t , assign e) catchs
+	)) e.etype e.epos);
+	v()
+	
+let is_method_defined ctx m static =
+	if static then
+		PMap.exists m ctx.curclass.cl_statics
+	else
+		PMap.exists m ctx.curclass.cl_fields
+
+let generate_self_method ctx rights m static setter =
+	if setter then (
+		if static then
+			print ctx "%s function %s($v) { return call_user_func(self::$%s, $v); }" rights (s_ident m) (s_ident m)
+		else
+			print ctx "%s function %s($v) { return call_user_func($this->%s, $v); }" rights (s_ident m) (s_ident m)
+	) else (
+		if static then
+			print ctx "%s function %s() { return call_user_func(self::$%s); }" rights (s_ident m) (s_ident m)
+		else
+			print ctx "%s function %s() { return call_user_func($this->%s); }" rights (s_ident m) (s_ident m)
+	);
+	newline ctx
+		
+let generate_field ctx static f =
+	newline ctx;
+	ctx.in_static <- static;
+	ctx.locals <- PMap.empty;
+	ctx.inv_locals <- PMap.empty;
+(*	let public = f.cf_public || Hashtbl.mem ctx.get_sets (f.cf_name,static) || (f.cf_name = "main" && static) || f.cf_name = "__resolve" in
+	let rights = (if public then "public" else "/*protected*/ public") ^ (if static then " static" else "") in *)
+	let rights = if static then "static" else "public" in 
+	let p = ctx.curclass.cl_pos in
+	match f.cf_expr with
+	| Some { eexpr = TFunction fd } ->
+		if static && PMap.exists f.cf_name ctx.curclass.cl_fields then error ("Can't redeclare method (PHP limitation): " ^ f.cf_name) ctx.curclass.cl_pos;
+		spr ctx (rights ^ " ");
+		(match f.cf_set with
+		| NormalAccess when (match fd.tf_expr.eexpr with | TBlock _ -> true | _ -> false) ->
+			gen_dynamic_function ctx static (s_ident f.cf_name) fd f.cf_params p
+		| _ ->
+			gen_function ctx (s_ident f.cf_name) fd f.cf_params p
+		);
+	| _ ->
+		if ctx.curclass.cl_interface then
+			match follow f.cf_type with
+			| TFun (args,r) ->
+				print ctx "function %s(" f.cf_name;
+				concat ctx ", " (fun (arg,o,t) ->
+				(*	spr ctx arg;
+					if o then spr ctx " = null"; *)
+					s_funarg ctx arg t p o; 
+				) args;
+				print ctx ")";
+			| _ -> spr ctx "//"; ()
+		else if 
+			(match f.cf_get, f.cf_set with 
+			| MethodAccess m1, MethodAccess m2 -> 
+				if not (is_method_defined ctx m1 static) then (
+					generate_self_method ctx rights m1 static false;
+					print ctx "%s $%s" rights (s_ident m1);
+					if not (is_method_defined ctx m2 static) then
+						newline ctx);
+				if not (is_method_defined ctx m2 static) then (
+					generate_self_method ctx rights m2 static true;
+					print ctx "%s $%s" rights (s_ident m2));
+				if (is_method_defined ctx m1 static) && (is_method_defined ctx m2 static) then
+					spr ctx "//";
+				true
+			| MethodAccess m, _ -> 
+				if not (is_method_defined ctx m static) then generate_self_method ctx rights m static false;
+				print ctx "%s $%s" rights (s_ident f.cf_name);
+				true
+			| _, MethodAccess m -> 
+				if not (is_method_defined ctx m static) then generate_self_method ctx rights m static true;
+				print ctx "%s $%s" rights (s_ident f.cf_name);
+				true
+			| _ -> 
+				false) then 
+				()
+		else begin
+			print ctx "%s $%s" rights (s_ident f.cf_name);
+			match f.cf_expr with
+			| None -> ()
+			| Some e ->
+				match e.eexpr with
+				| TConst _ -> 
+					print ctx " = ";
+					gen_value ctx e
+				| _ -> ()
+		end
+
+let generate_static_field_assign ctx path f =
+	ctx.in_static <- true;
+	let p = ctx.curclass.cl_pos in
+	if not ctx.curclass.cl_interface then
+		(match f.cf_expr with
+		| None -> ()
+		| Some e ->
+			match e.eexpr with
+			| TConst _ -> ()
+			| TFunction fd ->
+				(match f.cf_set with
+				| NormalAccess when (match fd.tf_expr.eexpr with | TBlock _ -> true | _ -> false) ->
+					newline ctx;
+					print ctx "%s::$%s = " (s_path ctx path false p) (s_ident f.cf_name);
+					gen_value ctx e
+				| _ -> ())
+			| _ ->
+				newline ctx;
+				print ctx "%s::$%s = " (s_path ctx path false p) (s_ident f.cf_name);
+				gen_value ctx e)
+
+let define_getset ctx stat f =
+	let def name =
+		Hashtbl.add ctx.get_sets (name,stat) f.cf_name
+	in
+		(match f.cf_get with MethodAccess m -> def m | _ -> ());
+		(match f.cf_set with MethodAccess m -> def m | _ -> ())
+
+let rec super_has_dynamic c =
+	match c.cl_super with
+	| None -> false
+	| Some (csup, _) -> (match csup.cl_dynamic with
+		| Some _ -> true
+		| _ -> super_has_dynamic csup)
+
+let generate_class ctx all_dynamic_methods c =
+	let requires_constructor = ref true in
+	ctx.curclass <- c;
+	ctx.all_dynamic_methods <- all_dynamic_methods;
+	List.iter (define_getset ctx false) c.cl_ordered_fields;
+	List.iter (define_getset ctx true) c.cl_ordered_statics;
+	ctx.local_types <- List.map snd c.cl_types;
+
+(*	register_required_path ctx (["php"], "Boot"); *)
+
+	print ctx "%s %s " (if c.cl_interface then "interface" else "class") (s_path ctx c.cl_path c.cl_extern c.cl_pos);
+	(match c.cl_super with
+	| None -> ()
+	| Some (csup,_) ->
+		requires_constructor := false;
+		print ctx "extends %s " (s_path ctx csup.cl_path csup.cl_extern c.cl_pos));
+	(match c.cl_implements with
+	| [] -> ()
+	| l ->
+		spr ctx (if c.cl_interface then "extends " else "implements ");
+		concat ctx ", " (fun (i,_) ->
+		print ctx "%s" (s_path ctx i.cl_path i.cl_extern c.cl_pos)) l);
+	spr ctx "{";
+
+	let get_dynamic_methods = List.filter is_dynamic_method c.cl_ordered_fields in
+
+	if not ctx.curclass.cl_interface then ctx.dynamic_methods <- get_dynamic_methods;
+
+	let cl = open_block ctx in
+	(match c.cl_constructor with
+	| None ->
+		if !requires_constructor && not c.cl_interface then begin
+			newline ctx;
+			spr ctx "public function __construct(){}"
+		end;
+	| Some f ->
+	let f = { f with
+			cf_name = "__construct";
+			cf_public = true;
+		} in
+		ctx.constructor_block <- true;
+		generate_field ctx false f;
+	);
+
+	List.iter (generate_field ctx false) c.cl_ordered_fields;
+
+	(match c.cl_dynamic with
+		| Some _ when not c.cl_interface && not (super_has_dynamic c) ->
+			newline ctx;
+			spr ctx "private $__dynamics = array();\n\tpublic function &__get($n) {\n\t\tif(isset($this->__dynamics[$n]))\n\t\t\treturn $this->__dynamics[$n];\n\t}\n\tpublic function __set($n, $v) {\n\t\t$this->__dynamics[$n] = $v;\n\t}\n\tpublic function __call($n, $a) {\n\t\tif(is_callable($this->__dynamics[$n]))\n\t\t\treturn call_user_func_array($this->__dynamics[$n], $a);\n\t\tthrow new HException(\"Unable to call «\".$n.\"»\");\n\t}"
+		| Some _
+		| _ -> 
+			if List.length ctx.dynamic_methods > 0 then begin
+				newline ctx;
+				spr ctx "public function __call($m, $a) {\n\t\tif(isset($this->$m) && is_callable($this->$m))\n\t\t\treturn call_user_func_array($this->$m, $a);\n\t\telse if(isset($this->__dynamics[$m]) && is_callable($this->__dynamics[$m]))\n\t\t\treturn call_user_func_array($this->__dynamics[$m], $a);\n\t\telse\n\t\t\tthrow new HException('Unable to call «'.$m.'»');\n\t}";
+			end;
+	);
+
+	List.iter (generate_field ctx true) c.cl_ordered_statics;
+
+	cl();
+	newline ctx;
+	print ctx "}"
+	
+let createmain com c =
+	let filename = match com.php_front with None -> "index.php" | Some n -> n in
+	let ctx = {
+		com = com;
+		tabs = "";
+		ch = open_out (com.file ^ "/" ^ filename);
+		path = ([], "");
+		buf = Buffer.create (1 lsl 14);
+		in_value = None;
+		in_static = false;
+		handle_break = false;
+		imports = Hashtbl.create 0;
+		curclass = null_class;
+		locals = PMap.empty;
+		inv_locals = PMap.empty;
+		local_types = [];
+		inits = [];
+		get_sets = Hashtbl.create 0;
+		constructor_block = false;
+		quotes = 0;
+		dynamic_methods = [];
+		all_dynamic_methods = [];
+		is_call = false;
+		cwd = "";
+	} in
+	
+	spr ctx "require_once dirname(__FILE__).'/lib/php/Boot.class.php';\n\n";
+	(match c.cl_ordered_statics with
+	| [{ cf_expr = Some e }] ->
+		gen_value ctx e; 
+	| _ -> assert false);
+	newline ctx;
+	spr ctx "\n?>";
+	close ctx
+
+let generate_main ctx c =
+	(match c.cl_ordered_statics with
+	| [{ cf_expr = Some e }] ->
+		gen_value ctx e; 
+	| _ -> assert false);
+		newline ctx
+
+let generate_enum ctx e =
+	ctx.local_types <- List.map snd e.e_types;
+	let pack = open_block ctx in
+	let ename = s_path ctx e.e_path e.e_extern e.e_pos in
+
+(*	register_required_path ctx (["php"], "Boot"); *)
+
+	print ctx "class %s extends enum {" ename;
+	let cl = open_block ctx in
+	PMap.iter (fun _ c ->
+		newline ctx;
+		match c.ef_type with
+		| TFun (args,_) ->
+			print ctx "public static function %s($" c.ef_name;
+			concat ctx ", $" (fun (a,o,t) ->
+				spr ctx a;
+				if o then spr ctx " = null";
+			) args;
+			spr ctx ") {";
+			print ctx " return new %s(\"%s\", %d, array($" ename c.ef_name c.ef_index;
+			concat ctx ", $" (fun (a,_,_) -> spr ctx a) args;
+			print ctx ")); }";
+		| _ ->
+			print ctx "public static $%s" c.ef_name;
+	) e.e_constrs;
+	cl();
+	newline ctx;
+	print ctx "}";
+
+	PMap.iter (fun _ c ->
+		match c.ef_type with
+		| TFun (args,_) ->
+			();
+		| _ ->
+			newline ctx;
+			print ctx "%s::$%s = new %s(\"%s\", %d)" ename c.ef_name ename c.ef_name  c.ef_index;
+	) e.e_constrs;
+
+	pack();
+	newline ctx
+
+let generate com =
+	let all_dynamic_methods = ref [] in
+	List.iter (fun t ->
+		(match t with
+		| TClassDecl c ->
+			let dynamic_methods_names lst =
+				List.map (fun fd -> {
+					mpath = c.cl_path;
+					mname = fd.cf_name;
+				}) (List.filter is_dynamic_method lst)
+			in
+			all_dynamic_methods := dynamic_methods_names c.cl_ordered_fields @ !all_dynamic_methods;
+			all_dynamic_methods := dynamic_methods_names c.cl_ordered_statics @ !all_dynamic_methods
+		| _ -> ())
+	) com.types;
+	List.iter (fun t ->
+		(match t with
+		| TClassDecl c ->
+			let c = (match c.cl_path with
+				| ["php"],"PhpXml__"	-> { c with cl_path = [],"Xml" }
+				| ["php"],"PhpDate__"   -> { c with cl_path = [],"Date" }
+				| ["php"],"PhpMath__"   -> { c with cl_path = [],"Math" }
+				| _ -> c
+			) in
+			if c.cl_extern then
+				()
+			else (match c.cl_path with
+			| [], "@Main" ->
+				createmain com c;
+				(*
+				let ctx = init dir "" ([], "index") 0 in
+				generate_main ctx c;
+				close ctx;
+				*)
+			| _ ->
+				let ctx = init com "lib" c.cl_path (if c.cl_interface then 2 else 0) in
+				(*let cp = s_path ctx c.cl_path c.cl_extern c.cl_pos in*)
+				generate_class ctx !all_dynamic_methods c;
+				(match c.cl_init with
+				| None -> ()
+				| Some e ->
+					newline ctx;
+					gen_expr ctx e);
+				(*
+				if c.cl_interface then begin
+					newline ctx;
+					print ctx "// php_Boot::__register_type(new __interfacetype__(\"%s\", \"%s\"))" cp (s_path_haxe c.cl_path);
+				end else begin
+					newline ctx;
+					print ctx "// php_Boot::__register_type(new __classtype__(\"%s\", \"%s\"))" cp (s_path_haxe c.cl_path);
+				end;
+				*)
+				List.iter (generate_static_field_assign ctx c.cl_path) c.cl_ordered_statics;
+				newline ctx;
+				close ctx);
+		| TEnumDecl e ->
+			if e.e_extern then
+				()
+			else
+				let ctx = init com "lib" e.e_path 1 in
+			generate_enum ctx e;
+(*
+			print ctx "// php_Boot::__register_type(new __enumtype__(\"%s\", \"%s\"))" (s_path ctx e.e_path false e.e_pos) (s_path_haxe e.e_path);
+			newline ctx;
+*)
+			close ctx
+		| TTypeDecl t ->
+			());
+	) com.types;
+	Hashtbl.iter (fun name data ->
+		write_resource com.file name data
+	) com.resources;

+ 9 - 1
main.ml

@@ -256,6 +256,9 @@ try
 			swf_lib := Some file
 		),"<file> : add the SWF library to the compiled SWF");
 		("-neko",Arg.String (set_platform Neko "neko"),"<file> : compile code to Neko Binary");
+		("-php",Arg.String (fun dir ->
+			set_platform Php "php" dir;
+		),"<directory> : generate PHP code into target directory");
 		("-x", Arg.String (fun file ->
 			let neko_file = file ^ ".n" in
 			set_platform Neko "neko" neko_file;
@@ -334,6 +337,10 @@ try
 		("--no-output", Arg.Unit (fun() -> no_output := true),": compiles but does not generate any file");
 		("--times", Arg.Unit (fun() -> measure_times := true),": mesure compilation times");
 		("--no-inline", define "no_inline", ": disable inlining");
+		("--php-front",Arg.String (fun f ->
+			if com.php_front <> None then raise (Arg.Bad "Multiple --php-front");
+			com.php_front <- Some f;
+		),"<filename> : select the name for the php front file");
 	] in
 	let current = ref 0 in
 	let args = Array.of_list ("" :: params) in
@@ -420,7 +427,8 @@ try
 			if com.verbose then print_endline ("Generating js : " ^ com.file);
 			Genjs.generate com
 		| Php ->
-			assert false
+			if com.verbose then print_endline ("Generating PHP in : " ^ com.file);
+			Genphp.generate com;
 		);
 		(match !xml_out with
 		| None -> ()

+ 2 - 0
std/Date.hx

@@ -114,6 +114,8 @@ extern class Date
 	#if neko
 		Date = neko.NekoDate__;
 		neko.Boot.__classes.Date = Date;
+	#elseif php
+		Date = php.PhpDate__;
 	#else
 		Date.now = function() {
 			return __new__(Date);

+ 2 - 0
std/DateTools.hx

@@ -119,6 +119,8 @@ class DateTools {
 			return __jsflash_format(d, f );
 		#elseif flash
 			return __jsflash_format(d, f );
+		#elseif php
+			return __jsflash_format(d, f );
 		#else
 			return null;
 		#end

+ 36 - 1
std/EReg.hx

@@ -38,6 +38,13 @@ class EReg {
 	var last : String;
 	var global : Bool;
 	#end
+	#if php
+	var pattern : String;
+	var options : String;
+	var re : String;
+	var last : String;
+	var matches : Array<Dynamic>;
+	#end
 
 	/**
 		Creates a new regular expression with pattern [r] and
@@ -55,6 +62,10 @@ class EReg {
 			this.r = untyped __new__("RegExp",r,opt);
 		#elseif flash9
 			this.r = untyped __new__(__global__["RegExp"],r,opt);
+		#elseif php
+			this.pattern = r;
+			this.options = opt;
+			this.re = "/" + untyped __php__("str_replace")("/", "\\/", r) + "/" + opt;
 		#else
 			throw "Regular expressions are not implemented for this platform";
 		#end
@@ -83,6 +94,13 @@ class EReg {
 		#elseif flash9
 			result = untyped r.exec(s);
 			return (result != null);
+		#elseif php
+			var p : Int = untyped __php__("preg_match")(re, s, matches, __php__("PREG_OFFSET_CAPTURE"));
+			if(p > 0)
+				last = s;
+			else
+				last = null;
+			return p > 0;
 		#else
 			return false;
 		#end
@@ -100,6 +118,9 @@ class EReg {
 			return untyped if( r.m != null && n >= 0 && n < r.m.length ) r.m[n] else throw "EReg::matched";
 		#elseif flash9
 			return untyped if( result != null && n >= 0 && n < result.length ) result[n] else throw "EReg::matched";
+		#elseif php
+			if(n >= 0 && n < matches.length) return matches[n][0];
+			else throw "EReg::matched";
 		#else
 			return null;
 		#end
@@ -122,13 +143,16 @@ class EReg {
 		#elseif flash9
 			if( result == null ) throw "No string matched";
 			return result.input.substr(0,result.index);
+		#elseif php
+			if( matches.length == 0 ) throw "No string matched";
+			return last.substr(0, matches[0][1]);
 		#else
 			return null;
 		#end
 	}
 
 	/**
-		Returns the part of the string that was as the right of
+		Returns the part of the string that was at the right of
 		of the matched substring.
 	**/
 	public function matchedRight() : String {
@@ -149,6 +173,9 @@ class EReg {
 			if( result == null ) throw "No string matched";
 			var rl = result.index + result[0].length;
 			return result.input.substr(rl,result.input.length - rl);
+		#elseif php
+			if( matches.length == 0 ) throw "No string matched";
+			return untyped __php__("substr")(last, matches[0][1] + __php__("strlen")(matches[0][0]));
 		#else
 			return null;
 		#end
@@ -167,6 +194,8 @@ class EReg {
 		#elseif flash9
 			if( result == null ) throw "No string matched";
 			return { pos : result.index, len : result[0].length };
+		#elseif php
+			return untyped { pos : matches[0][1], len : __php__("strlen")(matches[0][0]) };
 		#else
 			return null;
 		#end
@@ -203,6 +232,8 @@ class EReg {
 			// we can't use directly s.split because it's ignoring the 'g' flag
 			var d = "#__delim__#";
 			return untyped s.replace(r,d).split(d);
+		#elseif php
+			return untyped __php__("preg_split")(re, s);
 		#else
 			return null;
 		#end
@@ -265,6 +296,10 @@ class EReg {
 			return b.toString();
 		#elseif (js || flash9)
 			return untyped s.replace(r,by);
+		#elseif php
+			by = untyped __call__("str_replace", "$$", "\\$", by);
+			untyped __php__("if(!preg_match('/\\\\([^?].+?\\\\)/', $this->re)) $by = preg_replace('/\\$(\\d+)/', '\\\\\\$\\1', $by)");
+			return untyped __php__("preg_replace")(re, by, s);
 		#else
 			return null;
 		#end

+ 23 - 1
std/Hash.hx

@@ -30,7 +30,7 @@
 **/
 class Hash<T> {
 
-	private var h : #if flash9 flash.utils.Dictionary #else Dynamic #end;
+	private var h : #if flash9 flash.utils.Dictionary #elseif php ArrayAccess<T> #else Dynamic #end;
 
 	/**
 		Creates a new empty hashtable.
@@ -50,6 +50,8 @@ class Hash<T> {
 				__js__("delete")(h.__proto__);
 			}
 		}
+		#elseif php
+		h = untyped __call__('array');
 		#end
 	}
 
@@ -63,6 +65,8 @@ class Hash<T> {
 		untyped h["$"+key] = value;
 		#elseif neko
 		untyped __dollar__hset(h,key.__s,value,null);
+		#elseif php
+		untyped __php__("$this->h[$key] = $value");
 		#end
 	}
 
@@ -76,6 +80,9 @@ class Hash<T> {
 		return untyped h["$"+key];
 		#elseif neko
 		return untyped __dollar__hget(h,key.__s,null);
+		#elseif php
+		if(!exists(key)) return null;
+		return untyped h[key];
 		#else
 		return null;
 		#end
@@ -104,6 +111,8 @@ class Hash<T> {
 		}
 		#elseif neko
 		return untyped __dollar__hmem(h,key.__s,null);
+		#elseif php
+		return untyped __php__("array_key_exists")(key, h);
 		#else
 		return false;
 		#end
@@ -131,6 +140,8 @@ class Hash<T> {
 		return true;
 		#elseif neko
 		return untyped __dollar__hremove(h,key.__s,null);
+		#elseif php
+		return php.Boot.__array_remove_at(cast h, untyped key);
 		#else
 		return false;
 		#end
@@ -155,6 +166,8 @@ class Hash<T> {
 		var l = new List<String>();
 		untyped __dollar__hiter(h,function(k,_) { l.push(new String(k)); });
 		return l.iterator();
+		#elseif php
+		return php.Boot.__array_iterator(untyped __php__("array_keys")(h));
 		#else
 		return null;
 		#end
@@ -189,6 +202,8 @@ class Hash<T> {
 		var l = new List<T>();
 		untyped __dollar__hiter(h,function(_,v) { l.push(v); });
 		return l.iterator();
+		#elseif php
+		return php.Boot.__array_iterator(untyped __php__("array_values")(h));
 		#else
 		return null;
 		#end
@@ -213,4 +228,11 @@ class Hash<T> {
 		return s.toString();
 	}
 
+#if php
+	static public function fromAssociativeArray<T>(arr : Dynamic) : Hash<T> {
+		var h = new Hash<T>();
+		untyped __php__("foreach($arr as $k => $v) $h->set($k, $v)");
+		return h;
+	}
+#end
 }

+ 16 - 1
std/IntHash.hx

@@ -29,7 +29,7 @@
 **/
 class IntHash<T> {
 
-	private var h : #if flash9 flash.utils.Dictionary #else Dynamic #end;
+	private var h : #if flash9 flash.utils.Dictionary #elseif php ArrayAccess<Int> #else Dynamic #end;
 
 	/**
 		Creates a new empty hashtable.
@@ -47,6 +47,8 @@ class IntHash<T> {
 			h.__proto__ = null;
 			__js__("delete")(h.__proto__);
 		};
+		#elseif php
+		h = untyped __call__('array');
 		#end
 	}
 
@@ -60,6 +62,8 @@ class IntHash<T> {
 		untyped h[key] = value;
 		#elseif neko
 		untyped __dollar__hset(h,key,value,null);
+		#elseif php
+		untyped __php__("$this->h[$key] = $value");
 		#end
 	}
 
@@ -73,6 +77,9 @@ class IntHash<T> {
 		return untyped h[key];
 		#elseif neko
 		return untyped __dollar__hget(h,key,null);
+		#elseif php
+		if(!exists(key)) return null;
+		return untyped h[key];
 		#else
 		return null;
 		#end
@@ -92,6 +99,8 @@ class IntHash<T> {
 		return untyped h[key] != null;
 		#elseif neko
 		return untyped __dollar__hmem(h,key,null);
+		#elseif php
+		return untyped __php__("array_key_exists")(key, h);
 		#else
 		return false;
 		#end
@@ -116,6 +125,8 @@ class IntHash<T> {
 		return true;
 		#elseif neko
 		return untyped __dollar__hremove(h,key,null);
+		#elseif php
+		return php.Boot.__array_remove_at(cast h, key);
 		#else
 		return false;
 		#end
@@ -143,6 +154,8 @@ class IntHash<T> {
 		var l = new List<Int>();
 		untyped __dollar__hiter(h,function(k,_) { l.push(k); });
 		return l.iterator();
+		#elseif php
+		return php.Boot.__array_iterator(untyped __php__("array_keys")(h));
 		#else
 		return null;
 		#end
@@ -177,6 +190,8 @@ class IntHash<T> {
 		var l = new List<T>();
 		untyped __dollar__hiter(h,function(_,v) { l.push(v); });
 		return l.iterator();
+		#elseif php
+		return php.Boot.__array_iterator(untyped __php__("array_values")(h));
 		#else
 		return null;
 		#end

+ 45 - 2
std/List.hx

@@ -30,8 +30,13 @@
 **/
 class List<T> {
 
+	#if php
+	private var h : ArrayAccess<Dynamic>;
+	private var q : ArrayAccess<Dynamic>;
+	#else
 	private var h : Array<Dynamic>;
 	private var q : Array<Dynamic>;
+	#end
 
 	/**
 		The number of elements in this list.
@@ -49,12 +54,19 @@ class List<T> {
 		Add an element at the end of the list.
 	**/
 	public function add( item : T ) {
-		var x = #if neko untyped __dollar__array(item,null) #else [item] #end;
+		var x = #if neko untyped __dollar__array(item,null) #elseif php untyped __call__('array', item, null) #else [item] #end;
 		if( h == null )
+		#if php
+			untyped __php__("$this->h =& $x");
+		else
+			untyped __php__("$this->q[1] =& $x");
+		untyped __php__("$this->q =& $x");
+		#else
 			h = x;
 		else
 			q[1] = x;
 		q = x;
+		#end
 		length++;
 	}
 
@@ -62,10 +74,22 @@ class List<T> {
 		Push an element at the beginning of the list.
 	**/
 	public function push( item : T ) {
-		var x = #if neko untyped __dollar__array(item,h) #else [item,h] #end;
+		var x = #if neko
+			untyped __dollar__array(item,h)
+		#elseif php
+			untyped __call__('array', item, __php__("&$this->h"))
+		#else
+			[item,h]
+		#end;
+		#if php
+		untyped __php__("$this->h =& $x");
+		if( q == null )
+			untyped __php__("$this->q =& $x");		
+		#else
 		h = x;
 		if( q == null )
 			q = x;
+		#end
 		length++;
 	}
 
@@ -123,6 +147,24 @@ class List<T> {
 	**/
 	public function remove( v : T ) : Bool {
 		var prev = null;
+		#if php
+		var l = null;
+		untyped __php__("$l =& $this->h");
+		while( l != null ) {
+			if( l[0] == v ) {
+				if( prev == null )
+					untyped __php__("$this->h =& $l[1]");
+				else
+					untyped __php__("$prev[1] =& $l[1]");
+				if(untyped __physeq__(q, l))
+					untyped __php__("$this->q =& $prev");
+				length--;
+				return true;
+			}
+			untyped __php__("$prev =& $l");
+			untyped __php__("$l =& $l[1]");
+		}		
+		#else
 		var l = h;
 		while( l != null ) {
 			if( l[0] == v ) {
@@ -138,6 +180,7 @@ class List<T> {
 			prev = l;
 			l = l[1];
 		}
+		#end
 		return false;
 	}
 

+ 4 - 1
std/Math.hx

@@ -59,6 +59,8 @@ extern class Math
 	#if neko
 		Math = neko.NekoMath__;
 		neko.Boot.__classes.Math = Math;
+	#elseif php
+		Math = php.PhpMath__;
 	#else
 		#if flash9
 		NaN = __global__["Number"].NaN;
@@ -94,7 +96,8 @@ extern class Math
 			#end
 		};
 	#end
-	#if !flash9
+	#if (flash9 || php)
+	#else
 		Math.__name__ = ["Math"];
 	#end
 	}

+ 115 - 3
std/Reflect.hx

@@ -46,6 +46,14 @@ class Reflect {
 			return false;
 		#elseif neko
 			return __dollar__typeof(o) == __dollar__tobject && __dollar__objfield(o,__dollar__hash(field.__s));
+		#elseif php
+			return __php__("
+			(is_object($o) && (method_exists($o, $field) || isset($o->$field) || property_exists($o, $field)))
+			||
+			(is_string($o) && (in_array($field, array('toUpperCase', 'toLowerCase', 'charAt', 'charCodeAt', 'indexOf', 'lastIndexOf', 'split', 'substr', 'toString', 'length'))))
+			||
+			(is_array($o)  && (in_array($field, array('concat', 'copy', 'insert', 'iterator', 'join', 'pop', 'push', 'remove', 'reverse', 'shift', 'slice', 'sort', 'splice', 'unshift', 'toString', 'length'))))
+			");
 		#else
 			return false;
 		#end
@@ -54,7 +62,7 @@ class Reflect {
 	/**
 		Returns the field of an object, or null if [o] is not an object or doesn't have this field.
 	**/
-	public inline static function field( o : Dynamic, field : String ) : Dynamic untyped {
+	public #if !php inline #end static function field( o : Dynamic, field : String ) : Dynamic untyped {
 		#if flash9
 			return (o == null) ? null : o[field];
 		#elseif flash
@@ -68,6 +76,67 @@ class Reflect {
 			return v;
 		#elseif neko
 			return if( __dollar__typeof(o) != __dollar__tobject ) null else __dollar__objget(o,__dollar__hash(field.__s));
+		#elseif php
+			if(hasField(o, field)) {
+				if(__php__("$o instanceof __type__")) {
+					if(__php__("is_callable(array($o->__tname__, $field))")) {
+						return __php__("array($o->__tname__, $field)");
+					} else {
+						return __php__("eval('return '.$o->__tname__.'::$'.$field.';')");
+					}
+				} else if(__call__("is_string", o)) {
+					if(field == 'length')
+						return php.Boot.__len(o);
+					else {
+						switch(field) {
+							case 'charAt':      return php.Boot.__closure(__php__("array('o' => $o)"), '$index', 'return substr($o, $index,1 );');
+							case 'charCodeAt':  return php.Boot.__closure(__php__("array('o' => $o)"), '$index', 'return ord(substr($o, $index, 1));');
+							case 'indexOf':     return php.Boot.__closure(__php__("array('o' => $o)"), '$value,$startIndex', 'return php_Boot::__index_of($o, $value, $startIndex);');
+							case 'lastIndexOf': return php.Boot.__closure(__php__("array('o' => $o)"), '$value,$startIndex', 'return php_Boot::__last_index_of($o, $value, $startIndex);');
+							case 'split':       return php.Boot.__closure(__php__("array('o' => $o)"), '$delimiter', 'return explode($delimiter, $o);');
+							case 'substr':      return php.Boot.__closure(__php__("array('o' => $o)"), '$pos,$len', 'return php_Boot::__substr($o, $pos, $len);');
+							case 'toUpperCase': return php.Boot.__closure(__php__("array('o' => $o)"), '', 'return strtoupper($o);');
+							case 'toLowerCase': return php.Boot.__closure(__php__("array('o' => $o)"), '', 'return strtolower($o);');
+							case 'toString':    return php.Boot.__closure(__php__("array('o' => $o)"), '', 'return $o;');
+						}
+						return null;
+					}
+				} else if(__call__("is_array", o)) {
+					if(field == 'length')
+						return php.Boot.__len(o);
+					else
+						switch(field) {
+							case 'concat':   return php.Boot.__closure(__php__("array('o' => &$o)"), '$a', 'return array_merge($o, $a);');
+							case 'join':     return php.Boot.__closure(__php__("array('o' => &$o)"), '$sep', 'return join($sep, $o);');
+							case 'pop':      return php.Boot.__closure(__php__("array('o' => &$o)"), '', 'return array_pop($o);');
+							case 'push':     return php.Boot.__closure(__php__("array('o' => &$o)"), '$x', 'return array_push($o, $x);');
+							case 'reverse':  return php.Boot.__closure(__php__("array('o' => &$o)"), '', 'return rsort($o);');
+							case 'shift':    return php.Boot.__closure(__php__("array('o' => &$o)"), '', 'return array_shift($o);');
+							case 'slice':    return php.Boot.__closure(__php__("array('o' => &$o)"), '$pos,$end', 'return php_Boot::__array_slice(array(&$o), $pos, $end);');
+							case 'sort':     return php.Boot.__closure(__php__("array('o' => &$o)"), '$f', 'return php_Boot::__array_sort($o, $f);');
+							case 'splice':   return php.Boot.__closure(__php__("array('o' => &$o)"), '$pos,$len', 'return php_Boot::__array_splice(array(&$o), $pos, $len);');
+							case 'toString': return php.Boot.__closure(__php__("array('o' => &$o)"), '', 'return "[".join(", ", $o)."]";');
+							case 'unshift':  return php.Boot.__closure(__php__("array('o' => &$o)"), '$x', 'return array_unshift($o, $x);');
+							case 'insert':   return php.Boot.__closure(__php__("array('o' => &$o)"), '$pos,$x', 'return php_Boot::__array_insert(array(&$o), $pos, $x);');
+							case 'remove':   return php.Boot.__closure(__php__("array('o' => &$o)"), '$x', 'return php_Boot::__array_remove(array(&$o), $x);');
+							case 'iterator': return php.Boot.__closure(__php__("array('o' => &$o)"), '', 'return new HArrayIterator($o);');
+							case 'copy':     return php.Boot.__closure(__php__("array('o' => $o)"), '', 'return $o;');
+						}
+					return null;
+				} else if(__php__("property_exists($o, $field)")) {
+					if(__php__("is_array($o->$field) && is_callable($o->$field)")) {
+						return __php__("$o->$field");
+					} else if(__php__("is_string($o->$field) && php_Boot::__is_lambda($o->$field)")) {
+						return __php__("array($o, $field)");
+					} else {
+						return __php__("$o->$field");
+					}
+				} else {
+					return __php__("array($o, $field)");
+				}
+			} else {
+				return null;
+			}
 		#else
 			return null;
 		#end
@@ -76,7 +145,7 @@ class Reflect {
 	/**
 		Set an object field value.
 	**/
-	public inline static function setField( o : Dynamic, field : String, value : Dynamic ) : Void untyped {
+	public #if !php inline #end static function setField( o : Dynamic, field : String, value : Dynamic ) : Void untyped {
 		#if flash
 			o[field] = value;
 		#elseif js
@@ -84,13 +153,15 @@ class Reflect {
 		#elseif neko
 			if( __dollar__typeof(o) == __dollar__tobject )
 				__dollar__objset(o,__dollar__hash(field.__s),value);
+		#elseif php
+			untyped __php__("$o->$field = $value");
 		#end
 	}
 
 	/**
 		Call a method with the given object and arguments.
 	**/
-	public inline static function callMethod( o : Dynamic, func : Dynamic, args : Array<Dynamic> ) : Dynamic untyped {
+	public #if !php inline #end static function callMethod( o : Dynamic, func : Dynamic, args : Array<Dynamic> ) : Dynamic untyped {
 		#if flash9
 			return func.apply(o,args);
 		#elseif flash
@@ -99,6 +170,13 @@ class Reflect {
 			return func.apply(o,args);
 		#elseif neko
 			return __dollar__call(func,o,args.__neko());
+		#elseif php
+			if(__call__("is_string", o) || __call__("is_array", o)) {
+				if(args.length == 0) return field(o, func)();
+				else if(args.length == 1) return field(o, func)(args[0]);
+				else return field(o, func)(args[0], args[1]);
+			}
+			return __php__("call_user_func_array(is_callable($func) ? $func : array($o, $func) , $args)");
 		#else
 			return null;
 		#end
@@ -164,6 +242,12 @@ class Reflect {
 				}
 				return Array.new1(a,l);
 			}
+		#elseif php
+			return __call__('is_array', o) 
+					? __call__('array', 'concat', 'copy', 'insert', 'iterator', 'length', 'join', 'pop', 'push', 'remove', 'reverse', 'shift', 'slice', 'sort', 'splice', 'toString', 'unshift') 
+					: (__call__('is_string', o) 
+						? __call__('array', 'charAt', 'charCodeAt', 'indexOf', 'lastIndexOf', 'length', 'split', 'substr', 'toLowerCase', 'toString', 'toUpperCase') 
+						: __call__('array_keys', __call__('get_object_vars', o)));
 		#else
 			return new Array();
 		#end
@@ -181,6 +265,8 @@ class Reflect {
 			return __js__("typeof(f)") == "function" && f.__name__ == null;
 		#elseif neko
 			return __dollar__typeof(f) == __dollar__tfunction;
+		#elseif php
+			return __php__("(is_array($f) && is_callable($f)) || php_Boot::__is_lambda($f)") || (__php__("is_array($f)") && hasField(f[0], f[1]) && f[1] != "length");
 		#else
 			return false;
 		#end
@@ -214,6 +300,12 @@ class Reflect {
 			return untyped f1["f"] == f2["f"] && f1["o"] == f2["o"] && f1["f"] != null;
 		#elseif js
 			return f1.scope == f2.scope && f1.method == f2.method && f1.method != null;
+		#elseif php
+			if(untyped __call__("is_array", f1) && untyped __call__("is_array", f1))
+				return f1[0] == f2[0] && f1[1] == f2[1];
+			if(untyped __call__("is_string", f1) && untyped __call__("is_string", f2))
+				return f1 == f2;
+			return false;
 		#else
 			return false;
 		#end
@@ -247,6 +339,14 @@ class Reflect {
 				return false;
 			var t = __js__("typeof(v)");
 			return (t == "string" || (t == "object" && !v.__enum__) || (t == "function" && v.__name__ != null));
+		#elseif php
+			if( v == null )
+				return false;
+			if(__call__("is_object", v))
+				return __php__("$v instanceof Anonymous") || Type.getClass(v) != null;
+			if(__php__("is_string($v) && !php_Boot::__is_lambda($v)")) return true;
+			if(__php__("is_array($v) && !is_callable($v)")) return true;
+			return false;
 		#else
 			return false;
 		#end
@@ -270,6 +370,10 @@ class Reflect {
 			return true;
 		#elseif neko
 			return __dollar__objremove(o,__dollar__hash(f.__s));
+		#elseif php
+			if(!hasField(o,f)) return false;
+			untyped __php__("unset($o->$f)");
+			return true;
 		#else
 			return false;
 		#end
@@ -282,6 +386,9 @@ class Reflect {
 		#if neko
 			return untyped __dollar__new(o);
 		#else
+			#if php
+				if(untyped __call__("is_string", o) || untyped __call__("is_array", o)) return o;
+			#end
 			var o2 : Dynamic = {};
 			for( f in Reflect.fields(o) )
 				Reflect.setField(o2,f,Reflect.field(o,f));
@@ -307,6 +414,11 @@ class Reflect {
 			};
 		#elseif flash
 			return function() { return f(untyped __arguments__); };
+		#elseif php
+			return function() { 
+				var args = untyped __call__("func_get_args");
+				return f(args); 
+			};
 		#else
 			return null;
 		#end

+ 14 - 1
std/Std.hx

@@ -39,6 +39,8 @@ class Std {
 		neko.Boot.__instanceof(v,t);
 		#elseif js
 		js.Boot.__instanceof(v,t);
+		#elseif php
+		php.Boot.__instanceof(v,t);
 		#else
 		false;
 		#end
@@ -55,6 +57,8 @@ class Std {
 		new String(__dollar__string(s));
 		#elseif js
 		js.Boot.__string_rec(s,"");
+		#elseif php
+		php.Boot.__string_rec(s);
 		#else
 		"";
 		#end
@@ -63,9 +67,11 @@ class Std {
 	/**
 		Convert a Float to an Int, rounded down.
 	**/
-	public #if flash9 inline #end static function int( x : Float ) : Int {
+	public #if (flash9 || php) inline #end static function int( x : Float ) : Int {
 		#if flash9
 		return untyped __int__(x);
+		#elseif php
+		return untyped __php__("intval")(x);
 		#else
 		if( x < 0 ) return Math.ceil(x);
 		return Math.floor(x);
@@ -101,6 +107,9 @@ class Std {
 		if( Math.isNaN(v) )
 			return null;
 		return v;
+		#elseif php
+		if(!__php__("is_numeric")(x)) return null;
+		return x.substr(0, 2).toLowerCase() == "0x" ? __php__("intval(substr($x, 2), 16)") : __php__("intval($x)");
 		#else
 		return 0;
 		#end
@@ -120,6 +129,8 @@ class Std {
 		__dollar__float(x.__s);
 		#elseif js
 		__js__("parseFloat")(x);
+		#elseif php
+		__php__("is_numeric($x) ? floatval($x) : acos(1.01)");
 		#else
 		0;
 		#end
@@ -138,6 +149,8 @@ class Std {
 		Math._rand_int(Math.__rnd,x);
 		#elseif js
 		Math.floor(Math.random()*x);
+		#elseif php
+		__call__("rand", 0, x-1);
 		#else
 		0;
 		#end

+ 1 - 1
std/StringBuf.hx

@@ -73,7 +73,7 @@ class StringBuf {
 	public inline function addChar( c : Int ) untyped {
 		#if neko
 			__add_char(b,c);
-		#elseif (flash9 || js)
+		#elseif (flash9 || js || php)
 			b += String.fromCharCode(c);
 		#elseif flash
 			b += String["fromCharCode"](c);

+ 41 - 9
std/StringTools.hx

@@ -35,7 +35,7 @@ class StringTools {
 	/**
 		Encode an URL by using the standard format.
 	**/
-	public static function urlEncode( s : String ) : String untyped {
+	public #if php inline #end static function urlEncode( s : String ) : String untyped {
 		#if flash9
 			return __global__["encodeURIComponent"](s);
 		#elseif flash
@@ -44,6 +44,8 @@ class StringTools {
 			return new String(_urlEncode(s.__s));
 		#elseif js
 			return encodeURIComponent(s);
+		#elseif php
+			return __call__("rawurlencode", s);
 		#else
 			return null;
 		#end
@@ -52,7 +54,7 @@ class StringTools {
 	/**
 		Decode an URL using the standard format.
 	**/
-	public static function urlDecode( s : String ) : String untyped {
+	public #if php inline #end static function urlDecode( s : String ) : String untyped {
 		#if flash9
 			return __global__["decodeURIComponent"](s.split("+").join(" "));
 		#elseif flash
@@ -61,6 +63,8 @@ class StringTools {
 			return new String(_urlDecode(s.__s));
 		#elseif js
 			return decodeURIComponent(s.split("+").join(" "));
+		#elseif php
+			return __call__("urldecode", s);
 		#else
 			return null;
 		#end
@@ -76,8 +80,12 @@ class StringTools {
 	/**
 		Unescape HTML special characters of the string.
 	**/
-	public static function htmlUnescape( s : String ) : String {
+	public #if php inline #end static function htmlUnescape( s : String ) : String {
+		#if php
+		return untyped __call__("htmlspecialchars_decode", s);
+		#else
 		return s.split("&gt;").join(">").split("&lt;").join("<").split("&amp;").join("&");
+		#end
 	}
 
 	/**
@@ -107,7 +115,10 @@ class StringTools {
 	/**
 		Removes spaces at the left of the String [s].
 	**/
-	public static function ltrim( s : String ) : String {
+	public #if php inline #end static function ltrim( s : String ) : String {
+		#if php
+		return untyped __call__("ltrim", s);
+		#else
 		var l = s.length;
 		var r = 0;
 		while( r < l && isSpace(s,r) ){
@@ -117,12 +128,16 @@ class StringTools {
 			return s.substr(r, l-r);
 		else
 			return s;
+		#end
 	}
 
 	/**
 		Removes spaces at the right of the String [s].
 	**/
-	public static function rtrim( s : String ) : String {
+	public #if php inline #end static function rtrim( s : String ) : String {
+		#if php
+		return untyped __call__("rtrim", s);
+		#else
 		var l = s.length;
 		var r = 0;
 		while( r < l && isSpace(s,l-r-1) ){
@@ -133,19 +148,27 @@ class StringTools {
 		}else{
 			return s;
 		}
+		#end
 	}
 
 	/**
 		Removes spaces at the beginning and the end of the String [s].
 	**/
-	public static function trim( s : String ) : String {
+	public #if php inline #end static function trim( s : String ) : String {
+		#if php
+		return untyped __call__("trim", s);
+		#else
 		return ltrim(rtrim(s));
+		#end
 	}
 
 	/**
 		Pad the string [s] by appending [c] at its right until it reach [l] characters.
 	**/
-	public static function rpad( s : String, c : String, l : Int ) : String {
+	public #if php inline #end static function rpad( s : String, c : String, l : Int ) : String {
+		#if php
+		return untyped __call__("str_pad", s, l, c, __php__("STR_PAD_RIGHT"));
+		#else
 		var sl = s.length;
 		var cl = c.length;
 		while( sl < l ){
@@ -158,12 +181,16 @@ class StringTools {
 			}
 		}
 		return s;
+		#end
 	}
 
 	/**
 		Pad the string [s] by appending [c] at its left until it reach [l] characters.
 	**/
-	public static function lpad( s : String, c : String, l : Int ) : String {
+	public #if php inline #end static function lpad( s : String, c : String, l : Int ) : String {
+		#if php
+		return untyped __call__("str_pad", s, l, c, __php__("STR_PAD_LEFT"));
+		#else
 		var ns = "";
 		var sl = s.length;
 		if( sl >= l ) return s;
@@ -179,13 +206,18 @@ class StringTools {
 			}
 		}
 		return ns+s;
+		#end
 	}
 
 	/**
 		Replace all occurences of the string [sub] in the string [s] by the string [by].
 	**/
-	public static function replace( s : String, sub : String, by : String ) : String {
+	public #if php inline #end static function replace( s : String, sub : String, by : String ) : String {
+		#if php
+		return untyped __call__("str_replace", sub, by, s);
+		#else
 		return s.split(sub).join(by);
+		#end
 	}
 
 	/**

+ 174 - 15
std/Type.hx

@@ -59,6 +59,21 @@ class Type {
 			if( p == null )
 				return null;
 			return p.__class__;
+		#elseif php
+			if(o == null) return null;
+			untyped if(__call__("is_array",  o)) {
+				if(__call__("count", o) == 2 && __call__("is_callable", o)) return null;
+				return __php__("php_Boot::__ttype('Array')");
+			}
+			if(untyped __call__("is_string", o)) {
+				if(php.Boot.__is_lambda(untyped o)) return null;
+				return __php__("php_Boot::__ttype('String')");
+			}
+			var c = __php__("get_class")(o);
+			if(c == false || c == 'Anonymous' || __call__("is_subclass_of", c, "enum"))
+				return null;
+			else
+				return __php__("php_Boot::__ttype($c)");
 		#else
 			return null;
 		#end
@@ -89,6 +104,11 @@ class Type {
 			if( __dollar__typeof(o) != __dollar__tobject )
 				return null;
 			return o.__enum__;
+		#elseif php
+			if(!__php__("$o instanceof enum"))
+				return null;
+			else
+				return __php__("php_Boot::__ttype(get_class($o))");
 		#else
 			return null;
 		#end
@@ -104,6 +124,12 @@ class Type {
 			if( cname == "Object" )
 				return null;
 			return __as__(__global__["flash.utils.getDefinitionByName"](cname),Class);
+		#elseif php
+			var s = __php__("get_parent_class")(c.__tname__);
+			if(s == false)
+				return null;
+			else
+				return __php__("php_Boot::__ttype($s)");
 		#else
 			return c.__super__;
 		#end
@@ -125,6 +151,8 @@ class Type {
 			default:
 			}
 			return str.split("::").join(".");
+		#elseif php
+			return untyped c.__qname__;
 		#else
 			var a : Array<String> = untyped c.__name__;
 			return a.join(".");
@@ -137,6 +165,8 @@ class Type {
 	public static function getEnumName( e : Enum ) : String {
 		#if flash9
 			return getClassName(cast e);
+		#elseif php
+		  return untyped e.__qname__;
 		#else
 			var a : Array<String> = untyped e.__ename__;
 			return a.join(".");
@@ -148,7 +178,15 @@ class Type {
 		to be accessible.
 	**/
 	public static function resolveClass( name : String ) : Class<Dynamic> untyped {
-		var cl : Class<Dynamic>;
+		#if php
+//			php.Boot.__require_once(StringTools.replace(name, '.', '/'));
+			var c = untyped __php__("php_Boot::__qtype($name)");
+			if(__php__("$c instanceof __classtype__"))
+				return c;
+			else
+				return null;
+		#else
+			var cl : Class<Dynamic>;
 		#if flash9
 			try {
 				cl = __as__(__global__["flash.utils.getDefinitionByName"](name),Class);
@@ -181,10 +219,11 @@ class Type {
 		#else
 			cl = null;
 		#end
-		// ensure that this is a class
-		if( cl == null || cl.__name__ == null )
-			return null;
-		return cl;
+			// ensure that this is a class
+			if( cl == null || cl.__name__ == null )
+				return null;
+			return cl;
+		#end
 	}
 
 
@@ -193,7 +232,14 @@ class Type {
 		to be accessible.
 	**/
 	public static function resolveEnum( name : String ) : Enum untyped {
-		var e : Dynamic;
+		#if php
+			var e = untyped __php__("php_Boot::__qtype($name)");
+			if(untyped __php__("$e instanceof __enumtype__"))
+				return e;
+			else
+				return null;
+		#else
+			var e : Dynamic;
 		#if flash9
 			try {
 				e = __global__["flash.utils.getDefinitionByName"](name);
@@ -223,10 +269,11 @@ class Type {
 		#else
 			e = null;
 		#end
-		// ensure that this is an enum
-		if( e == null || e.__ename__ == null )
-			return null;
-		return e;
+			// ensure that this is an enum
+			if( e == null || e.__ename__ == null )
+				return null;
+			return e;
+		#end
 	}
 
 	/**
@@ -258,6 +305,12 @@ class Type {
 			if( args.length > 8 )
 				throw "Too many arguments";
 			return __new__(cl,args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7]);
+		#elseif php
+			if(cl.__qname__ == 'Array') return [];
+			if(cl.__qname__ == 'String') return args[0];
+			var c = cl.__rfl__();
+			if(c == null) return null;
+			return __php__("$inst = $c->getConstructor() ? $c->newInstanceArgs($args) : $c->newInstanceArgs()");
 		#else
 			return null;
 		#end
@@ -289,6 +342,29 @@ class Type {
 			var o = __dollar__new(null);
 			__dollar__objsetproto(o,cl.prototype);
 			return o;
+		#elseif php
+			if(cl.__qname__ == 'Array') return [];
+			if(cl.__qname__ == 'String') return '';
+			try {
+				php.Boot.skip_constructor = true;
+				var rfl = cl.__rfl__();
+				if(rfl == null) return null;
+				var m = __php__("$rfl->getConstructor()");
+				var nargs : Int = m.getNumberOfRequiredParameters();
+				var i;
+				if(nargs > 0) {
+					var args = __call__("array_fill", 0, m.getNumberOfRequiredParameters(), null);
+					i = __php__("$rfl->newInstanceArgs($args)");
+				} else {				
+					i = __php__("$rfl->newInstanceArgs(array())");
+				}
+				php.Boot.skip_constructor = false;
+				return i;
+			} catch( e : Dynamic ) {
+				php.Boot.skip_constructor = false;
+				throw "Unable to instantiate " + Std.string(cl);
+			}
+			return null;
 		#else
 			return null;
 		#end
@@ -331,6 +407,24 @@ class Type {
 	public static function getInstanceFields( c : Class<Dynamic> ) : Array<String> {
 		#if flash9
 			return describe(c,true);
+		#elseif php
+			if(untyped c.__qname__ == 'String') return ['substr', 'charAt', 'charCodeAt', 'indexOf', 'lastIndexOf', 'split', 'toLowerCase', 'toUpperCase', 'toString', 'length'];
+			if(untyped c.__qname__ == 'Array') return  ['push', 'concat', 'join', 'pop', 'reverse', 'shift', 'slice', 'sort', 'splice', 'toString', 'copy', 'unshift', 'insert', 'remove', 'iterator', 'length'];
+			untyped __php__("
+			$rfl = $c->__rfl__();
+			if($rfl === null) return array();
+			$ms = $rfl->getMethods();
+			$ps = $rfl->getProperties();
+			$r = array();
+			$internals = array('__construct', '__call', '__get', '__set', '__isset', '__unset', '__toString');
+			foreach($ms as $m) {
+				$n = $m->getName();				
+				if(!$m->isStatic() && ! in_array($n, $internals)) $r[] = $n;
+			}
+			foreach($ps as $p)
+				if(!$p->isStatic()) $r[] = $p->getName();
+			");
+			return untyped __php__("array_values(array_unique($r))");
 		#else
 			var a = Reflect.fields(untyped c.prototype);
 			c = untyped c.__super__;
@@ -356,6 +450,21 @@ class Type {
 			var a = describe(c,false);
 			a.remove("__construct__");
 			return a;
+		#elseif php
+			if(untyped c.__qname__ == 'String') return ['fromCharCode'];
+			if(untyped c.__qname__ == 'Array')  return [];
+			untyped __php__("
+			$rfl = $c->__rfl__();
+			if($rfl === null) return array();
+			$ms = $rfl->getMethods();
+			$ps = $rfl->getProperties();
+			$r = array();
+			foreach($ms as $m)
+				if($m->isStatic()) $r[] = $m->getName();
+			foreach($ps as $p)
+				if($p->isStatic()) $r[] = $p->getName();
+			");
+			return untyped __php__("$r");
 		#else
 			var a = Reflect.fields(c);
 			a.remove(__unprotect__("__name__"));
@@ -376,8 +485,20 @@ class Type {
 	/**
 		Returns all the available constructor names for an enum.
 	**/
-	public static function getEnumConstructs( e : Enum ) : Array<String> {
-		return untyped e.__constructs__;
+	public static function getEnumConstructs( e : Enum ) : Array<String> untyped {		
+		#if php
+			if(__php__("$e->__tname__ == 'Bool'")) return ['true', 'false'];
+			if(__php__("$e->__tname__ == 'Void'")) return [];
+			var rfl = __php__("new ReflectionClass($e->__tname__)");
+			var sps : ArrayAccess<Dynamic> = rfl.getStaticProperties();
+			var r : ArrayAccess<String> = __call__('array');
+			__php__("foreach($sps as $k => $v) $r[] = $k");
+			sps = rfl.getMethods();
+			__php__("foreach($sps as $m) { $n = $m->getName(); if($n != '__construct' && $n != '__toString') $r[] = $n; }");
+			return r;
+		#else
+			return untyped e.__constructs__;
+		#end
 	}
 
 	/**
@@ -463,6 +584,29 @@ class Type {
 			default:
 				return TUnknown;
 			}
+		#elseif php
+			if(v == null) return TNull;
+			if(__call__("is_array", v)) { 
+				if(__call__("is_callable", v)) return TFunction;
+				return TClass(Array);
+			}
+			if(__call__("is_string", v)) {
+				if(__call__("class_exists", v)) return TObject;
+				if(php.Boot.__is_lambda(v)) return TFunction;
+				return TClass(String);
+			}
+			if(__call__("is_bool", v)) return TBool;
+			if(__call__("is_int", v)) return TInt;
+			if(__call__("is_float", v)) return TFloat;
+			if(__php__("$v instanceof Anonymous"))  return TObject;    
+			if(__php__("$v instanceof __enumtype__"))  return TObject;  
+			if(__php__("$v instanceof __classtype__"))  return TObject;  
+    
+			var c = __php__("php_Boot::__ttype(get_class($v))");
+    
+			if(__php__("$c instanceof __enumtype__"))  return TEnum(cast c);
+			if(__php__("$c instanceof __classtype__")) return TClass(cast c);
+			return TUnknown;
 		#else
 			return TUnknown;
 		#end
@@ -494,6 +638,21 @@ class Type {
 			} catch( e : Dynamic ) {
 				return false;
 			}
+		#elseif php
+			try {
+				if( a.tag != b.tag )
+					return false;
+				for( i in 0...__call__("count", a.params))
+					if(getEnum(a.params[i]) != null) {
+						if(!enumEq(a.params[i],b.params[i]))
+							return false;
+					} else {
+						if(!php.Boot.__equal(a.params[i],b.params[i]))
+							return false;
+					}
+			} catch( e : Dynamic ) {
+				return false;
+			}
 		#else
 			if( a[0] != b[0] )
 				return false;
@@ -513,7 +672,7 @@ class Type {
 	public static function enumConstructor( e : Dynamic ) : String {
 		#if neko
 			return new String(e.tag);
-		#elseif flash9
+		#elseif (flash9 || php)
 			return e.tag;
 		#else
 			return e[0];
@@ -526,7 +685,7 @@ class Type {
 	public static function enumParameters( e : Dynamic ) : Array<Dynamic> {
 		#if neko
 			return if( e.args == null ) [] else untyped Array.new1(e.args,__dollar__asize(e.args));
-		#elseif flash9
+		#elseif (flash9 || php)
 			return if( e.params == null ) [] else e.params;
 		#else
 			return e.slice(2);
@@ -537,7 +696,7 @@ class Type {
 		Returns the index of the constructor of an enum
 	**/
 	public inline static function enumIndex( e : Dynamic ) : Int {
-		#if (neko || flash9)
+		#if (neko || flash9 || php)
 			return e.index;
 		#else
 			return e[1];

+ 2 - 0
std/Xml.hx

@@ -234,6 +234,8 @@ extern class Xml {
 			#if swf_mark
 			flash.Lib.current["Xml"] = Xml;
 			#end
+		#elseif php
+			Xml = php.PhpXml__;
 		#end
 		#if !flash9
 		Xml.__name__ = ["Xml"];

+ 5 - 1
std/haxe/Firebug.hx

@@ -84,10 +84,14 @@ class Firebug {
 			#end // flash9
 		#elseif js
 			untyped console[type]( (if( inf == null ) "" else inf.fileName+":"+inf.lineNumber+" : ") + Std.string(v) );
-		#elseif neko
+		#elseif (neko || php)
 			var str = inf.fileName + ":" + inf.lineNumber + " : ";
 			try str += Std.string(v) catch( e : Dynamic ) str += "???";
+			#if neko
 			neko.Lib.print('<script type="text/javascript">console.'+type+'(decodeURIComponent("'+StringTools.urlEncode(str)+'"))</script>');
+			#else
+			php.Lib.print('<script type="text/javascript">console.'+type+'(decodeURIComponent("'+StringTools.urlEncode(str)+'"))</script>');
+			#end
 		#end
 	}
 

+ 37 - 10
std/haxe/Http.hx

@@ -25,10 +25,18 @@
 package haxe;
 
 #if neko
+import neko.net.Host;
+import neko.net.Socket;
+#elseif php
+import php.net.Host;
+import php.net.Socket;
+#end
+
+#if (neko || php)
 private typedef AbstractSocket = {
 	var input(default,null) : haxe.io.Input;
 	var output(default,null) : haxe.io.Output;
-	function connect( host : neko.net.Host, port : Int ) : Void;
+	function connect( host : Host, port : Int ) : Void;
 	function setTimeout( t : Float ) : Void;
 	function write( str : String ) : Void;
 	function close() : Void;
@@ -39,7 +47,7 @@ private typedef AbstractSocket = {
 class Http {
 
 	public var url : String;
-#if neko
+#if (neko || php)
 	public var noShutdown : Bool;
 	public var cnxTimeout : Float;
 	var responseHeaders : Hash<String>;
@@ -54,7 +62,7 @@ class Http {
 	var headers : Hash<String>;
 	var params : Hash<String>;
 
-	#if neko
+	#if (neko || php)
 	public static var PROXY : { host : String, port : Int, auth : { user : String, pass : String } } = null;
 	#end
 
@@ -64,7 +72,7 @@ class Http {
 		params = new Hash();
 		#if js
 		async = true;
-		#elseif neko
+		#elseif (neko || php)
 		cnxTimeout = 10;
 		#end
 	}
@@ -224,7 +232,7 @@ class Http {
 		}
 		if( !r.sendAndLoad(small_url,r,if( param ) { if( post ) "POST" else "GET"; } else null) )
 			onError("Failed to initialize Connection");
-	#elseif neko
+	#elseif (neko || php)
 		var me = this;
 		var output = new haxe.io.BytesOutput();
 		var old = onError;
@@ -235,11 +243,15 @@ class Http {
 		}
 		customRequest(post,output);
 		if( !err )
+		#if neko
 			me.onData(neko.Lib.stringReference(output.getBytes()));
+		#else
+			me.onData(output.getBytes().toString());
+		#end
 	#end
 	}
 
-#if neko
+#if (neko || php)
 
 	public function fileTransfert( argname : String, filename : String, file : haxe.io.Input, size : Int ) {
 		this.file = { param : argname, filename : filename, io : file, size : size };
@@ -252,7 +264,7 @@ class Http {
 			return;
 		}
 		if( sock == null )
-			sock = new neko.net.Socket();
+			sock = new Socket();
 		var host = url_regexp.matched(2);
 		var portString = url_regexp.matched(3);
 		var request = url_regexp.matched(4);
@@ -361,16 +373,19 @@ class Http {
 		}
 		try {
 			if( Http.PROXY != null )
-				sock.connect(new neko.net.Host(Http.PROXY.host),Http.PROXY.port);
+				sock.connect(new Host(Http.PROXY.host),Http.PROXY.port);
 			else
-				sock.connect(new neko.net.Host(host),port);
+				sock.connect(new Host(host),port);
 			sock.write(b.toString());
 			if( multipart ) {
 				var bufsize = 4096;
 				var buf = haxe.io.Bytes.alloc(bufsize);
 				while( file.size > 0 ) {
 					var size = if( file.size > bufsize ) bufsize else file.size;
-					var len = try file.io.readBytes(buf,0,size) catch( e : haxe.io.Eof ) break;
+					var len = 0;
+					try {
+						len = file.io.readBytes(buf,0,size);
+					} catch( e : haxe.io.Eof ) break;
 					sock.output.writeFullBytes(buf,0,len);
 					file.size -= len;
 				}
@@ -450,7 +465,11 @@ class Http {
 				}
 			}
 		}
+		#if neko
 		var headers = neko.Lib.stringReference(b.getBytes()).split("\r\n");
+		#else
+		var headers = b.getBytes().toString().split("\r\n");
+		#end
 		var response = headers.shift();
 		var rp = response.split(" ");
 		var status = Std.parseInt(rp[1]);
@@ -527,7 +546,11 @@ class Http {
 				len += chunk_buf.length;
 				chunk_buf = null;
 			}
+			#if neko
 			if( chunk_re.match(neko.Lib.stringReference(buf)) ) {
+			#else
+			if( chunk_re.match(buf.toString()) ) {
+			#end
 				var p = chunk_re.matchedPos();
 				if( p.len <= len ) {
 					var cstr = chunk_re.matched(1);
@@ -582,7 +605,11 @@ class Http {
 	}
 
 #if !flash
+	#if php
+	public static function requestUrl( url : String ) : String {
+	#else
 	public static function request( url : String ) : String {
+	#end
 		var h = new Http(url);
 	#if js
 		h.async = false;

+ 2 - 0
std/haxe/Log.hx

@@ -33,6 +33,8 @@ class Log {
 		untyped __dollar__print(infos.fileName+":"+infos.lineNumber+": ",v,"\n");
 		#elseif js
 		untyped js.Boot.__trace(v,infos);
+		#elseif php
+		untyped php.Boot.__trace(v,infos);
 		#end
 	}
 

+ 3 - 1
std/haxe/Md5.hx

@@ -32,6 +32,8 @@ class Md5 {
 	public static function encode( s : String ) : String {
 		#if neko
 			return untyped new String(base_encode(make_md5(s.__s),"0123456789abcdef".__s));
+		#elseif php
+			return untyped __call__("md5", s);
 		#else
 			return inst.doEncode(s);
 		#end
@@ -40,7 +42,7 @@ class Md5 {
 	#if neko
 	static var base_encode = neko.Lib.load("std","base_encode",2);
 	static var make_md5 = neko.Lib.load("std","make_md5",1);
-	#else
+	#elseif !php
 
 /*
  * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message

+ 30 - 0
std/haxe/Resource.hx

@@ -25,7 +25,34 @@
 package haxe;
 
 class Resource {
+#if php
+	static function cleanName(name : String) : String {
+		return ~/[\\\/:?"*<>|]/.replace(name, '_');
+	}
+	
+	static function getDir() {
+		return untyped __call__('dirname', __php__('__FILE__'))+"/../../res";
+	}
+	
+	static function getPath(name : String) {
+		return getDir()+'/'+cleanName(name);
+	}
 
+	public static function listNames() : Array<String> {
+		var a = php.FileSystem.readDirectory(getDir());
+		if(a[0] == '.') a.shift();
+		if(a[0] == '..') a.shift();
+		return a;
+	}
+	
+	public static function getString( name : String ) {
+		return php.io.File.getContent(getPath(name));
+	}
+	
+	public static function getBytes( name : String ) {
+		return php.io.File.getBytes(getPath(name));
+	}
+#else
 	static var content : Array<{ name : String, data : #if (neko || flash9) String #else Array<String> #end }>;
 
 	public static function listNames() : Array<String> {
@@ -68,8 +95,11 @@ class Resource {
 		#if neko
 		var tmp = untyped __resources__();
 		content = untyped Array.new1(tmp,__dollar__asize(tmp));
+		#elseif php
+		content = null;
 		#else
 		content = untyped __resources__();
 		#end
 	}
+#end
 }

+ 16 - 1
std/haxe/Serializer.hx

@@ -190,7 +190,7 @@ class Serializer {
 				#if flash9
 				var v : Array<Dynamic> = v;
 				#end
-				var l = #if (neko || flash9) v.length #else v[untyped "length"] #end;
+				var l = #if (neko || flash9) v.length #elseif php untyped __call__("count", v) #else v[untyped "length"] #end;
 				for( i in 0...l ) {
 					if( v[i] == null )
 						ucount++;
@@ -328,6 +328,21 @@ class Serializer {
 				for( p in pl )
 					serialize(p);
 			}
+			#elseif php
+			if( useEnumIndex ) {
+				buf.add(":");
+				buf.add(v.index);
+			} else
+				serializeString(v.tag);
+			buf.add(":");
+			var l : Int = untyped __call__("count", v.params);
+			if( l == 0 || v.params == null)
+				buf.add(0);
+			else {
+				buf.add(l);
+				for( i in 0...l )
+					serialize(v.params[i]);
+			}
 			#else
 			if( useEnumIndex ) {
 				buf.add(":");

+ 4 - 2
std/haxe/Timer.hx

@@ -25,8 +25,8 @@
 package haxe;
 
 class Timer {
-
-	#if !neko
+	#if (neko || php)
+	#else
 
 	private var id : Null<Int>;
 
@@ -91,6 +91,8 @@ class Timer {
 			return flash.Lib.getTimer() / 1000;
 		#elseif neko
 			return neko.Sys.time();
+		#elseif php
+			return php.Sys.time();
 		#elseif js
 			return Date.now().getTime() / 1000;
 		#else

+ 7 - 0
std/haxe/io/Bytes.hx

@@ -134,6 +134,8 @@ class Bytes {
 		#elseif flash9
 		b.position = pos;
 		return b.readUTFBytes(len);
+		#elseif php
+		return untyped __call__("call_user_func_array", "pack", __call__("array_merge", ["C*"], __call__("array_slice", b, pos, len)));
 		#else
 		var s = "";
 		var b = b;
@@ -166,6 +168,8 @@ class Bytes {
 		#elseif flash9
 		b.position = 0;
 		return b.readUTFBytes(length);
+		#elseif php
+		return untyped __call__("call_user_func_array", "pack", __call__("array_merge", ["C*"], b));
 		#else
 		return readString(0,length);
 		#end
@@ -197,6 +201,9 @@ class Bytes {
 		var b = new flash.utils.ByteArray();
 		b.writeUTFBytes(s);
 		return new Bytes(b.length,b);
+		#elseif php
+		var a : Array<Int> = untyped __call__("array_values", __call__("unpack", "C*",  s));
+		return new Bytes(a.length,a);
 		#else
 		var a = new Array();
 		// utf8-decode

+ 4 - 0
std/haxe/io/BytesBuffer.hx

@@ -97,7 +97,11 @@ class BytesBuffer {
 		#else
 		var bytes = new Bytes(b.length,b);
 		#end
+		#if php
+		untyped __call__('unset', b);
+		#else
 		b = null;
+		#end
 		return bytes;
 	}
 

+ 4 - 0
std/haxe/io/Input.hx

@@ -128,6 +128,8 @@ class Input {
 	public function readFloat() : Float {
 		#if neko
 			return _float_of_bytes(untyped read(4).b,bigEndian);
+		#elseif php
+			return untyped __call__('unpack', 'f', readString(4))[1];
 		#else
 			throw "Not implemented";
 			return 0;
@@ -137,6 +139,8 @@ class Input {
 	public function readDouble() : Float {
 		#if neko
 			return _double_of_bytes(untyped read(8).b,bigEndian);
+		#elseif php
+			return untyped __call__('unpack', 'd', readString(8))[1];
 		#else
 			throw "Not implemented";
 			return 0;

+ 4 - 0
std/haxe/io/Output.hx

@@ -92,6 +92,8 @@ class Output {
 	public function writeFloat( x : Float ) {
 		#if neko
 		write(untyped new Bytes(4,_float_bytes(x,bigEndian)));
+		#elseif php
+		write(untyped Bytes.ofString(__call__('pack', 'f', x)));
 		#else
 		throw "Not implemented";
 		#end
@@ -100,6 +102,8 @@ class Output {
 	public function writeDouble( x : Float ) {
 		#if neko
 		write(untyped new Bytes(8,_double_bytes(x,bigEndian)));
+		#elseif php
+		write(untyped Bytes.ofString(__call__('pack', 'd', x)));
 		#else
 		throw "Not implemented";
 		#end

+ 5 - 0
std/haxe/remoting/ContextAll.hx

@@ -49,6 +49,11 @@ class ContextAll extends Context {
 		var f = path2.pop();
 		var o = flash.Lib.eval(path2.join("."));
 		var m = Reflect.field(o,f);
+		#elseif php
+		var path2 = path.copy();
+		var f = path2.pop();
+		var o = Type.resolveClass(path2.join("."));
+		var m = Reflect.field(o,f);
 		#else
 		var o = null;
 		var m = null;

+ 1 - 1
std/haxe/remoting/HttpConnection.hx

@@ -63,7 +63,7 @@ class HttpConnection implements Connection {
 		return new haxe.Unserializer(data).unserialize();
 	}
 
-	#if (js || neko)
+	#if (js || neko || php)
 
 	public static function urlConnect( url : String ) : Connection {
 		return new HttpConnection(url,[]);

+ 4 - 2
std/haxe/remoting/SocketProtocol.hx

@@ -33,6 +33,8 @@ typedef Socket =
 		js.XMLSocket
 	#elseif neko
 		neko.net.Socket
+	#elseif php
+		php.net.Socket
 	#else
 		Dynamic
 	#end
@@ -137,7 +139,7 @@ class SocketProtocol {
 
 	public function sendMessage( msg : String ) {
 		var e = encodeMessageLength(msg.length + 3);
-		#if neko
+		#if (neko || php)
 		var o = socket.output;
 		o.writeByte(e.c1);
 		o.writeByte(e.c2);
@@ -188,7 +190,7 @@ class SocketProtocol {
 		return s.unserialize();
 	}
 
-	#if neko
+	#if (neko || php)
 
 	public function readMessage() {
 		var i = socket.input;

+ 2 - 0
std/haxe/unit/TestRunner.hx

@@ -62,6 +62,8 @@ class TestRunner {
 			}
 		#elseif neko
 			__dollar__print(v);
+		#elseif php
+			php.Lib.print(v);
 		#elseif js
 			var msg = StringTools.htmlEscape(js.Boot.__string_rec(v,"")).split("\n").join("<br/>");
 			var d = document.getElementById("haxe:trace");

+ 645 - 0
std/php/Boot.hx

@@ -0,0 +1,645 @@
+package php;
+
+class Boot {
+	public static function __trace(v,i : haxe.PosInfos) {
+		var msg = if( i != null ) i.fileName+":"+i.lineNumber+": " else "";
+		untyped __call__("echo", msg+ __string_rec(v)+"<br/>"); // TODO: __unhtml
+	}
+	
+	static public function __anonymous(?p : Dynamic) : Dynamic {
+		untyped __php__("$o = new Anonymous();
+		if(is_array($p)) {
+			foreach($p as $k => $v) {
+				$o->$k = $v;
+			}
+		}
+		return $o");
+	}
+	
+	static private var __cid = 0;
+	static public var __scopes = [];
+	static public function __closure(locals : ArrayAccess<Dynamic>, params : String, body : String) : String {
+		var cid = __cid++;
+		var n = "__closure__"+cid+"__";
+//		if(locals == null) locals = [];
+		untyped __php__("php_Boot::$__scopes[$n] = array('scope' => null, 'locals' => $locals)");
+		var f : String = untyped __call__(
+			"create_function", 
+			params, 
+			"$__this =& php_Boot::$__scopes['"+n+"']['scope'];\nforeach(array_keys(php_Boot::$__scopes['"+n+"']['locals']) as ${'%k'}) ${${'%k'}} =& php_Boot::$__scopes['"+n+"']['locals'][${'%k'}];\n"+body);
+		var nl = "__"+f.substr(1)+"__";
+		untyped __php__("php_Boot::$__scopes[$nl] =& php_Boot::$__scopes[$n]");
+		return f;
+	}
+	
+	static public function __is_lambda(s : String) : Bool {
+		return untyped __call__("is_string", s) && s.substr(0, 8) == __call__("chr", 0) + "lambda_";
+	}
+	
+	static public function __array() : Dynamic {
+		return untyped __call__("func_get_args");
+	}
+	
+	static public function __array_empty() : Dynamic {
+		return untyped __call__("array");
+	}
+	
+	static public function __array_null() : Dynamic {
+		return null;
+	}
+	
+	static public function __array_copy(a : ArrayAccess<Dynamic>) : Dynamic {
+		return cast a;
+	}
+	
+	static public function __array_iterator<T>(arr : Dynamic) : Iterator<T> {
+		return untyped __php__("new HArrayIterator($arr)");
+	}
+	
+	static public function __array_sort<T>(arr : Array<T>, f : T -> T -> Int) : Void {
+		var i = 0;
+		var l = arr.length;
+		while( i < l ) {
+			var swap = false;
+			var j = 0;
+			var max = l - i - 1;
+			while( j < max ) {
+				if( f(arr[j],arr[j+1]) > 0 ) {
+					var tmp = arr[j+1];
+					arr[j+1] = arr[j];
+					arr[j] = tmp;
+					swap = true;
+				}
+				j += 1;
+			}
+			if(!swap) break;
+			i += 1;
+		}	
+	}
+
+	static public function __array_insert<T>(arr : Array<T>,  pos : Int, x : T) : Void {
+		untyped __php__("array_splice")(arr, pos, 0, __call__("array", x));
+	}
+	
+	static public function __array_remove<T>(arr : Array<T>, x : T) : Bool {
+		for(i in 0...arr.length)
+			if(arr[i] == x) {
+				untyped __call__("unset", arr[i]);
+				arr = untyped __call__("array_values", arr);
+				return true;
+			}
+		return false;
+	}
+	
+	static public function __array_remove_at(arr : Array<Dynamic>, pos : Int) : Bool {
+		if(untyped __php__("array_key_exists")(pos, arr)) {
+			untyped __php__("unset")(arr[pos]);
+			return true;
+		} else return false;
+	}
+	
+	static public function __array_splice(arr : Array<Dynamic>, pos : Int, len : Int) : Bool {
+		if(len < 0) len = 0;
+		return untyped __php__("array_splice")(arr, pos, len);
+	}
+	
+	static public function __array_slice(arr : Array<Dynamic>, pos : Int, ?end : Int) : Bool {
+		if(end == null)
+			return untyped __php__("array_slice")(arr, pos);
+		else
+			return untyped __php__("array_slice")(arr, pos, end-pos);
+	}
+  
+	static public function __array_set<T>(arr : Array<Dynamic>, pos : Int, v : T) : T untyped {
+		if(__call__("is_int", pos)) {
+			var l = __call__("count", arr);
+			if(l < pos) {
+			__call__("array_splice", arr, l, 0, __call__("array_fill", l, pos-l, null)); 
+			}
+		}
+		__php__("$arr[$pos] = $v");
+		return v;
+	}
+	
+	static public function __char_code_at(s : String, pos : Int) : Null<Int> untyped {
+		if(__call__("empty", s) || pos >= s.length) return null;
+		return s.cca(pos);
+	}
+	
+	static public function __substr(s : String, pos : Int, ?len : Int) {
+		if( pos != null && pos != 0 && len != null && len < 0 ) return '';
+		if( len == null ) len = s.length;
+		if( pos < 0 ) {
+			pos = s.length + pos;
+			if( pos < 0 ) pos = 0;
+		} else if( len < 0 )
+			len = s.length + len - pos;
+		var s : Bool = untyped __php__("substr")(s, pos, len);
+		if(untyped __physeq__(s, false)) return "" else return untyped s;
+	}
+
+	static public function __index_of(s : String, value : String, ?startIndex : Int) {
+		var x = untyped __php__("strpos")(s, value, startIndex);
+		if(untyped __physeq__(x, false))
+			return -1;
+		else
+			return x;
+	}
+	
+	static public function __last_index_of(s : String, value : String, ?startIndex : Int) {
+		var x = untyped __php__("strrpos")(s, value, startIndex == null ? null : s.length - startIndex);
+		if(untyped __php__("$x === false")) 
+			return -1
+		else
+			return x;
+	}
+	
+	static public function __instanceof(v : Dynamic, t : Dynamic) {
+		if(t == null) return false;
+		switch(t.__tname__) {
+			case "Array":
+				return untyped __call__("is_array", v);
+			case "String":
+				return untyped __call__("is_string", v) && !__is_lambda(v);
+			case "Bool":
+				return untyped __call__("is_bool", v);
+			case "Int":
+				return untyped __call__("is_int", v);
+			case "Float":
+				return untyped __call__("is_float", v) || __call__("is_int", v);
+			case "Dynamic":
+				return true;
+			case "Class":
+				return untyped __php__("$v instanceof __classtype__") && __php__("$v->__tname__ != 'Enum'");
+			case "Enum":
+				return untyped __php__("$v instanceof __enumtype__");
+			default:
+				return untyped __call__("is_a", v, t.__tname__);
+		}
+	}
+	
+	static public function __shift_right(v : Int, n : Int) {
+		untyped __php__("$z = 0x80000000;  
+		if ($z & $v) { 
+			$v = ($v>>1);
+			$v &= (~$z);
+			$v |= 0x40000000;
+			$v = ($v>>($n-1));
+		} else $v = ($v>>$n)");
+		return v;
+	}
+	
+	static public function __error_handler(errno : Int, errmsg : String, filename : String, linenum : Int, vars : Dynamic) {
+		var msg = errmsg + " (errno: " + errno + ") in " + filename + " at line #" + linenum;
+		var e = new php.HException(msg, errmsg, errno);
+		e.setFile(filename);
+		e.setLine(linenum);
+		untyped __php__("throw $e");
+		return null;
+	}
+	
+	static public function __exception_handler(e : Dynamic) {
+		var msg = "<pre>Uncaught exception: <b>"+e.getMessage()+"</b>\nin file: <b>"+e.getFile()+"</b> line <b>"+e.getLine()+"</b>\n\n"+e.getTraceAsString()+"</pre>";
+		untyped __php__("die($msg)");
+	}
+  
+	static public function __equal(x : Dynamic, y : Dynamic) untyped {
+		if(__call__("is_null", x)) {
+			return __call__("is_null", y);
+		} else if(__call__("is_null", y)) {
+			return false;
+		} else  if((__call__("is_float", x) || __call__("is_int", x)) && (__call__("is_float", y) || __call__("is_int", y))) {
+			return __php__("$x == $y");
+		} else {
+			return __php__("$x === $y");
+		}
+	}
+
+	static private var __qtypes : Array<Dynamic>;
+	static private var __ttypes : Array<Dynamic>;
+	static private var __tpaths : Array<Dynamic>;
+	static public function __register_type(t : Dynamic) {
+		untyped __php__(
+		"php_Boot::$__qtypes[$t->__qname__] = $t;
+		php_Boot::$__ttypes[$t->__tname__] = $t;
+		if($t->__path__ !== null)
+			php_Boot::$__tpaths[$t->__tname__] = $t->__path__");
+	}
+
+	static public function __qtype(n) untyped {
+		if(__call__("isset", __qtypes[n]))
+			return __qtypes[n];
+		else 
+			return null;
+	}
+
+	static public function __ttype(n) untyped {
+		if(__call__("isset", __ttypes[n]))
+			return __ttypes[n];
+		else 
+			return null;
+	}
+	
+	static public function __deref(byref__o : Dynamic) {
+		return byref__o;
+	}
+	
+	static public function __byref__array_get(byref__o : Dynamic, index : Dynamic) {
+		return untyped byref__o[index];
+	}
+
+	static private var __resources = [];
+	static public function __res(n : String) : String untyped {
+		if(! __php__("isset(self::$__resources[$n])")) {
+			var file = __php__("dirname(__FILE__).'/../../res/'.$n");
+			if(!__call__("file_exists", file))
+				throw "Invalid Resource name: " + n;
+			__php__("self::$__resources[$n] = file_get_contents($file)");
+		}
+		return __php__("self::$__resources[$n]");
+	}
+
+	public static function __string_call(s : Dynamic, method : String, params : ArrayAccess<Dynamic>) {
+		if(!untyped __call__("is_string", s)) return untyped __php__("call_user_func_array(array($s, $method), $params)");
+		var s2 : String = s;
+		switch(method) {
+			case "toUpperCase": return untyped s2.toUpperCase();
+			case "toLowerCase": return untyped s2.toLowerCase();
+			case "charAt"     : return untyped s2.charAt(params[0]);
+			case "charCodeAt" : return untyped s2.charCodeAt(params[0]);
+			case "indexOf"    : return untyped s2.indexOf(params[0], params.length > 1 ? params[1] : null);
+			case "lastIndexOf": return untyped s2.lastIndexOf(params.length > 1 ? params[1] : null);
+			case "split"      : return untyped s2.split(params[0]);
+			case "substr"     : return untyped s2.substr(params[0], params.length > 1 ? params[1] : null);
+			default: throw "Invalid Operation: " + method;
+		}
+	}
+	
+	public static function __array_call(arr : Array<Dynamic>, method : String, params : ArrayAccess<Dynamic>) {
+		if(!untyped __call__("is_array", arr)) return untyped __php__("call_user_func_array(array($arr, $method), $params)");
+		switch(method) {
+			case "concat"  : return untyped arr.concat(params[0]);
+			case "copy"    : return untyped arr.copy();
+			case "insert"  : return untyped arr.insert(params[0], params[1]);
+			case "iterator": return untyped arr.iterator();
+			case "join"    : return untyped arr.join(params[0]);
+			case "pop"     : return untyped arr.pop();
+			case "push"    : return untyped arr.push(params[0]);
+			case "remove"  : return untyped arr.remove(params[0]);
+			case "reverse" : return untyped arr.reverse();
+			case "shift"   : return untyped arr.shift();
+			case "slice"   : return untyped arr.slice(params[0], params.length > 1 ? params[1] : null);
+			case "sort"    : return untyped arr.sort(params[0]);
+			case "splice"  : return untyped arr.splice(params[0], params[1]);
+			case "unshift" : return untyped arr.unshift(params[0]);
+			default: throw "Invalid Operation: " + method;
+		}
+	}
+	
+	public static function __len(o : Dynamic) {
+		return untyped __php__("is_array($o) ? count($o) : (is_string($o) ? strlen($o) : $o->length)");
+	}
+	
+//	public static var __REGISTERED_CLASSES : Array<Dynamic>;
+  
+	static function __init__() untyped {
+		__php__("//error_reporting(0);
+set_error_handler(array('php_Boot', '__error_handler'), E_ALL);
+set_exception_handler(array('php_Boot', '__exception_handler'));
+
+class Anonymous extends stdClass{
+	public function __call($m, $a) {
+		$v = $this->$m;
+		if(is_string($v) && substr($v, 0, 8) == chr(0).'lambda_') {
+			$nl = '__'.substr($v, 1).'__';
+			php_Boot::$__scopes[$nl]['scope'] =& $this;
+		}
+		try {
+			return call_user_func_array($v, $a);
+		} catch(Exception $e) {
+			throw new HException('Unable to call «'.$m.'»');
+		}
+	}
+	
+	public function __set($n, $v) {
+		$this->$n = $v;
+	}
+	
+	public function &__get($n) {
+		if(isset($this->$n))
+			return $this->$n;
+		$null = null;
+		return $null;
+	}
+	
+	public function __isset($n) {
+		return isset($this->$n);
+	}
+	
+	public function __unset($n) {
+		unset($this->$n);
+	}
+	
+	public function __toString() {
+		return php_Boot::__string_rec($this, null);
+	}
+}
+
+class __type__ {
+	public $__tname__;
+	public $__qname__;  
+	public $__path__;  
+	public function __construct($cn, $qn, $path = null) {
+		$this->__tname__ = $cn;
+		$this->__qname__ = $qn;
+		$this->__path__ = $path;
+	}
+	
+	public function toString()   { return $this->__toString(); }
+	
+	public function __toString() {
+		return $this->__qname__;
+	}
+
+	private $rfl = false;
+	public function __rfl__() {
+		if($this->rfl !== false) return $this->rfl;
+		if(class_exists($this->__tname__))
+			$this->rfl = new ReflectionClass($this->__tname__);
+		else
+			$this->rfl = null;
+		return $this->rfl;
+	}
+	
+	public function __call($n, $a) {
+		return call_user_func_array(array($this->__tname__, $n), $a);
+	}
+
+	public function __get($n) {
+		if(($r = $this->__rfl__())==null) return null;
+		if($r->hasProperty($n))
+			return $r->getStaticPropertyValue($n);
+		else if($r->hasMethod($n))
+			return array($r, $n);
+		else
+			return null;
+	}
+
+	public function __set($n, $v) {
+		if(($r = $this->__rfl__())==null) return null;
+		return $r->setStaticPropertyValue($n, $v);
+	}
+
+	public function __isset($n) {
+		if(($r = $this->__rfl__())==null) return null;
+		return $r->hasProperty($n) || $r->hasMethod($n);
+	}
+}
+
+class __classtype__ extends __type__ { }
+
+class __enumtype__ extends __type__ {}
+
+class __interfacetype__ extends __type__ { }
+
+class HArrayIterator {
+	private $a;
+	private $i;
+	public function __construct($a) {
+		$this->a = $a;
+		$this->i = 0;
+	}
+	
+	public function next() {
+		if(!$this->hasNext()) return null;
+		return $this->a[$this->i++];
+	}
+	
+	public function hasNext() {
+		return $this->i < count($this->a);
+	}
+}
+
+class HException extends Exception {
+	public function __construct($e, $message = null, $code = null, $p = null) { if( !php_Boot::$skip_constructor ) {
+		$message = php_Boot::__string_rec($e, null) . $message;
+		parent::__construct($message,$code);
+		$this->e = $e;
+		$this->p = $p;
+	}}
+	public $e;
+	public $p;
+	public function setLine($l) {
+		$this->line = $l;
+	}
+	public function setFile($f) {
+		$this->file = $f;
+	}
+}
+
+class enum {
+	public function __construct($tag, $index, $params = null) { $this->tag = $tag; $this->index = $index; $this->params = $params; }
+	public $tag;
+	public $index;
+	public $params;
+
+	public function __toString() {
+		return $this->tag;
+	}
+}
+
+php_Boot::$__qtypes = array();
+php_Boot::$__ttypes = array();
+php_Boot::$__tpaths = array();
+php_Boot::__register_type(new __classtype__('String',  'String'));
+php_Boot::__register_type(new __classtype__('Array',   'Array'));
+php_Boot::__register_type(new __classtype__('Int',     'Int'));
+php_Boot::__register_type(new __classtype__('Float',   'Float'));
+php_Boot::__register_type(new __classtype__('Class',   'Class'));
+php_Boot::__register_type(new __classtype__('Enum',    'Enum'));
+php_Boot::__register_type(new __classtype__('Dynamic', 'Dynamic'));
+php_Boot::__register_type(new __enumtype__('Bool',     'Bool'));
+php_Boot::__register_type(new __enumtype__('Void',     'Void'));
+
+
+$_lib_dir = dirname(__FILE__) . '/..';
+$_autload_cache_file = $_lib_dir . '/../cache/haxe_autoload.php';
+if(!file_exists($_autload_cache_file)) {
+	function buildPaths($d, &$a, $pack) {
+		$h = opendir($d);
+		while (false !== ($f = readdir($h))) {
+			$p = $d.'/'.$f;
+			if($f == '.' || $f == '..')
+				continue;
+			if(is_file($p) && substr($f, -4) == '.php') {
+				$bn = basename($f, '.php');
+				if(substr($bn, -6) == '.class') {
+					$bn = substr($bn, 0, -6);
+					$t = 0;
+				} else if(substr($bn, -5) == '.enum') {
+					$bn = substr($bn, 0, -5);
+					$t = 1;
+				} else if(substr($bn, -10) == '.interface') {
+					$bn = substr($bn, 0, -10);
+					$t = 2;
+				} else 
+					continue;
+				$qname = ($bn == 'HList' && empty($pack)) ? 'List' : join(array_merge($pack, array($bn)), '.');
+				$a[] = array(
+					'path' => $p,
+					'name' => $bn,
+					'type' => $t,
+					'qname' => $qname,
+					'phpname' => join(array_merge($pack, array($bn)), '_')
+				);
+			} else if(is_dir($p))
+				buildPaths($p, $a, array_merge($pack, array($f)));
+		}
+		closedir($h);
+	}
+	
+	$a = array();
+	
+	buildPaths($_lib_dir, $a, array());
+	
+	$content = '<?php\n\n';
+	for($i=0;$i<count($a);$i++) {
+		$content .= 'php_Boot::__register_type(new ';
+		$t = null;
+		if($a[$i]['type'] == 0) {
+			$t = new __classtype__($a[$i]['phpname'], $a[$i]['qname'], $a[$i]['path']);
+			$content .= '__classtype__';
+		} else if($a[$i]['type'] == 1) {
+			$t = new __enumtype__($a[$i]['phpname'], $a[$i]['qname'], $a[$i]['path']);
+			$content .= '__enumtype__';
+		} else {
+			$t = new __interfacetype__($a[$i]['phpname'], $a[$i]['qname'], $a[$i]['path']);
+			$content .= '__interfacetype__';
+		}
+		php_Boot::__register_type($t);
+		$content .= '(\\''.$a[$i]['phpname'].'\\', \\''.$a[$i]['qname'].'\\', \\''.$a[$i]['path'].'\\'));\n';
+	}
+	try {
+		file_put_contents($_autload_cache_file, $content);
+	} catch(Exception $e) {}
+} else {
+	require($_autload_cache_file);
+}
+
+function __haxe_autoload($name) {
+	if(!isset(php_Boot::$__tpaths[$name])) return false;
+	require_once php_Boot::$__tpaths[$name];
+	return true;
+}
+spl_autoload_register('__haxe_autoload')");
+	}
+
+	static public function __string(o : Dynamic) {
+		if( o == null )
+			return "null";		
+		if(untyped __call__("is_int", o) || __call__("is_float", o))
+			return o;
+		if(untyped __call__("is_bool", o))
+			return o ? "true" : "false";
+		if(untyped __call__("is_object", o)) {
+			var c = untyped __call__("get_class", o);
+			if(untyped __php__("$o instanceof Anonymous")) {
+				return "Object";
+			} else if(untyped __php__("$o instanceof __type__")) {
+				return untyped __qtype(o.__qname__);
+			} else {
+				if(untyped __call__("is_callable", [o, "__toString"]))
+					return o.__toString();
+				else
+					return "[" + __ttype(c) + "]";
+			}
+		}
+		
+		if(untyped __call__("is_string", o)) {
+			if(__is_lambda(o)) return "«function»";
+			return o;
+		}
+		if(untyped __call__("is_array", o)) {
+			if(untyped __call__("is_callable", o)) return "«function»";
+			return "Array";
+		}
+		
+		return '';
+	}
+	
+	static public function __string_rec(o : Dynamic, ?s : String) {
+		if( o == null )
+			return "null";
+		if( s.length >= 5 )
+			return "<...>"; // too much deep recursion
+		
+		if(untyped __call__("is_int", o) || __call__("is_float", o))
+			return o;
+			
+		if(untyped __call__("is_bool", o))
+			return o ? "true" : "false";
+			
+		if(untyped __call__("is_object", o)) {
+			var c = untyped __call__("get_class", o);
+			if(untyped __php__("$o instanceof enum")) {
+				var b : String = o.tag;
+				if(!untyped __call__("empty", o.params)) {
+					s += "\t";
+					b += '(';
+					for( i in 0...untyped __call__("count", o.params) ) {
+						if(i > 0) 
+							b += ', ' + __string_rec(o.params[i],s);
+						else
+							b += __string_rec(o.params[i],s);
+					}
+					b += ')';
+				}
+				return b;
+			} else if(untyped __php__("$o instanceof Anonymous")) {
+				var rfl = untyped __php__("new ReflectionObject($o)");
+				var b = "{\n";
+				s += "\t";
+				var properties : Array<Dynamic> = rfl.getProperties();
+				for(prop in properties) {
+					var f : String = prop.getName();
+					if(b.length != 2)
+						b += ", \n";
+					b += s + f + " : " + __string_rec(prop.getValue(o), s);
+				}
+				s = s.substr(1);
+				b += "\n" + s + "}";
+				return b;
+			} else if(untyped __php__("$o instanceof __type__")) {
+				return untyped o.__qname__;
+			} else {
+				if(untyped __call__("is_callable", [o, "toString"]))
+					return untyped __php__("$o->toString()");
+				else if(untyped __call__("is_callable", [o, "__toString"]))
+					return o.__toString();
+				else
+					return "[" + __ttype(c) + "]";
+			}
+		}
+			
+		if(untyped __call__("is_string", o)) {
+			if(__is_lambda(o)) return "«function»";
+			if(s != null)
+				return '"'+untyped __call__("str_replace", '"', '\\"', o)+'"';
+			else
+				return o;
+		}
+			
+		if(untyped __call__("is_array", o)) {
+			if(untyped __call__("is_callable", o)) return "«function»";
+			var str = "[";
+			s += "\t";
+			for( i in 0...untyped __call__("count", o) )
+				str += (if (i > 0) ", " else "")+__string_rec(untyped o[i],s);
+			str += "]";
+			return str;
+		}
+		
+		return '';
+	}
+	static public var skip_constructor = false;
+}

+ 945 - 0
std/php/Curl.hx

@@ -0,0 +1,945 @@
+package php;
+/**
+* TODO: TEST IT!
+*/
+class Curl {
+	var h : Void;
+	public inline function new(?url : String) {
+		if(url != null)
+			h = untyped __call__("curl_init", url);
+		else
+			h = untyped __call__("curl_init");
+	}
+	
+	public inline function close() {
+		untyped __call__("curl_close", h);
+	}
+	
+	public function clone() {
+		var n = new Curl();
+		untyped n.h = untyped __call__("curl_copy_handle", h);
+		return n;
+	}
+	
+	/**
+	* CURLE_OK = 0,
+	* CURLE_UNSUPPORTED_PROTOCOL,    1
+	* CURLE_FAILED_INIT,             2
+	* CURLE_URL_MALFORMAT,           3
+	* CURLE_URL_MALFORMAT_USER,      4 - NOT USED
+	* CURLE_COULDNT_RESOLVE_PROXY,   5
+	* CURLE_COULDNT_RESOLVE_HOST,    6
+	* CURLE_COULDNT_CONNECT,         7
+	* CURLE_FTP_WEIRD_SERVER_REPLY,  8
+	*/	
+	public inline function errNo() : Int {
+		return untyped __call__("curl_errno", h);
+	}
+	
+	public inline function error() : String {
+		return untyped __call__("curl_error", h);
+	}
+	
+	public inline function execute() : Bool {
+		return untyped __call__("curl_exec", h);
+	}
+	
+	public inline function executeTransfer() : String {
+		setReturnTransfer(true);
+		var r : String = untyped __call__("curl_exec", h);
+		if(untyped r == false) 
+			return null;
+		else
+			return r;
+	}
+	
+	public inline function version(?age : Int) : {
+		version_number : Int,
+		version : String,
+		ssl_version_number : Int,
+		ssl_version : String,
+		libz_version : String,
+		host : String,
+		age : Int,
+		features : Int,
+		protocols : Array<String> } {
+		var v = untyped __call__("curl_version", age);
+		return php.Boot.__anonymous(v);
+	}
+	/**
+	* Last effective URL
+	*/
+	public inline function getEffectiveUrl() : String {
+		return untyped __call__("curl_getinfo", h, __php__("CURLINFO_EFFECTIVE_URL"));
+	}
+	
+	/**
+	* Last received HTTP code
+	*/
+	// TODO: check return time is really Int
+	public inline function getHttpCode() : Int {
+		return untyped __call__("curl_getinfo", h, __php__("CURLINFO_HTTP_CODE"));
+	}
+	
+	/**
+	* Remote time of the retrieved document, if -1 is returned the time of the document is unknown
+	*/
+	public inline function getFileTime() : Float {
+		return untyped __call__("curl_getinfo", h, __php__("CURLINFO_FILETIME"));
+	}
+	
+	/**
+	* Total transaction time in seconds for last transfer
+	*/
+	public inline function getTotalTime() : Float {
+		return untyped __call__("curl_getinfo", h, __php__("CURLINFO_TOTAL_TIME"));
+	}
+	
+	/**
+	* Time in seconds until name resolving was complete
+	*/
+	public inline function getNameLookupTime() : Float {
+		return untyped __call__("curl_getinfo", h, __php__("CURLINFO_NAMELOOKUP_TIME"));
+	}
+	
+	/**
+	* Time in seconds it took to establish the connection
+	*/
+	public inline function getConnectTime() : Float {
+		return untyped __call__("curl_getinfo", h, __php__("CURLINFO_CONNECT_TIME"));
+	}
+	
+	/**
+	* Time in seconds from start until just before file transfer begins
+	*/
+	public inline function getPreTransferTime() : Float {
+		return untyped __call__("curl_getinfo", h, __php__("CURLINFO_PRETRANSFER_TIME"));
+	}
+	
+	/**
+	* Time in seconds until the first byte is about to be transferred
+	*/
+	public inline function getStartTransferTime() : Float {
+		return untyped __call__("curl_getinfo", h, __php__("CURLINFO_STARTTRANSFER_TIME"));
+	}
+	
+	/**
+	* Time in seconds of all redirection steps before final transaction was started
+	*/
+	public inline function getRedirectTime() : Float {
+		return untyped __call__("curl_getinfo", h, __php__("CURLINFO_REDIRECT_TIME"));
+	}
+	
+	/**
+	* Total number of bytes uploaded
+	*/
+	public inline function getSizeUpload() : Float {
+		return untyped __call__("curl_getinfo", h, __php__("CURLINFO_SIZE_UPLOAD"));
+	}
+	
+	/**
+	* Total number of bytes downloaded
+	*/
+	public inline function getSizeDownload() : Float {
+		return untyped __call__("curl_getinfo", h, __php__("CURLINFO_SIZE_DOWNLOAD"));
+	}
+	
+	/**
+	* Average download speed
+	*/
+	public inline function getSpeedDownload() : Float {
+		return untyped __call__("curl_getinfo", h, __php__("CURLINFO_SPEED_DOWNLOAD"));
+	}
+	
+	/**
+	* Average upload speed
+	*/
+	public inline function getSpeedUpload() : Float {
+		return untyped __call__("curl_getinfo", h, __php__("CURLINFO_SPEED_UPLOAD"));
+	}
+	
+	/**
+	* Total size of all headers received
+	*/
+	// TODO: maybe this can return very big values so a Float is a better option
+	public inline function getHeaderSize() : Int {
+		return untyped __call__("curl_getinfo", h, __php__("CURLINFO_HEADER_SIZE"));
+	}
+	
+	/**
+	* The request string sent. Available since PHP 5.1.3
+	*/
+	public inline function getHeaderOut() : String {
+		return untyped __call__("curl_getinfo", h, __php__("CURLINFO_HEADER_OUT"));
+	}
+	
+	/**
+	* Total size of issued requests, currently only for HTTP requests
+	*/
+	public inline function getRequestSize() : Int {
+		return untyped __call__("curl_getinfo", h, __php__("CURLINFO_REQUEST_SIZE"));
+	}
+	
+	/**
+	* Result of SSL certification verification requested by setting setSsslVerifyPeer
+	*/
+	// TODO: is the return type correct?
+	public inline function getSslVerifyResult() : Bool {
+		return untyped __call__("curl_getinfo", h, __php__("CURLINFO_SSL_VERIFYRESULT"));
+	}
+	
+	/**
+	* content-length of download, read from Content-Length: field
+	*/
+	public inline function getContentLengthDownload() : Float {
+		return untyped __call__("curl_getinfo", h, __php__("CURLINFO_CONTENT_LENGTH_DOWNLOAD"));
+	}
+	
+	/**
+	* Specified size of upload
+	*/
+	public inline function getContentLengthUpload() : Float {
+		return untyped __call__("curl_getinfo", h, __php__("CURLINFO_CONTENT_LENGTH_UPLOAD"));
+	}
+	
+	/**
+	* Content-type of downloaded object, NULL indicates server did not send valid Content-Type: header
+	*/
+	public inline function getContentType() : String {
+		return untyped __call__("curl_getinfo", h, __php__("CURLINFO_CONTENT_TYPE"));
+	}
+	
+	/**
+	* TRUE to automatically set the Referer: field in requests where it 
+	* follows a Location: redirect.
+	* Available since PHP 5.1.0.
+	*/
+	public inline function setAutoReferer(v : Bool) : Bool {
+		return untyped __call__("curl_setopt", h, __php__("CURLOPT_AUTOREFERER"), v);
+	}
+	
+	/**
+	* TRUE to return the raw output when setReturnTransfer is used. 	
+	*/
+	public inline function setBinaryTransfer(v : Bool) : Bool {
+		return untyped __call__("curl_setopt", h, __php__("CURLOPT_BINARYTRANSFER"), v);
+	}
+
+	/**
+	* TRUE to mark this as a new cookie "session". It will force libcurl 
+	* to ignore all cookies it is about to load that are "session cookies"
+	* from the previous session. By default, libcurl always stores and
+	* loads all cookies, independent if they are session cookies are not.
+	* Session cookies are cookies without expiry date and they are meant 
+	* to be alive and existing for this "session" only.
+	* Available since PHP 5.1.0.
+	*/
+	public inline function setCookieSession(v : Bool) : Bool {
+		return untyped __call__("curl_setopt", h, __php__("CURLOPT_COOKIESESSION"), v);
+	}
+	
+	/**
+	* TRUE to convert Unix newlines to CRLF newlines on transfers.
+	*/
+	public inline function setCrLf(v : Bool) : Bool {
+		return untyped __call__("curl_setopt", h, __php__("CURLOPT_CRLF"), v);
+	}
+	
+	/**
+	* TRUE to use a global DNS cache. This option is not thread-safe and is enabled by default. 	
+	*/
+	public inline function setDnsUseGlobalCache(v : Bool) : Bool {
+		return untyped __call__("curl_setopt", h, __php__("CURLOPT_DNS_USE_GLOBAL_CACHE"), v);
+	}
+	
+	/**
+	* TRUE to fail silently if the HTTP code returned is greater than or equal to 400. The default behavior is to return the page normally, ignoring the code. 	
+	*/
+	public inline function setFailOnError(v : Bool) : Bool {
+		return untyped __call__("curl_setopt", h, __php__("CURLOPT_FAILONERROR"), v);
+	}
+	
+	/**
+	* TRUE to attempt to retrieve the modification date of the remote document. This value can be retrieved using the CURLINFO_FILETIME option with curl_getinfo(). 	
+	*/
+	public inline function setFileTime(v : Bool) : Bool {
+		return untyped __call__("curl_setopt", h, __php__("CURLOPT_FILETIME"), v);
+	}
+
+	/**
+	* TRUE to follow any "Location: " header that the server sends as part of the HTTP header (note this is recursive, PHP will follow as many "Location: " headers that it is sent, unless CURLOPT_MAXREDIRS is set). 	
+	*/
+	public inline function setFollowLocation(v : Bool) : Bool {
+		return untyped __call__("curl_setopt", h, __php__("CURLOPT_FOLLOWLOCATION"), v);
+	}
+	
+	/**
+	* TRUE to force the connection to explicitly close when it has finished processing, and not be pooled for reuse. 	
+	*/
+	public inline function setForbidReuse(v : Bool) : Bool {
+		return untyped __call__("curl_setopt", h, __php__("CURLOPT_FORBID_REUSE"), v);
+	}
+	
+	/**
+	* TRUE to force the use of a new connection instead of a cached one. 	
+	*/
+	public inline function setFreschConnect(v : Bool) : Bool {
+		return untyped __call__("curl_setopt", h, __php__("CURLOPT_FRESH_CONNECT"), v);
+	}
+	
+	/**
+	* TRUE to use EPRT (and LPRT) when doing active FTP downloads. Use FALSE to disable EPRT and LPRT and use PORT only. 	Added in PHP 5.0.0.
+	*/
+	public inline function setFtpUseEprt(v : Bool) : Bool {
+		return untyped __call__("curl_setopt", h, __php__("CURLOPT_FTP_USE_EPRT"), v);
+	}
+	
+	/**
+	* TRUE to first try an EPSV command for FTP transfers before reverting back to PASV. Set to FALSE to disable EPSV. 	
+	*/
+	public inline function setFtpUseEpsv(v : Bool) : Bool {
+		return untyped __call__("curl_setopt", h, __php__("CURLOPT_FTP_USE_EPSV"), v);
+	}
+
+	/**
+	* TRUE to append to the remote file instead of overwriting it. 	
+	*/
+	public inline function setFtpAppend(v : Bool) : Bool {
+		return untyped __call__("curl_setopt", h, __php__("CURLOPT_FTPAPPEND"), v);
+	}
+	
+	/**
+	* TRUE to only list the names of an FTP directory. 	
+	*/
+	public inline function setFtpListOnly(v : Bool) : Bool {
+		return untyped __call__("curl_setopt", h, __php__("CURLOPT_FTPLISTONLY"), v);
+	}
+	
+	/**
+	* TRUE to include the header in the output. 	
+	*/
+	public inline function setHeader(v : Bool) : Bool {
+		return untyped __call__("curl_setopt", h, __php__("CURLOPT_HEADER"), v);
+	}
+	
+	/**
+	* TRUE to reset the HTTP request method to GET. Since GET is the default, this is only necessary if the request method has been changed. 	
+	*/
+	public inline function setHttpGet(v : Bool) : Bool {
+		return untyped __call__("curl_setopt", h, __php__("CURLOPT_HTTPGET"), v);
+	}
+	
+	/**
+	* TRUE to tunnel through a given HTTP proxy. 	
+	*/
+	public inline function setHttpProxyTunnel(v : Bool) : Bool {
+		return untyped __call__("curl_setopt", h, __php__("CURLOPT_HTTPPROXYTUNNEL"), v);
+	}
+	
+	/**
+	* TRUE to be completely silent with regards to the cURL functions. 	
+	*/
+	public inline function setMute(v : Bool) : Bool {
+		return untyped __call__("curl_setopt", h, __php__("CURLOPT_MUTE"), v);
+	}
+	
+	/**
+	* TRUE to scan the ~/.netrc file to find a username and password for the remote site that a connection is being established with. 	
+	*/
+	public inline function setNetRc(v : Bool) : Bool {
+		return untyped __call__("curl_setopt", h, __php__("CURLOPT_NETRC"), v);
+	}
+	
+	/**
+	* TRUE to exclude the body from the output. 	
+	*/
+	public inline function setNoBody(v : Bool) : Bool {
+		return untyped __call__("curl_setopt", h, __php__("CURLOPT_NOBODY"), v);
+	}
+	
+	/**
+	* TRUE to disable the progress meter for cURL transfers. Note: PHP automatically sets this option to TRUE, this should only be changed for debugging purposes.
+	*/
+	public inline function setNoProgress(v : Bool) : Bool {
+		return untyped __call__("curl_setopt", h, __php__("CURLOPT_NOPROGRESS"), v);
+	}
+ 	
+	/**
+	* TRUE to ignore any cURL function that causes a signal to be sent to the PHP process. This is turned on by default in multi-threaded SAPIs so timeout options can still be used. 	Added in cURL 7.10 and PHP 5.0.0.
+	*/
+	public inline function setNoSignal(v : Bool) : Bool {
+		return untyped __call__("curl_setopt", h, __php__("CURLOPT_NOSIGNAL"), v);
+	}
+	
+	/**
+	* TRUE to do a regular HTTP POST. This POST is the normal application/x-www-form-urlencoded kind, most commonly used by HTML forms. 	
+	*/
+	public inline function setPost(v : Bool) : Bool {
+		return untyped __call__("curl_setopt", h, __php__("CURLOPT_POST"), v);
+	}
+	
+	/**
+	* TRUE to HTTP PUT a file. The file to PUT must be set with CURLOPT_INFILE and CURLOPT_INFILESIZE. 	
+	*/
+	public inline function setPut(v : Bool) : Bool {
+		return untyped __call__("curl_setopt", h, __php__("CURLOPT_PUT"), v);
+	}
+	
+	/**
+	* TRUE to return the transfer as a string of the return value of curl_exec() instead of outputting it out directly. 	
+	*/
+	public inline function setReturnTransfer(v : Bool) : Bool {
+		return untyped __call__("curl_setopt", h, __php__("CURLOPT_RETURNTRANSFER"), v);
+	}
+	
+	/**
+	* FALSE to stop cURL from verifying the peer's certificate. Alternate certificates to verify against can be specified with the CURLOPT_CAINFO option or a certificate directory can be specified with the CURLOPT_CAPATH option. CURLOPT_SSL_VERIFYHOST may also need to be TRUE or FALSE if CURLOPT_SSL_VERIFYPEER is disabled (it defaults to 2). 	TRUE by default as of cURL 7.10. Default bundle installed as of cURL 7.10.
+	*/
+	public inline function setSslVerifyPeer(v : Bool) : Bool {
+		return untyped __call__("curl_setopt", h, __php__("CURLOPT_SSL_VERIFYPEER"), v);
+	}
+
+ 	/**
+	* TRUE to use ASCII mode for FTP transfers. For LDAP, it retrieves data in plain text instead of HTML. On Windows systems, it will not set STDOUT to binary mode. 	
+	*/
+	public inline function setTransferText(v : Bool) : Bool {
+		return untyped __call__("curl_setopt", h, __php__("CURLOPT_TRANSFERTEXT"), v);
+	}
+	
+	/**
+	* TRUE to keep sending the username and password when following locations (using CURLOPT_FOLLOWLOCATION), even when the hostname has changed. 	Added in PHP 5.0.0.
+	*/
+	public inline function setUnrestrictedAuth(v : Bool) : Bool {
+		return untyped __call__("curl_setopt", h, __php__("CURLOPT_UNRESTRICTED_AUTH"), v);
+	}
+	
+	/**
+	* TRUE to prepare for an upload. 	
+	*/
+	public inline function setUpload(v : Bool) : Bool {
+		return untyped __call__("curl_setopt", h, __php__("CURLOPT_UPLOAD"), v);
+	}
+	
+	/**
+	* TRUE to output verbose information. Writes output to STDERR, or the file specified using CURLOPT_STDERR. 	
+	*/
+	public inline function setVerbose(v : String) : Bool {
+		return untyped __call__("curl_setopt", h, __php__("CURLOPT_VERBOSE"), v);
+	} 
+
+	/**
+	* The size of the buffer to use for each read. There is no guarantee this request will be fulfilled, however. 	Added in cURL 7.10 and PHP 5.0.0.
+	*/
+	public inline function setBufferSize(v : Int) : Bool {
+		return untyped __call__("curl_setopt", h, __php__("CURLOPT_BUFFERSIZE"), v);
+	}
+
+	/**
+	* Either CURLCLOSEPOLICY_LEAST_RECENTLY_USED or CURLCLOSEPOLICY_OLDEST . There are three other CURLCLOSEPOLICY_ constants, but cURL does not support them yet. 	
+	*/
+	public inline function setClosePolicy(v : Int) : Bool {
+		return untyped __call__("curl_setopt", h, __php__("CURLOPT_CLOSEPOLICY"), v);
+	}
+	
+	/**
+	* The number of seconds to wait whilst trying to connect. Use 0 to wait indefinitely. 	
+	*/
+	public inline function setConnectTimeout(v : Int) : Bool {
+		return untyped __call__("curl_setopt", h, __php__("CURLOPT_CONNECTTIMEOUT"), v);
+	}
+	
+	/**
+	* The number of seconds to keep DNS entries in memory. This option is set to 120 (2 minutes) by default. 	
+	*/
+	public inline function setDnsCacheTimeout(v : Int) : Bool {
+		return untyped __call__("curl_setopt", h, __php__("CURLOPT_DNS_CACHE_TIMEOUT"), v);
+	}
+	
+	/**
+	* The FTP authentication method (when is activated): CURLFTPAUTH_SSL (try SSL first), CURLFTPAUTH_TLS (try TLS first), or CURLFTPAUTH_DEFAULT (let cURL decide). 	Added in cURL 7.12.2 and PHP 5.1.0.
+	*/
+	public inline function setFtpSslAuth(v : Int) : Bool {
+		return untyped __call__("curl_setopt", h, __php__("CURLOPT_FTPSSLAUTH"), v);
+	}
+	
+	/**
+	* lets CURL decide which version to use
+	*/
+	public inline function setHttpDefaultVersion() : Bool {
+		return untyped __call__("curl_setopt", h, __php__("CURLOPT_HTTP_VERSION"), __php__("CURL_HTTP_VERSION_NONE"));
+	}
+	
+	/**
+	* lets CURL decide which version to use
+	*/
+	public inline function setHttpVersion10() : Bool {
+		return untyped __call__("curl_setopt", h, __php__("CURLOPT_HTTP_VERSION"), __php__("CURL_HTTP_VERSION_1_0"));
+	}
+	
+	/**
+	* lets CURL decide which version to use
+	*/
+	public inline function setHttpVersion11() : Bool {
+		return untyped __call__("curl_setopt", h, __php__("CURLOPT_HTTP_VERSION"), __php__("CURL_HTTP_VERSION_1_1"));
+	}
+
+	public static var CURLAUTH_BASIC : Int = untyped __php__("CURLAUTH_BASIC");
+	public static var CURLAUTH_DIGEST : Int = untyped __php__("CURLAUTH_DIGEST");
+	public static var CURLAUTH_GSSNEGOTIATE : Int = untyped __php__("CURLAUTH_GSSNEGOTIATE");
+	public static var CURLAUTH_NTLM : Int = untyped __php__("CURLAUTH_NTLM");
+	public static var CURLAUTH_ANY : Int = untyped __php__("CURLAUTH_ANY");
+	public static var CURLAUTH_ANYSAFE : Int = untyped __php__("CURLAUTH_ANYSAFE");
+	
+	/**
+	* The HTTP authentication method(s) to use. The options are: CURLAUTH_BASIC , CURLAUTH_DIGEST , CURLAUTH_GSSNEGOTIATE , CURLAUTH_NTLM , CURLAUTH_ANY , and CURLAUTH_ANYSAFE . The bitwise | (or) operator can be used to combine more than one method. If this is done, cURL will poll the server to see what methods it supports and pick the best one.
+	*/
+	public inline function setHttpAuth(v : Int) : Bool {
+		return untyped __call__("curl_setopt", h, __php__("CURLOPT_HTTPAUTH"), v);
+	}
+
+	/**
+	* The expected size, in bytes, of the file when uploading a file to a remote site. 	
+	*/
+	public inline function setInFileSize(v : Int) : Bool {
+		return untyped __call__("curl_setopt", h, __php__("CURLOPT_INFILESIZE"), v);
+	}
+	
+	/**
+	* The transfer speed, in bytes per second, that the transfer should be below during CURLOPT_LOW_SPEED_TIME seconds for PHP to consider the transfer too slow and abort. 	
+	*/
+	public inline function setLowSpeedLimit(v : Int) : Bool {
+		return untyped __call__("curl_setopt", h, __php__("CURLOPT_LOW_SPEED_LIMIT"), v);
+	}
+
+	/**
+	* The number of seconds the transfer should be below CURLOPT_LOW_SPEED_LIMIT for PHP to consider the transfer too slow and abort. 	
+	*/
+	public inline function setLowSpeedTime(v : Int) : Bool {
+		return untyped __call__("curl_setopt", h, __php__("CURLOPT_LOW_SPEED_TIME"), v);
+	}
+	
+	/**
+	* The maximum amount of persistent connections that are allowed. When the limit is reached, CURLOPT_CLOSEPOLICY is used to determine which connection to close. 	
+	*/
+	public inline function setMaxConnects(v : Int) : Bool {
+		return untyped __call__("curl_setopt", h, __php__("CURLOPT_MAXCONNECTS"), v);
+	}
+	
+	/**
+	* The maximum amount of HTTP redirections to follow. Use this option alongside CURLOPT_FOLLOWLOCATION. 	
+	*/
+	public inline function setMaxRedirs(v : Int) : Bool {
+		return untyped __call__("curl_setopt", h, __php__("CURLOPT_MAXREDIRS"), v);
+	}
+	
+	/**
+	* An alternative port number to connect to. 	
+	*/
+	public inline function setPort(v : Int) : Bool {
+		return untyped __call__("curl_setopt", h, __php__("CURLOPT_PORT"), v);
+	}
+	
+	/**
+	* The HTTP authentication method(s) to use for the proxy connection. Use the same bitmasks as described in CURLOPT_HTTPAUTH. For proxy authentication, only CURLAUTH_BASIC and CURLAUTH_NTLM are currently supported. 	Added in cURL 7.10.7 and PHP 5.1.0.
+	*/
+	public inline function setProxyAuth(v : Int) : Bool {
+		return untyped __call__("curl_setopt", h, __php__("CURLOPT_PROXYAUTH"), v);
+	}
+
+	/**
+	* The port number of the proxy to connect to. This port number can also be set in CURLOPT_PROXY. 	Added in PHP 5.0.0.
+	*/
+	public inline function setProxyPort(v : Int) : Bool {
+		return untyped __call__("curl_setopt", h, __php__("CURLOPT_PROXYPORT"), v);
+	}
+	
+	/**
+	* Either CURLPROXY_HTTP (default) or CURLPROXY_SOCKS5 . 	Added in cURL 7.10 and PHP 5.0.0.
+	*/
+	public inline function setProxyType(v : Int) : Bool {
+		return untyped __call__("curl_setopt", h, __php__("CURLOPT_PROXYTYPE"), v);
+	}
+	
+	/**
+	* The offset, in bytes, to resume a transfer from.
+	*/
+	public inline function setResumeForm(v : Int) : Bool {
+		return untyped __call__("curl_setopt", h, __php__("CURLOPT_RESUME_FROM"), v);
+	}
+	
+	/**
+	* 1 to check the existence of a common name in the SSL peer certificate. 2 to check the existence of a common name and also verify that it matches the hostname provided. 
+	*/
+	public inline function setSslVerifyHost(v : Int) : Bool {
+		return untyped __call__("curl_setopt", h, __php__("CURLOPT_SSL_VERIFYHOST"), v);
+	}
+
+	/**
+	* The SSL version (2 or 3) to use. By default PHP will try to determine this itself, although in some cases this must be set manually. 	
+	*/
+	public inline function setSslVersion(v : Int) : Bool {
+		return untyped __call__("curl_setopt", h, __php__("CURLOPT_SSLVERSION"), v);
+	}
+
+	/**
+	* How setTimeValue() is treated. Use setTimeConditionIsUnmodSince() for the reverse effect of setTimeConditionIfModSince(). Added in PHP 5.1.0.
+	*/
+	public inline function setTimeConditionIsUnmodSince() : Bool {
+		return untyped __call__("curl_setopt", h, __php__("CURLOPT_TIMECONDITION"), __php__("CURL_TIMECOND_IFMODSINCE"));
+	}
+
+	/**
+	* How setTimeValue() is treated. Use setTimeConditionIfModSince to return the page only if it has been modified since the time specified in setTimeValue(true). If it hasn't been modified, a "304 Not Modified" header will be returned assuming setHeader(true). 
+	* This is the default behavior.
+	* Added in PHP 5.1.0.
+	*/
+	public inline function setTimeConditionIfModSince() : Bool {
+		return untyped __call__("curl_setopt", h, __php__("CURLOPT_TIMECONDITION"), __php__("CURL_TIMECOND_ISUNMODSINCE"));
+	}
+	
+	/**
+	* The maximum number of seconds to allow cURL functions to execute. 	
+	*/
+	public inline function setTimeOut(v : Int) : Bool {
+		return untyped __call__("curl_setopt", h, __php__("CURLOPT_TIMEOUT"), v);
+	}
+	
+	/**
+	* The time in seconds since January 1st, 1970. The time will be used by CURLOPT_TIMECONDITION. By default, CURL_TIMECOND_IFMODSINCE is used. 	
+	*/
+	public inline function setTimeValue(v : Int) : Bool {
+		return untyped __call__("curl_setopt", h, __php__("CURLOPT_TIMEVALUE"), v);
+	}
+	
+	/**
+	* The name of a file holding one or more certificates to verify the peer with. This only makes sense when used in combination with CURLOPT_SSL_VERIFYPEER. 	
+	*/
+	public inline function setCaInfo(v : String) : Bool {
+		return untyped __call__("curl_setopt", h, __php__("CURLOPT_CAINFO"), v);
+	}
+	
+	/**
+	* A directory that holds multiple CA certificates. Use this option alongside CURLOPT_SSL_VERIFYPEER. 	
+	*/
+	public inline function setCaPath(v : String) : Bool {
+		return untyped __call__("curl_setopt", h, __php__("CURLOPT_CAPATH"), v);
+	}
+
+	/**
+	* The contents of the "Set-Cookie: " header to be used in the HTTP request. 	
+	*/
+	public inline function setCookie(v : String) : Bool {
+		return untyped __call__("curl_setopt", h, __php__("CURLOPT_COOKIE"), v);
+	}
+	
+	/**
+	* The name of the file containing the cookie data. The cookie file can be in Netscape format, or just plain HTTP-style headers dumped into a file. 	
+	*/
+	public inline function setCookieFile(v : String) : Bool {
+		return untyped __call__("curl_setopt", h, __php__("CURLOPT_COOKIEFILE"), v);
+	}
+	
+	/**
+	* The name of a file to save all internal cookies to when the connection closes. 	
+	*/
+	public inline function setCookieJar(v : String) : Bool {
+		return untyped __call__("curl_setopt", h, __php__("CURLOPT_COOKIEJAR"), v);
+	}
+	
+	/**
+	* A custom request method to use instead of "GET" or "HEAD" when doing a HTTP request. This is useful for doing "DELETE" or other, more obscure HTTP requests. Valid values are things like "GET", "POST", "CONNECT" and so on; i.e. Do not enter a whole HTTP request line here. For instance, entering "GET /index.html HTTP/1.0\r\n\r\n" would be incorrect.  Note: Don't do this without making sure the server supports the custom request method first.
+	*/
+	public inline function setCustomRequest(v : String) : Bool {
+		return untyped __call__("curl_setopt", h, __php__("CURLOPT_CUSTOMREQUEST"), v);
+	}
+	
+	/**
+	* Like setRandomFile(), except a filename to an Entropy Gathering Daemon socket. 	
+	*/
+	public inline function setEgdSocket(v : String) : Bool {
+		return untyped __call__("curl_setopt", h, __php__("CURLOPT_EGDSOCKET"), v);
+	}
+
+	/**
+	* The contents of the "Accept-Encoding: " header. This enables decoding of the response. Supported encodings are "identity", "deflate", and "gzip". If an empty string, "", is set, a header containing all supported encoding types is sent. 	Added in cURL 7.10.
+	*/
+	public inline function setEncoding(v : String) : Bool {
+		return untyped __call__("curl_setopt", h, __php__("CURLOPT_ENCODING"), v);
+	}
+
+	/**
+	* The value which will be used to get the IP address to use for the FTP "POST" instruction. The "POST" instruction tells the remote server to connect to our specified IP address. The string may be a plain IP address, a hostname, a network interface name (under Unix), or just a plain '-' to use the systems default IP address. 	
+	*/
+	public inline function setFtpPort(v : String) : Bool {
+		return untyped __call__("curl_setopt", h, __php__("CURLOPT_FTPPORT"), v);
+	}
+	
+	/**
+	* The name of the outgoing network interface to use. This can be an interface name, an IP address or a host name. 	
+	*/
+	public inline function setInterface(v : String) : Bool {
+		return untyped __call__("curl_setopt", h, __php__("CURLOPT_INTERFACE"), v);
+	}
+	
+	/**
+	* The KRB4 (Kerberos 4) security level. Any of the following values (in order from least to most powerful) are valid: "clear", "safe", "confidential", "private".. If the string does not match one of these, "private" is used. Setting this option to NULL will disable KRB4 security. Currently KRB4 security only works with FTP transactions. 	
+	*/
+	public inline function setKrb4Level(v : String) : Bool {
+		return untyped __call__("curl_setopt", h, __php__("CURLOPT_KRB4LEVEL"), v);
+	}
+	
+	/**
+	* The full data to post in a HTTP "POST" operation. To post a file, prepend a filename with @ and use the full path. 	
+	*/
+	public inline function setPostFields(v : String) : Bool {
+		return untyped __call__("curl_setopt", h, __php__("CURLOPT_POSTFIELDS"), v);
+	}
+
+	/**
+	* The HTTP proxy to tunnel requests through. 	
+	*/
+	public inline function setProxy(v : String) : Bool {
+		return untyped __call__("curl_setopt", h, __php__("CURLOPT_PROXY"), v);
+	}
+	
+	/**
+	* A username and password formatted as "[username]:[password]" to use for the connection to the proxy. 	
+	*/
+	public inline function setProxyUserPwd(v : String) : Bool {
+		return untyped __call__("curl_setopt", h, __php__("CURLOPT_PROXYUSERPWD"), v);
+	}
+	
+	/**
+	* A filename to be used to seed the random number generator for SSL. 	
+	*/
+	public inline function setRandomFile(v : String) : Bool {
+		return untyped __call__("curl_setopt", h, __php__("CURLOPT_RANDOM_FILE"), v);
+	}
+	
+	/**
+	* Range(s) of data to retrieve in the format "X-Y" where X or Y are optional. HTTP transfers also support several intervals, separated with commas in the format "X-Y,N-M". 	
+	*/
+	public inline function setRange(v : String) : Bool {
+		return untyped __call__("curl_setopt", h, __php__("CURLOPT_RANGE"), v);
+	}
+	
+	/**
+	* The contents of the "Referer: " header to be used in a HTTP request. 	
+	*/
+	public inline function setReferer(v : String) : Bool {
+		return untyped __call__("curl_setopt", h, __php__("CURLOPT_REFERER"), v);
+	}
+	
+	/**
+	* A list of ciphers to use for SSL. For example, RC4-SHA and TLSv1 are valid cipher lists. 	
+	*/
+	public inline function setSslCipherList(v : String) : Bool {
+		return untyped __call__("curl_setopt", h, __php__("CURLOPT_SSL_CIPHER_LIST"), v);
+	}
+	
+	/**
+	* The name of a file containing a PEM formatted certificate. 	
+	*/
+	public inline function setSslCert(v : String) : Bool {
+		return untyped __call__("curl_setopt", h, __php__("CURLOPT_SSLCERT"), v);
+	}
+	
+	/**
+	* The password required to use the CURLOPT_SSLCERT certificate. 	
+	*/
+	public inline function setSslCertPasswd(v : String) : Bool {
+		return untyped __call__("curl_setopt", h, __php__("CURLOPT_SSLCERTPASSWD"), v);
+	}
+	
+	/**
+	* The format of the certificate. Supported formats are "PEM" (default), "DER", and "ENG". 	Added in cURL 7.9.3 and PHP 5.0.0.
+	*/
+	public inline function setSslCertType(v : String) : Bool {
+		return untyped __call__("curl_setopt", h, __php__("CURLOPT_SSLCERTTYPE"), v);
+	}
+	
+	/**
+	* The identifier for the crypto engine of the private SSL key specified in CURLOPT_SSLKEY. 	
+	*/
+	public inline function setSslEngine(v : String) : Bool {
+		return untyped __call__("curl_setopt", h, __php__("CURLOPT_SSLENGINE"), v);
+	}
+
+	/**
+	* The identifier for the crypto engine used for asymmetric crypto operations. 	
+	*/
+	public inline function setSsleEngineDefault(v : String) : Bool {
+		return untyped __call__("curl_setopt", h, __php__("CURLOPT_SSLENGINE_DEFAULT"), v);
+	}
+	
+	/**
+	* The name of a file containing a private SSL key. 	
+	*/
+	public inline function setSslKey(v : String) : Bool {
+		return untyped __call__("curl_setopt", h, __php__("CURLOPT_SSLKEY"), v);
+	}
+	
+	/**
+	* The secret password needed to use the private SSL key specified in CURLOPT_SSLKEY. Note: Since this option contains a sensitive password, remember to keep the PHP script it is contained within safe.
+	*/
+	public inline function setSslKeyPasswd(v : String) : Bool {
+		return untyped __call__("curl_setopt", h, __php__("CURLOPT_SSLKEYPASSWD"), v);
+	}
+	
+	/**
+	* The key type of the private SSL key specified in CURLOPT_SSLKEY. Supported key types are "PEM" (default), "DER", and "ENG". 	
+	*/
+	public inline function setSslKeyType(v : String) : Bool {
+		return untyped __call__("curl_setopt", h, __php__("CURLOPT_SSLKEYTYPE"), v);
+	}
+	
+	/**
+	* The URL to fetch. This can also be set when initializing a session with curl_init(). 	
+	*/
+	public inline function setUrl(v : String) : Bool {
+		return untyped __call__("curl_setopt", h, __php__("CURLOPT_URL"), v);
+	}
+
+	/**
+	* The contents of the "User-Agent: " header to be used in a HTTP request. 	
+	*/
+	public inline function setUserAgent(v : String) : Bool {
+		return untyped __call__("curl_setopt", h, __php__("CURLOPT_USERAGENT"), v);
+	}
+	
+	/**
+	* A username and password formatted as "[username]:[password]" to use for the connection. 
+	*/
+	public inline function setUserPwd(v : String) : Bool {
+		return untyped __call__("curl_setopt", h, __php__("CURLOPT_USERPWD"), v);
+	}
+	
+	/**
+	* An array of HTTP 200 responses that will be treated as valid responses and not as errors. 	Added in cURL 7.10.3 and PHP 5.0.0.
+	*/
+	public inline function setHttp200Aliases(v : Array<Int>) : Bool {
+		return untyped __call__("curl_setopt", h, __php__("CURLOPT_HTTP200ALIASES"), v);
+	}
+	
+	/**
+	* An array of HTTP header fields to set. 	
+	*/
+	public inline function setHttpHeader(v : Array<String>) : Bool {
+		return untyped __call__("curl_setopt", h, __php__("CURLOPT_HTTPHEADER"), v);
+	}
+	
+	/**
+	* An array of FTP commands to execute on the server after the FTP request has been performed. 	
+	*/
+	public inline function setPostQuote(v : Array<String>) : Bool {
+		return untyped __call__("curl_setopt", h, __php__("CURLOPT_POSTQUOTE"), v);
+	}
+	
+	/**
+	* An array of FTP commands to execute on the server prior to the FTP request. 	
+	*/
+	public inline function setQuote(v : Array<String>) : Bool {
+		return untyped __call__("curl_setopt", h, __php__("CURLOPT_QUOTE"), v);
+	}
+	
+	/**
+	* The file that the transfer should be written to. The default is STDOUT (the browser window). 	
+	*/
+	// TODO: adjust the followings to be more haxe oriented
+	public inline function setFile(v : Dynamic) : Bool {
+		return untyped __call__("curl_setopt", h, __php__("CURLOPT_FILE"), v);
+	}
+	
+	/**
+	* The file that the transfer should be read from when uploading. 	
+	*/
+	public inline function setInFile(v : Dynamic) : Bool {
+		return untyped __call__("curl_setopt", h, __php__("CURLOPT_INFILE"), v);
+	}
+	
+	/**
+	* An alternative location to output errors to instead of STDERR. 	
+	*/
+	public inline function setStdErr(v : Dynamic) : Bool {
+		return untyped __call__("curl_setopt", h, __php__("CURLOPT_STDERR"), v);
+	}
+	
+	/**
+	* The file that the header part of the transfer is written to. 	
+	*/
+	public inline function setWriteHeader(v : Dynamic) : Bool {
+		return untyped __call__("curl_setopt", h, __php__("CURLOPT_WRITEHEADER"), v);
+	}	
+ 	
+	/**
+	* The name of a callback function where the callback function takes two parameters. The first is the cURL resource, the second is a string with the header data to be written. The header data must be written when using this callback function. Return the number of bytes written. 	
+	*/
+	public inline function setHeaderFunction(v : Dynamic -> String -> Int) : Bool {
+		return untyped __call__("curl_setopt", h, __php__("CURLOPT_HEADERFUNCTION"), v);
+	}
+	
+	/**
+	* The name of a callback function where the callback function takes three parameters. The first is the cURL resource, the second is a string containing a password prompt, and the third is the maximum password length. Return the string containing the password. 	
+	*/
+	public inline function setPasswdFunction(v : Dynamic -> String -> Int -> String) : Bool {
+		return untyped __call__("curl_setopt", h, __php__("CURLOPT_PASSWDFUNCTION"), v);
+	}
+	
+	/**
+	* The name of a callback function where the callback function takes two parameters. The first is the cURL resource, and the second is a string with the data to be read. The data must be read by using this callback function. Return the number of bytes read. Return 0 to signal EOF. 	
+	*/
+	public inline function setReadFunction(v : Dynamic -> String -> Int) : Bool {
+		return untyped __call__("curl_setopt", h, __php__("CURLOPT_READFUNCTION"), v);
+	}
+	
+	/**
+	* The name of a callback function where the callback function takes two parameters. The first is the cURL resource, and the second is a string with the data to be written. The data must be written by using this callback function. Must return the exact number of bytes written or this will fail. 
+	*/
+	public inline function setWriteFunction(v : Dynamic -> String -> Int) : Bool {
+		return untyped __call__("curl_setopt", h, __php__("CURLOPT_WRITEFUNCTION"), v);
+	}
+	
+	private static function __init__() {
+		untyped __php__('if (!extension_loaded("Curl")) dl("php_curl.".(PHP_OS == "WINNT" || PHP_OS == "WIN32" ? "dll" : "so"))');
+	}
+}
+
+class CurlMulti {
+	var mh : Void;
+	public function new() {
+		stillRunning = false;
+		mh = untyped __call__("curl_multi_init");
+	}
+	
+	public inline function close() {
+		untyped __call__("curl_multi_close", mh);
+	}
+	
+	public var stillRunning(default, null) : Bool;
+	public inline function execute() : Int {
+		var i;
+		var r = untyped __call__("curl_multi_exec", mh, i);
+		stillRunning = i == 1;
+		return r;
+	}
+	
+	public inline function getContent() : String {
+		return untyped __call__("curl_multi_getcontent", mh);
+	}
+	
+	public inline function infoRead(?msgsinqueue : Int) : Hash<String> {
+		var m = untyped __call__("curl_multi_info_read", mh, msgsinqueue);
+		if(m == false)
+			return new Hash();
+		else
+			return Hash.fromAssociativeArray(m);
+	}
+	
+	public function addCurl(c : Curl) : Int {
+		return untyped __call__("curl_multi_add_handle", mh, c.h);
+	}
+	
+	public function removeCurl(c : Curl) {
+		return untyped __call__("curl_multi_remove_handle", mh, c.h);
+	}
+}

+ 19 - 0
std/php/Exception.hx

@@ -0,0 +1,19 @@
+package php;
+
+extern class Exception {
+  public function new(?message : String, ?code : Int) : Void;
+  
+  private var message : String;
+  private var code : Int;
+  private var file : String;
+  private var line : Int;
+  
+  public function getMessage() : String;       // message of the exception 
+  public function getCode() : Int;             // code of the exception
+  public function getFile() : String;          // source filename
+  public function getLine() : Int;             // source line
+  public function getTrace() : Array<String>;  // an array of the backtrace()
+  public function getTraceAsString() : String; // formated string of trace
+  
+  public function __toString() : String;       // formated string for display
+}

+ 112 - 0
std/php/FileSystem.hx

@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2005, The haXe Project Contributors
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   - Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *   - Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE HAXE PROJECT CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE HAXE PROJECT CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ */
+package php;
+
+typedef FileStat = {
+	var gid : Int;
+	var uid : Int;
+	var atime : Date;
+	var mtime : Date;
+	var ctime : Date;
+	var dev : Int;
+	var ino : Int;
+	var nlink : Int;
+	var rdev : Int;
+	var size : Int;
+	var mode : Int;
+}
+
+enum FileKind {
+	kdir;
+	kfile;
+	kother( k : String );
+}
+
+class FileSystem {
+
+	public static inline function exists( path : String ) : Bool {
+		return untyped __call__("file_exists", path);
+	}
+
+	public static inline function rename( path : String, newpath : String ) {
+		return untyped __call__("rename", path, newpath);
+	}
+
+	public static function stat( path : String ) : FileStat {
+		untyped __php__('$fp = fopen($path, "r");
+		$fstat = fstat($fp);
+		fclose($fp);');
+		return untyped {
+			gid   : __php__("$fstat['gid']"),
+			uid   : __php__("$fstat['uid']"),
+			atime : Date.fromTime(__php__("$fstat['atime']")),
+			mtime : Date.fromTime(__php__("$fstat['mtime']")),
+			ctime : Date.fromTime(__php__("$fstat['ctime']")),
+			dev   : __php__("$fstat['dev']"),
+			ino   : __php__("$fstat['ino']"),
+			nlink : __php__("$fstat['nlink']"),
+			rdev  : __php__("$fstat['rdev']"),
+			size  : __php__("$fstat['size']"),
+			mode  : __php__("$fstat['mode']")
+		};
+	}
+
+	public static inline function fullPath( relpath : String ) : String {
+		return untyped __call__("realpath", relpath);
+	}
+
+	public static function kind( path : String ) : FileKind {
+		var k = untyped __call__("filetype", path);
+		switch(k) {
+			case "file": return kfile;
+			case "dir": return kdir;
+			default: return kother(k);
+		}
+	}
+
+	public static inline function isDirectory( path : String ) : Bool {
+		return untyped __call__("is_dir", path);
+	}
+
+	public static inline function createDirectory( path : String ) {
+		return untyped __call__("@mkdir", path, 493); // php default is 0777, neko is 0755
+	}
+
+	public static inline function deleteFile( path : String ) {
+		return untyped __call__("@unlink", path);
+	}
+
+	public static inline function deleteDirectory( path : String ) {
+		return untyped __call__("@rmdir", path);
+	}
+
+	public static function readDirectory( path : String ) : Array<String> {
+		var l : Array<String> =  [];
+		untyped __php__('$dh = opendir($path);
+        while (($file = readdir($dh)) !== false) $l[] = $file;
+        closedir($dh);');
+		return l;
+	}
+}

+ 9 - 0
std/php/HException.hx

@@ -0,0 +1,9 @@
+package php;
+
+extern class HException extends Exception {
+  public var e : Dynamic;
+  public var p : haxe.PosInfos;
+  public function new(e : Dynamic, ?message : String, ?code : Int, ?p : haxe.PosInfos) : Void;
+  public function setLine(l:Int) : Void;
+  public function setFile(f:String) : Void;
+}

+ 9 - 0
std/php/IniHash.hx

@@ -0,0 +1,9 @@
+package php;
+
+class IniHash extends Hash<String> {
+	public function new(file : String) {
+		super();
+		if(file == null) throw "File can't be null";
+		h = untyped __call__("parse_ini_file", file, false);
+	}
+}

+ 60 - 0
std/php/Lib.hx

@@ -0,0 +1,60 @@
+package php;
+
+class Lib {
+	/**
+		Print the specified value on the default output.
+	**/
+	public static function print( v : Dynamic ) : Void {
+		untyped __call__("echo", Std.string(v));
+	}
+
+	/*
+		Print the specified value on the default output followed by a newline character.
+	*/
+	public static function println( v : Dynamic ) : Void {
+		print(v);
+		print("\n");
+	}
+	
+	public static function dump(v : Dynamic) : Void {
+		untyped __call__("var_dump", v);
+	}
+	
+	/**
+		Serialize using native PHP serialization. This will return a Binary string that can be
+		stored for long term usage.
+	**/
+	public static function serialize( v : Dynamic ) : String {
+		return untyped __call__("serialize", v);
+	}
+
+	/**
+		Unserialize a string using native PHP serialization. See [serialize].
+	**/
+	public static function unserialize( s : String ) : Dynamic {
+		return untyped __call__("unserialize", s);
+	}
+	
+	public static function extensionLoaded(name : String) {
+		return untyped __call__("extension_loaded", name);
+	}
+	
+	public static function isCli() : Bool {
+		return untyped __php__("0 == strncasecmp(PHP_SAPI, 'cli', 3)");
+	}
+	
+	public static function exit(?msg : String) {
+		return untyped __call__("exit", msg);
+	}
+	
+	public static function exitCode(code : Int) {
+		return untyped __call__("exit", code);
+	}
+	
+	public static function printFile(file : String) {
+		var h = untyped __call__("fopen", file,  "r");
+		return untyped __call__("fpassthru", h);
+	}
+}
+
+

+ 97 - 0
std/php/PhpDate__.hx

@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2005, The haXe Project Contributors
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   - Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *   - Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE HAXE PROJECT CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE HAXE PROJECT CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ */
+package php;
+
+class PhpDate__ //implements Date
+{
+	static var __name__ = ["Date"];
+	private var __t : Float;
+
+	public function new(year : Int, month : Int, day : Int, hour : Int, min : Int, sec : Int ) {
+		__t = untyped __call__("mktime", hour, min, sec, month+1, day, year);
+	}
+
+	public function getTime() : Float {
+		return __t*1000;
+	}
+	
+	public function getPhpTime() : Float {
+		return __t;
+	}
+
+	public function getFullYear() : Int {
+		return untyped __call__("intval", __call__("date", "Y", this.__t));
+	}
+
+	public function getMonth() : Int {
+		return -1 + untyped __call__("intval", __call__("date", "n", this.__t));
+	}
+
+	public function getDate() : Int {
+		return untyped __call__("intval", __call__("date", "j", this.__t));
+	}
+
+	public function getHours() : Int {
+		return untyped __call__("intval", __call__("date", "G", this.__t));
+	}
+
+	public function getMinutes() : Int {
+		return untyped __call__("intval", __call__("date", "i", this.__t));
+	}
+
+	public function getSeconds() : Int {
+		return untyped __call__("intval", __call__("date", "s", this.__t));
+	}
+
+	public function getDay() : Int {
+		return untyped __call__("intval", __call__("date", "w", this.__t));
+	}
+
+	public function toString():String {
+		return untyped __call__("date", "Y-m-d H:i:s", this.__t);
+	}
+
+	public static function now() {
+		return fromPhpTime(untyped __call__("time"));
+	}
+
+	public static function fromPhpTime( t : Float ){
+		var d = new PhpDate__(2000,1,1,0,0,0);
+		d.__t = t;
+		return d;
+	}
+	
+	public static function fromTime( t : Float ){
+		var d = new PhpDate__(2000,1,1,0,0,0);
+		d.__t = t/1000;
+		return d;
+	}
+
+	public static function fromString( s : String ) {
+		return fromPhpTime(untyped __call__("strtotime", s));
+	}
+}
+
+

+ 64 - 0
std/php/PhpMath__.hx

@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2005, The haXe Project Contributors
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   - Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *   - Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE HAXE PROJECT CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE HAXE PROJECT CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ */
+package php;
+
+class PhpMath__ 
+{
+	public static var PI;
+	public static var NaN;
+	public static var POSITIVE_INFINITY;
+	public static var NEGATIVE_INFINITY;
+
+	public static function abs(v)      { return untyped __call__("abs", v); }
+	public static function min(a,b)    { return untyped __call__("min", a, b); }
+	public static function max(a,b)    { return untyped __call__("max", a, b); }
+	public static function sin(v)      { return untyped __call__("sin", v); }
+	public static function cos(v)      { return untyped __call__("cos", v); }
+	public static function atan2(y,x)  { return untyped __call__("atan2", y, x); }
+	public static function tan(v)      { return untyped __call__("tan", v); }
+	public static function exp(v)      { return untyped __call__("exp", v); }
+	public static function log(v)      { return untyped __call__("log", v); }
+	public static function sqrt(v)     { return untyped __call__("sqrt", v); }
+	public static function round(v)    { return untyped __call__("round", v); }
+	public static function floor(v)    { return untyped __call__("floor", v); }
+	public static function ceil(v)     { return untyped __call__("ceil", v); }
+	public static function atan(v)     { return untyped __call__("atan", v); }
+	public static function asin(v)     { return untyped __call__("asin", v); }
+	public static function acos(v)     { return untyped __call__("acos", v); }
+	public static function pow(b,e)    { return untyped __call__("pow", b, e); }
+	public static function random()    { return untyped __call__("mt_rand") / __call__("mt_getrandmax"); }
+	public static function isNaN(f)    { return untyped __call__("is_nan", f); }
+	public static function isFinite(f) { return untyped __call__("is_finite", f); }
+
+	static function __init__() {
+	 	PI = untyped __php__("M_PI");
+	 	NaN = untyped __php__("acos(1.01)");
+	 	NEGATIVE_INFINITY = untyped __php__("log(0)");
+	 	POSITIVE_INFINITY = -NEGATIVE_INFINITY;
+	}
+
+}
+
+

+ 374 - 0
std/php/PhpXml__.hx

@@ -0,0 +1,374 @@
+/*
+ * Copyright (c) 2005, The haXe Project Contributors
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   - Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *   - Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE HAXE PROJECT CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE HAXE PROJECT CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ */
+package php;
+import Xml;
+
+class PhpXml__ {
+
+	public static var Element(default,null) : XmlType;
+	public static var PCData(default,null) : XmlType;
+	public static var CData(default,null) : XmlType;
+	public static var Comment(default,null) : XmlType;
+	public static var DocType(default,null) : XmlType;
+	public static var Prolog(default,null) : XmlType;
+	public static var Document(default,null) : XmlType;
+
+	public var nodeType(default,null) : XmlType;
+	public var nodeName(getNodeName,setNodeName) : String;
+	public var nodeValue(getNodeValue,setNodeValue) : String;
+	public var parent(getParent,null) : PhpXml__;
+
+	public var _nodeName : String;
+	public var _nodeValue : String;
+	public var _attributes : Hash<String>;
+	public var _children : Array<PhpXml__>;
+	public var _parent : PhpXml__;
+
+	private static var build : PhpXml__;
+	private static function __start_element_handler(parser : Dynamic, name : String, attribs : Array<String>) {
+		var node = createElement(name);
+		untyped __php__("foreach($attribs as $key => $value) $node->set($key, $value)");
+		build.addChild(node);
+		build = node;
+	}
+	
+	private static function __end_element_handler(parser : Dynamic, name : String) {
+//		if(untyped __call__("count", build._children) == 0)
+//			build.addChild(createPCData(""));
+		build = build.getParent();
+	}
+	
+	private static function __character_data_handler(parser : Dynamic, data : String) {
+		// TODO: this function can probably be simplified
+		var lc : PhpXml__ = (build._children == null || untyped __call__("count", build._children) == 0) ? null : build._children[untyped __call__("count", build._children) -1];
+		if(lc != null && Xml.PCData == lc.nodeType) {
+			lc.nodeValue = lc.nodeValue + untyped __call__("htmlentities", data);
+		} else if((untyped __call__("strlen", data) == 1 && __call__("htmlentities", data) != data) || untyped __call__("htmlentities", data) == data) {
+			build.addChild(createPCData(untyped __call__("htmlentities", data)));
+		} else
+			build.addChild(createCData(data));
+	}
+	
+	private static function __default_handler(parser : Dynamic, data : String) {
+		build.addChild(createPCData(data));
+	}
+
+	public static function parse( str : String ) : PhpXml__ {
+		build = createDocument();
+		var xml_parser = untyped __call__("xml_parser_create");
+		untyped __call__("xml_set_element_handler", xml_parser, __start_element_handler, __end_element_handler);
+		untyped __call__("xml_set_character_data_handler", xml_parser, __character_data_handler);
+		untyped __call__("xml_set_default_handler", xml_parser, __default_handler);
+		untyped __call__("xml_parser_set_option", xml_parser, __php__("XML_OPTION_CASE_FOLDING"), 0);
+		untyped __call__("xml_parser_set_option", xml_parser, __php__("XML_OPTION_SKIP_WHITE"), 0);
+
+		if(untyped __call__("xml_parse", xml_parser, str, true) != 1) {
+			throw untyped __call__("xml_error_string", xml_parser) + ", at line #" + __call__("xml_get_current_line_number", xml_parser);
+		}
+		untyped __call__("xml_parser_free", xml_parser);
+		return build;
+	}
+
+	private function new(){
+	}
+
+	public static function createElement( name : String ) : PhpXml__ {
+		var r = new PhpXml__();
+		r.nodeType = Xml.Element;
+		r._children = new Array();
+		r._attributes = new Hash();
+		r.setNodeName( name );
+		return r;
+	}
+
+	public static function createPCData( data : String ) : PhpXml__ {
+		var r = new PhpXml__();
+		r.nodeType = Xml.PCData;
+		r.setNodeValue( data );
+		return r;
+	}
+
+	public static function createCData( data : String ) : PhpXml__ {
+		var r = new PhpXml__();
+		r.nodeType = Xml.CData;
+		r.setNodeValue( data );
+		return r;
+	}
+
+	public static function createComment( data : String ) : PhpXml__ {
+		var r = new PhpXml__();
+		r.nodeType = Xml.Comment;
+		r.setNodeValue( data );
+		return r;
+	}
+
+	public static function createDocType( data : String ) : PhpXml__ {
+		var r = new PhpXml__();
+		r.nodeType = Xml.DocType;
+		r.setNodeValue( data );
+		return r;
+	}
+
+	public static function createProlog( data : String ) : PhpXml__ {
+		var r = new PhpXml__();
+		r.nodeType = Xml.Prolog;
+		r.setNodeValue( data );
+		return r;
+	}
+
+	public static function createDocument() : PhpXml__ {
+		var r = new PhpXml__();
+		r.nodeType = Xml.Document;
+		r._children = new Array();
+		return r;
+	}
+
+	private function getNodeName() : String {
+		if( nodeType != Xml.Element )
+			throw "bad nodeType";
+		return _nodeName;
+	}
+
+	private function setNodeName( n : String ) : String {
+		if( nodeType != Xml.Element )
+			throw "bad nodeType";
+		return _nodeName = n;
+	}
+
+	private function getNodeValue() : String {
+		if( nodeType == Xml.Element || nodeType == Xml.Document )
+			throw "bad nodeType";
+		return _nodeValue;
+	}
+
+	private function setNodeValue( v : String ) : String {
+		if( nodeType == Xml.Element || nodeType == Xml.Document )
+			throw "bad nodeType";
+		return _nodeValue = v;
+	}
+
+	private function getParent() {
+		return _parent;
+	}
+
+	public function get( att : String ) : String {
+		if( nodeType != Xml.Element )
+			throw "bad nodeType";
+		return _attributes.get( att );
+	}
+
+	public function set( att : String, value : String ) : Void {
+		if( nodeType != Xml.Element )
+			throw "bad nodeType";
+		_attributes.set( att, untyped __call__("htmlspecialchars", value, __php__('ENT_COMPAT'), 'UTF-8', true));
+	}
+
+	public function remove( att : String ) : Void{
+		if( nodeType != Xml.Element )
+			throw "bad nodeType";
+		_attributes.remove( att );
+	}
+
+	public function exists( att : String ) : Bool {
+		if( nodeType != Xml.Element )
+			throw "bad nodeType";
+		return _attributes.exists( att );
+	}
+
+	public function attributes() : Iterator<String> {
+		if( nodeType != Xml.Element )
+			throw "bad nodeType";
+		return _attributes.keys();
+	}
+
+	public function iterator() : Iterator<PhpXml__> {
+		if( _children == null ) throw "bad nodetype";
+		return untyped {
+			cur: 0,
+			x: this._children,
+			hasNext : function(){
+				return this.cur < __call__("count", this.x);
+			},
+			next : function(){
+				return this.x[this.cur++];
+			}
+		}
+	}
+
+	public function elements(){
+		if( _children == null ) throw "bad nodetype";
+		return untyped {
+			cur: 0,
+			x: this._children,
+			hasNext : function() {
+				var k = this.cur;
+				var l = __call__("count", this.x);
+				while( k < l ) {
+				
+					if( this.x[k].nodeType == Xml.Element )
+						untyped __php__("break");
+					k += 1;
+				}
+				this.cur = k;
+				return k < l;
+			},
+			next : function() {
+				var k = this.cur;
+				var l = __call__("count", this.x);
+				while( k < l ) {
+					var n = this.x[k];
+					k += 1;
+					if( n.nodeType == Xml.Element ) {
+						this.cur = k;
+						return n;
+					}
+				}
+				return null;
+			}
+		}
+	}
+
+	public function elementsNamed( name : String ) {
+		if( _children == null ) throw "bad nodetype";
+		return untyped {
+			cur: 0,
+			x: this._children,
+			hasNext : function() {
+				var k = this.cur;
+				var l = __call__("count", this.x);
+				while( k < l ) {
+					var n = this.x[k];
+					if( n.nodeType == Xml.Element && n._nodeName == name )
+						untyped __php__("break");
+					k++;
+				}
+				this.cur = k;
+				return k < l;
+			},
+			next : function() {
+				var k = this.cur;
+				var l = __call__("count", this.x);
+				while( k < l ) {
+					var n = this.x[k];
+					k++;
+					if( n.nodeType == Xml.Element && n._nodeName == name ) {
+						this.cur = k;
+						return n;
+					}
+				}
+				return null;
+			}
+		}
+	}
+
+	public function firstChild() : PhpXml__ {
+		if( _children == null ) throw "bad nodetype";
+		return _children[0];
+	}
+
+	public function firstElement() : PhpXml__ {
+		if( _children == null ) throw "bad nodetype";
+		var cur = 0;
+		var l = _children.length;
+		while( cur < l ) {
+			var n = _children[cur];
+			if( n.nodeType == Xml.Element )
+				return n;
+			cur++;
+		}
+		return null;
+	}
+
+	public function addChild( x : PhpXml__ ) : Void {
+		if( _children == null ) throw "bad nodetype";
+		if( x._parent != null ) x._parent._children.remove(x);
+		x._parent = this;
+		_children.push( x );
+	}
+
+	public function removeChild( x : PhpXml__ ) : Bool {
+		if( _children == null ) throw "bad nodetype";
+		var b = _children.remove( x );
+		if( b )
+			x._parent = null;
+		return b;
+	}
+
+	public function insertChild( x : PhpXml__, pos : Int ) : Void {
+		if( _children == null ) throw "bad nodetype";
+		if( x._parent != null ) x._parent._children.remove(x);
+		x._parent = this;
+		_children.insert( pos, x );
+	}
+
+	public function toString() {
+		if( nodeType == Xml.PCData )
+			return _nodeValue;
+		if( nodeType == Xml.CData )
+			return "<![CDATA["+_nodeValue+"]]>";
+		if( nodeType == Xml.Comment || nodeType == Xml.DocType || nodeType == Xml.Prolog )
+			return _nodeValue;
+
+		var s = "";
+
+		if( nodeType == Xml.Element ) {
+			s += "<";
+			s += _nodeName;
+			for( k in _attributes.keys() ){
+				s += " ";
+				s += k;
+				s += "=\""; // \"
+				s += _attributes.get(k);
+				s += "\""; // \"
+			}
+			if( _children.length == 0 ) {
+				s += "/>";
+				return s;
+			}
+			s += ">";
+		}
+
+		for( x in iterator() )
+			s += x.toString();
+
+		if( nodeType == Xml.Element ) {
+			s += "</";
+			s += _nodeName;
+			s += ">";
+		}
+		return s;
+	}
+	
+	static function __init__() : Void untyped {
+		PhpXml__.Element = "element";
+		PhpXml__.PCData = "pcdata";
+		PhpXml__.CData = "cdata";
+		PhpXml__.Comment = "comment";
+		PhpXml__.DocType = "doctype";
+		PhpXml__.Prolog = "prolog";
+		PhpXml__.Document = "document";
+	}
+
+}

+ 139 - 0
std/php/Session.hx

@@ -0,0 +1,139 @@
+package php;
+/**
+* TODO: TEST IT!
+*/
+class Session {	
+	public static function getCacheLimiter() {
+		switch(untyped __call__("session_cache_limiter")) {
+			case "public":
+				return Public;
+			case "private":
+				return Private;
+			case "nocache":
+				return NoCache;
+			case "private_no_expire":
+				return PrivateNoExpire;
+		}
+		return null;
+	}	
+	
+	public static function setCacheLimiter(l : CacheLimiter) {
+		if(_started) throw "You can't set the cache limiter while the session is already in use";
+		switch(l) {
+			case Public:
+				untyped __call__("session_cache_limiter", "public");
+			case Private:
+				untyped __call__("session_cache_limiter", "private");
+			case NoCache:
+				untyped __call__("session_cache_limiter", "nocache");
+			case PrivateNoExpire:
+				untyped __call__("session_cache_limiter", "private_no_expire");
+		}
+	}
+	
+	public static function getCacheExpire() : Int {
+		return untyped __call__("session_cache_expire");
+	}
+	
+	public static function setCacheExpire(minutes : Int) {
+		if(_started) throw "You can't set the cache expire time while the session is already in use";
+		untyped __call__("session_cache_expire", minutes);
+	}
+	
+	public static function setName(name : String) {
+		if(_started) throw "You can't set the name while the session is already in use";
+		untyped __call__("session_name", name);
+	}
+	
+	public static function getName() : String {
+		return untyped __call__("session_name");
+	}
+	
+	public static function getId() : String {
+		return untyped __call__("session_id");
+	}
+	
+	public static function setId(id : String) {
+		if(_started) throw "You can't set the session id while the session is already in use";
+		untyped __call__("session_id", id);
+	}
+
+	public static function getSavePath() : String {
+		return untyped __call__("session_save_path");
+	}
+	
+	public static function setSavePath(path : String) {
+		if(_started) throw "You can't set the save path while the session is already in use";
+		untyped __call__("session_save_path", path);
+	}
+	
+	public static function getModule() : String {
+		return untyped __call__("session_module_name");
+	}
+	
+	public static function setModule(module : String) {
+		if(_started) throw "You can't set the module while the session is already in use";
+		untyped __call__("session_module_name", module);
+	}
+	
+	public static function regenerateId(?deleteold : Bool) : Bool {
+		return untyped __call__("session_regenerate_id", deleteold);
+	}
+	
+	public static function get(name : String) : Dynamic {
+		start();
+		return untyped __var__("_SESSION", name);
+	}
+	
+	public static function set(name : String, value : Dynamic) {
+		start();
+		return untyped __set__("_SESSION", name, value);
+	}
+	
+	public static function setCookieParams(?lifetime : Int, ?path : String, ?domain : String, ?secure : Bool, ?httponly : Bool) {
+		if(_started) throw "You can't set the cookie params while the session is already in use";
+		untyped __call__("session_get_cookie_params", lifetime, path, domain, secure, httponly);
+	}
+	
+	public static function getCookieParams() : { lifetime : Int, path : String, domain : String, secure : Bool, httponly : Bool} {
+		return php.Boot.__anonymous(untyped __call__("session_get_cookie_params"));
+	}
+	
+	// TODO: completely untested
+	public static function setSaveHandler(open : String -> String -> Bool, close : Void -> Bool, read : String -> String, write : String -> String -> Bool, destroy, gc) : Bool {
+		return untyped __call__("session_set_save_handler", open, close, read, write, destroy, gc);
+	}
+	
+	public static function exists(name : String) {
+		start();
+		return untyped __call__("array_key_exists", name, __var__("_SESSION"));
+	}
+	
+	public static function remove(name : String) {
+		start();
+		untyped __call__("unset", __var__("_SESSION", name));
+	}
+	
+	private static var _started = false;
+	private static function start() {
+		if(_started) return;
+		_started = true;
+		untyped __call__("session_start");
+	}
+	
+	public function clear() {
+		untyped __call__("session_unset");
+	}
+	
+	public function close() {
+		untyped __call__("session_write_close");
+		_started = false; // TODO: not sure this useful; test if a closed session can be re-opened (I doubt)
+	}
+}
+
+enum CacheLimiter {
+	Public;
+	Private;
+	NoCache;
+	PrivateNoExpire;
+}

+ 86 - 0
std/php/Sys.hx

@@ -0,0 +1,86 @@
+package php;
+
+
+class Sys {	
+	public static function args() : Array<String> {
+		return untyped __php__("array_key_exists('argvs', $_SERVER) ? $_SERVER['argv'] : array()");
+	}
+
+	public static function getEnv( s : String ) : String {
+		return untyped __call__("getenv");
+	}
+
+	public static function putEnv( s : String, v : String ) : Void {
+		return untyped __call__("putenv", s + "=" + v);
+	}
+
+	public static function sleep( seconds : Float ) {
+		return untyped __call__("putenv", seconds);
+	}
+
+	public static function setTimeLocale( loc : String ) : Bool {
+		return untyped __call__("setlocale", __php__("LC_TIME"), loc) != false;
+	}
+
+	public static function getCwd() : String {
+		var cwd : String = untyped __call__("getcwd");
+		var l = cwd.substr(-1);
+		return cwd + (l == '/' || l == '\\' ? '' : '/');
+	}
+
+	public static function setCwd( s : String ) {
+		return untyped __call__("chdir", s);
+	}
+
+	public static function systemName() : String {
+		var s : String = untyped __call__("php_uname", "s");
+		var p : Int;
+		if((p = s.indexOf(" ")) >= 0)
+			return s.substr(0, p);
+		else
+			return s;
+	}
+
+	public static function escapeArgument( arg : String ) : String {
+		var ok = true;
+		for( i in 0...arg.length )
+			switch( arg.charCodeAt(i) ) {
+			case 32, 34: // [space] "
+				ok = false;
+			case 0, 13, 10: // [eof] [cr] [lf]
+				arg = arg.substr(0,i);
+			}
+		if( ok )
+			return arg;
+		return '"'+arg.split('"').join('\\"')+'"';
+	}
+
+	public static function command( cmd : String, ?args : Array<String> ) : Int {
+		if( args != null ) {
+			cmd = escapeArgument(cmd);
+			for( a in args )
+				cmd += " "+escapeArgument(a);
+		}
+		return untyped __call__("system", cmd);
+	}
+
+	public static function exit( code : Int ) {
+		return untyped __call__("exit", code);
+	}
+
+	public static function time() : Float {
+		return untyped __call__("microtime", true);
+	}
+
+	public static function cpuTime() : Float {
+		return untyped __call__("microtime", true) - __php__("$_SERVER['REQUEST_TIME']");
+	}
+
+	public static function executablePath() : String {
+		return untyped __php__("$_SERVER['SCRIPT_FILENAME']");
+	}
+
+	public static function environment() : Hash<String> {
+		return Hash.fromAssociativeArray(untyped __php__("$_SERVER"));
+	}
+}

+ 87 - 0
std/php/Utf8.hx

@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2005, The haXe Project Contributors
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   - Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *   - Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE HAXE PROJECT CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE HAXE PROJECT CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ */
+package php;
+
+class Utf8 {
+
+	var __b : String;
+
+	public function new() {
+		__b = '';
+	}
+
+	public function addChar( c : Int ) {
+		__b += uchr(c);
+	}
+
+	public function toString() : String {
+		return __b;
+	}
+
+	public static function encode( s : String ) : String {
+		return untyped __call__("utf8_encode", s);
+	}
+
+	public static function decode( s : String ) : String {
+		return untyped __call__("utf8_decode", s);
+	}
+
+	public static function iter(s : String, chars : Int -> Void ) {
+		var len = length(s);
+		for(i in 0...len)
+			chars(charCodeAt(s, i));
+	}
+
+	public static function charCodeAt( s : String, index : Int ) : Int {
+		return uord(sub(s, index, 1));
+	}
+
+	public static function uchr(i : Int) : String {
+		return untyped __php__("mb_convert_encoding(pack('N',$i), mb_internal_encoding(), 'UCS-4BE')");
+	}
+
+	public static function uord(s : String) : Int untyped {
+		var c : Array<Int> = untyped __php__("unpack('N', mb_convert_encoding($s, 'UCS-4BE', 'UTF-8'))");
+		return c[1];
+	}
+	
+	public static function validate( s : String ) : Bool {
+		return untyped __call__("mb_check_encoding", s, enc);
+	}
+
+	public static function length( s : String ) : Int {
+		return untyped __call__("mb_strlen", s, enc);
+	}
+
+	public static function compare( a : String, b : String ) : Int {
+		return untyped __call__("strcmp", a, b);
+	}
+
+	public static function sub( s : String, pos : Int, len : Int ) : String {
+		return untyped __call__("mb_substr", s, pos, len, enc);
+	}
+	
+	private static inline var enc = "UTF-8";
+}

+ 333 - 0
std/php/Web.hx

@@ -0,0 +1,333 @@
+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() {
+		var a : Array<String> = 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 Hash.fromAssociativeArray(a);
+	}
+
+	/**
+		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<String> {
+		var reg = new EReg("^"+param+"(\\[|%5B)([0-9]*?)(\\]|%5D)=(.*?)$", "");
+		var res = new Array<String>();
+		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 inline function getURI() : String {
+		return untyped __var__('_SERVER', 'REQUEST_URI');
+	}
+
+	/**
+		Tell the client to redirect to the given url ("Location" header)
+	**/
+	public static function redirect( url : String ) {
+		untyped __call__('header', "Location: " + url);
+		untyped __call__('exit');
+	}
+
+	/**
+		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 = Hash.fromAssociativeArray(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<String>();
+		var k = "";
+		var h1 = Hash.fromAssociativeArray(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<String> {
+		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<String> = 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();
+	}
+}

+ 38 - 0
std/php/db/Connection.hx

@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2005, The haXe Project Contributors
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   - Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *   - Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE HAXE PROJECT CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE HAXE PROJECT CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ */
+package php.db;
+
+interface Connection {
+
+	function request( s : String ) : ResultSet;
+	function close() : Void;
+	function escape( s : String ) : String;
+	function quote( s : String ) : String;
+	function lastInsertId() : Int;
+	function dbName() : String;
+	function startTransaction() : Void;
+	function commit() : Void;
+	function rollback() : Void;
+}

+ 158 - 0
std/php/db/DBase.hx

@@ -0,0 +1,158 @@
+/*
+ * Copyright (c) 2005, The haXe Project Contributors
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   - Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *   - Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE HAXE PROJECT CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE HAXE PROJECT CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ */
+package php.db;
+
+private class DBaseConnection {
+
+	var c : Void;
+	var fields : Array<Field>;
+	
+	public function new( file : String, mode : Int) {
+		c = untyped __call__("dbase_open", file, mode);
+		if(c == null) throw "Invalid dBase file: " + file;
+		var infos : Array<Dynamic> = untyped __call__("dbase_get_header_info", c);
+		fields = [];
+		for(info in infos) {
+			fields.push({
+				name : info[untyped 'name'],
+				type : getType(info)
+			});
+		}
+	}
+
+	public function close() {
+		untyped __call__("dbase_close", c);
+		untyped __call__("unset", c);
+	}
+
+	public function count() {
+		return untyped __call__("dbase_numrecords", c);
+	}
+
+	public function insert(values : Array<Dynamic>) : Bool {
+		return untyped __call__("dbase_add_record", c, values);
+	}
+	
+	public function replace(index : Int, values : Array<Dynamic>) {
+		return untyped __call__("dbase_replace_record", c, values, index);
+	}
+	
+	public function delete(index : Int) : Bool {
+		return untyped __call__("dbase_delete_record", c, index);
+	}
+	
+	public function records() : Array<Dynamic> {
+		var arr = [];
+		for(i in 1...count()+1)
+			arr.push(record(i));
+		return arr;
+	}
+	
+	public function rows() : Array<Array<Dynamic>> {
+		var arr = [];
+		for(i in 1...count()+1)
+			arr.push(row(i));
+		return arr;
+	}
+	
+	public function row(index : Int) : Array<Dynamic> {
+		var r = untyped __call__("dbase_get_record", c, index);
+		if(untyped __php__("isset($r['deleted'])")) {
+			untyped __php__("unset($r['deleted'])");
+		}
+		return r;
+	}
+	
+	public function record(index : Int) : Dynamic {
+		var row = row(index);
+		var record = {};
+		for(j in 0...fields.length)
+			Reflect.setField(record, fields[j].name, row[j]);
+		return record;
+	}
+	
+	private function getType(info : Array<Dynamic>) {
+		switch(info[untyped 'type']) {
+			case 'D': return DateField;
+			case 'N': return NumberField(info[untyped 'length'], info[untyped 'precision']);
+			case 'C': return StringField(info[untyped 'length']);
+			case 'L': return BooleanField;
+			case 'F': return FloatField;
+		}
+		return null;
+	}
+}
+
+class DBase {
+
+	public static function open( file : String ) : DBaseConnection {
+		return new DBaseConnection(file, 2);
+	}
+
+	public static function openReadOnly( file : String ) : DBaseConnection {
+		return new DBaseConnection(file, 0);
+	}
+	
+	public static function create(file : String, fields : Array<Field>) : Void {
+		var flds : Array<Array<Dynamic>> = [];
+		for(field in fields) {
+			var fld : Array<Dynamic>= [];
+			fld.push(field.name);
+			switch(field.type) {
+				case DateField:
+					fld.push('D');
+				case NumberField(len, precision):
+					fld.push('N');
+					fld.push(len);
+					fld.push(precision);
+				case StringField(len):
+					fld.push('C');
+					fld.push(len);
+				case BooleanField:
+					fld.push('L');
+				case FloatField:
+					fld.push('F');
+			}
+			flds.push(fld);
+		}
+		var h = untyped __call__("dbase_create", file, flds);
+		if(h == false) throw "Error creating: " + file;
+		untyped __call__("dbase_close", h);
+	}
+}
+
+typedef Field = {
+	name : String, // max 10 chars
+	type : FieldType
+}
+
+enum FieldType {
+//	MemoField;
+	DateField;
+	NumberField(len : Int, precision : Int);
+	StringField(len : Int);
+	BooleanField;
+	FloatField;
+}

+ 492 - 0
std/php/db/Manager.hx

@@ -0,0 +1,492 @@
+/*
+ * Copyright (c) 2005, The haXe Project Contributors
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   - Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *   - Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE HAXE PROJECT CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE HAXE PROJECT CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ */
+package php.db;
+
+import Reflect;
+import php.db.Connection;
+
+/**
+	SPOD Manager : the persistent object database manager. See the tutorial on
+	haXe website to learn how to use SPOD.
+**/
+class Manager<T : Object> {
+
+	/* ----------------------------- STATICS ------------------------------ */
+	public static var cnx(default,setConnection) : Connection;
+	private static var object_cache : Hash<Object> = new Hash();
+//	private static var init_list : List<Manager<Object>> = new List();
+	private static var cache_field = "__cache__";
+	private static var no_update : Dynamic = function() { throw "Cannot update not locked object"; }
+	private static var FOR_UPDATE = "";
+	
+	public static var managers = new Hash<Manager<Dynamic>>();
+
+	private static dynamic function setConnection( c : Connection ) {
+		Reflect.setField(Manager,"cnx",c);
+		if( c != null )
+			FOR_UPDATE = if( c.dbName() == "MySQL" ) " FOR UPDATE" else "";
+		return c;
+	}
+
+	/* ---------------------------- BASIC API ----------------------------- */
+	var table_name : String;
+	var table_fields : List<String>;
+	var table_keys : Array<String>;
+	var cls : Dynamic; //Class<php.db.Object>;
+
+	public function new( classval : Class<php.db.Object> ) {
+		cls = classval;
+		var clname = Type.getClassName(cls);
+		// get basic infos
+		table_name = quoteField((cls.TABLE_NAME != null ) ? cls.TABLE_NAME : clname.split('.').pop());
+		table_keys = if( cls.TABLE_IDS != null ) cls.TABLE_IDS else ["id"];
+
+		// get the list of private fields
+		var apriv : Array<String> = cls.PRIVATE_FIELDS;
+		apriv = if( apriv == null ) new Array() else apriv.copy();
+		apriv.push("local_manager");
+		apriv.push("__cache__");
+		apriv.push("update");
+		
+		// get the proto fields not marked private (excluding methods)
+		table_fields = new List();
+		var stub = Type.createEmptyInstance(cls);
+
+		for( f in Type.getInstanceFields(cls) ) {
+			var isfield = !Reflect.isFunction(Reflect.field(stub,f));
+			if( isfield )
+				for( f2 in apriv ) {
+					if(f == f2 ) {
+						isfield = false;
+						break;
+					}
+				}
+			if( isfield ) {
+				table_fields.add(f);
+			}
+		}
+
+		// set the manager and ready for further init
+		//proto.local_manager = this;
+		managers.set(clname, this);
+//		init_list.add(untyped this);
+
+		var rl : Array<Dynamic>;
+		try {
+		  rl = untyped cls.RELATIONS();
+		} catch(e : Dynamic) { return; }
+		for(r in rl) {
+			// remove prop from precomputed table_fields
+			// always add key to table fields (even if not declared)
+			table_fields.remove(r.prop);
+			table_fields.remove("get_" + r.prop);
+			table_fields.remove("set_" + r.prop);
+			table_fields.remove(r.key);
+			table_fields.add(r.key);
+		}
+	}
+
+	public function get( id : Int, ?lock : Bool ) : T {
+		if( lock == null )
+			lock = true;
+		if( table_keys.length != 1 )
+			throw "Invalid number of keys";
+		if( id == null )
+			return null;
+		var x : Dynamic = untyped object_cache.get(id + table_name);
+		if( x != null && (!lock || x.update != no_update) )
+			return x;
+		var s = new StringBuf();
+		s.add("SELECT * FROM ");
+		s.add(table_name);
+		s.add(" WHERE ");
+		s.add(quoteField(table_keys[0]));
+		s.add(" = ");
+		addQuote(s,id);
+		if( lock )
+			s.add(FOR_UPDATE);
+		return object(s.toString(),lock);
+	}
+
+	public function getWithKeys( keys : {}, ?lock : Bool ) : T {
+		if( lock == null )
+			lock = true;
+		var x : Dynamic = getFromCache(untyped keys,false);
+		if( x != null && (!lock || x.update != no_update) )
+			return x;
+		var s = new StringBuf();
+		s.add("SELECT * FROM ");
+		s.add(table_name);
+		s.add(" WHERE ");
+		addKeys(s,keys);
+		if( lock )
+			s.add(FOR_UPDATE);
+		return object(s.toString(),lock);
+	}
+
+	public function delete( x : {} ) {
+		var s = new StringBuf();
+		s.add("DELETE FROM ");
+		s.add(table_name);
+		s.add(" WHERE ");
+		addCondition(s,x);
+		execute(s.toString());
+	}
+
+	public function search( x : {}, ?lock : Bool ) : List<T> {
+		if( lock == null )
+			lock = true;
+		var s = new StringBuf();
+		s.add("SELECT * FROM ");
+		s.add(table_name);
+		s.add(" WHERE ");
+		addCondition(s,x);
+		if( lock )
+			s.add(FOR_UPDATE);
+		return objects(s.toString(),lock);
+	}
+
+	function addCondition(s : StringBuf,x) {
+		var first = true;
+		if( x != null )
+			for( f in Reflect.fields(x) ) {
+				if( first )
+					first = false;
+				else
+					s.add(" AND ");
+				s.add(quoteField(f));
+				var d = Reflect.field(x,f);
+				if( d == null )
+					s.add(" IS NULL");
+				else {
+					s.add(" = ");
+					addQuote(s,d);
+				}
+			}
+		if( first )
+			s.add("1");
+	}
+
+	public function all( ?lock: Bool ) : List<T> {
+		if( lock == null )
+			lock = true;
+		return objects("SELECT * FROM " + table_name + if( lock ) FOR_UPDATE else "",lock);
+	}
+
+	public function count( ?x : {} ) : Int {
+		var s = new StringBuf();
+		s.add("SELECT COUNT(*) FROM ");
+		s.add(table_name);
+		s.add(" WHERE ");
+		addCondition(s,x);
+		return execute(s.toString()).getIntResult(0);
+	}
+
+	public function quote( s : String ) : String {
+		return cnx.quote( s );
+	}
+
+	public function result( sql : String ) : Dynamic {
+		return cnx.request(sql).next();
+	}
+
+	public function results<T>( sql : String ) : List<T> {
+		return cast cnx.request(sql).results();
+	}
+
+	/* -------------------------- SPODOBJECT API -------------------------- */
+
+	function doInsert( x : T ) {
+		unmake(x);
+		var s = new StringBuf();
+		var fields = new List();
+		var values = new List();
+		for( f in table_fields ) {
+			var v = Reflect.field(x,f);
+			if( v != null ) {
+				fields.add(quoteField(f));
+				values.add(v);
+			}
+		}
+		s.add("INSERT INTO ");
+		s.add(table_name);
+		s.add(" (");
+		s.add(fields.join(","));
+		s.add(") VALUES (");
+		var first = true;
+		for( v in values ) {
+			if( first )
+				first = false;
+			else
+				s.add(", ");
+			addQuote(s,v);
+		}
+		s.add(")");
+		execute(s.toString());
+		// table with one key not defined : suppose autoincrement
+		if( table_keys.length == 1 && Reflect.field(x,table_keys[0]) == null )
+			Reflect.setField(x,table_keys[0],cnx.lastInsertId());
+		addToCache(x);
+	}
+
+	function doUpdate( x : T ) {
+		unmake(x);
+		var s = new StringBuf();
+		s.add("UPDATE ");
+		s.add(table_name);
+		s.add(" SET ");
+		var cache = Reflect.field(x,cache_field);
+		var mod = false;
+		for( f in table_fields ) {
+			var v = Reflect.field(x,f);
+			var vc = Reflect.field(cache,f);
+			if( v != vc ) {
+				if( mod )
+					s.add(", ");
+				else
+					mod = true;
+				s.add(quoteField(f));
+				s.add(" = ");
+				addQuote(s,v);
+				Reflect.setField(cache,f,v);
+			}
+		}
+		if( !mod )
+			return;
+		s.add(" WHERE ");
+		addKeys(s,x);
+		execute(s.toString());
+	}
+
+	function doDelete( x : T ) {
+		var s = new StringBuf();
+		s.add("DELETE FROM ");
+		s.add(table_name);
+		s.add(" WHERE ");
+		addKeys(s,x);
+		execute(s.toString());
+	}
+
+
+	function doSync( i : T ) {
+		object_cache.remove(makeCacheKey(i));
+		var i2 = getWithKeys(i, untyped i.update != no_update);
+		// delete all fields
+		for( f in Reflect.fields(i) )
+			Reflect.deleteField(i,f);
+		// copy fields from new object
+		for( f in Reflect.fields(i2) )
+			Reflect.setField(i,f,Reflect.field(i2,f));
+		// set same field-cache
+		Reflect.setField(i,cache_field,Reflect.field(i2,cache_field));
+		addToCache(i);
+	}
+
+	function objectToString( it : T ) : String {
+		var s = new StringBuf();
+		s.add(table_name);
+		if( table_keys.length == 1 ) {
+			s.add("#");
+			s.add(Reflect.field(it,table_keys[0]));
+		} else {
+			s.add("(");
+			var first = true;
+			for( f in table_keys ) {
+				if( first )
+					first = false;
+				else
+					s.add(",");
+				s.add(quoteField(f));
+				s.add(":");
+				s.add(Reflect.field(it,f));
+			}
+			s.add(")");
+		}
+		return s.toString();
+	}
+
+	/* ---------------------------- INTERNAL API -------------------------- */
+
+	function cacheObject( x : T, lock : Bool ) {
+		addToCache(x);
+		Reflect.setField(x, cache_field, Type.createEmptyInstance(cls));
+		if( !lock )
+			x.update = no_update;
+	}
+
+	function make( x : T ) {
+	}
+
+	function unmake( x : T ) {
+	}
+
+	function quoteField(f : String) {
+		var fsmall = f.toLowerCase();
+		if( fsmall == "read" || fsmall == "desc" || fsmall == "out" || fsmall == "group" || fsmall == "version" || fsmall == "option" )
+			return "`"+f+"`";
+		return f;
+	}
+
+	function addQuote( s : StringBuf, v : Dynamic ) {
+		if( untyped __call__("is_int", v) || __call__("is_null", v))
+			s.add(v);
+		else if( untyped __call__("is_bool", v) )
+			s.add(if( v ) 1 else 0);
+		else
+			s.add(cnx.quote(Std.string(v)));
+	}
+
+	function addKeys( s : StringBuf, x : {} ) {
+		var first = true;
+		for( k in table_keys ) {
+			if( first )
+				first = false;
+			else
+				s.add(" AND ");
+			s.add(quoteField(k));
+			s.add(" = ");
+			var f = Reflect.field(x,k);
+			if( f == null )
+				throw ("Missing key "+k);
+			addQuote(s,f);
+		}
+	}
+
+	function execute( sql : String ) {
+		return cnx.request(sql);
+	}
+
+	function select( cond : String ) {
+		var s = new StringBuf();
+		s.add("SELECT * FROM ");
+		s.add(table_name);
+		s.add(" WHERE ");
+		s.add(cond);
+		s.add(FOR_UPDATE);
+		return s.toString();
+	}
+
+	function selectReadOnly( cond : String ) {
+		var s = new StringBuf();
+		s.add("SELECT * FROM ");
+		s.add(table_name);
+		s.add(" WHERE ");
+		s.add(cond);
+		return s.toString();
+	}
+
+	public function object( sql : String, lock : Bool ) : T {
+		var r = cnx.request(sql).next();
+		if( r == null )
+			return null;
+		var c = getFromCache(r,lock);
+		if( c != null )
+			return c;
+		cacheObject(r,lock);
+		make(r);
+		return r;
+	}
+
+	public function objects( sql : String, lock : Bool ) : List<T> {
+		var me = this;
+		var l = cnx.request(sql).results();
+		var l2 = new List<T>();
+		for( x in l ) {
+			var c = getFromCache(x,lock);
+			if( c != null )
+				l2.add(c);
+			else {
+				cacheObject(x,lock);
+				make(x);
+				l2.add(x);
+			}
+		}
+		return l2;
+	}
+
+	/* --------------------------- INIT / CLEANUP ------------------------- */
+
+	/**
+	* Left for compability with neko SPOD
+	*/
+	public static function initialize() {
+
+	}
+
+	public static function cleanup() {
+		object_cache = new Hash();
+	}
+
+	function initRelation(o : Dynamic, r : { prop : String, key : String, manager : Manager<Object>, lock : Bool } ) {
+		// setup getter/setter
+		var manager = r.manager;
+		var hkey = r.key;
+		var lock = r.lock;
+		if( lock == null ) lock = true;
+		if( manager == null || manager.table_keys == null ) throw ("Invalid manager for relation "+table_name+":"+r.prop);
+		if( manager.table_keys.length != 1 ) throw ("Relation "+r.prop+"("+r.key+") on a multiple key table");
+		Reflect.setField(o,"get_"+r.prop,function() {
+			return manager.get(Reflect.field(o,hkey), lock);
+		});
+		Reflect.setField(o,"set_"+r.prop,function(f) {
+			Reflect.setField(o, hkey, Reflect.field(f, manager.table_keys[0]));
+			return f;
+		});
+	}
+
+	/* ---------------------------- OBJECT CACHE -------------------------- */
+
+	function makeCacheKey( x : T ) : String {
+		if( table_keys.length == 1 ) {
+			var k = Reflect.field(x,table_keys[0]);
+			if( k == null )
+				throw("Missing key "+table_keys[0]);
+			return Std.string(k)+table_name;
+		}
+		var s = new StringBuf();
+		for( k in table_keys ) {
+			var v = Reflect.field(x,k);
+			if( k == null )
+				throw("Missing key "+k);
+			s.add(v);
+			s.add("#");
+		}
+		s.add(table_name);
+		return s.toString();
+	}
+
+	function addToCache( x : T ) {
+		object_cache.set(makeCacheKey(x),x);
+	}
+
+	function getFromCache( x : T, lock : Bool ) : T {
+		var c : Dynamic = object_cache.get(makeCacheKey(x));
+		// restore update method since now the object is locked
+		if( c != null && lock && c.update == no_update )
+			//c.update = class_proto.prototype.update;
+			c.update = untyped cls.update;
+		return c;
+	}
+}

+ 153 - 0
std/php/db/Mysql.hx

@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 2005, The haXe Project Contributors
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   - Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *   - Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE HAXE PROJECT CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE HAXE PROJECT CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ */
+package php.db;
+
+import php.db.Connection;
+
+private class MysqlConnection implements Connection {
+
+	var c : Void;
+
+	public function new( c : Void) {
+		this.c = c;
+	}
+
+	public function close() {
+		untyped __call__("mysql_close", c);
+		untyped __call__("unset", c);
+	}
+
+	public function request( s : String ) : ResultSet {
+		var h = untyped __call__("mysql_query", s, c);
+		if(untyped __physeq__(h, false))
+			throw "Error while executing "+s+" ("+untyped __call__("mysql_error", c)+")";
+		return new MysqlResultSet(cast h);
+	}
+
+	public function escape( s : String ) {
+		return untyped __call__("mysql_real_escape_string", s, c);
+	}
+
+	public function quote( s : String ) {
+		return "'" + untyped __call__("mysql_real_escape_string", s, c) + "'";
+	}
+
+	public function lastInsertId() {
+		return untyped __call__("mysql_insert_id", c);
+	}
+
+	public function dbName() {
+		return "MySQL";
+	}
+
+	public function startTransaction() {
+		request("START TRANSACTION");
+	}
+
+	public function commit() {
+		request("COMMIT");
+	}
+
+	public function rollback() {
+		request("ROLLBACK");
+	}
+}
+
+
+private class MysqlResultSet implements ResultSet {
+	public var length(getLength,null) : Int;
+	public var nfields(getNFields,null) : Int;
+	private var __r : Void;
+	private var cache : Dynamic;
+
+	public function new(r) {
+		__r = r;
+	}
+
+	private function getLength() {
+		return untyped __call__("mysql_num_rows", __r);
+	}
+
+	private function getNFields() {
+		return untyped __call__("mysql_num_fields", __r);
+	}
+
+	public function hasNext() {
+		if( cache == null )
+			cache = next();
+		return (cache != null);
+	}
+
+	public function next() : Dynamic {
+		var c = cache;
+		if( c != null ) {
+			cache = null;
+			return c;
+		}
+		c = untyped __call__("mysql_fetch_array", __r);
+		if(untyped __physeq__(c, false))
+			return null;
+		return php.Boot.__anonymous(c);
+	}
+
+	public function results() : List<Dynamic> {
+		var l = new List();
+		while( hasNext() )
+			l.add(next());
+		return l;
+	}
+
+	public function getResult( n : Int ) : String {
+		return Reflect.field(next(), cast n);
+	}
+
+	public function getIntResult( n : Int ) : Int {
+		return untyped __call__("intval", Reflect.field(next(), cast n));
+	}
+
+	public function getFloatResult( n : Int ) : Float {
+		return untyped __call__("floatval", Reflect.field(next(), cast n));
+	}
+}
+
+class Mysql {
+
+	public static function connect( params : {
+		host : String,
+		port : Int,
+		user : String,
+		pass : String,
+		socket : String,
+		database : String
+	} ) : php.db.Connection {
+		var c = untyped __call__("mysql_connect", 
+			params.host + (params.port == null ? '' : ':'+params.port) + (params.socket == null ? '' : ':'+params.socket),
+			params.user,
+			params.pass);
+		untyped __call__("mysql_select_db", params.database, c);
+		return new MysqlConnection(c);
+	}
+
+}

+ 89 - 0
std/php/db/Object.hx

@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2005, The haXe Project Contributors
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   - Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *   - Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE HAXE PROJECT CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE HAXE PROJECT CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ */
+package php.db;
+
+/**
+	SPOD Object : the persistent object base type. See the tutorial on haXe
+	website to learn how to use SPOD.
+**/
+class Object #if spod_rtti implements haxe.rtti.Infos #end {
+
+/*
+	(optional)
+	static var TABLE_NAME = "TableName";
+	static var TABLE_IDS = ["id"];
+	static var PRIVATE_FIELDS = ["my_priv_field"];
+	static function RELATIONS() {
+		return [{ key : "uid", prop : "user", manager : User.manager }];
+	}
+
+	static var manager = new php.db.Manager();
+*/
+
+	var local_manager : {
+		private function doUpdate( o : Object ) : Void;
+		private function doInsert( o : Object ) : Void;
+		private function doSync( o : Object ) : Void;
+		private function doDelete( o : Object ) : Void;
+		private function objectToString( o : Object ) : String;
+	};
+
+	var __cache__ : Object;
+
+	public function new() {
+		__init_object();
+	}
+	
+	private function __init_object() {
+		local_manager = Manager.managers.get(Type.getClassName(Type.getClass(this)));
+		var rl : Array<Dynamic>;
+		try {
+			rl = untyped local_manager.cls.RELATIONS();
+		} catch(e : Dynamic) { return; }
+		for(r in rl)
+			untyped local_manager.initRelation(this, r);
+	}
+
+	public function insert() {
+		local_manager.doInsert(this);
+	}
+
+	public dynamic function update() {
+		local_manager.doUpdate(this);
+	}
+
+	public function sync() {
+		local_manager.doSync(this);
+	}
+
+	public function delete() {
+		local_manager.doDelete(this);
+	}
+
+	public function toString() {
+		return local_manager.objectToString(this);
+	}
+
+}

+ 40 - 0
std/php/db/ResultSet.hx

@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2005, The haXe Project Contributors
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   - Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *   - Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE HAXE PROJECT CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE HAXE PROJECT CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ */
+package php.db;
+
+interface ResultSet {
+
+	var length(getLength,null) : Int;
+	var nfields(getNFields,null) : Int;
+
+
+	function hasNext() : Bool;
+	function next() : Dynamic;
+	function results() : List<Dynamic>;
+	function getResult( n : Int ) : String;
+	function getIntResult( n : Int ) : Int;
+	function getFloatResult( n : Int ) : Float;
+
+}

+ 172 - 0
std/php/db/Sqlite.hx

@@ -0,0 +1,172 @@
+/*
+ * Copyright (c) 2005, The haXe Project Contributors
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   - Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *   - Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE HAXE PROJECT CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE HAXE PROJECT CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ */
+package php.db;
+
+import php.db.Connection;
+
+private class SqliteConnection implements Connection {
+
+	var c : Void;
+	var e : Void;
+
+	public function new( file : String ) {
+		c = untyped __call__("sqlite_open", file, 0666, e);
+	}
+
+	public function close() {
+		untyped __call__("sqlite_close", c);
+		untyped __call__("unset", c);
+	}
+
+	public function request( s : String ) : ResultSet {
+		var h = untyped __call__("sqlite_query", c, s, __php__("SQLITE_BOTH"), e);
+		if(untyped __physeq__(h, false))
+			throw "Error while executing "+s+" ("+e+")";
+		return new SqliteResultSet(cast h);
+	}
+
+	public function escape( s : String ) {
+		return untyped __call__("sqlite_escape_string", s);
+	}
+
+	public function quote( s : String ) {
+		if( s.indexOf("\000") >= 0 )
+			return "x'"+base16_encode(s)+"'";
+		return "'" + untyped __call__("sqlite_escape_string", s) + "'";
+	}
+
+	public function lastInsertId() {
+		return untyped __call__("sqlite_last_insert_rowid", c);
+	}
+
+	public function dbName() {
+		return "SQLite";
+	}
+
+	public function startTransaction() {
+		request("BEGIN TRANSACTION");
+	}
+
+	public function commit() {
+		request("COMMIT");
+		startTransaction(); // match mysql usage
+	}
+
+	public function rollback() {
+		request("ROLLBACK");
+		startTransaction(); // match mysql usage
+	}
+
+	function base16_encode(str : String) {
+		str = untyped __call__("unpack", "H"+(2 * str.length), str);
+		str = untyped __call__("chunk_split", untyped str[1]);
+		return str;
+	}
+}
+
+
+private class SqliteResultSet implements ResultSet {
+
+	public var length(getLength,null) : Int;
+	public var nfields(getNFields,null) : Int;
+	var r : Void;
+	var cache : List<Dynamic>;
+
+	public function new( r ) {
+		cache = new List();
+		this.r = r;
+		hasNext(); // execute the request
+	}
+
+	function getLength() {
+		if( nfields != 0 ) {
+			while( true ) {
+				var c = doNext();
+				if( c == null )
+					break;
+				cache.add(c);
+			}
+			return cache.length;
+		}
+		return untyped __call__("sqlite_num_rows", r);
+	}
+
+	function getNFields() {
+		return untyped __call__("sqlite_num_fields", r);
+	}
+
+	public function hasNext() {
+		var c = next();
+		if( c == null )
+			return false;
+		cache.push(c);
+		return true;
+	}
+
+	public function next() : Dynamic {
+		var c = cache.pop();
+		if( c != null )
+			return c;
+		return doNext();
+	}
+
+	private function doNext() : Dynamic {
+		var c = untyped __call__("sqlite_fetch_array", r, __php__("SQLITE_BOTH"));
+		if(untyped __physeq__(c, false))
+			return null;
+		return php.Boot.__anonymous(c);
+	}
+
+	public function results() : List<Dynamic> {
+		var l = new List();
+		while( true ) {
+			var c = next();
+			if( c == null )
+				break;
+			l.add(c);
+		}
+		return l;
+	}
+
+	public function getResult( n : Int ) : String {
+		return Reflect.field(next(), cast n);
+	}
+
+	public function getIntResult( n : Int ) : Int {
+		return untyped __call__("intval", Reflect.field(next(), cast n));
+	}
+
+	public function getFloatResult( n : Int ) : Float {
+		return untyped __call__("floatval", Reflect.field(next(), cast n));
+	}
+}
+
+class Sqlite {
+
+	public static function open( file : String ) : Connection {
+		return new SqliteConnection(file);
+	}
+
+}

+ 86 - 0
std/php/io/File.hx

@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2005, The haXe Project Contributors
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   - Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *   - Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE HAXE PROJECT CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE HAXE PROJECT CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ */
+package php.io;
+
+enum FileHandle {
+}
+
+enum FileSeek {
+	SeekBegin;
+	SeekCur;
+	SeekEnd;
+}
+
+/**
+	API for reading and writing to files.
+**/
+class File {
+
+	public static function getContent( path : String ) : String {
+		return untyped __call__("file_get_contents", path);
+	}
+	
+	public static function getBytes( path : String ) {
+		return haxe.io.Bytes.ofString(getContent(path));
+	}
+	
+	public static function putContent( path : String, content : String) : String {
+		return untyped __call__("file_put_contents", path, content);
+	}
+	
+	public static function read( path : String, binary : Bool ) {
+		return new FileInput(untyped __call__('fopen', path, binary ? "rb" : "r"));
+	}
+
+	public static function write( path : String, binary : Bool ) {
+		return new FileOutput(untyped __call__('fopen', path, binary ? "wb" : "w"));
+	}
+
+	public static function append( path : String, binary : Bool ) {
+		return new FileOutput(untyped __call__('fopen', path, binary ? "ab" : "a"));
+	}
+	
+	public static function copy( src : String, dst : String ) {
+		return untyped __call__("copy", src, dst);
+	}
+
+	public static function stdin() {
+		return new FileInput(untyped __php__('STDIN'));
+	}
+
+	public static function stdout() {
+		return new FileOutput(untyped __call__('STDOUT'));
+	}
+
+	public static function stderr() {
+		return new FileOutput(untyped __call__('STDERR'));
+	}
+/*
+* TODO: what is this for?
+	public static function getChar( echo : Bool ) : Int {
+		return getch(echo);
+	}
+*/
+}

+ 77 - 0
std/php/io/FileInput.hx

@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2005, The haXe Project Contributors
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   - Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *   - Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE HAXE PROJECT CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE HAXE PROJECT CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ */
+package php.io;
+import php.io.File;
+
+/**
+	Use [php.io.File.read] to create a [FileInput]
+**/
+class FileInput extends haxe.io.Input {
+
+	private var __f : FileHandle;
+
+	public function new(f) {
+		__f = f;
+	}
+
+	public override function readByte() : Int {
+		if(untyped __call__('feof', __f)) return throw new haxe.io.Eof();
+		var r = untyped __call__('fread', __f, 1);
+		if(untyped __physeq__(r, false)) return throw haxe.io.Error.Custom('An error occurred');
+		return untyped __call__('ord', r);
+	}
+
+	public override function readBytes( s : haxe.io.Bytes, p : Int, l : Int ) : Int {
+		if(untyped __call__('feof', __f)) return throw new haxe.io.Eof();
+		var r : String = untyped __call__('fread', __f, l);
+		if(untyped __physeq__(r, false)) return throw haxe.io.Error.Custom('An error occurred');
+		
+		var b = haxe.io.Bytes.ofString(r);
+		s.blit(p, b, 0, r.length);
+		return r.length;
+	}
+
+	public override function close() {
+		super.close();
+		if(__f != null)	untyped __call__('fclose', __f);
+	}
+
+	public function seek( p : Int, pos : FileSeek ) {
+		var w;
+		switch( pos ) { 
+			case SeekBegin: w = untyped __php__('SEEK_SET');
+			case SeekCur  : w = untyped __php__('SEEK_CUR');
+			case SeekEnd  : w = untyped __php__('SEEK_END');
+		}
+		var r = untyped __call__('fseek', __f, p, w);
+		if(untyped __physeq__(r, false)) throw haxe.io.Error.Custom('An error occurred');
+	}
+
+	public function tell() : Int {
+		var r = untyped __call__('ftell', __f);
+		if(untyped __physeq__(r, false)) return throw haxe.io.Error.Custom('An error occurred');
+		return cast r;
+	}
+}

+ 82 - 0
std/php/io/FileOutput.hx

@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2005, The haXe Project Contributors
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   - Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *   - Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE HAXE PROJECT CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE HAXE PROJECT CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ */
+package php.io;
+import php.io.File;
+
+/**
+	Use [php.io.File.write] to create a [FileOutput]
+**/
+class FileOutput extends haxe.io.Output {
+	private var __f : FileHandle;
+
+	public function new(f) {
+		__f = f;
+	}
+
+	public override function writeByte( c : Int ) {
+		var r = untyped __call__('fwrite', __f, __call__('chr', c));
+		if(untyped __physeq__(r, false)) return throw haxe.io.Error.Custom('An error occurred');
+		return r;
+	}
+
+	public override function writeBytes( b : haxe.io.Bytes, p : Int, l : Int ) : Int {
+		var s = b.readString(p, l);
+		if(untyped __call__('feof', __f)) return throw new haxe.io.Eof();
+		var r = untyped __call__('fwrite', __f, s, l);
+		if(untyped __physeq__(r, false)) return throw haxe.io.Error.Custom('An error occurred');
+		return r;
+	}
+
+	public override function flush() {
+		var r = untyped __call__('fflush', __f);
+		if(untyped __physeq__(r, false)) throw haxe.io.Error.Custom('An error occurred');
+	}
+
+	public override function close() {
+		super.close();
+		if(__f != null)	untyped __call__('fclose', __f);
+	}
+
+	public function seek( p : Int, pos : FileSeek ) {
+		var w;
+		switch( pos ) { 
+			case SeekBegin: w = untyped __php__('SEEK_SET');
+			case SeekCur  : w = untyped __php__('SEEK_CUR');
+			case SeekEnd  : w = untyped __php__('SEEK_END');
+		}
+		var r = untyped __call__('fseek', __f, p, w);
+		if(untyped __physeq__(r, false)) throw haxe.io.Error.Custom('An error occurred');
+	}
+
+	public function tell() : Int {
+		var r = untyped __call__('ftell', __f);
+		if(untyped __physeq__(r, false)) return throw haxe.io.Error.Custom('An error occurred');
+		return cast r;
+	}
+
+	public function eof() : Bool {
+		return untyped __call__('feof', __f);
+	}
+}

+ 87 - 0
std/php/io/Path.hx

@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2005, The haXe Project Contributors
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   - Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *   - Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE HAXE PROJECT CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE HAXE PROJECT CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ */
+package php.io;
+
+class Path {
+
+	public var ext : String;
+	public var dir : String;
+	public var file : String;
+	public var backslash : Bool;
+
+	public function new( path : String ) {
+		var c1 = path.lastIndexOf("/");
+		var c2 = path.lastIndexOf("\\");
+		if( c1 < c2 ) {
+			dir = path.substr(0,c2);
+			path = path.substr(c2+1);
+			backslash = true;
+		} else if( c2 < c1 ) {
+			dir = path.substr(0,c1);
+			path = path.substr(c1+1);
+		} else
+			dir = null;
+		var cp = path.lastIndexOf(".");
+		if( cp != -1 ) {
+			ext = path.substr(cp+1);
+			file = path.substr(0,cp);
+		} else {
+			ext = null;
+			file = path;
+		}
+	}
+
+	public function toString() {
+		return (if( dir == null ) "" else dir + if( backslash ) "\\" else "/") + file + (if( ext == null ) "" else "." + ext);
+	}
+
+	public static function withoutExtension( path : String ) {
+		var s = new Path(path);
+		s.ext = null;
+		return s.toString();
+	}
+
+	public static inline function withoutDirectory( path : String) : String  {
+		return untyped __call__("basename", path);
+	}
+
+	public static inline function directory( path : String) : String {
+		return untyped __call__("dirname", path);
+	}
+
+	public static function extension( path ) {
+		var s = new Path(path);
+		if( s.ext == null )
+			return "";
+		return s.ext;
+	}
+
+	public static function withExtension( path, ext ) {
+		var s = new Path(path);
+		s.ext = ext;
+		return s.toString();
+	}
+
+}

+ 108 - 0
std/php/io/Process.hx

@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2005-2007, The haXe Project Contributors
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   - Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *   - Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE HAXE PROJECT CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE HAXE PROJECT CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ */
+package php.io;
+
+private class Stdin extends haxe.io.Output {
+	var p : Void;
+	var buf : haxe.io.Bytes;
+
+	public function new(p) {
+		this.p = p;
+		buf = haxe.io.Bytes.alloc(1);
+	}
+
+	public override function close() {
+		super.close();
+		untyped __call__('fclose', p);
+	}
+
+	public override function writeByte(c) {
+		buf.set(0,c);
+		writeBytes(buf,0,1);
+	}
+
+	public override function writeBytes( b : haxe.io.Bytes, pos : Int, l : Int ) : Int {
+		var s = b.readString(pos, l);
+		if(untyped __call__('feof', p)) return throw new haxe.io.Eof();
+		var r = untyped __call__('fwrite', p, s, l);
+		if(untyped __physeq__(r, false)) return throw haxe.io.Error.Custom('An error occurred');
+		return r;
+	}
+}
+
+private class Stdout extends haxe.io.Input {
+	var p : Void;
+	var buf : haxe.io.Bytes;
+
+	public function new(p) {
+		this.p = p;
+		buf = haxe.io.Bytes.alloc(1);
+	}
+
+	public override function readByte() {
+		if( readBytes(buf,0,1) == 0 )
+			throw haxe.io.Error.Blocked;
+		return buf.get(0);
+	}
+
+	public override function readBytes( str : haxe.io.Bytes, pos : Int, l : Int ) : Int {
+		if(untyped __call__('feof', p)) return throw new haxe.io.Eof();
+		var r : String = untyped __call__('fread', p, 1);
+		if(untyped __physeq__(r, false)) return throw haxe.io.Error.Custom('An error occurred');
+		var b = haxe.io.Bytes.ofString(r);
+		str.blit(pos, b, 0, r.length);
+		return r.length;
+	}
+}
+
+class Process {
+	var p : Void;
+	public var stdout(default,null) : haxe.io.Input;
+	public var stderr(default,null) : haxe.io.Input;
+	public var stdin(default,null) : haxe.io.Output;
+
+	public function new( cmd : String, args : Array<String> ) {
+		var pipes = new Array<Dynamic>();
+		var descriptorspec = [
+			['pipe', 'r'],
+			['pipe', 'w'],
+			['pipe', 'w']
+		];
+		// TODO: check how args are passed in neko 
+		p = untyped __call__('proc_open', cmd, descriptorspec, pipes, null, __php__("array('args' => join(' ', $args))"));
+		if(untyped __physeq__(p, false)) throw "Process creation failure : "+cmd;
+		stdin  = new Stdin(pipes[0]);
+		stdout = new Stdout(pipes[1]);
+		stderr = new Stdout(pipes[2]);
+	}
+
+	public function getPid() : Int {
+		return untyped __call__('proc_get_status', p)['pid'];
+	}
+
+	public function exitCode() : Int {
+		return untyped __call__('proc_get_status', p)['exitcode'];
+	}
+}

+ 59 - 0
std/php/net/Host.hx

@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2005, The haXe Project Contributors
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   - Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *   - Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE HAXE PROJECT CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE HAXE PROJECT CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ */
+package php.net;
+
+
+class Host {
+
+	private var _ip : String;
+	public var ip(default,null) : haxe.Int32;
+
+	public function new( name : String ) {
+		if(~/^(\d{1,3}\.){3}\d{1,3}$/.match(name)) {
+		  _ip = name;
+		} else {
+			_ip = untyped __call__('gethostbyname', name);
+			if(_ip == name) {
+				ip = haxe.Int32.ofInt(0);
+				return;
+			}
+		}
+		var p = _ip.split('.');
+		ip = haxe.Int32.ofInt(untyped __call__('intval', __call__('sprintf', '%02X%02X%02X%02X', p[3], p[2], p[1], p[0]), 16));
+	}
+
+	public function toString() : String {
+		return _ip;
+	}
+
+	public function reverse() : String {
+		return untyped __call__('gethostbyaddress', _ip);
+	}
+
+	public static function localhost() : String {
+		return untyped __var__('_SERVER', 'HTTP_HOST');
+	}
+}

+ 167 - 0
std/php/net/Socket.hx

@@ -0,0 +1,167 @@
+/*
+ * Copyright (c) 2005, The haXe Project Contributors
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   - Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *   - Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE HAXE PROJECT CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE HAXE PROJECT CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * Contributor: Lee McColl Sylvester
+ */
+package php.net;
+
+import php.io.File;
+
+typedef SocketHandle = php.io.FileHandle;
+
+class Socket {
+	private var __s : SocketHandle;
+	public var input(default,null) : SocketInput;
+	public var output(default,null) : SocketOutput;
+	public var custom : Dynamic;
+
+	public var isUdp(default, null) : Bool;
+	
+	public function new( ?s ) {
+		__s = s;
+		input = new SocketInput(__s);
+		output = new SocketOutput(__s);
+	}
+	
+	private function assignHandler() {
+		untyped input.__f = __s;
+		untyped output.__f = __s;
+	}
+
+	public function close() : Void {
+		untyped __call__('fclose', __s);
+		untyped {
+			input.__f = null;
+			output.__f = null;
+		}
+		input.close();
+		output.close();
+	}
+
+	public function read() : String {
+		var b = '';
+		untyped __php__('while (!feof($this->__s)) $b .= fgets($this->__s)');
+		return b;
+	}
+
+	public function write( content : String ) {
+		return untyped __call__('fwrite', __s, content);
+	}
+
+	public function connect(host : Host, port : Int) {
+		var errs = null;
+		var errn = null;
+		var r = untyped __call__('stream_socket_client', (isUdp ? 'udp' : 'tcp') + '://' +host._ip + ':' + port, errn, errs);
+		checkError(r, errn, errs);
+		__s = cast r;
+		assignHandler();
+	}
+
+	public function listen(connections : Int) {
+/* TODO: ??????
+		var r = untyped __call__('socket_listen', __s, connections);
+		checkError(r);
+*/
+	}
+
+	public function shutdown( read : Bool, write : Bool ){
+		var rw = read && write ? 2 : (write ? 1 : (read ? 0 : 2));
+		var r = untyped __call__('stream_socket_shutdown', __s, rw);
+		checkError(r, 0, 'Unable to Shutdown');
+	}
+
+	public function bind(host : Host, port : Int) {
+		var errs = null;
+		var errn = null;
+		var r = untyped __call__('stream_socket_server', (isUdp ? 'udp' : 'tcp') + '://' +host._ip + ':' + port, errn, errs, isUdp ? __php__('STREAM_SERVER_BIND') : __php__('STREAM_SERVER_BIND | STREAM_SERVER_LISTEN'));
+		checkError(r, errn, errs);
+		__s = cast r;
+		assignHandler();
+	}
+
+	public function accept() : Socket {
+		var r = untyped __call__('stream_socket_accept', __s);
+		checkError(r, 0, 'Unable to accept connections on socket');
+		return untyped new Socket(cast r);
+	}
+
+	private function hpOfString(s : String) {
+		var parts = s.split(':');
+		if(parts.length == 2) {
+			return { host : new Host(parts[0]), port : Std.parseInt(parts[1]) };
+		} else {
+			return { host : new Host(parts[1].substr(2)), port : Std.parseInt(parts[2]) };
+		}
+	}
+	
+	public function peer() : { host : Host, port : Int } {
+		var r : String = untyped __call__('stream_socket_get_name', __s, true);
+		checkError(cast r, 0, 'Unable to retrieve the peer name');
+		return hpOfString(r);
+	}
+
+	public function host() : { host : Host, port : Int } {
+		var r : String = untyped __call__('stream_socket_get_name', __s, false);
+		checkError(cast r, 0, 'Unable to retrieve the host name');
+		return hpOfString(r);
+	}
+
+	public function setTimeout( timeout : Float ) {
+		var s = Std.int(timeout);
+		var ms = Std.int((timeout % 1) * 100000);
+		var r = untyped __call__('stream_set_timeout', __s, s, ms);
+		checkError(r, 0, 'Unable to set timeout');
+	}
+
+	public function setBlocking( b : Bool ) {
+		var r = untyped __call__('stream_set_blocking', __s, b);
+		checkError(r, 0, 'Unable to block');
+	}
+
+	// STATICS
+	public static function newUdpSocket() {
+		var s = new Socket();
+		untyped s.isUdp = true;
+		return s;
+	}
+	
+	private static function checkError(r : Bool, code : Int, msg : String) {
+		if(!untyped __physeq__(r, false)) return;
+		throw haxe.io.Error.Custom('Error ['+code+']: ' +msg);
+	}
+	
+	private static function getType(isUdp : Bool) : Int {
+		return isUdp ? untyped __php__('SOCK_DGRAM') : untyped __php__('SOCK_STREAM');
+	}
+	
+	private static function getProtocol(isUdp : Bool) : Int {
+		return isUdp ? untyped __call__('getprotobyname', 'udp') : untyped __call__('getprotobyname', 'tcp');
+	}	
+}
+
+enum SocketDomain {
+	AfInet;
+	AfInet6;
+	AfUnix;
+}

+ 62 - 0
std/php/net/SocketInput.hx

@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2005, The haXe Project Contributors
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   - Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *   - Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE HAXE PROJECT CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE HAXE PROJECT CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ */
+package php.net;
+
+typedef SocketInput = php.io.FileInput;
+
+/*
+import php.net.Socket;
+import haxe.io.Error;
+class SocketInput extends haxe.io.Input {
+
+	var __s : SocketHandle;
+
+	public function new(s) {
+		__s = s;
+	}
+
+	public override function readByte() {
+		var r = untyped __call__('socket_read', __s, 1);
+		untyped Socket.checkError(r);
+		if(r == 0) return throw new haxe.io.Eof();
+		return untyped __call__('ord', r);
+	}
+
+	public override function readBytes( buf : haxe.io.Bytes, pos : Int, len : Int ) : Int {
+		var r : String = untyped __call__('socket_read', __s, len);
+		untyped Socket.checkError(r);
+		var b = haxe.io.Bytes.ofString(r);
+		if(r.length == 0) return throw new haxe.io.Eof();
+		s.blit(pos, b, 0, r.length);
+		return r.length;
+	}
+
+	public override function close() {
+		super.close();
+		if( __s != null ) untyped __call__('socket_close', __s);
+	}
+}
+
+*/

+ 57 - 0
std/php/net/SocketOutput.hx

@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2005, The haXe Project Contributors
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   - Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *   - Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE HAXE PROJECT CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE HAXE PROJECT CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ */
+package php.net;
+
+typedef SocketOutput = php.io.FileOutput;
+
+/*
+import php.net.Socket;
+import haxe.io.Error;
+class SocketOutput extends haxe.io.Output {
+
+	var __s : SocketHandle;
+
+	public function new(s) {
+		__s = s;
+	}
+
+	public override function writeByte( c : Int ) {
+		var r = __call__('socket_write', __s, __call__('chr', c), 1);
+		untyped Socket.checkError(r);
+	}
+
+	public override function writeBytes( buf : haxe.io.Bytes, pos : Int, len : Int) : Int {
+		var s = b.readString(p, l);
+		var r = untyped __call__('socket_write', __f, s, len);
+		untyped Socket.checkError(r);
+		return cast r;
+	}
+
+	public override function close() {
+		super.close();
+		if( __s != null ) untyped __call__('socket_close', __s);
+	}
+}
+*/

+ 5 - 1
tests/unit/Test.hx

@@ -139,7 +139,8 @@ class Test #if swf_mark implements mt.Protect #end {
 	}
 
 	static function resetTimer() {
-		#if !neko
+		#if (neko || php)
+		#else
 		if( timer != null ) timer.stop();
 		timer = new haxe.Timer(10000);
 		timer.run = asyncTimeout;
@@ -150,6 +151,9 @@ class Test #if swf_mark implements mt.Protect #end {
 		#if neko
 		if( neko.Web.isModNeko )
 			neko.Lib.print("<pre>");
+		#elseif php
+		if( php.Web.isModNeko )
+			php.Lib.print("<pre>");
 		#end
 		resetTimer();
 		trace("START");

+ 2 - 2
tests/unit/TestIO.hx

@@ -33,7 +33,7 @@ class TestIO extends Test {
 		exc(function() o.writeBytes(b,3,20));
 
 		o.writeByte(98);
-		#if (neko || flash9)
+		#if (neko || flash9 || php)
 		o.writeDouble(1.23);
 		o.writeFloat(1.2e10);
 		#end
@@ -84,7 +84,7 @@ class TestIO extends Test {
 		eq( i.read(5).compare(b.sub(3,5)), 0 );
 
 		eq( i.readByte(), 98 );
-		#if (neko || flash9)
+		#if (neko || flash9 || php)
 		eq( i.readDouble(), 1.23 );
 		eq( i.readFloat(), 1.2e10 );
 		#else

+ 11 - 2
tests/unit/TestRemoting.hx

@@ -44,7 +44,9 @@ class TestRemoting extends Test {
 		#if (flash || js)
 		doTestConnection(ecnx);
 		#end
+		#if !php // accessing the properties of a null object generates a fatal error in php
 		exc(function() ecnx3.api.add.call([1,3]));
+		#end
 		#if js
 		doTestConnection(ecnx2);
 		#end
@@ -55,7 +57,7 @@ class TestRemoting extends Test {
 		// flash-flash through-js connection
 		doTestAsyncConnection(fjscnx);
 		#end
-		#if (js || neko)
+		#if (js || neko || php)
 		// http sync connection
 		var hcnx = haxe.remoting.HttpConnection.urlConnect("http://"+HOST+"/remoting.n");
 		doTestConnection(hcnx);
@@ -75,7 +77,7 @@ class TestRemoting extends Test {
 		doTestAsyncConnection(dcnx);
 
 		// socket connection
-		#if (flash || neko)
+		#if (flash || neko || php)
 		async( doConnect, new Socket(), true );
 		#elseif js
 		async( doConnect, new Socket("haxeFlash8"), true );
@@ -122,6 +124,10 @@ class TestRemoting extends Test {
 		var ret = try { s.connect(new neko.net.Host(HOST),PORT); true; } catch( e : Dynamic ) false;
 		if( ret ) doTestSocket(s);
 		onResult(ret);
+		#elseif php
+		var ret = try { s.connect(new php.net.Host(HOST),PORT); true; } catch( e : Dynamic ) false;
+		if( ret ) doTestSocket(s);
+		onResult(ret);
 		#end
 	}
 
@@ -129,6 +135,9 @@ class TestRemoting extends Test {
 		#if neko
 		var scnx = haxe.remoting.NekoSocketConnection.create(s,new haxe.remoting.Context());
 		doTestConnection(scnx);
+		#elseif php
+		var scnx = haxe.remoting.PhpSocketConnection.create(s,new haxe.remoting.Context());
+		doTestConnection(scnx);
 		#else
 		var scnx = haxe.remoting.SocketConnection.create(s,new haxe.remoting.Context());
 		doTestAsyncConnection(scnx);

+ 1 - 1
tests/unit/TestResource.hx

@@ -18,7 +18,7 @@ class TestResource extends Test {
 			eq( names[1], "res1.txt" );
 		}
 		eq( haxe.Resource.getString("res1.txt"), STR );
-		#if (neko || flash9)
+		#if (neko || flash9 || php)
 		// allow binary strings
 		eq( haxe.Resource.getString("res2.bin"), "Héllo\000World\000\000\000\000!" );
 		#else

+ 98 - 88
tests/unit/unit.html

@@ -1,100 +1,110 @@
 <html>
-
 <head>
-	<title>haXe</title>
 	<meta http-equiv="Content-Type" content="text/html;charset=UTF-8" />
+	<title>haXe Tests</title>
+	<style>
+body {
+  font-family: Verdana;
+  font-size: 9pt;
+}
+	
+iframe {
+  border: 0; padding: 0; margin: 0;
+  width: 100%; height: 100%;
+}
+
+.label {
+  padding: 2px;
+  font-weight: bold;
+  background-color: #000000;
+  color: #ffffff;
+  text-align: center;
+}
+
+.window {
+  float:left;
+  border: 1px solid #000000;
+  margin: 0 4px 4px 0;
+}
+
+.window .cont {
+  width: 400px;
+  height: 300px;
+  overflow: auto;
+  font-family: monospace;
+  white-space: pre;
+}
+	</style>
 	<script type="text/javascript" src="unit.js"></script>
 </head>
-
-<body bgcolor="#dddddd" onLoad="setTimeout('unit.Test.main()',1000)">
-
-<p>
-	Note : These tests need to be run from a local domain called <code>dev.unit-tests</code> which is running mod_neko in this directory.
-</p>
-
-<table>
-<tr>
-<td>
-
-<p>JS :</p>
-
-<pre id="haxe:trace" style="{ background-color : white; height : 290px; width : 390px; padding : 5px; overflow : auto; }">
-</pre>
-
-</td>
-<td>
-
-<p>Neko :</p>
-
-<iframe src="http://dev.unit-tests/unit.n" style="{ border : none; background-color : white; width : 400px; height : 300px; }">
-</iframe>
-
-</td>
-</tr>
-
-<tr>
-<td>
-
-<p>Flash 8 :</p>
-
-<object	classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000"
-        width="400"
+<body>
+<p>Note : These tests need to be run from a local domain called <code>dev.unit-tests</code> which is running mod_neko in this directory.</p>
+<div class="window">
+  <div class="label">JavaScript</div>
+  <div id="haxe:trace" class="cont"></div>
+</div>
+<div class="window">
+  <div class="label">Neko</div>
+  <div id="neko_container" class="cont"><iframe src="unit.n"></iframe></div>
+</div>
+<div class="window">
+  <div class="label">Php</div>
+  <div id="php_container" class="cont"><iframe src="php/index.php"></iframe></div>
+</div>
+<div class="window">
+  <div class="label">Flash 8</div>
+  <object	classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000"
+	width="400"
 	height="300"
 	id="haxeFlash8"
 	align="middle">
-<param name="movie" value="unit8.swf"/>
-<param name="allowScriptAccess" value="always" />
-<param name="quality" value="high" />
-<param name="scale" value="noscale" />
-<param name="salign" value="lt" />
-<param name="bgcolor" value="#ffffff"/>
-<embed src="unit8.swf"
-       bgcolor="#ffffff"
-       width="400"
-       height="300"
-       name="haxeFlash8"
-       quality="high"
-       align="middle"
-       allowScriptAccess="always"
-       type="application/x-shockwave-flash"
-       pluginspage="http://www.macromedia.com/go/getflashplayer"
-/>
-</object>
-
-</td>
-<td>
-
-<p>
-Flash 9 :
-</p>
-
-<object	classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000"
-        width="400"
+    <param name="movie" value="unit8.swf"/>
+    <param name="allowScriptAccess" value="always" />
+    <param name="quality" value="high" />
+    <param name="scale" value="noscale" />
+    <param name="salign" value="lt" />
+    <param name="bgcolor" value="#ffffff"/>
+    <embed src="unit8.swf"
+      bgcolor="#ffffff"
+      width="400"
+      height="300"
+      name="haxeFlash8"
+      quality="high"
+      align="middle"
+      allowScriptAccess="always"
+      type="application/x-shockwave-flash"
+      pluginspage="http://www.macromedia.com/go/getflashplayer"
+    />
+  </object>
+</div>
+<div class="window">
+  <div class="label">Flash 9</div>
+  <object	classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000"
+	width="400"
 	height="300"
 	id="haxeFlash9"
 	align="middle">
-<param name="movie" value="unit9.swf"/>
-<param name="allowScriptAccess" value="always" />
-<param name="quality" value="high" />
-<param name="scale" value="noscale" />
-<param name="salign" value="lt" />
-<param name="bgcolor" value="#ffffff"/>
-<embed src="unit9.swf"
-       bgcolor="#ffffff"
-       width="400"
-       height="300"
-       name="haxeFlash9"
-       quality="high"
-       align="middle"
-       allowScriptAccess="always"
-       type="application/x-shockwave-flash"
-       pluginspage="http://www.macromedia.com/go/getflashplayer"
-/>
-</object>
-
-</td>
-</tr>
-</table>
-
+    <param name="movie" value="unit9.swf"/>
+    <param name="allowScriptAccess" value="always" />
+    <param name="quality" value="high" />
+    <param name="scale" value="noscale" />
+    <param name="salign" value="lt" />
+    <param name="bgcolor" value="#ffffff"/>
+    <embed src="unit9.swf"
+      bgcolor="#ffffff"
+      width="400"
+      height="300"
+      name="haxeFlash9"
+      quality="high"
+      align="middle"
+      allowScriptAccess="always"
+      type="application/x-shockwave-flash"
+      pluginspage="http://www.macromedia.com/go/getflashplayer"
+    />
+  </object>
+</div>
+<script type="text/javascript">
+setTimeout('unit.Test.main()', 1000)
+</script>
 </body>
-</html>
+</html>

+ 8 - 0
tests/unit/unit.hxp

@@ -7,6 +7,14 @@
 -resource res2.bin</output>
   <output name="JS" mode="js" out="unit.js" class="unit.Test" lib="" cmd="" main="False" debug="False">-cp ..
 -resource res1.txt
+-resource res2.bin
+
+--next
+# Php
+-php out
+-main unit.Test
+-cp ..
+-resource res1.txt
 -resource res2.bin</output>
   <output name="Neko" mode="neko" out="unit.n" class="unit.Test" lib="" cmd="" main="True" debug="False">-cp ..
 -resource res1.txt