config = config('services.dropbox'); } public function authoriseUrl(Storage $storage) { $service = $storage->externalService; $redirectUrl = $this->callbackUrl(); return sprintf( '%s?client_id=%s&response_type=code&redirect_uri=%s&state=%s', $this->config['authorise_url'], urlencode(decrypt($service->app_id)), urlencode($redirectUrl), urlencode(encrypt($storage->id)) ); } public function callbackUrl() { return route('services.authoriseDropbox'); } public function downloadFile($pathOnStorage) { $dropboxArgs = ['path' => $pathOnStorage]; return $this->sendRequest( $this->config['download_url'], 'POST', null, [ 'http_headers' => [ sprintf('Dropbox-API-Arg: %s', json_encode($dropboxArgs)), 'Content-Type: application/octet-stream' ], 'post_body_is_json' => false, 'response_body_is_json' => false ] ); } public function handleAuthenticationResponse(Request $request, Storage $storage) { $authorisationCode = $request->query('code'); $storage->access_token = encrypt($this->convertAuthorisationCodeToToken($authorisationCode, $storage)); $storage->save(); return true; } /** * @param string $accessToken */ public function setAccessToken(string $accessToken) { $this->accessToken = $accessToken; } public function uploadFile($pathToFileToUpload, $pathToStorage) { $dropboxArgs = [ 'path' => $pathToStorage, 'mode' => 'add', 'mute' => true ]; $uploadResult = $this->sendRequest( $this->config['upload_url'], 'POST', file_get_contents($pathToFileToUpload), [ 'http_headers' => [ sprintf('Dropbox-API-Arg: %s', json_encode($dropboxArgs)), 'Content-Type: application/octet-stream' ], 'post_body_is_json' => false ] ); } private function convertAuthorisationCodeToToken($authorisationCode, Storage $storage) { $service = $storage->externalService; $credentials = sprintf('%s:%s', decrypt($service->app_id), decrypt($service->app_secret)); $redirectUrl = $this->callbackUrl(); $httpHeaders = [ 'Accept: application/json', sprintf('Authorization: Basic %s', base64_encode($credentials)) ]; $ch = curl_init($this->config['token_url']); curl_setopt($ch, CURLOPT_HTTPHEADER, $httpHeaders); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, [ 'code' => $authorisationCode, 'grant_type' => 'authorization_code', 'redirect_uri' => $redirectUrl ]); $response = json_decode(curl_exec($ch)); if (is_null($response) || $response === false) { throw new \Exception('Unable to read the response from Dropbox'); } else if (isset($response->error_description)) { throw new \Exception(sprintf('Error from Dropbox: %s', $response->error_description)); } return $response->access_token; } private function getBasicHttpClient($url, $method = 'GET', array $httpHeaders = []) { $httpHeaders = array_merge( [ 'Accept: application/json', sprintf('Authorization: Bearer %s', $this->accessToken) ], $httpHeaders ); $ch = curl_init($url); curl_setopt($ch, CURLOPT_HTTPHEADER, $httpHeaders); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); switch (strtoupper($method)) { case 'GET': curl_setopt($ch, CURLOPT_HTTPGET, true); break; case 'POST': curl_setopt($ch, CURLOPT_POST, true); break; } return $ch; } private function sendRequest($url, $method = 'GET', $postData = null, array $postOptions = []) { $postOptions = array_merge( [ 'http_headers' => [], 'post_body_is_json' => true, 'response_body_is_json' => true ], $postOptions ); $httpHeaders = $postOptions['http_headers']; $ch = $this->getBasicHttpClient($url, $method, $httpHeaders); if (!is_null($postData)) { if ($postOptions['post_body_is_json']) { $postData = json_encode($postData); } curl_setopt($ch, CURLOPT_POSTFIELDS, $postData); } Log::info(sprintf('%s: %s', strtoupper($method), $url)); Log::debug('HTTP headers:', $httpHeaders); // Only log a post body if we have one and it's in JSON format (i.e. not a file upload) if (!is_null($postData) && $postOptions['post_body_is_json']) { Log::debug($postData); } $result = curl_exec($ch); $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); Log::info(sprintf('Received HTTP code %d', $httpCode)); // Only log a result if we have one and it's in JSON format (i.e. not a file download) if (!is_null($result) && $result !== false && $postOptions['response_body_is_json']) { Log::debug($result); } if ($httpCode != 200 && $httpCode != 304) { throw new \Exception(sprintf('Exception from Dropbox: %s', $result)); } curl_close($ch); return $postOptions['response_body_is_json'] ? json_decode($result) : $result; } }