ojt実習報告書...
TRANSCRIPT
OJT実習報告書mooldeのプラグイン作成方法編
実習先:合資会社 eラーニングサービス所属:琉球大学工学部情報工学科
学籍番号:055717A
報告者氏名:金城佑典
2007/09/20
概 要
moodleの「ブロック」「フィルタ」「モジュール」を作成する時の注意点をまとめた文書です
1
目 次
1 moodleについて 3
2 共通事項 3
2.1 プログラム作成前に . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32.2 プログラムの作成 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32.3 プログラムの配布 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
3 block 4
3.1 ファイル構成 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43.2 例:サンプルブロック . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
3.2.1 サンプルブロックのファイル構成 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53.2.2 言語ファイル (block sample.php) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53.2.3 設定画面の定義 (config instance.html) . . . . . . . . . . . . . . . . . . . . . . . . . . 53.2.4 本体 (block sample.php) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
4 filter 7
4.1 ファイル構成 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74.2 例:イメージファイルフィルタ(imagesize) . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
4.2.1 イメージファイルフィルタのファイル構成 . . . . . . . . . . . . . . . . . . . . . . . . 84.2.2 デフォルトの値の定義 (defaultsettings.php) . . . . . . . . . . . . . . . . . . . . . . . 84.2.3 設定画面の定義 (filterconfig.html) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84.2.4 本体 (filter.php) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104.2.5 言語ファイル (imagesize.php) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
5 module 11
5.1 ファイル構成 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 115.2 例:sample . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
5.2.1 ファイル構成 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 125.2.2 データベースの作成(mysql.sql) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 125.2.3 ライブラリ(lib.php) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 125.2.4 バージョンなど(version.php) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 145.2.5 アイコン(icon.gif) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 155.2.6 言語ファイル(sample.php) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 155.2.7 アップデート(mysql.php) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 155.2.8 コース内のインスタンスを表示(index.php) . . . . . . . . . . . . . . . . . . . . . . 155.2.9 設定画面(mod.html) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 175.2.10 一つ一つのインスタンスを表示(view.php) . . . . . . . . . . . . . . . . . . . . . . . 18
6 注意点 19
6.1 バージョン問題 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 196.1.1 ロールとケーパビリティ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 206.1.2 データベースの仕様変更 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
2
6.1.3 関数の仕様変更 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 216.2 セキュリティ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
6.2.1 ケイパビリティ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 216.2.2 ユーザからの入力の処理 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
6.3 動作テスト . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
3
1 moodleについて
http://download.moodle.org/ からダウンロードできるオープンソース(GNU GENERAL PUBLIC LI-CENSE 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> </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 auto_increment,
course int(10) NOT NULL default ’0’,
timemodified int(10) NOT NULL default ’0’,
name varchar(255) NOT NULL default ’’,
PRIMARY KEY (id),
KEY course (course)
) TYPE=MyISAM COMMENT=’sample Module’;
sampleモジュールのインスタンス情報を格納するためのデータベースを作成します、ためしに一つインスタンスを作成したあとは下のようになりました。
id course timemodified name
1 2 1189238566 さんぷるもじゅ~る
5.2.3 ライブラリ(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 = 2006042900; // モジュールのバージョン (Date: YYYYMMDDXX)
$module->cron = 0; // 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