Your IP : 3.142.152.51


Current Path : /var/www/axolotl/data/www/krym.axolotls.ru/bitrix/modules/disk/lib/document/
Upload File :
Current File : /var/www/axolotl/data/www/krym.axolotls.ru/bitrix/modules/disk/lib/document/yandexdiskhandler.php

<?php

namespace Bitrix\Disk\Document;

use Bitrix\Disk\Driver;
use Bitrix\Disk\Internals\Error\Error;
use Bitrix\Disk\SpecificFolder;
use Bitrix\Main\Loader;
use Bitrix\Main\Localization\Loc;
use Bitrix\Main\Web\HttpClient;
use Bitrix\Main\Web\Json;

Loc::loadMessages(__FILE__);

class YandexDiskHandler extends DocumentHandler
{
	const API_URL_V1 = 'https://cloud-api.yandex.net/v1/disk';

	const SPECIFIC_FOLDER_CODE = SpecificFolder::CODE_FOR_IMPORT_YANDEX;

	const ERROR_METHOD_IS_NOT_SUPPORTED   = 'DISK_YD_HANDLER_22001';
	const ERROR_NOT_INSTALLED_SOCSERV     = 'DISK_YD_HANDLER_22002';
	const ERROR_BAD_JSON                  = 'DISK_YD_HANDLER_22005';
	const ERROR_HTTP_DELETE_FILE          = 'DISK_YD_HANDLER_22006';
	const ERROR_HTTP_DOWNLOAD_FILE        = 'DISK_YD_HANDLER_22007';
	const ERROR_HTTP_GET_METADATA         = 'DISK_YD_HANDLER_22008';
	const ERROR_HTTP_FILE_INTERNAL        = 'DISK_YD_HANDLER_22009';
	const ERROR_COULD_NOT_VIEW_FILE       = 'DISK_YD_HANDLER_22013';
	const ERROR_SHARED_EDIT_LINK          = 'DISK_YD_HANDLER_22014';
	const ERROR_SHARED_EMBED_LINK         = 'DISK_YD_HANDLER_22015';
	const ERROR_COULD_NOT_FIND_EMBED_LINK = 'DISK_YD_HANDLER_22016';
	const ERROR_HTTP_LIST_FOLDER          = 'DISK_YD_HANDLER_22017';

	/**
	 * @inheritdoc
	 */
	public static function getCode()
	{
		return 'yandexdisk';
	}

	/**
	 * @inheritdoc
	 */
	public static function getName()
	{
		return Loc::getMessage('DISK_YANDEX_DISK_HANDLER_NAME');
	}

	/**
	 * Public name storage of documents. May show in user interface.
	 * @throws \Bitrix\Main\NotImplementedException
	 * @return string
	 */
	public static function getStorageName()
	{
		return static::getName();
	}

	/**
	 * Execute this method for check potential possibility get access token.
	 * @return bool
	 * @throws \Bitrix\Main\LoaderException
	 */
	public function checkAccessibleTokenService()
	{
		if(!Loader::includeModule('socialservices'))
		{
			$this->errorCollection->add(array(new Error(Loc::getMessage('DISK_YANDEX_HANDLER_ERROR_NOT_INSTALLED_SOCSERV'), self::ERROR_NOT_INSTALLED_SOCSERV)));
			return false;
		}
		$authManager = new \CSocServAuthManager();
		$socNetServices = $authManager->getActiveAuthServices(array());

		return !empty($socNetServices[\CSocServYandexAuth::ID]);
	}


	/**
	 * Return link for authorize user in external service.
	 * @param string $mode
	 * @return string
	 */
	public function getUrlForAuthorizeInTokenService($mode = 'modal')
	{
		if(!Loader::includeModule('socialservices'))
		{
			$this->errorCollection->add(array(new Error(Loc::getMessage('DISK_YANDEX_HANDLER_ERROR_NOT_INSTALLED_SOCSERV'), self::ERROR_NOT_INSTALLED_SOCSERV)));
			return false;
		}

		$yandexOAuth = new \CSocServYandexAuth($this->userId);
		if($mode === 'opener')
		{
			return $yandexOAuth->getUrl(
				'opener',
				null,
				array('BACKURL' => '#external-auth-ok')
			);
		}

		return $yandexOAuth->getUrl('modal');
	}

	/**
	 * Request and store access token (self::accessToken) for self::userId
	 * @return $this
	 */
	public function queryAccessToken()
	{
		if(!Loader::includeModule('socialservices'))
		{
			$this->errorCollection->add(array(new Error(Loc::getMessage('DISK_YANDEX_HANDLER_ERROR_NOT_INSTALLED_SOCSERV'), self::ERROR_NOT_INSTALLED_SOCSERV)));
			return false;
		}

		$yandexOAuth = new \CSocServYandexAuth($this->userId);
		//this bug. SocServ fill entityOAuth in method getUrl.....
		$yandexOAuth->getUrl('modal');
		$this->accessToken = $yandexOAuth->getStorageToken();

		return $this;
	}

	/**
	 * Create new blank file in cloud service.
	 * It is not necessary set shared rights on file.
	 * @param FileData $fileData
	 * @return FileData|null
	 */
	public function createBlankFile(FileData $fileData)
	{
		$this->errorCollection->add(array(
			new Error(Loc::getMessage('DISK_YANDEX_DISK_HANDLER_ERROR_METHOD_IS_NOT_SUPPORTED'), self::ERROR_METHOD_IS_NOT_SUPPORTED)
		));
		return null;
	}

	/**
	 * Create file in cloud service by upload from us server.
	 * Necessary set shared rights on file for common work.
	 *
	 * @param FileData $fileData
	 * @return FileData|null
	 */
	public function createFile(FileData $fileData)
	{
		$this->errorCollection->add(array(
			new Error(Loc::getMessage('DISK_YANDEX_DISK_HANDLER_ERROR_METHOD_IS_NOT_SUPPORTED'), self::ERROR_METHOD_IS_NOT_SUPPORTED)
		));
		return null;
	}

	/**
	 * Download file from cloud service by FileData::id, put contents in FileData::src
	 * @param FileData $fileData
	 * @return FileData|null
	 */
	public function downloadFile(FileData $fileData)
	{
		$this->errorCollection->add(array(
			new Error(Loc::getMessage('DISK_YANDEX_DISK_HANDLER_ERROR_METHOD_IS_NOT_SUPPORTED'), self::ERROR_METHOD_IS_NOT_SUPPORTED)
		));
		return null;
	}

	/**
	 * Gets a file's metadata by ID.
	 *
	 * @param FileData $fileData
	 * @return array|null Describes file (id, title, size)
	 */
	public function getFileMetadata(FileData $fileData)
	{
		if(!$this->checkRequiredInputParams($fileData->toArray(), array(
			'id',
		)))
		{
			return null;
		}

		$fileId = $this->getForApiDecodedId($fileData->getId());

		$http = new HttpClient(array(
			'socketTimeout' => 10,
			'streamTimeout' => 30,
			'version' => HttpClient::HTTP_1_1,
		));
		$http->setHeader('Content-Type', 'application/json; charset=UTF-8');
		$http->setHeader('Authorization', "OAuth {$this->getAccessToken()}");

		if($http->get(self::API_URL_V1 . "/resources?path={$fileId}") === false)
		{
			$errorString = implode('; ', array_keys($http->getError()));
			$this->errorCollection->add(array(
				new Error($errorString, self::ERROR_HTTP_GET_METADATA)
			));
			return null;
		}

		if(!$this->checkHttpResponse($http))
		{
			return null;
		}

		$metaData = Json::decode($http->getResult());
		if($metaData === null)
		{
			$this->errorCollection->add(array(
				new Error('Could not decode response as json', self::ERROR_BAD_JSON)
			));
			return null;
		}

		return $this->normalizeMetadata($metaData);
	}

	public function getDownloadUrl(FileData $fileData)
	{
		if(!$this->checkRequiredInputParams($fileData->toArray(), array(
			'id',
		)))
		{
			return null;
		}

		$fileId = $this->getForApiDecodedId($fileData->getId());

		$http = new HttpClient(array(
			'socketTimeout' => 10,
			'streamTimeout' => 30,
			'version' => HttpClient::HTTP_1_1,
		));
		$http->setHeader('Content-Type', 'application/json; charset=UTF-8');
		$http->setHeader('Authorization', "OAuth {$this->getAccessToken()}");

		if($http->get(self::API_URL_V1 . "/resources/download?path={$fileId}") === false)
		{
			$errorString = implode('; ', array_keys($http->getError()));
			$this->errorCollection->add(array(
				new Error($errorString, self::ERROR_HTTP_GET_METADATA)
			));
			return null;
		}

		if(!$this->checkHttpResponse($http))
		{
			return null;
		}

		$downloadData = Json::decode($http->getResult());
		if($downloadData === null || empty($downloadData['href']))
		{
			$this->errorCollection->add(array(
				new Error('Could not decode response as json', self::ERROR_BAD_JSON)
			));
			return null;
		}

		return $downloadData['href'];
	}

	/**
	 * Download part of file from cloud service by FileData::id, put contents in FileData::src
	 * @param FileData $fileData
	 * @param          $startRange
	 * @param          $chunkSize
	 * @return FileData|null
	 */
	public function downloadPartFile(FileData $fileData, $startRange, $chunkSize)
	{
		if(!$this->checkRequiredInputParams($fileData->toArray(), array(
			'id', 'src',
		)))
		{
			return null;
		}
		$accessToken = $this->getAccessToken();

		@set_time_limit(0);
		$http = new HttpClient(array(
			'socketTimeout' => 10,
			'streamTimeout' => 30,
			'version' => HttpClient::HTTP_1_1,
		));

		$http->setHeader('Authorization', "OAuth {$accessToken}");

		$endRange = $startRange + $chunkSize - 1;
		$http->setHeader('Range', "bytes={$startRange}-{$endRange}");

		if($http->download($this->getDownloadUrl($fileData), $fileData->getSrc()) === false)
		{
			$errorString = implode('; ', array_keys($http->getError()));
			$this->errorCollection->add(array(
				new Error($errorString, self::ERROR_HTTP_DOWNLOAD_FILE)
			));
			return null;
		}

		return $fileData;
	}

	/**
	 * Delete file from cloud service by FileData::id
	 * @param FileData $fileData
	 * @return bool
	 */
	public function deleteFile(FileData $fileData)
	{
		$this->errorCollection->add(array(
			new Error(Loc::getMessage('DISK_YANDEX_DISK_HANDLER_ERROR_METHOD_IS_NOT_SUPPORTED'), self::ERROR_METHOD_IS_NOT_SUPPORTED)
		));
		return null;
	}


	/**
	 * Get url for showing preview file.
	 * @param FileData $fileData
	 * @return string|null
	 */
	public function getDataForViewFile(FileData $fileData)
	{
		$this->errorCollection->add(array(
			new Error(Loc::getMessage('DISK_YANDEX_DISK_HANDLER_ERROR_METHOD_IS_NOT_SUPPORTED'), self::ERROR_METHOD_IS_NOT_SUPPORTED)
		));
		return null;
	}

	/**
	 * Lists folder contents
	 * @param $path
	 * @param $folderId
	 * @return mixed
	 */
	public function listFolder($path, $folderId)
	{
		if($path === '/')
		{
			$folderId = urlencode('/');
		}
		else
		{
			$folderId = $this->getForApiDecodedId($folderId);
		}

		$http = new HttpClient(array(
			'socketTimeout' => 10,
			'streamTimeout' => 30,
			'version' => HttpClient::HTTP_1_1,
		));
		$http->setHeader('Content-Type', 'application/json; charset=UTF-8');
		$http->setHeader('Authorization', "OAuth {$this->getAccessToken()}");

		if($http->get(self::API_URL_V1 . "/resources?path={$folderId}&limit=200") === false)
		{
			$errorString = implode('; ', array_keys($http->getError()));
			$this->errorCollection->add(array(
				new Error($errorString, self::ERROR_HTTP_LIST_FOLDER)
			));
			return null;
		}

		if(!$this->checkHttpResponse($http))
		{
			return null;
		}

		$items = Json::decode($http->getResult());
		if($items === null)
		{
			$this->errorCollection->add(array(
				new Error('Could not decode response as json', self::ERROR_BAD_JSON)
			));
			return null;
		}
		if(!isset($items['_embedded']['items']))
		{
			$this->errorCollection->add(array(
				new Error('Could not find items in response', self::ERROR_HTTP_LIST_FOLDER)
			));
			return null;
		}

		$reformatItems = array();
		foreach($items['_embedded']['items'] as $item)
		{
			$isFolder = $item['type'] === 'dir';
			$dateTime = new \DateTime($item['modified']);
			$itemPath = substr($item['path'], 5); //disk:
			$pseudoId = base64_encode($itemPath);
			$reformatItems[$pseudoId] = array(
				'id' => $pseudoId,
				'name' => $item['name'],
				'type' => $isFolder? 'folder' : 'file',

				'size' => $isFolder? '' : \CFile::formatSize($item['size']),
				'sizeInt' => $isFolder? '' : $item['size'],
				'modifyBy' => '',
				'modifyDate' => $dateTime->format('d.m.Y'),
				'modifyDateInt' => $dateTime->getTimestamp(),
				'provider' => static::getCode(),
			);

			if(!$isFolder)
			{
				$reformatItems[$pseudoId]['storage'] = '';
				$reformatItems[$pseudoId]['ext'] = getFileExtension($item['name']);
			}
		}
		unset($item);

		return $reformatItems;
	}

	protected function getEncodedId($path)
	{
		return base64_encode($path);
	}

	protected function getDecodedId($path)
	{
		return base64_decode($path);
	}

	protected function getForApiDecodedId($path)
	{
		return Driver::getInstance()->getUrlManager()->encodeUrn($this->getDecodedId($path));
	}

	/**
	 * Returns normalized metadata.
	 *
	 * @param array $metaData
	 * @return array
	 */
	protected function normalizeMetadata($metaData)
	{
		return array(
			'id' => $this->getEncodedId($metaData['path']),
			'name' => $metaData['name'],
			'size' => $metaData['size'],
			'mimeType' => $metaData['mime_type'],
			'etag' => $metaData['md5'],
			'original' => $metaData,
		);
	}
}