開発:ファイルAPI

提供:MoodleDocs
2009年3月1日 (日) 18:30時点におけるMitsuhiro Yoshida (トーク | 投稿記録)による版 (→‎クオータ)
移動先:案内検索

Moodle 2.0 このページは、Moodle 2.0でのファイルストレージおよびアクセスの実装に関する、現在考えていることに関する概要ページです。作成中の仕様書です!

作成中です - Mitsuhiro Yoshida 2009年1月6日 (火) 09:16 (CST)

このページは、誰でも編集することができますので、誰でも間違いを訂正したり、このドキュメントを進化させることができます。あなたに質問、報告する問題または主要な変更に関する提案がある場合、ページコメント欄に追加するか、リポジトリフォーラム (英語)でディスカッションを開始してください。開発を開始する前、私たちは、それらのすべてのご意見をメインの仕様に取り込むよう努力します。


目的

  1. ファイルを直接Moodleに追加できるようにする (現在、私たちが追加しているように)。
  2. ファイルがどこから来たのか記憶する。
  3. ケイパビリティおよび他のローカルルールを使用して、モジュールにファイルアクセスのコントロールを与える。
  4. Moodle内のすべてのファイル処理に関して、一貫してシンプルにアプローチする。


オーバービュー

ファイルAPIは、Moodleコードが次の目的で使用するインターフェースのコアです:

  1. Moodle内にファイルを保存する
  2. Moodleユーザにファイルを表示する

ファイルAPIは「ユーザ」ファイルのみ提供します。また、ファイルAPIは、次のディレクトリのような、Moodleのdatarootディレクトリに作成されたローカルファイルおよびキャッシュを提供しません: temp、lang、cache、environment、filter、rss、search、sessions, upgradelogs等

APIは、いくつかの独立したパーツに分かれます:

  1. ファイル提供API
    1. file.php
    2. pluginfile.php
    3. userfile.php
    4. draftfile.php
    5. rssfile.php
  2. ファイル保存API
    1. 任意のアクセスコントロール
    2. 任意のリポジトリsync
  3. ファイル管理API
    1. ファイル閲覧
    2. ファイルリンク (エディタ統合)
    3. リポジトリからのアップロード

ファイル提供API

ファイルの提供に対応します - ブラウザがファイルをリクエストした場合、そのファイルをMoodleが返します。私たちには、3つのメインファイルがあります。サーバ上でスラッシュ (例 file.php/some/thing/xxx.jpg) を設定することが重要です。相対リンクを使用するコンテンツは、スラッシュなしではアクセスできなくなります (scorm、アップロードhtmlページ等)。

file.php

コースファイルを提供します。

基本的なファイルを扱います。理想的には、コースセクションからリンクされたイメージおよびファイルのみ扱われるべきです。XSS保護は必要としません - 私たちはjavaスクリプト、sw (shockwave) 等の使用を想定しています。「セキュア」にする方法はありません。私たちがほとんどのファイルをモジュール内に移動する場合、アクセスコントロールは重要な意味を持ちません。

既存のコースコンテンツに対する下位互換性に関して、ファイル名およびパラメータ構造は重要です。

/file.php/courseid/dir/dir/filename.ext

内部的にファイルは、array('contextid'=>$coursecontextid, 'filearea'=>'coursefiles', 'itemid'=>0)に保存されます。

pluginfile.php

(別名 modfile.php) モジュール、ブロック、問題ファイルを送信します。

  • モジュールは、アクセスコントロールを決定します。
  • 任意のXSS保護 - 学生が送信したファイルは、ノーマルヘッダと共に提供されるべきではありません。私たちは、代わりにダウンロードさせる必要があります。理想的には、信頼できないファイルに対して、第2のwwwrootを使用した方が良いでしょう。
  • 選択したエリアの内部リンクのみサポートされます - あなたは要約エリアのみイメージをリンクすることができますが、提出課題にはリンクすることができません。

モジュールでHTML編集が許可されている場合、絶対リンクは書き換えられる必要があります。リンクは、相対リンクとして内部に保存されます。編集または表示する前、str_replace()を使用して、内部リンクは絶対リンクに変換されます (@@thipluginlink/summary@@/image.jpg --> /pluginfile.php/assignmentcontextid/intro/image.jpg)。保存される前、内部リンクに戻されます。

明確な (distinct) ファイルエリアは、情報を追加するため、どこかで定義されたプラグインによってサポートされますか? 例えば、以下のように宣言されると面白いと思います:
  • assignment_summary:
    • relpath='intro'
    • userdata=false
    • anotherproperty=anothervalue
  • assignment_submission:
    • relpath='submission/@@USERID@@'
    • userdata=false
    • anotherproperty=anothervalue
  • など ...
それから、エディタが「assignment_summary」エリア名を「受信」した場合、何を表示するのか等、知っているとしたら? また、バックアップおよびリストアにおいて、ファイルエリアが処理されるか否か (userdata=fals) 判断するため、その情報が有用だとしたら。または、リンクの再構築 (str_replace() above) に対して、その情報が有用だとしたら。そして、自由にコーディング (prone to errors 間違いがち) する代わりに、モジュールによって良く定義されたファイルエリアのリストがあるとしたら。Eloy Lafuente (stronk7) 16:35, 28 June 2008 (CDT)
このような機能は、ファイル管理APIの一部にありますが、これをファイル保存のコードにハードコードすると柔軟性が失われます、私の考えでは。Skodak
はい、はい。ストレージは、ファイルをget/putする以外、何も知ってませんね。確かに、これは管理の一部ですね。Eloy Lafuente (stronk7) 11:21, 29 June 2008 (CDT)
/pluginfile.php/contextid/areaname/arbitrary/params/or/dirs/filename.ext

pluginfile.phpは、コンテクストテーブルよりプラグインタイプを検出し、基本情報 (状況に応じて、$courseまたは$cm) を取得します。また、アクセスをコントロールして最終的にファイルをユーザに送信するプラグイン関数 (または後のメソッド) をコールます。areanameは、タイプ別にファイルを分離して、コンテクストをいくつかのサブツリーに分けます - 例えば、summaryファイル (モジュールのイントロダクションで使用されるイメージ)、投稿の添付ファイル等。

課題例

/pluginfile.php/assignmentcontextid/intro/someimage.jpg
/pluginfile.php/assignmentcontextid/submission/submissionid/attachmentname.ext
/pluginfile.php/assignmentcontextid/extra/allsubmissionfiles.zip
あの ... これらすべてのファイルが同じ場所ですか? 上記例の「submission」パスを「summary」から区別したらどうなりますか? エディタまたはファイルマネージャが許可しないからですか? 例えば、課題の要約 (summary) として1つのファイルを「submission」エリアからピックアップした場合、「summary」エリアのみ表示されますか? コンテクストに複数のファイルマネージャが存在することになり、以下で合意された「コンテクストあたり1つのファイルマネージャ」という考え方に反してしまいます。 Eloy Lafuente (stronk7) 21:28, 26 June 2008 (CDT)
はい、Eloyさん、異なるエリア (summary、submission) 等は、異なる使い方をされて、異なるアクセスコントロールを持ちます。ファイルマネージャには、2種類あります - すべてのコンテクスト+エリア一覧にユーザがアクセス可能な2つのウィンドウ枠を持ったファイルマネージャ、および (他へリンクできないため) 現在のプラグインのサブセットのみ表示する最小限のHTMLエディタです。

SCORM例

/pluginfile.php/scormcontextid/intro/someimage.jpg
/pluginfile.php/scormcontextid/content/revisionnumber/dir/somescormfile.js

キャッシングの問題を避けるため、すべてのファイル変更に関して、リビジョンカウンターの値が増加されます。存続期間は、モジュール設定で調整されるようにすべきです。

小テスト例

pluginfile.php/quizcontextid/intro/niceimage.jpg
pluginfile.php/quizcontextid/report/type/export.ods

問題例

pluginfile.php/SYSCONTEXTID/question/questionid/file.jpg

ブログ例

一般的にブログエントリまたはメモには、コンテクストIDを持ちません (これらはシステムコンテクスト内に存在し、以下のSYSCONTEXTIDがシステムコンテクストのIDだからです)。 メモの添付ファイルは、常にXSSプロテクションと共に提供されます。理想的には、私たちはこのファイルとwwwrootを分けるべきです。アクセスコントロールは、ハードコードできます。

/pluginfile.php/SYSCONTEXTID/blog/blogentryid/attachmentname.ext

内部的には、array('contextid'=>SYSCONTEXTID, 'filearea'=>'blog', 'itemid'=>$blogentryid)に保存されます。

バックアップ例

特別に保護されたバックアップファイルを持つことは素晴らしいと思います - バックアップファイルのダウンロードおよびアップロードに関する新しいケイパビリティ。バックアップには、多くの個人情報を含んでいます。ですから、私たちは他のサイトでバックアップをリストアすることをブロックできるのではないでしょうか。

/pluginfile.php/coursecontextid/backup/backupfile.zip

内部的には、array('contextid'=>$coursecontextid, 'filearea'=>'backup', 'itemid'=>0)に保存されます。

userfile.php

パーソナルファイルの保存は、提出する前の課題のような、作業中のファイルのオンラインストレージを目的としています。

  • 自分のファイルのみ読み込み/書き込みします。
  • 後で他のユーザと共有できるオプションを持ちます。
  • パーソナル「ウェブサイトはサポートされません (セキュリティ上の理由から)。
/userfile.php/userid/dir/dir/filename.ext

rssfile.php

下位互換を保持するためのみ実装されているrss/file.phpと入れ替えます。 RSSファイルは、セッション/クッキーを要求すべきではありません。URIは、ある種のセキュリティトークン/キーを含むべきです。 内部的には、ファイルはデータベースに保存されるか、他のファイルと共に保存されます。 パフォーマンス改善 - If-None-Match/If-Modified-Since => 304を受け取った場合、私たちはEtag (cool) および Last-Modified (より多く使われています) をサポートします。

/rssfile.php/contextid/any/parameters/module/wants/rss.xml
/rssfile.php/SYSCONTEXTID/blog/userid/rss.xml

さらに、モジュールおよびプラグインは、何をユーザに送信するか決定します。

一時ファイル

通常、一時ファイルは1つのスクリプトの存続期間中のみに使用されます。 一時ファイルは、次のスクリプトで使用されます:

  • エクスポート
  • インポート
  • ZIP圧縮/解凍
  • 実行ファイルによる処理 (latex、mimetex)

理想的には、これらのファイルはUTF-8 (現在のところZIP圧縮に問題があります) を使用べきではありません。 提案している新しいsha1ベースのファイルストレージでは、パフォーマンスおよび技術的な理由からUTF-8の使用は適していません。

レガシーのファイル保存および提供

$CFG->dataroot内の古き良き個別ディレクトリを使用する予定です。

ファイルの提供および保存:

  1. ユーザアバター - user/pix.php
  2. グループアバター - user/pixgroup.php
  3. tex、algebra - filter/tex/* and filter/algebra/*
  4. rssキャッシュ (?full rss rewrite soon?) - 下位互換は、rss/file.phpのみ

保存のみ:

  1. セッション

ファイル保存API

一般的にモジュールは、ローカルのMoodleファイルとともに動作します。主な理由として、外部リポジトリにアクセスすることがあります。ファイルをアップロードする代わりにリポジトリを利用して、外部リポジトリとローカルファイルを同期化させることもできます。

ファイルコンテンツは、ファイル名の代わりにSHA1ハッシュを使用して、moodledata/filepoolの中に保存されます。ファイル名、相対パスおよび他のメタデータは、file(_xxx)データベーステーブルに保存されます。どこにファイルがあるのか、モジュールが実際に知らなくても良いよう、これは完全に抽象化されます。ファイルを保存する場合、コンテンツはストリングまたはファイルハンドルとして送信されます。また、コンテンツを読む場合、ファイルハンドルとして返されます。

ファイルテーブル

このテーブルは、すべてのファイルに対して、それぞれ1つのエントリを含みます。ファイルが十分に識別され、必要に応じて検索されるよう、十分な情報をここで保持します。

note:「file」は予約語のため、pluralが使用されます。

フィールド タイプ デフォルト 情報
id int(10) オートインクリメント
contenthash varchar(40) sha1ハッシュコンテンツ
pathnamehash varchar(40) contextid+filearea+itemid+filepath+filenameのsha1ハッシュ - ファイル重複防止および迅速なルックアップを実現します。
contextid int(10) コンテクストテーブルで定義されるコンテクストID - ファイルを所有しているプラグインインターフェースの識別
filearea varchar(50) 「submissions」「intro」「content」(サマリーからのイメージおよびswfのリンク) 等のように、「blogs」および「userfiles」は、システムコンテクストにある特別なケースです。
itemid int(10) プラグイン特有のアイテムID (例 フォーラム投稿、ブログエントリ、提出課題、ユーザファイルのユーザID等)
filepath text モジュールコンテンツのルートからのファイル相対パスです。SCORMおよびリソースモジュールで有用です。多くのモジュールでは、必要としません。
filename varchar(255) このファイルに関するフルユニコード名です (大文字小文字の区別をします)。
filesize int(10) ファイルサイズ - バイト
mimetype varchar(100) NULL ファイルタイプ
userid int(10) NULL 任意 - 一般的なユーザIDフィールド - プラグインに依存します。
timecreated int(10) このファイルが作成された日時です。
timemodified int(10) このファイルが更新された最終日時です。

非ユニークインデックス: contextid、filearea、itemid、contenthash
ユニークインデックス: pathnamehash

contextidから生成されるため、プラグインタイプは指定されません。ブログのような独自のコンテクストを持たないアイテムは通常、systemcontextidから独自のファイルエリアを使用します。

DBサイドにテキスト制限 (インデックス長の制限、インデックス不可、複合検索 ...) を保存するため、恐らく、私たちはハッシュファイルパスおよびファイル名、それらのインデックスを持つことができると思います。 Eloy Lafuente (stronk7) 11:54, 29 June 2008 (CDT)
また、それぞれのプラグインの正確なファイル処理に使用するため、恐らく私たちは、最終的にそこへプラグインタイプを保存すべきです。 Eloy Lafuente (stronk7) 18:54, 29 June 2008 (CDT)

files_cleanupテーブル

このテーブルには、ファイルプールからの削除対象ファイルが含まれます。すぐにファイルが削除されるのではなく、cronがfiles_cleanupテーブルを使用して、もはやファイルが使用されていないか確認した後、プールから削除します。cronでクリーンアップする理由は、パフォーマンスおよび衝突の回避にあります - 同時アップロードおよび削除では問題が生じる場合があります。クリーンアップ中、恐らく私たちは、さらにテーブルベースのロッキングが必要だと思います。

プールエリアの深い妥当性チェックのため、私たちは特別なスクリプトを追加することができます - 不明なファイルの報告、迷子ファイルの報告、sh1ファイル名に合致しないコンテンツ等 - これには、とてもとても時間がかかります。

フィールド タイプ デフォルト 情報
id int(10) オートインクリメント
contenthash varchar(40)

files_metadataテーブル

このテーブルは、ファイルに関する特別なメタデータを含みます。リポジトリは、このデータを提供することができます。または、ローカルコピーを手動で編集することができます。

フィールド タイプ デフォルト 情報
id int(10) オートインクリメント
fileid int(10) ファイルID
name varchar(255) 特別メタデータ名
value text

files_aclテーブル

このテーブルでは、ファイルの任意なACPに関して記述します。多くの場合、この記述は必要ではありません。通常、モジュールはアクセスロジックをハードコードしますし、コースファイルが使われることは極めて少ないと思われます。

フィールド タイプ デフォルト 情報
id int(10) オートインクリメント
fileid int(10) 私たちがアクセスを定義するファイルです。
contextid int(10) このファイルが公開されるコンテクストです。
capability text このファイルの閲覧に必要なケイパビリティです。

aclメモ

  • これには、user/group/othersに似ている、いくつかのコンセプトがありません。例えば、ユーザファイルに関して、標準的なユーザはパーミッションを割り当てたり、閲覧することができません - これでは役に立ちません。
  • ファイルリンクおよびファイルの可用性を同期することは、さらに重要です - アクセスできないファイルにリンクしている場合、またはアクセスを望まないファイルにアクセスしている場合、両者とも問題になります。
  • ここでは、ブラウザ/プロクシのキャッシングは私たちに反して動作します - 「シークレット」なファイルはキャッシュされるべきではありません。

files_syncテーブル

このテーブルには、リポジトリのデータをどのように同期化するかという情報を含んでいます。データは、cron.phpまたはファイルマネージャの要求により同期化されます。同期化は一方向 (リポジトリ -> ローカルファイル) からのみです。

フィールド タイプ デフォルト 情報
id int(10) オートインクリメント
fileid int(10) ファイルID
repositoryid int(10) このファイルが関連付けられているリポジトリインスタンスです。詳細は、開発:リポジトリAPIをご覧ください。
updates int(10) アップデータスケジュールを指定します (0 = なし、1 = オンデマンド、other = 秒数)
repositorypath text リポジトリのオリジナルファイルのフルパスです。
timeimportfirst int(10) このファイルが最初にMoodleにインポートされた日時です。
timeimportlast int(10) このファイルがMoodleにインポートされた最新日時です

ファイルコンテンツストレージ

最初、ファイルストレージ階層には、ユーザID、エントリiD、ファイル名等、数多くのメタデータを含んでいました。現在、ファイルコンテンツは、ファイルメタデータと分離して保存されます。すべてのプラットフォームにおいて、UTF8をサポートします。

ファイル保存:

  1. コンテンツのSHA1ハッシュを計算する。
  2. SHA1名のファイルが存在するかどうか確認する。存在しない場合、ファイルをファイルプールに追加する。
  3. 削除ファイルのリストにSHA1ファイルがある場合、削除する。
  4. SHA1をファイルプールIDに使用して、ファイルをfileテーブルに保存する。

ファイル読込み:

  1. fileテーブルよりファイルレコードを取得 - 恐らく、ファイルIDまたはコンテクストID+インスタンスIDを使用する。
  2. ファイルコンテンツを取得する。

ファイル削除:

  1. fileテーブルよりレコードを削除して、SHA1を記憶する。
  2. 削除ファイルテーブルに削除されたSHA1を保存する。まだ、物理ファイルは削除しません。
  3. クリーンアップスクリプトによる、実際のSHA1ファイル削除を待ちます (ファイルの追加/削除に関して、競合が発生しないよう、適切なテーブルロックが必要です)。

ファイルプール詳細

ファイルプールは、$CFG->dataroot/filepool/ にありますが、OSの制限により、ファイルすべてを1つのディレクトリに保存することはできません。ファイルの保存には、sha1ハッシュの先頭3文字を使用します。コンテンツのsha1ハッシュ先頭3文字が同じファイルが数千あるということは考えられません。

同じ大きなファイルを複数保存する場合、このタイプのストーレジでは多くのディスクスペースを節約することができます。データを外部リポジトリと同期化する場合、ディスクスペースを大幅に節約することもできます。もうひとつの利点は、私たちがファイルコンテンツの不一致を発見することができることです。

ファイル読み込みのパフォーマンスは、前のコードに似ています。ハッシングおよび特別なデータベースアクセスのため、ファイル書き込みのパフォーマンスは遅くなります。

dataroot 
   /filepool
      /00
      /01
      ...
      /23
        /00
        /01
        ...
        /1e
           /00
           /01
           ...
           /2d
              /231e2dc421be4fcd0172e5afceea3970e2f3d940
      ...
      /fe
      /ff

ファイル管理API

このセクションでは、以下の内容に関して記述します:

  1. ファイルマネージャ
  2. HTMLエディタとの統合
  3. リポジトリとの相互関係

ファイルマネージャ

単一ウィンドウ枠のファイルマネージャは、ウェブベースのアプリケーションでは悪評高いドラッグ&ドロップなしに実装するのは、簡単ではありません。私は2つのウィンドウ枠を持ったコマンダースタイルのファイルマネージャーを提案します。2つのウィンドウ枠を持ったマネージャーを使用することで、あなたは2つの異なるコンテクスト間 (例: コース) において、簡単にファイルをコピー/移動することができます。

ファイルマネージャは、直接ファイルシステムAPIと相互作用すべきではありません。代わりに、それぞれのモジュールは、実およびローカライズ名 (ローカライズ名は、backupdataのようなディレクトリに必要です) のファイルおよびディレクトリの横断的なツリーを返すべきです。

最初、それぞれのコースには単一のファイルツリーがありました。私たちは、それぞれのモジュール/ブロックをコースから完全に分離して、モジュール内に独立したファイルエリア (例: モジュールイントロダクション、コンテンツファイル、提出課題、投稿添付ファイル) を持つ必要がありました。ファイルエリアは、私たちが相対パスを使用できるよう、小さなツリーとして定義することができます。これらのファイルエリアは、コンテンツツリーのブランチからぶら下がっています (これには図が必要です)。

HTMLエディタとの統合

HTMLエディタは、関係するファイルのみ閲覧できるべきです - 例えば、リソースのイントロダクションを編集する場合、そのリソースのファイルエリアのみのイメージを使用できるべきです。また、HTMLリソースページを編集する場合、コンテンツエリアのイメージのみ使用できるべきです。

ここにいくつか問題を挙げます:

  1. 新しいリソースを追加する場合、まだコンテンツは存在していません。新しいコンテンツを追加するため、私たちは一時的なファイルストレージを処理するためのテーブルを作成する必要があります。簡単ではありませんが、解決できないことではありません - 恐らく、私たちはコースコンテクストIDを使ってしまうか、特別なユーザファイルエリアに一時的に保存できると思います。
  2. 私たちは、pluginfile.phpのリンクに絶対アドレス再リンクを使用することができません。代わりに、編集時または保存前に@@thispluginfile@@/2112/112/image.jpgのように変換される前のみ、私たちは絶対リンクを使用することができます。表示または編集される前、ローカルリンクは完全な絶対リンクに変換されます。すべてのファイルエリアがこれをサポートするわけではありません (例: 誰もアクセスしないため、提出課題にリンクすることは意味をなしません)。HTMLエディタのイメージプレビューに関して、私たちはこれを実装することはできます。

HTMLエディタは、基本的な操作のみできる、シンプルな単一のウィンドウ枠を持ったファイルマネージャであるべきです - ファイルエリアの選択、ファイルエリアの閲覧、ファイルのアップロード、ユーザファイルのコピー、リポジトリファイルの使用、削除。エディタに埋め込まれたモジュールにより指定されるスクリプトをコールするajaxを通して、エディタはモジュールおよびコアとコミュニケートします。コールバックスクリプトは、ファイルツリーを作成するため、ファイルマネージャとは異なるロジックを使用します。コールバックスクリプトは、他のユーザが閲覧した結果として生じる、HTMLがアクセスすることのできるファイルのみ知る必要があるからです。

リポジトリとの相互関係

リポジトリは、ファイルアップロードの代替手段として提供されます。また、リポジトリは、コース間のファイル同期化にも使用することができます。リポジトリオプションは、ファイルアップロードフィールドがある場合、また、時々「同期化を維持する」オプションが有効にされた場合 (これは、提出課題等に意味をなします)、常に利用できるようにすべきです。

アップグレード、移行および下位互換性

DML/DDLのように、大変な作業になりそうです ;-)

コード下位互換性

ファイルストーレッジに関して、下位互換性はゼロ%です。新しいオブジェクトの使用が必須です。古い $CFG->dataroot/$courseid/ および $CFG->dataroot/blog/ は空です。

コンテンツ下位互換性

既存のコースがイメージ、Flash等を失わないための手段です。しかし、これは、コースファイルエリアからファイルを使用している既存のデータでは動作しない、新しい機能 (実装されている場合、リソース共有のようなもの) です。

ファイルアップロード時の特殊文字の除去により、アップロードされたHTMLファイル内のリンクとファイルが合致しなくなるかもしれません。私は、このようなことが、頻繁に起きないことを望むばかりです。

コンテンツの移行

  • リソース - 新しいコンテンツファイルエリアにPDF、イメージリソース等を自動的に移動します。当然、アップロードされたウェブページは、正確ではなくなります。
  • 問題 - イメージファイルは、新しいアリアに移動されます。問題にはイメージタグが付加されます。
  • moddataファイル - 最も簡単な部分です。新しいストレージに移動するだけです。
  • コースファイル - 恐らく非常に多くの古いファイルがあると思います :-( :-(
  • リーダー内のRSSフィードリンク - 壊れます。新しいセキュリティ関連のコードがリンクを壊してしまいます。

ファイルをファイルテーブルおよびファイルプールに移動する

処理に極めて長い時間を要するため、移行プロセスは中断できるようにすべきです。ファイルは古いロケーションから移動されます。再スタートは、簡単にする予定です。

ステージ案:

  1. moddataを除く、すべてのコースファイルの移行 - $CFG->files_migrated=true; のように設定して実行完了させる - このステップでは、古いファイルマネージャおよびHTMLエディタのインテグレーションを壊してしまいます。
  2. ブログ添付ファイルの移行
  3. 問題ファイルの移行
  4. moddataファイルの移行 - それぞれのモジュールは、変換されたコースファイルまたはmoddataから直接データをコピーすることに関して責任を負います。なぜなら、これらのデータは自動的に変換されないからです。

いくつかのpplでは、コースファイルにシンボリックリンクを使用します - コースファイルとシンボリックリンクが使われないとしても、私たちは両者が新しいストレージにコピーされることを確認すべきです - 同期化されたコンテンツを望む人は誰でも、ファイルの移動先でも再度同期化を必要とするものです。

ここでは、コースファイルをモジュールエリアに移行する場合の二重タスクに関して話題にしました:
  1. すべての依存状態を見つけて、同時に移動するため、HTMLファイルを構文解析します。
  2. モジュールファイルエリアで足りないものが見つかった場合、コースファイルエリアで検索した後、コピーして提供するため、pluginfile.php内でフォールバックします。
また、古いコースファイルまたは新しく自動的に作成されるファイルエリアに対して適用できるかどうか明確にするため、私たちはリソースに新しい設定を追加する可能性についても話しました。移行されたリーソースは、自動的に作成されたファイルエリアに新しいコースファイルが移行されるまで、古いコースファイルを扱います。
リソースファイルのみ本当に複雑なようです (なぜなら、HTMLを自由に含むことができるからです)。残り (ラベル、イントロダクション ... ではなく) の構文解釈は難しくありません。
Eloy Lafuente (stronk7) 19:00, 29 June 2008 (CDT)

バックアップ/リストアの変更

バックアップのファイル処理の部分は、完全に書き換えるる必要があります - xmlのファイル一覧 + sha1署名ファイルコンテンツのプール。これにより、utf-8のトラブルを解消できます、yay!!

クオータ

ファイルサイズは、ファイルテーブルに保存されます。私たちは、どれくらいのスペースを使用しているか、シンプルなクエリを使用して探すことができます。しかし、sha1ハッシュベースのストレージでは、重複したファイルは取り除かれるため、このファイルサイズは、正確ではありません。

If sha1 string is stored in the files table (non-unique), then it can be used to detect duplicates within the files table and only counting their size once. To avoid having to search this often, we could do it periodically and store the filesize with each file record (only the first of the duplicates gets a filesize, the others get 0). Nicolas Connault
  • 合計コースファイル - find out all contexts used in course, query files table with contextid IN ($listofcontexts)
  • module files - find module context and calculate space per file area
  • ユーザファイルクオータ - inside the personal area only, counting all attachments in all mods might take a while

We could also divide the file size by number of instances that are using it, this might be considered more accurate in some scenarios.

その他

  • antivirus scanning + upload manager rewrite/integration with forms lib
  • zip compression and extraction

主要な問題

List of hard to solve prolbems

zip support

Zip format is an old standard for compression of files, it was created long before the unicode and added support for it just recently. There are several ways used for encoding of non-ascii characters in path names, unfortunately it is not much standardised. Most windows packers use DOS encoding.

Client software:

  • Windows built-in compression - bundled with Windows, non-standard DOS encoding only
  • WinZip - shareware, unicode option (since v11.2)
  • TotalCommander - shareware, single byte(DOS) encoding only
  • 7-Zip - free, unicode or DOS encoding depending on characters used in file name (since v4.58beta)
  • Info-ZIP - free, uses some weird charset conversions

PHP extraction:

  • Info-ZIP binary execution - no unicode support at all, mangles charsets in filename (depends on OS, see docs), files must be copied to temp directory before compression and after extraction
  • PclZip PHP library - reads single byte encoded names only, problems with random problems and higher memory usage
  • Zip PHP extension - reads single byte encoded names only, 64bit operating system can not open/create archives with more than 500 files (depends on sum of lengths of all filenames and directories, to be fixed in PHP 5.3 and external PECL library, no PHP 5.2.x backport planned!), adding of files is limited by number of free file handles (around 1000 - depends on OS and other PHP code, workaround is to close and reopen archive)

Large file support: PHP running under 32bit operating systems does not support files >2GB (do not expect fix before PHP 6). This might be a potential problem for larger backups.

Tar Alternative:

  • tar with gzip compression - easy to implement in PHP + zlib extension (PclTar, Tar from PEAR or custom code)
  • no problem with unicode in *nix, Windows again expects DOS encoding :-(
  • seems suitable for backup/restore - yay!

Roadmap:

  1. add zip processing class that fully hides the underlying library
  2. use single byte encoding "garbage in/garbage out" approach for encoding of files in zip archives; add new 'zipencoding' string into lang packs (ex: cp852 DOS charset for Czech locale) and use it during extraction, we might support true unicode later when PHP Zip extension does that

empty directories

Hmm, thinking a bit more about Justin's comment I realised there is no support for empty directories in this proposal. This will require either new table or some hack in files table - maybe we could add files with "." as name and just skip them when iterating directory content.

Note: solved with files named '.'; the dirs are automatically created when adding files, the area root dir is created when browsing.

file overwriting

Concept of file overwriting does not exist anymore here, the path+filename are not enforced to be unique - we can not make index because sloppy mssql does not allow indexes larger than 900 bytes :-( We will haev to emulate it somehow and deal with collisions if found.

Note: solved with unique index on pathnamehash field.

Some little comments to be considered (to avoid forgetting them)

  • each context will have its own "file manager"
  • separate "file manager context" files (FMF) and "internal context" (ICF) files (current modedit files, submissions, attachements...)
  • /pluginfile.php/SYSCONTEXTID/{blog|question} and so... will have own FMF too? Or only ICF ?
  • Way to copy between contexts
  • Links = -1 for them
  • Deletion strategy (locks, quarantine status...)
  • include support for quotas per user, per course, etc
  • upgrade process should be interruptable (like the unicode upgrade) so it can be stopped/restarted any time

Justin's thinking out loud

I'm actually working on implementing this along with extending an existing Alfresco integration to work together with the whole File / Repository system and I wanted to get some of my comments and thoughts in here for feedback. Go easy on me. =)

So far I've only got one that I'd like to solicit some feedback on (BTW, if this would be better suited to a forum discussion, let me know):

Not storing the full filepath with each entry in the file table

  • For browsing a directory structure, determining things like child directories or a parent directory given a filepath requires a lot of extraneous coding in PHP. I think it might be better served to create a new file_directory table, storing only a directory name, and reference to a parent directory record. The benefits here are that we're storing a lot of duplicate text field values in the file table and browsing through the file picker for local files doesn't require a lot of PHP overhead to calculate links to parent / child directories.
  • Given that file permissions are no longer calculated using structured file paths, using the complete, full, path to a given file would most likely never be needed.
  • The repositorypath field in the repository_sync table still makes sense, though.
  • The file_directory table:
フィールド タイプ デフォルト 情報
id int(10) オートインクリメント
parent int(10) ID of directory that this record is a child of.
directoryname varchar(255) The actual name of this directory.

skodak: filepath is stored in files table - its root is the corresponding filearea, the file manager will use the context tree to find all plugins/courses and ask them to return the list of areas with all those small branches inside it

関連情報