Files
glastree/vendor/as247/cloud-storages/src/Service/OneDrive.php
T

329 lines
8.2 KiB
PHP

<?php
namespace As247\CloudStorages\Service;
use ArrayObject;
use As247\CloudStorages\Exception\StorageException;
use As247\CloudStorages\Support\Path;
use As247\CloudStorages\Support\StorageAttributes;
use Generator;
use As247\CloudStorages\Contracts\Storage\StorageContract;
use InvalidArgumentException;
use Microsoft\Graph\Exception\GraphException;
use Microsoft\Graph\Graph;
use Microsoft\Graph\Http\GraphRequest;
class OneDrive
{
protected $graph;
const ROOT = '/me/drive/root';
protected $publishPermission = [
'role' => 'read',
'scope' => 'anonymous',
'withLink' => true
];
protected $options;
//Add prefix / when original root has /
protected $rootPrefix='';
use HasLogger;
public function __construct(Graph $graph,$options=[])
{
$this->options=$options;
$root=$options['root']??'';
if($root){
$firstChar=substr($root,0,1);
if($firstChar==='/' || $firstChar==='\\'){
$this->rootPrefix=$firstChar;
}
}
$this->setupLogger($options);
$this->graph=$graph;
}
function normalizeMetadata(array $response, string $path): array
{
$permissions=$response['permissions']??[];
$visibility = StorageContract::VISIBILITY_PRIVATE;
$shareLink=null;
foreach ($permissions as $permission) {
if(!isset($permission['link']['scope']) || !isset($permission['roles'])){
continue;
}
if(in_array($this->publishPermission['role'],$permission['roles'])
&& $permission['link']['scope']==$this->publishPermission['scope']){
$visibility = StorageContract::VISIBILITY_PUBLIC;
$shareLink=$permission['link']['webUrl']??null;
break;
}
}
$meta= [
StorageAttributes::ATTRIBUTE_PATH => $this->rootPrefix.ltrim($path,'\/'),
StorageAttributes::ATTRIBUTE_LAST_MODIFIED => strtotime($response['lastModifiedDateTime']),
StorageAttributes::ATTRIBUTE_FILE_SIZE => $response['size'],
StorageAttributes::ATTRIBUTE_TYPE => isset($response['file']) ? 'file' : 'dir',
StorageAttributes::ATTRIBUTE_MIME_TYPE => $response['file']['mimeType'] ?? null,
StorageAttributes::ATTRIBUTE_VISIBILITY=>$visibility,
'@id'=>$response['id']??null,
'@link' => $response['webUrl'] ?? null,
'@shareLink'=>$shareLink,
'@downloadUrl' => $response['@microsoft.graph.downloadUrl']?? null,
];
return $meta;
}
function getEndpoint($path='',$action='',$params=[]){
$this->validatePath($path);
$path=Path::clean($path);
$path=trim($path,'\\/');
$path=static::ROOT.':/'.$path;
/**
* Path should not end with /
* /me/drive/root:/path/to/file
* /me/drive/root
*/
$path=rtrim($path,':/');
if($action===true){//path reference
if(strpos($path,':')===false) {
$path .= ':';//root path should end with :
}
}
if ($action && is_string($action)) {
/**
* Append action to path
* /me/drive/root:/path:/action
* trim : for root
* /me/drive/root/action
*/
$path= rtrim($path,':');
if(strpos($path,':')!==false) {
$path .=':/' . $action;//root:/path:/action
}else{
$path .= '/' . $action;//root/action
}
}
if($params){
$path.='?'.http_build_query($params);
}
return $path;
}
/**
* @param $path
* @param $newPath
* @return array|null
* @throws GraphException
*/
public function copy($path,$newPath){
$endpoint = $this->getEndpoint($path,'copy');
$name=basename($newPath);
$this->createDirectory(dirname($newPath));
$newPathParent=$this->getEndpoint(dirname($newPath),true);
$body=[
'name' => $name,
'parentReference' => [
'path' => $newPathParent,
],
];
return $this->createRequest('POST', $endpoint)
->attachBody($body)
->execute()->getBody();
}
/**
* @param $path
* @return array|null
* @throws GraphException
*/
public function createDirectory($path){
$path=Path::clean($path);
if($path==='/'){
return $this->getItem('/');
}
$endpoint=$this->getEndpoint($path);
return $this->createRequest('PATCH', $endpoint)
->attachBody([
'folder' => new ArrayObject(),
])->execute()->getBody();
}
/**
* @param $path
* @return array|null
* @throws GraphException
*/
public function delete($path){
$endpoint=$this->getEndpoint($path);
return $this->createRequest('DELETE', $endpoint)->execute()->getBody();
}
/**
* @param $path
* @param null $format
* @return resource|null
* @throws GraphException
*/
public function download($path,$format=null){
$args=[];
if($format){
if(is_string($format)){
$args=['format'=>$format];
}elseif(is_array($format)){
$args=$format;
}
}
$endpoint=$this->getEndpoint($path,'content',$args);
$response=$this->createRequest('GET',$endpoint)->setReturnType('GuzzleHttp\Psr7\Stream')->execute();
/**
* @var StreamWrapper $response
*/
return $response->detach();
}
/**
* @param $path
* @param array $args
* @return array|null
* @throws GraphException
*/
public function getItem($path,$args=[]){
$endpoint=$this->getEndpoint($path,'',$args);
$response = $this->createRequest('GET', $endpoint)->execute();
return $response->getBody();
}
/**
* @param $path
* @return Generator
* @throws GraphException
*/
public function listChildren($path){
$endpoint = $this->getEndpoint($path,'children');
$nextPage=null;
do {
if ($nextPage) {
$endpoint = $nextPage;
}
$response = $this->createRequest('GET', $endpoint)
->execute();
$nextPage = $response->getNextLink();
$items = $response->getBody()['value']??[];
if(!is_array($items)){
$items=[];
}
yield from $items;
}while($nextPage);
}
/**
* @param $path
* @param $newPath
* @return array|null
* @throws GraphException
*/
public function move($path,$newPath){
$endpoint = $this->getEndpoint($path);
$name=basename($newPath);
$this->createDirectory(dirname($newPath));
$newPathParent=$this->getEndpoint(dirname($newPath),true);
$body=[
'name' => $name,
'parentReference' => [
'path' => $newPathParent,
],
];
return $this->createRequest('PATCH', $endpoint)
->attachBody($body)
->execute()->getBody();
}
/**
* @param $path
* @param $contents
* @return array|null
* @throws GraphException
*/
public function upload($path,$contents){
$endpoint = $this->getEndpoint($path,'content');
try {
$stream = StreamWrapper::wrap($contents);
}catch (InvalidArgumentException $e){
throw new StorageException("Invalid contents. ".$e->getMessage());
}
$this->createDirectory(dirname($path));
return $this->createRequest('PUT', $endpoint)
->attachBody($stream)
->execute()->getBody();
}
/**
* @param $path
* @return array|mixed
* @throws GraphException
*/
public function getPermissions($path){
$endpoint=$this->getEndpoint($path,'permissions');
$response = $this->createRequest('GET', $endpoint)->execute();
return $response->getBody()['value']??[];
}
/**
* @param $path
* @return array
* @throws GraphException
*/
function publish($path){
$endpoint=$this->getEndpoint($path,'createLink');
$body=['type'=>'view','scope'=>'anonymous'];
$response = $this->createRequest('POST', $endpoint)
->attachBody($body)->execute();
return $response->getBody();
}
/**
* @param $path
* @throws GraphException
*/
function unPublish($path){
$permissions=$this->getPermissions($path);
$idToRemove='';
foreach ($permissions as $permission){
if(in_array($this->publishPermission['role'],$permission['roles'])
&& $permission['link']['scope']==$this->publishPermission['scope']){
$idToRemove=$permission['id'];
break;
}
}
if(!$idToRemove){
return ;
}
$endpoint=$this->getEndpoint($path,'permissions/'.$idToRemove);
$this->createRequest('DELETE', $endpoint)->execute();
}
/**
* @param $requestType
* @param $endpoint
* @return GraphRequest
* @throws GraphException
*/
protected function createRequest($requestType, $endpoint){
$this->logger->request($requestType,$endpoint);
return $this->graph->createRequest($requestType,$endpoint);
}
protected function validatePath($path){
$invalidChars=['"','*',':','<','>','?', '|'];
foreach ($invalidChars as $char){
if(strpos($path,$char)!==false){
throw new StorageException("Invalid character $char in path $path");
}
}
}
}