/** * Create new genesis document * @param File $file * */ public function __construct(File $file) { $view = $file->getOwnerView(); $path = $file->getPath(); $owner = $file->getOwner(); $this->view = new View('/' . $owner); if (!$this->view->file_exists(self::DOCUMENTS_DIRNAME)) { $this->view->mkdir(self::DOCUMENTS_DIRNAME); } $this->validate($view, $path); $this->hash = $view->hash('sha1', $path, false); $this->path = self::DOCUMENTS_DIRNAME . '/' . $this->hash . '.odt'; if (!$this->view->file_exists($this->path)) { //copy new genesis to /user/documents/{hash}.odt // get decrypted content $content = $view->file_get_contents($path); $mimetype = $view->getMimeType($path); $data = Filter::read($content, $mimetype); $this->view->file_put_contents($this->path, $data['content']); } try { $this->validate($this->view, $this->path); } catch (\Exception $e) { throw new \Exception('Failed to copy genesis'); } }
public function render() { if ($this->getStatus() === Http::STATUS_NOT_FOUND) { return ''; } $info = $this->view->getFileInfo($this->path); $this->ETag = $info['etag']; $content = $this->view->file_get_contents($this->path); $data = \OCA\Documents\Filter::read($content, $info['mimetype']); $size = strlen($data['content']); if (isset($this->request->server['HTTP_RANGE']) && !is_null($this->request->server['HTTP_RANGE'])) { $isValidRange = preg_match('/^bytes=\\d*-\\d*(,\\d*-\\d*)*$/', $this->request->server['HTTP_RANGE']); if (!$isValidRange) { return $this->sendRangeNotSatisfiable($size); } $ranges = explode(',', substr($this->request->server['HTTP_RANGE'], 6)); foreach ($ranges as $range) { $parts = explode('-', $range); if ($parts[0] === '' && $parts[1] == '') { $this->sendNotSatisfiable($size); } if ($parts[0] === '') { $start = $size - $parts[1]; $end = $size - 1; } else { $start = $parts[0]; $end = $parts[1] === '' ? $size - 1 : $parts[1]; } if ($start > $end) { $this->sendNotSatisfiable($size); } $buffer = substr($data['content'], $start, $end - $start); $md5Sum = md5($buffer); // send the headers and data $this->addHeader('Content-Length', $end - $start); $this->addHeader('Content-md5', $md5Sum); $this->addHeader('Accept-Ranges', 'bytes'); $this->addHeader('Content-Range', 'bytes ' . $start . '-' . $end . '/' . $size); $this->addHeader('Connection', 'close'); $this->addHeader('Content-Type', $data['mimetype']); $this->addContentDispositionHeader(); return $buffer; } } $this->addHeader('Content-Type', $data['mimetype']); $this->addContentDispositionHeader(); $this->addHeader('Content-Length', $size); return $data['content']; }
/** * Send the whole file content as a response */ public function sendResponse() { $mimetype = $this->getMimeType(); $content = $this->view->file_get_contents($this->filepath); $data = \OCA\Documents\Filter::read($content, $mimetype); header('Content-Type:' . $data['mimetype']); $encodedName = rawurlencode($this->getFilename()); if (preg_match("/MSIE/", $_SERVER["HTTP_USER_AGENT"])) { header('Content-Disposition: attachment; filepath="' . $encodedName . '"'); } else { header('Content-Disposition: attachment; filepath*=UTF-8\'\'' . $encodedName . '; filepath="' . $encodedName . '"'); } header('Content-Length: ' . strlen($data['content'])); \OC_Util::obEnd(); echo $data['content']; }
/** * Start a editing session or return an existing one * @param string $uid of the user starting a session * @param \OCA\Documents\File $file - file object * @return array * @throws \Exception */ public static function start($uid, $file) { // Create a directory to store genesis $genesis = new \OCA\Documents\Genesis($file); list($ownerView, $path) = $file->getOwnerViewAndPath(); $mimetype = $ownerView->getMimeType($path); if (!Filter::isSupportedMimetype($mimetype)) { throw new \Exception($path . ' is ' . $mimetype . ' and is not supported by Documents app'); } $oldSession = new Session(); $oldSession->loadBy('file_id', $file->getFileId()); //If there is no existing session we need to start a new one if (!$oldSession->hasData()) { $newSession = new Session(array($genesis->getPath(), $genesis->getHash(), $file->getOwner(), $file->getFileId())); if (!$newSession->insert()) { throw new \Exception('Failed to add session into database'); } } $sessionData = $oldSession->loadBy('file_id', $file->getFileId())->getData(); $memberColor = \OCA\Documents\Helper::getMemberColor($uid); $member = new \OCA\Documents\Db\Member(array($sessionData['es_id'], $uid, $memberColor, time(), intval($file->isPublicShare()), $file->getToken())); if (!$member->insert()) { throw new \Exception('Failed to add member into database'); } $sessionData['member_id'] = (string) $member->getLastInsertId(); // Do we have OC_Avatar in out disposal? if (\OC_Config::getValue('enable_avatars', true) !== true) { $imageUrl = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAAAAACH5BAAAAAAALAAAAAABAAEAAAICTAEAOw=='; } else { $imageUrl = $uid; } $displayName = $file->isPublicShare() ? $uid . ' ' . \OCA\Documents\Db\Member::getGuestPostfix() : \OCP\User::getDisplayName($uid); $userId = $file->isPublicShare() ? $displayName : \OCP\User::getUser(); $op = new \OCA\Documents\Db\Op(); $op->addMember($sessionData['es_id'], $sessionData['member_id'], $displayName, $userId, $memberColor, $imageUrl); $sessionData['title'] = basename($path); $fileInfo = $ownerView->getFileInfo($path); $sessionData['permissions'] = $fileInfo->getPermissions(); return $sessionData; }
/** * Send the requested parts of the file */ public function sendResponse() { if (!preg_match('/^bytes=\\d*-\\d*(,\\d*-\\d*)*$/', $_SERVER['HTTP_RANGE'])) { $this->sendNotSatisfiable(); } $mimetype = $this->getMimeType(); $content = $this->view->file_get_contents($this->filepath); $data = \OCA\Documents\Filter::read($content, $mimetype); $size = strlen($data['content']); $ranges = explode(',', substr($_SERVER['HTTP_RANGE'], 6)); foreach ($ranges as $range) { $parts = explode('-', $range); if ($parts[0] === '' && $parts[1] == '') { $this->sendNotSatisfiable(); } if ($parts[0] === '') { $start = $size - $parts[1]; $end = $size - 1; } else { $start = $parts[0]; $end = $parts[1] === '' ? $size - 1 : $parts[1]; } if ($start > $end) { $this->sendNotSatisfiable(); } $buffer = substr($data['content'], $start, $end - $start); $md5Sum = md5($buffer); // send the headers and data header("Content-Length: " . ($end - $start)); header("Content-md5: " . $md5Sum); header("Accept-Ranges: bytes"); header('Content-Range: bytes ' . $start . '-' . $end . '/' . $size); header("Connection: close"); header("Content-type: " . $data['mimetype']); header('Content-Disposition: attachment; filename=' . $this->getFilename()); \OC_Util::obEnd(); echo $buffer; flush(); } }
/** * @NoAdminRequired * @PublicPage * Store the document content to its origin */ public function save() { try { $esId = $this->request->server['HTTP_WEBODF_SESSION_ID']; if (!$esId) { throw new \Exception('Session id can not be empty'); } $memberId = $this->request->server['HTTP_WEBODF_MEMBER_ID']; $currentMember = new Db\Member(); $currentMember->load($memberId); //check if member belongs to the session if ($esId != $currentMember->getEsId()) { throw new \Exception($memberId . ' does not belong to session ' . $esId); } // Extra info for future usage // $sessionRevision = $this->request->server['HTTP_WEBODF_SESSION_REVISION']; //NB ouch! New document content is passed as an input stream content $stream = fopen('php://input', 'r'); if (!$stream) { throw new \Exception('New content missing'); } $content = stream_get_contents($stream); $session = new Db\Session(); $session->load($esId); if (!$session->getEsId()) { throw new \Exception('Session does not exist'); } try { if ($currentMember->getIsGuest()) { $file = File::getByShareToken($currentMember->getToken()); } else { $file = new File($session->getFileId()); } list($view, $path) = $file->getOwnerViewAndPath(true); } catch (\Exception $e) { //File was deleted or unshared. We need to save content as new file anyway //Sorry, but for guests it would be lost :( if ($this->uid) { $view = new View('/' . $this->uid . '/files'); $dir = \OCP\Config::getUserValue($this->uid, 'documents', 'save_path', ''); $path = Helper::getNewFileName($view, $dir . 'New Document.odt'); } else { throw $e; } } $member = new Db\Member(); $members = $member->getActiveCollection($esId); $memberIds = array_map(function ($x) { return $x['member_id']; }, $members); // Active users except current user $memberCount = count($memberIds) - 1; if ($view->file_exists($path)) { $currentHash = sha1($view->file_get_contents($path)); if (!Helper::isVersionsEnabled() && $currentHash !== $session->getGenesisHash()) { // Original file was modified externally. Save to a new one $path = Helper::getNewFileName($view, $path, '-conflict'); } $mimetype = $view->getMimeType($path); } else { $mimetype = Storage::MIMETYPE_LIBREOFFICE_WORDPROCESSOR; } $data = Filter::write($content, $mimetype); if ($view->file_put_contents($path, $data['content'])) { // Not a last user if ($memberCount > 0) { // Update genesis hash to prevent conflicts $this->logger->debug('Update hash', array('app' => $this->appName)); $session->updateGenesisHash($esId, sha1($data['content'])); } else { // Last user. Kill session data Db\Session::cleanUp($esId); } $view->touch($path); } $response = array('status' => 'success'); } catch (\Exception $e) { $this->logger->warning('Saving failed. Reason:' . $e->getMessage(), array('app' => $this->appName)); \OC_Response::setStatus(500); $response = array(); } return $response; }
public function __construct($mimeSpec) { $this->readSpec = $mimeSpec['read']; $this->writeSpec = $mimeSpec['write']; \OCA\Documents\Filter::add($mimeSpec['write']['target'], $this); }
/** * @NoAdminRequired */ public function getSupportedMimes() { return array('status' => 'success', 'mimes' => Filter::getAll()); }
protected function initViews() { $this->ownerView = new View('/' . $this->owner); $this->ownerViewFiles = new View('/' . $this->owner . '/files'); $this->path = $this->ownerView->getPath($this->fileId); $this->pathFiles = $this->ownerViewFiles->getPath($this->fileId); if (!$this->path || !$this->pathFiles) { throw new \Exception($this->fileId . ' can not be resolved'); } if (!$this->ownerView->file_exists($this->path)) { throw new \Exception($this->path . ' doesn\'t exist'); } if (!$this->ownerViewFiles->file_exists($this->pathFiles)) { throw new \Exception($this->pathFiles . ' doesn\'t exist'); } if (!$this->ownerView->is_file($this->path)) { throw new \Exception('Object ' . $this->path . ' is not a file.'); } //TODO check if it is a valid odt $mimetype = $this->ownerView->getMimeType($this->path); if (!Filter::isSupportedMimetype($mimetype)) { throw new \Exception($this->path . ' is ' . $mimetype . ' and is not supported by Documents app'); } }