[ Index ] |
|
Code source de PHP PEAR 1.4.5 |
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.0 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 ?>
titre
Description
Corps
titre
Description
Corps
titre
Description
Corps
titre
Corps
Généré le : Sun Feb 25 14:08:00 2007 | par Balluche grâce à PHPXref 0.7 |