tr('Preview Files'), 'documentation' => 'PluginPreviewFiles', 'description' => tr('Enabled to generate preview of images or video files'), 'prefs' => ['wikiplugin_preview'], 'iconname' => 'file', 'introduced' => 18, 'tags' => ['experimental'], 'packages_required' => ['media-alchemyst/media-alchemyst' => 'MediaAlchemyst\Alchemyst'], 'format' => 'html', 'params' => [ 'fileId' => [ 'required' => true, 'name' => tr('fileId'), 'description' => tr('Id of the file in the file gallery'), 'since' => '18.0', 'filter' => 'int', ], 'animation' => [ 'required' => false, 'name' => tr('Animation'), 'description' => tr('Output should be a static image (0) or an animation (1)'), 'since' => '18.0', 'filter' => 'int', ], 'width' => [ 'required' => false, 'name' => tr('Width'), 'description' => tr('Width of the result in pixels'), 'since' => '18.0', 'filter' => 'int', ], 'height' => [ 'required' => false, 'name' => tr('Height'), 'description' => tr('Height of the result in pixels'), 'since' => '18.0', 'filter' => 'int', ], 'download' => [ 'required' => false, 'name' => tr('Download'), 'description' => tr('Show download link to the original file'), 'since' => '19.0', 'filter' => 'int', ], 'range' => [ 'required' => false, 'name' => tr('Range'), 'description' => tr('Page range preview in the format -. Example for the preview page from 2 to 4: "2-4"'), 'since' => '21.0', ], ], ]; } /** * Plugin definition for Preview * * @param $data * @param $params * @return string|void */ function wikiplugin_preview($data, $params) { global $user, $prefs, $tikipath, $tikidomain; if (! AlchemyLib::isLibraryAvailable()) { return; } $fileId = isset($params['fileId']) ? (int)$params['fileId'] : 0; $animation = isset($params['animation']) ? (int)$params['animation'] : 0; $width = isset($params['width']) ? (int)$params['width'] : null; $height = isset($params['height']) ? (int)$params['height'] : null; $range = isset($params['range']) ? $params['range'] : null; $smartyLib = TikiLib::lib('smarty'); $fileGalleryLib = TikiLib::lib('filegal'); $userLib = TikiLib::lib('user'); $file = \Tiki\FileGallery\File::id($fileId); if (! $file->exists() || ! $userLib->user_has_perm_on_object($user, $file->fileId, 'file', 'tiki_p_download_files')) { return; } $requestUniqueIdentifier = md5(serialize([$data, $params])); if (! isset($_REQUEST[$requestUniqueIdentifier])) { // generate the html output $urlParts = parse_url($_SERVER['REQUEST_URI']); $path = isset($urlParts['path']) ? $urlParts['path'] : '/'; if (isset($urlParts['query'])) { parse_str($urlParts['query'], $pageParams); } else { $pageParams = []; } if (isset($_GET['page'])) { $pageParams['page'] = $_GET['page']; } $pageParams[$requestUniqueIdentifier] = '1'; $pageParamStr = http_build_query($pageParams, null, '&'); $fileLink = $path . '?' . $pageParamStr; $smartyLib->assign('param', $params); $files = []; if (! empty($range)) { $rangeFormat = preg_match("/^\d+\-\d+$/", $range); if ($rangeFormat !== 1) { Feedback::error(tr('File ID %0 preview contains an invalid range parameter.', $fileId)); } else { $pageIterator = explode('-', $range)[0]; $lastPage = explode('-', $range)[1]; while ($pageIterator <= $lastPage) { $files[] = $fileLink . "&previewPage=" . $pageIterator; $pageIterator++; } } } else { $files[] = $fileLink; } $smartyLib->assign('files', $files); if ((isset($params['download']) && $params['download'] === 1)) { $tikilib = TikiLib::lib('tiki'); $smartyLib->assign('original_file_download_link', $tikilib->tikiUrl() . 'tiki-download_file.php?fileId=' . $fileId, true); } return $smartyLib->fetch('wiki-plugins/wikiplugin_preview.tpl'); } $filePath = $file->getWrapper()->getReadableFile(); $fileMd5 = $file->getWrapper()->getChecksum(); while (ob_get_level() > 1) { ob_end_clean(); } // Be sure output buffering is turned off /** @var Cachelib $cacheLib */ $cacheLib = TikiLib::lib('cache'); $cacheName = $fileMd5 . $requestUniqueIdentifier; $previewPage = isset($_GET['previewPage']) ? $_GET['previewPage'] : null; if ($previewPage) { $cacheName .= "_" . $previewPage; } $cacheType = 'wp_preview_' . $fileId . '_'; $buildContent = true; $content = null; $contentType = null; $content_temp = $cacheLib->getCached($cacheName, $cacheType); if ($content_temp && $content_temp !== serialize(false) && $content_temp != "") { $buildContent = false; $pos = strpos($content_temp, ';'); $contentType = substr($content_temp, 0, $pos); $content = substr($content_temp, $pos + 1); } unset($content_temp); if ($buildContent) { $newFileExtension = $animation ? '.gif' : '.png'; $newFilePath = $tikipath . DIRECTORY_SEPARATOR . 'temp' . DIRECTORY_SEPARATOR . 'cache' . DIRECTORY_SEPARATOR . $tikidomain . DIRECTORY_SEPARATOR . 'target_' . $cacheType . $cacheName . $newFileExtension; // This will allow apps executed by Alchemy (like when converting doc to pdf) to have a writable home // save existing ENV $envHomeDefined = isset($_ENV) && array_key_exists('HOME', $_ENV); if ($envHomeDefined) { $envHomeCopy = $_ENV['HOME']; } // set a proper home folder $_ENV['HOME'] = $tikipath . DIRECTORY_SEPARATOR . 'temp' . DIRECTORY_SEPARATOR . 'cache' . DIRECTORY_SEPARATOR . $tikidomain; AlchemyLib::hintMimeTypeByFilePath($filePath, $file->filetype); $alchemy = new AlchemyLib(); $contentType = $alchemy->convertToImage($filePath, $newFilePath, $width, $height, $animation, $previewPage); // Restore the environment if ($envHomeDefined) { $_ENV['HOME'] = $envHomeCopy; } else { unset($_ENV['HOME']); } if (file_exists($newFilePath)) { $content = file_get_contents($newFilePath); } unlink($newFilePath); if (empty($content)) { exit; } $cacheLib->cacheItem($cacheName, $contentType . ';' . $content, $cacheType); } session_write_close(); // close the session in case of large transcode/downloads to enable further browsing // Compression of the stream may corrupt files on windows ini_set('zlib.output_compression', 'Off'); header("Expires: 0"); header("Cache-Control: must-revalidate, post-check=0, pre-check=0"); header("Cache-Control: private", false); header('Content-Length: ' . strlen($content)); header('Content-Type: ' . $contentType); header('Content-Disposition: inline; filename="' . $fileMd5 . '";'); header('Connection: close'); header('Content-Transfer-Encoding: binary'); echo $content; exit; }