Ejemplo n.º 1
0
 /**
  * Perform a request to the server and return the result
  *
  * Perform a request to the server and return the result converted into a
  * phpillowResponse object. If you do not expect a JSON structure, which
  * could be converted in such a response object, set the forth parameter to
  * true, and you get a response object retuerned, containing the raw body.
  *
  * @param string $method
  * @param string $path
  * @param string $data
  * @return phpillowResponse
  */
 protected function request($method, $path, $data, $raw = false)
 {
     $basicAuth = '';
     if ($this->options['username']) {
         $basicAuth .= "{$this->options['username']}:{$this->options['password']}@";
     }
     $url = 'http://' . $basicAuth . $this->options['host'] . ':' . $this->options['port'] . $path;
     $httpFilePointer = @fopen($url = 'http://' . $this->options['host'] . ':' . $this->options['port'] . $path, 'r', false, stream_context_create(array('http' => array('method' => $method, 'content' => $data, 'ignore_errors' => true, 'user_agent' => 'PHPillow arbit-0.5-alpha', 'timeout' => $this->options['timeout'], 'header' => 'Content-type: application/json'))));
     // Check if connection has been established successfully
     if ($httpFilePointer === false) {
         $error = error_get_last();
         throw new phpillowConnectionException("Could not connect to server at %ip:%port: %error", array('ip' => $this->options['ip'], 'port' => $this->options['port'], 'error' => $error['message']));
     }
     // Read request body
     $body = '';
     while (!feof($httpFilePointer)) {
         $body .= fgets($httpFilePointer);
     }
     $metaData = stream_get_meta_data($httpFilePointer);
     // @TODO: This seems to have changed in last CVS versions of PHP 5.3,
     // should be removeable, once there is a next release of PHP 5.3
     $rawHeaders = isset($metaData['wrapper_data']['headers']) ? $metaData['wrapper_data']['headers'] : $metaData['wrapper_data'];
     $headers = array();
     foreach ($rawHeaders as $lineContent) {
         // Extract header values
         if (preg_match('(^HTTP/(?P<version>\\d+\\.\\d+)\\s+(?P<status>\\d+))S', $lineContent, $match)) {
             $headers['version'] = $match['version'];
             $headers['status'] = (int) $match['status'];
         } else {
             list($key, $value) = explode(':', $lineContent, 2);
             $headers[strtolower($key)] = ltrim($value);
         }
     }
     // If requested log response information to http log
     if ($this->options['http-log'] !== false) {
         file_put_contents($this->options['http-log'], sprintf("Requested: %s\n\n%s\n\n%s\n\n", $url, implode("\n", $rawHeaders), $body));
     }
     // Create repsonse object from couch db response
     return phpillowResponseFactory::parse($headers, $body, $raw);
 }
Ejemplo n.º 2
0
 /**
  * Perform a request to the server and return the result
  *
  * Perform a request to the server and return the result converted into a
  * phpillowResponse object. If you do not expect a JSON structure, which
  * could be converted in such a response object, set the forth parameter to
  * true, and you get a response object returned, containing the raw body.
  *
  * @param string $method
  * @param string $path
  * @param string $data
  * @param bool $raw
  * @return phpillowResponse
  */
 protected function request($method, $path, $data, $raw = false)
 {
     // Try establishing the connection to the server
     $this->checkConnection();
     // Send the build request to the server
     if (fwrite($this->connection, $request = $this->buildRequest($method, $path, $data)) === false) {
         // Reestablish which seems to have been aborted
         //
         // The recursion in this method might be problematic if the
         // connection establishing mechanism does not correctly throw an
         // exception on failure.
         $this->connection = null;
         return $this->request($method, $path, $data, $raw);
     }
     // If requested log request information to http log
     if ($this->options['http-log'] !== false) {
         $fp = fopen($this->options['http-log'], 'a');
         fwrite($fp, "\n\n" . $request);
     }
     // Read server response headers
     $rawHeaders = '';
     $headers = array('connection' => $this->options['keep-alive'] ? 'Keep-Alive' : 'Close');
     // Remove leading newlines, should not occur at all, actually.
     while (($line = fgets($this->connection)) !== false && ($lineContent = rtrim($line)) === '') {
     }
     // Throw exception, if connection has been aborted by the server, and
     // leave handling to the user for now.
     if ($line === false) {
         // Reestablish which seems to have been aborted
         //
         // The recursion in this method might be problematic if the
         // connection establishing mechanism does not correctly throw an
         // exception on failure.
         //
         // An aborted connection seems to happen here on long running
         // requests, which cause a connection timeout at server side.
         $this->connection = null;
         return $this->request($method, $path, $data, $raw);
     }
     do {
         // Also store raw headers for later logging
         $rawHeaders .= $lineContent . "\n";
         // Extract header values
         if (preg_match('(^HTTP/(?P<version>\\d+\\.\\d+)\\s+(?P<status>\\d+))S', $lineContent, $match)) {
             $headers['version'] = $match['version'];
             $headers['status'] = (int) $match['status'];
         } else {
             list($key, $value) = explode(':', $lineContent, 2);
             $headers[strtolower($key)] = ltrim($value);
         }
     } while (($line = fgets($this->connection)) !== false && ($lineContent = rtrim($line)) !== '');
     // Read response body
     $body = '';
     if (!isset($headers['transfer-encoding']) || $headers['transfer-encoding'] !== 'chunked') {
         // HTTP 1.1 supports chunked transfer encoding, if the according
         // header is not set, just read the specified amount of bytes.
         $bytesToRead = (int) (isset($headers['content-length']) ? $headers['content-length'] : 0);
         // Read body only as specified by chunk sizes, everything else
         // are just footnotes, which are not relevant for us.
         while ($bytesToRead > 0) {
             $body .= $read = fgets($this->connection, $bytesToRead + 1);
             $bytesToRead -= strlen($read);
         }
     } else {
         // When transfer-encoding=chunked has been specified in the
         // response headers, read all chunks and sum them up to the body,
         // until the server has finished. Ignore all additional HTTP
         // options after that.
         do {
             $line = rtrim(fgets($this->connection));
             // Get bytes to read, with option appending comment
             if (preg_match('(^([0-9a-f]+)(?:;.*)?$)', $line, $match)) {
                 $bytesToRead = hexdec($match[1]);
                 // Read body only as specified by chunk sizes, everything else
                 // are just footnotes, which are not relevant for us.
                 $bytesLeft = $bytesToRead;
                 while ($bytesLeft > 0) {
                     $body .= $read = fread($this->connection, $bytesLeft + 2);
                     $bytesLeft -= strlen($read);
                 }
             }
         } while ($bytesToRead > 0);
         // Chop off \r\n from the end.
         $body = substr($body, 0, -2);
     }
     // Reset the connection if the server asks for it.
     if ($headers['connection'] !== 'Keep-Alive') {
         fclose($this->connection);
         $this->connection = null;
     }
     // If requested log response information to http log
     if ($this->options['http-log'] !== false) {
         fwrite($fp, "\n" . $rawHeaders . "\n" . $body . "\n");
         fclose($fp);
     }
     // Handle some response state as special cases
     switch ($headers['status']) {
         case 301:
         case 302:
         case 303:
         case 307:
             $path = parse_url($headers['location'], PHP_URL_PATH);
             return $this->request('GET', $path, $data, $raw);
     }
     // Create response object from couch db response
     return phpillowResponseFactory::parse($headers, $body, $raw);
 }