5 use PhpXmlRpc\Exception\StateErrorException
;
6 use PhpXmlRpc\Traits\CharsetEncoderAware
;
7 use PhpXmlRpc\Traits\DeprecationLogger
;
8 use PhpXmlRpc\Traits\PayloadBearer
;
11 * This class provides the representation of the response of an XML-RPC server.
12 * Server-side, a server method handler will construct a Response and pass it as its return value.
13 * An identical Response object will be returned by the result of an invocation of the send() method of the Client class.
15 * @property Value|string|mixed $val deprecated - public access left in purely for BC. Access via value()/__construct()
16 * @property string $valtyp deprecated - public access left in purely for BC. Access via valueType()/__construct()
17 * @property int $errno deprecated - public access left in purely for BC. Access via faultCode()/__construct()
18 * @property string $errstr deprecated - public access left in purely for BC. Access faultString()/__construct()
19 * @property string $payload deprecated - public access left in purely for BC. Access via getPayload()/setPayload()
20 * @property string $content_type deprecated - public access left in purely for BC. Access via getContentType()/setPayload()
21 * @property array $hdrs deprecated. Access via httpResponse()['headers'], set via $httpResponse['headers']
22 * @property array _cookies deprecated. Access via httpResponse()['cookies'], set via $httpResponse['cookies']
23 * @property string $raw_data deprecated. Access via httpResponse()['raw_data'], set via $httpResponse['raw_data']
27 use CharsetEncoderAware
;
28 use DeprecationLogger
;
31 /** @var Value|string|mixed */
38 protected $errstr = '';
40 protected $httpResponse = array('headers' => array(), 'cookies' => array(), 'raw_data' => '', 'status_code' => null);
43 * @param Value|string|mixed $val either a Value object, a php value or the xml serialization of an xml-rpc value (a string).
44 * Note that using anything other than a Value object wll have an impact on serialization.
45 * @param integer $fCode set it to anything but 0 to create an error response. In that case, $val is discarded
46 * @param string $fString the error string, in case of an error response
47 * @param string $valType The type of $val passed in. Either 'xmlrpcvals', 'phpvals' or 'xml'. Leave empty to let
48 * the code guess the correct type by looking at $val - in which case strings are assumed
49 * to be serialized xml
50 * @param array|null $httpResponse this should be set when the response is being built out of data received from
51 * http (i.e. not when programmatically building a Response server-side). Array
52 * keys should include, if known: headers, cookies, raw_data, status_code
54 * @todo add check that $val / $fCode / $fString is of correct type? We could at least log a warning for fishy cases...
55 * NB: as of now we do not do it, since it might be either an xml-rpc value or a plain php val, or a complete
56 * xml chunk, depending on usage of Client::send() inside which the constructor is called.
58 public function __construct($val, $fCode = 0, $fString = '', $valType = '', $httpResponse = null)
62 $this->errno
= $fCode;
63 $this->errstr
= $fString;
65 // successful response
68 // user did not declare type of response value: try to guess it
69 if (is_object($this->val
) && is_a($this->val
, 'PhpXmlRpc\Value')) {
70 $this->valtyp
= 'xmlrpcvals';
71 } elseif (is_string($this->val
)) {
72 $this->valtyp
= 'xml';
74 $this->valtyp
= 'phpvals';
77 $this->valtyp
= $valType;
78 // user declares the type of resp value: we "almost" trust it... but log errors just in case
79 if (($this->valtyp
== 'xmlrpcvals' && (!is_a($this->val
, 'PhpXmlRpc\Value'))) ||
80 ($this->valtyp
== 'xml' && (!is_string($this->val
)))) {
81 $this->getLogger()->error('XML-RPC: ' . __METHOD__
. ': value passed in does not match type ' . $valType);
86 if (is_array($httpResponse)) {
87 $this->httpResponse
= array_merge(array('headers' => array(), 'cookies' => array(), 'raw_data' => '', 'status_code' => null), $httpResponse);
92 * Returns the error code of the response.
94 * @return integer the error code of this response (0 for not-error responses)
96 public function faultCode()
102 * Returns the error code of the response.
104 * @return string the error string of this response ('' for not-error responses)
106 public function faultString()
108 return $this->errstr
;
112 * Returns the value received by the server. If the Response's faultCode is non-zero then the value returned by this
113 * method should not be used (it may not even be an object).
115 * @return Value|string|mixed the Value object returned by the server. Might be an xml string or plain php value
116 * depending on the convention adopted when creating the Response
118 public function value()
126 public function valueType()
128 return $this->valtyp
;
132 * Returns an array with the cookies received from the server.
133 * Array has the form: $cookiename => array ('value' => $val, $attr1 => $val1, $attr2 => $val2, ...)
134 * with attributes being e.g. 'expires', 'path', domain'.
135 * NB: cookies sent as 'expired' by the server (i.e. with an expiry date in the past) are still present in the array.
136 * It is up to the user-defined code to decide how to use the received cookies, and whether they have to be sent back
137 * with the next request to the server (using $client->setCookie) or not.
138 * The values are filled in at constructor time, and might not be set for specific debug values used.
140 * @return array[] array of cookies received from the server
142 public function cookies()
144 return $this->httpResponse
['cookies'];
148 * Returns an array with info about the http response received from the server.
149 * The values are filled in at constructor time, and might not be set for specific debug values used.
151 * @return array array with keys 'headers', 'cookies', 'raw_data' and 'status_code'.
153 public function httpResponse()
155 return $this->httpResponse
;
159 * Returns xml representation of the response, XML prologue _not_ included. Sets `payload` and `content_type` properties
161 * @param string $charsetEncoding the charset to be used for serialization. If null, US-ASCII is assumed
162 * @return string the xml representation of the response
163 * @throws StateErrorException if the response was built out of a value of an unsupported type
165 public function serialize($charsetEncoding = '')
167 if ($charsetEncoding != '') {
168 $this->content_type
= 'text/xml; charset=' . $charsetEncoding;
170 $this->content_type
= 'text/xml';
173 if (PhpXmlRpc
::$xmlrpc_null_apache_encoding) {
174 $result = "<methodResponse xmlns:ex=\"" . PhpXmlRpc
::$xmlrpc_null_apache_encoding_ns . "\">\n";
176 $result = "<methodResponse>\n";
179 // Let non-ASCII response messages be tolerated by clients by xml-encoding non ascii chars
180 $result .= "<fault>\n" .
181 "<value>\n<struct><member><name>faultCode</name>\n<value><int>" . $this->errno
.
182 "</int></value>\n</member>\n<member>\n<name>faultString</name>\n<value><string>" .
183 $this->getCharsetEncoder()->encodeEntities($this->errstr
, PhpXmlRpc
::$xmlrpc_internalencoding, $charsetEncoding) .
184 "</string></value>\n</member>\n</struct>\n</value>\n</fault>";
186 if (is_object($this->val
) && is_a($this->val
, 'PhpXmlRpc\Value')) {
187 $result .= "<params>\n<param>\n" . $this->val
->serialize($charsetEncoding) . "</param>\n</params>";
188 } else if (is_string($this->val
) && $this->valtyp
== 'xml') {
189 $result .= "<params>\n<param>\n" .
191 "</param>\n</params>";
192 } else if ($this->valtyp
== 'phpvals') {
193 $encoder = new Encoder();
194 $val = $encoder->encode($this->val
);
195 $result .= "<params>\n<param>\n" . $val->serialize($charsetEncoding) . "</param>\n</params>";
197 throw new StateErrorException('cannot serialize xmlrpc response objects whose content is native php values');
200 $result .= "\n</methodResponse>";
202 $this->payload
= $result;
208 * @param string $charsetEncoding
211 public function xml_header($charsetEncoding = '')
213 if ($charsetEncoding != '') {
214 return "<?xml version=\"1.0\" encoding=\"$charsetEncoding\"?" . ">\n";
216 return "<?xml version=\"1.0\"?" . ">\n";
222 // we have to make this return by ref in order to allow calls such as `$resp->_cookies['name'] = ['value' => 'something'];`
223 public function &__get($name)
232 $this->logDeprecation('Getting property Response::' . $name . ' is deprecated');
235 $this->logDeprecation('Getting property Response::' . $name . ' is deprecated');
236 return $this->httpResponse
['headers'];
238 $this->logDeprecation('Getting property Response::' . $name . ' is deprecated');
239 return $this->httpResponse
['cookies'];
241 $this->logDeprecation('Getting property Response::' . $name . ' is deprecated');
242 return $this->httpResponse
['raw_data'];
244 /// @todo throw instead? There are very few other places where the lib trigger errors which can potentially reach stdout...
245 $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS
, 1);
246 trigger_error('Undefined property via __get(): ' . $name . ' in ' . $trace[0]['file'] . ' on line ' . $trace[0]['line'], E_USER_WARNING
);
252 public function __set($name, $value)
261 $this->logDeprecation('Setting property Response::' . $name . ' is deprecated');
262 $this->$name = $value;
265 $this->logDeprecation('Setting property Response::' . $name . ' is deprecated');
266 $this->httpResponse
['headers'] = $value;
269 $this->logDeprecation('Setting property Response::' . $name . ' is deprecated');
270 $this->httpResponse
['cookies'] = $value;
273 $this->logDeprecation('Setting property Response::' . $name . ' is deprecated');
274 $this->httpResponse
['raw_data'] = $value;
277 /// @todo throw instead? There are very few other places where the lib trigger errors which can potentially reach stdout...
278 $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS
, 1);
279 trigger_error('Undefined property via __set(): ' . $name . ' in ' . $trace[0]['file'] . ' on line ' . $trace[0]['line'], E_USER_WARNING
);
283 public function __isset($name)
292 $this->logDeprecation('Checking property Response::' . $name . ' is deprecated');
293 return isset($this->$name);
295 $this->logDeprecation('Checking property Response::' . $name . ' is deprecated');
296 return isset($this->httpResponse
['headers']);
298 $this->logDeprecation('Checking property Response::' . $name . ' is deprecated');
299 return isset($this->httpResponse
['cookies']);
301 $this->logDeprecation('Checking property Response::' . $name . ' is deprecated');
302 return isset($this->httpResponse
['raw_data']);
308 public function __unset($name)
317 $this->logDeprecation('Setting property Response::' . $name . ' is deprecated');
321 $this->logDeprecation('Unsetting property Response::' . $name . ' is deprecated');
322 unset($this->httpResponse
['headers']);
325 $this->logDeprecation('Unsetting property Response::' . $name . ' is deprecated');
326 unset($this->httpResponse
['cookies']);
329 $this->logDeprecation('Unsetting property Response::' . $name . ' is deprecated');
330 unset($this->httpResponse
['raw_data']);
333 /// @todo throw instead? There are very few other places where the lib trigger errors which can potentially reach stdout...
334 $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS
, 1);
335 trigger_error('Undefined property via __unset(): ' . $name . ' in ' . $trace[0]['file'] . ' on line ' . $trace[0]['line'], E_USER_WARNING
);