EVOLUTION-MANAGER
Edit File: Client.php
<?php namespace DuplicatorPro\Krizalys\Onedrive; defined("ABSPATH") or die(""); include_once "ResumableUploader.php"; use Monolog\Handler\StreamHandler; use Monolog\Logger; /** * @class Client * * A Client instance allows communication with the OneDrive API and perform * operations programmatically. * * For an overview of the OneDrive protocol flow, see here: * http://msdn.microsoft.com/en-us/library/live/hh243647.aspx * * To manage your Live Connect applications, see here: * https://account.live.com/developers/applications/index * Or here: * https://manage.dev.live.com/ (not working?) * * For an example implementation, see here: * https://github.com/drumaddict/skydrive-api-yii/blob/master/SkyDriveAPI.php */ class Client { /** * @var string Client information. */ private $_clientId; /** * @var object OAuth state (token, etc...). */ private $_state; /** * @var int The last HTTP status received. */ private $_httpStatus; /** * @var string The last Content-Type received. */ private $_contentType; /** * @var bool Verify SSL hosts and peers. */ private $_sslVerify; /** * @var null|string Over-ride SSL CA path for verification (only relevant * when verifying). */ private $_sslCaPath; public $use_msgraph_api; private $api_url; public $route_prefix; // The base URL for authorization requests. private $auth_url; // The base URL for token requests. private $token_url; /** * @var int The name conflict behavior. */ private $_nameConflictBehavior; /** * @var int The stream back end. */ private $_streamBackEnd; /** * @var NameConflictBehaviorParameterizer The name conflict behavior * parameterizer. */ private $_nameConflictBehaviorParameterizer; /** * @var StreamOpener The stream opener. */ private $_streamOpener; /** * @var bool If the Client should use the Business Endpoint url on calls. * */ private $_isBusiness = false; /** * @var string OneDrive endpoint url */ private $_endpointURL; /** * @var null|string The Resource ID to get the OneDrive tokens with. */ private $_resourceId; /** * @var ResumableUploader Contains the upload session data */ public $RUploader; /** * Creates a base cURL object which is compatible with the OneDrive API. * * @param string $path The path of the API call (eg. me/skydrive). * @param array $options Extra cURL options to apply. * * @return resource A compatible cURL object. */ private function _createCurl($path, $options = []) { $curl = curl_init(); $defaultOptions = [ // General options. CURLOPT_RETURNTRANSFER => true, CURLOPT_FOLLOWLOCATION => true, CURLOPT_AUTOREFERER => true, // SSL options. // The value 2 checks the existence of a common name and also // verifies that it matches the hostname provided. CURLOPT_SSL_VERIFYHOST => ($this->_sslVerify ? 2 : false), CURLOPT_SSL_VERIFYPEER => $this->_sslVerify, ]; if ($this->_sslVerify && $this->_sslCaPath) { $defaultOptions[CURLOPT_CAINFO] = $this->_sslCaPath; } $defaultOptions[CURLOPT_TIMEOUT] = 1000; // See http://php.net/manual/en/function.array-merge.php for a // description of the + operator (and why array_merge() would be wrong). $finalOptions = $options + $defaultOptions; curl_setopt_array($curl, $finalOptions); return $curl; } /** * Processes a result returned by the OneDrive API call using a cURL object. * * @param resource $curl The cURL object used to perform the call. * * @return object|string The content returned, as an object instance if * served a JSON, or as a string if served as anything * else. * * @throws \Exception Thrown if curl_exec() fails. */ private function _processResult($curl) { $result = curl_exec($curl); // error_log('res: '.print_r($result, true)); if (false === $result) { throw new \Exception('curl_exec() failed: ' . curl_error($curl)); } $info = curl_getinfo($curl); $this->_httpStatus = array_key_exists('http_code', $info) ? (int)$info['http_code'] : null; $this->_contentType = array_key_exists('content_type', $info) ? (string)$info['content_type'] : null; // Parse nothing but JSON. if (1 !== preg_match('|^application/json|', $this->_contentType)) { return $result; } // Empty JSON string is returned as an empty object. if ('' == $result) { return (object)[]; } $decoded = json_decode($result); $vars = get_object_vars($decoded); if (array_key_exists('error', $vars)) { throw new \Exception($decoded->error->message, (int)$decoded->error->code); } return $decoded; } /** * Constructor. * * @param array $options The options to use while creating this object. * Valid supported keys are: * - 'state' (object) When defined, it should contain * a valid OneDrive client state, as returned by * getState(). Default: []. * - 'logger' (Logger) A LoggerInterface instance. * Default: new Logger('DuplicatorPro\Krizalys\Onedrive\Client') * which logs every message to 'php://stderr'. * - 'ssl_verify' (bool) Whether to verify SSL hosts * and peers. Default: false. * - 'ssl_capath' (bool|string) CA path to use for * verifying SSL certificate chain. Default: false. * - 'name_conflict_behavior' (int) Default name * conflict behavior. Either: * NameConflictBehavior::FAIL, * NameConflictBehavior::RENAME or * NameConflictBehavior::REPLACE. Default: * NameConflictBehavior::REPLACE. * - 'stream_back_end' (int) Default stream back end. * Either StreamBackEnd::MEMORY or * StreamBackEnd::TEMP. Default: * StreamBackEnd::MEMORY. * Using temporary files is recommended when uploading * big files. * Default: StreamBackEnd::MEMORY. */ public function __construct(array $options = []) { $this->_clientId = array_key_exists('client_id', $options) ? (string)$options['client_id'] : null; $this->_state = array_key_exists('state', $options) ? $options['state'] : (object)[ 'redirect_uri' => null, 'token' => null, ]; $this->_serviceResourceId = property_exists($this->_state,"resource_id") ? $this->_state->resource_id : null; $this->_sslVerify = array_key_exists('ssl_verify', $options) ? $options['ssl_verify'] : false; $this->_sslCaPath = array_key_exists('ssl_capath', $options) ? $options['ssl_capath'] : false; $this->_streamBackEnd = array_key_exists('stream_back_end', $options) ? $options['stream_back_end'] : StreamBackEnd::TEMP; $this->_streamOpener = new StreamOpener(); $this->_nameConflictBehavior = array_key_exists('name_conflict_behavior', $options) ? $options['name_conflict_behavior'] : NameConflictBehavior::REPLACE; $this->_nameConflictBehaviorParameterizer = new NameConflictBehaviorParameterizer(); $this->use_msgraph_api = array_key_exists('use_msgraph_api', $options) ? $options['use_msgraph_api'] : false; if ($this->use_msgraph_api) { $this->api_url = 'https://graph.microsoft.com/v1.0/'; $this->route_prefix = 'me/'; // The base URL for authorization requests. $this->auth_url = 'https://login.microsoftonline.com/common/oauth2/v2.0/authorize'; // The base URL for token requests. $this->token_url = 'https://login.microsoftonline.com/common/oauth2/v2.0/token'; } else { // Custom App or old live sdk $this->route_prefix = ''; // $this->api_url = 'https://api.onedrive.com/v1.0/'; $this->api_url = !empty($this->_state->endpoint_url) ? $this->_state->endpoint_url : 'https://api.onedrive.com/v1.0/'; $this->_isBusiness = $this->api_url != 'https://api.onedrive.com/v1.0/'; // $this->_isBusiness = true; /* if (!empty($this->_state->endpoint_url)) { $this->_isBusiness = true; } */ if ($this->_isBusiness) { // The base URL for authorization requests. $this->auth_url = 'https://login.microsoftonline.com/common/oauth2/authorize'; // The base URL for token requests. $this->token_url = 'https://login.microsoftonline.com/common/oauth2/token'; } else { // The base URL for authorization requests. $this->auth_url = 'https://login.live.com/oauth20_authorize.srf'; // The base URL for token requests. $this->token_url = 'https://login.live.com/oauth20_token.srf'; } } } /** * Makes current client use business logic */ public function setBusinessMode() { // The base URL for authorization requests. $this->auth_url = 'https://login.microsoftonline.com/common/oauth2/authorize'; // The base URL for token requests. $this->token_url = 'https://login.microsoftonline.com/common/oauth2/token'; $this->_isBusiness = true; } public function isBusiness() { return $this->_isBusiness; } /** * Gets the name conflict behavior of this client instance. * * @return int */ public function getNameConflictBehavior() { return $this->_nameConflictBehavior; } /** * Gets the stream back end of this client instance. * * @return int */ public function getStreamBackEnd() { return $this->_streamBackEnd; } /** * Gets the current state of this Client instance. Typically saved in the * session and passed back to the Client constructor for further requests. * * @return object The state of this Client instance. */ public function getState() { return $this->_state; } /** * Gets the URL of the log in form. After login, the browser is redirected * to the redirect URL, and a code is passed as a GET parameter to this URL. * * The browser is also redirected to this URL if the user is already logged * in. * * @param array $scopes The OneDrive scopes requested by the * application. Supported values: * - 'wl.signin' * - 'wl.basic' * - 'wl.contacts_skydrive' * - 'wl.skydrive_update' * @param string $redirectUri The URI to which to redirect to upon * successful log in. * @param array $options Reserved for future use. Default: []. * * @return string The login URL. * * @throws \Exception Thrown if this Client instance's clientId is not set. * * @todo Support $options. */ public function getLogInUrl( array $scopes, $redirectUri, array $options = [] ) { if (null === $this->_clientId) { throw new \Exception( 'The client ID must be set to call getLoginUrl()' ); } if ($this->use_msgraph_api) { $imploded = implode(' ', $scopes); } else { $imploded = implode(',', $scopes); } $redirectUri = (string) $redirectUri; $this->_state->redirect_uri = $redirectUri; // When using this URL, the browser will eventually be redirected to the // callback URL with a code passed in the URL query string (the name of // the variable is "code"). This is suitable for PHP. $url = $this->auth_url . '?client_id=' . urlencode($this->_clientId) . '&scope=' . urlencode($imploded) . '&response_type=code' . '&redirect_uri=' . urlencode($redirectUri) . '&display=popup' . '&locale=en'; return $url; } /** * Gets the access token expiration delay. * * @return int The token expiration delay, in seconds. */ public function getTokenExpire() { return $this->_state->token->obtained + $this->_state->token->data->expires_in - time(); } /** * Gets the status of the current access token. * * @return int The status of the current access token: * - 0 No access token. * - -1 Access token will expire soon (1 minute or less). * - -2 Access token is expired. * - 1 Access token is valid. */ public function getAccessTokenStatus() { if (null === $this->_state->token) { return 0; } $remaining = $this->getTokenExpire(); if (0 >= $remaining) { return -2; } if (60 >= $remaining) { return -1; } return 1; } /** * Obtains a new access token from OAuth. This token is valid for one hour. * * @param string $clientSecret The OneDrive client secret. * @param array $options Contains all custom parameters of the request * * @throws \Exception Thrown if this Client instance's clientId is not set. * @throws \Exception Thrown if the redirect URI of this Client instance's * state is not set. */ public function obtainAccessToken($clientSecret, $options = array()) { if (null === $this->_clientId) { throw new \Exception( 'The client ID must be set to call obtainAccessToken()' ); } if (null === $this->_state->redirect_uri) { throw new \Exception( 'The state\'s redirect URI must be set to call' . ' obtainAccessToken()' ); } $url = $this->token_url; $fields_arr = array( 'client_id' => $this->_clientId, 'redirect_uri' => $this->_state->redirect_uri, 'client_secret' => $clientSecret, ); $fields_arr = array_merge($fields_arr, $options); $curl = curl_init(); $fields = http_build_query($fields_arr); curl_setopt_array($curl, [ // General options. CURLOPT_RETURNTRANSFER => true, CURLOPT_FOLLOWLOCATION => true, CURLOPT_AUTOREFERER => true, CURLOPT_POST => 1, CURLOPT_POSTFIELDS => $fields, CURLOPT_HTTPHEADER => [ 'Content-Length: ' . strlen($fields), ], // SSL options. CURLOPT_SSL_VERIFYHOST => false, CURLOPT_SSL_VERIFYPEER => false, CURLOPT_URL => $url, ]); $result = curl_exec($curl); if (false === $result) { if (curl_errno($curl)) { throw new \Exception('curl_setopt_array() failed: ' . curl_error($curl)); } else { throw new \Exception('curl_setopt_array(): empty response'); } } $decoded = json_decode($result); if (null === $decoded) { throw new \Exception('json_decode() failed'); } $this->_state->token = (object)[ 'obtained' => time(), 'data' => $decoded, ]; } /** * Fetches the OneDrive Endpoint url and Resource ID * * @return array Containing the OneDrive Endpoint url and Resource ID */ public function getServiceInfo() { $url = "https://graph.microsoft.com/v1.0/me/drive/sharepointIds/siteUrl"; $curl = curl_init(); curl_setopt_array($curl, [ CURLOPT_RETURNTRANSFER => true, CURLOPT_FOLLOWLOCATION => true, CURLOPT_AUTOREFERER => true, CURLOPT_HTTPHEADER => [ 'Authorization: Bearer ' . $this->_state->token->data->access_token, ], // SSL options. CURLOPT_SSL_VERIFYHOST => false, CURLOPT_SSL_VERIFYPEER => false, CURLOPT_URL => $url, ]); $result = curl_exec($curl); $result = json_decode($result); $response = array( 'endpoint_url' => $result->value.'/_api/v2.0/', 'resource_id' => 'https://'.parse_url($result->value)['host'] ); return $response; } /** * Renews the access token from OAuth. This token is valid for one hour. * * @param string $clientSecret The client secret. */ public function renewAccessToken($clientSecret) { if (null === $this->_clientId) { throw new \Exception( 'The client ID must be set to call renewAccessToken()' ); } if (null === $this->_state->token->data->refresh_token) { throw new \Exception( 'The refresh token is not set or no permission for' . ' \'wl.offline_access\' was given to renew the token' ); } $url = $this->token_url; $curl = curl_init(); $post_fields = 'client_id=' . urlencode($this->_clientId) . '&client_secret=' . urlencode($clientSecret) . '&grant_type=refresh_token'; if (!empty($this->_state->token->data->refresh_token)) { $post_fields .= '&refresh_token=' . urlencode( $this->_state->token->data->refresh_token ); } curl_setopt_array($curl, [ // General options. CURLOPT_RETURNTRANSFER => true, CURLOPT_FOLLOWLOCATION => true, CURLOPT_AUTOREFERER => true, CURLOPT_POST => 1, // i am sending post data CURLOPT_POSTFIELDS => $post_fields, // SSL options. CURLOPT_SSL_VERIFYHOST => false, CURLOPT_SSL_VERIFYPEER => false, CURLOPT_URL => $url, ]); $result = curl_exec($curl); if (false === $result) { if (curl_errno($curl)) { throw new \Exception( 'curl_setopt_array() failed: ' . curl_error($curl) ); } else { throw new \Exception('curl_setopt_array(): empty response'); } } $decoded = json_decode($result); if (null === $decoded) { throw new \Exception('json_decode() failed'); } $this->_state->token = (object)[ 'obtained' => time(), 'data' => $decoded, ]; } /** * Performs a call to the OneDrive API using the GET method. * * @param string $path The path of the API call (eg. me/skydrive). * @param array $options Further curl options to set. * * @return object|string The response body, if any. */ public function apiGet($path, $options = []) { $api = $this->api_url; // $url = (strpos($path, 'https://') === 0) ? $path : $api . $path; if (strpos($path, "https") === false) { $url = $api . $path; } else { $url = $path; } if (!$this->use_msgraph_api) $url .= '?access_token=' . urlencode($this->_state->token->data->access_token); //throw new \Exception(print_r($this->_state,true)); $curl = self::_createCurl($path, $options); $curl_options = array( CURLOPT_URL => $url, CURLOPT_HTTPHEADER => array( 'Authorization: Bearer ' . $this->_state->token->data->access_token ), ); // error_log($url); curl_setopt_array($curl, $curl_options); // curl_setopt($curl, CURLOPT_URL, $url); return $this->_processResult($curl); } /** * Performs a call to the OneDrive API using the POST method. * * @param string $path The path of the API call (eg. me/skydrive). * @param array|object $data The data to pass in the body of the request. * * @return object|string The response body, if any. */ public function apiPost($path, $data) { $api = $this->api_url; $url = (strpos($path, 'https://') === 0) ? $path : $api . $path; $data = (object)$data; $curl = self::_createCurl($path); curl_setopt_array($curl, [ CURLOPT_URL => $url, CURLOPT_POST => true, CURLOPT_HTTPHEADER => [ // The data is sent as JSON as per OneDrive documentation. 'Content-Type: application/json', 'Authorization: Bearer ' . $this->_state->token->data->access_token, ], CURLOPT_POSTFIELDS => json_encode($data), ]); return $this->_processResult($curl); } /** * Performs a call to the OneDrive API using the PUT method. * * @param string $path The path of the API call (eg. me/skydrive). * @param resource $stream The data stream to upload. * @param integer $size Size of the file * @param string $contentType The MIME type of the data stream, or null if * unknown. Default: null. * * @return object|string The response body, if any. */ public function apiPut($path, $stream, $pheaders = [], $size = null, $contentType = null) { $api = $this->api_url; $url = (strpos($path, 'https://') === 0) ? $path : $api . $path; $curl = self::_createCurl($path); if (is_null($size)) { $stats = fstat($stream); $size = $stats[7]; } $headers = [ 'Authorization: Bearer ' . $this->_state->token->data->access_token, ]; if (null !== $contentType) { $headers[] = 'Content-Type: ' . $contentType; } $headers = array_merge($headers, $pheaders); // error_log('headers: '.print_r($headers, true)); $options = [ CURLOPT_URL => $url, CURLOPT_HTTPHEADER => $headers, CURLOPT_PUT => true, CURLOPT_INFILE => $stream, CURLOPT_INFILESIZE => $size, // Size ]; curl_setopt_array($curl, $options); return $this->_processResult($curl); } /** * Performs a call to the OneDrive API using the DELETE method. * * @param string $path The path of the API call (eg. me/skydrive). * * @return object|string The response body, if any. */ public function apiDelete($path) { $url = $this->api_url . $path; if (!$this->use_msgraph_api) $url .= '?access_token=' . urlencode($this->_state->token->data->access_token); $curl = self::_createCurl($path); curl_setopt_array($curl, [ CURLOPT_URL => $url, CURLOPT_CUSTOMREQUEST => 'DELETE', CURLOPT_HTTPHEADER => array( 'Authorization: Bearer ' . $this->_state->token->data->access_token ) ]); return $this->_processResult($curl); } /** * Performs a call to the OneDrive API using the MOVE method. * * @param string $path The path of the API call (eg. me/skydrive). * @param array|object $data The data to pass in the body of the request. * * @return object|string The response body, if any. */ public function apiPatch($path, $data) { $url = $this->api_url.$path; $data = (object)$data; $curl = self::_createCurl($path); curl_setopt_array($curl, [ CURLOPT_URL => $url, CURLOPT_CUSTOMREQUEST => 'PATCH', CURLOPT_HTTPHEADER => [ // The data is sent as JSON as per OneDrive documentation. 'Content-Type: application/json', 'Authorization: Bearer ' . $this->_state->token->data->access_token, ], CURLOPT_POSTFIELDS => json_encode($data), ]); return $this->_processResult($curl); } /** * Performs a call to the OneDrive API using the COPY method. * * @param string $path The path of the API call (eg. me/skydrive). * @param array|object $data The data to pass in the body of the request. * * @return object|string The response body, if any. */ public function apiCopy($path, $data) { if (strpos($path, "https") === false) { $url = $this->_endpointURL . $path; } else { $url = $path; } $data = (object)$data; $curl = self::_createCurl($path); curl_setopt_array($curl, [ CURLOPT_URL => $url, CURLOPT_CUSTOMREQUEST => 'COPY', CURLOPT_HTTPHEADER => [ // The data is sent as JSON as per OneDrive documentation. 'Content-Type: application/json', 'Authorization: Bearer ' . $this->_state->token->data->access_token, ], CURLOPT_POSTFIELDS => json_encode($data), ]); return $this->_processResult($curl); } /** * Creates a folder in the current OneDrive account. * * @param string $name The name of the OneDrive folder to be * created. * @param null|string $parentId The ID of the OneDrive folder into which * to create the OneDrive folder, or null to * create it in the OneDrive root folder. * Default: null. * @param null|string $description The description of the OneDrive folder to * be created, or null to create it without * a description. Default: null. * * @return Folder The folder created, as a Folder instance referencing to * the OneDrive folder created. */ public function createFolder($name, $parentId = null, $description = null) { $path = $this->route_prefix.'drive/special/approot/children'; if (null !== $parentId) { $path = $this->route_prefix.'drive/items/' . $parentId . '/children'; } $properties = [ 'name' => $name, 'folder' => (object)[] ]; $folder = $this->apiPost($path, $properties); return new Folder($this, $folder->id, $folder); } /** * Creates a file in the current OneDrive account. * * @param string $name The name of the OneDrive file to be * created. * @param null|string $parentId The ID of the OneDrive folder into which * to create the OneDrive file, or null to * create it in the OneDrive root folder. * Default: null. * @param string|resource $content The content of the OneDrive file to be * created, as a string or as a resource to * an already opened file. In the latter * case, the responsibility to close the * handle is left to the calling function. * Default: ''. * @param array $options The options. * * @return File The file created, as File instance referencing to the * OneDrive file created. * * @throws \Exception Thrown on I/O errors. */ public function createFile( $name, $parentId = null, $content = '', array $options = [] ) { $path = 'drive/special/approot:/' . $name . ':/content'; if (null !== $parentId) { $path = 'drive/items/' . $parentId . ':/' . $name . ':/content'; } if (is_resource($content)) { $stream = $content; } else { $options = array_merge([ 'stream_back_end' => $this->_streamBackEnd, ], $options); $stream = $this ->_streamOpener ->open($options['stream_back_end']); if (false === $stream) { throw new \Exception('fopen() failed'); } if (false === fwrite($stream, $content)) { fclose($stream); throw new \Exception('fwrite() failed'); } if (!rewind($stream)) { fclose($stream); throw new \Exception('rewind() failed'); } } $options = array_merge([ 'name_conflict_behavior' => $this->_nameConflictBehavior, ], $options); $params = $this ->_nameConflictBehaviorParameterizer ->parameterize([], $options['name_conflict_behavior']); $query = http_build_query($params); /** * @todo some versions of cURL cannot PUT memory streams? See here for a * workaround: https://bugs.php.net/bug.php?id=43468 */ $file = $this->apiPut($path, $stream); // Close the handle only if we opened it within this function. if (!is_resource($content)) { fclose($stream); } return new File($this, $file->id, $file); } public function uploadFileChunk( $sourcePath, $path = null, $resumable = null, $max_worker_time = 15, $server_load_delay = 0, $offset = 0 ) { $start_time = time(); $time_passed = 0; $completed = false; if ($path !== null) { $RUploader = new ResumableUploader($this, $sourcePath); $RUploader->obtainResumableUploadUrl($path); } elseif ($resumable !== null) { $RUploader = new ResumableUploader($this, $sourcePath, $resumable); } else { throw new \Exception("Must set destination path or resumable object"); } $this->RUploader = $RUploader; $this->RUploader->setUploadOffset($offset); $sourcePath = $RUploader->getSourcePath(); while (!$completed && ($time_passed < $max_worker_time)) { if ($server_load_delay !== 0) { usleep($server_load_delay); } $chunkSize = $this->RUploader->getChunkSize(); $fileOffset = $this->RUploader->getUploadOffset(); \DUP_PRO_Log::trace("chunk size:" . $chunkSize); // error_log("## UploadOffset:" . $fileOffset); \DUP_PRO_Log::trace("UploadOffset:" . $fileOffset); $handle = fopen($sourcePath, "rw+b"); fseek($handle, $fileOffset); $uploadContent = fread($handle, $chunkSize); fclose($handle); $uploadStream = $this->_streamOpener->open($this->_streamBackEnd); fwrite($uploadStream, $uploadContent); if (false === $uploadStream) { throw new \Exception('fopen() failed'); } if (false === fwrite($uploadStream, $uploadContent)) { fclose($uploadStream); throw new \Exception('fwrite() failed'); } if (!rewind($uploadStream)) { fclose($uploadStream); throw new \Exception('rewind() failed'); } $this->RUploader->uploadChunk($uploadStream); fclose($uploadStream); if ($this->RUploader->completed() == true) { $completed = true; } if ($this->RUploader->success()) { $this->RUploader->setUploadOffset($fileOffset + $chunkSize); } else { throw new \Exception($this->RUploader->getError()); } $time_passed = time() - $start_time; } } /** * Fetches a drive item from the current OneDrive account. * * @param null|string $driveItemId The unique ID of the OneDrive drive item * to fetch, or null to fetch the OneDrive * root folder. Default: null. * * @return object The drive item fetched, as a DriveItem instance * referencing to the OneDrive drive item fetched. */ public function fetchDriveItem($driveItemId = null) { $root = $this->route_prefix.'drive/special/approot'; $path = (null !== $driveItemId) ? $this->route_prefix.'drive/items/' . $driveItemId : $root; $result = $this->apiGet($path); if (property_exists($result, 'folder')) { return new Folder($this, $result->id, $result); } elseif (property_exists($result, 'file')) { return new File($this, $driveItemId, $result); } return null; } public function fetchDriveItemByPath($path = null) { $root = $this->route_prefix.'drive/special/approot:/'; $path = $root . $path; $result = $this->apiGet($path); if (property_exists($result, 'folder')) { return new Folder($this, $result->id, $result); } elseif (property_exists($result, 'file')) { return new File($this, $result->id, $result); } return null; } /** * Fetches the root folder from the current OneDrive account. * * @return Folder The root folder, as a Folder instance referencing to the * OneDrive root folder. */ public function fetchRoot() { return $this->fetchDriveItem(); } /** * Fetches the "Documents" folder from the current OneDrive account. * * @return Folder The "Documents" folder, as a Folder instance referencing * to the OneDrive "Documents" folder. */ public function fetchDocs() { return $this->fetchDriveItemByPath($this->route_prefix.'drive/root:/Documents'); } /** * Fetches the "Pictures" folder from the current OneDrive account. * * @return Folder The "Pictures" folder, as a Folder instance referencing to * the OneDrive "Pictures" folder. */ public function fetchPics() { return $this->fetchDriveItem($this->route_prefix.'drive/root:/Pictures'); } /** * Fetches the properties of a drive item in the current OneDrive account. * * @param string $driveItemId The drive item ID. * * @return object The properties of the drive item fetched. */ public function fetchProperties($driveItemId) { $root = $this->route_prefix.'drive/special/approot'; $path = (null !== $driveItemId) ? $this->route_prefix.'drive/items/' . $driveItemId : $root; return $this->apiGet($path); } /** * Fetches the drive items in a folder in the current OneDrive account. * * @param string $driveItemId The drive item ID. * * @return array The drive items in the folder fetched, as DriveItem * instances referencing OneDrive drive items. */ public function fetchDriveItems($driveItemId = null) { $root = $this->route_prefix.'drive/special/approot'; $path = (null !== $driveItemId) ? $this->route_prefix.'drive/items/' . $driveItemId . '/children' : $root.'/children'; $result = $this->apiGet($path); $driveItems = []; foreach ($result->value as $data) { $driveItem = property_exists($data, 'folder') ? new Folder($this, $data->id, $data) : new File($this, $data->id, $data); $driveItems[] = $driveItem; } return $driveItems; } /** * Updates the properties of a drive item in the current OneDrive account. * * @param string $driveItemId The unique ID of the drive item to * update. * @param array|object $properties The properties to update. Default: []. * @param bool $temp Option to allow save to a temporary file * in case of large files. * * @throws \Exception Thrown on I/O errors. */ public function updateDriveItem($driveItemId, $properties = [], $temp = true) { $path = $this->route_prefix.'drive/items/' . $driveItemId; $this->apiPatch($path, $properties, 'application/json'); } /** * Moves a drive item into another folder. * * @param string $driveItemId The unique ID of the drive item to * move. * @param null|string $destinationId The unique ID of the folder into which * to move the drive item, or null to move * it to the OneDrive root folder. * Default: null. */ public function moveDriveItem($driveItemId, $destinationId = null) { $path = $this->route_prefix."drive/items/" . $driveItemId; if (null === $destinationId) { $root = $this->fetchRoot(); $destinationId = $root->getId(); } $data = [ "parentReference" => [ "id" => $destinationId, ] ]; $this->apiPatch($path, $data); } /** * Copies a DriveItem into another folder. * * @param string $driveItemId The unique ID of the file to copy. * @param null|string $destinationId The unique ID of the folder into which * to copy the file, or null to copy it to * the OneDrive root folder. Default: * null. */ public function copyDriveItem($driveItemId, $destinationId = null) { $path = $this->route_prefix."drive/items/" . $driveItemId . "/copy"; if (null === $destinationId) { $copyTo = $this->fetchRoot(); } else { $copyTo = $this->fetchDriveItem($destinationId); } $data = [ "parentReference" => [ "id" => $copyTo->getId(), "driveId" => $copyTo->getDriveId() ], ]; //echo json_encode($data); $this->apiPost($path, $data); } /** * Deletes a drive item in the current OneDrive account. * * @param string $driveItemId The unique ID of the drive item to delete. */ public function deleteDriveItem($driveItemId) { $path = $this->route_prefix."drive/items/" . $driveItemId; $this->apiDelete($path); } /** * Fetches the quota of the current OneDrive account. * * @return object An object with the following properties: * - 'quota' (int) The total space, in bytes. * - 'available' (int) The available space, in bytes. */ public function fetchQuota() { $result = $this->apiGet($this->route_prefix.'drive'); return (object)[ "quota" => $result->quota->total, "available" => $result->quota->remaining, ]; } public function fetchAccountInfo() { return $this->apiGet($this->route_prefix.'drive/special/approot')->createdBy->user; } }