カスタムモジュールでのExif除去

We encourage users to post events happening in the community to the community events group on https://www.drupal.org.
birdaqua's picture

画像をアップロード時に,Exifデータを消去しようと思い,phpのimagick拡張モジュールとhook_file_presaveを用いて,下記のカスタムモジュールを作成しました。

function modulename_file_presave(Drupal\file\FileInterface $file) {
if ($file->getMimeType() == 'image/jpeg') {
$path = $file->getFileUri();
$img = new Imagick($path);
$img->stripImage();
$img->writeImage($path);
$img->clear;
}

}

  $img->writeImage($path);

の部分がよくないようで,実行すると,下記のエラーメッセージが表示されます。

Drupal\Core\Entity\EntityStorageException: unable to open image `public://filefield_paths/ファイル名.jpg': No such file or directory @ error/blob.c/OpenBlob/2643 in Drupal\Core\Entity\Sql\SqlContentEntityStorage->save() (line 777 of core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorage.php).

filefield_pathのモジュールを有効にしておりますが,使用しない設定にしても同様のエラーメッセージが表示されました。
また,ファイルのアップロード後に「public://filefield_paths/ファイル名.jpg」は存在しております。

何が問題で,どのようにすればExifなしの画像ファイルに置き換えられますでしょうか。
おわかりの方,ご教示いただけますと幸いです。よろしくお願いいたします。

Comments

blauerberg's picture

Imagick:: writeImage が引数に要求するのはファイルシステム上のパスですが、$path に入っているのがDrupalのファイルURIだからじゃないでしょうか。

こんな感じでどうでしょうか?

$filepath = \Drupal::service('file_system')->realpath($file->getFileUri());
$img = new Imagick();
$img->stripImage();
$img->writeImage($path);
...

解決しました!

birdaqua's picture

うまくいきました!
パスにもいろいろあるのですね。勉強になりました。
ありがとうございました!

birdaqua's picture

今更ながら気がついたのですが、hook_file_presaveで処理を行うと、どのように画像ファイルをアップロードしても、処理が実行されてしまいます。

そこで、
if ($file->getMimeType() == 'image/jpeg') {
の行に
  &&コンテンツタイプが○○
という条件を追加して、特定のコンテンツタイプに画像ファイルをアップロードしたときのみ処理を実行したいのですが、ファイルがどのコンテンツタイプに紐付いているのかを特定する手段がわかりません。
何かよい方法はございませんでしょうか。
よろしくお願いいたします。

entityQueryで

blauerberg's picture

entityQueryで「そのfidをフィールドとして持っているノードのコンテンツタイプ」を取るクエリを書けば判断できます。
https://api.drupal.org/api/drupal/core%21lib%21Drupal.php/function/Drupa...

早速ありがとうございます

birdaqua's picture

早速ありがとうございます。viewsのフィルターみたいなことができるのですね。

あまりよく理解できておらず申し訳ございませんが、このようなことで合っておりますでしょうか?
 fileのfidを取得;
 $query = \Drupal::entityQuery('node');
$query->condition('fid', '取得したfid');
$content_type = $query -> bundle();
if ($content_type ==○○){
 ……

そして、fidの取得方法で躓いております。
度々申し訳ございませんが、ご教示いただけますと幸いです。
よろしくお願いいたします。

保存前だと動かない?

birdaqua's picture

度々すみません。

entityQueryで取得する方法ですが,
file_presaveでファイルやノードが保存される前だと,取得することはできないのではないかと思ったのですが,考え違いでしょうか。

よろしくお願いいたします。