Data in postgresql bytea field is corrupted when saved

Hello there,
I am fighting with a problem for hours now.
this is my first forum entry, so I hope not to forget any needed information.
I am developing a management app where I need to save pictures directly into the database(Dont ask me why, just got the project from another developer-group). I thought this would go quite simple, but then i encounterd a problem.

I am sending all data via AJAX(AngularJs), so the picture is base64_encoded.

At first I thought it already got corrupted on this way, but when base64_decoding and saving the data, I get the exact picture. But when I save it into the database(postgresql) and retrieve it back, the picture is corrupted.
The picture is saved in a BYTEA field. Here is the beforeSave() method(Where I prepare the data to be saved):

public function beforeSave(Event $e, EntityInterface $entity, ArrayObject $options){
$entity->picture = base64_decode(str_replace([‘data:image/png;base64,’, ‘data:image/jpeg;base64,’], ‘’, $entity->picture));
$entity->picture_type = ‘image/png’;
$entity->picture_hash = hash(‘sha256’, $entity->picture);
$entity->logo = $entity->picture;
$entity->logo_hash = $entity->picture_hash;
$entity->logo_type = $entity->picture_type;

Am I doing anything wrong?

I found the answer.
It was not, that the image got corrupted while saving, but while reading.
I tried everything before, read it from the database, save it as file, but everything failed.
I was so frustrated, that I actually wrote code to upload the data via PDO.
This was when I encountered a missing piece of information on the Php Website which says,
that Bytea fields get returned as stream. I already knew that what I got as return value was a resource, but I never used streams before:

Long Story Short: I have to use stream_get_contents() to read the data correctly.

1 Like

Hello, how do you use the stream_get_contents() to get it from the database? I’m struggling when I call find in the table, the bytea field always returns null. Please help…

I use this method:

public function beforeFind(Event $event, Query $query, ArrayObject $options){
  $query->formatResults(function($results) use($options){
    return $results->map(function($row) use($options){
           $row['picture'] = "data:image/png;base64,".base64_encode(stream_get_contents($row['picture'])); //Before the row gets put into an entity, where it will be null
          $row['picture'] = '';
          $row['logo'] = "data:image/png;base64,".base64_encode(stream_get_contents($row['logo']));
          $row['logo'] = '';
      return $row;

After find, the stream won’t be accesible in the entity. Therefore you have to read the streams content here.

1 Like