Tiny
Tiny

Reputation: 27899

PDF file stored in BLOB is not displayed with the "Content-Length" response header

The following example is meant for displaying a PDF file, when requested.

$sql = "SELECT file FROM file_upload WHERE id=:id and file_type in('pdf')";
$query = $conn->prepare($sql);
$query->execute(array(':id' => $_GET['id']));

$query->bindColumn("file", $file, PDO::PARAM_LOB);
$query->fetch(PDO::FETCH_BOUND);

$finfo = new finfo(FILEINFO_MIME);
$mimeType = $finfo->buffer($file);

header("Content-type: $mimeType");
header('Content-Description: PDF document');
header('Content-Transfer-Encoding: binary');
header('Accept-Ranges: bytes');
//header('Content-Length: '.strlen($file));
header('Expires: 0');
header('Pragma: no-cache');
header('Cache-Control: no-cache, must-revalidate, max-age=0');

ob_clean();
flush();
echo $file;

The requested PDF file is displayed but when the following line is added,

header('Content-Length: '.strlen($file));

the browser does not display the requested PDF file. The browser issues a message.

enter image description here

What might be the reason? The length returned by strlen() does not appear to be the exact length. strlen() however, returns 451295 for an uploaed PDF file of size 506,296 bytes (about 495 KB).

Trying on recent versions of Google Chrome and Mozilla FireFox using PHP 5.4.

Upvotes: 1

Views: 872

Answers (1)

bishop
bishop

Reputation: 39364

When you have the mbstring extension enabled, the strlen function returns the length of the string in characters, not necesasrily as bytes. The workaround is to detect, at run-time, the extension situation and use the appropriate method.

One way to handle this is a function that always returns bytes, regardless of the presence or absence of the mb extension. Example:

if (2 & ini_get('mbstring.func_overload')) {
    function bytes($string) {
        return mb_strlen($string, '8bit');
    }
} else {
    function bytes($string) {
        return strlen($string);
    }
}

You can of course rewrite that to put the condition inside the function, instead of having a conditional function. That incurs a run-time penalty for a constant check, so it's more efficient to have conditional functions. Depends upon your needs, though.

You may also use a third-party library. The example above is taken from haldayne/boost. Disclaimer: I'm the author of haldayne/boost.

Upvotes: 1

Related Questions