comments and formatting
[plcapi.git] / src / Response.php
1 <?php
2
3 namespace PhpXmlRpc;
4
5 use PhpXmlRpc\Helper\Charset;
6
7 /**
8  * This class provides the representation of the response of an XML-RPC server.
9  * Server-side, a server method handler will construct a Response and pass it as its return value.
10  * An identical Response object will be returned by the result of an invocation of the send() method of the Client class.
11  */
12 class Response
13 {
14     /// @todo: do these need to be public?
15     /** @internal */
16     public $val = 0;
17     /** @internal */
18     public $valtyp;
19     /** @internal */
20     public $errno = 0;
21     /** @internal */
22     public $errstr = '';
23     public $payload;
24     public $content_type = 'text/xml';
25     public $hdrs = array();
26     public $_cookies = array();
27     public $raw_data = '';
28
29     /**
30      * @param Value|string|mixed $val either a Value object, a php value or the xml serialization of an xmlrpc value (a string)
31      * @param integer $fCode set it to anything but 0 to create an error response. In that case, $val is discarded
32      * @param string $fString the error string, in case of an error response
33      * @param string $valType The type of $val passed in. Either 'xmlrpcvals', 'phpvals' or 'xml'. Leave empty to let
34      *                        the code guess the correct type.
35      *
36      * @todo add check that $val / $fCode / $fString is of correct type???
37      *       NB: as of now we do not do it, since it might be either an xmlrpc value or a plain php val, or a complete
38      *       xml chunk, depending on usage of Client::send() inside which creator is called...
39      */
40     public function __construct($val, $fCode = 0, $fString = '', $valType = '')
41     {
42         if ($fCode != 0) {
43             // error response
44             $this->errno = $fCode;
45             $this->errstr = $fString;
46         } else {
47             // successful response
48             $this->val = $val;
49             if ($valType == '') {
50                 // user did not declare type of response value: try to guess it
51                 if (is_object($this->val) && is_a($this->val, 'PhpXmlRpc\Value')) {
52                     $this->valtyp = 'xmlrpcvals';
53                 } elseif (is_string($this->val)) {
54                     $this->valtyp = 'xml';
55                 } else {
56                     $this->valtyp = 'phpvals';
57                 }
58             } else {
59                 // user declares type of resp value: believe him
60                 $this->valtyp = $valType;
61             }
62         }
63     }
64
65     /**
66      * Returns the error code of the response.
67      *
68      * @return integer the error code of this response (0 for not-error responses)
69      */
70     public function faultCode()
71     {
72         return $this->errno;
73     }
74
75     /**
76      * Returns the error code of the response.
77      *
78      * @return string the error string of this response ('' for not-error responses)
79      */
80     public function faultString()
81     {
82         return $this->errstr;
83     }
84
85     /**
86      * Returns the value received by the server. If the Response's faultCode is non-zero then the value returned by this
87      * method should not be used (it may not even be an object).
88      *
89      * @return Value|string|mixed the Value object returned by the server. Might be an xml string or plain php value
90      *                            depending on the convention adopted when creating the Response
91      */
92     public function value()
93     {
94         return $this->val;
95     }
96
97     /**
98      * Returns an array with the cookies received from the server.
99      * Array has the form: $cookiename => array ('value' => $val, $attr1 => $val1, $attr2 => $val2, ...)
100      * with attributes being e.g. 'expires', 'path', domain'.
101      * NB: cookies sent as 'expired' by the server (i.e. with an expiry date in the past) are still present in the array.
102      * It is up to the user-defined code to decide how to use the received cookies, and whether they have to be sent back
103      * with the next request to the server (using Client::setCookie) or not.
104      *
105      * @return array[] array of cookies received from the server
106      */
107     public function cookies()
108     {
109         return $this->_cookies;
110     }
111
112     /**
113      * Returns xml representation of the response. XML prologue not included.
114      *
115      * @param string $charsetEncoding the charset to be used for serialization. If null, US-ASCII is assumed
116      *
117      * @return string the xml representation of the response
118      *
119      * @throws \Exception
120      */
121     public function serialize($charsetEncoding = '')
122     {
123         if ($charsetEncoding != '') {
124             $this->content_type = 'text/xml; charset=' . $charsetEncoding;
125         } else {
126             $this->content_type = 'text/xml';
127         }
128         if (PhpXmlRpc::$xmlrpc_null_apache_encoding) {
129             $result = "<methodResponse xmlns:ex=\"" . PhpXmlRpc::$xmlrpc_null_apache_encoding_ns . "\">\n";
130         } else {
131             $result = "<methodResponse>\n";
132         }
133         if ($this->errno) {
134             // Let non-ASCII response messages be tolerated by clients by xml-encoding non ascii chars
135             $result .= "<fault>\n" .
136                 "<value>\n<struct><member><name>faultCode</name>\n<value><int>" . $this->errno .
137                 "</int></value>\n</member>\n<member>\n<name>faultString</name>\n<value><string>" .
138                 Charset::instance()->encodeEntities($this->errstr, PhpXmlRpc::$xmlrpc_internalencoding, $charsetEncoding) . "</string></value>\n</member>\n" .
139                 "</struct>\n</value>\n</fault>";
140         } else {
141             if (!is_object($this->val) || !is_a($this->val, 'PhpXmlRpc\Value')) {
142                 if (is_string($this->val) && $this->valtyp == 'xml') {
143                     $result .= "<params>\n<param>\n" .
144                         $this->val .
145                         "</param>\n</params>";
146                 } else {
147                     /// @todo try to build something serializable?
148                     throw new \Exception('cannot serialize xmlrpc response objects whose content is native php values');
149                 }
150             } else {
151                 $result .= "<params>\n<param>\n" .
152                     $this->val->serialize($charsetEncoding) .
153                     "</param>\n</params>";
154             }
155         }
156         $result .= "\n</methodResponse>";
157         $this->payload = $result;
158
159         return $result;
160     }
161 }