I have migrated from a small laptop using the docker installation (8.0.0 - Patch 3) to a desktop with a new, regular installation (8.0.0 - Patch 3). I had to restore the backup from the laptop to the desktop manually. All my documents appear in my records - that is, I see their names in the “Documents List” - but I cannot access them: trying to pop them out or download them gives only a blank page. How can I resolve this? Thank you.
Update: ChatGPT has, after a long and winding road down the garden path, got it to a state where I can download documents. However, Pop Out does not pop out but instead triggers a download, too. Not critical but annoying. How can I make pop out work properly? (ChatGPT tried and failed, and broke Download in the process - managed to get Download back again though.) Many thanks.
Hi @rdh61
While I don’t have a fix for your issue, here is an advice based on my experience that might help you get this sorted out:
-
If ChatGPT is stuck, try feeding your issue and setup details into other models like Claude, Gemini, or DeepSeek.
-
Check the Browser Console: open the Console tab before you click the “Pop Out” button. If a JavaScript error is breaking the pop-out logic and forcing a fallback download, the error will show up there in red.
-
Gather Logs: Check your web server (Apache/Nginx) or PHP error logs during the time you attempt to click the button.
Providing these logs to an alternative AI will give it data to work with. Hope this helps you track it down!
i think its the permission issue.
u can try these ( change the path to ur install
cd /var/www/html/openemr
Set ownership
chown -R www-data:www-data .
Directories
find . -type d -exec chmod 755 {} \;
Files
find . -type f -exec chmod 644 {} \;
chmod -R 775 /var/www/html/openemr/sites/default/documents
chown -R www-data:www-data /var/www/html/openemr/sites/default/documents
run these in console/terminal. should fix it.
Thank you for your kind suggestions. I will give them a try.
Thank you for your response, but given that I can now access the documents to download them, I don’t think the remaining fault would be with permissions. Also, the permissions of the documents directory, its sub-directories and the files within them are already set to www-data.
Following @moussa’s suggestion to check the browser console, I find that when opening the record for a patient, the following appears:
Request Method
GET
Status Code 403 Forbidden
I’m guessing this has something to do with it.
However, no new error messages appear when I click on Documents or Pop Out.
By Claude:
Issue 1: 403 on context=patient_picture — This Is Intentional in 8.0.0-P3
The document_id=-1 with context=patient_picture URL pattern was identified as an IDOR (Insecure Direct Object Reference) vulnerability — patient photos (PHI) could be retrieved for any patient by any authenticated user with document access, without the server verifying authorization. The expected fix is that the server now checks whether the user may access the patient’s record before serving the photo, and returns 403 if not. GitHub
So the 403 you’re seeing is the security patch working correctly — but it broke legitimate use cases too, as confirmed by the community.
The error log signature is: OpenEMR.WARNING: An attempt was made to retrieve a patient picture for an unauthorized patient {"user-id":"4","requested-patient-id":"2236","session-pid":"0"} — the key is "session-pid":"0", meaning the session doesn’t have the patient loaded when the picture request fires (e.g., on calendar hover). OpenEMR
The root cause: The security fix requires $_SESSION['pid'] to match the requested patient_id. When the request fires outside of an active patient context (like a calendar tooltip, or a custom module calling it directly), session-pid is 0 and it returns 403.
Fix Options
Option A — Set the session pid before the request (proper fix)
Before making the controller.php?...context=patient_picture call, your code (or the custom module) needs to have the patient loaded in session. In OpenEMR, this means the patient must be selected via setpid(). If you’re calling this from a custom module or external page, add:
php
// At the top of your custom page, before rendering the photo URL:
require_once($GLOBALS['srcdir'] . '/pid.inc.php');
setpid($patient_id); // sets $_SESSION['pid']
Option B — Use the authenticated demographics route instead
Rather than calling controller.php directly, load the photo through a page that already has the patient in session context (i.e., navigate to the patient first via interface/patient_file/summary/demographics.php). The photo will load correctly once the patient is active.
Option C — Check the new authorization logic in C_Document.class.php
The new check in 8.0.0-P3 for patient_picture context likely looks something like:
php
if ($_SESSION['pid'] != $patient_id) {
// 403
}
If your use case is legitimately a staff user (not a patient portal session), you can patch C_Document.class.php to also allow access when $_SESSION['authUserID'] is set and the user has document ACL permissions — essentially restoring the pre-patch behavior for authenticated staff while keeping the portal restriction. But be cautious: this is a security regression.
Issue 2: Pop-Out Triggering Download Instead of New Window
Good news: OpenEMR’s C_Document.class.php already controls Content-Disposition based on the as_file parameter — when as_file=false, it serves Content-Disposition: inline; when as_file=true, it serves attachment. GitHub
So the PHP side is already correct for the pop-out case (as_file=false in the URL). The problem is purely on the JavaScript side — the Pop Out button is likely triggering a download action or using the wrong URL. Here’s where to look:
Locate the Pop Out button JS
In OpenEMR 8.x, the document viewer JS is in:
interface/patient_file/documents.php
or rendered via the document list template. Search for popout, pop_out, or window.open in that file.
The fix is to ensure the Pop Out handler uses window.open() and passes as_file=false:
javascript
// Find something like this (broken — may be using location.href or a download link):
document.getElementById('btn_popout').addEventListener('click', function() {
window.location.href = docUrl; // ← this triggers download behavior
});
// Fix — force new window with inline disposition:
document.getElementById('btn_popout').addEventListener('click', function() {
let url = docUrl.replace('as_file=true', 'as_file=false');
window.open(url, '_blank', 'width=900,height=700,noopener,noreferrer');
});
If ChatGPT swapped the Download button to use window.open() when fixing something else, it may have accidentally made both buttons share the same handler or URL. Check that:
-
Download button uses
as_file=true(or justwindow.location.href) -
Pop Out button uses
window.open(url_with_as_file=false, '_blank')
@moussa Thank you very much for taking the time and for the exhaustive response. It may take me a little while to process all that - I’ll feed back here when I have.