お世話になっております。
MOです。
現在私の環境はRedHat EL4+moodle1.8+
です。RedHat EL4からUTF-8が標準のようです。
最近までEL3(EUC)試していたのですが、
EL4で試すようになってからIEでのダウンロードが
調子が悪いです。
既知の問題で「file.php」の
$filename = mb_convert_encoding($filename,SJIS", "UTF-8");を
$filename = urlencode($filename);に修正すると
文字化けせずにダウンロードできるとのことでした。
しかし、私の現在の環境でうまくいきませんでした。
状況としては、
コースのリソース追加からファイルをアップロードすると
「moodledata」のフォルダ内には正しい日本語名でファイルがアップされるにも関わらず、ダウンロードのリンクに文字化けしたファイル名で呼び出しを行い、ファイルが無いとエラー表示がでます。
どなたか、このエラーの原因を追究している方がいれば
教えて頂けると助かります。
いくつか参照させて頂いた情報を下記に示します。
http://docs.moodle.org/ja/サイトファイル
http://oku.edu.mie-u.ac.jp/~okumura/linux/?Moodle
http://moodle.org/mod/forum/discuss.php?d=72567
当方の環境で改造中の箇所のうちの一つが,まさにその部分です.
これはアップロードされているファイルのリストからダウンロードする場合だけであって,もしかしたらフォーラムにアップロードされたファイルやウェブページの場合にはうまくいかない可能性もあります.
かならずrawurlencode()してしまえば,FirefoxだろうとIEだろうと同じ,という意味で,MOさんの仰る通りに改善になっているはずです.
mod/assignment/type/upload/assignment.class.libのprint_user_files()を以下のように変更.
これはアップロードされているファイルのリストからダウンロードする場合だけであって,もしかしたらフォーラムにアップロードされたファイルやウェブページの場合にはうまくいかない可能性もあります.
かならずrawurlencode()してしまえば,FirefoxだろうとIEだろうと同じ,という意味で,MOさんの仰る通りに改善になっているはずです.
mod/assignment/type/upload/assignment.class.libのprint_user_files()を以下のように変更.
if ($basedir = $this->file_area($userid)) {
if ($files = get_directory_list($basedir, 'responses')) {
require_once($CFG->libdir.'/filelib.php');
foreach ($files as $key => $file) {
foreach ($files as $key => $file) {
$icon = mimeinfo('icon', $file);
// $ffurl = "$CFG->wwwroot/file.php?file=/$filearea/$file";
$ffurl = "$CFG->wwwroot/file.php?file=/$filearea/" . rawurlencode($file);
$output .= '<a href="'.$ffurl.'" ><img src="'.$CFG->pixpath.'/f/'.$icon.'" class="icon" alt="'.$icon.'" />'.$file.'</a>';
// $ffurl = "$CFG->wwwroot/file.php?file=/$filearea/$file";
$ffurl = "$CFG->wwwroot/file.php?file=/$filearea/" . rawurlencode($file);
$output .= '<a href="'.$ffurl.'" ><img src="'.$CFG->pixpath.'/f/'.$icon.'" class="icon" alt="'.$icon.'" />'.$file.'</a>';
そうですね.
ハイパーリンクのhtmlコードをechoしている箇所と云うのはあちこちにあるし,しかも総じて読みにくいため追跡が意外と大変でしたが,あの例示した箇所だけで,当方は特に問題なくIEでダウンロードできています.
あの箇所で,$fileはUTF-8のファイル名そのままです.
ブラウザがそこ(<a> href="ほにゃらら" </a>)をクリックしてファイル名をサーバ側に送る際に,Firefoxはエンコードして送信するのに対して,IEはUTF-8のまま送信するため,サーバ側で受けた際に奥村先生たちが示したfile.phpの修正が必要だったのでした.そういう意味ではあの箇所を修正すればfile.phpの対策は不要なのかも知れませんが,file.phpは色々なところから利用されるため,当方でもfile.phpの対策はそのまま残しています.
ハイパーリンクのhtmlコードをechoしている箇所と云うのはあちこちにあるし,しかも総じて読みにくいため追跡が意外と大変でしたが,あの例示した箇所だけで,当方は特に問題なくIEでダウンロードできています.
あの箇所で,$fileはUTF-8のファイル名そのままです.
ブラウザがそこ(<a> href="ほにゃらら" </a>)をクリックしてファイル名をサーバ側に送る際に,Firefoxはエンコードして送信するのに対して,IEはUTF-8のまま送信するため,サーバ側で受けた際に奥村先生たちが示したfile.phpの修正が必要だったのでした.そういう意味ではあの箇所を修正すればfile.phpの対策は不要なのかも知れませんが,file.phpは色々なところから利用されるため,当方でもfile.phpの対策はそのまま残しています.
すいまんせん。
どのページのソースでしょうか?
アップさせて頂いた2つの画像のどちらにも、16進数のリンクは貼られていませんでした。
mod/assignment/type/upload/assignment.class.phpの
print_user_files()の部分は変更したんですが、/moodle/course/view.phpや
/moodle/file.phpに影響を与えているような動作はしていない気がします。
どのページのソースでしょうか?
アップさせて頂いた2つの画像のどちらにも、16進数のリンクは貼られていませんでした。
mod/assignment/type/upload/assignment.class.phpの
print_user_files()の部分は変更したんですが、/moodle/course/view.phpや
/moodle/file.phpに影響を与えているような動作はしていない気がします。
file.phpの以下の箇所の修正を試していただけませんか? 900行目前後です.$filelistの表示の前に,良く似たコードで,$dirlistの表示を行なっています.そちらと間違えないように!
$filesafe, $fileurlsafeは思わせぶりに存在するのですが,パッと見た感じでは使用されていません.
試してみることとして以下の2つがあります.
(1) $fileurl = $fileurlsafe;
これをこのまま直後に記述して$fileurlを上書きする.これで良いと思ったのですが,当方の環境ではうまく行きませんでした.パスの/や何故か拡張子までエンコードされてしまいました.もしこの方法でブラウザから「Object not found!」とエラーを返された場合(当方はこうなります)は,以下のコードを試して見て下さい.パスやファイル名のみをrawurlencodeします.
(2)上の方法でダメな場合.
$path_parts = mb_split("/", $fileurl);
foreach ($path_parts as $key => $path) {
これでブラウザでファイル名にカーソルを持っていくと,URLエンコードされたアドレスがfile.php/以降に表示されるはずです.
ただ,なんとなく問題から逃げているような気もしますが!
(apache/php等の設定かも知れませんね)
if (!empty($filelist)) {
この$fileurlがリンク先のアドレスとして使用されています. asort($filelist);
foreach ($filelist as $file) {
foreach ($filelist as $file) {
$icon = mimeinfo("icon", $file);
$count++;
$filename = $fullpath."/".$file;
$fileurl = trim($wdir, "/")."/$file";
$filesafe = rawurlencode($file);
$fileurlsafe = rawurlencode($fileurl);
$count++;
$filename = $fullpath."/".$file;
$fileurl = trim($wdir, "/")."/$file";
$filesafe = rawurlencode($file);
$fileurlsafe = rawurlencode($fileurl);
$filesafe, $fileurlsafeは思わせぶりに存在するのですが,パッと見た感じでは使用されていません.
試してみることとして以下の2つがあります.
(1) $fileurl = $fileurlsafe;
これをこのまま直後に記述して$fileurlを上書きする.これで良いと思ったのですが,当方の環境ではうまく行きませんでした.パスの/や何故か拡張子までエンコードされてしまいました.もしこの方法でブラウザから「Object not found!」とエラーを返された場合(当方はこうなります)は,以下のコードを試して見て下さい.パスやファイル名のみをrawurlencodeします.
(2)上の方法でダメな場合.
$path_parts = mb_split("/", $fileurl);
foreach ($path_parts as $key => $path) {
if ($key == 0) $fileurl = rawurlencode($path);
} else $fileurl .= "/".rawurlencode($path);
ただ,なんとなく問題から逃げているような気もしますが!
(apache/php等の設定かも知れませんね)
MOです。
すいません、返信が遅れて。。;
Shirai さんがいっている「file.php」はmoodle直下のファイルのことですか?
私のは900行もないので、別のディレクトリかと思っているのですが。
どこのファイルでしょうか?
>(apache/php等の設定かも知れませんね)
そうなんですよ、この設定も確かに疑わないといけないんですよね。
ただ、RHEL3では全て上手くいってたんですよ。
OSの文字コードがEUC→UTF-8に変更されているので影響を受けているのでしょう。
UTF-8からEUCに変更するとOSのサポート対象外になるので、変更したくない気持ちもあるんですよねぇ。
すいません、返信が遅れて。。;
Shirai さんがいっている「file.php」はmoodle直下のファイルのことですか?
私のは900行もないので、別のディレクトリかと思っているのですが。
どこのファイルでしょうか?
>(apache/php等の設定かも知れませんね)
そうなんですよ、この設定も確かに疑わないといけないんですよね。
ただ、RHEL3では全て上手くいってたんですよ。
OSの文字コードがEUC→UTF-8に変更されているので影響を受けているのでしょう。
UTF-8からEUCに変更するとOSのサポート対象外になるので、変更したくない気持ちもあるんですよねぇ。
ん~~上手くいかないですねぇ。
URLもエンコードが上手くいってない感じです。
エンコードという意味だと
moodle/mod/resource/type/file以下にある
「resource.class.php」の314行目程度にある$fullurl変数を
以下のコードで変更すると一応正しくURLにファイル名は入力されるのですが、
結局ダウンロードできず・・・
$ua = $_SERVER['HTTP_USER_AGENT'];
if (strstr($ua, "MSIE") && !strstr($ua, 'Opera')) {
$fullurl = mb_convert_encoding($fullurl, "SJIS", get_string('thischarset')); }else{
$fullurl = mb_convert_encoding($fullurl, "UTF8", get_string('thischarset'));
}
運用で話をしたら、ファイル名を英数字で対応していくようにまとまりそうですが
なんとか、したいものですね。
長々とありがとうございました。
今後とも宜しくおねがいします。
URLもエンコードが上手くいってない感じです。
エンコードという意味だと
moodle/mod/resource/type/file以下にある
「resource.class.php」の314行目程度にある$fullurl変数を
以下のコードで変更すると一応正しくURLにファイル名は入力されるのですが、
結局ダウンロードできず・・・
$ua = $_SERVER['HTTP_USER_AGENT'];
if (strstr($ua, "MSIE") && !strstr($ua, 'Opera')) {
$fullurl = mb_convert_encoding($fullurl, "SJIS", get_string('thischarset')); }else{
$fullurl = mb_convert_encoding($fullurl, "UTF8", get_string('thischarset'));
}
運用で話をしたら、ファイル名を英数字で対応していくようにまとまりそうですが
なんとか、したいものですね。
長々とありがとうございました。
今後とも宜しくおねがいします。
すみません,リソースでしたね.どうもピントがズレたことばかりしています.
当方の環境はWindowsですのであまり参考にならないかと思いますが,
php.iniのmbstring関係の設定を以下のように行なっています.
正しいという保証はありません.
[mbstring]
mbstring.language = Japanese
mbstring.internal_encoding = "UTF-8"
mbstring.http_output = "UTF-8"
mbstring.encoding_translation = On
mbstring.func_overload = 0
余計なコメントや未設定の項目は省略しています.
当方の環境はWindowsですのであまり参考にならないかと思いますが,
php.iniのmbstring関係の設定を以下のように行なっています.
正しいという保証はありません.
[mbstring]
mbstring.language = Japanese
mbstring.internal_encoding = "UTF-8"
mbstring.http_output = "UTF-8"
mbstring.encoding_translation = On
mbstring.func_overload = 0
余計なコメントや未設定の項目は省略しています.
白井です.
少々気になるのは,IE向けの対策としてfile.phpに施した対策ですが,現在のトレンドは以下のような修正だと思うのですが,いかがでしょう?
ところで,file.phpのデバッグはechoを行なっても画面に文字表示を行なえないため,面倒ですよね.PHPのデバッグツールをお持ちならば良いのですが(私は準備していません...),そうでないならば,以下のような感じで,function not_found()を改造して$pathnameの値を画面に表示・確認してみては如何でしょうか.
少々気になるのは,IE向けの対策としてfile.phpに施した対策ですが,現在のトレンドは以下のような修正だと思うのですが,いかがでしょう?
// ========================================
// finally send the file
// ========================================
session_write_close(); // unlock session during fileserving
$filename = $args[count($args)-1];
/// (ここから)
$ua = $_SERVER['HTTP_USER_AGENT'];
if (strstr($ua, "MSIE") && !strstr($ua, 'Opera')) {
$filename = "";
}
$filename = str_replace('#', '%23', $filename);
/// (ここまで)
send_file($pathname, $filename, $lifetime, $CFG->filteruploadedfiles, false, $forcedownload);
元々は上記のように"UTF-8"から"CP932"(S-JIS)へ変換するというものでしたね.ただ,気になるのは,この対策は「IEでファイルをダウンロードすると名前が化ける」という問題だったと記憶しています.MOさんの現状は,file.phpが「ファイルが見つからない」というエラーを出すのですよね? であるならば,上記コードで行なう対策とは別の要素が問題となっているのではないでしょうか.お話から察するに,上記コードの直前にある,// finally send the file
// ========================================
session_write_close(); // unlock session during fileserving
$filename = $args[count($args)-1];
/// (ここから)
$ua = $_SERVER['HTTP_USER_AGENT'];
if (strstr($ua, "MSIE") && !strstr($ua, 'Opera')) {
// $filename = mb_convert_encoding($filename, "CP932", "UTF-8");
$filename = urlencode($filename);
} else if (strstr($ua, "Safari")) {$filename = "";
}
$filename = str_replace('#', '%23', $filename);
/// (ここまで)
send_file($pathname, $filename, $lifetime, $CFG->filteruploadedfiles, false, $forcedownload);
// check that file exists
if (!file_exists($pathname)) {
こちらのエラーに引っ掛かっている,つまり問題は$pathnameの方ではないでしょうか?($filenameはクライアントPC側で再現すべきファイル名) mod/resource/type/file/resource.class.phpのdisplay()にてURLエンコードを行なってfile.phpをうまく(文字化けしないでUTF-8の名前で)呼び出せたのであれば,この$pathnameも正しいと思います.$pathnameがどういうことになっているのかを確認できないでしょうか.大元を辿ると,$pathnameは,if (!file_exists($pathname)) {
not_found($course->id);
} $relativepath = get_file_argument('file.php');
が, $pathname = $CFG->dataroot.$relativepath;
のように合体したものです.$pathnameの正当性(余分な/が付いていないか,などのチェック)はほとんど行なわれていません.ところで,file.phpのデバッグはechoを行なっても画面に文字表示を行なえないため,面倒ですよね.PHPのデバッグツールをお持ちならば良いのですが(私は準備していません...),そうでないならば,以下のような感じで,function not_found()を改造して$pathnameの値を画面に表示・確認してみては如何でしょうか.
(1) file not found 検出
// check that file exists
if (!file_exists($pathname)) {
(2) error表示
function not_found($courseid, $str="") {
// check that file exists
if (!file_exists($pathname)) {
not_found($course->id, $pathname);
}(2) error表示
function not_found($courseid, $str="") {
global $CFG;
header('HTTP/1.0 404 not found');
// error(get_string('filenotfound', 'error'), $CFG->wwwroot.'/course/view.php?id='.$courseid); //this is not displayed on IIS??
error("[$str]", $CFG->wwwroot.'/course/view.php?id='.$courseid); //this is not displayed on IIS??
}header('HTTP/1.0 404 not found');
// error(get_string('filenotfound', 'error'), $CFG->wwwroot.'/course/view.php?id='.$courseid); //this is not displayed on IIS??
error("[$str]", $CFG->wwwroot.'/course/view.php?id='.$courseid); //this is not displayed on IIS??
moodleでは,実際のファイルがある場所を隠匿していますので,Webサーバ(apache)等のようにダイレクトにURLアドレスで表示はできません.全てfile.phpを介してファイルの送信を行なうはずです.したがって,ブラウザのアドレスバーをクリックして,apache等がファイルを送信している訳ではないはずですので,バイナリーデータがブラウザ画面上に表示されるのが謎です.http手順でファイルを送信する際に,そのファイルの種類に応じて(mimeでしたか?)アプリケーションを立ち上げるのか,ダウンロードさせるのか,画面に表示させるのか,apacheのメカニズムがうまく働いていないのでしょうね.
ファイルが見つからない,という表示は,apacheが表示しているものなのか,それともmoodleが表示しているものなのか,です.もし添付したような画面が表示されるならばmoodleが出しているエラー画面であり,それは,
どちらからfile.phpを呼び出してもfile_exists()をパスできればapacheを介してファイルがブラウザに向けて送信されます.それがダウンロードされたりアプリケーションで起動するか,あるいは画面表示されるかは,apacheの設定によると思います.apacheはファイルの拡張子によってファイルの種別を判断しているのかな? もしかしたらここの処理もmoodleが行なってmime設定を生成しているとすると,拡張子をうまく認識できていないのかも知れませんね.マルチバイトの文字列に対するpathinfo()かbasename()がうまく機能していないのかも知れません.こちらを確認するには,
http://moodle.org/mod/forum/discuss.php?d=73428
を参照し,ご自身の環境で試して見て下さい.
ファイルが見つからない,という表示は,apacheが表示しているものなのか,それともmoodleが表示しているものなのか,です.もし添付したような画面が表示されるならばmoodleが出しているエラー画面であり,それは,
// check that file exists
if (!file_exists($pathname)) {
if (!file_exists($pathname)) {
not_found($course->id);
}
ここで表示されています.つまり外部からは隠匿されているmoodledata以下の実際のファイルのフルパス名を表す$pathnameでファイルの有無を確認した結果,file_exists()で発見できなかったことを意味します.ですので,この$pathnameがmod/resource/type/file/resource.class.phpのdisplay()から呼ばれた場合と,ブラウザのアドレス欄をクリックし直した場合とで異なることが理由の一つでしょう.どちらからfile.phpを呼び出してもfile_exists()をパスできればapacheを介してファイルがブラウザに向けて送信されます.それがダウンロードされたりアプリケーションで起動するか,あるいは画面表示されるかは,apacheの設定によると思います.apacheはファイルの拡張子によってファイルの種別を判断しているのかな? もしかしたらここの処理もmoodleが行なってmime設定を生成しているとすると,拡張子をうまく認識できていないのかも知れませんね.マルチバイトの文字列に対するpathinfo()かbasename()がうまく機能していないのかも知れません.こちらを確認するには,
http://moodle.org/mod/forum/discuss.php?d=73428
を参照し,ご自身の環境で試して見て下さい.
重要な確認です.
IE以外ならばダウンロードできるという前提で宜しいのでしょうか?
Firefox等でならばダウンロードが正常に行なえるのでしょうか.
もし,[サイト管理]-[サーバ]-[動作環境]で表示されるphpの設定で,iconv以降の欄の右端がOKでないならば,Firefox等でも正しく日本語のファイルをダウンロードできない可能性が高いです.PHPもソースからコンパイルしたのであれば,mbstring等がコンパイルオプションで有効になっていなかったか(コンパイルしたことが無いので分かりません),あるいはモジュールをロードするのかも知れませんが,その設定が行なわれていないということが考えられます.
それと,moodleではなく,MOさんの環境のapacheの普通のWebページにおいて,日本語ファイル名のExcelファイルのダウンロードはIEからでも正常に行うことができるのでしょうか? moodleのフォルダにhtmlファイルとエクセルのファイルを置いて確認できると思います.これでExcelが画面にバイナリーデータとして表示されるのならば問題はapacheのmimeの設定が疑われますし,Excelのファイル名を英数字に変えるとダウンロード(あるいはアプリケーションから起動)されるのであれば同じくapacheの日本語パス名に対する取り扱いが正しく機能していない結果,mime設定が正しく機能できなかったということでしょう.
IE以外ならばダウンロードできるという前提で宜しいのでしょうか?
Firefox等でならばダウンロードが正常に行なえるのでしょうか.
もし,[サイト管理]-[サーバ]-[動作環境]で表示されるphpの設定で,iconv以降の欄の右端がOKでないならば,Firefox等でも正しく日本語のファイルをダウンロードできない可能性が高いです.PHPもソースからコンパイルしたのであれば,mbstring等がコンパイルオプションで有効になっていなかったか(コンパイルしたことが無いので分かりません),あるいはモジュールをロードするのかも知れませんが,その設定が行なわれていないということが考えられます.
それと,moodleではなく,MOさんの環境のapacheの普通のWebページにおいて,日本語ファイル名のExcelファイルのダウンロードはIEからでも正常に行うことができるのでしょうか? moodleのフォルダにhtmlファイルとエクセルのファイルを置いて確認できると思います.これでExcelが画面にバイナリーデータとして表示されるのならば問題はapacheのmimeの設定が疑われますし,Excelのファイル名を英数字に変えるとダウンロード(あるいはアプリケーションから起動)されるのであれば同じくapacheの日本語パス名に対する取り扱いが正しく機能していない結果,mime設定が正しく機能できなかったということでしょう.