NB: since the xml-rpc spec mandates that no Timezone is used on the wire for dateTime values, the DateTime objects
created by the library will be set to the default php timzeone, set using the 'date.timezone' ini setting.
+* new: it is now possible to tell the library to allow non-standard formats for received datetime value, such as f.e.
+ datetimes with a timezone specifier, by setting a custom value to `PhpXmlRpc\PhpXmlRpc::$xmlrpc_datetime_format`.
+ Note that the regex used by default to validate the incoming date strings has been tightened not to accept clearly
+ invalid dates such as a month '13', day '32' or hour '25'. The vale '60' is now allowed for seconds, as required by
+ the ISO 8601 standard for leap seconds.
+
* fixed: when calling `Client::multicall()` with `$client->return_type = 'xml'`, we would be always falling back to
non-multicall requests
to a custom character set and the mbstring extension is enabled. It will be encoded instead in the specified character
set. We expect this to affect few users, as setting `PhpXmlRpc::$internal_encoding` to a custom character set did
not make a lot of sense beforehand
+ - the regular expression used to check if incoming datetime values are valid has been tightened to reject clearly
+ invalid dates. It has been widened as well, to allow leap seconds.
- parameters `$timeout` and `$method` are now considered deprecated in `Client::send()` and `Client::multicall()`
- Client properties `$errno` and `$errstring` are now deprecated
- the code generated by the debugger when using "Generate stub for method call" will throw on errors instead of
$type = gettype($phpVal);
switch ($type) {
case 'string':
- /// @todo should we be stricter in the accepted dates (i.e. reject more of invalid days & times)?
- if (in_array('auto_dates', $options) && preg_match('/^[0-9]{8}T[0-9]{2}:[0-9]{2}:[0-9]{2}$/', $phpVal)) {
+ if (in_array('auto_dates', $options) && preg_match(PhpXmlRpc::$xmlrpc_datetime_format, $phpVal)) {
$xmlrpcVal = new Value($phpVal, Value::$xmlrpcDateTime);
} else {
$xmlrpcVal = new Value($phpVal, Value::$xmlrpcString);
namespace PhpXmlRpc\Helper;
+use PhpXmlRpc\PhpXmlRpc;
+
/**
* Helps to convert timestamps to the xml-rpc date format.
*
public static function iso8601Decode($idate, $utc = 0)
{
$t = 0;
- if (preg_match('/([0-9]{4})([0-1][0-9])([0-3][0-9])T([0-2][0-9]):([0-5][0-9]):([0-5][0-9])/', $idate, $regs)) {
+ if (preg_match(PhpXmlRpc::$xmlrpc_datetime_format, $idate, $regs)) {
if ($utc) {
$t = gmmktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]);
} else {
if ($name == 'STRING') {
$this->_xh['value'] = $this->_xh['ac'];
} elseif ($name == 'DATETIME.ISO8601') {
- if (!preg_match('/^[0-9]{8}T[0-9]{2}:[0-9]{2}:[0-9]{2}$/', $this->_xh['ac'])) {
+ if (!preg_match(PhpXmlRpc::$xmlrpc_datetime_format, $this->_xh['ac'])) {
$this->getLogger()->errorLog('XML-RPC: ' . __METHOD__ . ': invalid value received in DATETIME: ' . $this->_xh['ac']);
}
$this->_xh['vt'] = Value::$xmlrpcDateTime;
// in the xml declaration, and verify if they match.
/// @todo implement check as described above?
/// @todo implement check for first bytes of string even without a BOM? (It sure looks harder than for cases WITH a BOM)
- if (preg_match('/^(\x00\x00\xFE\xFF|\xFF\xFE\x00\x00|\x00\x00\xFF\xFE|\xFE\xFF\x00\x00)/', $xmlChunk)) {
+ if (preg_match('/^(?:\x00\x00\xFE\xFF|\xFF\xFE\x00\x00|\x00\x00\xFF\xFE|\xFE\xFF\x00\x00)/', $xmlChunk)) {
return 'UCS-4';
- } elseif (preg_match('/^(\xFE\xFF|\xFF\xFE)/', $xmlChunk)) {
+ } elseif (preg_match('/^(?:\xFE\xFF|\xFF\xFE)/', $xmlChunk)) {
return 'UTF-16';
- } elseif (preg_match('/^(\xEF\xBB\xBF)/', $xmlChunk)) {
+ } elseif (preg_match('/^(?:\xEF\xBB\xBF)/', $xmlChunk)) {
return 'UTF-8';
}
{
// scan the first bytes of the data for a UTF-16 (or other) BOM pattern
// (source: http://www.w3.org/TR/2000/REC-xml-20001006)
- if (preg_match('/^(\x00\x00\xFE\xFF|\xFF\xFE\x00\x00|\x00\x00\xFF\xFE|\xFE\xFF\x00\x00)/', $xmlChunk)) {
+ if (preg_match('/^(?:\x00\x00\xFE\xFF|\xFF\xFE\x00\x00|\x00\x00\xFF\xFE|\xFE\xFF\x00\x00)/', $xmlChunk)) {
return true;
- } elseif (preg_match('/^(\xFE\xFF|\xFF\xFE)/', $xmlChunk)) {
+ } elseif (preg_match('/^(?:\xFE\xFF|\xFF\xFE)/', $xmlChunk)) {
return true;
- } elseif (preg_match('/^(\xEF\xBB\xBF)/', $xmlChunk)) {
+ } elseif (preg_match('/^(?:\xEF\xBB\xBF)/', $xmlChunk)) {
return true;
}
// EQ: SPACE?=SPACE? === [ \x9\xD\xA]*=[ \x9\xD\xA]*
if (preg_match('/^<\?xml\s+version\s*=\s*' . "((?:\"[a-zA-Z0-9_.:-]+\")|(?:'[a-zA-Z0-9_.:-]+'))" .
'\s+encoding\s*=\s*' . "((?:\"[A-Za-z][A-Za-z0-9._-]*\")|(?:'[A-Za-z][A-Za-z0-9._-]*'))/",
- $xmlChunk, $matches)) {
+ $xmlChunk)) {
return true;
}
*/
public static $xmlpc_double_precision = 128;
+ /**
+ * @var string
+ * Used to validate received date values. Alter this if the server/client you are communicating with uses date
+ * formats non-conformant with the spec
+ */
+ public static $xmlrpc_datetime_format = '/^([0-9]{4})(0[1-9]|1[012])(0[1-9]|[12][0-9]|3[01])T([01][0-9]|2[0-4]):([0-5][0-9]):([0-5][0-9]|60)$/';
+
/**
* A function to be used for compatibility with legacy code: it creates all global variables which used to be declared,
* such as library version etc...