Moodleのユーザ画像を新サイトに移行させる

# Moodleのユーザ画像
利用者はMoodleのプロフィールページで自分のユーザ画像をアップロードすることができる。フォーラムなどで認識しやすいように利用者に画像をアップロードするよう指示している管理者は少なくないと考える。
Moodleを年度毎に構築しているような場合はこの作業を毎年利用者に強いることになるため、管理者側で一括してユーザ画像を取り込み、新年度用システムにアップロードしたい。ついでに自己紹介文も上書きしておく。

# やりかた
下記のスクリプトを適当な場所において実行する。アクセス制限を行ったWebページ上での実行を想定しているが、CLI用に一部書き換えて実行しても良い。
管理者がちゃちゃっと作業するためのものなのでエラーハンドリングとかまじめにやってない手抜き。
そのまま実行すると動作チェック時になり、 *$mode = "update"* に変更してから実行すれば自己紹介のアップデートが行われる。 

```php
<?php
ini_set('display_errors', 1);
ini_set('max_execution_time', -1);

// 定義
// 新しいMoodle環境
$conf['db']['new']['host']   = "";
$conf['db']['new']['user']   = "";
$conf['db']['new']['passwd'] = "";
$conf['db']['new']['dbname']  = "";

// 古いMoodle環境
$conf['db']['old']['host']   = "";
$conf['db']['old']['user']   = "";
$conf['db']['old']['passwd'] = "";
$conf['db']['old']['dbname']  = "";
$conf['old']['dataroot'] = "/path/to/moodledata/";

// ユーザ画像の保存先
$targetdir = '/path/to/saveimages/';

$mode = "";  // 動作チェック時
//$mode = "update";  // アップデート時

// DBに接続
$dbold = new PDO("mysql:host=".$conf['db']['old']['host']."; dbname=".$conf['db']['old']['dbname'].";charset=utf8",
    $conf['db']['old']['user'], $conf['db']['old']['passwd'],
    array(PDO::ATTR_EMULATE_PREPARES => false));  // Moodle 3.1以前を想定
$dbnew = new PDO("mysql:host=".$conf['db']['new']['host']."; dbname=".$conf['db']['new']['dbname'].";charset=utf8mb4",
    $conf['db']['new']['user'], $conf['db']['new']['passwd'],
    array(PDO::ATTR_EMULATE_PREPARES => false));  // Moodle 3.2.2以降utf8mb4対応
$dbold->exec("set names utf8");
$dbnew->exec("set names utf8");

// 古いMoodleの全てのユーザリストを取得
$sql = "SELECT u.id, username, description, picture, imagealt, contenthash, filename
        FROM user AS u
        LEFT JOIN files AS f ON u.picture = f.id";
$stmt = $dbold->prepare($sql);
$stmt->execute();
$oldusers = $stmt->fetchAll(PDO::FETCH_OBJ);
$stmt = null;

// 新しいMoodleから指定されたユーザ名を探すクエリ
$username = "dummy";
$sql = "SELECT id, username, description, descriptionformat, imagealt, picture
        FROM user
        WHERE username = :username";
$stmt = $dbnew->prepare($sql);
$stmt->bindParam(':username', $username, PDO::PARAM_STR);

// ユーザの自己紹介を更新するクエリ
$description = "dummy";
$id = 0;
$sql = "UPDATE user SET description = :description WHERE id = :id";
$update = $dbnew->prepare($sql);
$update->bindParam(':description', $description, PDO::PARAM_STR);
$update->bindParam(':id', $id, PDO::PARAM_INT);

foreach ($oldusers as $olduser) {
  $username = $olduser->username;
  $stmt->execute();
  $newuser = $stmt->fetch(PDO::FETCH_OBJ);
  $stmt->closeCursor();
  
  if (@$newuser->id !== null) {  // ユーザは両Moodleに存在する？
    if (strlen($newuser->description) == 0) {  // 新しいMoodleのユーザの自己紹介は空欄？
      echo $olduser->username . "(" . $olduser->id . ")" . "/" . $newuser->username . "(" . $newuser->id . ")" . "<br />";
    
      // ユーザの自己紹介を更新
      $description = $olduser->description;
      echo $description;
      $id = $newuser->id;
      if ($mode == "update") $update->execute();
    }
    
    if ($olduser->picture) {  // ユーザ画像は登録されてる？
      echo $olduser->picture . ' - ' . $olduser->contenthash . '<br />';
      $file = $conf['old']['dataroot'] . '/filedir/' . substr($olduser->contenthash, 0, 2) . '/' . substr($olduser->contenthash, 2, 2) . '/' . $olduser->contenthash;
      $path_parts = pathinfo($olduser->filename);
      $ext = $path_parts['extension'];

      copy($file, $targetdir . '/' . $olduser->username . '.' . $ext);
    }
    echo '</p>';
  }
}

die('完了！');
?>
```

実行すると */path/to/saveimages/* にユーザ名（ログイン名）の付いたjpgファイルが保存される。これをzipで固めて新サイトの[サイト管理] > [ユーザ] > [アカウント] > [ユーザ画像をアップロードする]でユーザ画像アップロードページに進み、*username* でマッチするように選択してからアップロードすれば完了。

Moodle 2.4以降で使っているが3.2までの間に問題が出たことは無い（はず）。
Moodleのライブラリを使わずにMySQLでだけ動作するようになっているのが良くないとか色々問題があるので、暇があれば修正したい。