Limited amount of files uploads with hook for iptc data

Using k3.6

I’m populating fields on image upload with exif- and iptc-data. It works fine but only for no more than 3 images at once (files are uploaded but an error is given saying files can’t be uploaded and iptc and exif fields remain empty). When I remove the iptc-data I can upload more than 3 files (tested with 10).

I haven’t used hooks before so I must be doing something wrong with the iptc data. I’ve got a fileMethods plugin:

<?php
  Kirby::plugin('myplugin/iptcmeta', [
    'fileMethods' => [
      'iptc' => function ($item) {

        getimagesize($this->url(), $info);
        if (isset($info['APP13'])) {
        $iptc = iptcparse($info['APP13']);

          if ($item == 'kop') {
            $iptc_item = $iptc['2#105'][0]; 
          }
          if ($item == 'beschrijving') {
            $iptc_item = $iptc['2#120'][0]; 
          }
          if ($item == 'locatie') {
            $iptc_item = $iptc['2#092'][0]; 
          } 

         # and so on …
       
        return $iptc_item;
      }
    ]
  ]);

My hook uses it like this:

<?php
  Kirby::plugin('myplugin/metadata', [
    'hooks' => [
      'file.create:after' => function ($file) {
        $file->update([
          'iptc_kop'  => $file->iptc('kop'),
          'iptc_desc' => $file->iptc('beschrijving'),
          'iptc_locatie' => $file->iptc('locatie')

         # and so on …

         # also exif 

          $time = $file->exif()->timestamp(),
          'exif_date' => date('j-n-Y', $time),
          'exif_timestamp' => $file->exif()->timestamp(),
          'exif_date2' => $file->exif()->timestamp(),
          'exif_aperture' => $file->exif()->aperture(),

          # and so on …

        ]);
      }
    ]
]);

Any ideas on how to improve this code?
Thanks!

I don’t know if you have left things out, but the first problem I seem in the iptc method, where $info is not defined.

Then this bit in the middle of the array looks strange as well, but the code is incomplete.

Also, you could prevent multiple calls to the iptc method if you return the data you need as an array.

Apart from these potential code issues, you might run into runtime issues if script execution takes too long.

I followed the example on php.net, mind you I left out $size didn’t see any purpose …

<?php
$size = getimagesize('./test.jpg', $info);
if(isset($info['APP13']))
{
    $iptc = iptcparse($info['APP13']);
    var_dump($iptc);
}
?>

Formatting the date or is that bad practice?:

$time = $file->exif()->timestamp(),
'exif_date' => date('j-n-Y', $time),

How would I do that?

Oh, sorry, my bad, $info is returned from the getimagesize() method.

Could you please post the complete array you pass to $file->update()If you really have that $time bit inside the array, it won’t work.

sure:

 $file->update([
          'iptc_kop'  => $file->iptc('kop'),
          'iptc_desc' => $file->iptc('beschrijving'),
          'iptc_locatie' => $file->iptc('locatie'),
          'iptc_plaats' => $file->iptc('plaats'),
          'iptc_trefwoorden' => $file->iptc('trefwoorden'),
          $time = $file->exif()->timestamp(),
          'exif_date' => date('j-n-Y', $time),
          'exif_timestamp' => $file->exif()->timestamp(),
          'exif_date2' => $file->exif()->timestamp(),
          'exif_aperture' => $file->exif()->aperture(),
          'exif_iso' => $file->exif()->iso(),
          'exif_exposure' => $file->exif()->exposure(),
          'exif_focallength' => $file->exif()->focalLength(),
          $camera = $file->exif()->camera(),
          'exif_camera' => Str::lower($camera)
        ]);

The ‘$camera’ bit works …

Make your file method return an array with the data you need:

    'fileMethods' => [
        'iptc' => function () {
            $iptc_item = [];
            getimagesize($this->url(), $info);
            if (isset($info['APP13'])) {
                $iptc = iptcparse($info['APP13']);
                $iptc_item = [
                    'kop' => $iptc['2#105'][0] ?? '',
                    'beschrijving' =>  $iptc['2#120'][0] ?? '',
                    'locatie' => $iptc['2#092'][0] ?? '',
                ];

            
            }
            return $iptc_item;
        }
    ]

The use the returned array:

 'iptc_kop'  => $file->iptc()['kop'],
 // etc.

I’d move those variable definitions out of the array:

$time = $file->exif()->timestamp();
$camera = $file->exif()->camera();

$file->update([
  'iptc_kop'  => $file->iptc('kop'),
  'iptc_desc' => $file->iptc('beschrijving'),
  'iptc_locatie' => $file->iptc('locatie'),
  'iptc_plaats' => $file->iptc('plaats'),
  'iptc_trefwoorden' => $file->iptc('trefwoorden'),
  'exif_date' => date('j-n-Y', $time),
  'exif_timestamp' => $file->exif()->timestamp(),
  'exif_date2' => $file->exif()->timestamp(),
  'exif_aperture' => $file->exif()->aperture(),
  'exif_iso' => $file->exif()->iso(),
  'exif_exposure' => $file->exif()->exposure(),
  'exif_focallength' => $file->exif()->focalLength(),
  'exif_camera' => Str::lower($camera)
]);

Ok, thanks a lot Sonja, I will try this later.

I’ve adapted your suggestions (see code underneath) but no improvement max. file upload is 3. From 4 onwards eventually shows an error, ‘files can’t be uploaded’ but files do get uploaded only the meta data is missing. I might have done something wrong?

Hook:

<?php
  Kirby::plugin('myplugin/metadata', [

    'hooks' => [
      
      'file.create:after' => function ($file) {

        $time = $file->exif()->timestamp();
        $camera = $file->exif()->camera();
        $keywords = $file->iptc()['trefwoorden'];
        $trefwoorden = implode(', ',  $keywords);

        $file->update([
          'exif_date' => date('j-n-Y', $time),
          'exif_timestamp' => $file->exif()->timestamp(),
          'exif_date2' => $file->exif()->timestamp(),
          'exif_aperture' => $file->exif()->aperture(),
          'exif_iso' => $file->exif()->iso(),
          'exif_exposure' => $file->exif()->exposure(),
          'exif_focallength' => $file->exif()->focalLength(),
          'exif_camera' => Str::lower($camera),
          'iptc_kop'  => $file->iptc()['kop'],
          'iptc_desc'  => $file->iptc()['beschrijving'],
          'iptc_locatie'  => $file->iptc()['locatie'],
          'iptc_plaats'  => $file->iptc()['plaats'],
          'iptc_trefwoorden'  => $trefwoorden
        ]);
      }
    ]
]);

fileMethods:

<?php

  Kirby::plugin('myplugin/iptcdata', [

    'fileMethods' => [
      'iptc' => function () {
        $iptc_data = [];
        getimagesize($this->url(), $info);
        if (isset($info['APP13'])) {
          $iptc = iptcparse($info['APP13']);
          $iptc_data = [
            'kop' => $iptc['2#105'][0] ?? '',
            'beschrijving' =>  $iptc['2#120'][0] ?? '',
            'locatie' => $iptc['2#092'][0] ?? '',
            'plaats' => $iptc['2#090'][0] ?? '',
            'trefwoorden' => $iptc['2#025'] ?? ''
          ];
        }
        return $iptc_data;
      }
    ]
]);

My assumption is that the script takes too long to execute with each file calling the hook. I’d try if setting php max_execution_time in your php.ini setting to a higher value makes any difference.

I have adjusted max_input_time to 60 sec with no difference also upped memory_limit from 128M to 256M without effect

Without the keywords I got error:
"The JSON response could not be parsed:"

Which is something I didn’t see before, no extra info though just that. With just one iptc field didn’t make any difference. With just exif, file uploads are fast. I guess it’s just three at a time, still faster than typing out meta data again.

I could maybe request a feature for Kirby; to do iptc as it does exif?

What keywords?

sorry, dutch: 'trefwoorden' => $iptc['2#025'] ?? ''

There are still some issues in the hook code:

'hooks' => [
      
    'file.create:after' => function ($file) {

      $time = $file->exif()->timestamp();
      $camera = $file->exif()->camera();
      $keywords = $file->iptc()['trefwoorden'] ?? [];
      $trefwoorden = implode(', ',  $keywords);

      $file->update([
        'exif_date' => date('j-n-Y', $time),
        'exif_timestamp' => $file->exif()->timestamp(),
        'exif_date2' => $file->exif()->timestamp(),
        'exif_aperture' => $file->exif()->aperture(),
        'exif_iso' => $file->exif()->iso(),
        'exif_exposure' => $file->exif()->exposure(),
        'exif_focallength' => $file->exif()->focalLength(),
        'exif_camera' => Str::lower($camera),
        'iptc_kop'  => $file->iptc()['kop'] ?? '',
        'iptc_desc'  => $file->iptc()['beschrijving'] ?? '',
        'iptc_locatie'  => $file->iptc()['locatie'] ?? '',
        'iptc_plaats'  => $file->iptc()['plaats'] ?? '',
        'iptc_trefwoorden'  => $trefwoorden
      ]);
    }
],

Didn’t we check for empty in the fileMethods already, not enough?

Anyway, as a double check I’ve changed that and used the hook in a 3.5.7.1 starterkit and got the same result 3 files ok, 4 files: throws an error but files are uploaded, but no meta data.