Drupalのファイルパスの種類と画像を読み込むときの注意点

  •  
 
ホス2021年1月18日 - 12:08 に投稿

こんにちは。

この記事では、Drupalのファイルパスの種類と、それを踏まえて画像ファイルを扱うときにハマった注意点を紹介します。

話の概要

  • Drupalのファイルパスについて
  • PHPで画像ファイルを扱うときの回転と、ファイルパスの注意点

環境

  • CMS
    • Drupal 9.1.0
  • PHP
    • PHP 7.4.13
  • Web Server
    • Apache/2.4.37 (centos)

Drupalのストリームラッパーについて

Drupalには、ストリームラッパーというファイル保存の仕組みがあります。

Drupalのソースコード内でファイルのパスとして利用することができます。

種類は以下のとおりです。

  • public:// (class PublicStream)
    • 誰でも保存できます。
    • 誰でも取得できます。
  • private:// (class PrivateStream)
    • 誰でも保存できます。
    • 権限のあるユーザだけが取得できます。
    • 匿名ユーザの場合は保存したときと同じSessionの場合取得できます。
  • temporary:// (class TemporaryStream)
    • 権限については確認しておりません。
    • 一定時間経過後に自動削除させることができる模様。

それぞれの実際のファイルシステム上での保存先は、settings.phpで任意の場所に設定することができます。

  • $settings['file_public_path'] = 'sites/default/files';
  • $settings['file_private_path'] = '/usr/share/httpd/drupal_private';
  • $settings['file_temp_path'] = '/tmp';
  • temporary://の削除タイミングは環境設定のファイルシステムから設定できるようです。

ファイルパスの種類について

Drupalでは、先ほどのストリームラッパーの他にも、一般的なファイルパスの指定方法が存在します。

  • ストリームラッパーのパス (uri)
    • public://data/~~~~~
  • URL
    • htp://example.com/system/~~~~~
  • ファイルシステム上のパス (realpath)
    • /var/www/html/drupal/~~~~~

uriからURLやrealpathへは変換が可能です。

  • uri以外からの変換は今回試しておりません。
  • 匿名ユーザがPrivateストリームに保存したファイルは、uriからURLへ変換したとしても、そのセッションがないとURLから取り出せません。(403エラー)

画像の向きとPHPの関係について

話がガラッと変わりまして、ここからはPHPで画像を回転するときのお話になります。

JPG画像には、画像の向きを指定するExif情報が保存されていることがあります。

カメラで撮影した画像は、撮影時のカメラの物理的な向きのまま画像保存されていて、それを正しい向きにするためのExif情報が画像と一緒にファイルに保存されています。

MacのプレビューアプリやブラウザなどではExifを読み取り正しい向きに回転して表示しているため、普段意識することはありません。

 ※ Macのプレビューアプリの ツール > インスペクタを表示 で画像内に保存されている回転の情報が確認することができます。

しかし、PHPではExifが自動で読み込まれないため、実装で対処する必要があります。

PHPでExifの向きの情報を処理する例

ここからは、Drupalのカスタムモジュールで画像をアップロードしてPHPでExifの向きの情報を処理する流れを紹介します。

1.FormでファイルをPrivateにアップロードするように実装します。

  • Drupalのカスタムモジュールの基本的な作り方については、この記事では割愛いたします。
  • Drupalのmanaged_fileを利用してファイルをアップロードする機能を実装できます。
  • 実装例
  public function buildForm(array $form, FormStateInterface $form_state) {
    $form = parent::buildForm($form, $form_state);
    $form['upload_image'] = [
      '#type' => 'managed_file',
      '#upload_location' => 'private://data',
    ];
    以下略

$form_state配列にファイルのIDが格納されていますので、
$form_state->getValue('upload_image')[0];でファイルのIDを取得することができます。

2.Formのsubmit処理などで以下のようにファイルを取得して回転の加工をします。

Formに入力されたファイルIDからPrivateストリームのパスを取得する処理を実装します。

  /**
   * Get upload image file path.
   */
  protected function getUploadFilePath($form_state) {
    $file_id = $form_state->getValue('upload_image')[0];
    $file = File::load($file_id);
    $uri = $file->uri;
    return $uri->value;
  }

3.DrupalのPrivateストリームをファイルシステムのパスに変換します。

$file_absolute_path = \Drupal::service('file_system')->realpath($file_private_path);

4.ファイルシステムにある画像のExif情報を取得します。(ファイルシステム上のパスを指定する必要がある点に注意)

$exif_data = exif_read_data($file_absolute_path, "EXIF", FALSE, FALSE);
  • このとき、Privateストリームのパスを渡すと一部の画像はExif情報が読み取れません。(一部はなぜか読み取れます)
  • exif_read_data()メソッドの仕様では、ファイルシステム上のパスを指定する必要があります。 ※ここが重要です。

5.もしExif情報があり、その中に回転の情報(Orientation)があったら、回転処理を行います。

if (!empty($exif_data) && array_key_exists('Orientation', $exif_data)) {
    $this->imageOrientation($src_file, $exif_data['Orientation']);
}
  • imageOrientation()メソッドは自作します。様々な方法がインターネット上に公開されておりますので、ここでは割愛いたします。

6.回転処理したあとの画像を変数に読み込み、このあと色々と目的の画像加工を行います。

$src_image = imagecreatefromjpeg($src_file);

まとめ

  • Drupalではファイルパスの種類が複数あります。
  • 呼び出すメソッドによって、どのファイルパスを利用すべきか注意する必要があります。

コメントを追加

プレーンテキスト

  • HTMLタグは利用できません。
  • 行と段落は自動的に折り返されます。
  • ウェブページのアドレスとメールアドレスは自動的にリンクに変換されます。
CAPTCHA
この質問はあなたが人間の訪問者であるかどうかをテストし、自動化されたスパム送信を防ぐためのものです。