public static function request($method, $url, $attributes = array(), $options = array()) { $podio = Podio::FromSession(); if (!$podio || !$podio->ch) { throw new Exception('Client has not been setup with client id and client secret.'); } // Reset attributes so we can reuse curl object curl_setopt($podio->ch, CURLOPT_POSTFIELDS, null); unset($podio->headers['Content-length']); $original_url = $url; $encoded_attributes = null; if (is_object($attributes) && substr(get_class($attributes), 0, 5) == 'Podio') { $attributes = $attributes->as_json(false); } if (!is_array($attributes) && !is_object($attributes)) { throw new PodioDataIntegrityError('Attributes must be an array'); } switch ($method) { case self::GET: curl_setopt($podio->ch, CURLOPT_CUSTOMREQUEST, self::GET); $podio->headers['Content-type'] = 'application/x-www-form-urlencoded'; $separator = strpos($url, '?') ? '&' : '?'; if ($attributes) { $query = Podio::encode_attributes($attributes); $url = $url . $separator . $query; } $podio->headers['Content-length'] = "0"; break; case self::DELETE: curl_setopt($podio->ch, CURLOPT_CUSTOMREQUEST, self::DELETE); $podio->headers['Content-type'] = 'application/x-www-form-urlencoded'; $separator = strpos($url, '?') ? '&' : '?'; if ($attributes) { $query = Podio::encode_attributes($attributes); $url = $url . $separator . $query; } $podio->headers['Content-length'] = "0"; break; case self::POST: curl_setopt($podio->ch, CURLOPT_CUSTOMREQUEST, self::POST); if (!empty($options['upload'])) { curl_setopt($podio->ch, CURLOPT_POST, TRUE); curl_setopt($podio->ch, CURLOPT_POSTFIELDS, $attributes); $podio->headers['Content-type'] = 'multipart/form-data'; } elseif (empty($options['oauth_request'])) { // application/json $encoded_attributes = json_encode($attributes); curl_setopt($podio->ch, CURLOPT_POSTFIELDS, $encoded_attributes); $podio->headers['Content-type'] = 'application/json'; } else { // x-www-form-urlencoded $encoded_attributes = Podio::encode_attributes($attributes); curl_setopt($podio->ch, CURLOPT_POSTFIELDS, $encoded_attributes); $podio->headers['Content-type'] = 'application/x-www-form-urlencoded'; } break; case self::PUT: $encoded_attributes = json_encode($attributes); curl_setopt($podio->ch, CURLOPT_CUSTOMREQUEST, self::PUT); curl_setopt($podio->ch, CURLOPT_POSTFIELDS, $encoded_attributes); $podio->headers['Content-type'] = 'application/json'; break; } // Add access token to request if (isset($podio->oauth) && !empty($podio->oauth->access_token) && !(isset($options['oauth_request']) && $options['oauth_request'])) { $token = $podio->oauth->access_token; $podio->headers['Authorization'] = "OAuth2 {$token}"; } else { unset($podio->headers['Authorization']); } // File downloads can be of any type if (empty($options['file_download'])) { $podio->headers['Accept'] = 'application/json'; } else { $podio->headers['Accept'] = '*/*'; } curl_setopt($podio->ch, CURLOPT_HTTPHEADER, $podio->curl_headers()); curl_setopt($podio->ch, CURLOPT_URL, empty($options['file_download']) ? $podio->url . $url : $url); $response = new PodioResponse(); $raw_response = curl_exec($podio->ch); $raw_headers_size = curl_getinfo($podio->ch, CURLINFO_HEADER_SIZE); $response->body = substr($raw_response, $raw_headers_size); $response->status = curl_getinfo($podio->ch, CURLINFO_HTTP_CODE); $response->headers = Podio::parse_headers(substr($raw_response, 0, $raw_headers_size)); $podio->last_response = $response; if (!isset($options['oauth_request'])) { $curl_info = curl_getinfo($podio->ch, CURLINFO_HEADER_OUT); $podio->log_request($method, $url, $encoded_attributes, $response, $curl_info); } switch ($response->status) { case 200: case 201: case 204: return $response; break; case 400: // invalid_grant_error or bad_request_error $body = $response->json_body(); if (strstr($body['error'], 'invalid_grant')) { // Reset access token & refresh_token $podio->clear_authentication(); throw new PodioInvalidGrantError($response->body, $response->status, $url); break; } else { throw new PodioBadRequestError($response->body, $response->status, $url); } break; case 401: $body = $response->json_body(); if (strstr($body['error_description'], 'expired_token') || strstr($body['error'], 'invalid_token')) { if ($podio->oauth->refresh_token) { // Access token is expired. Try to refresh it. if ($podio->authenticate('refresh_token', array('refresh_token' => $podio->oauth->refresh_token))) { // Try the original request again. return Podio::request($method, $original_url, $attributes); } else { $podio->clear_authentication(); throw new PodioAuthorizationError($response->body, $response->status, $url); } } else { // We have tried in vain to get a new access token. Log the user out. $podio->clear_authentication(); throw new PodioAuthorizationError($response->body, $response->status, $url); } } elseif (strstr($body['error'], 'invalid_request') || strstr($body['error'], 'unauthorized')) { // Access token is invalid. $podio->clear_authentication(); throw new PodioAuthorizationError($response->body, $response->status, $url); } break; case 403: throw new PodioForbiddenError($response->body, $response->status, $url); break; case 404: throw new PodioNotFoundError($response->body, $response->status, $url); break; case 409: throw new PodioConflictError($response->body, $response->status, $url); break; case 410: throw new PodioGoneError($response->body, $response->status, $url); break; case 420: throw new PodioRateLimitError($response->body, $response->status, $url); break; case 500: throw new PodioServerError($response->body, $response->status, $url); break; case 502: case 503: case 504: throw new PodioUnavailableError($response->body, $response->status, $url); break; default: throw new PodioError($response->body, $response->status, $url); break; } return false; }