diff --git a/Request.inc.php b/Request.inc.php index 6d2314f..84b3119 100644 --- a/Request.inc.php +++ b/Request.inc.php @@ -2,7 +2,10 @@ namespace wellrested; -require_once(dirname(__FILE__) . '/Response.inc.php'); +require_once(dirname(__FILE__) . '/Response.inc.php'); +require_once(dirname(__FILE__) . '/exceptions/CurlException.inc.php'); + +// !TODO: Include port in the URI /** * A Request instance contains information relating to the current HTTP request @@ -14,10 +17,12 @@ require_once(dirname(__FILE__) . '/Response.inc.php'); * * @property string body Entity body of the request * @property array headers Associative array of HTTP headers + * @property array hostname The Hostname for the request (e.g., google.com) * @property string method HTTP method or verb for the request * @property string path Path component of the URI for the request * @property string pathParts Fragments of the path, delimited by slashes * @property array query Associative array of query parameters + * @property array uri Full URI, including protocol, hostname, path, and query * * @package WellRESTed */ @@ -49,7 +54,7 @@ class Request { * * @var string */ - protected $method; + protected $method = 'GET'; /** * Path component of the URI for the request @@ -166,38 +171,83 @@ class Request { } + /** + * Return the body payload of the instance. + * + * @return string + */ public function getBody() { return $this->body; } + /** + * Return an associative array of all set headers. + * + * @return array + */ public function getHeaders() { return $this->headers; } + /** + * Return the hostname set for the instance. + * + * @return array + */ public function getHostname() { return $this->hostname; } + /** + * Return the HTTP method (e.g., GET, POST, PUT, DELETE) + * + * @return string + */ public function getMethod() { return $this->method; } + /** + * Return the protocol (e.g., http, https) + * + * @return string + */ public function getProtocol() { - return $this->rotocol; + return $this->protocol; } + /** + * Return the path part of the URI as a string. + * + * @return string + */ public function getPath() { return $this->path; } + /** + * Return an array of the sections of the path delimited by slashes. + * + * @return array + */ public function getPathParts() { return $this->pathParts; } + /** + * Return an associative array representing the query. + * + * @return array + */ public function getQuery() { return $this->query; } + /** + * Return the full URI includeing protocol, hostname, path, and query. + * + * @return array + */ public function getUri() { // Construct the URI if it is unset. @@ -217,7 +267,6 @@ class Request { $this->body = $body; } - /** * Set the hostname for the request and update the URI. * @@ -320,7 +369,6 @@ class Request { } - /** * Build the URI member from the other members (path, query, etc.) */ @@ -336,15 +384,28 @@ class Request { } - // ------------------------------------------------------------------------- + /** + * Make a cURL request out of the instance and return a Response. + * + * @return Response + * @throws exceptions\CurlException + */ public function request() { $ch = curl_init(); + + // Set the URL. curl_setopt($ch, CURLOPT_URL, $this->uri); + + // Include headers in the response. + curl_setopt($ch, CURLOPT_HEADER, 1); + + // Return the response from curl_exec(). curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); + // Set the method. Include the body, if needed. switch ($this->method) { case 'GET': @@ -368,20 +429,35 @@ class Request { } + // Make the cURL request. $result = curl_exec($ch); - $resp = new Response(); - - if ($result !== false) { - - $resp->body = $result; - $resp->statusCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); - - // TODO: Read headers - + // Throw an exception in the event of a cURL error. + if ($result === false) { + $error = curl_error($ch); + $errno = curl_errno($ch); + curl_close($ch); + throw new exceptions\CurlException($error, $errno); } - // TODO: Account for error + // Make a reponse to populate and return with data obtained via cURL. + $resp = new Response(); + + $resp->statusCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); + + // Split the result into headers and body. + list ($headers, $body) = explode("\r\n\r\n", $result, 2); + + // Set the body. Do not auto-add the Content-length header. + $resp->setBody($body, false); + + // Iterate over the headers line by line and add each one. + foreach (explode("\r\n", $headers) as $header) { + if (strpos($header, ':')) { + list ($headerName, $headerValue) = explode(':', $header, 2); + $resp->setHeader($headerName, ltrim($headerValue)); + } + } curl_close($ch); @@ -394,13 +470,13 @@ class Request { */ public function readHttpRequest() { - $this->body = file_get_contents("php://input"); + $this->setBody(file_get_contents("php://input"), false); $this->headers = apache_request_headers(); $this->method = $_SERVER['REQUEST_METHOD']; $this->uri = $_SERVER['REQUEST_URI']; $this->hostname = $_SERVER['HTTP_HOST']; - } // readHttpRequest() + } /** * Return a reference to the singleton instance of the Request derived @@ -409,7 +485,7 @@ class Request { * @return Request * @static */ - static public function getRequest() { + public static function getRequest() { if (!isset(self::$theRequest)) { @@ -423,7 +499,7 @@ class Request { return self::$theRequest; - } // getRequest() + } } // Request diff --git a/samples/client-side-endpoint.php b/samples/client-side-endpoint.php new file mode 100644 index 0000000..cef446f --- /dev/null +++ b/samples/client-side-endpoint.php @@ -0,0 +1,21 @@ +statusCode = 200; +$resp->setHeader('Content-Type', 'text/plain'); +$resp->setHeader('User-Agent', 'Well RESTed'); +$resp->body = 'The test works!'; +$resp->respond(); +exit; + +?> diff --git a/samples/client-side-request-and-response.php b/samples/client-side-request-and-response.php index 2996325..160d54d 100644 --- a/samples/client-side-request-and-response.php +++ b/samples/client-side-request-and-response.php @@ -5,26 +5,54 @@ * * This script will build a request to an external server, issue the request, * then read the reponse returned by the server. + * + * Please modify samples/client-side-endpoint.php to see results. */ // Include the Well RESTed Request and Response class files. require_once('../Request.inc.php'); require_once('../Response.inc.php'); +// Get a Request instance describing the request made to this script. $thisRequest = \wellrested\Request::getRequest(); // Create a new empty request. $rqst = new \wellrested\Request(); - -// Set some of the information for it. $rqst->hostname = $thisRequest->hostname; -$rqst->path = '/wellrested/samples/server-side-request-and-response.php'; -$rqst->method = 'PUT'; -$rqst->body = 'This is the body'; +$rqst->path = '/wellrested/samples/client-side-endpoint.php'; -$resp = $rqst->request(); +// Uncomment this to get a cURL exception. +//$rqst->uri = 'http://not-a-real.domain'; -print 'Response code: ' . $resp->statusCode . "\n"; -print 'Response body: ' . $resp->body . "\n"; +// Issue the request, and read the response returned by the server. +try { + $resp = $rqst->request(); +} catch (\wellrested\exceptions\CurlException $e) { + + // Create new response to send to output to the browser. + $myResponse = new \wellrested\Response(); + $myResponse->statusCode = 500; + $myResponse->setHeader('Content-Type', 'text/plain'); + $myResponse->body = 'Message: ' .$e->getMessage() ."\n"; + $myResponse->body .= 'Code: ' . $e->getCode() . "\n"; + $myResponse->respond(); + exit; + +} + +// Create new response to send to output to the browser. +$myResponse = new \wellrested\Response(); +$myResponse->statusCode = 200; +$myResponse->setHeader('Content-Type', 'application/json'); + +$json = array( + 'Status Code' => $resp->statusCode, + 'Body' => $resp->body, + 'Headers' => $resp->headers +); +$myResponse->body = json_encode($json); + +$myResponse->respond(); +exit; ?> \ No newline at end of file