<?php

class Wopi
{
    static function CheckFileInfo($path,$lock)
    {
		global $_G;
        $meta=IO::getMeta($path);
		$editperm=perm_check::checkperm('edit',$meta);
		$code=self::checkLock($path,$lock);
		if(intval($code)==409) $editperm=0;//文件被锁定，不能编辑
		$FileInfoDto = array(
			'BaseFileName' => $meta['name'],
			'OwnerId' => $meta['uid'].'_'.TIMESTAMP,
			'ReadOnly' => $editperm?false:true,
			'SupportsCoauth'=>true,//，表示WOPI服务器支持多个用户同时对文件进行修改
			
			'UserFriendlyName'=>getglobal('username'),//是用户的名称，如果被锁定，WOPI客户端在某些场景可能会配置一个替代的字符串，或者展示没有名称
			'UserId'=>getglobal('uid'),//用于WOPI服务器唯一标识用户。
			'UserCanWrite'=>$editperm?true:false,//表示用户有权限改变文件
			
			'UserCanAttend'=>'true',//表示用户有权限查看这个文件的广播。广播是一个文件的活动，涉及控制一组参加者的文件的视图的一个或多个呈现者。比如一个传播者能够通过广播将幻灯片广播给多个接受者。
			'UserCanPresent'=>true,//表示用户有权限广播这个文件给那些有权限浏览文件的人。广播是一个文件的活动，涉及控制一组参加者的文件的视图的一个或多个呈现者。比如一个传播者能够通过广播将幻灯片广播给多个接受者。
			
			'SupportsCobalt'=>true,//表示WOPI服务器支持ExecuteCellStorageRequest 和ExcecuteCellStorageRelativeRequest 的操作
			
			'SHA256' => base64_encode(hash_file('sha256', IO::getStream($path), true)),
			'Size' => $meta['size'],//filesize($_SERVER['DOCUMENT_ROOT'] . '/' . $fileName),
			'Version' => $meta['md5'],//代表基于WOPI服务器的版本模式，文件的当前版本。当文件改变时，这个值一定要改变，同时对于一个给定的文件，版本的值应该从不重复。
			
		);
		//判断是否支持文件锁
		if($editperm && in_array( $meta['ext'],array('docm','docx','odt'))){
			$FileInfoDto['SupportsLocks']=true;//表示WOPI服务器支持对于文件Lock 、Unlock 、RefreshLock 和UnlockAndRelock 操作
			$FileInfoDto['SupportsGetLock']=true;//表示WOPI服务器提供了GetLock 
			
		}else{
			$FileInfoDto['SupportsLocks']=false;
		}
		//判断是否支持文件更新
		if($editperm && in_array( $meta['ext'],array('docm','docx','odt','dotx','ods','xlsb','xlsm','xlsx','odp','ppsx','pptx','odp','pptx'))){
			$FileInfoDto['SupportsUpdate']=true;//表示WOPI服务器支持对于文件的PutFile 和PutRelativeFile 操作
		}

		$jsonString = json_encode($FileInfoDto);
		header('Content-Type: application/json');
		echo $jsonString;
        
       
    }
	
    static function GetFile($path)
    {
        $filepath=IO::getStream($path);
		$meta=IO::getMeta($path);
		if(!$filesize=filesize($filepath)) $filesize=$meta['size'];
		$chunk = 10 * 1024 * 1024; 
		if(!$fp = @fopen($filepath, 'rb')) {
			exit();
		}
		dheader('Content-Disposition: attachment; filename='.$meta['name']);
		dheader('Content-Type: application/octet-stream');
		dheader('Content-Length: '.$filesize);
		@ob_end_clean();if(getglobal('gzipcompress')) @ob_start('ob_gzhandler');
		while (!feof($fp)) { 
			echo fread($fp, $chunk);
			@ob_flush();  // flush output
			@flush();
		}
		fclose($fp);
		exit();
      
    }
	 static function PutFile($path,$lock='')
    {
		$code=self::checkLock($path,$lock);
		if(intval($code)==409){
			$arr=explode('|',$code);
			header("HTTP/1.1 409 Conflict",409);
			header('X-WOPI-LOCK: '.$arr[1]);
		}else{
			$content=file_get_contents("php://input");
			IO::setFileContent($path,$content,true);	
		}
		return $code;
    }
	static function Lock($path,$lock='',$oldlock='')
	{
	
		$code=self::setLock($path,$lock,$oldlock);
		if(intval($code)==409){
			$arr=explode('|',$code);
			header("HTTP/1.1 409 Conflict",409);
			header('X-WOPI-LOCK: '.$arr[1]);
		}
		return $code;
	}
	static function unLock($path,$lock='')
	{
		$code=self::checkLock($path,$lock);
		if(intval($code)==409){
			$arr=explode('|',$code);
			header("HTTP/1.1 409 Conflict",409);
			header('X-WOPI-LOCK: '.$arr[1]);
		}else{
			self::delLock($path);
		}
		return $code;
	}
	static function setLock($path,$lock='',$oldlock='')
	{
		$rid=md5($path);
		$uid=getglobal('uid');
		$code=self::checkLock($path,$lock,$oldlock);
		if($code==200){	
			$filepath=getglobal('setting/attachdir').'/cache/'.$rid.'.lock';
			if(!file_put_contents($filepath,$lock)){
				$code=500;
			}
		}
		return $code;
	}
	static function getLock($path)
	{
		$lock=self::getLockStr($path);
		header('X-WOPI-LOCK: '.$lock);
		return $lock;
	}
	
	static function checkLock($path,$lock='',$oldlock=''){
		$code=200;
		if(empty($lock)){
			$code=400;
		}elseif($lock1=self::getLockStr($path)){
			if($lockarr1=json_decode($lock1,true)){
				$lockarr=json_decode(($oldlock?$oldlock:$lock),true);
				if($lockarr['S']!=$lockarr1['S']){
					$code='409'.'|'.$lock1;
				}
			}elseif($lock1!=$lock){
				$code='409'.'|'.$lock1;
			}
		}
		return $code;
	}
	static function getLockStr($path,$decode=false)
	{
		$rid=md5($path);
		$filepath=getglobal('setting/attachdir').'/cache/'.$rid.'.lock';
		$mtime=filemtime($filepath);
		if($mtime && TIMESTAMP-$mtime>30*60) return '';//超过30分钟自动失效
		if($json=file_get_contents($filepath)){
			return $decode?json_decode($json):$json;
		}
		return '';
	}
	static function delLock($path)
	{
		$rid=md5($path);
		$filepath=getglobal('setting/attachdir').'./cache/'.$rid.'.lock';
		if(@unlink($filepath)) return true;
		return false;
	}
	
	/*
		$lock        : 文件锁内容，后续通过内容来标识是否有解锁权限；
		$ooServerURL : 文档服务器地址；如http://oos.dzz.com
		$path        : 文件路径;
	*/
	static function GenerateFileLink($path,$ooServerURL,$lock='')
	{
		$code=200;
		$meta=IO::getMeta($path);
		if($meta['error']) return $meta;
		$editperm=perm_check::checkperm('edit',$meta);
		$code=self::checkLock($path,$lock);
		if(intval($code)==409) $editperm=0;//文件被锁定，不能编辑
		$ooServerURL=rtrim($ooServerURL,'/').'/hosting/discovery';
		
		$fileExtension = $meta['ext'];
		$guid = dzzencode(getglobal('uid').'|'.$lock);
		$wopi_url_temlpate = "WOPISrc={0}&access_token={1}";
		$fileID=dzzencode($meta['path']);
	    $discovery=self::getActionByDiscovery($ooServerURL);
		if($discovery['error']) return  $discovery;
		
		if(!in_array($fileExtension,$discovery['exts'])){
			return array('error'=>'filetype error');
		}
		
		if($editperm){
			if(in_array($fileExtension,array_keys($discovery['actions']['edit']))){
				$action='edit';
			}elseif(in_array($fileExtension,array_keys($discovery['actions']['view']))){
				$action='view';
			}
		}else{
			if(in_array($fileExtension,array_keys($discovery['actions']['view']))){
				$action='view';
			}elseif(in_array($fileExtension,array_keys($discovery['actions']['edit']))){
				$action='edit';
			}
		}
		if( defined('IN_MOBILE') && in_array($fileExtension,array_keys($discovery['actions']['mobileView']))){
			$action='mobileView';
		}
				
		$urlsrc=$discovery['actions'][$action][$fileExtension];
		
		$parts = parse_url($ooServerURL);
		if (strtolower($parts['scheme'])=='https') {
		
			$webSocketProtocol = "wss://";
		} else {
		
			$webSocketProtocol = "ws://";
		}
		$protocol=$_SERVER['SERVER_PROTOCOL'];
		$parts = parse_url($ooServerURL);
		if (strtolower($parts['scheme'])=='https') {
			$protocol = "https";
			$webSocketProtocol = "wss://";
		} else {
			$protocol = "http";
			$webSocketProtocol = "ws://";
		}
		
		$webSocket = sprintf("%s%s%s",$webSocketProtocol,$parts['host'],isset($parts['port']) ? ":" . $parts['port'] : "");
																		 
		$fileUrl = urlencode(getglobal('siteurl'). "wopi/files/" . $fileID);
		$requestUrl = preg_replace("/<.*>/", "", $urlsrc);
		$requestUrl = $requestUrl . str_replace('{1}', $guid, $wopi_url_temlpate);
		$requestUrl = str_replace("{0}", $fileUrl, $requestUrl).'&ui=zh-CN&rs=zh-CN'; 
		$wopiSrc=getglobal('siteurl'). "wopi/files/$fileID?access_token=$guid&ui=zh-CN&rs=zh-CN";
		$ret=array(
			'fileID'=>$fileID,
			'protocol'=>$protocol,
			'wopiSrc'=>$wopiSrc,
			'urlsrc'=>$urlsrc,
			'webSocket'=>$webSocket,
			'fullsrc'=>$requestUrl,
			'access_token'=>$guid,
			'action'=>$action,
			'lockstatus'=>$code,//检测锁状态
			//'discovery'=>$discovery
		);
		return $ret; //LINK SHOW TEST
	}
	private function getActionByDiscovery($oosDiscoveryUrl){
		$cachefile=getglobal('setting/attachdir').'./cache/'.md5($oosDiscoveryUrl).'.cache';
		if(file_exists($cachefile)){
			$sourceXml=file_get_contents($cachefile);
		}
		if(!$sourceXml){
			$arrContextOptions = array(
				"ssl" => array(
					"verify_peer" => false,
					"verify_peer_name" => false,
				),
			);
			if(!$sourceXml = file_get_contents($oosDiscoveryUrl, false, stream_context_create($arrContextOptions))) {
				$error = error_get_last();
				return array('error'=>"HTTP request failed. Error was: " . $error['message']);
			}
			str_replace('"', "'", $sourceXml);
			@file_put_contents($cachefile,$sourceXml);
		}
		
		$xml = simplexml_load_string($sourceXml);
		$elements = $xml->xpath("net-zone/app/action");
		$actions=$exts=array();
		foreach($elements as  $value){
			$temparr=array(
				'ext'=>(string)$value['ext'],
				'action'=>(string)$value['name'],
				'urlsrc'=>(string)$value['urlsrc']
			);
			if(empty($temparr['ext'])) continue;
			//if(isset($actions[$temparr['action']][$temparr['ext']])) continue;
			$exts[$temparr['ext']]=$temparr['ext'];
			$actions[$temparr['action']][$temparr['ext']]=$temparr['urlsrc'];
		}
		$ret= array(
					'exts'=>array_keys($exts),
					'actions'=>$actions
				   );
		return $ret;
	}
}
