Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix thumbnail generation for mis-detected file types #769

Open
wants to merge 20 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
13 changes: 8 additions & 5 deletions src/_h5ai/private/conf/options.json
Original file line number Diff line number Diff line change
Expand Up @@ -234,11 +234,9 @@
Show an image preview on click.

- types: array of strings
- size: number, sample size, or false for original size
*/
"preview-img": {
"enabled": true,
"size": false,
"types": ["img", "img-bmp", "img-gif", "img-ico", "img-jpg", "img-png", "img-raw", "img-svg"]
},

Expand Down Expand Up @@ -349,15 +347,18 @@

/*
Show thumbnails for image files. Needs the "/_h5ai/public/cache" folder to be
writable for the web Server.
writable for the web Server. Removing a default value from an array of strings
results in adding it to the blocklist implicitly.

- img: array of strings
- mov: array of strings
- doc: array of strings
- delay: number, delay in milliseconds after "dom-ready" before thumb-requesting starts
- size: number, size in pixel of the generated thumbnails
- size: number, height in pixel of the generated thumbnails
- seek: number, percentage of total video duration to seek into
- exif: boolean, use included EXIF thumbs if possible
- chunksize: int, number of thumbs per request
- blocklist: array of strings, do not generate thumbnails for these types
*/
"thumbnails": {
"enabled": true,
Expand All @@ -366,8 +367,10 @@
"doc": ["x-pdf", "x-ps"],
"delay": 1,
"size": 240,
"seek": 50,
"exif": false,
"chunksize": 20
"chunksize": 20,
"blocklist": []
},

/*
Expand Down
20 changes: 17 additions & 3 deletions src/_h5ai/private/php/core/class-context.php
Original file line number Diff line number Diff line change
Expand Up @@ -247,12 +247,26 @@ public function get_l10n($iso_codes) {

public function get_thumbs($requests) {
$hrefs = [];
$thumbs = [];
$height = $this->options['thumbnails']['size'] ?? 240;
$width = floor($height * (4 / 3));

foreach ($requests as $req) {
$thumb = new Thumb($this);
$hrefs[] = $thumb->thumb($req['type'], $req['href'], $req['width'], $req['height']);
if ($req['type'] === 'blocked') {
$hrefs[] = null;
continue;
}
$path = $this->to_path($req['href']);
if (!array_key_exists($path, $thumbs)) {
$thumbs[$path] = new Thumb($this, $path, $req['type']);
}
else if ($thumbs[$path]->type === 'file') {
// File has already been mime tested and cannot have a thumbnail
$hrefs[] = null;
continue;
}
$hrefs[] = $thumbs[$path]->thumb($width, $height);
}

return $hrefs;
}

Expand Down
5 changes: 4 additions & 1 deletion src/_h5ai/private/php/core/class-setup.php
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ private function add_php_checks() {
$has_php_jpeg = array_key_exists('JPEG Support', $infos) && $infos['JPEG Support'];
}
$this->set('HAS_PHP_JPEG', $has_php_jpeg);

$this->set('HAS_PHP_FILEINFO', extension_loaded('fileinfo'));
}

private function add_app_metadata() {
Expand Down Expand Up @@ -133,7 +135,7 @@ private function add_sys_cmd_checks() {
$cmd = 'where';
}

foreach (['avconv', 'convert', 'du', 'ffmpeg', 'gm', 'tar', 'zip'] as $c) {
foreach (['avconv', 'avprobe', 'convert', 'du', 'ffmpeg', 'ffprobe', 'gm', 'tar', 'zip'] as $c) {
$cmds[$c] = ($cmd !== false) && (Util::exec_0($cmd . ' ' . $c) || Util::exec_0($cmd . ' ' . $c . '.exe'));
}

Expand All @@ -159,6 +161,7 @@ public function to_jsono($as_admin = false) {
'PHP_ARCH',
'HAS_PHP_EXIF',
'HAS_PHP_JPEG',
'HAS_PHP_FILEINFO',

'SERVER_NAME',
'SERVER_VERSION',
Expand Down
85 changes: 77 additions & 8 deletions src/_h5ai/private/php/core/class-util.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ class Util {
const ERR_UNSUPPORTED = 'ERR_UNSUPPORTED';
const NO_DEFAULT = 'NO_*@+#?!_DEFAULT';
const RE_DELIMITER = '@';
// 'file' has to be the last item!
public const AVAILABLE_TYPES = ['img', 'mov', 'doc', 'swf', 'file'];

public static function normalize_path($path, $trailing_slash = false) {
$path = preg_replace('#[\\\\/]+#', '/', $path);
Expand Down Expand Up @@ -59,16 +61,21 @@ public static function passthru_cmd($cmd) {
return $rc;
}

public static function exec_cmdv($cmdv) {
if (!is_array($cmdv)) {
$cmdv = func_get_args();
}
public static function exec_cmdv($cmdv, $capture = false, $redirect = false) {
$cmd = implode(' ', array_map('escapeshellarg', $cmdv));

$lines = [];
$rc = null;
exec($cmd, $lines, $rc);
return implode("\n", $lines);
if ($redirect) {
// Redirect stderr to stdout (notably for ffmpeg)
$cmd .= ' 2>&1'; // This cannot be shellarg-escaped
}

if ($capture){
$lines = [];
$rc = null;
exec($cmd, $lines, $rc);
return [$lines, $rc];
}
return exec($cmd);
}

public static function exec_0($cmd) {
Expand All @@ -81,9 +88,71 @@ public static function exec_0($cmd) {
return false;
}

public static function proc_open_cmdv($cmdv, &$output, &$error) {
$cmd = implode(' ', array_map('escapeshellarg', $cmdv));

$descriptorspec = array(
0 => array("pipe", "r"), // stdin is a pipe that the child will read from
1 => array("pipe", "w"), // stdout is a pipe that the child will write to
2 => array("pipe", "w") // stderr is a pipe the child will write to
);
$process = proc_open($cmd, $descriptorspec, $pipes);

if (is_resource($process)) {
fclose($pipes[0]); // We usually don't need stdin

if (is_resource($output)) {
stream_copy_to_stream($pipes[1], $output);
} else {
$output = stream_get_contents($pipes[1]);
}
fclose($pipes[1]);

$error = stream_get_contents($pipes[2]);
fclose($pipes[2]);

$exit_code = proc_close($process);
return $exit_code;
}
return -1;
}

public static function filesize($context, $path) {
$withFoldersize = $context->query_option('foldersize.enabled', false);
$withDu = $context->get_setup()->get('HAS_CMD_DU') && $context->query_option('foldersize.type', null) === 'shell-du';
return Filesize::getCachedSize($path, $withFoldersize, $withDu);
}

public static function get_mimetype($source_path) {
//return mime_content_type($filename);
$finfo = new finfo(FILEINFO_MIME_TYPE);
return $finfo->file($source_path);
}

public static function mime_to_handler_type($mime) {
if (strpos($mime, 'image') !== false) {
return 'img';
}
if (strpos($mime, 'video') !== false) {
return 'mov';
}
if (strpos($mime, 'pdf') !== false) {
return 'doc';
}
if (strpos($mime, 'flash') !== false) {
return 'swf';
}
return 'file';
}

public static function get_types_array($type) {
/* Returns an array of possible types, with $type as the first element*/
$types = Util::AVAILABLE_TYPES;
$key = array_search($type, $types);
if ($key !== false) {
unset($types[$key]);
array_unshift($types, $type);
}
return $types;
}
}