tao-test/app/taoItems/models/classes/media/LocalItemSource.php

356 lines
10 KiB
PHP

<?php
/**
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; under version 2
* of the License (non-upgradable).
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Copyright (c) 2014 (original work) Open Assessment Technologies SA;
*
*
*/
namespace oat\taoItems\model\media;
use common_exception_Error;
use oat\oatbox\filesystem\Directory;
use oat\oatbox\filesystem\File;
use oat\tao\model\media\MediaManagement;
use oat\tao\model\media\mediaSource\DirectorySearchQuery;
use Psr\Http\Message\StreamInterface;
use tao_helpers_File;
use taoItems_models_classes_ItemsService;
/**
* This media source gives access to files that are part of the item
* and are addressed in a relative way
*/
class LocalItemSource implements MediaManagement
{
private $item;
private $lang;
protected $itemService;
public function __construct($data)
{
$this->item = (isset($data['item'])) ? $data['item'] : null;
$this->lang = (isset($data['lang'])) ? $data['lang'] : '';
}
/**
* @return \core_kernel_classes_Resource
*/
public function getItem()
{
return $this->item;
}
/**
* @throws \common_Exception
* @throws \tao_models_classes_FileNotFoundException
* @throws common_exception_Error
*/
public function getDirectories(DirectorySearchQuery $params): array
{
return $this->searchDirectories(
$params->getParentLink(),
$params->getFilter(),
$params->getDepth(),
$params->getChildrenLimit()
);
}
/**
* Get a array representing the tree of directory
* @deprecated in favor of MediaBrowser::getDirectories
* @throws \common_Exception
* @throws \tao_models_classes_FileNotFoundException
* @throws common_exception_Error
*/
public function getDirectory($parentLink = '', $acceptableMime = [], $depth = 1)
{
return $this->searchDirectories($parentLink, $acceptableMime, $depth, 0);
}
/**
* Return file info regarding a file
*
* @see \oat\tao\model\media\MediaBrowser::getFileInfo
* @param string $link
* @return array
* @throws \tao_models_classes_FileNotFoundException
* @throws common_exception_Error
*/
public function getFileInfo($link)
{
return $this->getInfoFromFile($this->getFile($link));
}
/**
* Method should be used only after uploading local file, when metadata like file size and mime type
* of remote uploaded file are not critical. To get more precise info about remote file use getInfoFromFile().
*
* In case of using S3 Flysystem adapter there might be latency and file cannot be accessed right after upload.
*
* @param File $file
* @param string $sourceFile
* @return array
* @throws \common_Exception
* @throws \tao_models_classes_FileNotFoundException
*/
protected function getInfoFromSource(File $file, string $sourceFile): array
{
if (file_exists($sourceFile)) {
$link = $this->getItemDirectory()->getRelPath($file);
return [
'name' => $file->getBasename(),
'uri' => $link,
'mime' => tao_helpers_File::getMimeType($sourceFile),
'filePath' => $link,
'size' => filesize($sourceFile),
];
} else {
return $this->getInfoFromFile($file);
}
}
protected function getInfoFromFile(File $file)
{
$link = $this->getItemDirectory()->getRelPath($file);
return [
'name' => $file->getBasename(),
'uri' => $link,
'mime' => $file->getMimeType(),
'filePath' => $link,
'size' => $file->getSize(),
];
}
/**
* Copy file content to temp file. Path is return to be downloaded
*
* @see \oat\tao\model\media\MediaBrowser::download
* @param string $link
* @return string
* @throws \common_Exception
* @throws \tao_models_classes_FileNotFoundException
* @throws common_exception_Error
*/
public function download($link)
{
$file = $this->getFile($link);
$relPath = $this->getItemDirectory()->getRelPath($file);
$tmpDir = rtrim(\tao_helpers_File::createTempDir(), '/');
$tmpFile = $tmpDir . $relPath;
if (! is_dir(dirname($tmpFile))) {
mkdir(dirname($tmpFile), 0755, true);
}
if (($resource = fopen($tmpFile, 'w')) !== false) {
stream_copy_to_stream($file->readStream(), $resource);
fclose($resource);
return $tmpFile;
}
throw new \common_Exception('Unable to write "' . $link . '" into tmp folder("' . $tmpFile . '").');
}
/**
* Return filename of given path
*
* @see \oat\tao\model\media\MediaBrowser::getBaseName
* @param string $link
* @return string
*/
public function getBaseName($link)
{
return basename($link);
}
/**
* Add content to file
*
* @see \oat\tao\model\media\MediaManagement::add
* @param string $source
* @param string $fileName
* @param string $parent
* @return array
* @throws \common_Exception
* @throws \tao_models_classes_FileNotFoundException
*/
public function add($source, $fileName, $parent)
{
if (! \tao_helpers_File::securityCheck($fileName, true)) {
throw new \common_Exception('Unsecured filename "' . $fileName . '"');
}
if (($resource = fopen($source, 'r')) === false) {
throw new \common_Exception('Unable to read content of file ("' . $source . '")');
}
$file = $this->getItemDirectory()->getDirectory($parent)->getFile($fileName);
$writeSuccess = $file->put($resource);
if (is_resource($resource)) {
fclose($resource);
}
if (! $writeSuccess) {
throw new \common_Exception('Unable to write file ("' . $fileName . '")');
}
return $this->getInfoFromSource($file, $source);
}
/**
* Delete the file located at $link
*
* @see \oat\tao\model\media\MediaManagement::delete
* @param $link
* @return bool
* @throws \tao_models_classes_FileNotFoundException
* @throws common_exception_Error
*/
public function delete($link)
{
return $this->getFile($link)->delete();
}
/**
* Return file stream of file located at $link
*
* @see tao/models/classes/media/MediaBrowser.php:getFileStream
* @param string $link
* @return StreamInterface
* @throws \tao_models_classes_FileNotFoundException
* @throws common_exception_Error
*/
public function getFileStream($link)
{
return $this->getFile($link)->readPsrStream();
}
/**
* Get file object associated to $link, search in main item directory or specific item directory
*
* @param $link
* @return File
* @throws \common_Exception
* @throws \tao_models_classes_FileNotFoundException
* @throws common_exception_Error
*/
private function getFile($link)
{
if (!tao_helpers_File::securityCheck($link)) {
throw new common_exception_Error(__('Your path contains error'));
}
$file = $this->getItemDirectory()->getFile($link);
if ($file->exists()) {
return $file;
}
throw new \tao_models_classes_FileNotFoundException($link);
}
/**
* Get item directory based on $this->item & $this->lang
*
* @return Directory
* @throws \common_Exception
*/
protected function getItemDirectory()
{
if (! $this->itemService) {
$this->itemService = taoItems_models_classes_ItemsService::singleton();
}
return $this->itemService->getItemDirectory($this->item, $this->lang);
}
/**
* @throws \common_Exception
* @throws \tao_models_classes_FileNotFoundException
* @throws common_exception_Error
*/
private function searchDirectories(
string $parentLink,
array $acceptableMime,
int $depth,
int $childrenLimit
): array {
if (!tao_helpers_File::securityCheck($parentLink)) {
throw new common_exception_Error(__('Your path contains error'));
}
$label = rtrim($parentLink, '/');
if (strrpos($parentLink, '/') !== false && substr($parentLink, -1) !== '/') {
$label = substr($parentLink, strrpos($parentLink, '/') + 1);
$parentLink = $parentLink . '/';
}
if (in_array($parentLink, ['', '/'])) {
$label = $this->getItem()->getLabel();
$parentLink = '/';
}
$data = [
'path' => $parentLink,
'label' => $label,
'childrenLimit' => $childrenLimit,
'total' => 0,
];
if ($depth <= 0) {
$data['parent'] = $parentLink;
return $data;
}
$children = [];
/** @var Directory $directory */
$itemDirectory = $this->getItemDirectory();
if ($parentLink != '/') {
$directory = $itemDirectory->getDirectory($parentLink);
} else {
$directory = $itemDirectory;
}
$iterator = $directory->getFlyIterator();
$total = 0;
foreach ($iterator as $content) {
if ($content instanceof Directory) {
$children[] = $this->searchDirectories(
$itemDirectory->getRelPath($content),
$acceptableMime,
$depth - 1,
$childrenLimit
);
continue;
}
$fileInfo = $this->getInfoFromFile($content);
if (empty($acceptableMime) || in_array($fileInfo['mime'], $acceptableMime)) {
$children[] = $fileInfo;
$total++;
}
}
$data['children'] = $children;
$data['total'] = $total;
return $data;
}
}