5 /// @todo: does these need to be public?
8 public $_php_class=null;
12 * @param string $type any valid xmlrpc type name (lowercase). If null, 'string' is assumed
14 function __construct($val=-1, $type='') {
15 /// @todo: optimization creep - do not call addXX, do it all inline.
16 /// downside: booleans will not be coerced anymore
17 if($val!==-1 || $type!='')
19 // optimization creep: inlined all work done by constructor
24 $this->me['string']=$val;
31 case 'dateTime.iso8601':
35 $this->me[$type]=$val;
39 $this->me['array']=$val;
43 $this->me['struct']=$val;
46 error_log("XML-RPC: ".__METHOD__.": not a known type ($type)");
52 if($GLOBALS['xmlrpcTypes'][$type]==1)
54 $this->addScalar($val,$type);
56 elseif($GLOBALS['xmlrpcTypes'][$type]==2)
58 $this->addArray($val);
60 elseif($GLOBALS['xmlrpcTypes'][$type]==3)
62 $this->addStruct($val);
68 * Add a single php value to an (unitialized) xmlrpcval
71 * @return int 1 or 0 on failure
73 function addScalar($val, $type='string')
75 $xmlrpc = Phpxmlrpc::instance();
78 if(isset($xmlrpc->xmlrpcTypes[$type])) {
79 $typeof = $xmlrpc->xmlrpcTypes[$type];
84 error_log("XML-RPC: ".__METHOD__.": not a scalar type ($type)");
88 // coerce booleans into correct values
89 // NB: we should either do it for datetimes, integers and doubles, too,
90 // or just plain remove this check, implemented on booleans only...
91 if($type==$xmlrpc->xmlrpcBoolean)
93 if(strcasecmp($val,'true')==0 || $val==1 || ($val==true && strcasecmp($val,'false')))
103 switch($this->mytype)
106 error_log('XML-RPC: '.__METHOD__.': scalar xmlrpcval can have only one value');
109 error_log('XML-RPC: '.__METHOD__.': cannot add anonymous scalar to struct xmlrpcval');
112 // we're adding a scalar value to an array here
113 //$ar=$this->me['array'];
114 //$ar[]=new xmlrpcval($val, $type);
115 //$this->me['array']=$ar;
116 // Faster (?) avoid all the costly array-copy-by-val done here...
117 $this->me['array'][]=new xmlrpcval($val, $type);
120 // a scalar, so set the value and remember we're scalar
121 $this->me[$type]=$val;
122 $this->mytype=$typeof;
128 * Add an array of xmlrpcval objects to an xmlrpcval
130 * @return int 1 or 0 on failure
132 * @todo add some checking for $vals to be an array of xmlrpcvals?
134 public function addArray($vals)
136 $xmlrpc = Phpxmlrpc::instance();
139 $this->mytype=$xmlrpc->xmlrpcTypes['array'];
140 $this->me['array']=$vals;
143 elseif($this->mytype==2)
145 // we're adding to an array here
146 $this->me['array'] = array_merge($this->me['array'], $vals);
151 error_log('XML-RPC: '.__METHOD__.': already initialized as a [' . $this->kindOf() . ']');
157 * Add an array of named xmlrpcval objects to an xmlrpcval
159 * @return int 1 or 0 on failure
161 * @todo add some checking for $vals to be an array?
163 public function addStruct($vals)
165 $xmlrpc = Phpxmlrpc::instance();
169 $this->mytype=$xmlrpc->xmlrpcTypes['struct'];
170 $this->me['struct']=$vals;
173 elseif($this->mytype==3)
175 // we're adding to a struct here
176 $this->me['struct'] = array_merge($this->me['struct'], $vals);
181 error_log('XML-RPC: '.__METHOD__.': already initialized as a [' . $this->kindOf() . ']');
187 * Returns a string containing "struct", "array" or "scalar" describing the base type of the value
190 public function kindOf()
192 switch($this->mytype)
208 private function serializedata($typ, $val, $charset_encoding='')
210 $xmlrpc = Phpxmlrpc::instance();
213 if(!isset($xmlrpc->xmlrpcTypes[$typ])) {
217 switch($xmlrpc->xmlrpcTypes[$typ])
222 case $xmlrpc->xmlrpcBase64:
223 $rs.="<${typ}>" . base64_encode($val) . "</${typ}>";
225 case $xmlrpc->xmlrpcBoolean:
226 $rs.="<${typ}>" . ($val ? '1' : '0') . "</${typ}>";
228 case $xmlrpc->xmlrpcString:
229 // G. Giunta 2005/2/13: do NOT use htmlentities, since
230 // it will produce named html entities, which are invalid xml
231 $rs.="<${typ}>" . xmlrpc_encode_entitites($val, $xmlrpc->xmlrpc_internalencoding, $charset_encoding). "</${typ}>";
233 case $xmlrpc->xmlrpcInt:
234 case $xmlrpc->xmlrpcI4:
235 $rs.="<${typ}>".(int)$val."</${typ}>";
237 case $xmlrpc->xmlrpcDouble:
238 // avoid using standard conversion of float to string because it is locale-dependent,
239 // and also because the xmlrpc spec forbids exponential notation.
240 // sprintf('%F') could be most likely ok but it fails eg. on 2e-14.
241 // The code below tries its best at keeping max precision while avoiding exp notation,
242 // but there is of course no limit in the number of decimal places to be used...
243 $rs.="<${typ}>".preg_replace('/\\.?0+$/','',number_format((double)$val, 128, '.', ''))."</${typ}>";
245 case $xmlrpc->xmlrpcDateTime:
248 $rs.="<${typ}>${val}</${typ}>";
250 else if(is_a($val, 'DateTime'))
252 $rs.="<${typ}>".$val->format('Ymd\TH:i:s')."</${typ}>";
254 else if(is_int($val))
256 $rs.="<${typ}>".strftime("%Y%m%dT%H:%M:%S", $val)."</${typ}>";
260 // not really a good idea here: but what shall we output anyway? left for backward compat...
261 $rs.="<${typ}>${val}</${typ}>";
264 case $xmlrpc->xmlrpcNull:
265 if ($xmlrpc->xmlrpc_null_apache_encoding)
275 // no standard type value should arrive here, but provide a possibility
276 // for xmlrpcvals of unknown type...
277 $rs.="<${typ}>${val}</${typ}>";
282 if ($this->_php_class)
284 $rs.='<struct php_class="' . $this->_php_class . "\">\n";
290 foreach($val as $key2 => $val2)
292 $rs.='<member><name>'.xmlrpc_encode_entitites($key2, $xmlrpc->xmlrpc_internalencoding, $charset_encoding)."</name>\n";
293 //$rs.=$this->serializeval($val2);
294 $rs.=$val2->serialize($charset_encoding);
301 $rs.="<array>\n<data>\n";
302 for($i=0; $i<count($val); $i++)
304 //$rs.=$this->serializeval($val[$i]);
305 $rs.=$val[$i]->serialize($charset_encoding);
307 $rs.="</data>\n</array>";
316 * Returns xml representation of the value. XML prologue not included
317 * @param string $charset_encoding the charset to be used for serialization. if null, US-ASCII is assumed
320 public function serialize($charset_encoding='')
322 // add check? slower, but helps to avoid recursion in serializing broken xmlrpcvals...
323 //if (is_object($o) && (get_class($o) == 'xmlrpcval' || is_subclass_of($o, 'xmlrpcval')))
326 list($typ, $val) = each($this->me);
327 return '<value>' . $this->serializedata($typ, $val, $charset_encoding) . "</value>\n";
332 function serializeval($o)
334 // add check? slower, but helps to avoid recursion in serializing broken xmlrpcvals...
335 //if (is_object($o) && (get_class($o) == 'xmlrpcval' || is_subclass_of($o, 'xmlrpcval')))
339 list($typ, $val) = each($ar);
340 return '<value>' . $this->serializedata($typ, $val) . "</value>\n";
345 * Checks whether a struct member with a given name is present.
346 * Works only on xmlrpcvals of type struct.
347 * @param string $m the name of the struct member to be looked up
350 public function structmemexists($m)
352 return array_key_exists($m, $this->me['struct']);
356 * Returns the value of a given struct member (an xmlrpcval object in itself).
357 * Will raise a php warning if struct member of given name does not exist
358 * @param string $m the name of the struct member to be looked up
361 public function structmem($m)
363 return $this->me['struct'][$m];
367 * Reset internal pointer for xmlrpcvals of type struct.
369 public function structreset()
371 reset($this->me['struct']);
375 * Return next member element for xmlrpcvals of type struct.
378 public function structeach()
380 return each($this->me['struct']);
383 // DEPRECATED! this code looks like it is very fragile and has not been fixed
384 // for a long long time. Shall we remove it for 2.0?
389 list($a,$b)=each($this->me);
390 // contributed by I Sofer, 2001-03-24
391 // add support for nested arrays to scalarval
392 // i've created a new method here, so as to
393 // preserve back compatibility
398 while(list($id,$cont) = @each($b))
400 $b[$id] = $cont->scalarval();
404 // add support for structures directly encoding php objects
407 $t = get_object_vars($b);
409 while(list($id,$cont) = @each($t))
411 $t[$id] = $cont->scalarval();
414 while(list($id,$cont) = @each($t))
424 * Returns the value of a scalar xmlrpcval
427 public function scalarval()
430 list(,$b)=each($this->me);
435 * Returns the type of the xmlrpcval.
436 * For integers, 'int' is always returned in place of 'i4'
439 public function scalartyp()
441 $xmlrpc = Phpxmlrpc::instance();
444 list($a,)=each($this->me);
445 if($a==$xmlrpc->xmlrpcI4)
447 $a=$xmlrpc->xmlrpcInt;
453 * Returns the m-th member of an xmlrpcval of struct type
454 * @param integer $m the index of the value to be retrieved (zero based)
457 public function arraymem($m)
459 return $this->me['array'][$m];
463 * Returns the number of members in an xmlrpcval of array type
466 public function arraysize()
468 return count($this->me['array']);
472 * Returns the number of members in an xmlrpcval of struct type
475 public function structsize()
477 return count($this->me['struct']);