Moodleの文字化け
Moodleはその生まれのためか所謂CJK文字への対応があまり良くなく、不具合を報告してもスルーされることがある。IE利用時の文字化けについては対応されているが、EdgeはIEとは全く異なる扱いとなっているため文字化けしてしまう。
状況
修正前は以下のようにダウンロード時に文字化けしてしまう。ファイル名が化けるだけならまだしも、拡張子前のピリオドが失われてしまうために文字化けについて詳しくないユーザだとファイルを開くことができなくなる場合がある(ファイル内容自体は壊れていない)。
修正方法
一般的なファイルのダウンロードの場合
ファイルダウンロード時にIE用にファイル名を処理している部分が lib/filelib.php 中に3箇所あるため、その部分を全て以下のように書き換える。
※Moodle 3.4では2箇所になっている。
※Moodle 3.5.1、3.4.4で修正された模様。
変更前
lib/filelib.php
// if user is using IE, urlencode the filename so that multibyte file name will show up correctly on popup
if (core_useragent::is_ie()) {
$filename = rawurlencode($filename);
}
変更後
lib/filelib.php
// if user is using IE, urlencode the filename so that multibyte file name will show up correctly on popup
if (core_useragent::is_ie() || core_useragent::is_edge()) {
$filename = rawurlencode($filename);
}
動作確認
mod_feedbackの回答結果をダウンロードする場合
この場合は lib/classes/dataformat/spout_base.php を書き換える必要がある。
lib/classes/dataformat/spout_base.php
public function send_http_headers() {
$this->writer = \Box\Spout\Writer\WriterFactory::create($this->spouttype);
if (method_exists($this->writer, 'setTempFolder')) {
$this->writer->setTempFolder(make_request_directory());
}
$filename = $this->filename . $this->get_extension();
+
+ // if user is using IE, urlencode the filename so that multibyte file name will show up correctly
+ if (\core_useragent::is_ie() || \core_useragent::is_edge()) {
+ $filename = rawurlencode($filename);
+ }
+
$this->writer->openToBrowser($filename);
備考
core_useragent::is_edge()
は lib/classes/useragent.php 中で定義されている。このメソッドは3.0系にも存在するが、2.8系には存在しない。
lib/classes/useragent.php
/**
* Checks the user agent is Edge (of any version).
*
* @return bool true if Edge
*/
public static function is_edge() {
return self::check_edge_version();
}
/**
* Check the User Agent for the version of Edge.
*
* @param string|int $version A version to check for, returns true if its equal to or greater than that specified.
* @return bool
*/
public static function check_edge_version($version = null) {
$useragent = self::get_user_agent_string();
if ($useragent === false) {
// No User Agent found.
return false;
}
if (strpos($useragent, 'Edge/') === false) {
// Edge was not found in the UA - this is not Edge.
return false;
}
if (empty($version)) {
// No version to check.
return true;
}
// Find the version.
// Edge versions are always in the format:
// Edge/<version>.<OS build number>
preg_match('%Edge/([\d]+)\.(.*)$%', $useragent, $matches);
// Just to be safe, round the version being tested.
// Edge only uses integer versions - the second component is the OS build number.
$version = round($version);
// Check whether the version specified is >= the version found.
return version_compare($matches[1], $version, '>=');
}