6 /// @todo: does these need to be public?
9 public $_php_class=null;
13 * @param string $type any valid xmlrpc type name (lowercase). If null, 'string' is assumed
15 function __construct($val=-1, $type='') {
16 /// @todo: optimization creep - do not call addXX, do it all inline.
17 /// downside: booleans will not be coerced anymore
18 if($val!==-1 || $type!='')
20 // optimization creep: inlined all work done by constructor
25 $this->me['string']=$val;
32 case 'dateTime.iso8601':
36 $this->me[$type]=$val;
40 $this->me['array']=$val;
44 $this->me['struct']=$val;
47 error_log("XML-RPC: ".__METHOD__.": not a known type ($type)");
53 if($GLOBALS['xmlrpcTypes'][$type]==1)
55 $this->addScalar($val,$type);
57 elseif($GLOBALS['xmlrpcTypes'][$type]==2)
59 $this->addArray($val);
61 elseif($GLOBALS['xmlrpcTypes'][$type]==3)
63 $this->addStruct($val);
69 * Add a single php value to an (unitialized) xmlrpcval
72 * @return int 1 or 0 on failure
74 function addScalar($val, $type='string')
76 $xmlrpc = Phpxmlrpc::instance();
79 if(isset($xmlrpc->xmlrpcTypes[$type])) {
80 $typeof = $xmlrpc->xmlrpcTypes[$type];
85 error_log("XML-RPC: ".__METHOD__.": not a scalar type ($type)");
89 // coerce booleans into correct values
90 // NB: we should either do it for datetimes, integers and doubles, too,
91 // or just plain remove this check, implemented on booleans only...
92 if($type==$xmlrpc->xmlrpcBoolean)
94 if(strcasecmp($val,'true')==0 || $val==1 || ($val==true && strcasecmp($val,'false')))
104 switch($this->mytype)
107 error_log('XML-RPC: '.__METHOD__.': scalar xmlrpcval can have only one value');
110 error_log('XML-RPC: '.__METHOD__.': cannot add anonymous scalar to struct xmlrpcval');
113 // we're adding a scalar value to an array here
114 //$ar=$this->me['array'];
115 //$ar[]=new xmlrpcval($val, $type);
116 //$this->me['array']=$ar;
117 // Faster (?) avoid all the costly array-copy-by-val done here...
118 $this->me['array'][]=new xmlrpcval($val, $type);
121 // a scalar, so set the value and remember we're scalar
122 $this->me[$type]=$val;
123 $this->mytype=$typeof;
129 * Add an array of xmlrpcval objects to an xmlrpcval
131 * @return int 1 or 0 on failure
133 * @todo add some checking for $vals to be an array of xmlrpcvals?
135 public function addArray($vals)
137 $xmlrpc = Phpxmlrpc::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
162 * @todo add some checking for $vals to be an array?
164 public function addStruct($vals)
166 $xmlrpc = Phpxmlrpc::instance();
170 $this->mytype=$xmlrpc->xmlrpcTypes['struct'];
171 $this->me['struct']=$vals;
174 elseif($this->mytype==3)
176 // we're adding to a struct here
177 $this->me['struct'] = array_merge($this->me['struct'], $vals);
182 error_log('XML-RPC: '.__METHOD__.': already initialized as a [' . $this->kindOf() . ']');
188 * Returns a string containing "struct", "array" or "scalar" describing the base type of the value
191 public function kindOf()
193 switch($this->mytype)
209 private function serializedata($typ, $val, $charset_encoding='')
211 $xmlrpc = Phpxmlrpc::instance();
214 if(!isset($xmlrpc->xmlrpcTypes[$typ])) {
218 switch($xmlrpc->xmlrpcTypes[$typ])
223 case $xmlrpc->xmlrpcBase64:
224 $rs.="<${typ}>" . base64_encode($val) . "</${typ}>";
226 case $xmlrpc->xmlrpcBoolean:
227 $rs.="<${typ}>" . ($val ? '1' : '0') . "</${typ}>";
229 case $xmlrpc->xmlrpcString:
230 // G. Giunta 2005/2/13: do NOT use htmlentities, since
231 // it will produce named html entities, which are invalid xml
232 $rs.="<${typ}>" . xmlrpc_encode_entitites($val, $xmlrpc->xmlrpc_internalencoding, $charset_encoding). "</${typ}>";
234 case $xmlrpc->xmlrpcInt:
235 case $xmlrpc->xmlrpcI4:
236 $rs.="<${typ}>".(int)$val."</${typ}>";
238 case $xmlrpc->xmlrpcDouble:
239 // avoid using standard conversion of float to string because it is locale-dependent,
240 // and also because the xmlrpc spec forbids exponential notation.
241 // sprintf('%F') could be most likely ok but it fails eg. on 2e-14.
242 // The code below tries its best at keeping max precision while avoiding exp notation,
243 // but there is of course no limit in the number of decimal places to be used...
244 $rs.="<${typ}>".preg_replace('/\\.?0+$/','',number_format((double)$val, 128, '.', ''))."</${typ}>";
246 case $xmlrpc->xmlrpcDateTime:
249 $rs.="<${typ}>${val}</${typ}>";
251 else if(is_a($val, 'DateTime'))
253 $rs.="<${typ}>".$val->format('Ymd\TH:i:s')."</${typ}>";
255 else if(is_int($val))
257 $rs.="<${typ}>".strftime("%Y%m%dT%H:%M:%S", $val)."</${typ}>";
261 // not really a good idea here: but what shall we output anyway? left for backward compat...
262 $rs.="<${typ}>${val}</${typ}>";
265 case $xmlrpc->xmlrpcNull:
266 if ($xmlrpc->xmlrpc_null_apache_encoding)
276 // no standard type value should arrive here, but provide a possibility
277 // for xmlrpcvals of unknown type...
278 $rs.="<${typ}>${val}</${typ}>";
283 if ($this->_php_class)
285 $rs.='<struct php_class="' . $this->_php_class . "\">\n";
291 foreach($val as $key2 => $val2)
293 $rs.='<member><name>'.xmlrpc_encode_entitites($key2, $xmlrpc->xmlrpc_internalencoding, $charset_encoding)."</name>\n";
294 //$rs.=$this->serializeval($val2);
295 $rs.=$val2->serialize($charset_encoding);
302 $rs.="<array>\n<data>\n";
303 for($i=0; $i<count($val); $i++)
305 //$rs.=$this->serializeval($val[$i]);
306 $rs.=$val[$i]->serialize($charset_encoding);
308 $rs.="</data>\n</array>";
317 * Returns xml representation of the value. XML prologue not included
318 * @param string $charset_encoding the charset to be used for serialization. if null, US-ASCII is assumed
321 public function serialize($charset_encoding='')
323 // add check? slower, but helps to avoid recursion in serializing broken xmlrpcvals...
324 //if (is_object($o) && (get_class($o) == 'xmlrpcval' || is_subclass_of($o, 'xmlrpcval')))
327 list($typ, $val) = each($this->me);
328 return '<value>' . $this->serializedata($typ, $val, $charset_encoding) . "</value>\n";
333 function serializeval($o)
335 // add check? slower, but helps to avoid recursion in serializing broken xmlrpcvals...
336 //if (is_object($o) && (get_class($o) == 'xmlrpcval' || is_subclass_of($o, 'xmlrpcval')))
340 list($typ, $val) = each($ar);
341 return '<value>' . $this->serializedata($typ, $val) . "</value>\n";
346 * Checks whether a struct member with a given name is present.
347 * Works only on xmlrpcvals of type struct.
348 * @param string $m the name of the struct member to be looked up
351 public function structmemexists($m)
353 return array_key_exists($m, $this->me['struct']);
357 * Returns the value of a given struct member (an xmlrpcval object in itself).
358 * Will raise a php warning if struct member of given name does not exist
359 * @param string $m the name of the struct member to be looked up
362 public function structmem($m)
364 return $this->me['struct'][$m];
368 * Reset internal pointer for xmlrpcvals of type struct.
370 public function structreset()
372 reset($this->me['struct']);
376 * Return next member element for xmlrpcvals of type struct.
379 public function structeach()
381 return each($this->me['struct']);
384 // DEPRECATED! this code looks like it is very fragile and has not been fixed
385 // for a long long time. Shall we remove it for 2.0?
390 list($a,$b)=each($this->me);
391 // contributed by I Sofer, 2001-03-24
392 // add support for nested arrays to scalarval
393 // i've created a new method here, so as to
394 // preserve back compatibility
399 while(list($id,$cont) = @each($b))
401 $b[$id] = $cont->scalarval();
405 // add support for structures directly encoding php objects
408 $t = get_object_vars($b);
410 while(list($id,$cont) = @each($t))
412 $t[$id] = $cont->scalarval();
415 while(list($id,$cont) = @each($t))
425 * Returns the value of a scalar xmlrpcval
428 public function scalarval()
431 list(,$b)=each($this->me);
436 * Returns the type of the xmlrpcval.
437 * For integers, 'int' is always returned in place of 'i4'
440 public function scalartyp()
442 $xmlrpc = Phpxmlrpc::instance();
445 list($a,)=each($this->me);
446 if($a==$xmlrpc->xmlrpcI4)
448 $a=$xmlrpc->xmlrpcInt;
454 * Returns the m-th member of an xmlrpcval of struct type
455 * @param integer $m the index of the value to be retrieved (zero based)
458 public function arraymem($m)
460 return $this->me['array'][$m];
464 * Returns the number of members in an xmlrpcval of array type
467 public function arraysize()
469 return count($this->me['array']);
473 * Returns the number of members in an xmlrpcval of struct type
476 public function structsize()
478 return count($this->me['struct']);