fpassthru

Reads a file handle from its current position to EOF and writes it straight to output.

Signature
fpassthru(resource $stream): int
  • Added in PHP 4.0.0

Parameters

ParameterTypeDescription
$streamresourceAn open file pointer from fopen() or fsockopen() that has not been closed.

Return value

intThe number of characters read from the stream and passed to output.

Errors

Throws a TypeError if the argument is not a valid open stream resource.

fpassthru takes an already-open stream and writes everything from the current position to the end straight to output. It streams in chunks rather than building a string, so memory usage stays flat no matter how large the file is.

When to reach for it

  • Serving a file download after you have already opened the handle — to check a header, verify a magic number, or take a lock.
  • Sending only the tail of a file, by fseek-ing first.
  • Draining a socket or process stream to the browser.

fpassthru or readfile?

If all you have is a path and you want the whole file, readfile() is the better choice — it does the fopen for you and returns the same byte count. Reach for fpassthru when you already hold a handle, or when you deliberately want to skip part of the file.

What trips people up

It starts from the current file position, not the beginning. If you have read a header or written to the handle, call rewind($fh) first or you will silently send a truncated file. This is the number one cause of "my download is missing its first bytes".

In a web context, send your Content-Type and Content-Length headers before calling it, and consider ob_end_flush() so output buffering does not undo the memory benefit. The handle is left open — fclose it yourself.

Example

Try it yourself
Loading editor…
Press Run to execute the code.

When to use it

  • Serve a protected download after checking permissions, without loading the file into memory.
  • Send only the last N bytes of a log file by fseek-ing before the passthru.
  • Pipe an in-memory stream you just built straight to the response body.

Frequently asked questions

What is the difference between fpassthru and readfile?

`readfile()` takes a path, opens it, and dumps the whole file; `fpassthru()` takes an already-open handle and dumps from the current position. Use `readfile` when you have just a filename and want everything.

Why is my fpassthru output missing the start of the file?

Because the file pointer was not at the beginning — any earlier `fgets`, `fread` or `fwrite` moved it. Call `rewind($fh)` before `fpassthru`.

Does fpassthru load the whole file into memory?

No, it streams the data in chunks, so memory usage stays constant regardless of file size. That is its main advantage over `echo file_get_contents($path)`.

More examples

Rewind before passing through

The full 31-byte file is emitted, header included, because `rewind()` reset the position after the inspection read. Drop the rewind and the output starts at `payload one`.

Example · php
<?php
file_put_contents('data.txt', "HEADER\npayload one\npayload two\n");

$fh = fopen('data.txt', 'rb');
$header = trim(fgets($fh));
echo "checked header: $header\n";

rewind($fh);                   // without this the header is missing
$n = fpassthru($fh);
fclose($fh);

echo "--\nsent $n bytes\n";
unlink('data.txt');

Sending only the tail of a file

Only the final stretch of the file is printed and the count reports 26 bytes. Combining `fseek` with `fpassthru` gives you a cheap tail without reading the earlier megabytes.

Example · php
<?php
$lines = '';
for ($i = 1; $i <= 20; $i++) { $lines .= "log line $i\n"; }
file_put_contents('tail.log', $lines);

$fh = fopen('tail.log', 'rb');
fseek($fh, -26, SEEK_END);     // jump near the end
$n = fpassthru($fh);
fclose($fh);

echo "--\n$n bytes from the tail\n";
unlink('tail.log');

Passing through an in-memory stream

The two written rows appear in the output followed by a count of 22. Because the stream lives in memory, this pattern lets you build a response body and flush it without a temp file.

Example · php
<?php
$fh = fopen('php://memory', 'r+');
fwrite($fh, "generated,report\n");
fwrite($fh, "1,ok\n");

rewind($fh);
$bytes = fpassthru($fh);
fclose($fh);

echo "--\n$bytes bytes emitted, nothing written to disk\n";

Discussion

  • Be the first to comment on this lesson.