実習報告書 - 琉球大学 工学部 情報工学科

OJT 実習報告書
moolde のプラグイン作成方法編
実習先:合資会社 e ラーニングサービス
所属:琉球大学工学部情報工学科
学籍番号:055717A
報告者氏名:金城佑典
2007/09/20
概 要
moodle の「ブロック」「フィルタ」「モジュール」を作成する時の注意点をまとめた文書です
1
目次
1
moodle について
3
2
共通事項
3
2.1
2.2
2.3
3
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
プログラムの作成 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
プログラムの配布 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3
3
4
block
3.1 ファイル構成 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
4
4
例:サンプルブロック . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
4
5
3.2
4
サンプルブロックのファイル構成 . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3.2.2
3.2.3
3.2.4
言語ファイル (block sample.php) . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
本体 (block sample.php) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
filter
4.1 ファイル構成 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
7
7
例:イメージファイルフィルタ(imagesize) . . . . . . . . . . . . . . . . . . . . . . . . . . .
7
8
設定画面の定義 (config instance.html) . . . . . . . . . . . . . . . . . . . . . . . . . .
4.2.1
イメージファイルフィルタのファイル構成 . . . . . . . . . . . . . . . . . . . . . . . .
4.2.2
4.2.3
4.2.4
デフォルトの値の定義 (defaultsettings.php) . . . . . . . . . . . . . . . . . . . . . . .
本体 (filter.php) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
8
8
10
4.2.5
言語ファイル (imagesize.php) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
11
設定画面の定義 (filterconfig.html) . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
module
5.1
5.2
6
3.2.1
5
5
6
4.2
5
プログラム作成前に
11
ファイル構成 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
例:sample . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
5.2.1
5.2.2
5.2.3
ファイル構成 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
5.2.4
5.2.5
バージョンなど(version.php) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
5.2.6
5.2.7
5.2.8
言語ファイル(sample.php) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
データベースの作成(mysql.sql) . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
ライブラリ(lib.php) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
アイコン(icon.gif) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
11
11
12
12
12
14
15
コース内のインスタンスを表示(index.php) . . . . . . . . . . . . . . . . . . . . . .
15
15
15
5.2.9 設定画面(mod.html) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
5.2.10 一つ一つのインスタンスを表示(view.php) . . . . . . . . . . . . . . . . . . . . . . .
17
18
注意点
6.1 バージョン問題 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
19
19
ロールとケーパビリティ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
20
20
6.1.1
6.1.2
アップデート(mysql.php) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
データベースの仕様変更 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2
6.2
6.1.3 関数の仕様変更 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
セキュリティ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
21
21
ケイパビリティ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
21
21
6.2.1
6.2.2
6.3
ユーザからの入力の処理 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
動作テスト
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3
22
moodle について
1
http://download.moodle.org/ からダウンロードできるオープンソース(GNU GENERAL PUBLIC LICENSE Version 2 1 )の e ラーニングプラットフォーム、PHP,MySQL そして一部は javascript がつかわれて
おり、これらが動作するほとんどの OS で動作する。
共通事項
2
2.1
プログラム作成前に
1. プログラムの仕様を決めておく
プログラムを作成するまえに先方の要求定義に従ってプログラムの仕様を決めておきましょう、入力値
と出力値だけでなく、画面構成や処理手順まで決めておくと楽ができます。
2. 先方の moodle のバージョンを調べておく
忘れがちですが結構重要です、後述するバージョン問題があるのでこれを知っておかないと「テストで
は動いたのに先方では動かない」という罠に陥ります。バージョンによっては大きな変更がなされてい
る場合もあるので運が悪いとプログラムの大部分を書き換えることになったりそもそも仕様が実現でき
なかったりします、プログラムの内容によってはもっと詳しいこと(PHP や MySQL のバージョン等)
も調べておく必要があります。
3. 環境の用意
moodle のバージョンなどに気をつけて開発/テスト用の環境を構築します、プログラムを作りながら
テストできるようにあらかじめデータをたくさん用意(ユーザを登録したり課題を提出しといたり)し
とくと便利です。
4. 参考にするプログラムを選ぶ
先に決めた仕様に基づいてひな形として使うプログラムを決めます、実現したい機能を実装していてな
おかつなるべく構成ファイル数が少ないものを選ぶと後々楽ができます、コメントとかついてるととて
もうれしいですね。
2.2
プログラムの作成
1. ネーミングルールに注意!
moodle にはネーミングルールがあります、1文字間違えただけで動かなかったりするのでファイル名や
定義する関数の名前等あらかじめ決められたルールがないか調べておきましょう。
2. ソースコードにはコメントをつけましょう
作ってる途中はめんどくさく感じますがコメントがないとデバッグの時に泣けてきます、開発を引き継
ぐ人のためにもコメントはなるべくつけるようにしましょう。moodle は海外にもユーザがいるのでで
きれば英語でつけましょう。
1 オープンソースのライセンス、このライセンスがついたプログラムは好きなように利用することができる、ただしそれを利用したプ
ログラムも GPL ライセンスで公開しなければならない
4
3. デバッグ用の文も書いておきましょう
デバッグ用の文があると後々とっても便利です、関数を実行したり変数を取得したりした後は var dump()
などを使って思った通りに動作しているか確認できるようにしておきましょう。
4. バージョン管理はきちんとしましょう
「;」を忘れたり関数名や引数を間違えたりするとエラーになります、運が良ければエラーメッセージが
出ますがたいていは真っ白な画面になって「なんで動かないのかわかんない」状態になります、要所要
所でコピーをとっておきましょう。
5. ユーザーインターフェースはわかりやすくしましょう
複雑なインタフェースは誤操作/誤作動の原因になります、誤操作によるエラーは原因究明が非常に難
しいのであらかじめ想定外の操作はできないようにしておきましょう。
2.3
プログラムの配布
1. ライセンス
moodle のライセンスは GPL です、作成した moodle プログラムは無料でソースコードを公開しましょ
う。(有料にしたりすると規約違反になります。)
2. ドキュメントの整備
readme やマニュアルを同梱しておきましょう、テスト用のファイルも入れておくとより親切です。
3
block
ブロックはコースの左右に表示されている長方形のやつのことです、本体は表示サイズがある程度制限され
るのでフィルタやモジュールよりデザインを簡素化する必要があります。
(「ボタンをクリックしたら別ウィン
ドウを開く」という方法もあります。)
3.1
ファイル構成
dataroot/blocks/作成するブロック名/block_作成するブロック名.php #本体
dataroot/blocks/作成するブロック名/config_instance.html #設定画面の定義
dataroot/blocks/作成するブロック名/db/ #データベースを使うブロックを作成するときに使う
dataroot/lang/文字コード名/block_作成するブロック名.php #プログラム中で使う日本語を定義
3.2
例:サンプルブロック
ボタンをクリックすると action でしていしたファイル(下記ソースコードでは sample.php)にコース ID
を渡すブロックです。
5
3.2.1
サンプルブロックのファイル構成
ブロック名を「sample」にするので設置した際のファイル構成は以下のようになります。
dataroot/
+-- blocks/
|
+-- sample/
|
+-- block_sample.php
|
+-- config_instance.html
|
+-- sample.php
+-- lang/
|
+-- ja_utf8/
|
+-- block_sample.php
3.2.2
言語ファイル (block sample.php)
言語ファイルではプログラム中で使う文字を定義しておきます、今回は言語ファイルが lang/ja utf8/block sample.php
なので文字コードは utf8 で保存してください。
ここで定義した日本語はプログラム中で get string() などを使って取得して使用することができます、今回
は言語ファイル名が「block sample.php」なのでプログラム中で「get string(’blockname’, ’block sample’);」
のようにすると「文字コード変換」という文字が string 型で帰ってきます。
<?PHP // $Id$
// block_assign_down
$string[’configtitle’] = ’ ブロック名’;
$string[’configlinkname’] = ’ リンク名’;
$string[’blockname’] = ’ サンプル’;
$string[’sampleblock’] = ’ サンプルブロック’;
$string[’defaultbname’] = ’ 表示’;
?>
3.2.3
設定画面の定義 (config instance.html)
編集モードでブロック名のところに表示される鉛筆マークをクリックすると表示される設定画面の定義で
す、ここにはユーザに設定してほしい内容を書いておきます。
ここで定義したものはプログラム中で「$this− >config− >(name 属性の名前)」で取得できます。
(「本体
(block sample.php)」参照)
<?php $usehtmleditor = can_use_html_editor(); ?>
<table cellpadding="9" cellspacing="0">
<!--ブロック名-->
<tr valign="top">
<td align="right"><?php print_string(’configtitle’, ’block_sample’); ?>:</td>
<td><input type="text" name="title" size="30" value="<?php echo isset($this->config->title)?
p($this->config->title):’’; ?>" /></td>
</tr>
<!--ボタンの名前->
<tr>
<td align="right"><?php print_string(’configlinkname’, ’block_sample’); ?>:</td>
<td><input type="text" name="bname" size="30" value="
<?php echo isset($this->config->bname)?p($this->config->bname):’’; ?>" /></td>
</tr>
<!--適用 -->
<tr>
6
<td colspan="3" align="center">
<input type="submit" value="<?php print_string(’savechanges’) ?>" /></td>
</tr>
</table>
<?php if ($usehtmleditor) {use_html_editor(); }?>
3.2.4
本体 (block sample.php)
ブロックはクラスで定義します、ここでクラス名を「block ブロック名」にすることと「block base」を継
承することを忘れないようにしましょう。
<?php //$Id: block_sample.php
class block_sample extends block_base {
function init() {//初期化
$this->title = get_string(’blockname’, ’block_sample’);
$this->version = 2007081700;
}
function applicable_formats() {
return array(’all’ => true);
}
function specialization() {
$this->title = isset($this->config->title) ? $this->config->title :
get_string(’sampleblock’, ’block_sample’);
}
function instance_allow_multiple() {
return true;
}
function get_content() {//表示部分
global $CFG;
//echo "<center>CFG</center> <hr><pre>";var_dump($CFG);echo "</pre><hr>";
$id = optional_param(’id’, PARAM_INT);
// course id URL からパラメータを取得
//もし URL が [http://localhost:8888/moodle/course/view.php?id=2] なら
//$id には2が代入される
if ($this->content !== NULL) {
return $this->content;
}
$filteropt = new stdClass;
$filteropt->noclean = true;
$this->content = new stdClass;//インスタンス化
//これで連想配列$this->content に代入したものを表示することができるようになる
//$this->content->text に代入したものは HTML のソースに反映される。(下記参照)
$this->content->text .= ’<form action="’.$CFG->wwwroot.’/blocks/sample/sample.php">’;
$this->content->text .= ’<input type="hidden" name="id" value="’.$id.’">’;
//bottom 「表示」ボタンの出力
$this->content->text .= ’<dev><center>’;
$buttomname = isset($this->config->bname) ? $this->config->bname : get_string(’defaultbname’, ’block_sample’);
$this->content->text .= ’<br> <input type="submit" value="’ .$buttomname. ’" />’;
$this->content->text .= ’</center></dev>’;
$this->content->text .= ’</form>’;
7
$this->content->footer = ’ ’;
unset($filteropt); // memory footprint
return $this->content;//これを返すと定義したコンテンツが表示される。
}
}
?>
上記のソースコードで以下のような HTML ソースが生成され
<span class="accesshide">サンプルブロック をスキップ</span>
</a><div class="title"><div class="hide-show">
<a title="ブロックの表示または非表示" href="#" onclick="elementToggleHide(this, true, function(el)
{return findParentNode(el, ’DIV’, ’sideblock’); }, ’http://localhost:8888/moodle/pix’ ); return false;">
<img src="http://localhost:8888/moodle/pix/spacer.gif" id = "togglehide_inst40" alt="ブロックの表示または非表示"
class="hide-show-image" /></a></div><h2>サンプルブロック</h2>
</div></div><div class="content">
<form action="http://localhost:8888/moodle/blocks/sample/sample.php"><input type="hidden"
name="id" value="2"><dev><center><br> <input type="submit" value="表示" /></center></dev>
</form><div class="footer">
</div></div></div><script type="text/javascript">
//<![CDATA[
elementCookieHide("inst40");
//]]>
下図のように表示されます
図 1: ブロック画面
あとは処理部分(dataroot/blocks/sample/sample.php)を実装すれば完成ですが、ここでは省略します。
4
filter
フィルタはブロックやモジュールと違って設定画面以外インタフェースは必要ありません、本体には関数を
定義してあります。
4.1
ファイル構成
dataroot/filter/作成するフィルタ名/defaultsettings.php #デフォルトの設定を定義
dataroot/filter/作成するフィルタ名/filter.php #本体
dataroot/filter/作成するフィルタ名/filterconfig.html #設定画面の定義
dataroot/lang/文字コード名/作成するフィルタ名.php #プログラム中で使う日本語を定義
4.2
例:イメージファイルフィルタ(imagesize)
例として画像ファイルを引数として渡すとアスペクト比(縦横比)をそのままにあらかじめ設定しておいた
最大サイズ以下で表示するための大きさを返すフィルタをあげます。
8
imagesize_filter((string) 画像ファイル,(int) 最大幅,(int) 最大高さ)
返り値の例: width="500" height="250"
4.2.1
イメージファイルフィルタのファイル構成
設置した際のファイル構成は以下のようになります。
dataroot/
+-- filter/
|
+-- imagesize/
|
+-- defaultsettings.php
|
+-- filter.php
|
+-- filterconfig.html
|
+-- sample600x450.jpg
+-- lang/
|
+-- ja_utf8/
|
+-- imagesize.php
4.2.2
デフォルトの値の定義 (defaultsettings.php)
このファイルではフィルタのデフォルト値を定義します、ここでは関数名を「フィルタ名 defaultsettings」
にしなければならないことに注意しましょう。
<?php
// defaultsettings.php
// deafault settings are done here, saves doing all this twice in
// both the rendering routine and the config screen
function imagesize_defaultsettings( $force=false
) {
global $CFG;
if (!isset($CFG->filter_imagesize_maxwidthsize) or $force) {
set_config( ’filter_imagesize_maxwidthsize’, "800");
}
if (!isset($CFG->filter_imagesize_maxhightsize) or $force) {
set_config( ’filter_imagesize_maxhightsize’, ’600’ );
}
}
?>
4.2.3
設定画面の定義 (filterconfig.html)
管理画面の [モジュール] → [フィルタ] → [設定] で表示される設定画面の定義です。
<h4>sample image (600x450) </h4>
<center>
<!-- imagesize_filter 使用例 -->
<?php
//echo ’<center>CFG</center><hr><pre>’;var_dump($CFG);echo ’</pre><hr>’;
require_once("$CFG->dirroot/filter/imagesize/filter.php");
$imagefile=$CFG->wwwroot.’/filter/imagesize/sample600x450.jpg’;
$imgsize = imagesize_filter($imagefile);
printf("<img src=\"%s\" %s /><br>",$imagefile,$imgsize);
printf("result %s <br>",$imgsize);
?>
</center>
9
<!-- 設定 -->
<table cellpadding="9" cellspacing="0">
<tr valign="top">
<th align="right" scope="col">Imgage size setting</th>
<th>&nbsp;</th>
</tr>
<tr valign="top">
<td align="right">max width : </td>
<td><input type="text" name="filter_imagesize_maxwidthsize"
value="<?php p($CFG->filter_imagesize_maxwidthsize) ?> " /> [pixel]</td>
</tr>
<tr valign="top">
<td align="right">max hight : </td>
<td><input type="text" name="filter_imagesize_maxhightsize"
value="<?php p($CFG->filter_imagesize_maxhightsize) ?>" /> [pixel]</td>
</tr>
</table>
この例ではフィルタの使用した際の表示例(画像部分)もつけています、表示されている画像の元のサイズ
は 600x450 ですが、フィルタを通して 510x382.5 のサイズで表示していることがわかります。
図 2: 設定画面の表示例
10
4.2.4
本体 (filter.php)
これが本体のソースコードです、ここでは関数名を「フィルタ名 filter」にしなければならないことに注意
しましょう、あとは通常の PHP 関数と同じように関数を定義します。
<?php
/**
* @author yusuke kinjyou
* @param (string)$imagefile image file path
* @optional param (int)$maxwidthsize max width size [pixel]
* @optional param (int)$maxhightsize max hight size [pixel]
* @return (string) " width="xxx" height="xxx" "
* usage : imagesize_filter($imagefile[,$maxwidthsize[,$maxhightsize]]);
*/
function imagesize_filter($imagefile=’’,$maxwidthsize=0,$maxhightsize=0) {
$imgstring = ’’;
if($imageinfo = getimagesize($imagefile)){
//if($imagefile != ’’){
//$imgstring .= ’ src="’.$imagefile.’" ’;
global $CFG;
//echo ’<center>CFG</center><hr><pre>’;var_dump($CFG);echo ’</pre><hr>’;
if($maxwidthsize == 0){
$maxwidthsize = $CFG->filter_imagesize_maxwidthsize;
}
if($maxhightsize == 0){
$maxhightsize = $CFG->filter_imagesize_maxhightsize;
}
//printf("%s , max hight = %d , max width = %d",$imagefile,$maxhightsize,$maxwidthsize);
//echo ’<center>imageinfo</center><hr><pre>’;var_dump($imageinfo);echo ’</pre><hr>’;
$setpercenttage = array(100,95,90,85,80,75,70,75,70,65,60,55,50,45,40,35,30,25,20,15,10,5,4,3,2,1);
$maxcount = count($setpercenttage);
//echo ’max count = ’.$maxcount.’<br>’;
//echo ’<center>setpercenttage</center><hr><pre>’;var_dump($setpercenttage);echo ’</pre><hr>’;
$count = 0;
while($imageinfo[0]*$setpercenttage[$count]*0.01 > $maxwidthsize){
//printf("image width is bigger<br>");printf("now %d %%<br>",$setpercenttage[$count]);
if ($count+1 >= $maxcount){
break;
}
$count++;
}
while($imageinfo[1]*$setpercenttage[$count]*0.01 > $maxhightsize){
//printf("image hight is bigger<br>");printf("now %d %%<br>",$setpercenttage[$count]);
if ($count+1 >= $maxcount){
break;
}
$count++;
}
$imgstring .= ’ width="’.$imageinfo[0]*$setpercenttage[$count]*0.01
.’" height="’.$imageinfo[1]*$setpercenttage[$count]*0.01.’" ’;
//echo ’return : ’.$imgstring;
}
return $imgstring;
11
}
?>
4.2.5
言語ファイル (imagesize.php)
言語ファイルではプログラム中で使う文字を定義しておきます、今回は言語ファイルが lang/ja utf8/imagesize.php
なので文字コードは utf8 で保存してください、ここではフィルタ名だけ定義しています。
<?php
$string[’filtername’] = ’Image size’;
?>
5
module
モジュールは moodle 内では「活動」と表示されます、ブロックやフィルタと違って cron による定時実行
が行えます。(cron 実行専用の不可視のモジュールもあります。)
module は lib.php 内に必ず定義しなければならない関数が指定されています、注意しましょう。
5.1
ファイル構成
dataroot/mod/作成するモジュール名/db/mysql.php #アップグレード時の設定
dataroot/mod/作成するモジュール名/db/mysql.sql #データベースの作成
dataroot/mod/作成するモジュール名/icon.gif #「活動」ブロックで使われるアイコン、サイズは 16x16
dataroot/mod/作成するモジュール名/index.php #コース内のインスタンスを表示する画面
dataroot/mod/作成するモジュール名/lib.php #ライブラリ
dataroot/mod/作成するモジュール名/mod.html #設定画面
dataroot/mod/作成するモジュール名/version.php #バージョンなど
dataroot/mod/作成するモジュール名/view.php #選択したインスタンスを表示する画面
dataroot/lang/文字コード名/作成するモジュール名.php #プログラム中で使う日本語を定義
オプション
dataroot/mod/作成するモジュール名/config.html #サイト全体での設定をする画面
5.2
例:sample
moodle の公式サイト http://download.moodle.org/plugins16/mod/NEWMODULE.zip からダウンロード
したサンプルモジュールに以下の修正を加えたものです。
• 「//$NEWMODULE CONSTANT = 7; /// for example」の行をコメントアウト
• すべてのファイルの「NEWMODULE」という文字列を「sample」に置き換える。
• lang ファイル(sample.php)を作成
• mysql.sql を書き換え
• コメント文の修正/削除(動作には影響なし)
12
5.2.1
ファイル構成
dataroot/mod/sample/db/mysql.php #アップグレード時の設定
dataroot/mod/sample/db/mysql.sql #データベースの作成
dataroot/mod/sample/icon.gif #「活動」ブロックで使われるアイコン、サイズは 16x16
dataroot/mod/sample/index.php #コース内のインスタンスを表示する画面
dataroot/mod/sample/lib.php #ライブラリ
dataroot/mod/sample/mod.html #設定画面
dataroot/mod/sample/version.php #バージョンなど
dataroot/mod/sample/view.php #選択したインスタンスを表示する画面
dataroot/lang/ja_utf8/sample.php #プログラム中で使う日本語を定義
5.2.2
データベースの作成(mysql.sql)
同梱されていた README.txt には option と書かれていたのに必要だったファイル、そういう大切なこと
は正確に書いてほしかったです……
CREATE TABLE prefix_sample
id
int(10) NOT NULL
course int(10) NOT NULL
timemodified int(10) NOT
name
varchar(255) NOT
(
auto_increment,
default ’0’,
NULL default ’0’,
NULL default ’’,
PRIMARY KEY (id),
KEY course (course)
) TYPE=MyISAM COMMENT=’sample Module’;
sample モジュールのインスタンス情報を格納するためのデータベースを作成します、ためしに一つインス
タンスを作成したあとは下のようになりました。
5.2.3
id
course
timemodified
name
1
2
1189238566
さんぷるもじゅ∼る
ライブラリ(lib.php)
<?php
/**
*インスタンス作成時に呼び出される
*データベースにインスタンスの情報を追加
*
* @param object $instance An object from the form in mod.html
* @return int The id of the newly inserted sample record
**/
function sample_add_instance($sample) {
$sample->timemodified = time();
return insert_record("sample", $sample);
}
/**
* インスタンスの更新時に呼び出される
*データベースのインスタンスの情報を更新
*
* @param object $instance An object from the form in mod.html
* @return boolean Success/Fail
**/
function sample_update_instance($sample) {
$sample->timemodified = time();
$sample->id = $sample->instance;
13
return update_record("sample", $sample);
}
/**
* インスタンス削除時に呼び出される
*データベースからインスタンスの情報を削除
*
* @param int $id Id of the module instance
* @return boolean Success/Failure
**/
function sample_delete_instance($id) {
if (! $sample = get_record("sample", "id", "$id")) {
return false;
}
$result = true;
if (! delete_records("sample", "id", "$sample->id")) {
$result = false;
}
return $result;
}
/**
* ユーザが何をしたかの概要を返す。
* $return->time = いつやったか
* $return->info = 何をしたか
*(今回はなにもできないのでなにも返さない)
*
* @return null
* @todo Finish documenting this function
**/
function sample_user_outline($course, $user, $mod, $sample) {
return $return;
}
/**
* ユーザが何をしたかの詳細を記述
*(今回はなにもできないのでなにもしない)
*
* @return boolean
* @todo Finish documenting this function
**/
function sample_user_complete($course, $user, $mod, $sample) {
return true;
}
/**
* 過去の活動を返す
*
* @uses $CFG
* @return boolean
* @todo Finish documenting this function
**/
function sample_print_recent_activity($course, $isteacher, $timestart) {
global $CFG;
return false;
//
True if anything was printed, otherwise false
}
/**
* cron で定時実行する内容を書く
*
* @uses $CFG
14
* @return boolean
* @todo Finish documenting this function
**/
function sample_cron () {
global $CFG;
return true;
}
/**
* これはインスタンスの成績を「配列で」返します
* 例えば:
*
$return->grades = array of grades;
*
$return->maxgrade = maximum allowed grade;
*
* @param int $sampleid ID of an instance of this module
* @return mixed Null or object with an array of grades and with the maximum grade
**/
function sample_grades($sampleid) {
return NULL;
}
/**
*インスタンスのユーザに関するすべての情報を配列で返します。
* ロールごとの情報も含めてください
*(例えばユーザ yusuke の students としての情報と teacher としての情報)
*詳細は他のモジュールを参考にしてください。
*
* @param int $sampleid ID of an instance of this module
* @return mixed boolean/array of students
**/
function sample_get_participants($sampleid) {
return false;
}
/**
*この関数は評価尺度をかえします
* 必ず必要なコメントをかいてください
* forum, glossary, journal モジュールを参考にしてください
*
* @param int $sampleid ID of an instance of this module
* @return mixed
* @todo Finish documenting this function
**/
function sample_scale_used ($sampleid,$scaleid) {
$return = false;
return $return;
}
?>
5.2.4
バージョンなど(version.php)
バージョン情報と cron の情報を書きます、今は「cron=0;」なので cron は動きません。
<?php
/**
* この情報は moodle_needs_upgrading() と /admin/index.php で使用されます
**/
$module->version
$module->cron
?>
= 2006042900;
= 0;
// モジュールのバージョン (Date: YYYYMMDDXX)
// cron が何秒置きにこのモジュールをチェックするか (secs)
15
5.2.5
アイコン(icon.gif)
アイコンです、下図のような感じで使われます。
5.2.6
言語ファイル(sample.php)
とりあえずモジュール名だけ書いておきます。
<?PHP
$string[’modulename’] = ’ サンプルモジュール’;
$string[’modulenameplural’] = ’ サンプルモジュール’;
?>
5.2.7
アップデート(mysql.php)
<?php
/**
* 古いバージョンからアップデートするときに必要な処理を書きます
*
* @uses $CFG
* @param int $oldversion The prior version number
* @return boolean Success/Failure
**/
function sample_upgrade($oldversion) {
global $CFG;
if ($oldversion < 2006042900) {
# なにかやることを書く
}
return true;
}
?>
5.2.8
コース内のインスタンスを表示(index.php)
各コースに作成されている sample モジュールのインスタンスの一覧を表示します
<?php
require_once("../../config.php");
require_once("lib.php");
$id = required_param(’id’, PARAM_INT);
// course
if (! $course = get_record("course", "id", $id)) {
error("Course ID is incorrect");
}
require_login($course->id);
add_to_log($course->id, "sample", "view all", "index.php?id=$course->id", "");
/// 言語ファイルから使う文字を読み込む
$strsamples = get_string("modulenameplural", "sample");
$strsample = get_string("modulename", "sample");
/// ヘッダを出力
if ($course->category) {
16
$navigation = "<a href=\"../../course/view.php?id=$course->id\">$course->shortname</a> ->";
} else {
$navigation = ’’;
}
print_header("$course->shortname: $strsamples", "$course->fullname",
"$navigation $strsamples", "", "", true, "", navmenu($course));
/// コース内の sample モジュールのインスタンスを取得
if (! $samples = get_all_instances_in_course("sample", $course)) {
notice("There are no samples", "../../course/view.php?id=$course->id");
die;
}
///インスタンスのリストを出力
$timenow = time();
$strname = get_string("name");
$strweek = get_string("week");
$strtopic = get_string("topic");
if ($course->format == "weeks") {
$table->head = array ($strweek, $strname);
$table->align = array ("center", "left");
} else if ($course->format == "topics") {
$table->head = array ($strtopic, $strname);
$table->align = array ("center", "left", "left", "left");
} else {
$table->head = array ($strname);
$table->align = array ("left", "left", "left");
}
foreach ($samples as $sample) {
if (!$sample->visible) {
//Show dimmed if the mod is hidden
$link = "<a class=\"dimmed\" href=\"view.php?id=$sample->
coursemodule\">$sample->name</a>";
} else {
//Show normal if the mod is visible
$link = "<a href=\"view.php?id=$sample->coursemodule\">$sample->name</a>";
}
if ($course->format == "weeks" or $course->format == "topics") {
$table->data[] = array ($sample->section, $link);
} else {
$table->data[] = array ($link);
}
}
echo "<br />";
print_table($table);
/// 終了
print_footer($course);
?>
表示するとこんな感じになります
17
5.2.9
設定画面(mod.html)
新しくモジュールを追加するときや、モジュールを更新するときに表示される設定画面です。
<?php // $Id: mod.html,v 1.5 2006/10/07 12:28:57 gustav_delius Exp $
/**
* This page defines the form to create or edit an instance of this module
* It is used from /course/mod.php. The whole instance is available as $form.
**/
/// First we check that form variables have been initialised
if (!isset($form->name)) {
$form->name = ’’;
}
// More similar blocks go here...
?>
<form name="form" method="post" action="mod.php">
<center>
<table cellpadding="5">
<tr valign="top">
<td align="right"><b><?php print_string("name") ?>:</b></td>
<td>
<input type="text" name="name" size="30" value="<?php p($form->name) ?>" />
</td>
</tr>
<!-- More rows go in here... -->
<!-- The following line for Moodle 1.5 prints the visibility setting form element -->
<?php print_visible_setting($form); ?>
<!-- and if your module uses groups you would also have -->
<?php print_groupmode_setting($form); ?>
</table>
<!-- These hidden variables are always the same -->
<input type="hidden" name=course
value="<?php p($form->course) ?>" />
<input type="hidden" name="sesskey"
value="<?php p($form->sesskey) ?>" />
<input type="hidden" name=coursemodule value="<?php p($form->coursemodule) ?>" />
<input type="hidden" name=section
value="<?php p($form->section) ?>" />
<input type="hidden" name=module
value="<?php p($form->module) ?>" />
<input type="hidden" name=modulename
value="<?php p($form->modulename) ?>" />
<input type="hidden" name=instance
value="<?php p($form->instance) ?>" />
<input type="hidden" name=mode
value="<?php p($form->mode) ?>" />
<input type="submit" value="<?php print_string("savechanges") ?>" />
</center>
</form>
18
5.2.10
一つ一つのインスタンスを表示(view.php)
モジュールのインスタンスを表示するモジュールの本体です、「YOUR CODE GOES HERE」のあたりに
処理を書くことでモジュールの動作を定義します。
<?php
require_once("../../config.php");
require_once("lib.php");
$id = optional_param(’id’, 0, PARAM_INT); // Course Module ID, or
$a = optional_param(’a’, 0, PARAM_INT); // sample ID
if ($id) {
if (! $cm = get_record("course_modules", "id", $id)) {
error("Course Module ID was incorrect");
}
if (! $course = get_record("course", "id", $cm->course)) {
error("Course is misconfigured");
}
if (! $sample = get_record("sample", "id", $cm->instance)) {
error("Course module is incorrect");
}
} else {
if (! $sample = get_record("sample", "id", $a)) {
error("Course module is incorrect");
}
if (! $course = get_record("course", "id", $sample->course)) {
error("Course is misconfigured");
}
if (! $cm = get_coursemodule_from_instance("sample", $sample->id, $course->id)) {
error("Course Module ID was incorrect");
}
}
require_login($course->id);
add_to_log($course->id, "sample", "view", "view.php?id=$cm->id", "$sample->id");
/// ヘッダを表示
if ($course->category) {
$navigation = "<a href=\"../../course/view.php?id=$course->id\">$course->shortname</a> ->";
} else {
$navigation = ’’;
19
}
$strsamples = get_string("modulenameplural", "sample");
$strsample = get_string("modulename", "sample");
print_header("$course->shortname: $sample->name", "$course->fullname",
"$navigation <a href=index.php?id=$course->id>$strsamples</a> -> $sample->name",
"", "", true, update_module_button($cm->id, $course->id, $strsample),
navmenu($course, $cm));
/// やりたい処理を書く
echo "YOUR CODE GOES HERE";
/// 終了
print_footer($course);
?>
このモジュールは「YOUR CODE GOES HERE」と出力するだけです。
右上の「この サンプルモジュール を更新する」をクリックすると設定画面に飛びます。
注意点
6
6.1
バージョン問題
2007/09/07 現在 moodle には 1.6 から 1.9 まで4つのバージョンがあります、そしてもちろんどんどん改良
されているため「1.6 で使えた関数が 1.7 では使えない」といったいわゆるバージョン問題が発生します。
各バージョンの特徴を書いておきます 2
• moodle1.7
– Roles
– XML Database Schema
– New Admin interface
– Unit testing framework
– AJAX Course editing
• moodle1.8
2 参考:http://docs.moodle.org/en/Release
Notes
20
– Accessibility
– Moodle Network
– Web Services API
– Moodle forms library
– Multi Authentication
– Customisable User Profiles
– Groups refactor
– Roles improvements
– Support for ODS export
• moodle1.9
– Gradebook
– Outcomes
– Events API
– Tags
– Improved question bank
– Notes
– New Custom Corners theme
6.1.1
ロールとケーパビリティ
moodle1.7 以降では「ロール」と「ケーバビリティ(アクセス権)」が詳細に設定できるようになりました、
逆に言えば moodle1.6 以前では「ロール」と「ケーバビリティ(アクセス権)」が存在しないということにな
ります。
例えば前述の参考プログラム(encode)に使われていた has capability() 関数はケーバビリティを調査する
ための関数なので moodle1.6 以前では使用できません、よって要求定義書にアクセス権関連の要求(例えば
「教師だけ操作できるようにしてほしい」など)が掲載されている場合はとくに気をつけなければなりません。
6.1.2
データベースの仕様変更
バージョンアップに伴ってデータベースのテーブルが変更されることがあります、get records() 等のデータ
ベースを使う関数がうまく動かなかったりしたらテーブル名やテーブルの内容を確認してみましょう。
プログラム作成側としてはデータベースの仕様変更にも簡単に対応できるように get records sql() などを
使って SQL query で検索するようにしておいたり、参照してるテーブル名やカラム名をコメント文にいれて
おくといいかもしれません。
21
6.1.3
関数の仕様変更
バージョンアップに伴って関数が追加/削除/修正されることがあります、追加や削除くらいならまだしも
引数や返り値が変更されているとなかなか発見するのが難しくなります(例えば moodle1.6 から moodle1.7 で
は「require login(course); 」から「require login(course− >id);」に変更されてたりします)、とくに moodle
は「関数内で別の関数を呼び出し、呼び出された関数でまた別の関数を呼び出す」ようになっているところも
あるので対応するのは大変です。
プログラム作成側としてはせめて自分が定義した分だけでもなにをしているかすぐにわかる関数作りを心が
けましょう、他の人が書いた関数でこのような問題が発生した場合はあきらめて関数の定義を一から読み直し
ましょう。
6.2
6.2.1
セキュリティ
ケイパビリティ
moodle1.7 以降には capability(アクセス権)という考え方があり、細かいアクセス権(閲覧できてもダウ
ンロードできないとか)を設定できるのでサイト管理者はきめ細かなアクセス制御ができます、このケイパビ
リティはプログラム作成時にも大切なものです、たとえば学生が成績を管理しているデータベースを閲覧でき
たらまずいですし教師にサイト管理ができてもまずいわけです。
プログラムでは has capability() 関数を使ってアクセス権のチェックを行い、権限のないユーザは何もでき
ないようにしておきましょう。
6.2.2
ユーザからの入力の処理
あくまで一例ですが、以下のような問題があります
• テキストフィールドで入力されたコマンドをそのまま実行させる
論外です、「実行したいコマンドを入力させる」「SQL のクエリを入力させる」「ファイルのパスを入力
させる」などサーバに直接渡すデータを入力させるのは絶対にしてはいけません、必ず文字列チェック
をしましょう。
絶対にしてはいけない例
ーーー
$cmd = optinal_param(’cmd’,’’,’RAW’);
exec($cmd);
ーーー
$cmd に「rm -rf /*」とか入力されたら……
してはいけない例
ーーー
$str = optinal_param(’cmd’,’’,’RAW’);
echo $str;
ーーー
$str に「<font size="100000000000000">zzzzzzzzzzzzzz</font>」とか入力されたら……
• DOS 攻撃
例えば以下のようなプログラムだと、ユーザの入力によってはループの回数が膨大になり大量の資源を
消費してしまいます、そしてサービスの停止に追い込まれ最悪の場合サーバが故障します。
22
ーーー
$count = optinal_param(’cmd’,’’,’INT’);
while($count > 0){
printf("roop %d",$count);
$count--;
}
ーーー
たとえプルダウンメニューで回数を選択するようなプログラムでも、上のようになっていると URL 欄
で回数を操作できるので非常に危険です。
• バッファオーバーフローの問題
どんな言語でもプログラム内で使う値はいったんメモリに格納されます、なので「x 文字以上は無視す
る」といった処理が大切になります。
C 言語での例(char_name はユーザに入力させた文字、)
ーーー
void overflow(char *char_name){
char name[256];
:
strcpy(name, char_name);
:
}
ーーー
上は C 言語で書いた時の例ですが、このようなことをしてしまうと入力された文字が 256 以上だった場
合メモリ想定外の部分に値が書き込まれてしまうことになります、もし 256 以上に機械語のコードを書
き込まれたりすると情報が盗まれたりサーバを壊されたりする恐れがあります。
メモリの中
ーーー
1 name[1]
2 name[2]
:
:
256 name[256]
257 悪意ある機械語のコード
:
ーーー
他にも様々なセキュリティ問題があります、プログラムを作成する際は「プログラマーが想定していない入
力は無視するようにする」ことが大切です、手間がかかりますけどね。
6.3
動作テスト
動作テストは大切です、依頼主のバージョンだけでなく最低でもその前後のバージョンくらいはテストしま
しょう。
まずはテストデータを用意します、あらゆる動作を検証するのに十分なデータを用意しましょう。
プログラム内部の動きは作りながらたしかめているはずなのでユーザインタフェースから行える動作をすべ
て試してみて想定通りの結果が帰ってくるかを確かめましょう、ユーザがやりそうな思いつく限りの操作をし
てみてエラーが出ないかどうか確かめます。
それが終わったらマニュアルを作成し必ず別の人にもテストしてもらいましょう、プログラム作成者には自
明でもユーザにはわからないことがあります、多かれ少なかれ「これくらいはわかるだろう」という「思い込
み」がある見つかるはずです、必ずプログラムの内容を知らない人にテストしてもらいましょう。
23
テストする側はまずはマニュアルを読まずにテストします、ユーザは基本的にマニュアルは読まないので
なんにも知らなくても操作できるか試してみましょう、そして「マニュアルが一読して意味が分かる内容に
なっているか」と「先ほどの操作はマニュアル(作成者の想定)通りの操作だったか」を確かめます、そして
マニュアルで禁止されている事項を試して「できないはずのことができてしまっていないか」調べます、最後
に思いつく限りのこと(英語を入れるところに日本語入れてみるとか)を試して「きちんと動作するか」もし
くは「きちんとエラーメッセージが出るか」を調べます。
参考文献
[1] moodle
http://moodle.org/course/view.php?id=14
[2] moodle download
http://download.moodle.org/
[3] PHP マニュアル
http://www.php.net/manual/ja/
[4] PHP と Web アプリケーションのセキュリティについてのメモ
http://www.asahi-net.or.jp/~wv7y-kmr/memo/php_security.html
合資会社 e ラーニングサービス 秋山實 印
24