課題の提出ファイルを一括ダウンロードする改良

課題を一括ダウンロードする改良(v1.2)

- Minoru Kawano の投稿
返信数: 10

河野です。

白井先生らのアドバイスや改良を参考に、課題モジュールで「単一ファイルのアップロード」や「高度なファイルのアップロード」で提出された学生のファイルを、一括してダウンロードする機能を改良しました。今回は、「オンライン課題」もダウンロードできるようにしました。
なお、あとで書きますが、動作に若干問題がある部分があります。ご注意ください。

今回は、2つパッチがあります。Moodle 1.9.2のオフィシャルリリース(Build: 20080711)のパッチと、三重大学版Moodle 1.9.2(Build: 20080723)へのパッチです。これは、三重大学版にはすでに以前公開した改良が適用されているためです。

利用するには、次のようにしてください。

  1. 添付している「lib.php.patch.tgz」をダウンロードして、mod/assignmentで解凍する。
  2. 「lib.php.orig.diff」と「lib.php.moodle19.diff」というファイルができあがる。
    1. オリジナルのMoodle 1.9.2 を利用している場合は、「lib.php.orig.diff」を「lib.php」に対してパッチを適用する。
    2. 三重大学版Moodle 1.9.2 を利用している場合は、「lib.php.moodle19.diff」を「lib.php」に対してパッチを適用する。
  3. オリジナルのMoodleの場合は、日本語の言語パック(例えば lang/ja_utf8/)のmoodle.phpの最後に次のような内容を、追記する。
    $string['downloadallassignment'] = '全ての課題をダウンロードする';

利用方法は、以前公開したのと同じです。提出課題を確認する画面で、右上にある「すべてのコース評定を表示する」の下に「すべての課題をダウンロードする」というリンクがあらわれるので、クリックすれば、課題を一括してダウンロードできます。
ダウンロードされるファイルの名前は、「20080916_第○会の課題.zip」というように、「ダウンロードした日付_課題の名前.zip」となります。ダウンロードしたファイルを展開すると、ユーザ名ごとのフォルダの中に、ユーザが提出したファイルがあります。オンライン課題の場合は、「ユーザ名.txt」というファイルが作られ、その中に入力した内容が書かれています。

最後に、動作上の問題点ですが、現在のところWindows XP上でIE6,7とFirefox3.0で動作を確認しています。Google Chromeでは、ダウンロードされるファイル名の日本語部分が文字化けします(圧縮された内容は問題ありません)。
また、なぜファイル名の最初にダウンロードした日付を入れたかという点ですが、白井先生のように、最初は「課題の名前.zip」としようと思ったのですが、「第○回」という課題名の場合、ZIPファイルの名前が「○回」となってしまう問題が発生しました。ちょっと改善策が思いつかなかったため、今回のような仕様になっています。この点について、アドバイスをいただけると幸いです。

Minoru Kawano への返信

Re: 課題を一括ダウンロードする改良(v1.2)

- Tatsuya Shirai の投稿

 関係ないかも知れませんが,fs_moodleでは以下の改良をZIPの処理に関して行っています.特に(2)の方はドライブレターの処理に関わる,つまりファイル名の頭の方に対して行なう処理のような気がします(記憶があやふや).ですので,このあたりを中心にチェックしてみては如何でしょうか.

http://www.suzuka-ct.ac.jp/mech/moodle/mod/wiki/view.php?id=320&page=view/lib%2Fpclzip%2Fpclzip.lib.php


      $p_path = fsCharset2CurrentCharset($p_path);  // (ADD)
      $p_path = CurrentCharset2fsCharset($p_path);  // (ADD)

は,$p_pathがシフトJISの場合はUTF-8に,一旦戻してから処理を行い,再びシフトJISに戻しています.もともと$p_pathがUTF-8ならばこの処理は不要です.もっとも,$p_pathがUTF-8ならばオリジナルのコードでも問題は発生しないとは思います.ただ,ZIP関係でファイル名を破損する可能性のある箇所がこのあたり,という程度の情報として参考にして下さい.

Minoru Kawano への返信

Re: 課題を一括ダウンロードする改良(v1.2)

- Hiroshi Ueda の投稿
群馬大学の上田です。

三重大学版Moodle 1.9.4+(2007101542) をRHEL4にて利用させていただいております。ありがとうございます。
課題一括ダウンロードの機能を便利に使わせていただいておりますが、課題によっては
「申し訳ございません。ファイルが見つかりませんでした。」というエラーになります。

「課題名」に「+」と「&」が含まれるとこうなる、というところまでつきとめました。

現在、mod/assignment/ 中のファイルを修正しようとしていますが、当方の力不足で
今も悩んでおります。アドバイスいただければ幸いです。

Hiroshi Ueda への返信

Re: 課題を一括ダウンロードする改良(v1.2)

- Haruhiko Okumura の投稿
バグレポートありがとうございます。
この機能を作ってくださったかたがここを見ておられるはずですので,直していただけることを期待しています。 笑顔

Haruhiko Okumura への返信

Re: 課題を一括ダウンロードする改良(v1.2)

- Takayuki Fukuyama の投稿

福山です

開発版の方はメール購読されていなかったためにすっかり見落しておりました。

> 課題によっては「申し訳ございません。ファイルが見つかりませんでした。」というエラーになります。
> 「課題名」に「+」と「&」が含まれるとこうなる、というところまでつきとめました。

調査した感じで、従来版では常にsubmission.zipとしていたものが(日付)+課題名.zipとなった部分で挙動が乱れているようです。zipの作成をzip_files関数に投げるように変更されていますが、これによりzip_files関数内のclean_filename関数が呼ばれる事になります。これにより多くの文字がアンダーバーに置き換わってzipされますが(ご指摘の「+
」「&」などの他に「()かっこ」なども置き換わります)、元の変数が加工されていない為に copy($zippath, $tmpzippath); が失敗します。

        $zipbasename = mb_ereg_replace('[<>"\|:\\/\*\? ]', '_', $assignment->name);
        $zipbasename = mb_ereg_replace('_+', '_', $zipbasename);
        $zipname     = date("Ymd").'_'.$zipbasename.'.zip';
        $zippath     = $tmpdir.'/'.$zipname;

従いましてこの辺りのコードで行っているアンダーバーの変換はclean_filename関数に投げればそちらで整形されますから、この関数を使ってみてはいかがでしょうか

        $zipbasename = clean_filename($assignment->name);
        // $zipbasename = mb_ereg_replace('[<>"\|:\\/\*\? ]', '_', $assignment->name);
        // $zipbasename = mb_ereg_replace('_+', '_', $zipbasename);
        $zipname     = date("Ymd").'_'.$zipbasename.'.zip';
        $zippath     = $tmpdir.'/'.$zipname;

とすればcleanされた後のファイル名が取得できるので(逆に、この関数を使って予め取得しておかないとclean_filenameされた後のファイル名を取れなそう)、失敗はほぼしないと思われます(厳密にはこのbasenameにひっついてくるprefixやテンポラリディレクトリのパスもclean_filenameした方がいいかもしれませんが、この処理ではまず問題なく失敗する事は無いと思います。

また、現在では

$CFG->unicodecleanfilename = true;

以外の状態で利用した場合、課題に日本語が入っていると失敗してしまいます。この機能を利用する環境は概ねこのフラグがonになっているとは思いますが、これが付いていない状態でclean_filenameするとファイル名が落ちたり大部分のファイル名がアンダーバーに置換されてしまいます。この関数内だけでも強制的に

$CFG->unicodecleanfilename = true;

を立ててからclean_filenameしてやれば課題名に日本語が入っていても正常にzipを吐いてくれると思います。この関数は課題のファイル郡をまとめたzipを吐いて抜けるだけなので、この設定フラグを立てても他への影響は少ないと思われますが、いかがでしょうか。

Takayuki Fukuyama への返信

Re: 課題を一括ダウンロードする改良(v1.2)

- Tatsuya Shirai の投稿

 大元のところから行くと,+や&のような文字をオリジナルのMoodleは取り扱えないはずですので,そもそもアップロードした段階でファイル名を修正する必要があるのかも知れません.

#当方の環境はそれらの文字を使用可能となるような改造を行ったMoodleですので,ファイルの削除やリネームが可能です.しかしzip書庫の作成はできませんでした.対策が必要ですね.

Tatsuya Shirai への返信

Re: 課題を一括ダウンロードする改良(v1.2)

- Tatsuya Shirai の投稿

 ああ,すみません,思いっきり勘違いしていました.学生が提出した課題のファイルのファイル名に+や&を含んでいた場合ではなく,ですね.

 fs_moodleではfunction clean_filename()の条件を緩和して,ダブルクオート以外の文字をファイル名と使用可能としています.ですので,その問題は発生しませんでした.

 しかし勘違いしたお陰で,もっと致命的な(fs_moodle版固有の)問題点が二つも発覚しました.一つはWindows環境で外部zipコマンドを利用してzip書庫を作成する際(バックアップでも使われていますね...)に,zipコマンドに引数として渡されるファイル名やフォルダ名に&や+が含まれているとzipコマンドが正しく引数を受け取れないという問題(zipに失敗)です.指定されたフォルダ以下に含まれるファイル名やフォルダ名に&や+が含まれていても問題はありません(escapeshellarg()関係なので).対策しました.
 もう一つは,一括ダウンロードにおいて学生が提出したファイルが”日本語文字を含むファイル名”の場合にzip書庫に格納されない”というバグでした.これは,データベースには提出した記録が残っているのに実際にはmoddataにファイルが存在しない(管理者がサーバ上で手作業にて削除したなど)場合であっても処理がコンティニューするようにした条件部分です.この問題はWindows環境においてのみ発生するfs_moodle版の問題です.もしファイルが存在しなかったらコピーしない(できなくても気にしない)という条件部にfile_exists()とis_file()関数を使用していました.自分で開発しておきながら,fs化を忘れるという痛恨のミスでした.これも対策しました.

 以上,fs_moodleをWindows環境にて使用している場合にのみ発生する問題です.もし急ぎで対策版が必要な方はご連絡下さい.来週の水曜日以降に公開する予定の次の版では直っています.

Takayuki Fukuyama への返信

Re: 課題を一括ダウンロードする改良(v1.2)

- Minoru Kawano の投稿

福山さん、こんにちは。河野です。

福山さんの改善がベストですね 笑顔 福山さんの書き込みを参考に、次のようにしてみました。

修正前は、

        $zipbasename = mb_ereg_replace('[<>"\|:\\/\*\? ]', '_', $assignment->name);
        $zipbasename = mb_ereg_replace('_+', '_', $zipbasename);
        $zipname     = date("Ymd").'_'.$zipbasename.'.zip';
        $zippath     = $tmpdir.'/'.$zipname;

となっていたものを、次のようにしてみました。ダウンロードするファイル名の最初の日付部分をコースの省略名に変更してみました。また、$CFG->unicodecleanfilename の設定も入れています。

                        // fukuyama & mkawano
        // fukuyama & mkawano
       
        $zippath     = $tmpdir.'/'.$zipname;

私も lib/moodlelib.php を見て、clean_filename 関数の中身を確認しました。基本的に、アルファベットと数字以外の文字は「_」に変換してしまうようですね。この関数を使ったほうがすっきりしますね。ereg_replace 関数を使わないのも、若干ですが、パフォーマンス的に良いように思います。

Minoru Kawano への返信

Re: 課題を一括ダウンロードする改良(v1.2)

- Hiroshi Ueda の投稿
上田です。
ありがとうございました。
課題名に「&」や「+」が入っていても正常に課題のzipファイルがダウンロードできるようになりました。
Hiroshi Ueda への返信

Re: 課題を一括ダウンロードする改良(v1.2)

- Minoru Kawano の投稿

兵庫大学の河野です。ダウンロード機能を作ったものです。

上田先生が報告してくださったエラーですが、私のほうでも確認しました。
サーバはCentOS5.2で、三重大学版 Moodle 1.9.4+ (Build: 20090325) です。

応急処置になりますが、mod/assignment/lib.php の次の内容の行(3か所あります)

$zipbasename = mb_ereg_replace('_+', '_', $zipbasename);

を、次のように書き換えてみてください(赤字の部分)。課題名の「+」や「&」の部分を、「_」に置き換えてしまいますが、ダウンロードできるようになると思います。

$zipbasename = mb_ereg_replace('', '_', $zipbasename);

おそらく課題ファイルを圧縮する部分(pclzip)で、圧縮先のファイル名に「+」や「&」が貼っていてはいないためではないかと思います。ただ、はっきりした原因はつかんでいませんので、調査してみたいと思います。
とくに支障がないようでしたら、上の修正で対応していただければと思います。

Minoru Kawano への返信

Re: 課題を一括ダウンロードする改良(v1.2)

- Minoru Kawano の投稿

本筋とは無関係ですが、一部訂正です。恥ずかしい

  • 誤:貼っていてはいないためではないか
  • 正:入っていてはいけないためではないか