|
@@ -1,7 +1,21 @@
|
|
|
<?php namespace Lib;
|
|
|
|
|
|
+/**
|
|
|
+ * Defines an unexpected response.
|
|
|
+ *
|
|
|
+ * @author Joachim M. Giaever (joachim[]giaever.org)
|
|
|
+ * @package curl
|
|
|
+ * @version 0.1
|
|
|
+ */
|
|
|
class HTTPUnexpectedResponse extends \Exception {
|
|
|
+ /**
|
|
|
+ * Includes valid codes, as a valid code can also be unexpeted.
|
|
|
+ *
|
|
|
+ * @var array $ecode HTTP status codes
|
|
|
+ * @static
|
|
|
+ */
|
|
|
static $ecode = array(
|
|
|
+ 0 => "Unknown error",
|
|
|
100 => 'Continue',
|
|
|
101 => 'Switching Protocols',
|
|
|
102 => 'Processing', // WebDAV; RFC 2518
|
|
@@ -81,46 +95,120 @@ class HTTPUnexpectedResponse extends \Exception {
|
|
|
599 => 'Network connect timeout error', // Unknown
|
|
|
);
|
|
|
|
|
|
+ /**
|
|
|
+ * The response from server (body)
|
|
|
+ * @access private
|
|
|
+ */
|
|
|
private $response;
|
|
|
|
|
|
- public function __construct($message, $code = 0, Exception $previous = null) {
|
|
|
+ /**
|
|
|
+ * Sets the exceptions.
|
|
|
+ *
|
|
|
+ * @string $message - the response from the server.
|
|
|
+ * @string $code - the HTTP status code.
|
|
|
+ * @exception $prev - Previous exceptions
|
|
|
+ **/
|
|
|
+ public function __construct(string $message, int $code = 0, Exception $previous = null) {
|
|
|
$this->response = $message;
|
|
|
parent::__construct(HTTPUnexpectedResponse::$ecode[$code], $code, $previous);
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * Visual representation of the exception.
|
|
|
+ *
|
|
|
+ * @return string
|
|
|
+ */
|
|
|
public function __toString() {
|
|
|
return __CLASS__ . ": [{$this->code} | {$this->message}]: {$this->response}\n";
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * Get the actual response from the body or the request.
|
|
|
+ *
|
|
|
+ * @return string
|
|
|
+ */
|
|
|
public function getResponse() {
|
|
|
return $this->response;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * When the request fails because of an unauthorized token,
|
|
|
+ * this is thrown instead.
|
|
|
+ *
|
|
|
+ * @author Joachim M. Giaever (joachim[]giaever.org)
|
|
|
+ * @package curl
|
|
|
+ * @version 0.1
|
|
|
+ */
|
|
|
class NotAuthorizedException extends HTTPUnexpectedResponse {
|
|
|
- public function __construct($message, Exception $previous = null) {
|
|
|
- parent::__contruct($message, 401, $previous);
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Sets the exceptions.
|
|
|
+ *
|
|
|
+ * @string $message - the response from the server.
|
|
|
+ * @string $code - the HTTP status code, @default 401
|
|
|
+ * @exception $prev - Previous exceptions
|
|
|
+ **/
|
|
|
+ public function __construct($message, $code = 401, Exception $previous = null) {
|
|
|
+ parent::__construct($message, $code, $previous);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * A trait used for every class referencing the api-url and token.
|
|
|
+ *
|
|
|
+ * @author Joachim M. Giaever (joachim[]giaever.org)
|
|
|
+ * @package curl
|
|
|
+ * @version 0.1
|
|
|
+ */
|
|
|
trait Curl {
|
|
|
protected $url;
|
|
|
protected $token;
|
|
|
|
|
|
- protected $user_agent = "Gogs PHP Api Client/0.0 (compatible; LINUX)";
|
|
|
+ // TODO: Change this to something!
|
|
|
+ protected $user_agent = "Gogs PHP Api Client/0.1 (compatible; LINUX)";
|
|
|
protected $timeout = 30;
|
|
|
protected $max_redirects = 4;
|
|
|
|
|
|
+ /**
|
|
|
+ * array_2_params takes an array and converts it into a
|
|
|
+ * query string (e.g param=val¶m2=val2).
|
|
|
+ *
|
|
|
+ * @param array $params parameters to pass
|
|
|
+ * @return string
|
|
|
+ */
|
|
|
private function array_2_params(array $params) {
|
|
|
return join("&", array_map(function($k, $v) {
|
|
|
return sprintf("%s=%s", $k, rawurlencode(is_bool($v) ? ($v ? "true" : "false") : $v ));
|
|
|
}, array_keys($params), $params));
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * array_2_json takes an array and converts it into a
|
|
|
+ * json-string (e.g {'name': 'This'}) which is typically
|
|
|
+ * used in a request body.
|
|
|
+ *
|
|
|
+ * @param array $params paramters to pass
|
|
|
+ * @return string
|
|
|
+ */
|
|
|
private function array_2_json(array $params) {
|
|
|
- return json_encode($params);
|
|
|
+ return count($params) == 0 ? null : json_encode($params);
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * Initializes a curl request of different kinds, depending
|
|
|
+ * on the specified method. This can be
|
|
|
+ *
|
|
|
+ * DELETE, PATCH, POST or GET. An unidentified value will
|
|
|
+ * become a GET-request.
|
|
|
+ *
|
|
|
+ * @param string $method either DELETE, PATCH, POST, GET
|
|
|
+ * @param string &$req variable to store request body in
|
|
|
+ * @param string $scope scope within the API (e.g /user/repos)
|
|
|
+ * @param array $params parameters to pass
|
|
|
+ * @param bool $ret return transfer
|
|
|
+ * @return int the status code
|
|
|
+ */
|
|
|
protected function method(string $method, string &$req, string $scope, array $params, bool $ret) {
|
|
|
$c = curl_init();
|
|
|
|
|
@@ -134,24 +222,22 @@ trait Curl {
|
|
|
|
|
|
$url = sprintf("%s%s", $this->url, $scope);
|
|
|
|
|
|
+ echo sprintf("%s: %s, params: %s\n", $method, $url, $this->array_2_json($params));
|
|
|
+
|
|
|
if (in_array($method, array("DELETE", "PATCH", "POST"))) {
|
|
|
$json = $this->array_2_json($params);
|
|
|
curl_setopt($c, CURLOPT_CUSTOMREQUEST, $method);
|
|
|
curl_setopt($c, CURLOPT_POSTFIELDS, $json);
|
|
|
- echo sprintf("JSON: %s", $json);
|
|
|
array_unshift($headers, "Content-Type: application/json");
|
|
|
array_push($headers, "Content-Length: " . strlen($json));
|
|
|
- var_dump($headers);
|
|
|
} else {
|
|
|
$url .= "?" . $this->array_2_params($params);
|
|
|
}
|
|
|
|
|
|
- echo sprintf("%s: %s\n", $method, $url);
|
|
|
-
|
|
|
curl_setopt($c, CURLOPT_USERAGENT, $this->user_agent);
|
|
|
curl_setopt($c, CURLOPT_URL, $url);
|
|
|
curl_setopt($c, CURLOPT_HTTPHEADER, $headers);
|
|
|
- curl_setopt($c, CURLOPT_RETURNTRANSFER, true);
|
|
|
+ curl_setopt($c, CURLOPT_RETURNTRANSFER, $ret);
|
|
|
curl_setopt($c, CURLOPT_TIMEOUT, $this->timeout);
|
|
|
curl_setopt($c, CURLOPT_MAXREDIRS, $this->max_redirects);
|
|
|
curl_setopt($c, CURLOPT_FOLLOWLOCATION, true);
|
|
@@ -165,7 +251,18 @@ trait Curl {
|
|
|
return $status_code;
|
|
|
}
|
|
|
|
|
|
- protected function authorized($scope) {
|
|
|
+ /**
|
|
|
+ * Checks if the user is authorized for the scope. Shouldn't
|
|
|
+ * be used frequently. One test for one scope should be enough,
|
|
|
+ * but if you know for sure thats you're programming with the
|
|
|
+ * use of an authorized user you should leave this and just
|
|
|
+ * handle the NotAuthorizedExeption whenever thrown.
|
|
|
+ *
|
|
|
+ * @param $scope the scope, a relative uri.
|
|
|
+ * @throws Not AuthorizedException if server responde with a 401
|
|
|
+ * @return bool
|
|
|
+ */
|
|
|
+ protected function authorized(string $scope = "") {
|
|
|
$ret = "";
|
|
|
if ($this->method("GET", $ret, $scope, array(), false) == 401) {
|
|
|
throw new NotAuthorizedException("Not authorized", 401);
|
|
@@ -173,7 +270,16 @@ trait Curl {
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
- private function post($scope = "", $params = array()) {
|
|
|
+ /**
|
|
|
+ * Post method.
|
|
|
+ *
|
|
|
+ * @param string $scope the scope, a relative uri.
|
|
|
+ * @param array $params the parameters to post.
|
|
|
+ * @throws NotAuthorizedException on 401, 403
|
|
|
+ * @throws HTTPUnexpectedResponse when not 200,201,401,403
|
|
|
+ * @return string the request content.
|
|
|
+ */
|
|
|
+ private function post(string $scope = "", array $params = array()) {
|
|
|
$req = "";
|
|
|
|
|
|
$code = $this->method("POST", $req, $scope, $params, true);
|
|
@@ -183,13 +289,22 @@ trait Curl {
|
|
|
case 201:
|
|
|
return $req;
|
|
|
case 401:
|
|
|
- throw new NotAuthorizedException($req);
|
|
|
+ case 403:
|
|
|
+ throw new NotAuthorizedException($req, $code);
|
|
|
default:
|
|
|
throw new HTTPUnexpectedResponse($req, $code);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- private function delete($scope = "") {
|
|
|
+ /**
|
|
|
+ * Delete method.
|
|
|
+ *
|
|
|
+ * @param string $scope the scope, a relative uri.
|
|
|
+ * @throws NotAuthorizedException on 401, 403
|
|
|
+ * @throws HTTPUnexpectedResponse when not 200,204,401,403
|
|
|
+ * @return string the request content.
|
|
|
+ */
|
|
|
+ private function delete(string $scope = "") {
|
|
|
$req = "";
|
|
|
|
|
|
$code = $this->method("DELETE", $req, $scope, array(), true);
|
|
@@ -199,12 +314,22 @@ trait Curl {
|
|
|
case 204:
|
|
|
return $req;
|
|
|
case 401:
|
|
|
- throw new NotAuthorizedException($req);
|
|
|
+ case 403:
|
|
|
+ throw new NotAuthorizedException($req, $code);
|
|
|
default:
|
|
|
throw new HTTPUnexpectedResponse($req, $code);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * GET method.
|
|
|
+ *
|
|
|
+ * @param string $scope the scope, a relative uri.
|
|
|
+ * @param array $params the parameters to post.
|
|
|
+ * @throws NotAuthorizedException on 401, 403
|
|
|
+ * @throws HTTPUnexpectedResponse when not 200,401,403
|
|
|
+ * @return string the request content.
|
|
|
+ */
|
|
|
private function get($scope = "", $params = array()) {
|
|
|
$req = "";
|
|
|
|
|
@@ -214,7 +339,8 @@ trait Curl {
|
|
|
case 200:
|
|
|
return $req;
|
|
|
case 401:
|
|
|
- throw new NotAuthorizedException($req);
|
|
|
+ case 403:
|
|
|
+ throw new NotAuthorizedException($req, $code);
|
|
|
default:
|
|
|
throw new HTTPUnexpectedResponse($req, $code);
|
|
|
|