+XML-RPC for PHP version 4.1.0 - 2016/6/26
+
+* improved: Added support for receiving <I8> and <EX:I8> integers, sending <I8>
+
+ If php is compiled in 32 bit mode, and an i8 int is received from a 3rd party, and error will be emitted.
+ Integers sent from the library to 3rd parties can be encoded using the i8 tag, but default to using 'int' by default;
+ the developer will have to create values as i8 explicitly if needed.
+ The library does *not* check if an outgoing integer is too big to fit in 4 bytes and convert it to an i8 automatically.
+
XML-RPC for PHP version 4.0.1 - 2016/3/27
* improved: all of the API documentation has been moved out of the manual and into the source code phpdoc comments
===== int
-The type i4 and i8 are accepted as a synonym
+The type i4 is accepted as a synonym
for int when creating xmlrpcval objects. The
- xml parsing code will always convert i4 and i8 to
+ xml parsing code will always convert i4 to
int: int is regarded
by this implementation as the canonical name for this type.
+The type i8 on the other hand is considered as a separate type.
+ Note that the library will never output integers as 'i8' on its own,
+ even when php is compiled in 64-bit mode.
+
===== base64
Base 64 encoding is performed transparently to the caller when
'BOOLEAN' => array('VALUE'),
'I4' => array('VALUE'),
'I8' => array('VALUE'),
+ 'EX:I8' => array('VALUE'),
'INT' => array('VALUE'),
'STRING' => array('VALUE'),
'DOUBLE' => array('VALUE'),
$this->_xh['lv'] = 1;
$this->_xh['php_class'] = null;
break;
- case 'I4':
case 'I8':
+ case 'EX:I8':
+ if (PHP_INT_SIZE === 4) {
+ /// INVALID ELEMENT: RAISE ISF so that it is later recognized!!!
+ $this->_xh['isf'] = 2;
+ $this->_xh['isf_reason'] = "Received i8 element but php is compiled in 32 bit mode";
+
+ return;
+ }
+ // fall through voluntarily
+ case 'I4':
case 'INT':
case 'STRING':
case 'BOOLEAN':
case 'DATETIME.ISO8601':
case 'BASE64':
if ($this->_xh['vt'] != 'value') {
- //two data elements inside a value: an error occurred!
+ // two data elements inside a value: an error occurred!
$this->_xh['isf'] = 2;
$this->_xh['isf_reason'] = "$name element following a {$this->_xh['vt']} element inside a single value";
case 'BOOLEAN':
case 'I4':
case 'I8':
+ case 'EX:I8':
case 'INT':
case 'STRING':
case 'DOUBLE':
$this->_xh['value'] = (double)$this->_xh['ac'];
}
} else {
- // we have an I4/INT
+ // we have an I4/I8/INT
// we must check that only 0123456789-<space> are characters here
if (!preg_match('/^[+-]?[0123456789 \t]+$/', $this->_xh['ac'])) {
/// @todo find a better way of throwing an error than this!
$pt = $p->kindOf();
}
} else {
- $pt = ($in[$n] == 'i4' || $in[$n] == 'i8') ? 'int' : strtolower($in[$n]); // dispatch maps never use i4...
+ $pt = ($in[$n] == 'i4') ? 'int' : strtolower($in[$n]); // dispatch maps never use i4...
}
// param index is $n+1, as first member of sig is return type
}
// coerce booleans into correct values
- // NB: we should either do it for datetimes, integers and doubles, too,
+ // NB: we should either do it for datetimes, integers, i8 and doubles, too,
// or just plain remove this check, implemented on booleans only...
if ($type == static::$xmlrpcBoolean) {
if (strcasecmp($val, 'true') == 0 || $val == 1 || ($val == true && strcasecmp($val, 'false'))) {
*/
public function serialize($charsetEncoding = '')
{
- // add check? slower, but helps to avoid recursion in serializing broken xmlrpc values...
- //if (is_object($o) && (get_class($o) == 'xmlrpcval' || is_subclass_of($o, 'xmlrpcval')))
- //{
reset($this->me);
list($typ, $val) = each($this->me);
return '<value>' . $this->serializedata($typ, $val, $charsetEncoding) . "</value>\n";
- //}
}
/**
/**
* Returns the type of the xmlrpc value.
*
- * For integers, 'int' is always returned in place of 'i4' or 'i8'.
+ * For integers, 'int' is always returned in place of 'i4'. 'i8' is considered a separate type and returned as such
*
* @return string
*/
{
reset($this->me);
list($a,) = each($this->me);
- if ($a == static::$xmlrpcI4 || $a == static::$xmlrpcI8) {
+ if ($a == static::$xmlrpcI4) {
$a = static::$xmlrpcInt;
}
return new \ArrayIterator();
}
-
public function offsetSet($offset, $value) {
switch ($this->mytype) {
}
return;
case 1:
-// todo: handle i4/i8 vs int
+// todo: handle i4 vs int
reset($this->me);
list($type,) = each($this->me);
if ($type != $offset) {
case 2:
return isset($this->me['array'][$offset]);
case 1:
-// todo: handle i4/i8 vs int
+// todo: handle i4 vs int
return $offset == $this->scalartyp();
default:
return false;
<value><int>01</int></value>
</member>
<member>
-<name>float1</name>
-<value><double>01.10</double></value>
-</member>
-<member>
<name>integer2</name>
<value><int>+1</int></value>
</member>
<member>
+<name>integer3</name>
+<value><i4>1</i4></value>
+</member>
+<member>
+<name>float1</name>
+<value><double>01.10</double></value>
+</member>
+<member>
<name>float2</name>
<value><double>+1.10</double></value>
</member>
$r = $m->parseResponse($fp);
$v = $r->value();
$s = $v->structmem('integer1');
- $t = $v->structmem('float1');
- $u = $v->structmem('integer2');
- $w = $v->structmem('float2');
- $x = $v->structmem('float3');
+ $t = $v->structmem('integer2');
+ $u = $v->structmem('integer3');
+ $x = $v->structmem('float1');
+ $y = $v->structmem('float2');
+ $z = $v->structmem('float3');
$this->assertEquals(1, $s->scalarval());
- $this->assertEquals(1.1, $t->scalarval());
+ $this->assertEquals(1, $t->scalarval());
$this->assertEquals(1, $u->scalarval());
- $this->assertEquals(1.1, $w->scalarval());
- $this->assertEquals(-110.0, $x->scalarval());
+
+ $this->assertEquals(1.1, $x->scalarval());
+ $this->assertEquals(1.1, $y->scalarval());
+ $this->assertEquals(-110.0, $z->scalarval());
+ }
+
+ public function testI8()
+ {
+ if (PHP_INT_SIZE == 4 ) {
+ $this->markTestSkipped('did not find a locale which sets decimal separator to comma');
+ return;
+ }
+
+ $m = $this->newMsg('dummy');
+ $fp =
+ '<?xml version="1.0"?>
+<methodResponse>
+<params>
+<param>
+<value>
+<struct>
+<member>
+<name>integer1</name>
+<value><i8>1</i8></value>
+</member>
+</member>
+</struct>
+</value>
+</param>
+</params>
+</methodResponse>';
+ $r = $m->parseResponse($fp);
+ $v = $r->value();
+ $s = $v->structmem('integer1');
+ $this->assertEquals(1, $s->scalarval());
}
public function testAddScalarToStruct()