94 |
jpm |
1 |
<?php
|
|
|
2 |
/**
|
|
|
3 |
* PEAR_Remote
|
|
|
4 |
*
|
|
|
5 |
* PHP versions 4 and 5
|
|
|
6 |
*
|
|
|
7 |
* LICENSE: This source file is subject to version 3.0 of the PHP license
|
|
|
8 |
* that is available through the world-wide-web at the following URI:
|
|
|
9 |
* http://www.php.net/license/3_0.txt. If you did not receive a copy of
|
|
|
10 |
* the PHP License and are unable to obtain it through the web, please
|
|
|
11 |
* send a note to license@php.net so we can mail you a copy immediately.
|
|
|
12 |
*
|
|
|
13 |
* @category pear
|
|
|
14 |
* @package PEAR
|
|
|
15 |
* @author Stig Bakken <ssb@php.net>
|
|
|
16 |
* @author Greg Beaver <cellog@php.net>
|
|
|
17 |
* @copyright 1997-2006 The PHP Group
|
|
|
18 |
* @license http://www.php.net/license/3_0.txt PHP License 3.0
|
|
|
19 |
* @version CVS: $Id: Remote.php,v 1.79 2006/03/27 04:33:11 cellog Exp $
|
|
|
20 |
* @link http://pear.php.net/package/PEAR
|
|
|
21 |
* @since File available since Release 0.1
|
|
|
22 |
*/
|
|
|
23 |
|
|
|
24 |
/**
|
|
|
25 |
* needed for PEAR_Error
|
|
|
26 |
*/
|
|
|
27 |
require_once 'PEAR.php';
|
|
|
28 |
require_once 'PEAR/Config.php';
|
|
|
29 |
|
|
|
30 |
/**
|
|
|
31 |
* This is a class for doing remote operations against the central
|
|
|
32 |
* PEAR database.
|
|
|
33 |
*
|
|
|
34 |
* @nodep XML_RPC_Value
|
|
|
35 |
* @nodep XML_RPC_Message
|
|
|
36 |
* @nodep XML_RPC_Client
|
|
|
37 |
* @category pear
|
|
|
38 |
* @package PEAR
|
|
|
39 |
* @author Stig Bakken <ssb@php.net>
|
|
|
40 |
* @author Greg Beaver <cellog@php.net>
|
|
|
41 |
* @copyright 1997-2006 The PHP Group
|
|
|
42 |
* @license http://www.php.net/license/3_0.txt PHP License 3.0
|
|
|
43 |
* @version Release: 1.5.1
|
|
|
44 |
* @link http://pear.php.net/package/PEAR
|
|
|
45 |
* @since Class available since Release 0.1
|
|
|
46 |
*/
|
|
|
47 |
class PEAR_Remote extends PEAR
|
|
|
48 |
{
|
|
|
49 |
// {{{ properties
|
|
|
50 |
|
|
|
51 |
var $config = null;
|
|
|
52 |
var $cache = null;
|
|
|
53 |
/**
|
|
|
54 |
* @var PEAR_Registry
|
|
|
55 |
* @access private
|
|
|
56 |
*/
|
|
|
57 |
var $_registry;
|
|
|
58 |
|
|
|
59 |
// }}}
|
|
|
60 |
|
|
|
61 |
// {{{ PEAR_Remote(config_object)
|
|
|
62 |
|
|
|
63 |
function PEAR_Remote(&$config)
|
|
|
64 |
{
|
|
|
65 |
$this->PEAR();
|
|
|
66 |
$this->config = &$config;
|
|
|
67 |
$this->_registry = &$this->config->getRegistry();
|
|
|
68 |
}
|
|
|
69 |
|
|
|
70 |
// }}}
|
|
|
71 |
// {{{ setRegistry()
|
|
|
72 |
|
|
|
73 |
function setRegistry(&$reg)
|
|
|
74 |
{
|
|
|
75 |
$this->_registry = &$reg;
|
|
|
76 |
}
|
|
|
77 |
// }}}
|
|
|
78 |
// {{{ getCache()
|
|
|
79 |
|
|
|
80 |
|
|
|
81 |
function getCache($args)
|
|
|
82 |
{
|
|
|
83 |
$id = md5(serialize($args));
|
|
|
84 |
$cachedir = $this->config->get('cache_dir');
|
|
|
85 |
$filename = $cachedir . DIRECTORY_SEPARATOR . 'xmlrpc_cache_' . $id;
|
|
|
86 |
if (!file_exists($filename)) {
|
|
|
87 |
return null;
|
|
|
88 |
}
|
|
|
89 |
|
|
|
90 |
$fp = fopen($filename, 'rb');
|
|
|
91 |
if (!$fp) {
|
|
|
92 |
return null;
|
|
|
93 |
}
|
|
|
94 |
fclose($fp);
|
|
|
95 |
$content = file_get_contents($filename);
|
|
|
96 |
$result = array(
|
|
|
97 |
'age' => time() - filemtime($filename),
|
|
|
98 |
'lastChange' => filemtime($filename),
|
|
|
99 |
'content' => unserialize($content),
|
|
|
100 |
);
|
|
|
101 |
return $result;
|
|
|
102 |
}
|
|
|
103 |
|
|
|
104 |
// }}}
|
|
|
105 |
|
|
|
106 |
// {{{ saveCache()
|
|
|
107 |
|
|
|
108 |
function saveCache($args, $data)
|
|
|
109 |
{
|
|
|
110 |
$id = md5(serialize($args));
|
|
|
111 |
$cachedir = $this->config->get('cache_dir');
|
|
|
112 |
if (!file_exists($cachedir)) {
|
|
|
113 |
System::mkdir(array('-p', $cachedir));
|
|
|
114 |
}
|
|
|
115 |
$filename = $cachedir.'/xmlrpc_cache_'.$id;
|
|
|
116 |
|
|
|
117 |
$fp = @fopen($filename, "wb");
|
|
|
118 |
if ($fp) {
|
|
|
119 |
fwrite($fp, serialize($data));
|
|
|
120 |
fclose($fp);
|
|
|
121 |
}
|
|
|
122 |
}
|
|
|
123 |
|
|
|
124 |
// }}}
|
|
|
125 |
|
|
|
126 |
// {{{ clearCache()
|
|
|
127 |
|
|
|
128 |
function clearCache($method, $args)
|
|
|
129 |
{
|
|
|
130 |
array_unshift($args, $method);
|
|
|
131 |
array_unshift($args, $this->config->get('default_channel')); // cache by channel
|
|
|
132 |
$id = md5(serialize($args));
|
|
|
133 |
$cachedir = $this->config->get('cache_dir');
|
|
|
134 |
$filename = $cachedir.'/xmlrpc_cache_'.$id;
|
|
|
135 |
if (file_exists($filename)) {
|
|
|
136 |
@unlink($filename);
|
|
|
137 |
}
|
|
|
138 |
}
|
|
|
139 |
|
|
|
140 |
// }}}
|
|
|
141 |
// {{{ call(method, [args...])
|
|
|
142 |
|
|
|
143 |
function call($method)
|
|
|
144 |
{
|
|
|
145 |
$_args = $args = func_get_args();
|
|
|
146 |
|
|
|
147 |
$server_channel = $this->config->get('default_channel');
|
|
|
148 |
$channel = $this->_registry->getChannel($server_channel);
|
|
|
149 |
if (!PEAR::isError($channel)) {
|
|
|
150 |
$mirror = $this->config->get('preferred_mirror');
|
|
|
151 |
if ($channel->getMirror($mirror)) {
|
|
|
152 |
if ($channel->supports('xmlrpc', $method, $mirror)) {
|
|
|
153 |
$server_channel = $server_host = $mirror; // use the preferred mirror
|
|
|
154 |
$server_port = $channel->getPort($mirror);
|
|
|
155 |
} elseif (!$channel->supports('xmlrpc', $method)) {
|
|
|
156 |
return $this->raiseError("Channel $server_channel does not " .
|
|
|
157 |
"support xml-rpc method $method");
|
|
|
158 |
}
|
|
|
159 |
}
|
|
|
160 |
if (!isset($server_host)) {
|
|
|
161 |
if (!$channel->supports('xmlrpc', $method)) {
|
|
|
162 |
return $this->raiseError("Channel $server_channel does not support " .
|
|
|
163 |
"xml-rpc method $method");
|
|
|
164 |
} else {
|
|
|
165 |
$server_host = $server_channel;
|
|
|
166 |
$server_port = $channel->getPort();
|
|
|
167 |
}
|
|
|
168 |
}
|
|
|
169 |
} else {
|
|
|
170 |
return $this->raiseError("Unknown channel '$server_channel'");
|
|
|
171 |
}
|
|
|
172 |
|
|
|
173 |
array_unshift($_args, $server_channel); // cache by channel
|
|
|
174 |
$this->cache = $this->getCache($_args);
|
|
|
175 |
$cachettl = $this->config->get('cache_ttl');
|
|
|
176 |
// If cache is newer than $cachettl seconds, we use the cache!
|
|
|
177 |
if ($this->cache !== null && $this->cache['age'] < $cachettl) {
|
|
|
178 |
return $this->cache['content'];
|
|
|
179 |
}
|
|
|
180 |
$fp = false;
|
|
|
181 |
if (extension_loaded("xmlrpc")) {
|
|
|
182 |
$result = call_user_func_array(array(&$this, 'call_epi'), $args);
|
|
|
183 |
if (!PEAR::isError($result)) {
|
|
|
184 |
$this->saveCache($_args, $result);
|
|
|
185 |
}
|
|
|
186 |
return $result;
|
|
|
187 |
} elseif (!($fp = fopen('XML/RPC.php', 'r', true))) {
|
|
|
188 |
return $this->raiseError("For this remote PEAR operation you need to load the xmlrpc extension or install XML_RPC");
|
|
|
189 |
}
|
|
|
190 |
include_once 'XML/RPC.php';
|
|
|
191 |
if ($fp) {
|
|
|
192 |
fclose($fp);
|
|
|
193 |
}
|
|
|
194 |
|
|
|
195 |
array_shift($args);
|
|
|
196 |
$username = $this->config->get('username');
|
|
|
197 |
$password = $this->config->get('password');
|
|
|
198 |
$eargs = array();
|
|
|
199 |
foreach($args as $arg) {
|
|
|
200 |
$eargs[] = $this->_encode($arg);
|
|
|
201 |
}
|
|
|
202 |
$f = new XML_RPC_Message($method, $eargs);
|
|
|
203 |
if ($this->cache !== null) {
|
|
|
204 |
$maxAge = '?maxAge='.$this->cache['lastChange'];
|
|
|
205 |
} else {
|
|
|
206 |
$maxAge = '';
|
|
|
207 |
}
|
|
|
208 |
$proxy_host = $proxy_port = $proxy_user = $proxy_pass = '';
|
|
|
209 |
if ($proxy = parse_url($this->config->get('http_proxy'))) {
|
|
|
210 |
$proxy_host = isset($proxy['host']) ? $proxy['host'] : null;
|
|
|
211 |
if (isset($proxy['scheme']) && $proxy['scheme'] == 'https') {
|
|
|
212 |
$proxy_host = 'https://' . $proxy_host;
|
|
|
213 |
}
|
|
|
214 |
$proxy_port = isset($proxy['port']) ? $proxy['port'] : 8080;
|
|
|
215 |
$proxy_user = isset($proxy['user']) ? urldecode($proxy['user']) : null;
|
|
|
216 |
$proxy_pass = isset($proxy['pass']) ? urldecode($proxy['pass']) : null;
|
|
|
217 |
}
|
|
|
218 |
$shost = $server_host;
|
|
|
219 |
if ($channel->getSSL()) {
|
|
|
220 |
$shost = "https://$shost";
|
|
|
221 |
}
|
|
|
222 |
$c = new XML_RPC_Client('/' . $channel->getPath('xmlrpc')
|
|
|
223 |
. $maxAge, $shost, $server_port, $proxy_host, $proxy_port,
|
|
|
224 |
$proxy_user, $proxy_pass);
|
|
|
225 |
if ($username && $password) {
|
|
|
226 |
$c->setCredentials($username, $password);
|
|
|
227 |
}
|
|
|
228 |
if ($this->config->get('verbose') >= 3) {
|
|
|
229 |
$c->setDebug(1);
|
|
|
230 |
}
|
|
|
231 |
$r = $c->send($f);
|
|
|
232 |
if (!$r) {
|
|
|
233 |
return $this->raiseError("XML_RPC send failed");
|
|
|
234 |
}
|
|
|
235 |
$v = $r->value();
|
|
|
236 |
if ($e = $r->faultCode()) {
|
|
|
237 |
if ($e == $GLOBALS['XML_RPC_err']['http_error'] && strstr($r->faultString(), '304 Not Modified') !== false) {
|
|
|
238 |
return $this->cache['content'];
|
|
|
239 |
}
|
|
|
240 |
return $this->raiseError($r->faultString(), $e);
|
|
|
241 |
}
|
|
|
242 |
|
|
|
243 |
$result = XML_RPC_decode($v);
|
|
|
244 |
$this->saveCache($_args, $result);
|
|
|
245 |
return $result;
|
|
|
246 |
}
|
|
|
247 |
|
|
|
248 |
// }}}
|
|
|
249 |
|
|
|
250 |
// {{{ call_epi(method, [args...])
|
|
|
251 |
|
|
|
252 |
function call_epi($method)
|
|
|
253 |
{
|
|
|
254 |
if (!extension_loaded("xmlrpc")) {
|
|
|
255 |
return $this->raiseError("xmlrpc extension is not loaded");
|
|
|
256 |
}
|
|
|
257 |
$server_channel = $this->config->get('default_channel');
|
|
|
258 |
$channel = $this->_registry->getChannel($server_channel);
|
|
|
259 |
if (!PEAR::isError($channel)) {
|
|
|
260 |
$mirror = $this->config->get('preferred_mirror');
|
|
|
261 |
if ($channel->getMirror($mirror)) {
|
|
|
262 |
if ($channel->supports('xmlrpc', $method, $mirror)) {
|
|
|
263 |
$server_channel = $server_host = $mirror; // use the preferred mirror
|
|
|
264 |
$server_port = $channel->getPort($mirror);
|
|
|
265 |
} elseif (!$channel->supports('xmlrpc', $method)) {
|
|
|
266 |
return $this->raiseError("Channel $server_channel does not " .
|
|
|
267 |
"support xml-rpc method $method");
|
|
|
268 |
}
|
|
|
269 |
}
|
|
|
270 |
if (!isset($server_host)) {
|
|
|
271 |
if (!$channel->supports('xmlrpc', $method)) {
|
|
|
272 |
return $this->raiseError("Channel $server_channel does not support " .
|
|
|
273 |
"xml-rpc method $method");
|
|
|
274 |
} else {
|
|
|
275 |
$server_host = $server_channel;
|
|
|
276 |
$server_port = $channel->getPort();
|
|
|
277 |
}
|
|
|
278 |
}
|
|
|
279 |
} else {
|
|
|
280 |
return $this->raiseError("Unknown channel '$server_channel'");
|
|
|
281 |
}
|
|
|
282 |
$params = func_get_args();
|
|
|
283 |
array_shift($params);
|
|
|
284 |
$method = str_replace("_", ".", $method);
|
|
|
285 |
$request = xmlrpc_encode_request($method, $params);
|
|
|
286 |
if ($http_proxy = $this->config->get('http_proxy')) {
|
|
|
287 |
$proxy = parse_url($http_proxy);
|
|
|
288 |
$proxy_host = $proxy_port = $proxy_user = $proxy_pass = '';
|
|
|
289 |
$proxy_host = isset($proxy['host']) ? $proxy['host'] : null;
|
|
|
290 |
if (isset($proxy['scheme']) && $proxy['scheme'] == 'https') {
|
|
|
291 |
$proxy_host = 'https://' . $proxy_host;
|
|
|
292 |
}
|
|
|
293 |
$proxy_port = isset($proxy['port']) ? $proxy['port'] : null;
|
|
|
294 |
$proxy_user = isset($proxy['user']) ? urldecode($proxy['user']) : null;
|
|
|
295 |
$proxy_pass = isset($proxy['pass']) ? urldecode($proxy['pass']) : null;
|
|
|
296 |
$fp = @fsockopen($proxy_host, $proxy_port);
|
|
|
297 |
$use_proxy = true;
|
|
|
298 |
if ($channel->getSSL()) {
|
|
|
299 |
$server_host = "https://$server_host";
|
|
|
300 |
}
|
|
|
301 |
} else {
|
|
|
302 |
$use_proxy = false;
|
|
|
303 |
$ssl = $channel->getSSL();
|
|
|
304 |
$fp = @fsockopen(($ssl ? 'ssl://' : '') . $server_host, $server_port);
|
|
|
305 |
if (!$fp) {
|
|
|
306 |
$server_host = "$ssl$server_host"; // for error-reporting
|
|
|
307 |
}
|
|
|
308 |
}
|
|
|
309 |
if (!$fp && $http_proxy) {
|
|
|
310 |
return $this->raiseError("PEAR_Remote::call: fsockopen(`$proxy_host', $proxy_port) failed");
|
|
|
311 |
} elseif (!$fp) {
|
|
|
312 |
return $this->raiseError("PEAR_Remote::call: fsockopen(`$server_host', $server_port) failed");
|
|
|
313 |
}
|
|
|
314 |
$len = strlen($request);
|
|
|
315 |
$req_headers = "Host: $server_host:$server_port\r\n" .
|
|
|
316 |
"Content-type: text/xml\r\n" .
|
|
|
317 |
"Content-length: $len\r\n";
|
|
|
318 |
$username = $this->config->get('username');
|
|
|
319 |
$password = $this->config->get('password');
|
|
|
320 |
if ($username && $password) {
|
|
|
321 |
$req_headers .= "Cookie: PEAR_USER=$username; PEAR_PW=$password\r\n";
|
|
|
322 |
$tmp = base64_encode("$username:$password");
|
|
|
323 |
$req_headers .= "Authorization: Basic $tmp\r\n";
|
|
|
324 |
}
|
|
|
325 |
if ($this->cache !== null) {
|
|
|
326 |
$maxAge = '?maxAge='.$this->cache['lastChange'];
|
|
|
327 |
} else {
|
|
|
328 |
$maxAge = '';
|
|
|
329 |
}
|
|
|
330 |
|
|
|
331 |
if ($use_proxy && $proxy_host != '' && $proxy_user != '') {
|
|
|
332 |
$req_headers .= 'Proxy-Authorization: Basic '
|
|
|
333 |
.base64_encode($proxy_user.':'.$proxy_pass)
|
|
|
334 |
."\r\n";
|
|
|
335 |
}
|
|
|
336 |
|
|
|
337 |
if ($this->config->get('verbose') > 3) {
|
|
|
338 |
print "XMLRPC REQUEST HEADERS:\n";
|
|
|
339 |
var_dump($req_headers);
|
|
|
340 |
print "XMLRPC REQUEST BODY:\n";
|
|
|
341 |
var_dump($request);
|
|
|
342 |
}
|
|
|
343 |
|
|
|
344 |
if ($use_proxy && $proxy_host != '') {
|
|
|
345 |
$post_string = "POST http://".$server_host;
|
|
|
346 |
if ($proxy_port > '') {
|
|
|
347 |
$post_string .= ':'.$server_port;
|
|
|
348 |
}
|
|
|
349 |
} else {
|
|
|
350 |
$post_string = "POST ";
|
|
|
351 |
}
|
|
|
352 |
|
|
|
353 |
$path = '/' . $channel->getPath('xmlrpc');
|
|
|
354 |
fwrite($fp, ($post_string . $path . "$maxAge HTTP/1.0\r\n$req_headers\r\n$request"));
|
|
|
355 |
$response = '';
|
|
|
356 |
$line1 = fgets($fp, 2048);
|
|
|
357 |
if (!preg_match('!^HTTP/[0-9\.]+ (\d+) (.*)!', $line1, $matches)) {
|
|
|
358 |
return $this->raiseError("PEAR_Remote: invalid HTTP response from XML-RPC server");
|
|
|
359 |
}
|
|
|
360 |
switch ($matches[1]) {
|
|
|
361 |
case "200": // OK
|
|
|
362 |
break;
|
|
|
363 |
case "304": // Not Modified
|
|
|
364 |
return $this->cache['content'];
|
|
|
365 |
case "401": // Unauthorized
|
|
|
366 |
if ($username && $password) {
|
|
|
367 |
return $this->raiseError("PEAR_Remote ($server_host:$server_port) " .
|
|
|
368 |
": authorization failed", 401);
|
|
|
369 |
} else {
|
|
|
370 |
return $this->raiseError("PEAR_Remote ($server_host:$server_port) " .
|
|
|
371 |
": authorization required, please log in first", 401);
|
|
|
372 |
}
|
|
|
373 |
default:
|
|
|
374 |
return $this->raiseError("PEAR_Remote ($server_host:$server_port) : " .
|
|
|
375 |
"unexpected HTTP response", (int)$matches[1], null, null,
|
|
|
376 |
"$matches[1] $matches[2]");
|
|
|
377 |
}
|
|
|
378 |
while (trim(fgets($fp, 2048)) != ''); // skip rest of headers
|
|
|
379 |
while ($chunk = fread($fp, 10240)) {
|
|
|
380 |
$response .= $chunk;
|
|
|
381 |
}
|
|
|
382 |
fclose($fp);
|
|
|
383 |
if ($this->config->get('verbose') > 3) {
|
|
|
384 |
print "XMLRPC RESPONSE:\n";
|
|
|
385 |
var_dump($response);
|
|
|
386 |
}
|
|
|
387 |
$ret = xmlrpc_decode($response);
|
|
|
388 |
if (is_array($ret) && isset($ret['__PEAR_TYPE__'])) {
|
|
|
389 |
if ($ret['__PEAR_TYPE__'] == 'error') {
|
|
|
390 |
if (isset($ret['__PEAR_CLASS__'])) {
|
|
|
391 |
$class = $ret['__PEAR_CLASS__'];
|
|
|
392 |
} else {
|
|
|
393 |
$class = "PEAR_Error";
|
|
|
394 |
}
|
|
|
395 |
if ($ret['code'] === '') $ret['code'] = null;
|
|
|
396 |
if ($ret['message'] === '') $ret['message'] = null;
|
|
|
397 |
if ($ret['userinfo'] === '') $ret['userinfo'] = null;
|
|
|
398 |
if (strtolower($class) == 'db_error') {
|
|
|
399 |
$ret = $this->raiseError(PEAR::errorMessage($ret['code']),
|
|
|
400 |
$ret['code'], null, null,
|
|
|
401 |
$ret['userinfo']);
|
|
|
402 |
} else {
|
|
|
403 |
$ret = $this->raiseError($ret['message'], $ret['code'],
|
|
|
404 |
null, null, $ret['userinfo']);
|
|
|
405 |
}
|
|
|
406 |
}
|
|
|
407 |
} elseif (is_array($ret) && sizeof($ret) == 1 && isset($ret[0])
|
|
|
408 |
&& is_array($ret[0]) &&
|
|
|
409 |
!empty($ret[0]['faultString']) &&
|
|
|
410 |
!empty($ret[0]['faultCode'])) {
|
|
|
411 |
extract($ret[0]);
|
|
|
412 |
$faultString = "XML-RPC Server Fault: " .
|
|
|
413 |
str_replace("\n", " ", $faultString);
|
|
|
414 |
return $this->raiseError($faultString, $faultCode);
|
|
|
415 |
} elseif (is_array($ret) && sizeof($ret) == 2 && !empty($ret['faultString']) &&
|
|
|
416 |
!empty($ret['faultCode'])) {
|
|
|
417 |
extract($ret);
|
|
|
418 |
$faultString = "XML-RPC Server Fault: " .
|
|
|
419 |
str_replace("\n", " ", $faultString);
|
|
|
420 |
return $this->raiseError($faultString, $faultCode);
|
|
|
421 |
}
|
|
|
422 |
return $ret;
|
|
|
423 |
}
|
|
|
424 |
|
|
|
425 |
// }}}
|
|
|
426 |
|
|
|
427 |
// {{{ _encode
|
|
|
428 |
|
|
|
429 |
// a slightly extended version of XML_RPC_encode
|
|
|
430 |
function _encode($php_val)
|
|
|
431 |
{
|
|
|
432 |
global $XML_RPC_Boolean, $XML_RPC_Int, $XML_RPC_Double;
|
|
|
433 |
global $XML_RPC_String, $XML_RPC_Array, $XML_RPC_Struct;
|
|
|
434 |
|
|
|
435 |
$type = gettype($php_val);
|
|
|
436 |
$xmlrpcval = new XML_RPC_Value;
|
|
|
437 |
|
|
|
438 |
switch($type) {
|
|
|
439 |
case "array":
|
|
|
440 |
reset($php_val);
|
|
|
441 |
$firstkey = key($php_val);
|
|
|
442 |
end($php_val);
|
|
|
443 |
$lastkey = key($php_val);
|
|
|
444 |
reset($php_val);
|
|
|
445 |
if ($firstkey === 0 && is_int($lastkey) &&
|
|
|
446 |
($lastkey + 1) == count($php_val)) {
|
|
|
447 |
$is_continuous = true;
|
|
|
448 |
reset($php_val);
|
|
|
449 |
$size = count($php_val);
|
|
|
450 |
for ($expect = 0; $expect < $size; $expect++, next($php_val)) {
|
|
|
451 |
if (key($php_val) !== $expect) {
|
|
|
452 |
$is_continuous = false;
|
|
|
453 |
break;
|
|
|
454 |
}
|
|
|
455 |
}
|
|
|
456 |
if ($is_continuous) {
|
|
|
457 |
reset($php_val);
|
|
|
458 |
$arr = array();
|
|
|
459 |
while (list($k, $v) = each($php_val)) {
|
|
|
460 |
$arr[$k] = $this->_encode($v);
|
|
|
461 |
}
|
|
|
462 |
$xmlrpcval->addArray($arr);
|
|
|
463 |
break;
|
|
|
464 |
}
|
|
|
465 |
}
|
|
|
466 |
// fall though if not numerical and continuous
|
|
|
467 |
case "object":
|
|
|
468 |
$arr = array();
|
|
|
469 |
while (list($k, $v) = each($php_val)) {
|
|
|
470 |
$arr[$k] = $this->_encode($v);
|
|
|
471 |
}
|
|
|
472 |
$xmlrpcval->addStruct($arr);
|
|
|
473 |
break;
|
|
|
474 |
case "integer":
|
|
|
475 |
$xmlrpcval->addScalar($php_val, $XML_RPC_Int);
|
|
|
476 |
break;
|
|
|
477 |
case "double":
|
|
|
478 |
$xmlrpcval->addScalar($php_val, $XML_RPC_Double);
|
|
|
479 |
break;
|
|
|
480 |
case "string":
|
|
|
481 |
case "NULL":
|
|
|
482 |
$xmlrpcval->addScalar($php_val, $XML_RPC_String);
|
|
|
483 |
break;
|
|
|
484 |
case "boolean":
|
|
|
485 |
$xmlrpcval->addScalar($php_val, $XML_RPC_Boolean);
|
|
|
486 |
break;
|
|
|
487 |
case "unknown type":
|
|
|
488 |
default:
|
|
|
489 |
return null;
|
|
|
490 |
}
|
|
|
491 |
return $xmlrpcval;
|
|
|
492 |
}
|
|
|
493 |
|
|
|
494 |
// }}}
|
|
|
495 |
|
|
|
496 |
}
|
|
|
497 |
|
|
|
498 |
?>
|