Skip to content

readfileLowMemory() uses ob_end_flush() instead of ob_end_clean(), corrupting binary file downloads #37239

@Erwan-Wiwit

Description

@Erwan-Wiwit

Bug

The function readfileLowMemory() in htdocs/core/lib/functions.lib.php (line ~14464) flushes output buffers before
sending binary file content:

// Be sure we don't have output buffering enabled to have readfile working correctly
while (ob_get_level()) {
ob_end_flush();
}

ob_end_flush() sends any buffered content to the browser before the binary file data. If any PHP file loaded during
the request (module, conf, hook, etc.) has produced even a single byte of output (e.g., a space after a closing ?>
tag), that byte is prepended to the downloaded file, silently corrupting it.

Impact

  • All binary file downloads via document.php are affected (images, PDFs, etc.)
  • The corruption is silent: no error is shown, the file size appears correct (Content-Length is set from the original
    file, but the browser receives extra bytes before the actual content)
  • A single stray whitespace in any included PHP file (custom module, conf.php, etc.) breaks every file download
  • Images appear broken, PDFs won't open

Root cause example

A PHP file ending with ?>\x20 (closing tag + space) produces one byte of output. When document.php serves a file,
readfileLowMemory() flushes this byte before the binary content, shifting the entire file by one byte.

Suggested fix

Replace ob_end_flush() with ob_end_clean() to discard any stray buffered output instead of sending it:

while (ob_get_level()) {
ob_end_clean();
}

When serving a binary file, any previous PHP output is never intentional and should be discarded. This makes
document.php resilient to stray whitespace in third-party modules or configuration files.

Environment

  • Dolibarr version: 22.0.0
  • PHP version: 8.x

Dolibarr Version

22.0.4

Environment PHP

8.2

Environment Database

mariadb

Steps to reproduce the behavior and expected behavior

No response

Attached files

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    BugThis is a bug (something does not work as expected)

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions