Esempio n. 1
0
File: call.php Progetto: rair/yacs
 /**
  * call a web service
  *
  * This function supports following protocols, as specified in last parameter:
  * - 'XML-RPC' - request and response are XML snippets
  * - 'JSON-RPC' - request and response are JSON snippets
  *
  * Minimum example:
  * [php]
  * $result = Call::invoke($url, $method);
  * if(!$result[0])
  *	echo $result[1]; // error message
  * else
  *	... // use call result from $result[1]
  * [/php]
  *
  * Note that in a previous version data was encoded.
  * Unfortunately, most servers do not handle encoding, despite it's a useful web standard.
  *
  * @param string the url to use
  * @param string the service to call
  * @param array the parameters to transmit
  * @param string the protocol to use
  * @return an array of which the first value indicates call success or failure
  *
  * @see control/scan.php
  * @see links/links.php
  * @see servers/servers.php
  * @see services/blog_test.php
  */
 public static function invoke($url, $service, $parameters = NULL, $variant = 'XML-RPC')
 {
     global $context;
     // submit a raw request
     $raw_request = FALSE;
     if ($variant == 'raw') {
         $raw_request = TRUE;
         $variant = 'XML-RPC';
     }
     // select a codec handler
     include_once $context['path_to_root'] . 'services/codec.php';
     $codec = Codec::initialize($variant);
     if (!is_object($codec)) {
         return array(FALSE, 'Do not know how to cope with API ' . $variant);
     }
     // adjust content type
     if ($variant == 'JSON-RPC') {
         $headers = 'Content-Type: application/json' . CRLF;
     } else {
         $headers = 'Content-Type: text/xml' . CRLF;
     }
     // build the request
     if ($raw_request) {
         $result = array(TRUE, $parameters);
     } else {
         $result = $codec->export_request($service, $parameters);
     }
     if (!$result[0]) {
         return array(FALSE, $result[1]);
     }
     $headers .= 'Content-Length: ' . strlen($result[1]) . CRLF;
     // parse the target URL
     $items = @parse_url($url);
     // no host, assume it's us
     if (!isset($items['host']) || !($host = $items['host'])) {
         $host = $context['host_name'];
     }
     // no port, assume the standard
     if (!isset($items['port']) || !($port = $items['port'])) {
         $port = 80;
     }
     // outbound web is not authorized
     if (isset($context['without_outbound_http']) && $context['without_outbound_http'] == 'Y') {
         return array(FALSE, 'Outbound HTTP is not authorized.');
     }
     // connect to the server
     if (!($handle = Safe::fsockopen($host, $port, $errno, $errstr, 30))) {
         return array(FALSE, sprintf('Impossible to connect to %s.', $host . ':' . $port));
     }
     // ensure enough execution time
     Safe::set_time_limit(30);
     // build the path, including any query
     $path = $items['path'];
     if (!$path) {
         $path = '/';
     }
     if (isset($items['query']) && $items['query']) {
         $path .= '?' . $items['query'];
     }
     // build an HTTP request
     $request = "POST " . $path . " HTTP/1.0" . CRLF . 'Host: ' . $host . CRLF . "Accept-Encoding: gzip" . CRLF . "User-Agent: YACS (www.yacs.fr)" . CRLF . "Connection: close" . CRLF . $headers . CRLF . $result[1];
     // save the request if debug mode
     if (isset($context['debug_call']) && $context['debug_call'] == 'Y') {
         Logger::remember('services/call.php: Call::invoke() request', str_replace("\r\n", "\n", $request), 'debug');
     }
     // submit the request
     fputs($handle, $request);
     // get everything by Ethernet-sized chunks
     $response = '';
     while (!feof($handle) && strlen($response) < 5242880) {
         $response .= fread($handle, 1500);
     }
     fclose($handle);
     // ensure we have a valid HTTP status line
     if (preg_match('/^HTTP/', $response) && !preg_match('/^HTTP\\/[0-9\\.]+ 200 /', $response)) {
         $lines = explode("\n", $response, 2);
         return array(FALSE, 'Unexpected HTTP status "' . $lines[0] . '"');
     }
     // separate headers from body
     list($headers, $content) = explode(CRLF . CRLF, $response, 2);
     // uncompress payload if necessary
     if (preg_match('/Content-Encoding: \\s*gzip/i', $headers)) {
         $content = gzinflate(substr($content, 10));
     }
     // save the response if debug mode
     if (isset($context['debug_call']) && $context['debug_call'] == 'Y') {
         Logger::remember('services/call.php: Call::invoke() response', str_replace("\r\n", "\n", $headers . "\n\n" . $content), 'debug');
     }
     // decode the result
     return $codec->import_response($content, $headers, $parameters);
 }