Section: Sending a binary file
« Generating PDF with TCPDF | ^ Responses: generating content | Generating a ZIP file » |
− Table of content
To send binary content to the user (a graphic, a video, some sound, an archive, etc.),
jResponseBinary
should be used. To use it, indicate 'binary'
as the type of
response.
$resp = $this->getResponse('binary');
Afterwards, some variables need to be set to a correct value before content is displayed.
First, you have to set outputFileName
property. outputFileName
will
be the name shown to the user.
$resp->outputFileName = 'filename.gif';
Next, you can define the mime type of your content:
$resp->mimeType = 'image/gif';
You have an option for files you want the user to download (particularly, files
not rendered by common browsers - archives, for example). To force the download
of the file, simple set doDownload
to true.
$resp->doDownload = true;
For the content itself, you have to define either the filename
or the content
property.
Sending a file ¶
To send an existing file, just use filename
:
$resp->fileName = jApp::varPath('file_to_send.gif');
The file content is sent directly to the browser once the controller has finished processing.
Rather than instantiating a “binary” response yourself and manipulating its
properties, you can use the getFileResponse()
method. This method accepts
the path of the file to be returned and a boolean indicating whether to enable the
HTTP cache or not.
In this example, it returns a PDF directly.
class myController extends jController
{
public function getInvoice()
{
$invoiceFile = '/somewhere/invoices/invoice202505.pdf';
return $this->getFileResponse($invoiceFile);
}
}
Please note:
- The MIME type is automatically declared based on the filename extension
- The filename displayed to the user is that of the original file
- No forced download (
doDownload
set tofalse
). - If the file is not found, a 404 error is returned.
- If the HTTP cache is enabled, its validity is determined by the file modification date.
If you want to change these conditions, retrieve the object returned by getFileResponse
,
and manipulate it as indicated above before returning it.
class myController extends jController
{
public function getInvoice()
{
$invoiceFile = '/somewhere/invoices/invoice202505.pdf';
$response = $this->getFileResponse($invoiceFile);
$response->doDownload = true;
return $response;
}
}
Sending a lightweight content ¶
If your content is generated or comes from your database for example, set it on
the content
property:
$resp->content = '...';
However, it will take as much memory as the size of the content, so it could be an issue if the content is huge (higher than 1MB). PHP could stop the script if there is not enough memory or if the maximal memory amount configured into PHP is reached.
Sending huge content ¶
For huge content, it is better to send it directly during the reading of the data source, when Jelix will be able to send it to the browser.
There are two methods on jResponseBinary
. Use setContentCallback()
to give a callback function that will
fetch the content from somewhere and return it to the PHP output. Or use setContentGenerator()
to give an iterator
or a generator.
Here is an example, by sending to the browser the response of an HTTP request made with GuzzleHttp:
// we prepare and send the HTTP request to a specific service
$client = new GuzzleHttp\Client();
$request = new GuzzleHttp\Psr7\Request('GET', 'https://foo.example/content', $headers);
$response = $client->send($request, ['stream' => true]);
// we retrieve the http response as a stream, that is not consumed yet.
$stream = $response->getBody();
$rep = $this->getResponse('binary');
// we give a callback function that read the stream and send it to the PHP output (`php://output`),
// with copyToStream
$rep->setContentCallback(function () use ($response) {
$output = Psr7\Utils::streamFor(fopen('php://output', 'w+'));
Psr7\Utils::copyToStream( $response->getBody(), $output);
});
// ..
return $rep;
An other example with a generator
class Business {
// this function is a generator, because of the use of yield
public function getAllData()
{
$db = jDb::getConnection();
$resultSet = $db->query("SELECT field1, field2, field3 FROM hugeTable")
foreach($resultSet as $record) {
yield $record->field1.';'.$record->field2.';'.$record->field3."\n";
}
}
}
// Into the controller:
$obj = new Business();
$rep = $this->getResponse('binary');
$rep->setContentGenerator($obj->getAllData());
// ..
return $rep;