|
H
hudster author
PHP Runner currently allows PDF documents to be viewed within the browser. However, word, excel, powerpoint and images are all downloaded. This solution allows you to view those files within the browser without needing to download. For this example I am using the library from Docmentis - it is free to use for personal and commercial use. If you want to remove their logo then you will need a licence. I am using the script loaded from their cdn but you can install it on your own server via npm. In this example I've used PHP Runner's document management template but it will work with your own projects.
Create a custom PHP pagein this example it is called docmentis_test_stream.php <?php
require_once("include/dbcommon.php");
if (!Security::isLoggedIn()) { http_response_code(401); exit("Not authorised"); }
$id = (int)($_GET["id"] ?? 0);
if ($id <= 0) { http_response_code(400); exit("Invalid document ID"); }
$sql = DB::PrepareSQL( "SELECT id, file, ownerid, share_users, share_type FROM doc_files WHERE id = :1", $id );
$rs = DB::Query($sql); $row = $rs ? $rs->fetchAssoc() : null;
if (!$row) { http_response_code(404); exit("Document not found"); }
/* * Basic ownership check. * You may need to extend this later for shared documents. */ $currentUser = Security::getUserName();
if ( isset($row["ownerid"]) && (string)$row["ownerid"] !== (string)$currentUser && !Security::isAdmin() ) { /* * Temporarily comment this block out during testing * if ownerid contains a numeric user ID rather than username. */ }
$fileData = json_decode($row["file"] ?? "", true);
if ( !is_array($fileData) || empty($fileData) || empty($fileData[0]["name"]) ) { http_response_code(500); exit("Invalid uploaded-file metadata"); }
$file = $fileData[0];
$filePath = $file["name"]; $fileName = $file["usrName"] ?? basename($filePath);
$mimeType = $file["type"] ?? "application/octet-stream";
if (!is_file($filePath)) { http_response_code(404); exit("Physical file not found"); }
/* * Ensure the file is within the expected PHPRunner files directory. */ $allowedDirectory = realpath(__DIR__ . "/files"); $realFilePath = realpath($filePath);
if ( $allowedDirectory === false || $realFilePath === false || strpos($realFilePath, $allowedDirectory . DIRECTORY_SEPARATOR) !== 0 ) { http_response_code(403); exit("Invalid file path"); }
header("Content-Type: " . $mimeType); header( 'Content-Disposition: inline; filename="' . rawurlencode($fileName) . '"' ); header("Content-Length: " . filesize($realFilePath)); header("Cache-Control: no-store, no-cache, must-revalidate"); header("Pragma: no-cache");
readfile($realFilePath); exit;NEXT CREATE A CUSTOM BUTTON IN DESIGNERin server $record = $button->getCurrentRecord();
if (!$record) { $result["success"] = false; $result["message"] = "The current document record could not be retrieved."; return; }
$id = $record["id"] ?? ""; $hash = $record["hash"] ?? ""; $fileName = $record["name"] ?? "";
if ($id === "" || $hash === "" || $fileName === "") { $result["success"] = false; $result["message"] = "The protected file details are incomplete."; $result["record"] = $record; return; }
$result["success"] = true; $result["fileName"] = $fileName;
$result["fileUrl"] = "doc_files_list.php" . "?file=" . rawurlencode($fileName) . "&table=doc_files" . "&field=file" . "&pageType=list" . "&key1=" . rawurlencode((string)$id) . "&hash=" . rawurlencode((string)$hash);In client after if (!result || result.success !== true) { alert( result && result.message ? result.message : "Unable to open the document." ); return; }
const fileUrl = result.fileUrl; const fileName = result.fileName || "Document";
(async function () { let viewer = null; let client = null;
try { const response = await fetch(fileUrl, { method: "GET", credentials: "same-origin", cache: "no-store", redirect: "follow" });
if (!response.ok) { throw new Error( "PHPRunner returned HTTP " + response.status + " while retrieving the document." ); }
const contentType = response.headers.get("content-type") || "application/octet-stream";
const buffer = await response.arrayBuffer();
if (!buffer.byteLength) { throw new Error("PHPRunner returned an empty document."); }
const documentFile = new File( [buffer], fileName, { type: contentType } );
console.log("DocMentis document source", { fileName: documentFile.name, contentType: documentFile.type, size: documentFile.size, signature: Array.from( new Uint8Array(buffer).slice(0, 16) ) });
$("#docmentisButtonModal").remove();
const safeTitle = $("<div>") .text(fileName) .html();
$("body").append(` <div class="modal fade" id="docmentisButtonModal" tabindex="-1" aria-hidden="true" > <div class="modal-dialog modal-xl" style=" width:96vw; max-width:96vw; height:94vh; margin:2vh auto; " > <div class="modal-content" style="height:94vh;" > <div class="modal-header"> <h4 class="modal-title"> ${safeTitle} </h4>
<button type="button" class="close" data-dismiss="modal" aria-label="Close" > <span aria-hidden="true"> × </span> </button> </div>
<div class="modal-body" style=" padding:0; height:calc(94vh - 65px); overflow:hidden; " > <div id="docmentisButtonViewer" style=" width:100%; height:100%; min-height:600px; " ></div> </div> </div> </div> </div> `);
const $modal = $("#docmentisButtonModal");
$modal.modal("show");
$modal.on("shown.bs.modal", async function () { try { const module = await import( "https://cdn.jsdelivr.net/npm/@docmentis/udoc-viewer@0.7.12/+esm" );
const UDocClient = module.UDocClient || module.default?.UDocClient || module.default;
if ( !UDocClient || typeof UDocClient.create !== "function" ) { throw new Error( "DocMentis UDocClient could not be loaded." ); }
client = await UDocClient.create({ googleFonts: true });
viewer = await client.createViewer({ container: document.getElementById( "docmentisButtonViewer" ),
theme: "system", scrollMode: "continuous", layoutMode: "single-page", zoomMode: "fit-spread-width",
hideToolbar: false, disableSearch: false, disableThumbnails: false, disableFullscreen: false });
viewer.on("error", function (event) { console.error( "DocMentis viewer error", event ); });
console.log( "Loading document into DocMentis", documentFile );
await viewer.load(documentFile);
console.log( "DocMentis document loaded successfully", { pageCount: viewer.pageCount, metadata: viewer.metadata } );
} catch (error) { console.error( "DocMentis initialisation/load error", error );
$("#docmentisButtonViewer").html(` <div class="alert alert-danger" style="margin:20px;" > **Document could not be opened.** ${ $("<div>") .text( error && error.message ? error.message : String(error) ) .html() } </div> `); } });
$modal.on("hidden.bs.modal", function () { try { if (viewer) { viewer.destroy(); viewer = null; }
if (client) { client.destroy(); client = null; } } catch (cleanupError) { console.warn( "DocMentis cleanup error", cleanupError ); }
$(this).remove(); });
} catch (error) { console.error( "Protected document retrieval error", error );
alert( error && error.message ? error.message : "The document could not be retrieved." ); } })();For your own project you will need to change the SQL query in the PHP file and how the document link is formed (in this case it's filename and hash - but might not be in your own project). And that's it! Enjoy!
|
|
|