487 lines
21 KiB
PHP
487 lines
21 KiB
PHP
<?php
|
|
|
|
namespace App;
|
|
|
|
use League\CommonMark\Environment\Environment;
|
|
use League\CommonMark\Extension\Autolink\AutolinkExtension;
|
|
use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
|
|
use League\CommonMark\Extension\TaskList\TaskListExtension;
|
|
use League\CommonMark\MarkdownConverter;
|
|
use Utils\Utils;
|
|
|
|
class FileAndDir {
|
|
private $currentDir;
|
|
private $requestedDir;
|
|
private $config = [];
|
|
private $fileExtensions = [
|
|
'deny' => ['sh', 'html', 'js', 'vbs', 'exe', 'md'],
|
|
'txt' => ['txt', 'md'],
|
|
'img' => ['jpeg', 'jpg', 'jpe', 'bmp', 'webp', 'gif', 'png'],
|
|
'pdf' => ['pdf'],
|
|
'zip' => ['7z', 'zip', 'gz', 'tar', 'rar', 'r[0-9]{2,}'],
|
|
'doc' => ['odt', 'doc', 'docx'],
|
|
'pres' => ['odp', 'ppt', 'pptx'],
|
|
'spread' => ['ods', 'xls', 'xlsx'],
|
|
'video' => ['ogv', 'mp4', 'mpg', 'mpeg', 'mov', 'avi', 'wmv', 'flv', 'webm'],
|
|
'audio' => ['aiff', 'aif', 'wma', 'aac', 'flac', 'mp3', 'ogg', 'm4a'],
|
|
];
|
|
private $appUrl;
|
|
|
|
/**
|
|
* Initializes the object with directory paths and configuration settings.
|
|
*
|
|
* This constructor initializes the object with the provided directory paths and configuration.
|
|
* It verifies that the given paths are authorized using utility methods. If any path is unauthorized,
|
|
* the script terminates with an error message.
|
|
*
|
|
* @param string $dir The current directory path to be set.
|
|
* @param string $requestedDir The requested directory path to be set, relative to the 'photos' directory.
|
|
* @param array $config Configuration settings to be used by the object.
|
|
*
|
|
* @throws \Exception If an unauthorized access attempt is detected.
|
|
*/
|
|
function __construct(string $dir, string $requestedDir, array $config) {
|
|
if (!Utils::isPathAuthorized($dir)) {
|
|
die("ERROR 02: Unauthorized access!");
|
|
}
|
|
|
|
if (!Utils::isPathAuthorized('photos' . $requestedDir)) {
|
|
die("ERROR 03: Unauthorized access!");
|
|
}
|
|
$this->currentDir = $dir;
|
|
$this->requestedDir = $requestedDir;
|
|
$this->config = $config;
|
|
if ($config['showShareLink'] === true) {
|
|
$this->appUrl = $_SERVER['REQUEST_SCHEME'] . '://' . $_SERVER['SERVER_NAME'];
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Generates a breadcrumb navigation based on the requested directory.
|
|
*
|
|
* This method creates an HTML breadcrumb navigation trail from the requested directory path.
|
|
* It links each directory level, except for the last one, which is displayed as plain text.
|
|
* If the requested directory is empty or set to "photos", it returns an empty string.
|
|
*
|
|
* @return string The HTML markup for the breadcrumb navigation, or an empty string if no breadcrumb is needed.
|
|
*/
|
|
public function makeBreadcrumb(): string {
|
|
if ($this->requestedDir !== '' && $this->requestedDir !== 'photos') {
|
|
$breadcrumb_navigation = '<div id="breadcrumb">';
|
|
$breadcrumb_navigation .= '<a href="?dir=">Home</a> > ';
|
|
|
|
$navitems = explode("/", htmlspecialchars($this->requestedDir));
|
|
$path = '';
|
|
|
|
foreach ($navitems as $index => $item) {
|
|
if ($index === 0) continue;
|
|
|
|
$path .= $item;
|
|
|
|
if ($index === count($navitems) - 1) {
|
|
$breadcrumb_navigation .= htmlspecialchars($item);
|
|
} else {
|
|
$breadcrumb_navigation .= '<a href="?dir=/' . htmlspecialchars($path) . '">' . htmlspecialchars($item) . '</a> > ';
|
|
$path .= '/';
|
|
}
|
|
}
|
|
|
|
$breadcrumb_navigation .= '</div>';
|
|
return $breadcrumb_navigation;
|
|
} else {
|
|
return '';
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Checks if the specified file is readable and updates a global message if it is not.
|
|
*
|
|
* This function verifies if the given file has read permissions. If the file is not
|
|
* readable, it sets a global `$messages` variable with a warning message and a link
|
|
* to a guide on how to change file permissions.
|
|
*
|
|
* @param string $file The path to the file or directory to check.
|
|
*
|
|
* @global string $messages A global variable used to store the error message if permissions are incorrect.
|
|
*/
|
|
function checkpermissions(string $file): void {
|
|
global $messages;
|
|
|
|
if (!is_readable($file)) {
|
|
$messages = "At least one file or folder has wrong permissions. "
|
|
. "Learn how to <a href='http://minigal.dk/faq-reader/items/"
|
|
. "how-do-i-change-file-permissions-chmod.html' target='_blank'>"
|
|
. "set file permissions</a>";
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Lists directories and files within the current directory.
|
|
*
|
|
* This method scans the current directory and generates a list of directories and files.
|
|
* Directories and files are categorized, and thumbnails are created or fetched based on
|
|
* the file type. The results are sorted and returned in an associative array containing
|
|
* two keys: 'dir' for directories and 'file' for files. If the directory cannot be opened,
|
|
* the script terminates with an error message.
|
|
*
|
|
* @return array An associative array with two keys:
|
|
* - 'dir': An array of directories with details like name, thumbnail URL, link, type, date, and size.
|
|
* - 'file': An array of files with details like name, thumbnail URL, link, type, date, size, data attributes, and image captions.
|
|
*
|
|
* @throws RuntimeException If the current directory cannot be opened.
|
|
*/
|
|
function listDirs(): array {
|
|
$listDir = $listFile = [];
|
|
if (is_dir($this->currentDir) && $handle = opendir($this->currentDir)) {
|
|
while (false !== ($file = readdir($handle))) {
|
|
if (in_array($file, $this->config['skipObjects'])) {
|
|
continue;
|
|
}
|
|
if (is_dir($this->currentDir . '/' . $file)) {
|
|
if ($file != "." && $file != "..") {
|
|
if ($this->defineThumbnailDir($file)) {
|
|
$thumb = $this->makeFolderThumbUrl($file);
|
|
} else {
|
|
$thumb = $this->getfirstImage($file);
|
|
}
|
|
$listDir[] = [
|
|
'name' => $file,
|
|
'thumb' => $thumb,
|
|
'link' => '?dir=' . urlencode($this->requestedDir . '/' . $file),
|
|
'type' => 'folder',
|
|
'date' => date("Y-m-d", filemtime($this->currentDir . '/' . $file)),
|
|
'size' => filesize($this->currentDir . '/' . $file),
|
|
'dataAttr' => null,
|
|
'imgCaption' => null
|
|
];
|
|
}
|
|
}
|
|
if (is_file($this->currentDir . '/' . $file) && $file != "." && $file != ".." && $file != "folder.jpg") {
|
|
$extension = $this->getExtension($file);
|
|
if ($extension === 'deny') {
|
|
continue;
|
|
}
|
|
if ($extension !== 'img') {
|
|
$thumb = '/assets/images/filetype_' . $extension . '.svg';
|
|
} else {
|
|
$thumb = $this->makeImageThumbUrl($file);
|
|
}
|
|
|
|
$caption = $this->computeCaption($file);
|
|
|
|
$listFile[] = [
|
|
'name' => pathinfo($file, PATHINFO_FILENAME),
|
|
'thumb' => $thumb,
|
|
'link' => $this->currentDir . '/' . $file,
|
|
'type' => $extension,
|
|
'date' => date("Y-m-d", filemtime($this->currentDir . '/' . $file)),
|
|
'size' => filesize($this->currentDir . '/' . $file),
|
|
'dataAttr' => $caption['dataAttr'],
|
|
'imgCaption' => $caption['content']
|
|
];
|
|
}
|
|
}
|
|
closedir($handle);
|
|
|
|
$order = $this->config['orderBy'] === 'desc' ? 1 : -1;
|
|
|
|
usort($listDir, function ($a, $b) use ($order) {
|
|
return $order * strcmp(strtolower($a[$this->config['sortBy']]), strtolower($b[$this->config['sortBy']]));
|
|
});
|
|
|
|
usort($listFile, function ($a, $b) use ($order) {
|
|
return $order * strcmp(strtolower($a[$this->config['sortBy']]), strtolower($b[$this->config['sortBy']]));
|
|
});
|
|
|
|
return ['dir' => $listDir, 'file' => $listFile];
|
|
} else {
|
|
die("ERROR: Could not open " . htmlspecialchars(stripslashes($this->currentDir)) . " for reading!");
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Determines the type of file based on its extension.
|
|
*
|
|
* This method checks the file extension against a predefined list of known file types
|
|
* and returns a category name corresponding to the file type. If the extension does not match
|
|
* any known types, it returns 'other'.
|
|
*
|
|
* @param string $file The name of the file whose extension is to be checked.
|
|
*
|
|
* @return string The category name of the file type based on its extension. Possible values
|
|
* include 'img', 'md', 'pdf', 'zip', 'rar', 'tar', 'gzip', 'doc', 'pres',
|
|
* 'ods', 'video', 'audio', or 'other' if the extension is not recognized.
|
|
*/
|
|
private function getExtension(string $file): string {
|
|
if (!is_readable($this->currentDir . '/' . $file) || !is_file($this->currentDir . '/' . $file)) {
|
|
return 'broken';
|
|
}
|
|
|
|
$fileExtension = strtolower(pathinfo($file, PATHINFO_EXTENSION));
|
|
foreach ($this->fileExtensions as $type => $extensions) {
|
|
foreach ($extensions as $ext) {
|
|
if (preg_match("/^$ext$/i", $fileExtension)) {
|
|
return $type;
|
|
}
|
|
}
|
|
}
|
|
return 'other';
|
|
}
|
|
|
|
/**
|
|
* Checks if a thumbnail image exists in the specified directory.
|
|
*
|
|
* This method determines if a `folder.jpg` file exists in the given directory
|
|
* within the current directory. It returns `true` if the file is found, indicating
|
|
* that the directory has a defined thumbnail; otherwise, it returns `false`.
|
|
*
|
|
* @param string $dir The name of the directory to check for a thumbnail.
|
|
*
|
|
* @return bool `true` if the `folder.jpg` file exists in the directory, `false` otherwise.
|
|
*/
|
|
private function defineThumbnailDir(string $dir): bool {
|
|
if (file_exists($this->currentDir . '/' . $dir . '/folder.jpg')) {
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Generates a URL for the folder thumbnail image.
|
|
*
|
|
* This method constructs a URL to request the creation of a thumbnail image for a
|
|
* specified folder. It uses the `createthumb.php` script with query parameters for
|
|
* the thumbnail image file and its size.
|
|
*
|
|
* @param string $file The name of the folder for which to create a thumbnail.
|
|
*
|
|
* @return string The URL to request the creation of the folder thumbnail image.
|
|
*/
|
|
private function makeFolderThumbUrl(string $file): string {
|
|
$imgParams = http_build_query(
|
|
array(
|
|
'filename' => "$this->currentDir/$file/folder.jpg"
|
|
),
|
|
'',
|
|
'&'
|
|
);
|
|
return 'createthumb.php?' . $imgParams;
|
|
}
|
|
|
|
/**
|
|
* Generates a URL for the image thumbnail.
|
|
*
|
|
* This method constructs a URL to request the creation of a thumbnail image for
|
|
* a given file if its extension is recognized as an image format. If the file's
|
|
* extension is not a recognized image format, it returns a URL to a default image.
|
|
*
|
|
* @param string $file The name of the image file for which to create a thumbnail.
|
|
*
|
|
* @return string The URL to request the creation of the image thumbnail or a default image URL if the extension is not recognized.
|
|
*/
|
|
private function makeImageThumbUrl(string $file): string {
|
|
$pathinfo = pathinfo($file);
|
|
$ext = strtolower($pathinfo['extension']);
|
|
if (in_array($ext, $this->fileExtensions['img'])) {
|
|
$imageName = $file;
|
|
$imgParams = 'createthumb.php?' . http_build_query(
|
|
array(
|
|
'filename' => $this->currentDir . '/' . $imageName
|
|
),
|
|
'',
|
|
'&'
|
|
);
|
|
} else {
|
|
$imgParams = 'assets/images/default.svg';
|
|
}
|
|
return $imgParams;
|
|
}
|
|
|
|
/**
|
|
* Retrieves the URL for the first image found in the specified directory.
|
|
*
|
|
* This method scans the given directory for image files with recognized extensions.
|
|
* It returns a URL for the thumbnail of the first image found. If no image is found
|
|
* or if the directory does not exist, it returns a URL to a default image.
|
|
*
|
|
* @param string $dir The name of the directory to scan for images.
|
|
*
|
|
* @return string The URL for the thumbnail of the first image found, or a URL to a default image if no image is found or the directory does not exist.
|
|
*/
|
|
private function getFirstImage(string $dir): string {
|
|
$fullPath = $this->currentDir . '/' . $dir;
|
|
$imageName = 'assets/images/default.svg';
|
|
|
|
if (!is_dir($fullPath)) {
|
|
return $imageName;
|
|
}
|
|
|
|
if ($handle = opendir($fullPath)) {
|
|
while (false !== ($file = readdir($handle))) {
|
|
if ($file[0] == '.') {
|
|
continue;
|
|
}
|
|
$pathinfo = pathinfo($file);
|
|
if (empty($pathinfo['extension'])) {
|
|
continue;
|
|
}
|
|
$ext = strtolower($pathinfo['extension']);
|
|
if (in_array($ext, $this->fileExtensions['img'])) {
|
|
$imageName = 'createthumb.php?' . http_build_query(
|
|
array(
|
|
'filename' => $fullPath . '/' . $file
|
|
),
|
|
'',
|
|
'&'
|
|
);
|
|
closedir($handle);
|
|
return $imageName;
|
|
}
|
|
}
|
|
closedir($handle);
|
|
}
|
|
return $imageName;
|
|
}
|
|
|
|
/**
|
|
* Retrieves and converts the content of a Markdown note in the current directory.
|
|
*
|
|
* This method checks if a `note.md` file exists in the current directory. If the file
|
|
* is found, its content is read and converted from Markdown to HTML using the
|
|
* `MarkdownConverter` with specified extensions. If the file does not exist, an
|
|
* empty string is returned.
|
|
*
|
|
* @return string The HTML content of the Markdown file, or an empty string if the file does not exist.
|
|
*/
|
|
public function getFolderNote(): string {
|
|
if (file_exists($this->currentDir . '/note.md')) {
|
|
$content = file_get_contents($this->currentDir . '/note.md');
|
|
$config = [];
|
|
$environment = new Environment($config);
|
|
$environment->addExtension(new CommonMarkCoreExtension());
|
|
$environment->addExtension(new TaskListExtension());
|
|
$environment->addExtension(new AutolinkExtension());
|
|
$converter = new MarkdownConverter($environment);
|
|
return $converter->convert($content)->getContent();
|
|
} else {
|
|
return '';
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Computes the caption for an image by combining Markdown content and EXIF data.
|
|
*
|
|
* This method checks for the presence of a Markdown file and EXIF data associated with
|
|
* the given image. It combines both sources of information, converting the Markdown content
|
|
* to HTML and appending EXIF data if available. The result is a caption that can be displayed
|
|
* in a Lightbox gallery, with the relevant CSS class and HTML content.
|
|
*
|
|
* @param string $img The name of the image for which to compute the caption.
|
|
*
|
|
* @return array An associative array containing:
|
|
* - `dataAttr` (string): A data attribute for the caption's CSS class, used by the Lightbox.
|
|
* - `content` (string): The HTML content of the caption, including Markdown and EXIF data if available.
|
|
*/
|
|
private function computeCaption(string $img): array {
|
|
$mdContent = $exifData = $shareLink = $listLink = '';
|
|
|
|
if (file_exists($this->currentDir . '/' . $img . '.md')) {
|
|
$mdContent = file_get_contents($this->currentDir . '/' . $img . '.md');
|
|
}
|
|
|
|
if ($this->config['displayExifInfo']) {
|
|
$exifData = $this->computeExifData($this->currentDir . '/' . $img);
|
|
}
|
|
|
|
if ($this->config['showShareLink'] === true) {
|
|
$shareLink = '## Share link';
|
|
$listLink = '
|
|
<p>
|
|
<ul>
|
|
<li><a href="#" onclick="copiedText(this);return false;">Copy thumbnail link</a> : <input class="urlToCopy" value="' . $this->appUrl . '/createthumb.php?filename=' . (urlencode($this->currentDir . '/' . $img)) . '"></li>
|
|
<li><a href="#" onclick="copiedText(this);return false;">Copy full link</a> : <input class="urlToCopy" value="' . $this->appUrl . '/' . $this->currentDir . '/' . $img . '"></li>
|
|
<li><a href="#" onclick="copiedText(this);return false;">Copy markdown link</a> : <input class="urlToCopy" value="[![](' . $this->appUrl . '/createthumb.php?filename=' . (urlencode($this->currentDir . '/' . $img)) . ')](' . $this->appUrl . '/' . $this->currentDir . '/' . $img . ')"></li>
|
|
</ul>
|
|
</p>';
|
|
}
|
|
|
|
if (empty($exifData) && empty($mdContent) && empty($shareLink)) {
|
|
return [
|
|
'dataAttr' => '',
|
|
'content' => ''
|
|
];
|
|
}
|
|
|
|
$id = uniqid();
|
|
$environment = new Environment();
|
|
$environment->addExtension(new CommonMarkCoreExtension());
|
|
$environment->addExtension(new TaskListExtension());
|
|
$environment->addExtension(new AutolinkExtension());
|
|
$converter = new MarkdownConverter($environment);
|
|
|
|
if (!empty($exifData)) {
|
|
$exifData = "\n" . '## Exif' . "\n" . $exifData;
|
|
}
|
|
|
|
$mdContent = $mdContent . "\n" . $exifData . "\n" . $shareLink;
|
|
|
|
$captionData = [
|
|
'dataAttr' => 'description: .custom-' . $id,
|
|
'content' => '<div class="glightbox-desc custom-' . $id . '">' . $converter->convert($mdContent)->getContent() . $listLink . '</div>'
|
|
];
|
|
|
|
return $captionData;
|
|
}
|
|
|
|
|
|
/**
|
|
* Computes and formats EXIF data from an image file.
|
|
*
|
|
* This method reads EXIF data from the specified image file and formats relevant
|
|
* pieces of information into a string. It includes details such as the camera model,
|
|
* orientation, exposure time, and flash status. If any of these details are missing
|
|
* from the EXIF data, they are simply omitted from the resulting string.
|
|
*
|
|
* @param string $file The path to the image file from which to extract EXIF data.
|
|
*
|
|
* @return string A formatted string containing the EXIF data of the image, or an empty string if no relevant EXIF data is found.
|
|
*/
|
|
private function computeExifData(string $file): string {
|
|
$returnExif = '';
|
|
$exifData = @exif_read_data($file, 'EXIF');
|
|
if ($exifData !== false) {
|
|
if (isset($exifData['Model'])) {
|
|
$returnExif .= ' - Model : ' . $exifData['Model'] . "\n";
|
|
}
|
|
if (isset($exifData['Orientation'])) {
|
|
$returnExif .= ' - Orientation : ' . $exifData['Orientation'] . "\n";
|
|
}
|
|
if (isset($exifData['ExposureTime'])) {
|
|
$returnExif .= ' - Exposure Time : ' . $exifData['ExposureTime'] . "\n";
|
|
}
|
|
if (isset($exifData['Flash'])) {
|
|
$returnExif .= ' - Flash : ' . $exifData['Flash'] . "\n";
|
|
}
|
|
}
|
|
return $returnExif;
|
|
}
|
|
|
|
/**
|
|
* Determines the Lightbox class to use based on the resource type.
|
|
*
|
|
* This static method checks if the given resource type is either 'video' or 'img'.
|
|
* If so, it returns the class name 'glightbox', indicating that the resource should
|
|
* be added to a Lightbox gallery. Otherwise, it returns `null`.
|
|
*
|
|
* @param string $ressourceType The type of the resource to check (e.g., 'video' or 'img').
|
|
*
|
|
* @return string|null The Lightbox class name if the resource type is valid, otherwise `null`.
|
|
*/
|
|
static function addToLightBox(string $ressourceType): string|null {
|
|
if (in_array($ressourceType, ['video', 'img'])) {
|
|
return 'glightbox';
|
|
}
|
|
return null;
|
|
}
|
|
}
|