Beispiel #1
0
 /**
  * Repacks exported document from Google.Drive, which has wrong order files in archive to show preview
  * in Google.Viewer. In Google.Viewer document should have file '[Content_Types].xml' on first position in archive.
  * @param FileData $fileData
  * @return FileData
  * @throws IO\FileNotFoundException
  * @throws IO\InvalidPathException
  * @internal
  */
 public function repackDocument(FileData $fileData)
 {
     if (!extension_loaded('zip')) {
         return null;
     }
     if (!TypeFile::isDocument($fileData->getName())) {
         return null;
     }
     $file = new IO\File($fileData->getSrc());
     if (!$file->isExists() || $file->getSize() > 15 * 1024 * 1024) {
         return null;
     }
     unset($file);
     $ds = DIRECTORY_SEPARATOR;
     $targetDir = \CTempFile::getDirectoryName(2, 'disk_repack' . $ds . md5(uniqid('di', true)));
     checkDirPath($targetDir);
     $targetDir = IO\Path::normalize($targetDir) . $ds;
     $zipOrigin = new \ZipArchive();
     if (!$zipOrigin->open($fileData->getSrc())) {
         return null;
     }
     if ($zipOrigin->getNameIndex(0) === '[Content_Types].xml') {
         $zipOrigin->close();
         return null;
     }
     if (!$zipOrigin->extractTo($targetDir)) {
         $zipOrigin->close();
         return null;
     }
     $zipOrigin->close();
     unset($zipOrigin);
     if (is_dir($targetDir) !== true) {
         return null;
     }
     $newName = md5(uniqid('di', true));
     $newFilepath = $targetDir . '..' . $ds . $newName;
     $repackedZip = new \ZipArchive();
     if (!$repackedZip->open($newFilepath, \ZipArchive::CREATE)) {
         return null;
     }
     $source = realpath($targetDir);
     $repackedZip->addFile($source . $ds . '[Content_Types].xml', '[Content_Types].xml');
     $files = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($source, \FilesystemIterator::SKIP_DOTS), \RecursiveIteratorIterator::SELF_FIRST);
     foreach ($files as $file) {
         if ($file->getBasename() === '[Content_Types].xml') {
             continue;
         }
         $file = str_replace('\\', '/', $file);
         $file = realpath($file);
         if (is_dir($file) === true) {
             $repackedZip->addEmptyDir(str_replace('\\', '/', str_replace($source . $ds, '', $file . $ds)));
         } elseif (is_file($file) === true) {
             $repackedZip->addFile($file, str_replace('\\', '/', str_replace($source . $ds, '', $file)));
         }
     }
     $repackedZip->close();
     $newFileData = new FileData();
     $newFileData->setSrc($newFilepath);
     return $newFileData;
 }
Beispiel #2
0
 /**
  * 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', "Bearer {$accessToken}");
     $endRange = $startRange + $chunkSize - 1;
     $http->setHeader('Range', "bytes={$startRange}-{$endRange}");
     if ($http->download(self::API_URL_V2 . "/files/{$fileData->getId()}/content", $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;
 }
 protected function processActionPublish()
 {
     $onlineSession = $this->getOnlineEditSessionForFile();
     if ($onlineSession) {
         $forkSession = $onlineSession;
         if ($onlineSession->getOwnerId() != $this->getUser()->getId()) {
             $forkSession = $this->forkEditSessionForCurrentUser($onlineSession);
         }
         $this->sendJsonSuccessResponse(array('editSessionId' => $forkSession->getId(), 'id' => $onlineSession->getServiceFileId(), 'link' => $onlineSession->getServiceFileLink()));
     }
     $src = $this->getFileSrcToPublish();
     if (!$src) {
         $this->errorCollection->add(array(new Error(Loc::getMessage('DISK_DOC_CONTROLLER_ERROR_COULD_NOT_GET_FILE'), self::ERROR_COULD_NOT_GET_FILE)));
         $this->sendJsonErrorResponse();
     }
     $fileData = new FileData();
     $fileData->setName($this->file->getName());
     $fileData->setMimeType(TypeFile::getMimeTypeByFilename($this->file->getName()));
     $fileData->setSrc($src);
     if (!$fileData->getSize()) {
         $fileData->setSize(filesize($fileData->getSrc()));
     }
     if ($fileData->getSize() === 0) {
         $fileData = $this->documentHandler->createBlankFile($fileData);
     } else {
         $fileData = $this->documentHandler->createFile($fileData);
     }
     if (!$fileData) {
         if ($this->documentHandler->isRequiredAuthorization()) {
             $this->sendNeedAuth();
         }
         $this->errorCollection->add($this->documentHandler->getErrors());
         $this->sendJsonErrorResponse();
     }
     //if somebody publish to google similar document
     $onlineSession = $this->getOnlineEditSessionForFile();
     if ($onlineSession) {
         $this->documentHandler->deleteFile($fileData);
         $forkSession = $onlineSession;
         if ($onlineSession->getOwnerId() != $this->getUser()->getId()) {
             $forkSession = $this->forkEditSessionForCurrentUser($onlineSession);
         }
         $this->sendJsonSuccessResponse(array('editSessionId' => $forkSession->getId(), 'id' => $onlineSession->getServiceFileId(), 'link' => $onlineSession->getServiceFileLink()));
     }
     $session = $this->addFileEditSessionByCurrentUser($fileData);
     $this->sendJsonSuccessResponse(array('editSessionId' => $session->getId(), 'id' => $fileData->getId(), 'link' => $fileData->getLinkInService()));
 }
Beispiel #4
0
 /**
  * Fix for Google. It does not get in metadata real size of empty file.
  * @param Entry             $entry
  * @param Document\FileData $fileData
  * @return bool
  * @throws IO\FileNotFoundException
  * @throws \Bitrix\Main\SystemException
  */
 protected function uploadEmptyFileFromGoogle(Entry $entry, Document\FileData $fileData)
 {
     $tmpFile = $fileData->getSrc();
     $downloadedContentSize = $entry->getDownloadedContentSize();
     $startRange = $downloadedContentSize;
     //fix for Google. It doesn't get in metadata real size of empty file.
     if (!$this->documentHandler->downloadFile($fileData)) {
         $this->errorCollection->add($this->documentHandler->getErrors());
         return false;
     }
     $realFile = new IO\File($tmpFile);
     $contentSize = $realFile->getSize();
     $entry->setContentSize($contentSize);
     $chunkSize = $contentSize - $downloadedContentSize;
     $uploadFileManager = new Bitrix24Disk\UploadFileManager();
     $uploadFileManager->setTmpFileClass(TmpFile::className())->setUser($this->documentHandler->getUserId())->setFileSize($contentSize)->setContentRange(array($startRange, $startRange + $chunkSize - 1));
     $tmpFileArray = \CFile::makeFileArray($tmpFile);
     if (!$uploadFileManager->upload($fileData->getId(), $tmpFileArray)) {
         $this->errorCollection->add($uploadFileManager->getErrors());
         return false;
     }
     $entry->linkTmpFile(TmpFile::load(array('=TOKEN' => $uploadFileManager->getToken())));
     return $entry->increaseDownloadedContentSize($chunkSize);
 }
Beispiel #5
0
 /**
  * @param FileData $fileData
  * @param string $lastStatus
  * @param array $fileMetadata
  * @return FileData|null
  */
 protected function createByResumableUpload(FileData $fileData, &$lastStatus, &$fileMetadata)
 {
     if (!$this->checkRequiredInputParams($fileData->toArray(), array('src', 'mimeType'))) {
         return null;
     }
     $accessToken = $this->getAccessToken();
     if (!$fileData->getSize()) {
         $fileData->setSize(filesize($fileData->getSrc()));
     }
     $chunkSize = 40 * 256 * 1024;
     // Chunk size restriction: All chunks must be a multiple of 256 KB (256 x 1024 bytes) in size except for the final chunk that completes the upload
     $locationForUpload = $this->getLocationForResumableUpload($fileData);
     if (!$locationForUpload) {
         return null;
     }
     $lastResponseCode = false;
     $fileMetadata = null;
     $lastRange = false;
     $transactionCounter = 0;
     $doExponentialBackoff = false;
     $exponentialBackoffCounter = 0;
     $response = array();
     while ($lastResponseCode === false || $lastResponseCode == '308') {
         $transactionCounter++;
         if ($doExponentialBackoff) {
             $sleepFor = pow(2, $exponentialBackoffCounter);
             sleep($sleepFor);
             usleep(rand(0, 1000));
             $exponentialBackoffCounter++;
             if ($exponentialBackoffCounter > 5) {
                 $lastStatus = $response['code'];
                 $this->errorCollection->add(array(new Error("Could not upload part (Exponential back off) ({$lastStatus})", self::ERROR_HTTP_RESUMABLE_UPLOAD)));
                 return null;
             }
         }
         // determining what range is next
         $rangeStart = 0;
         $rangeEnd = min($chunkSize, $fileData->getSize() - 1);
         if ($lastRange !== false) {
             $lastRange = explode('-', $lastRange);
             $rangeStart = (int) $lastRange[1] + 1;
             $rangeEnd = min($rangeStart + $chunkSize, $fileData->getSize() - 1);
         }
         $http = new HttpClient(array('socketTimeout' => 10, 'streamTimeout' => 30, 'version' => HttpClient::HTTP_1_1));
         $http->setHeader('Authorization', "Bearer {$accessToken}");
         $http->setHeader('Content-Length', (string) ($rangeEnd - $rangeStart + 1));
         $http->setHeader('Content-Type', $fileData->getMimeType());
         $http->setHeader('Content-Range', "bytes {$rangeStart}-{$rangeEnd}/{$fileData->getSize()}");
         $toSendContent = file_get_contents($fileData->getSrc(), false, null, $rangeStart, $rangeEnd - $rangeStart + 1);
         if ($http->query('PUT', $locationForUpload, $toSendContent)) {
             $response['code'] = $http->getStatus();
             $response['headers']['range'] = $http->getHeaders()->get('Range');
         }
         $doExponentialBackoff = false;
         if (isset($response['code'])) {
             // checking for expired credentials
             if ($response['code'] == "401") {
                 // todo: make sure that we also got an invalid credential response
                 //$access_token       = get_access_token(true);
                 $lastResponseCode = false;
             } else {
                 if ($response['code'] == "308") {
                     $lastResponseCode = $response['code'];
                     $lastRange = $response['headers']['range'];
                     // todo: verify x-range-md5 header to be sure
                     $exponentialBackoffCounter = 0;
                 } else {
                     if ($response['code'] == "503") {
                         // Google's letting us know we should retry
                         $doExponentialBackoff = true;
                         $lastResponseCode = false;
                     } else {
                         if ($response['code'] == "200") {
                             // we are done!
                             $lastResponseCode = $response['code'];
                         } else {
                             $lastStatus = $response['code'];
                             $this->errorCollection->add(array(new Error("Could not upload part ({$lastStatus})", self::ERROR_HTTP_RESUMABLE_UPLOAD)));
                             return null;
                         }
                     }
                 }
             }
         } else {
             $doExponentialBackoff = true;
             $lastResponseCode = false;
         }
     }
     if ($lastResponseCode != "200") {
         $lastStatus = $response['code'];
         $this->errorCollection->add(array(new Error("Could not upload final part ({$lastStatus})", self::ERROR_HTTP_RESUMABLE_UPLOAD)));
         return null;
     }
     $fileMetadata = null;
     if (isset($http)) {
         $fileMetadata = Json::decode($http->getResult());
     }
     if ($fileMetadata === null) {
         $this->errorCollection->add(array(new Error('Could not decode response as json', self::ERROR_BAD_JSON)));
         return null;
     }
     $fileData->setLinkInService($fileMetadata['alternateLink']);
     $fileData->setId($fileMetadata['id']);
     return $fileData;
 }