16

For my client I have to use blob storage for some various files.

So I have created a independent bundle with a Blob class extends Doctrine\DBAL\Types\Type. and with a boot function in the bundle class.

That works pretty fine I can write in the database Blob datas.

But I can't download any document after :/

I have got:

public function downloadAction($id) {
    $em = $this->getDoctrine()->getManager();

    /* @var $entity Document */
    $entity = $em->getRepository('Lille3SapBundle:Document')->find($id);

    if (!$entity) {
        throw $this->createNotFoundException('Unable to find Document entity.');
    }

    $file = $entity->getFichier();

    $response = new \Symfony\Component\HttpFoundation\Response($file, 200, array(
        'Content-Type' => 'application/octet-stream',
        'Content-Length' => sizeof($file),
        'Content-Disposition' => 'attachment; filename="'.$entity->getNomDocument().'"',
    ));

    return $response;
}

and I have got an Exception: The Response content must be a string or object implementing __toString(), "resource" given.

in fact, the $file values is not the expected BLOB but something like Resource id #123

-> I have check blob data fields values, and they are ok in the database

So how can I force in the controller to have the blob row and not a Resource id #111

BenMorel
  • 34,448
  • 50
  • 182
  • 322
saillantist
  • 191
  • 1
  • 1
  • 6
  • 1
    Can you show us the content of `getFichier` method? Is `resource` being generated in that call? If not it's a bit odd to store resource **handle** in you database... – Jovan Perovic Mar 04 '13 at 17:12

2 Answers2

28

You can still use BLOB field for your field in DB as you initially planned.

In createAction store data as usual (with no base64_encode()):

$stream = fopen($entity->getFichier(),'rb');
$entity->setFichier(stream_get_contents($stream));

and in downloadAction just use:

$file = $entity->getFichier();
$response = new \Symfony\Component\HttpFoundation\Response(stream_get_contents($file), 
    200, 
    array(
        'Content-Type' => 'application/octet-stream',
        'Content-Length' => sizeof($file),
        'Content-Disposition' => 'attachment; filename="'.$entity->getNomDocument().'"',
    ));

return $response;

Explanation:

BLOB fields are treated as resource variable which have no __toString() implementation.

gettype($file) -> "resource"
get_resource_type($file) -> "stream"

stream_get_contents($file) makes the magic here: gets STRING content from resource variable.

DazBaldwin
  • 4,125
  • 3
  • 39
  • 43
Rafal Gradziel
  • 321
  • 3
  • 4
  • 4
    Don't forget to call `rewind($entity->getFichier());`, if you are getting stream straight from Doctrine entity's attribute. – Dejv Apr 22 '16 at 13:01
  • @Rafal Gradziel It worked 90%. But I couldn't download the file. In the response I am getting the file contents as the output in the console. Any help ! ! – Prabhu Khanna Mahadevan Oct 05 '16 at 15:54
  • 1
    I am trying to apply this but end up with PHP error: `Message: fopen() expects parameter 1 to be a valid path, resource given` – Gerard van den Bosch Nov 01 '18 at 03:56
  • FYI I had issues with sizeof() always returning 1 and thus severely truncated files. I had to do `strlen($file)` instead of `sizeof($file)` – willbradley Jan 14 '21 at 23:55
1

Okay, I have got a (very uggly) solution:

Firstly: I changed the data type blob to text for the file attribute of Document entity.

Secondly: in createAction I've changed the setFichier call:

$stream = fopen($entity->getFichier(),'rb');
$entity->setFichier(base64_encode(stream_get_contents($stream)));

Thirdly: in downloadAction, I decode the text base64 text field:

$file = $entity->getFichier();              
$response = new \Symfony\Component\HttpFoundation\Response(base64_decode($file), 200, array(
        'Content-Type' => 'application/octet-stream',
        'Content-Length' => sizeof($file),
        'Content-Disposition' => 'attachment; filename="'.$entity->getNomDocument().'"',
));

return $response;

And now I can persist and download files as blob way...

saillantist
  • 191
  • 1
  • 1
  • 6