<?php
define('CLIENT_ID','');
define('CLIENT_SECRET','');
define('CALLBACK_URI','http://localhost/core/api/onedrive/example/auth.php');
class Client {
const API_URL = 'https://api.onedrive.com/v1.0';
const AUTH_URL = 'https://login.live.com/oauth20_authorize.srf';
const TOKEN_URL = 'https://login.live.com/oauth20_token.srf';
private $_clientId;
private $_state;
private $_httpStatus;
private $_contentType;
public function __construct(array $options = array()) {
$this->_clientId = array_key_exists('client_id', $options)
? (string) $options['client_id'] : CLIENT_ID;
$this->_state = array_key_exists('state', $options)
? $options['state'] :array(
'redirect_uri' => '',
'token' => '',
'expire_in' => 0,
'refreshtime'=>0
);
}
public function getState(){
return $this->_state;
}
public function setState($arr){
if(is_array($arr)) $this->_state=array_merge($this->_state,$arr);
return $this->_state;
}
public function getLogInUrl(array $scopes, $redirectUri, array $options = array()) {
if (null === $this->_clientId) {
return array('error'=>'The client ID must be set to call getLoginUrl()');
}
$imploded = implode(' ', $scopes);
$redirectUri = $redirectUri?((string) $redirectUri):CALLBACK_URI;
$this->_state['redirect_uri'] = $redirectUri;
$url = self::AUTH_URL
. '?client_id=' . urlencode($this->_clientId)
. '&scope=' . ($imploded)
. '&response_type=code'
. '&redirect_uri=' . urlencode($redirectUri)
. '&display=popup'
. '&locale=en';
return $url;
}
public function getTokenExpire() {
return $this->_state['refreshtime']
+ $this->_state['expires_in'] - time();
}
public function getAccessTokenStatus() {
if (null === $this->_state['access_token']) {
return 0;
}
$remaining = $this->getTokenExpire();
if (0 >= $remaining) {
return -2;
}
if (60 >= $remaining) {
return -1;
}
return 1;
}
public function obtainAccessToken($clientSecret, $code) {
if (null === $this->_clientId) {
return array('error'=>'The client ID must be set to call obtainAccessToken()');
}
if (null === $this->_state['redirect_uri']) {
return array('error'=>'The state\'s redirect URI must be set to call obtainAccessToken()');
}
$url = self::TOKEN_URL
. '?client_id=' . urlencode($this->_clientId)
. '&redirect_uri=' . urlencode($this->_state['redirect_uri'])
. '&client_secret=' . urlencode($clientSecret)
. '&grant_type=authorization_code'
. '&code=' . urlencode($code);
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => $url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_AUTOREFERER => true,
CURLOPT_SSL_VERIFYHOST => false,
CURLOPT_SSL_VERIFYPEER => false,
CURLOPT_TIMEOUT => 15
));
$result = curl_exec($curl);
curl_close($curl);
$decoded = json_decode($result,true);
if (null === $decoded) {
return array('error'=>'json_decode() failed');
}
return $this->_state =$decoded;
}
public function refreshAccessToken($clientSecret, $refresh_token) {
if (null === $this->_clientId) {
return array('error'=>'没有获取到 client ID');
}
if (!$refresh_token) {
return array('error'=>'没有获取到refresh_token');
}
if(!$this->_state['redirect_uri']) $this->_state['redirect_uri'] = CALLBACK_URI;
$url = self::TOKEN_URL
. '?client_id=' . urlencode($this->_clientId)
. '&redirect_uri=' . urlencode($this->_state['redirect_uri'])
. '&client_secret=' . urlencode($clientSecret)
. '&grant_type=refresh_token'
. '&refresh_token=' . urlencode($refresh_token);
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => $url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_AUTOREFERER => true,
CURLOPT_SSL_VERIFYHOST => false,
CURLOPT_SSL_VERIFYPEER => false,
CURLOPT_TIMEOUT => 15
));
$result = curl_exec($curl);
curl_close($curl);
$decoded = json_decode($result,true);
if (null === $decoded) {
return array('error'=>'json_decode() failed');
}
return $this->_state = $decoded;
}
public function fetchAccountInfo() {
return $this->apiGet('/drive');
}
public function fetchChildren($path,$parameter) {
return $this->apiGet('/drive/root:'.($path?$path:'/').':/children',array(),$parameter);
}
public function fetchObject($path='') {
return $this->apiGet('/drive/root:'.($path?$path:'/'));
}
public function updateObject($path, $properties = array()) {
$path = '/drive/root:'.($path?$path:'/');
return $this->apiPatch($path, $properties);
}
public function thumbnails($path,$width,$height,$type='') {
$parameter=array('select'=>'c'.$width.'x'.$height.($type=='Crop'?'_Crop':''));
return $this->apiGet('/drive/root:'.($path?$path:'/').':/thumbnails',array(),$parameter);
}
public function createFolder($path,$name,$ondup='fail') {
if(!in_array((string)$ondup,array('rename','fail'))) $ondup='rename';
if ('' === $path) {
$path = '/drive/root/children';
}else{
$path = '/drive/root:'.$path.':/children';
}
$properties = array(
'name' => (string)($name),
'@name.conflictBehavior'=>(string)$ondup,
'folder'=>(object)array()
);
return $this->apiPost($path, (object) $properties);
}
public function createFile( $path = null,$name, $content = '') {
if (null === $path) {
$path = '';
}
$stream = fopen('php://temp', 'w+b');
if (false === $stream) {
return array('error'=>'fopen() failed');
}
if (false === fwrite($stream, $content)) {
fclose($stream);
return array('error'=>'fwrite() failed');
}
if (!rewind($stream)) {
fclose($stream);
return array('error'=>'rewind() failed');
}
$file = $this->apiPut('/drive/root:' .$path. '/' . urlencode(urldecode($name)).':/content', $stream);
fclose($stream);
return $file;
}
public function uploadFile( $path = null,$name, $file) {
if (null === $path) {
$path = '';
}
if(!$stream = fopen($file, 'r+b')){
return array('error'=>'打开文件失败');
}
$ret = $this->apiPut('/drive/root:' .$path. '/' . urlencode(urldecode($name)).':/content', $stream);
fclose($stream);
return $ret;
}
public function fetchRoot() {
return $this->fetchObject();
}
public function createSession($path,$name,$ondup='rename') {
if(!in_array((string)$ondup,array('rename','replace','fail'))) $ondup='rename';
if ('' === $path) {
$path = '/drive/root:/'.urlencode(urldecode($name)).':/upload.createSession';
}else{
$path = '/drive/root:'.$path.'/'.urlencode(urldecode($name)).':/upload.createSession';
}
$properties = array(
'item'=>array(
'@name.conflictBehavior'=>(string)$ondup,
)
);
return $this->apiPost($path, (object) $properties);
}
public function cancelSession($uploadUrl) {
$this->apiDelete($uploadUrl);
}
public function uploadFragment($uploadUrl,$file ,$contentRange) {
$stream = @fopen($file, 'r+b');
$ret = $this->apiPut($uploadUrl, $stream,array('Content-Range'=>$contentRange));
@fclose($stream);
return $ret;
}
public function createLink($path,$type='view') {
if(!in_array((string)$type,array('view','edit'))) $ondup='view';
if ('' === $path) {
$path = '/drive/root:/'.$path.':/action.createLink';
}else{
$path = '/drive/root:'.$path.':/action.createLink';
}
$properties = array(
'type'=>$type
);
return $this->apiPost($path, (object) $properties);
}
public function moveObject($path, $tpath = null) {
if (empty($path)) {
$path = '/drive/root';
}else{
$path = '/drive/root:'.($path);
}
if (empty($tpath)) {
$tpath = '/drive/root';
}else{
$tpath = '/drive/root:'.urldecode($tpath);
}
$this->apiPatch($path, (object) array(
'parentReference' => array('path'=>$tpath),
));
}
public function copyObject($path, $tpath = null) {
if (empty($path)) {
$path = '/drive/root/action.copy';
}else{
$path = '/drive/root:'.$path.':/action.copy';
}
if (empty($tpath)) {
$tpath = '/drive/root';
}else{
$tpath = '/drive/root:'.$tpath;
}
$properties = array(
'parentReference' => array('path'=>$tpath),
);
return $this->apiPost($path, (object) $properties);
}
public function deleteObject($path) {
if (empty($path)) {
$path = '/drive/root';
}else{
$path = '/drive/root:'.$path;
}
$this->apiDelete($path);
}
public function fetchShared() {
return $this->apiGet('me/skydrive/shared');
}
private static function _createCurl($path, $options = array()) {
$curl = curl_init();
$default_options = array(
CURLOPT_RETURNTRANSFER => true,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_AUTOREFERER => true,
CURLOPT_SSL_VERIFYHOST => false,
CURLOPT_SSL_VERIFYPEER => false,
CURLOPT_TIMEOUT => 1500
);
$final_options = $options + $default_options;
curl_setopt_array($curl, $final_options);
return $curl;
}
public function apiGet($path, $options = array(),$data=array()) {
$url = self::API_URL . $path
. ($data?('?'.http_build_query($data).'&'):'?')
. 'access_token=' . urlencode($this->_state['access_token']);
$curl = self::_createCurl($path, $options);
curl_setopt($curl, CURLOPT_URL, $url);
return $this->_processResult($curl);
}
public function apiPost($path, $data) {
$url = self::API_URL . $path;
$data = (object) $data;
$curl = self::_createCurl($path);
curl_setopt_array($curl, array(
CURLOPT_URL => $url,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => array(
'Content-Type: application/json', 'Authorization: Bearer ' . $this->_state['access_token']
),
CURLOPT_POSTFIELDS => json_encode($data)
));
return $this->_processResult($curl);
}
public function apiPut($path, $stream, $extraheader = null) {
$url = (strpos($path,'https://')===false)?self::API_URL . $path:$path;
$curl = self::_createCurl($path);
$stats = fstat($stream);
$headers = array(
'Authorization: Bearer ' . $this->_state['access_token']
);
foreach($extraheader as $key => $val){
$headers[] = "$key: $val";
}
$options = array(
CURLOPT_URL => $url,
CURLOPT_HTTPHEADER => $headers,
CURLOPT_PUT => true,
CURLOPT_INFILE => $stream,
CURLOPT_INFILESIZE => $stats[7] );
curl_setopt_array($curl, $options);
return $this->_processResult($curl);
}
public function apiPatch($path, $data) {
$url = self::API_URL . $path;
$data = (object) $data;
$curl = self::_createCurl($path);
curl_setopt_array($curl, array(
CURLOPT_URL => $url,
CURLOPT_CUSTOMREQUEST => 'PATCH',
CURLOPT_HTTPHEADER => array(
'Content-Type: application/json', 'Authorization: Bearer ' . $this->_state['access_token']
),
CURLOPT_POSTFIELDS => json_encode($data)
));
return $this->_processResult($curl);
}
public function apiDelete($path) {
$url = self::API_URL . $path
. '?access_token=' . urlencode($this->_state['access_token']);
$curl = self::_createCurl($path);
curl_setopt_array($curl, array(
CURLOPT_URL => $url,
CURLOPT_CUSTOMREQUEST => 'DELETE'
));
return $this->_processResult($curl);
}
public function apiMove($path, $data) {
$url = self::API_URL . $path;
$data = (object) $data;
$curl = self::_createCurl($path);
curl_setopt_array($curl, array(
CURLOPT_URL => $url,
CURLOPT_CUSTOMREQUEST => 'MOVE',
CURLOPT_HTTPHEADER => array(
'Content-Type: application/json', 'Authorization: Bearer ' . $this->_state['access_token']
),
CURLOPT_POSTFIELDS => json_encode($data)
));
return $this->_processResult($curl);
}
public function apiCopy($path, $data) {
$url = self::API_URL . $path;
$data = (object) $data;
$curl = self::_createCurl($path);
curl_setopt_array($curl, array(
CURLOPT_URL => $url,
CURLOPT_CUSTOMREQUEST => 'COPY',
CURLOPT_HTTPHEADER => array(
'Content-Type: application/json', 'Authorization: Bearer ' . $this->_state['access_token']
),
CURLOPT_POSTFIELDS => json_encode($data)
));
return $this->_processResult($curl);
}
private function _processResult($curl) {
$result = curl_exec($curl);
if (false === $result) {
return array('error'=>'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;
if (1 !== preg_match('|^application/json|', $this->_contentType)) {
return $result;
} if ('' == $result) {
return array();
}
$decoded = json_decode($result,true);
if (isset($decoded['error'])) {
return array('error'=> $decoded['error']['code'].':'.$decoded['error']['message'],'code'=>$decoded['error']['code']);
}
return $decoded;
}
}