11 * @param string $type any valid xmlrpc type name (lowercase). If null, 'string' is assumed
13 function xmlrpcval($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 = Xmlrpc::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
133 * @todo add some checking for $vals to be an array of xmlrpcvals?
135 function addArray($vals)
137 $xmlrpc = Xmlrpc::instance();
140 $this->mytype=$xmlrpc->xmlrpcTypes['array'];
141 $this->me['array']=$vals;
144 elseif($this->mytype==2)
146 // we're adding to an array here
147 $this->me['array'] = array_merge($this->me['array'], $vals);
152 error_log('XML-RPC: '.__METHOD__.': already initialized as a [' . $this->kindOf() . ']');
158 * Add an array of named xmlrpcval objects to an xmlrpcval
160 * @return int 1 or 0 on failure
163 * @todo add some checking for $vals to be an array?
165 function addStruct($vals)
167 $xmlrpc = Xmlrpc::instance();
171 $this->mytype=$xmlrpc->xmlrpcTypes['struct'];
172 $this->me['struct']=$vals;
175 elseif($this->mytype==3)
177 // we're adding to a struct here
178 $this->me['struct'] = array_merge($this->me['struct'], $vals);
183 error_log('XML-RPC: '.__METHOD__.': already initialized as a [' . $this->kindOf() . ']');
188 // poor man's version of print_r ???
192 foreach($ar as $key => $val)
194 echo "$key => $val<br />";
197 while(list($key2, $val2) = each($val))
199 echo "-- $key2 => $val2<br />";
206 * Returns a string containing "struct", "array" or "scalar" describing the base type of the value
212 switch($this->mytype)
231 function serializedata($typ, $val, $charset_encoding='')
233 $xmlrpc = Xmlrpc::instance();
236 if(!isset($xmlrpc->xmlrpcTypes[$typ])) {
240 switch($xmlrpc->xmlrpcTypes[$typ])
245 case $xmlrpc->xmlrpcBase64:
246 $rs.="<${typ}>" . base64_encode($val) . "</${typ}>";
248 case $xmlrpc->xmlrpcBoolean:
249 $rs.="<${typ}>" . ($val ? '1' : '0') . "</${typ}>";
251 case $xmlrpc->xmlrpcString:
252 // G. Giunta 2005/2/13: do NOT use htmlentities, since
253 // it will produce named html entities, which are invalid xml
254 $rs.="<${typ}>" . xmlrpc_encode_entitites($val, $xmlrpc->xmlrpc_internalencoding, $charset_encoding). "</${typ}>";
256 case $xmlrpc->xmlrpcInt:
257 case $xmlrpc->xmlrpcI4:
258 $rs.="<${typ}>".(int)$val."</${typ}>";
260 case $xmlrpc->xmlrpcDouble:
261 // avoid using standard conversion of float to string because it is locale-dependent,
262 // and also because the xmlrpc spec forbids exponential notation.
263 // sprintf('%F') could be most likely ok but it fails eg. on 2e-14.
264 // The code below tries its best at keeping max precision while avoiding exp notation,
265 // but there is of course no limit in the number of decimal places to be used...
266 $rs.="<${typ}>".preg_replace('/\\.?0+$/','',number_format((double)$val, 128, '.', ''))."</${typ}>";
268 case $xmlrpc->xmlrpcDateTime:
271 $rs.="<${typ}>${val}</${typ}>";
273 else if(is_a($val, 'DateTime'))
275 $rs.="<${typ}>".$val->format('Ymd\TH:i:s')."</${typ}>";
277 else if(is_int($val))
279 $rs.="<${typ}>".strftime("%Y%m%dT%H:%M:%S", $val)."</${typ}>";
283 // not really a good idea here: but what shall we output anyway? left for backward compat...
284 $rs.="<${typ}>${val}</${typ}>";
287 case $xmlrpc->xmlrpcNull:
288 if ($xmlrpc->xmlrpc_null_apache_encoding)
298 // no standard type value should arrive here, but provide a possibility
299 // for xmlrpcvals of unknown type...
300 $rs.="<${typ}>${val}</${typ}>";
305 if ($this->_php_class)
307 $rs.='<struct php_class="' . $this->_php_class . "\">\n";
313 foreach($val as $key2 => $val2)
315 $rs.='<member><name>'.xmlrpc_encode_entitites($key2, $xmlrpc->xmlrpc_internalencoding, $charset_encoding)."</name>\n";
316 //$rs.=$this->serializeval($val2);
317 $rs.=$val2->serialize($charset_encoding);
324 $rs.="<array>\n<data>\n";
325 for($i=0; $i<count($val); $i++)
327 //$rs.=$this->serializeval($val[$i]);
328 $rs.=$val[$i]->serialize($charset_encoding);
330 $rs.="</data>\n</array>";
339 * Returns xml representation of the value. XML prologue not included
340 * @param string $charset_encoding the charset to be used for serialization. if null, US-ASCII is assumed
344 function serialize($charset_encoding='')
346 // add check? slower, but helps to avoid recursion in serializing broken xmlrpcvals...
347 //if (is_object($o) && (get_class($o) == 'xmlrpcval' || is_subclass_of($o, 'xmlrpcval')))
350 list($typ, $val) = each($this->me);
351 return '<value>' . $this->serializedata($typ, $val, $charset_encoding) . "</value>\n";
356 function serializeval($o)
358 // add check? slower, but helps to avoid recursion in serializing broken xmlrpcvals...
359 //if (is_object($o) && (get_class($o) == 'xmlrpcval' || is_subclass_of($o, 'xmlrpcval')))
363 list($typ, $val) = each($ar);
364 return '<value>' . $this->serializedata($typ, $val) . "</value>\n";
369 * Checks whether a struct member with a given name is present.
370 * Works only on xmlrpcvals of type struct.
371 * @param string $m the name of the struct member to be looked up
375 function structmemexists($m)
377 return array_key_exists($m, $this->me['struct']);
381 * Returns the value of a given struct member (an xmlrpcval object in itself).
382 * Will raise a php warning if struct member of given name does not exist
383 * @param string $m the name of the struct member to be looked up
387 function structmem($m)
389 return $this->me['struct'][$m];
393 * Reset internal pointer for xmlrpcvals of type struct.
396 function structreset()
398 reset($this->me['struct']);
402 * Return next member element for xmlrpcvals of type struct.
406 function structeach()
408 return each($this->me['struct']);
411 // DEPRECATED! this code looks like it is very fragile and has not been fixed
412 // for a long long time. Shall we remove it for 2.0?
417 list($a,$b)=each($this->me);
418 // contributed by I Sofer, 2001-03-24
419 // add support for nested arrays to scalarval
420 // i've created a new method here, so as to
421 // preserve back compatibility
426 while(list($id,$cont) = @each($b))
428 $b[$id] = $cont->scalarval();
432 // add support for structures directly encoding php objects
435 $t = get_object_vars($b);
437 while(list($id,$cont) = @each($t))
439 $t[$id] = $cont->scalarval();
442 while(list($id,$cont) = @each($t))
452 * Returns the value of a scalar xmlrpcval
459 list(,$b)=each($this->me);
464 * Returns the type of the xmlrpcval.
465 * For integers, 'int' is always returned in place of 'i4'
471 $xmlrpc = Xmlrpc::instance();
474 list($a,)=each($this->me);
475 if($a==$xmlrpc->xmlrpcI4)
477 $a=$xmlrpc->xmlrpcInt;
483 * Returns the m-th member of an xmlrpcval of struct type
484 * @param integer $m the index of the value to be retrieved (zero based)
488 function arraymem($m)
490 return $this->me['array'][$m];
494 * Returns the number of members in an xmlrpcval of array type
500 return count($this->me['array']);
504 * Returns the number of members in an xmlrpcval of struct type
508 function structsize()
510 return count($this->me['struct']);