fn name of service requested $rqst->hdrs headers sent by Flash client $rqst->fnargs arguments sent by Flash client - array of arrays, one for every AMF request, each containing the arguments sent by that request $rqst->addresult(num,data) give a response back to the Flash client - num is the number of the AMF request to which we're responding - data is the actual response $rqst->send send all responses prepared by addresult example: $rqst=new amfdata(); switch ($rqst->fn) { # what service are we requesting? case 'senddata': foreach ($rqst->fnargs as $seq=>$args) { print "AMF request $seq, first argument is ".$args[0]."\n"; $rqst->addresult($seq,"Received ok."); } $rqst->send(); break; } */ class amfdata { var $fn, $fnargs; var $hdrs; var $byteorder; var $results, $result; # ===== amfdata # create and parse a new AMF request function amfdata() { $this->hdrs=array(); $this->fnargs=array(); $this->results=0; $this->result=''; $tmp=pack("d", 1); if ($tmp == "\0\0\0\0\0\0\360\77") { $this->byteorder='x86'; } else if ($tmp == "\77\360\0\0\0\0\0\0") { $this->byteorder='ppc'; } else die("unknown byteorder in amfdata\n"); # --- Get raw data $d=$GLOBALS['HTTP_RAW_POST_DATA']; $l=strlen($d); $n=3; # --- Read headers $nv=ord($d[$n++]); while(--$nv >= 0) { $key=$this->getstr($d, $n); $n++; $lo=$this->getlength($d, $n); #Ênot used $ch=ord($d[$n++]); $val=$this->parseitem($ch, $d, $n); $this->$hdrs[$key]=$val; } # --- Read each call $n+=2; while ($n<$l) { # Get call name $this->fn=$this->getstr($d, $n); # Get number in sequence $seq=substr($this->getstr($d, $n),1); $lo=$this->getlength($d, $n); # length of all params? not used # Get all parameters (sent as an array, hence the '10') $ch=ord($d[$n++]); if($ch != 10) { print " ??"; } # error $lo=$this->getlength($d, $n); for ($ni=0; $ni<$lo; $ni++) { $ch=ord($d[$n++]); $p=$this->parseitem($ch, $d, $n); $this->fnargs[$seq][]=$p; } } return $this; } # ===== addresult # add an AMF response function addresult($seq,$data) { $this->results++; $this->result.=$this->sendstr("/$seq/onResult"). $this->sendstr("null"). pack("N",-1). $this->sendobj($data); } # ===== send # send all AMF responses function send() { header('Content-type: application/x-amf'); print "\0\0\0\0"; print pack("n",$this->results); print $this->result; } # ======================================================================== # Get/send data types # ===== Item parser (item type, raw form data, position in data) # this reads the ID byte and calls the appropriate 'get' routine function parseitem($ch, $d, &$n) { switch($ch) { case 0: return $this->getnumber($d,$n); break; // number case 1: $ch= ord($d[$n++]); return $ch; break; // boolean case 2: return $this->getstr($d, $n); break; // string case 3: return $this->getobj($d, $n); break; // object // 4 unsupported // movieclip case 5: return null; // null case 6: return null; // undefined case 8: return $this->getmixed($d, $n); break; // mixedArray case 10:return $this->getarray($d, $n); break; // array default:print "xxx $ch "; // error } } # ===== Get each data type # all called with $d (raw form data), $n (position in data) function getstr($d, &$n) { $hi=ord($d[$n++]); $lo=ord($d[$n++]); $lo+=256*$hi; $val=substr($d,$n,$lo); $n+=$lo; return $val; } function getnumber($d, &$n) { $ibf=""; switch($this->byteorder) { case 'x86': for ($nc=7; $nc>=0; $nc--) { $ibf.=$d[$n+$nc]; } break; case 'ppc': $ibf=substr($d,$n,8); break; } $n += 8; $zz=unpack("dflt", $ibf); return $zz['flt']; } function getobj($d, &$n) { $ret=array(); while($key=$this->getstr($d, $n)) { $ch=ord($d[$n++]); $val=$this->parseitem($ch, $d, $n); $ret[$key]=$val; } $ch=ord($d[$n++]); if($ch != 9) { print "obj?? $ch "; } # error return $ret; } function getmixed($d, &$n) { $lo=$this->getlength($d, $n); # not used return $this->getobj($d,$n); } function getarray($d, &$n) { $ret=array(); $lo=$this->getlength($d, $n); # read array for ($ni=0; $ni<$lo; $ni++) { $ch=ord($d[$n++]); $ret[]=$this->parseitem($ch, $d, $n); } return $ret; } # ===== Send all data types function sendobj($val) { if(is_array($val) || is_object($val)) { $first=1; $num_array=1; foreach($val as $key => $data) { if(!is_int($key) || ($key < 0)) { $num_array=0; break; } if ($first) { $lo=$hi=$key; $first=0; } else if ($key<$lo) { $lo=$key; } else if ($key>$hi) { $hi=$key; } } if ($num_array) { # Send as array (code 10) if (!empty($hi)) { $ret="\12" . pack("N", $hi+1); for($n=0; $n<=$hi; $n++) { $ret.=$this->sendobj($val[$n]); } } else { $ret="\12".pack("N",0); } } else { # Send as object (code 3) $ret="\3"; foreach ($val as $key => $data) { $ret.=$this->sendstr($key); $ret.=$this->sendobj($data); } $ret .= $this->sendstr('') . "\11"; } return $ret; } else if (is_integer($val) || is_numeric($val)) { # Send as number (code 0) return "\0" . $this->sendnum($val); } else { # Send as string (code 2) return "\2" . $this->sendstr($val); } } # ===== Utility functions function sendstr($str) { return pack("n", strlen($str)).$str; } function sendnum($val) { $b=pack("d", $val); switch($this->byteorder) { case 'x86': $r=""; for ($n=7; $n>=0; $n--) { $r.=$b[$n]; } return $r; case 'ppc': return $b; } } function getlength($d,&$n) { for ($b=0, $c=0; $c<4; $c++) { $b*=256; $b+=ord($d[$n++]); } return $b; } }