giftファイルの拡張子について

Re: giftファイルの拡張子について

- Tatsuya Shirai の投稿
返信数: 8

了解です。

 明日まで出張ですので実験はできませんが、後日、確認してみましょう。

 5年前のMoodle2.4ではfinfo_file()関数を使用してファイルの種類を判別する機能が実装されています。但しバックアップ機能の中での実装のようですので、システム全体では別のメカニズムを使用しているのかも知れません。

https://ja.osdn.net/projects/fs-moodle/scm/svn/blobs/head/tags/fs_moodle2.4/fs_moodle5.00.05/backup/cc/cc_lib/gral_lib/functions.php

 可能性としては、Windows用PHPの実装や設定の影響の可能性もありますね。finfo_file()関数を併用してmimeタイプを判別していると仮定しますと、php_fileinfo.dllを有効にしないと機能しません。その場合は拡張子のみに基づいてmimeタイプを取得するようmoodleが実装されているかも知れません。

http://stackoverflow.com/questions/23287341/how-to-get-mime-type-of-a-file-in-php-5-5

すみません、憶測ばかりになってしまって…


評点平均: お役立ち度: ★★★★★★★ (2)
Tatsuya Shirai への返信

Re: giftファイルの拡張子について

- タツヤ フジイ の投稿

白井 様

php_fileinfo.dllを有効にしたところ、拡張子giftのファイルをインポートできるようになりました。

的確なアドバイスありがとうございました。

ご相談の内容が変わってしまいますが、このようなケースで確認すべきログ等はございますでしょうか。

具体的には「php_fileinfo.dll」が無効であることのエラーログがどこかに出力されているものなのでしょうか。

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


PHPのバージョンを追記しておきます。

PHP Version 5.6.30

タツヤ フジイ への返信

Re: giftファイルの拡張子について

- Tatsuya Shirai の投稿

 おお,ビンゴですね.良かった.

 さて,問題のエラーですが,moodle/question/inport_fomat.phpのfunction validate_updloaded_file()の

            $errors['newfile'] = get_string('importwrongfiletype', 'question', $a);

ここで発生していますね.条件は,(!$qformat->can_import_file($file)) で,これはmoodle/question/fomat.phpの

    public function can_import_file($file) {
        return ($file->get_mimetype() == $this->mime_type());
    }

これです.function get_mimetype()は,うーん,追跡が困難ですが,多分,moodle/lib/filestorage/file_storage.phpの

     public static function mimetype($pathname, $filename = null) {
        if (empty($filename)) {
            $filename = $pathname;
        }
        $type = mimeinfo('type', $filename);
        if ($type === 'document/unknown' && class_exists('finfo') && file_exists($pathname)) {
            $finfo = new finfo(FILEINFO_MIME_TYPE);
            $type = mimeinfo_from_type('type', $finfo->file($pathname));
        }
        return $type;
    }

ですね.太字の部分,function mimeinfo()は,moodle/lib/filelib.phpの中にあります.うーん,拡張子で判断しているようですね.

var_dump($filename);
    $filetype = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
    if (empty($filetype)) {
        $filetype = 'xxx'; // file without extension
    }
var_dump($filetype);

とトラップを仕掛けると,インポートする際にここを二回通っていますね.一度目は$filenameが「ファイル名.gift」で$filetypeが「gift」,二度目が「.txt」と「txt」.その後に$mimeinfo[$filetype][$element]をチェックすると,一度目がNULLで二度目が「text/plain」.ファイル名だけではダメで,function mimetype()の中の

            $finfo = new finfo(FILEINFO_MIME_TYPE);
            $type = mimeinfo_from_type('type', $finfo->file($pathname));

で調べ直しているようですね.このコードが実行されるのは,class_exists('finfo')がtrueの時なので,dllが読み込まれていない場合はエラーを起こさずにdocument/unknownのまま抜けてしまいますね.したがってIISのエラーログにはdllが無効だという記録は残らないと思います.

Tatsuya Shirai への返信

Re: giftファイルの拡張子について

- Tatsuya Shirai の投稿
 それよりも気になった点が二つあります.

  1.  moodledata/tempにインポートするファイルをコピーしている
  2.  Shift-JISのままでインポートするとデータベース書き込みエラーが発生する

 1はOSがLinuxの場合は問題ないのですが,WindowsServerの場合はインポートするファイルが日本語を含む場合にトラブルが発生する可能性があります.如何ですか? 日本語ファイル名のテキストファイルをインポートして,直後にmoodledata/temp/questionの下を見て下さい.文字化けしたファイルが存在する可能性があります.Moodle1.9からMoodle2にバージョンアップした際にmoodledata内のファイルの管理が文字コードに依存しないデータベースを利用した方式に変わったことで,WindowsServerでこの問題は発生しなくなったのですが,moodledata/tempには素のファイルをコピーするコードがまだ多少,残っています.コピーする際に1バイト文字コードのテンポラリーなファイル名にしてくれれば良いのですが.2バイト文字をファイル名(やフォルダ名)に使った場合に,WindowsServer(日本語版)で発生する問題は以下の文書にまとめてあります.
http://tatsuva.com/ThesisPage/JECT/JECT2010_Vol32_Moodle_Shirai.pdf

 もし日本語ファイル名のテキストファイルをインポートする際に問題が生じる場合は,

  • 日本語のファイル名を使わないように注意徹底する.
  • インポートする前にファイル名のチェックを行ってエラーを発生するようにする(Moodleのソースコード追加).
  • テンポラリーファイルを作成する際にANKの一時ファイル名に置き換える処理を追加する(Moodleのソースコード追加).
  • fs_moodle(私が公開しているパッケージです)を使用する(ただし更新は滞り気味).

の対策が必要です.

 2のShift-JISは皆さん問題になっていないのでしょうか? ついうっかりとやらかしかねませんよね.これは比較的簡単に解決できる問題で,多分,moodle/question/format.phpの中のfunction readdata()で,$filearray = file($filename); で読み込んだ後に$filearrayをforaechで全要素の文字コードを強制的にUTF-8に変えてしまえば良いと思う.

Tatsuya Shirai への返信

Re: giftファイルの拡張子について

- Tatsuya Shirai の投稿

 2の,インポートする問題がUTF-8ではない(Shift-JISなど)と読み込みに支障が出る問題ですが,以前にLessonの読み込みで対応していましたね.

という訳で,moodle/question/format.phpを以下のように修正したらOKでしたね.from encoding(3つ目の引数)を"auto"にすると正しく動かないのは,何か私の環境で設定を間違えているのかも知れません.

    protected function readdata($filename) {
        if (is_readable($filename)) {
            $filearray = file($filename);
// (Shirai014): テキストファイルからインポートする問題(チェックはGIFTのみ)がUTF-8ではない場合に文字化けする問題
// (Shirai014): ここから追加
            foreach ($filearray as $key => $line) {
//              $filearray[$key] = mb_convert_encoding($line, 'UTF-8', 'auto');
                $filearray[$key] = mb_convert_encoding($line, "UTF-8", "ASCII,JIS,UTF-8,EUC-JP,SJIS");
            }
// (Shirai014): ここまで追加
            // If the first line of the file starts with a UTF-8 BOM, remove it.
            $filearray[0] = core_text::trim_utf8_bom($filearray[0]);

これはTrackerに投稿した方が良いでしょうかねぇ.皆さん,どうです?


Tatsuya Shirai への返信

Re: giftファイルの拡張子について

- Tatsuya Shirai の投稿

私の環境の設定ミスでした./etc/php.iniの mb_string関係が一切設定されていませんでした^^;

Tatsuya Shirai への返信

Re: giftファイルの拡張子について

- タツヤ フジイ の投稿

白井 様

お世話になります。

詳細な検証ありがとうございます。


エラーがログに残らない件、承知しました。

現在の環境では、使うとわかっているdllしか有効にしていないので、

ログに「xxxx.dllが無効」といったようなエラーや警告が確認できれば、

効率的にトラブルシュートができるかと思ったのですが、そうはなっていないようですね。

ちょっと逸れますが、ソースコードの辿り方など、大変参考になります。

OSSを使っているのですから、まずはソースを眺めるべきですよね。


----

インポートしたファイル名ですが、moodledata/temp/questionの配下をみると

たしかに文字化けしたファイル名のファイルが存在しました。

ファイルはUTF-8で作成したものですが、設問はちゃんと取り込めています。

今後の運用で注意していきたいと思います。

タツヤ フジイ への返信

Re: giftファイルの拡張子について

- Tatsuya Shirai の投稿

 やはり,moodledata/temp/questionの下に文字化けしたファイル(アップロードしたGiftファイル)がありましたか.

 ごく稀にですが,エクスプローラーでは削除できないファイルが生成されてしまう場合があります.どうやって削除したか私も覚えていないのですが….

 あと一つ気になるのはWindows版PHPの5C問題です.
 https://moodle.org/mod/forum/discuss.php?d=188351

 UTF-8で指定されたファイル名の文字コードに5Cを含むファイルが指定された場合,それがパスの区切り子(\)と誤解釈されます.つまりmoodleが,moodledata/temp/questionの下に存在しないディレクトリの下にファイルを作成あるいは読み出そうとしてエラーを発します.とりあえずソースコードに手を入れない方針であるならば,日本語ファイル名を使用しないように徹底するしかないですね.

 ソースコードを変更するのであれば,ブラウザから渡されたファイル名でmoodledata/temp/questionの下に受信したファイルの中身を保存する際に,tmpfile()で安全な一時ファイル名を取得してその名前に置き換えてしまうのが良いでしょうね.

 http://php.net/manual/ja/function.tmpfile.php

Tatsuya Shirai への返信

Re: giftファイルの拡張子について

- タツヤ フジイ の投稿

白井 様

いろいろ問題があるのですね。

Moodleを触り始めたばかりで、まだソースコードどうこうというレベルにありませんので、当面は日本語ファイル名を使わないよう運用を徹底します。

ありがとうございました。