言語パックのインストールでエラー(Windows2000)

言語パックのインストールでエラー(Windows2000)

Tatsuya Shirai發表於
Number of replies: 13

鈴鹿高専の白井と申します.

つい1週間ほど前にxamppliteを用いて,moodle1.7.1を Windows2000 SP4のPCにインストールしました.インストールしたPCは学内LANに接続されており,プロキシサーバを介してインターネットに専用線で接続されています.ほぼ同じ環境を Windows XP SP2のPCにて確認しましたが,ほぼ同じ現象が発生します.

(問題)
言語パックを管理メニューからインストールできない.

(現象)
[A] 新しく選択してインストール:
"コンポーネットをダウンロードできません。" と表示され,単にインストールされない.

[B] いま現在インストールされている言語(例えば日本語)を選択した場合,あるいは”利用中の全ての言語パックを更新する”:
いま現在ある言語パックがフォルダ(moodledata/lang/ja_utf8)ごと削除され,単にインストールに失敗する.

(調査結果)
デバッグをONにして新たな言語パックのインストールを試みたところ,
Warning: fopen() [function.fopen]: php_network_getaddresses: getaddrinfo failed: ���̂悤�ȃz�X�g�͕s���ł��B in C:\xampplite\moodle\lib\componentlib.class.php on line 461

Warning: fopen(http://download.moodle.org/lang16/languages.md5) [function.fopen]: failed to open stream: No such file or directory in C:\xampplite\moodle\lib\componentlib.class.php on line 461

の2つのワーニングで発生しています.componentlib.class.phpの461行目,
if ($fp = fopen($source, 'r')) {
でワーニングが発生,これが原因で langimport.phpがコンポーネントのダウンロードに失敗しているらしいことが分かりました.
Warning2件のうちの1件目で,getaddrinfo failed:の後が化けています.できる範囲で調べてみましたが何を表示しようとしているのか分かりません.2件目のWarningで,$sourceが正しく"http://download.moodle.org/lang16/languages.md5"を指し示しているらしいことは確認できます.では,このサーバからdownload.moodle.org/lang16/languages.md5を見えないのか,と云えば,Webブラウザを用いることで,
---
af_utf8,7a8e9bfd778916f6a0183d913f0b2cd3,Afrikaans
ar_utf8,cb62603c6ad280c3a280f65f2d1136bb,عربي
・・・
---
のように,ファイル名,MD5コードなどのリストが表示できますので到達できているようです.では,moodleのhttpのプロクシホストの設定が正しくないのか,といいますと,192.168.0.1,ポートを8080に設定しているのをhttp://192.168.0.1(明白に変ですね)に変更すると,
Warning: fsockopen() [function.fsockopen]: unable to connect to http://192.168.0.1:8080 (Unable to find the socket transport "http" - did you forget to enable it when you configured PHP?) in C:\xampplite\moodle\admin\langimport.php on line 386
と表示され,言語パックのリスト一覧が取得できないので手動でインストールするように,という日本語のメッセージが表示されます.以上のことからプロクシホストは正しいように思えます.ちなみに192.168.0.2に設定(そのようなプロクシは存在しない)すると,やはり60秒後にTimeoutが発生して,
Warning: fsockopen() [function.fsockopen]: unable to connect to 192.168.0.2:8080 (�ڑ��ς݂̌Ăяo���悪 ���̎��Ԃ�߂��Ă������������Ȃ�������߁A�ڑ��ł��܂���ł����B�܂��͐ڑ��ς݂̃z�X�g���������Ȃ�������߁A�m����� ꂽ�ڑ��͎��s���܂����B ) in C:\xampplite\moodle\admin\langimport.php on line 386
のエラーが発生します.192.168.0.1で正しいのではないかと思う根拠の一つです.

PHPによるfopen()のエラーで調べてみたところ,php.iniの設定で,
; Whether to allow the treatment of URLs (like http:// or ftp://) as files.
allow_url_fopen = On
をOffにしている場合にもエラーが出るという話がありましたので確認しましたが,上記のようにOnです.

学内ネットワークの内側と,さらにその内側の研究室内LANの内側(192.168.0.*)の双方で試しましたが,どちらでも状況は変りません.

OSがwindowsであること,プロキシを経由していること,この辺りに原因があるのであって,他の方々に問題が生じていないと思われるのはこのせいか,と思います.最新のmoodle1.7.1+で上書きしてみましたが,この問題は解決しません.

何が原因か,その切り分け方法に何かアドバイス頂けないでしょうか.当方,PHPは全くの初心者です.C/C++言語は分かりますので,なんとなくソースを追いかけたのですが,Apacheを含めたネットワークに問題があるような気がする,というところまで追い詰めたところで限界です...


評比平均分數: -
In reply to Tatsuya Shirai

Re: 言語パックのインストールでエラー(Windows2000)

Tatsuya Shirai發表於
自己レスです.

調査を再開しました.

(1) php.ini
PHPのプロキシ設定が必要なのかと思い,
pfpro.proxyaddress =
pfpro.proxyport =
の2行にプロキシサーバのアドレスとポートを設定しましたが変化なし.
でも,これはきっと,
[管理]-[サーバ]-[HTTP]
で設定したアドレスが利用されているのでしょうねぇ.関係ないのかな.

(2) Apacheのエラーログ

Apacheのerr.logに以下のエラー報告が出ています.言語パックの追加に失敗するたびに出ているようです.
[Wed Feb 28 12:15:16 2007] [error] [client 127.0.0.1] File does not exist: C:/xampplite/moodle/moodle

moodle/moodleとダブっていますね.どこの設定が影響を与えているのか分かりませんが,これが原因(あるいは単に結果?)なのか.

やはり未解決ですが,(2)のApacheのエラーから原因追求をしていこうと思います.

In reply to Tatsuya Shirai

Re: 言語パックのインストールでエラー(Windows2000)

Tatsuya Shirai發表於

これは私の勘違いでした.
(2)のApacheのエラーログの件です.
そもそも err.logではなく,error.logですし.

さて,File does not existは,cronの設定ミスでした.アドレスとして,http://localhost/admin/cron.phpを設定すべきところ,http://localhost/moodle/admin/cron.phpとしていたためでした.Webサーバのドキュメントのルートが既にmoodleでしたので,moodle/moodle/admin/cron.phpと指示されていた次第です.

さて,結局,言語パックのダウンロードの件は状況として変化なし,ですん.


In reply to Tatsuya Shirai

Re: 言語パックのインストールでエラー(Windows2000)

Tatsuya Shirai發表於

同じ問題が他でも発生しているようです.

http://moodle.org/mod/forum/discuss.php?d=60405

>Well, I tried to change the configuration line as suggested, from

>$CFG->unicodedb=true

>to

>$CFG->unicodedb='1'

>(that it seems to be the same, true = 1 isn't ?)

>and got with both options the same time out error

unicodedb='1'として改善した人もいたようですが,上記のコメントをつけている方と同じく,私の環境もtrueですので,やはり同じですね.

うーん,言語のリストを獲得する際にはproxy_url()を使っているのに,いざ読み込む段では使っていないように見えるので,もしかしてこの辺りにあるのでは,と睨んでいます.Proxyサーバのログを見ると,確かに,

2007/03/02(10:27:14) P-SV(HTTP) 192.168.0.55 [8080] http-p.srv.cc.suzuka-ct.ac.jp [8080] "GET http://download.moodle.org/lang16/languages.md5 HTTP/1.0"

プロキシを通っているように見えるのですが,どうもこれはリスト獲得時のログのようです.言語パック一覧を獲得し,指定された言語パックを獲得するためにmode=2でlangimport.phpを読んだ後, fopen($source, 'r')で単純に読みに行って,失敗しているように見えるのだが...

プロキシサーバの内側から,言語パックを自動インストールできた方,いらっしゃいましたら「できたよ」とReply頂けないでしょうか.


In reply to Tatsuya Shirai

Re: 言語パックのインストールでエラー(Windows2000)

Mitsuhiro Yoshida發表於
Developers的相片 Particularly helpful Moodlers的相片 Translators的相片
白井先生

プロクシに関して、管理画面(1) で下記の内容に何か設定されていますでしょうか?
  • プロクシホスト proxyhost
  • プロクシポート proxyport

(1) 管理画面
Moodle 1.7以上: 管理 >> サーバ >> HTTP
Moodle 1.64以下: 管理 >> 設定 >> 詳細設定 >> オペレーティングシステム

In reply to Mitsuhiro Yoshida

Re: 言語パックのインストールでエラー(Windows2000)

Tatsuya Shirai發表於
お世話になります.

白井です.

$CFG->proxyhost と $CFG->proxyport がcomponentlib.class.php内で,言語パックのダウンロードの段階で全く使用されていないことを発見しました.availablelangsのリストを取得するところでは使用しているのに! (proxy_url()関数 in langimport.php)

いやぁ,難儀しました.
proxyサーバも自分で管理している,ということをすっかり忘れていました.ログを見て,利用可能な言語パック一覧を取得する時は [GET}のリクエストが来ているのに,その後はまったくリクエストが来ないことに気付いたあとは,早かったです.

In reply to Tatsuya Shirai

Re: 言語パックのインストールでエラー(Windows2000)

Tatsuya Shirai發表於

解決しました満面の笑顔

やはり,Proxy経由でのデータ取得のコーディングに一部不完全な実装が残っていますね.これはプロキシを使用しているユーザにとっては致命的です.

プログラムを数箇所直したところ,無事に言語パッケージ(とりあえず試しでit_utf8,イタリア語)の追加に成功しました.まだ削除や更新のチェックはおっかなくて行なっていません.PHPの命令や文法を知りませんので,ヒヤヒヤです.

問題2種類,どちらも componentlib.class.php内です.fopen()とfile_get_contents()を無造作に使用しています.これらはProxyの内側からでは使えないようです.言語パックの一覧の表示では,langimport.php内のproxy_url()関数を使用しているのでProxyに対応できています.したがって,これを流用してcomponentlib.class.phpを以下のように修正しました.

(1) Proxy対応の関数 proxy_url()とproxy_file_get_contents()を追加
componentlib.class.phpの最後の方に,
function get_extra_md5_field() {
return $this->extramd5info;
}
のあとに,関数を追加.ちなみにproxy_url()はlangimport.php内のものと完全に同一(仕事も同じですから),proxy_file_get_contents()はそれを元にして改造したものです.
------ここから
function proxy_url($url) {
global $CFG;

if ($CFG->proxyhost && $CFG->proxyport) {

$proxy_fp = fsockopen($CFG->proxyhost, $CFG->proxyport);
if (!$proxy_fp) {
return false; //failed
}
fputs($proxy_fp, "GET $url HTTP/1.0\r\nHost: $CFG->proxyhost\r\n\r\n");
$i = 0;
while(!feof($proxy_fp)) {
$string = fgets($proxy_fp, 1024);
if ($i > 11) { //12 lines of info skipped
$availablelangs[] = split(',', $string);
}
$i++;
}
fclose($proxy_fp);

} else { //proxy not in use
if ($fp = fopen($url, 'r')){ /// attempt to get the list from Moodle.org.
while(!feof ($fp)) {
$availablelangs[] = split(',', fgets($fp,1024));
}
} else { /// fopen failed, return false.
return false;
}
}
return $availablelangs;
}

// based on proxy_url() modified by T.Shirai
function proxy_file_get_contents($url) {
global $CFG;

if ($CFG->proxyhost && $CFG->proxyport) {

$proxy_fp = fsockopen($CFG->proxyhost, $CFG->proxyport);
if (!$proxy_fp) {
return false; //failed
}
fputs($proxy_fp, "GET $url HTTP/1.0\r\nHost: $CFG->proxyhost\r\n\r\n");
$i = 0;
$contents = ""; // Added
while(!feof($proxy_fp)) {
if ($i <= 11) fgets($proxy_fp, 1024); else { // Added
$contents .= fread($proxy_fp, 8192); // Added
}
$i++;
}
fclose($proxy_fp);

} else { //proxy not in use
if (!$contents = file_get_contents($url)) return false;
}
return $contents;
}
---------ここまで.

(2)以上,2つの関数をそれぞれ呼び出すべき場所を修正
(2-1) proxy_url()
461行あたりの
if ($fp = fopen($source, 'r')) {
/// Read from URL, each line will be one component
while(!feof ($fp)) {
$availablecomponents[] = split(',', fgets($fp,1024));
}
fclose($fp);
をコメントアウト( /* */ ) し,
代わりに,
if ($availablecomponents = $this->proxy_url($source)) {
とする.カッコのネストに注意.余計な } を消さないように.

(2-2) file_get_contents その1
274行あたりの
if ($contents = file_get_contents($source)) {

if ($contents = $this->proxy_file_get_contents($source)) {
に変更.

(2-3) file_get_contents その2
393行あたりの
if ($temp = file_get_contents($source)) {

if ($temp = $this->proxy_file_get_contents($source)) {
に変更.

以上です.

私はPHPに関して全くの素人なのですが,プロキシの内/外を意識しないでfgets()やfile_get_contents()を使えるようなテクニックというものは無いのでしょうか.Proxyを通してGETすると,頭11行分ほど余計なゴミが付いて来るのでしょうか(私はソースコードからそのように判断したのですが),これを読み飛ばす必要があります.でも,これが環境によっては12行になったり10行になったりすることはないのでしょうか.不安ですねぇ,

私は英語に自信がないので,どなたかこの問題をフィードバックして頂けないでしょうか? 原因究明はともかく,対策自体が正しい方法なのか自信がありませんので,間違った用語で間違ったアドバイスを間違った文法で伝えると被害が広がる可能性が高いです...

In reply to Tatsuya Shirai

Re: 言語パックのインストールでエラー(Windows2000)

Tatsuya Shirai發表於
あらあら,インデントの空白が全て消えてしまうのですね.
読みにくくて申し訳ありません.
ソースリストを書き込むにはどうしたら良かったのでしょう?
In reply to Tatsuya Shirai

Re: 言語パックのインストールでエラー(Windows2000)

Tatsuya Shirai發表於
以上の改善で,
(1)追加した言語パックのアンインストール:問題なし
(2)インストールされている言語パックのアップデート:エラー

(2)は単にエラーになるだけではなく,既にインストール済みの言語パックも消してくれました...改めて日本語パックを追加しました.これは成功.

まだfopen()+fgets()がProxyの使用に関知せず,そのまま使われている箇所が残っていそうです.

In reply to Tatsuya Shirai

Re: 言語パックのインストールでエラー(Windows2000)

Tatsuya Shirai發表於
白井です.
どうやら以下の修正だけでなんとかなりそうですね.
以前に指摘したポイントのうちの,393行目のfile_get_contents()は修正しない方が良いので,最終的には以下のような修正をmoodle/lib/componentslib.class.phpに行なうだけで良いようです.デバッグ表示を有効にしていると,”全ての言語パックを更新”すると,[Notice!]が表示されますが.

しかし,proxy_url()という関数の名前は(私が言うのも何ですが)センスが悪いです.とても汎用性の高いクラスなのかな?と思いきや,そうではない.確かに,言語パックのリストをダウンロードするだけではなく,webからダウンロード可能なテキストファイルをリスト化して返す比較的汎用性の高い関数ではありますが,その意味合いを表した名前ではないですね.

Blue : original

Red : Modification (adding)

(1) Line 273
$zipfile= $CFG->dataroot.'/temp/'.$this->zipfilename;
// if ($contents = file_get_contents($source)) {
if ($contents = $this->proxy_file_get_contents($source)) {
(2) Line 460
$availablecomponents = array();
if ($availablecomponents = $this->proxy_url($source)) {
/* if ($fp = fopen($source, 'r')) {
/// Read from URL, each line will be one component
while(!feof ($fp)) {
$availablecomponents[] = split(',', fgets($fp,1024));
}
fclose($fp);
*/
(3) Line 516
function get_extra_md5_field() {
return $this->extramd5info;
}

//returns an array of languages, or false if can not read from source
//uses a socket if proxy is set as a config variable
function proxy_url($url) {
global $CFG;

if ($CFG->proxyhost && $CFG->proxyport) {
$proxy_fp = fsockopen($CFG->proxyhost, $CFG->proxyport);
if (!$proxy_fp) {
return false; //failed
}
fputs($proxy_fp, "GET $url HTTP/1.0\r\nHost: $CFG->proxyhost\r\n\r\n");
$i = 0;
while(!feof($proxy_fp)) {
$string = fgets($proxy_fp, 1024);
if ($i > 11) { //12 lines of info skipped
$availablelangs[] = split(',', $string);
}
$i++;
}
fclose($proxy_fp);
} else { //proxy not in use
if ($fp = fopen($url, 'r')){ /// attempt to get the list from Moodle.org.
while(!feof ($fp)) {
$availablelangs[] = split(',', fgets($fp,1024));
}
} else { /// fopen failed, return false.
return false;
}
}
return $availablelangs;
}

// based on proxy_url() modified by T.Shirai
function proxy_file_get_contents($url) {
global $CFG;

if ($CFG->proxyhost && $CFG->proxyport) {
$proxy_fp = fsockopen($CFG->proxyhost, $CFG->proxyport);
if (!$proxy_fp) {
return false; //failed
}
fputs($proxy_fp, "GET $url HTTP/1.0\r\nHost: $CFG->proxyhost\r\n\r\n");
$i = 0;
$contents = "";
while(!feof($proxy_fp)) {
if ($i <= 11) fgets($proxy_fp, 1024); else {
$contents .= fread($proxy_fp, 8192);
}
$i++;
}
fclose($proxy_fp);
} else { //proxy not in use
if (!$contents = file_get_contents($url)) return false;
}
return $contents;
}
} /// End of component_installer class
In reply to Tatsuya Shirai

Re: 言語パックのインストールでエラー(Windows2000)

Tatsuya Shirai發表於
まだ問題点が残っていました.
一見,うまくいっていたように見えた言語パックのアップデートですが,しくじります.

まず,PHPのNoticeも出ていました.これはadmin/langimport.phpのproxy_url()に問題があり,つまりこれをコピーして対策したlib/componentlib.class.phpのproxy_url()も同じ問題があります.

$string = fgets($proxy_fp, 1024);
if ($i > 11) { //12 lines of info skipped
$availablelangs[] = split(',', $string);
}
の$string,最終行を読み込んだ後に$string=""がfeof()をすり抜けてしまうため,$availablelangs[]の配列の一番最後に空の要素が追加されてしまいます.それをlangimport.php内foreachで分解しようとしてundefined indexのNoticeが発生します.空の文字列を読み込んだ時は無視すれば良いので,
$string = fgets($proxy_fp, 1024);
if (strlen($string) >0 && $i > 11) { //12 lines of info skipped
$availablelangs[] = split(',', $string);
}
とすればNoticeは発生しなくなります.

これで無事に,アップデートに成功しました.



附件 updateok.jpg
In reply to Tatsuya Shirai

Re: 言語パックのインストールでエラー(Windows2000)

Tatsuya Shirai發表於
白井です.

moodle 1.8のソースも見てみたのですが,改善されていなかったので,
moodle trackerにリクエストしておきました.

http://tracker.moodle.org/browse/MDL-8752

trackerの使い方が良く分からない上に,英語力が徹底的に不足しているので,うまく反映されるかどうか...

In reply to Tatsuya Shirai

Re: 言語パックのインストールでエラー(Windows2000)

Tatsuya Shirai發表於

moodle1.8で,言語パック関係のバグの一部は修正されましたが,根本的な原因はまだ対応されていません.using moodleのフォーラムにて私以外の方も問題提起し始めたので動き始めてくれるかも知れません.

さて,moodle1.8でも相変わらずProxy経由でインターネット接続しているサーバの場合,言語パックのダウンロード/更新(だけ)に失敗します.以前にmoodle1.7用の修正箇所を掲載しました.moodle1.8ではそのままでは適用できません.調査した結果,以下の修正を moodle/lib/componentlib.class.phpに対して行なうことで,言語パックの更新が行なえるようになることを確認しました.

紫色の部分はadmin/langimport.php内のproxy_url()関数をそのままコピーして下さい(改良されています).

-----
Blue : original
Red : Modification (adding)
Purple : Copy from admin/langimport.php (function proxy_url() : line363)

(1) Line 273
$zipfile= $CFG->dataroot.'/temp/'.$this->zipfilename;
// if ($contents = file_get_contents($source)) {
if ($contents = $this->proxy_file_get_contents($source)) {
(2) Line 460
$availablecomponents = array();
if ($availablecomponents = $this->proxy_url($source)) {
/* if ($fp = fopen($source, 'r')) {
/// Read from URL, each line will be one component
while(!feof ($fp)) {
$availablecomponents[] = split(',', fgets($fp,1024));
}
fclose($fp);
*/
(3) Line 516
function get_extra_md5_field() {
return $this->extramd5info;
}

//returns an array of languages, or false if can not read from source
//uses a socket if proxy is set as a config variable
function proxy_url($url) {
global $CFG;

if ($CFG->proxyhost && $CFG->proxyport) {

$proxy_fp = fsockopen($CFG->proxyhost, $CFG->proxyport);
if (!$proxy_fp) {
return false; //failed
}
fputs($proxy_fp, "GET $url HTTP/1.0\r\nHost: $CFG->proxyhost\r\n\r\n");

$headers_done = false;
while(!feof($proxy_fp)) {
$string = fgets($proxy_fp, 1024);
if(!$headers_done){
// A new line indicates end of HTTP headers
$headers_done = ("\r\n" == $string);
} else {
$availablelangs[] = split(',', $string);
}
}
fclose($proxy_fp);

} else { //proxy not in use
if ($fp = fopen($url, 'r')){ /// attempt to get the list from Moodle.org.
while(!feof ($fp)) {
$availablelangs[] = split(',', fgets($fp,1024));
}
} else { /// fopen failed, return false.
return false;
}
}
return $availablelangs;
}

// based on proxy_url() modified by T.Shirai
function proxy_file_get_contents($url) {
global $CFG;

if ($CFG->proxyhost && $CFG->proxyport) {

$proxy_fp = fsockopen($CFG->proxyhost, $CFG->proxyport);
if (!$proxy_fp) {
return false; //failed
}
fputs($proxy_fp, "GET $url HTTP/1.0\r\nHost: $CFG->proxyhost\r\n\r\n");

$headers_done = false;
$contents = '';
while(!feof($proxy_fp)) {
if(!$headers_done){
// A new line indicates end of HTTP headers
$string = fgets($proxy_fp, 1024);
$headers_done = ("\r\n" == $string);
} else {
$contents .= fread($proxy_fp, 8192);
}
}
fclose($proxy_fp);

} else { //proxy not in use
if (!$contents = file_get_contents($url)) return false;
}
return $contents;
}
} /// End of component_installer class
-----------------

もっとも,私は近頃,言語パックの更新機能を使用していません.言語パックは個人的にカスタマイズしている部分もありますし,サードパーティ製のBlockも使用しています.日本語フォントの問題もありますので,フォルダごとゴッソリと入れ替えることで更新する,本家の機能ですと支障があるためです.

最新版の日本語言語パックをダウンロードし,WinMergeを用いて差異のある部分のみ更新しています.moodle本体のアップグレードも同様に,CVSではなくWinMergeを用いて行なっています.CVSのクライアントがProxyを通過できない...と悩んでいたのですが,結局は手作業が一番効率と安全性が高いことに気付きました.

In reply to Tatsuya Shirai

Re: 言語パックのインストールでエラー(Windows2000)

Tatsuya Shirai發表於

 本件同様に,Proxyサーバ経由でMoodleのいくつかの機能が正しくインターネットにアクセスできない問題は,Moodle1.9.1およびMoodle2.0で解決されたようです.

http://tracker.moodle.org/browse/MDL-11845

まだMoodle1.9はベータ版ですので試していません.