PageRenderTime 38ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 1ms

/lib/wiki-plugins/wikiplugin_preview.php

https://gitlab.com/ElvisAns/tiki
PHP | 242 lines | 181 code | 37 blank | 24 comment | 27 complexity | 5595f72b7b41157dbb82e74b4c9cf36c MD5 | raw file
  1. <?php
  2. // (c) Copyright by authors of the Tiki Wiki CMS Groupware Project
  3. //
  4. // All Rights Reserved. See copyright.txt for details and a complete list of authors.
  5. // Licensed under the GNU LESSER GENERAL PUBLIC LICENSE. See license.txt for details.
  6. // $Id$
  7. use Tiki\Lib\Alchemy\AlchemyLib;
  8. /**
  9. * Plugin definition for preview
  10. *
  11. * @return array
  12. */
  13. function wikiplugin_preview_info()
  14. {
  15. return [
  16. 'name' => tr('Preview Files'),
  17. 'documentation' => 'PluginPreviewFiles',
  18. 'description' => tr('Enabled to generate preview of images or video files'),
  19. 'prefs' => ['wikiplugin_preview'],
  20. 'iconname' => 'file',
  21. 'introduced' => 18,
  22. 'tags' => ['experimental'],
  23. 'packages_required' => ['media-alchemyst/media-alchemyst' => 'MediaAlchemyst\Alchemyst'],
  24. 'format' => 'html',
  25. 'params' => [
  26. 'fileId' => [
  27. 'required' => true,
  28. 'name' => tr('fileId'),
  29. 'description' => tr('Id of the file in the file gallery'),
  30. 'since' => '18.0',
  31. 'filter' => 'int',
  32. ],
  33. 'animation' => [
  34. 'required' => false,
  35. 'name' => tr('Animation'),
  36. 'description' => tr('Output should be a static image (<code>0</code>) or an animation (<code>1</code>)'),
  37. 'since' => '18.0',
  38. 'filter' => 'int',
  39. ],
  40. 'width' => [
  41. 'required' => false,
  42. 'name' => tr('Width'),
  43. 'description' => tr('Width of the result in pixels'),
  44. 'since' => '18.0',
  45. 'filter' => 'int',
  46. ],
  47. 'height' => [
  48. 'required' => false,
  49. 'name' => tr('Height'),
  50. 'description' => tr('Height of the result in pixels'),
  51. 'since' => '18.0',
  52. 'filter' => 'int',
  53. ],
  54. 'download' => [
  55. 'required' => false,
  56. 'name' => tr('Download'),
  57. 'description' => tr('Show download link to the original file'),
  58. 'since' => '19.0',
  59. 'filter' => 'int',
  60. ],
  61. 'range' => [
  62. 'required' => false,
  63. 'name' => tr('Range'),
  64. 'description' => tr('Page range preview in the format <integer>-<integer>. Example for the preview page from 2 to 4: "2-4"'),
  65. 'since' => '21.0',
  66. ],
  67. ],
  68. ];
  69. }
  70. /**
  71. * Plugin definition for Preview
  72. *
  73. * @param $data
  74. * @param $params
  75. * @return string|void
  76. */
  77. function wikiplugin_preview($data, $params)
  78. {
  79. global $user, $prefs, $tikipath, $tikidomain;
  80. if (! AlchemyLib::isLibraryAvailable()) {
  81. return;
  82. }
  83. $fileId = isset($params['fileId']) ? (int)$params['fileId'] : 0;
  84. $animation = isset($params['animation']) ? (int)$params['animation'] : 0;
  85. $width = isset($params['width']) ? (int)$params['width'] : null;
  86. $height = isset($params['height']) ? (int)$params['height'] : null;
  87. $range = isset($params['range']) ? $params['range'] : null;
  88. $smartyLib = TikiLib::lib('smarty');
  89. $fileGalleryLib = TikiLib::lib('filegal');
  90. $userLib = TikiLib::lib('user');
  91. $file = \Tiki\FileGallery\File::id($fileId);
  92. if (! $file->exists() || ! $userLib->user_has_perm_on_object($user, $file->fileId, 'file', 'tiki_p_download_files')) {
  93. return;
  94. }
  95. $requestUniqueIdentifier = md5(serialize([$data, $params]));
  96. if (! isset($_REQUEST[$requestUniqueIdentifier])) {
  97. // generate the html output
  98. $urlParts = parse_url($_SERVER['REQUEST_URI']);
  99. $path = isset($urlParts['path']) ? $urlParts['path'] : '/';
  100. if (isset($urlParts['query'])) {
  101. parse_str($urlParts['query'], $pageParams);
  102. } else {
  103. $pageParams = [];
  104. }
  105. if (isset($_GET['page'])) {
  106. $pageParams['page'] = $_GET['page'];
  107. }
  108. $pageParams[$requestUniqueIdentifier] = '1';
  109. $pageParamStr = http_build_query($pageParams, null, '&');
  110. $fileLink = $path . '?' . $pageParamStr;
  111. $smartyLib->assign('param', $params);
  112. $files = [];
  113. if (! empty($range)) {
  114. $rangeFormat = preg_match("/^\d+\-\d+$/", $range);
  115. if ($rangeFormat !== 1) {
  116. Feedback::error(tr('File ID %0 preview contains an invalid range parameter.', $fileId));
  117. } else {
  118. $pageIterator = explode('-', $range)[0];
  119. $lastPage = explode('-', $range)[1];
  120. while ($pageIterator <= $lastPage) {
  121. $files[] = $fileLink . "&previewPage=" . $pageIterator;
  122. $pageIterator++;
  123. }
  124. }
  125. } else {
  126. $files[] = $fileLink;
  127. }
  128. $smartyLib->assign('files', $files);
  129. if ((isset($params['download']) && $params['download'] === 1)) {
  130. $tikilib = TikiLib::lib('tiki');
  131. $smartyLib->assign('original_file_download_link', $tikilib->tikiUrl() . 'tiki-download_file.php?fileId=' . $fileId, true);
  132. }
  133. return $smartyLib->fetch('wiki-plugins/wikiplugin_preview.tpl');
  134. }
  135. $filePath = $file->getWrapper()->getReadableFile();
  136. $fileMd5 = $file->getWrapper()->getChecksum();
  137. while (ob_get_level() > 1) {
  138. ob_end_clean();
  139. } // Be sure output buffering is turned off
  140. /** @var Cachelib $cacheLib */
  141. $cacheLib = TikiLib::lib('cache');
  142. $cacheName = $fileMd5 . $requestUniqueIdentifier;
  143. $previewPage = isset($_GET['previewPage']) ? $_GET['previewPage'] : null;
  144. if ($previewPage) {
  145. $cacheName .= "_" . $previewPage;
  146. }
  147. $cacheType = 'wp_preview_' . $fileId . '_';
  148. $buildContent = true;
  149. $content = null;
  150. $contentType = null;
  151. $content_temp = $cacheLib->getCached($cacheName, $cacheType);
  152. if ($content_temp && $content_temp !== serialize(false) && $content_temp != "") {
  153. $buildContent = false;
  154. $pos = strpos($content_temp, ';');
  155. $contentType = substr($content_temp, 0, $pos);
  156. $content = substr($content_temp, $pos + 1);
  157. }
  158. unset($content_temp);
  159. if ($buildContent) {
  160. $newFileExtension = $animation ? '.gif' : '.png';
  161. $newFilePath = $tikipath . DIRECTORY_SEPARATOR
  162. . 'temp' . DIRECTORY_SEPARATOR
  163. . 'cache' . DIRECTORY_SEPARATOR
  164. . $tikidomain . DIRECTORY_SEPARATOR
  165. . 'target_' . $cacheType . $cacheName . $newFileExtension;
  166. // This will allow apps executed by Alchemy (like when converting doc to pdf) to have a writable home
  167. // save existing ENV
  168. $envHomeDefined = isset($_ENV) && array_key_exists('HOME', $_ENV);
  169. if ($envHomeDefined) {
  170. $envHomeCopy = $_ENV['HOME'];
  171. }
  172. // set a proper home folder
  173. $_ENV['HOME'] = $tikipath . DIRECTORY_SEPARATOR . 'temp' . DIRECTORY_SEPARATOR . 'cache' . DIRECTORY_SEPARATOR . $tikidomain;
  174. AlchemyLib::hintMimeTypeByFilePath($filePath, $file->filetype);
  175. $alchemy = new AlchemyLib();
  176. $contentType = $alchemy->convertToImage($filePath, $newFilePath, $width, $height, $animation, $previewPage);
  177. // Restore the environment
  178. if ($envHomeDefined) {
  179. $_ENV['HOME'] = $envHomeCopy;
  180. } else {
  181. unset($_ENV['HOME']);
  182. }
  183. if (file_exists($newFilePath)) {
  184. $content = file_get_contents($newFilePath);
  185. }
  186. unlink($newFilePath);
  187. if (empty($content)) {
  188. exit;
  189. }
  190. $cacheLib->cacheItem($cacheName, $contentType . ';' . $content, $cacheType);
  191. }
  192. session_write_close(); // close the session in case of large transcode/downloads to enable further browsing
  193. // Compression of the stream may corrupt files on windows
  194. ini_set('zlib.output_compression', 'Off');
  195. header("Expires: 0");
  196. header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
  197. header("Cache-Control: private", false);
  198. header('Content-Length: ' . strlen($content));
  199. header('Content-Type: ' . $contentType);
  200. header('Content-Disposition: inline; filename="' . $fileMd5 . '";');
  201. header('Connection: close');
  202. header('Content-Transfer-Encoding: binary');
  203. echo $content;
  204. exit;
  205. }