/** *send a query to the CouchDB server * * In a continuous query, the server send headers, and then a JSON object per line. * On each line received, the $callable callback is fired, with two arguments : * * - the JSON object decoded as a PHP object * * - a couchClient instance to use to make queries inside the callback * * If the callable returns the boolean FALSE , continuous reading stops. * * @param callable $callable PHP function name / callable array ( see http://php.net/is_callable ) * @param string $method HTTP method to use (GET, POST, ...) * @param string $url URL to fetch * @param array $parameters additionnal parameters to send with the request * @param string|array|object $data request body * * @return string|false server response on success, false on error */ public function continuousQuery($callable, $method, $url, $parameters = array(), $data = null) { if (!in_array($method, $this->HTTP_METHODS)) { throw new Exception("Bad HTTP method: {$method}"); } if (!is_callable($callable)) { throw new InvalidArgumentException("callable argument have to success to is_callable PHP function"); } if (is_array($parameters) and count($parameters)) { $url = $url . '?' . http_build_query($parameters); } //Send the request to the socket $request = $this->_socket_buildRequest($method, $url, $data, null); if (!$this->_connect()) { return FALSE; } fwrite($this->socket, $request); //Read the headers and check that the response is valid $response = ''; $code = 0; $headers = false; while (!feof($this->socket) && !$headers) { $response .= fgets($this->socket); if ($response == "HTTP/1.1 100 Continue\r\n\r\n") { $response = ''; continue; } elseif (preg_match("/\r\n\r\n\$/", $response)) { $headers = true; } } $headers = explode("\n", trim($response)); $split = explode(" ", trim(reset($headers))); $code = $split[1]; unset($split); //If an invalid response is sent, read the rest of the response and throw an appropriate couchException if (!in_array($code, array(200, 201))) { stream_set_blocking($this->socket, false); $response .= stream_get_contents($this->socket); fclose($this->socket); throw couchException::factory($response, $method, $url, $parameters); } //For as long as the socket is open, read lines and pass them to the callback $c = clone $this; while ($this->socket && !feof($this->socket)) { $e = NULL; $e2 = NULL; $read = array($this->socket); if (false === ($num_changed_streams = stream_select($read, $e, $e2, 1))) { $this->socket = null; } elseif ($num_changed_streams > 0) { $line = fgets($this->socket); if (strlen(trim($line))) { $break = call_user_func($callable, json_decode($line), $c); if ($break === FALSE) { fclose($this->socket); } } } } return $code; }
/** * helper method to execute the following algorithm : * * query the couchdb server * test the status_code * return the response body on success, throw an exception on failure * * @param string $method HTTP method (GET, POST, ...) * @param string $url URL to fetch * @param $array $allowed_status_code the list of HTTP response status codes that prove a successful request * @param array $parameters additionnal parameters to send with the request * @param string|object|array $data the request body. If it's an array or an object, $data is json_encode()d * @param string $content_type set the content-type of the request */ protected function _queryAndTest($method, $url, $allowed_status_codes, $parameters = array(), $data = NULL, $content_type = NULL) { $raw = $this->query($method, $url, $parameters, $data, $content_type); $response = $this->parseRawResponse($raw, $this->results_as_array); $this->results_as_array = $this->default_as_array; if (in_array($response['status_code'], $allowed_status_codes)) { return $response['body']; } throw couchException::factory($response, $method, $url, $parameters); return FALSE; }