卒業論文 - 科学的教育知

平成 25 年度 卒業研究論文
授業応答システム
効率の良い学習方法について
近畿大学工学部 情報システム工学科
システム開発コース
1010960053 谷本貴明
提出日 平成 26 年 2 月 10 日
目次
1 研究背景と目的................................................................................................................................1
1.1 教育現場の現状........................................................................................................................1
1.2 クリッカーについて....................................................................................................................1
1.3 クリッカーの構成と運用方法.....................................................................................................1
1.4 クリッカーを用いる効果・利点...................................................................................................2
1.5 クリッカーの問題点....................................................................................................................2
1.6 研究目的...................................................................................................................................2
1.7 スマートフォンを対象にする理由..............................................................................................3
2 開発環境...........................................................................................................................................4
2.1 heteml.........................................................................................................................................4
2.2 XAMPP......................................................................................................................................4
2.3 Developer Tools.........................................................................................................................4
3 スマート web クリッカー概要..............................................................................................................5
3.1 仕様書.......................................................................................................................................5
3.2 リフレクション機能......................................................................................................................6
3.2.1 リフレクション環境..............................................................................................................6
3.2.2 認知的葛藤........................................................................................................................6
3.3 アップロードの簡略化...............................................................................................................6
3.4 画像表示機能...........................................................................................................................7
3.5 画像拡大機能...........................................................................................................................7
4 システム構成.....................................................................................................................................7
5 スマート web クリッカーの運用方法..................................................................................................8
6 画面設計と機能................................................................................................................................9
6.1 クリッカー画面............................................................................................................................9
6.2 出題画面.................................................................................................................................10
6.3 クリッカー画面(集計結果)......................................................................................................11
6.4 過去問ダウンロード画面.........................................................................................................12
6.5 問題作成方法.........................................................................................................................12
6.5.1 内容識別子「T」...............................................................................................................14
6.5.2 内容識別子「Q」...............................................................................................................14
6.5.3 内容識別子「C」...............................................................................................................14
6.5.4 内容識別子「CA」............................................................................................................14
7 動作環境.........................................................................................................................................15
7.1 ブラウザ[8]...............................................................................................................................15
7.2 Web サーバー..........................................................................................................................15
8 技術的要素.....................................................................................................................................15
8.1 PHP..........................................................................................................................................15
8.1.1 実施問題のダウンロード機能..........................................................................................15
8.1.2 ファイルの自動保存.........................................................................................................16
8.1.3 過去問題のダウンロード..................................................................................................17
8.1.4 アップロードファイルの自動振り分け機能......................................................................17
8.1.5 画像表示機能..................................................................................................................18
8.1.6 IP アドレスの重複保存について.....................................................................................18
8.1.7 セッションキーの設定......................................................................................................18
8.2 JavaScript.................................................................................................................................19
8.2.1 jQuery...............................................................................................................................19
8.2.2 jQuery による非同期通信................................................................................................19
8.2.3 回答データ送信機能.......................................................................................................20
8.2.4 アップロードの簡略化......................................................................................................21
8.2.5 1 度だけ回答可能なボタン..............................................................................................21
9 まとめ...............................................................................................................................................22
9.1 更新することで再回答が可能となる問題...............................................................................22
9.2 セキュリティの低さ...................................................................................................................22
10 謝辞...............................................................................................................................................22
11 参考文献.......................................................................................................................................22
12 付録...............................................................................................................................................23
1 研究背景と目的
1.1 教育現場の現状
日本において,少子化の影響などにより,大学全入に近い状態が実現されようとしている.競
争意識の低下や,高校における受験への効率的な対応法により,同一大学であってもその学生の
学力の多様化が進んできている.このような多様化に応するには,少人数教育が有効である.実
際に様々な大学が少人数教育を打ち出す傾向がみられる.これは,学生の保護者が,学生が手厚
い教育を受けているかどうかの目安としているのも原因であると言える.しかし,この様な少人
数教育は,教員間のチーム的取り組みがなければ教員間で教える内容や教え方などの格差を生じ
させる.その結果,少人数教育では教育に必要な平等性の確保が困難となる傾向がある.また,
能力別学習は大学においては必ずしもうまく機能しない側面がある.それは,多くの学生が知的
好奇心でのみ授業を受講するわけではなく,できるだけ最小の努力でよい成績をとるという最適
化作業を行う傾向が強いからである.したがって,難易度別クラスでは,できるだけ易しい授業
に集中する傾向が見られるのである.[3]
それでは,大人数の授業ではどうであろうか.大人数の授業においては,平等性の確保が容易
な反面,多様な学力に対する対応が問題となる.特に,大規模授業では,授業についていけない,
無気力な学生の割合が増加する傾向にある.どのレベルにターゲットを絞ればよいのか,同じ学
年の同じ授業においても年度ごとに平均レベルが異なることもあり,対応が困難になる.このよ
うに,平等性の確保はどの大学にとっても難しい課題である.
OECD(先進主要国)各国の大学進学率と大学退学率から教育の現状を考察する.なお,こ
こで退学率とは,最初に得られる教育資格を得ずに退学した者の比率である.図 1.1.1 と図
1.1.2 は 2012 年における OECD 各国の大学進学率比較と 2005 年における OECD 各国の大学退
学率比較である.日本は進学率 51%,退学率 10%であり,これは大学に入学するのは難しいが
卒業するのは簡単であることを表している.一方でアメリカは進学率 74%,退学率 53%とどち
らも高い数字を示している.これは大学に入学するのは簡単であるが,卒業するのは難しいこと
を表している.卒業が難しいということはそれだけ真剣に勉学に取り組む必要がある.退学率の
低い日本では勉学への意識が低いと考えられる.しかし,中には意識の高い学生も存在するため,
大学は学生全体の勉強に対する意識を把握する必要がある.それを把握することが前述した平等
性の確保につながると考えられる.
図 1.1.1OECD 各国の大学進学率(2012 年)
1
図 1.1.2OECD 各国の大学退学率(2005 年)
1.2 授業応答システムとクリッカー
授業応答システムとは講義で利用されるときに呼ばれる聴衆応答システム(ARS:オーディ
オレスポンスシステム)の呼称である.授業応答システムは,学習者や聴衆に対する質問の回
答をリアルタイムで集計し,表示するシステムである.また,講義者と学習者の双方向コミュ
ニケーションを可能にするコミュニケーションツールである.クリッカーとは,授業応答シス
テムに利用される回答端末であり,会議や説明会,クイズ番組などで利用されている.クリッ
カーという名称は,聴衆が回答に使用するリモコンのことであり,クリックするものであるこ
とから”クリッカー”と呼ばれることに由来する.米国の大学において導入が進んでいる.近
年では日本の大学でも導入され始めている.
1.3 クリッカーの構成と運用方法
一般的なクリッカーの構成と運用方法を解説する.クリッカーは以下のような装置及びソフ
トウェアで構成される.
・回答送信リモコン
・パソコンに接続する回答受信機
・設問作成,集計結果などを表示させるアプリケーション
・プロジェクター
・パソコン
2
1.4 クリッカーを用いる効果・利点
・匿名性
クリッカーは,挙手や発表などと違い他者に自分の考えを知られることはない.なので,周
りの生徒につられて挙手を行ったり,羞恥心から回答に参加しないといった行動を防止するこ
とが期待できる.
・学生理解度等の把握が容易になる
クリッカーの回答集計はリアルタイムで行われているため,アンケートなどのように集計に
時間をとられることがない.また,挙手で数を数えるのとは違い,瞬時に回答数を知ることが
でき,学生の授業に対する理解度の把握が容易になる.
・短期的記憶の問題の改善
人間の記憶のうち,短期的に保持される記憶のこと.持続時間は数十秒から数ヶ月程度とさ
れ,時間の経過や新たな情報のインプットとともに失われる.しかし,繰り返し呼び起こされ
た記憶は長期記憶に受け渡され,一層の記憶が可能となる.つまり,クリッカーによって重要
な部分の記憶を意図的に呼び起こさせることで,記憶力の向上が期待できる.
・集中力の欠如の防止
クリッカーを授業の要所ごとに使用することで,学生の長期的集中力の欠如の防止につな
がることが期待できる.通常,人間の集中力の持続時間は,10 分から 15 分である.そのた
め,講義においては集中力が欠落した状態が不可避である.集中が切れると,その後の流れ
が理解できなくなってしまう.
・学生の出席率増加
クリッカーはリモコン 1 つ 1 つを識別することが可能であるから,学生の投票を成績に反映
することなどを周知しておくと,学生の出席率増加に期待できる.
・認知的葛藤の促進
授業でレポートを提出するのとは違い,回答結果が表示されることで,自他の考え方によ
る違いを認識させ,認知的葛藤を意図的に起こす.認知的葛藤については後ほど詳しく解説
する.
1.5 クリッカーの問題点
クリッカーの導入には大きな問題がある.それは,導入コストである.30 人のクラスで使用
するためのシステム一式でも約 30 万円かかってしまう.また,リモコンは授業の度に生徒に配
布する形式をとると,どうしても破損や紛失といった事態が発生してしまい,高額な損失と
なってしまう.こういった導入コストの高さや,その後の管理の難しさから日本ではあまり普
及していない.
1.6 研究目的
クリッカーは,1.4 で述べたように多くの利点を持っており,日本の教育の場においても非常
に有用である.しかし,導入コストの高さや,管理の難しさから,日本では殆ど導入されてい
ないのが現状である.そこで,低コストかつ導入も容易というコンセプトから考案されたのが
「web クリッカー」である.web クリッカーは,リモコン,受信機,集計結果表示機能をそれ
ぞれ web アプリケーション化し,スマートフォンをリモコン代わりに使うことでコストを抑え
ると同時に,管理も容易にしている.本研究では,この web クリッカーにドラッグ&ドロップ
機能や,学生に認知的葛藤を促すリフレクション機能など新しい機能を追加した「スマート
3
web クリッカー」を開発することを目的とする.
1.7 スマートフォンを対象にする理由
下図は一昨年,2012 年におけるスマートフォンの
年代別の使用率である.2012 年のスマートフォン普
及率は約 23%,2013 年のスマートフォン普及率は約
37%であるが,年代別に考察してみると 20 代の普及
率は 63.8%であり,2011 年から 2012 年の間に
22.7%増加し,今後も増加の一途をたどると考えら
れる.このことから,大学生の大半はスマートフォン
を所持していると考えた.また,最近のスマートフォ
ンは web 閲覧はさることながら,小型の PC といっ
ても過言でないほど高性能になっており,web の動
作による制限が少なく開発に適している.以上のこと
から,学生個人のスマートフォンを web クリッカー
の開発端末に選択しても問題ないと判断した.
右図:時事ドットコムより引用
2 開発環境
2.1 heteml
PHP5.4 まで利用可能な有料レンタル web サーバである.本研究では,スマート web クリッ
カーをサーバに保存し,web サーバ上での動作確認に用いた.
2.2 XAMPP
Apache Friend が提供している,web サーバとデータベース管理ソフト,スクリプト言語環
境などを 1 つにまとめたパッケージソフト.本研究では web クリッカーの動作確認に用いた.
名前の由来は以下の通り.
・X : 対応 OS が複数存在することより,クロスプラットフォーム
・A : Apache の A
・M : MySQL の M
・P : PHP の P
・P : Perl の P
2.3 Developer Tools
Google Chrome に標準搭載されいるデベロッパーツール,及び Mozilla Firefox の拡張機能で
ある Firebug を用いて,web でデザイニングの補助や JavaScript の動作確認を行った.
4
3 スマート web クリッカー概要
3.1 仕様書
テーマ名称
スマートWebクリッカー
差異化ポイント
1. リフレクション機能
認知的葛藤の提供
2. 出席確認機能
出席確認に掛かる時間の短縮
3. 画像表示機能
様々な問題に対応
メリット
1. 出席確認の時間を短縮することにより、授業進度の向上
2. 中間、期末試験の参考になる
3. 過去の問題文、回答を参照することで、生徒にリフレクションを促す
4. 画像を表示できることで、問題の幅が広がる
開発方針
1. 教師、生徒の双方の理解を深める
2. 授業外でも利用可能
3. あくまでも、コミュニケーションツールの1つ
ターゲット
大学教授とそこに通う生徒
イメージ
授業進行
理解度確認
+
ディスカッション
出席確認
解説
5
機能
1. 問題作成ツール
excelを使用してcsvファイルとして出力する。そのファイルをサーバにアップロード
2. 集計、結果表示機能
Androidで回答、集計結果をWebで表示
3. 出席確認システム
htmlなど、メール先のURLにアクセスすると出席認証
4. 回答履歴確認システム
⇒学生が回答した全体の答えと個人の答えを保存。リフレクションを促す機能
開発目標
1. Androidを使用した出席確認機能
URLを利用した確認方法、セキュリティ対策が必要
2. 問題作成ツールの機能性向上
画像を入れた問題作成をできるようにする
3. Android,webの両方で履歴の閲覧が可能
PCだけでなく携帯端末でも閲覧できるように配慮する
4. 認知的葛藤モデルを使用するのに適した設計
認知的葛藤モデルという授業モデルに使用するのに適したアプリケーションにする
3.2 リフレクション機能
リフレクションとは日本語で「内省」を表す.学習において最も効果のある過程のことであ
り,自分の問題解決過程を振り返る内省のことである.この内省を喚起することがこの機能の
目的である.しかし,学習者の誰もが内省を行うことが容易ではなく,内省を行うための動機
付けであったり,内省を行うためのメディアなどを使用したりと,リフレクション環境を構築
する必要がある.
3.2.1 リフレクション環境
リフレクション環境とは,リフレクションが行われるような環境のことである.リフレ
クション環境を作るうえで最も有効な方法の 1 つが認知的葛藤を起こさせることである.
3.2.2 認知的葛藤
認知的葛藤とは,学習者が自分の予想・期待に反する結果や対立する考えを認識し,そ
の差を解消すべきものと考えたときに生じるものである.この認知的葛藤を解消すること
を動機として学習が行われることになる.例として米国の学校では,教師が 1 つの問題・
課題を提示し,生徒同士にディスカッションをさせることで認知的葛藤を起こさせている.
3.3 アップロードの簡略化
アップロードを行う場合,通常はアップロードしたいファイルの場所を指定し,決定ボタンを
押すことでアップロードが開始される.ファイルの場所を覚えていないと探すのに時間をとられ
たり,誤って違うファイルをアップロードする可能性があり効率が悪い.そこで今回は,アップ
ロードする際の操作を簡単なものとし,ユーザへの負担を極力無くし,ミスの無いアップロード
6
を行えるようにする機能の実装を目的とする.具体的な使用方法として,ユーザはアップロード
したいファイルをアップロード用の枠中にドラッグ&ドロップするだけでアップロードが行われ
る.
3.4 画像表示機能
画像を表示できるようにすることで画像提示型の問題にも対応でき,問題のバリエーション増
加に期待できる.
3.5 画像拡大機能
出題画面で表示される画像をクリックすることで画像を全画面表示に変更することが出来る.
大教室等で画像が見えにくい,もしくは問題文が必要ない問題を使用する場合に利用する.
4 システム構成
スマート web クリッカーのファイル構成は以下の通りである.
ファイル名
説明
index.php5
クリッカー画面を生成する.
duestion.php5
出題画面を生成する.
addAnwer.php5
学生から送信された回答を保存する.回答は answer.csv に書き込まれ
る.
download.php5
「集計結果を DL」ボタンが押されたときに実行する.question.csv と
answer.csv を読み込んで,ダウンロード用のファイルを生成する.
upload.php
問題または画像のアップロードを行う.dropzone.js から送信される
データを拡張子ごとに分け保存する.
subwindow.php
「過去問を DL」ボタンが押された時に実行する.サブウィンドウを表
示し,用意されたフォームに月日を入力することで該当する過去問を
検索する.
csvDL.php5
過去問題をダウンロードする.subwindow.php から送信された value
から目的のファイル名を取得し,ダウンロードする.実行の流れは
download.php5 と同じである.
query-1.9.0.min.js
jQuery のライブラリである.
csvToArray.js
読み込んだ csv 形式のファイルを配列に変換し,格納する JavaScript
のライブリである.
dropzone.js
ドラッグ&ドロップを行う領域を設定している.ドロップした時に,
データを指定された URL にアップロードすることが簡単に出来る
jQuery のプラグインである.
7
ファイル名
説明
function_store.js
JavaScript を使用した関数を 1 つのファイルにまとめたものである.
answer.csv
学生から送信された回答データが書き込まれるファイル.回答データ
は addAnswer.php5 によって書き込まれる.
default.csv
問題を記述したファイルであり,出題画面に表示されるファイルであ
る.
question.csv
集計結果をダウンロードする際に読み込まれるファイル.
session.txt
出題問題に対する回答データが有効かどうかを認証するのに使うキー
を記したテキストである.
5 スマート web クリッカーの運用方法
web サーバに置かれたスマート web クリッカーに,教員は出題画面に,学生はクリッカー画面に
それぞれアクセスする.教員は出題画面下部にあるアップロード領域に問題または問題画像をド
ラッグ&ドロップし,それによりアップロードされた問題に学生は回答を行う.回答数は自動的に
更新され,頃合いをみて教員は出題画面の回答結果表示を実行する.回答結果によって教員は適宜,
解説を行う.再度同じ問題を使用したい場合は,もう1度アップロードからやり直す必要がある.
また,次の問題を表示する場合も同様にアップロードを行う.使用した問題と回答結果は,出題画
面下部の「結果を DL」から csv ファイルでダウンロードすることが可能である.また,過去の問
題と回答結果を調べたい場合にはその隣の「過去問を DL」からダウンロードか可能である.
8
6 画面設計と機能
6.1 クリッカー画面
学生が操作する画面である.選択肢の文章は,問題がアップロードされるたびに変わる.学
生は出題画面に表示される問題文を読み,答えとして相応しい番号をクリックする.クリック
は1度しかできない.クリックされた番号はサーバに送信される.出題画面とクリッカー画面
の問題が違っていた場合は,送信エラーとなりユーザに問題が違うことを知らせる.
図 6.1.1 クリッカー画面(通常時)
回答を行うと回答データが,jQuery によって送信される.送信が正常に終了すると,その旨
を伝えるアラートが表示される.回答後は,回答したボタンの色が薄くなり,それ以上回答が
行えないようになっている.
左図:回答送信を知らせるアラート 右図:クリッカー画面(回答後)
9
6.2 出題画面
教員がスクリーンなどで学生に表示する画面である.画面左下の「アップロード領域表示」を
押すことで表示される枠内に,アップロードするファイルをドロップすることでアップロードを
行うことが出来る.画面下中央にある「集計結果」を押すと,回答の集計状況が表示される.
「正解」を押すと,正解の選択肢の文字が赤色で表示される.画面右下の各種ダウンロードボタ
ンを押すことで,それぞれダウンロードが行われる.過去問のダウンロードはサブウィンドウが
表示される.
図 6.2.1
10
6.3 クリッカー画面(集計結果)
図 6.3.1 と図 6.3.2 は出題画面下部の集計結果の部分である.右端の数字が全体の回答数であ
る.その左側にある数字は選択肢ごとの数字である.この数字は,「集計結果」のボタンを押
すことで表示されるようになる.集計結果が表示されると,選択肢部分の背景色が赤色に変わ
り,選択肢領域を 100%とした棒グラフで表示され,視覚的にも分かりやすくなっている.その
様子が,図 6.3.2 である.
図 6.3.1
図 6.3.2
11
6.4 過去問ダウンロード画面
過去問をダウンロードする画面である.問題を行った年と月を選択し検索を押すと,その年月
に行った問題が表示される.ダウンロードしたい問題をクリックし,「DL」を押すことで,ダ
ウンロードが実行される.
図 6.4.1
図 6.4.2
6.5 問題作成方法
問題ファイルは SJIS-win エンコーディングの CSV ファイルである.問題ファイルの作成は,
Microsoft Excel や LibreOffice Calc といった表計算ソフトを用いるのが適当である.図 6.5.1
と図 6.5.2 はそれぞれ,表計算ソフト(LibreOffice Calc)を使用した問題作成画面と,その問
題を実際にアップロードした出題画面である.
図 6.5.1
12
図 6.5.2
スマート web クリッカーは,各行の先頭にある「内容識別子」により,その行に記された内
容を判断している.以下の表に内容識別子ごとの役割について説明を記す.内容識別子は,
フィールドの A 列に記入することで正常に動作する.違うフィールドに内容識別子を入力した
り,小文字で入力した場合はエラーの原因となるので注意が必要である.図 6.5.3 は内容識別子
をフィールド B に入力した場合(エラー)である.
内容識別子
役割
T
その行はタイトルと判断され,タイトル表示領域へ表示される.
Q
その行は問題文と判断され,問題文表示領域へ表示される.
C
その行は選択肢と判断され,選択肢領域へ表示される.
CA
13
図 6.5.3
基本的に同じ行内であれば,空白のセルを隔てて続きを記入しても問題はない.ただし,セ
ル内で改行を行っている場合,その2行目以降は表示されない.
内容識別子は,同じ内容識別子を何回でも使用でき,またどのような順番で記入しても正し
く表示されるようになっている.ただし,上のセルから順番に処理して表示されるため,各行
の内容の順番には注意が必要である.また,HTML の使用が可能であるが,web クリッカーに
おける CSV ファイルの入出力の仕様上,ダブルクォーテーションを使用することができない点
に留意する必要がある.以下に内容識別子の詳細を記す.
6.5.1 内容識別子「T」
内容識別子「T」が記入された行は,タイトルと判断され,その後の行内容はタイトル
表示領域に表示される.タイトルは他の文字と比べ,若干強調されて表示されるように
なっている.この行はクリッカー画面にも表示される.表示するタイトルが長い場合,タ
イトルの後半が省略され,「・・・」で表示される可能性がある.そのため,タイトルは
なるべく簡潔で短いものが望ましい.
6.5.2 内容識別子「Q」
内容識別子「Q」が記入された行は,問題文として判断され,その後の行内容は問題表
示領域に表示される.意図的な改行を行いたい場合は,複数行に内容識別子を記入し,内
の行を分けることで実現できる.
6.5.3 内容識別子「C」
内容識別子「C」が記入された行は,選択肢として判断される.内容識別子の直後のセ
ルに記入した内容は,選択肢番号表示領域に表示され,それ以降のセルの内容が選択肢表
示領域に表示される.また,この内容識別子を指定した数だけ選択肢が用意される.その
ため,内容識別子「Q」のような改行は行うことは出来ない.またこの行の内容はクリッ
カー画面にも表示される.
6.5.4 内容識別子「CA」
内容識別子「CA」は,内容識別子「C」と同等に扱われる.先頭が「CA」の行は,こ
の選択肢が正答であることを意味する.出題画面において正解を表示するときに使用する.
14
7 動作環境
7.1 ブラウザ[8]
スマート Web クリッカーの各画面は,HTML5 の書式に則って記述している.また CSS3 で
新規に追加されたプロパティである border-radius や linear-gradient,box-shadow を,デザイ
ンや機能を実装するために使用している.このため,HTML5 やそれ以上のプロパティに対応
しているブラウザで閲覧する必要がある.具体的には Google Chrome や
MozillaFirefox,Opera の各最新版を推奨する.また,Android や iOS では,デフォルトのブ
ラウザがレンダリングエンジンとして Webkit を採用している.Webkit では上記のプロパティ
に対応しているため,クリッカー画面の閲覧においては問題ないものと思われる.実際に
Android2.3 及び 4.1 の端末にて動作確認を行ったところ,問題なく表示された.
また本研究では,クリッカー画面はスマートフォンでの閲覧を想定している.従って,フィー
チャーフォンでの閲覧に際しては,一切配慮を施していない.そのため,そういった端末で
Web クリッカーを閲覧した際には,レイアウトが崩れたり,閲覧そのものができない可能性が
ある.
7.2 Web サーバー
スマート web クリッカーは PHP,JavaScript を使用するため,それらに対応した web サーバ
に設置する必要がある.ただし,PHP に関しては,PHP5 から新たに追加された関数を使用し
ているため,PHP5 以上に対応しする Web サーバー上でのみ正常に動作する.
8 技術的要素
8.1 PHP
PHP は”PHP:Hypertext Preprocessor”を意味し,オープンソースの汎用スクリプト言語で
あり,動的に web ページを生成する web サーバの拡張機能の一つである.また,そこで使われ
るスクリプト言語.レイアウトの「雛形」となる HTML ファイル内に,処理内容を記述したス
クリプトを埋め込み,処理結果に応じて動的に文書を生成し,送出することができる.この言語
は,動的に生成される web ページを web 開発者が速やかに作成できるようにすることを主な目
標として作られた.
8.1.1 実施問題のダウンロード機能
出題画面右下にある「集計結果を DL」ボタンを押すことで現在行われている問題に関
するデータのダウンロードが始まる.図 8.1.1.1 は前作の web クリッカーでダウンロード
を実行した結果である.タイトルと回答数,回答率しか表示されない.そのため,どんな
問題を行ったのかわからず,学生にとっては意味の無いデータになっていた.なので今回,
図 8.1.1.2 のように問題文と選択肢の内容,自分が回答した番号を記述するようにした.
ダウンロードを実行して生成されたデータは表計算ソフト「Libre Office Calc」で表示さ
せている.
15
図 8.1.1.1
図 8.1.1.2
このデータは,問題文や選択肢のデータが保存されている question.csv と,学生たちが
回答したデータが保存されている answer.csv の2つをダウンロード用のファイルに作り直
したものである.ダウンロード用ファイルの名前は,question.csv 内のタイトル部分と実
行時のタイムスタンプを組み合わせたものである(図 8.1.1.2 の場合:2013 力学集計結
果_13 年 12 月 24 日 14 時 19 分).学生がこの実施問題をダウンロードする場合,学生が
問題に解答していれば,合計回答数下のセルに自分が回答した番号が表示される.
8.1.2 ファイルの自動保存
前作の web クリッカーでは,実施問題のダウンロード機能によりデータがローカルに保
存できるようになっている.しかし,サーバにデータを保存する機能が実装されていない.
新しい問題がアップロードされると,以前にあった問題は上書きされるため,データをダ
ウンロードし忘れた場合にはデータを確認する方法が無い.なので,実施した問題を保存
する機能が必要である.そこで考案したのが問題をアップロードすると,前回使用した問
題に関するデータを自動で保存する機能である.保存を自動で行うことで,人為的なミス
を抑える.教員が問題のアップロードを行うと,サーバは question.csv と answer.csv を保
存用フォルダ「reflectionbox」にコピーする.その際,それぞれのファイル名を処理実行
時の年月日に(answer.csv は年月日に「-a」を追加で)リネームしている.
16
8.1.3 過去問題のダウンロード
出題画面右下にある「過去問を DL」ボタンを押すことでサブウィンドウを生成する関
数が実行され,ダウンロード用のサブウィンドウ(subwindow.php)が生成される.検索
したいファイルを実施した年と月を選択し,検索ボタンを押す.そうすると,年と月 2 つ
の項目にある value を参考にして,保存用フォルダ「reflectionbox」内で検索を行う.
ファイル名にその文字列を含むファイルを列挙していく.列挙していくファイルは,クラ
スを指定したリストにして表示している.ダウンロードしたいファイルをクリックすると,
クリックされたファイル名が画面下のダウンロード用のテキストエリアに記述される.記
述されたのを確認し,「DL」ボタンを押すと 8.1.1 と同じようにダウンロードが実行され
る.過去問題のダウンロードでは,自分が回答した問題であっても,自分の回答は表示さ
れない.
8.1.4 アップロードファイルの自動振り分け機能
アップロードされたファイルを自動で判別し,振り分ける機能.アップロードするファ
イルは 2 種類がある.1つは,問題文や選択肢などが保存されている csv 形式の問題ファ
イル.そしてもう 1 つは,問題文と共に表示される可能性がある jpg 形式の画像ファイル
である.これら 2 つのファイルは,保存場所や処理が違うためアップロード用のファイル
をそれぞれ設けてやる必要があった.しかしそれでは,ユーザへの負担が増え,ミスを誘
発する可能性があるためファイルをアップロードする段階で自動化してやる必要があった.
そこで考案されたのが,下図のように Dropzone によってアップロードされたファイルを,
upload.php でファイル形式別に処理してやる方法である.Dropzone
upload.php では,まず最初にアップロードしたファイルの拡張子を調べる.拡張子を調
べるにあたっては,正規表現を利用し,csv 形式かどうかで if 文を組んだ.画像ファイル
である場合(false)は,保存用の image フォルダと出題画面に提示される
uploadImage.jpg に保存される.問題ファイルである場合(true)は,画像ファイルの処
理と同じく,保存用の csv フォルダと出題画面に表示される default.csv に保存される.し
かし,default.csv には前回使用した問題が残っているため先にその問題を過去問保存用
フォルダ reflectionbox に保存する.reflectionbox に保存された問題は,過去問題をダウ
ンロードするときに利用する.保存が完了すると前述した保存を実行する.
17
8.1.5 画像表示機能
スマート web クリッカーでは,出題画面において問題文と共に画像を表示する機能があ
る.画像は問題と同様にアップロードすることで自動的に保存,表示される.画像がアッ
プロードされると,uploadImage.jpg に上書きが行われ,出題画面にはこのファイルを画
像として出力する.表示された画像は,出題画面下部の「画像非表示」からいつでも表
示・非表示を切り替えることが出来る.
8.1.6 IP アドレスの重複保存について
プロキシサーバによって管理されている複数のパソコンで web クリッカーを使用した場
合,回答データがうまく集計できない事象が確認された.原因はユーザのパソコンがプロ
キシサーバを経由して web にアクセスしていることにあった.プロキシサーバはパソコン
が web にアクセスするとき,IP アドレスの漏えいを防ぐために,プロキシサーバの IP ア
ドレスを本来の IP アドレスの代わりに使用してアクセスを行う.そのため,プロキシサー
バを経由して web にアクセスしたパソコンの IP アドレスは,全てプロキシサーバの IP ア
ドレスとなる.そのため,IP アドレスが重複している場合は前回の回答データに上書きを
行う web クリッカーでは,回答データが送信される度に上書きが行われ,集計が上手く行
われなかったのである.
この事象からスマート web クリッカーでは,IP アドレスの重複による上書き機能
を廃止し,代わりに回答が行える回数を 1 度に限定した.これにより,プロキシサー
バを経由していても集計が行えるようになった.
8.1.7 セッションキーの設定
スマート web クリッカーでは,問題と選択肢が互いに正しいことを確認するためにセッ
ションキーによる確認を行う.確認には COOKIE を使用する.COOKIE とは web サイト
の提供者が,web ブラウザを通じて訪問者のコンピュータに一時的にデータを書き込んで
保存させる仕組みである.ユーザがスマートフォンでクリッカー画面の読み込み時に
COOKIE を発行し,アップロード時に設定したセッションキーを登録する.そして,ユー
ザが回答を行ったとき回答番号と共にそのデータも送信する.サーバは受け取ったセッ
ションキーと,問題に設定されたセッションキーを比較し一致した場合にのみ,その後の
登録処理を行う.このチェック機能は,問題が更新されたにもかかわらず,クリッカー画
面を更新せずに回答を行った場合などで動作する.なお,セッションキーは問題をアップ
ロードする度に更新される.
セッションキーの作成には PHP の uniqid 関数を使用する.以下に詳細を記述する.
string uniqid([string prefix [, bool more_entropy]])
uniqid()は,マイクロ秒単位の現在時刻に基づき prefix(先頭辞)をつけたユニークな ID を返す.
prefix は PHP5 以降はオプションとなったが,有用である.prefix を空とした場合,13文字の文字
列が返される.more_entropy が TRUE の場合は23文字の文字列が返される.
18
8.2 JavaScript
web 上でインタラクティブな表現をするために開発されたオブジェクト指向のスクリプト言
語である. プログラミング言語の1つである.Java と名前が似ているが,異なるプログラミ
ング言語である.HTML 内にプログラムを埋め込むことで,web ページに様々な機能を付加で
きるため,HTML や CSS では表現できないユーザの動きに対応したものを作ることができる.
従来は印刷物のような静的な表現しかできなかった web ページに,動きや対話性を付加するこ
とを目的に開発され,主要なブラウザのほとんどに搭載されている.
JavaScript の特徴は以下の通りである.
・JavaScript に対応したブラウザソフトがあれば,サーバに負担をかけることなくスクリプト
が実行できる.
・特別な開発環境を要さず,HTML ファイルに書き込むだけで簡単に実行できる.
・スクリプト言語のため,コンパイルを必要としない.
8.2.1 jQuery
ウェブブラウザ用の JavaScript コードをより容易に記述できるようにするために設計さ
れたオープンソースの JavaScript ライブラリである.jQuery は,web ページに効果やア
ニメーション,ユーザインターフェース要素などを短いコードで追加することができる.
また,Ajax による通信も容易に実装できるほか,様々な機能を実現する対応プラグイン
が公開されている.
jQuery では独特の記法を使い,複数の処理を容易に組み合わせられるようになってい
る.jQuery では機能のほとんどは,「$」あるいは「jQuery」という名前のオブジェク
トのメソッドとして定義されている.このオブジェクトのことを jQuery オブジェクトと
いう.jQuery オブジェクトは jQuery の命令をもったオブジェクトである.jQuery のメ
ソッドやプロパティを利用したい場合は,まず jQuery オブジェクトを記述してその後ろ
に,ドット(.)を繋げて記述する必要がある.例えば,IMG 要素のボーダーを青の5ピ
クセルに設定するには次のように記述する.
$(“img”).css(“border”,”5px solid blue”);
セレクタで対象(IMG 要素)を指定し,css というメソッドでボーダーの属性値を設定
している.セレクタには要素名以外にも,id 名や class 名を指定することができる.
$(“要素名”)
$(“#id”)
$(“.class”)
div タグなど要素名を指定する際の書き方
id を指定する際は id 名の前に(#)を付ける
class を指定する際は class 名の前に(.)を付ける
8.2.2 jQuery による非同期通信
データのやり取りが頻繁に行われるスマート web クリッカーでは,多くの場面で非同期
通信が行われている.そのやり取りを可能としているのが jQuery の関数の 1 つである
ajax である.この関数を使用することで非同期通信によるデータのやり取りが可能になる.
非同期通信は,同期通信と違い画面遷移がないため,同期が完了するまで待機する必要が
無く,同期通信と比べてユーザの自由を奪わず,ユーザに与えるストレスが少ない.しか
し,JavaScript が無効な環境では動作しないため,各ブラウザに大きく依存する.
19
8.2.3 回答データ送信機能
クリッカー画面で回答をクリックしたとき,クリックしたという動作に対して,jQuery
が反応してその後の動作を記述したとおりに実行する.回答データの送信は,8.2.2 で説
明したように ajax を使用している.ajax には様々なプロパティが存在するが,今回使用
したプロパティを紹介する.
種別
名前
基本
url
結果取得
説明
リソースの URL を表示する.
( 例: url: “../test/post.php” )
type
HTTP メソッドの種別を”GET”か”POST”で指定する.
( 例: type: “POST” )
data
サーバに送信するフォームデータを指定する.
( 例 1: data: { id:”tanimoto” , pw:”password” }
)
( 例 2: data: “ id=tanimoto & pw=password ” )
timeout
タイムアウト値(ミリ秒)を指定する.
( 例: timeout: 10000 )
success
通信が成功した時に呼ばれるコールバック関数を指定す
る.
error
通信が失敗した時に呼ばれるコールバック関数を指定す
る.
complete
成功・失敗に関わらず通信が完了した時に呼ばれるコー
ルバック関数を指定する.
記述例:$.ajax({
url:”post.php”,
type:”POST”,
data: { postdata:”hello!!”},
success: function(data){
alert(data);
}
});
記述例は,post.php に「hello!!」を代入した変数 postdata を POST 送信するプログラ
ムである.通信が成功した場合はアラートが表示される.なお,通信開始時に送信される
「data」と通信成功時に実行される function の引数「data」は別の変数である.
20
8.2.4 アップロードの簡略化
アップロードの簡略化において本研究で注目したのが,jQuery のプラグインである
Dropzone.js である.Dropzone.js はドラッグ&ドロップが行える領域を設定でき,その
領域にファイルをドロップすることでアップロードが自動で始まる.複数ファイルを1度
にドロップすることも可能である.Dropzone.js を使用するには下記に記したように,
head タグ内と body タグ内でそれぞれ記述する.
head タグ内
<script src=”js/dropzone.js”></script>
body タグ内
<form action=”/file-upload”class=”dropzone”></form>
8.2.5 1 度だけ回答可能なボタン
8.1.4 で説明した通り,プロキシの関係で本研究では回答回数を制限する.方法と
して,クリッカー画面において回答をクリックしたとき,JavaScript で回答ボタン
の属性を変更し,クリックしたボタンの色を薄くするようにした.プログラミング
は以下の通りである.
・HTML
<button class="ansFadeOutBtn" type="submit" value="1">男性</button>
<button class="ansFadeOutBtn" type="submit" value="2">女性</button>
・JavaScript
$(function(){
var isClicked = false;
// 一度だけデータ送信するボタン button class="ansBtn"
$(".ansBtn").click(function(){
if( !isClicked ){
$(this).css("opacity", 0.2);
$(".ansBtn").attr({ type: "button" });
}
isClicked = true;
});
ボタンの色合い等の属性値を変更するので,jQuery でセレクタ指定できるように
HTML ではボタン生成時にクラスを指定する.JavaScript では jQuery を利用し,
クラスを指定したボタンがクリックされたときに処理が開始されるようにする.最
初の回答かどうかは,関数の最初に記述した変数(isClicked)で判断する.この変
数には初期値として false を代入している.処理が始まったときにこの変数を参照し,
false の場合ボタンへの属性値変更が行われる.そして最後に,変数に true を代入す
ることでこれ以降クリックしても反応しなくなっている.下図は男性のボタンを押
した場合の実行結果である.
図:実行前 実行後
21
9 まとめ
クリッカーの利用は,日本ではまだ普及していない.しかしクリッカーに関する論文では,その
多くが教育現場への有効活用が報告されており,クリッカーを利用した授業体系の注目が高まれば,
近い将来導入が進むことが期待できる.
今回の研究で,スマート web クリッカーは仕様書の 8 割は実装でき,教員・学生共に使い勝手のよ
いものになった.クリッカー画面では,学生が回答を行うと回答ボタンの色を薄くすると共に,回
答を 1 回に限定することで重複回答を防止し,回答の支援を行った.出題画面では,問題に画像表
示・拡大機能を実装することで画像提示型の問題にも対応できるようにした.また,ファイルド
ラッグ&ドロップ式アップロードの実装をしたことで教員は簡単に利用でき,授業に集中できるも
のと考える.
スマート web クリッカーには,研究を進めていく中で判明した問題がある.以下にその問題を記
述し,今後の課題とする.
9.1 更新することで再回答が可能となる問題
8.2.5 で説明したように,クリッカー画面では1度だけしか問題に回答できないようにした.
しかし,ブラウザを更新した場合再度回答を行うことができてしまう.これによって,回答数が
増加してしまい,集計結果の信憑性が崩れてしまう.この問題を解消する方法として,問題によ
りセッションキーが違うという特徴を利用した確認方法である.あらかじめ COOKIE にセッ
ションキーを登録しておき,更新が実行されるとそのセッションキーと更新時に保存されるセッ
ションキーを比較する,2つのキーが一致した場合ボタンの回答をできなくするというものであ
る.これを実装することで再回答可能の問題を回避できる.
9.2 セキュリティの低さ
出題画面へは直接 URL を入力し,移動するほかに,クリッカー画面下部にある「問題画面」をクリック
することで移動することが可能である.この処理にセキュリティは一切かけておらず学生でも自由に移動
することが可能である.そのため,学生は回答前に集計結果を知ることができ,回答の信憑性が薄れる恐
れがある.これを防ぐために,「集計結果」や「正解」などのボタンに認証をかける必要がある.また,学生
による勝手なアップロードを避けるため,アップロード枠にも同様に認証をかける必要がある.
10 謝辞
本研究を進めるにあたり,手厚いご指導を頂いた卒業論文指導教員の徐 丙鉄教授に深く感謝い
たします.また,日々の研究を通じて活発に議論を交わした情報物理研究室の皆様に感謝いたしま
す.
11 参考文献
1. PHP マニュアル
http://www.php.net/manual/ja/
2. jQuery 日本語リファレンス
http://semooh.jp/jquery/
3. 北海道大学大学院理学研究科 , 北海道大学高等教育機能開発総合センター
「授業応答システム”クリッカー”による能動的学習授業」
http://socyo.high.hokudai.ac.jp/Journal/J16PDF/No1601.pdf
22
4. 金沢大学大学教育開発・支援センター , キーパッド・ジャパン
「授業客観化のためのクリッカー活用-教育効果のリアルタイム把握を中心に-」
http://www.rche-kanazawa-u.jp/Clicker/abstract/Pro002-Aono-Abstract.pdf
5. 山田邦雄(北海道大学大学院理学研究科)
「自作クリッカーシステムによる授業」
http://socyo.high.hokudai.ac.jp/Journal/J16PDF/No1602.pdf
6. 教養教育センター 「双方向性の高い授業を目指して-クリッカーの可能性を探る-」
http://ci.nii.ac.jp/els/110008007493.pdf?
id=ART0009597928&type=pdf&lang=jp&host=cinii&order_no=&ppv_type=0&lang_s
w=&no=1391662118&cp=
7.
著:小島まさご 「実践マスター PHP+MySQL」
8.
矢持敬也
「web クリッカー-授業応答システムの開発-」
http://buturi.heteml.jp/student/2012/yamochi_t/evidence/Graduation_yamochi.pdf
9. 文部科学省
http://www.mext.go.jp/
12 付録
ソースコードを次ページから添付する.
23
12 付録
・index.php5(クリッカー画面)
<?php
$fpCookie = fopen("./data/session.txt", "r");
setcookie('checkChoices', fgets($fpCookie));
fclose($fpCookie);
// クッキーを発行
?>
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8" />
<!-キャッシュをしないようにする-->
<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Cache-Control" content="no-cache">
<meta http-equiv="Expires" content="0">
<meta name="viewport" content="width=device-width , height=device-height "/>
<title>CLICKER</title>
<link rel="stylesheet" href="default.css" />
<script src="js/jquery-1.9.0.min.js"></script>
</head>
<body>
<div class="siteBox">
<div class="tittleClicker">
<?php
$fp = fopen("./upload/question.csv", "r");
//変数初期化
$c = $t = 0;
//T 属性と C 属性をそれぞれ別の配列へ格納
setlocale(LC_ALL, 'ja_JP.UTF-8');
setlocale(LC_ALL, 'ja_JP.EUC-JP');
setlocale(LC_ALL, 'ja_JP.Shift_JIS');
for ($i = 0; FALSE != ( $data = fgetcsv($fp) ); $i++) {
// 配列 $csv の文字コードを SJIS から UTF-8 に変換
mb_convert_variables("UTF-8", "SJIS-win", $data);
if ($data[0] === "C" ) {
$choice[$c] = $data;
$c++;
}
if ($data[0] === "CA") {
$choice[$c] = $data;
24
$c++;
}
if ($data[0] === "T") {
$tittle[$t] = $data;
$t++;
}
}
fclose($fp);
print "<h1>";
for ($i = 0; $i < count($tittle); $i++) {
for ($j = 1; $j < count($tittle[$i]); $j++) {
print $tittle[$i][$j];
}
}
print "</h1>";
?>
</div>
<script>
$(function(){
//ボタンの値をテキストに書き込むプログラム
var isClicked = false;
$('.ansBtn').click(
function(){
if( !isClicked ){
$(this).css("opacity",0.2);
var data = {postdata : this.value};
$.ajax({
type: 'post',
url: 'addAnswer.php5',
data: data,
success: function(data){
alert(data);
}
});
}
isClicked = true;
}
);
});
</script>
<script>
$(function(){
$('.ansBtn').click(
25
function(){
$.get("data/session.txt", function(myData){
alert("get メソッド実行");
resultArray = myData.split("\r\n");
alert(resultArray[0])
document.cookie = 'sessionID='+resultArray[0];
});
document.cookie = 'answerNum='+this.value;
}
);
});
</script>
<!--選択肢の数だけクリックボタンを生成-->
<div id="clickerSpace" >
<?php
for ($i = 0; $i < count($choice); $i++) {
print'<button class="ansBtn" type="submit" name="answer" value= ' . ($i + 1) .
'><p class="ansBtnTxt">';
for ($j = 1; $j < count($choice[$i]); $j++) {
print $choice[$i][$j];
if($j == 1){
print (" : ");
}
}
print "</p></button>";
print "<br/>";
}
?>
</div>
<a href ="./host/question.php5">問題画面</a>
</div>
</body>
</html>
・addAnswer.php5(回答保存を行う部分)
<?php
//print ("同期チェック準備");
if (isset($_COOKIE['checkChoices'])) {
//print ("同期チェック開始");
$fpSes = fopen("./data/session.txt", "r");
$compkeyA = fgets($fpSes);
$compKeyB = $_COOKIE['checkChoices'];
fclose($fpSes);
26
//より確かにファイルロックを行うため,ロック専用ファイルをロック
$fpLockEX = fopen("lockEX", "a");
flock( $fpLockEX , LOCK_EX);
if ($compkeyA === $compKeyB) {
//正しい送信先だった場合
//送信者の IP アドレスを取得
$IPaddr = $_SERVER["REMOTE_ADDR"];
$filepath = "./data/answer.csv";
$fpRead = fopen($filepath, "r");
flock($fpRead, LOCK_SH);
//今回送信された回答データと IP アドレス
$ans = array($_POST['postdata'], $IPaddr);
$ansData = array();//前回と今回の回答を格納する
//今回の回答データを追加
$ansData[$i] = $ans;
fclose($fpRead);
//結果を書き出す
$fpWrite = fopen($filepath, "a");
mb_convert_encoding($tempData, "sjis-win", "UTF-8");
foreach( $ansData as $tempData ){
//print($tempData[0]." || ".$tempData[1]."<br/>");
fputcsv($fpWrite, $tempData);
}
fclose($fpWrite);
//ファイルロックを解除
fclose($fpLockEX);
print $_POST['postdata'].'番目の回答を送信しました.';
} else {
print "異なる問題への回答です";
}
}
?>
27
・question.php5(出題画面)
<!DOCTYPE html>
<html lang="ja">
<head>
<title>Question</title>
<!--キャッシュをしないようにする-->
<meta http-equiv="Cache-Control" content="no-cache">
<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Expires" content="0">
<meta charset="UTF-8" />
<link rel="stylesheet" href="../default.css" id="maincss" type="text/css" >
<script src="../js/jquery-1.9.0.min.js"></script>
<script src="../js/csvToArray.js"></script>
<script src="../js/jquery.fullImage.js"></script>
<script src="../js/function_store.js"></script>
<script type="text/javascript" src="../js/dropzone.js"></script>
<script type ="text/javascript">
//選択肢の数を取得する
var ans = new Array();//選択肢ごとの回答数を配列として用意
var choice = 0;//選択肢の数
var ansAll = 0 ;//すべての回答数
var ansPar = new Array();//回答率を格納する配列
var bgColor;//背景色の値を格納
function getChoicesGraphData(){
jQuery.ajax({
url : "../upload/question.csv",
type : "get",
cache: false,
beforeSend: function(xhr){
xhr.overrideMimeType("text/html;charset=Shift_JIS");
},
success : function(data){
var csv = $.csv()(data);
$(csv).each(function(){
//data には CSV ファイルの中身が入っている
//this は each 文の中で,CSV ファイルのポインタの当たっている1行を指す
if( this[0] == "C" || this[0] =="CA" ){
28
ans[choice] = 0;
choice++;
}
})
getResponse();
}
});
}
//カウント CSV を参照して回答集計を行う関数
function getResponse(){
jQuery.ajax({
url : "../data/answer.csv",
type : "get",
cache: false,
beforeSend: function(xhr){
xhr.overrideMimeType("text/html;charset=Shift_JIS");
},
success : function(data){
//この関数が実行される度に初期化.
//これを行わないと次の実行で全体回答数が倍になる
ansAll = 0 ;
//選択肢の数だけ回答集計配列を初期化
for(i=0 ; i < choice ; i++){
ans[i] =0;
}
//jQuary の拡張ライブラリより,CSV ファイルを配列へと読み込む
var csv = $.csv()(data);
//each 文で CSV 配列の要素を回す
$(csv).each(function(){
//回答番号を配列に合わせて,該当配列番号をインクリメント
ans[ this[0] - 1]++;
//全体回答数をカウント
ansAll++;
})
//回答率の計算,及び桁数調整
for(i = 0 ; i < choice ; i++){
ansPar[i]= ans[i] / ansAll;
//小数点以下3桁までに直す
ansPar[i]= ansPar[i].toFixed(3);
29
}
//全体回答数を#response 要素へ上書き
$("#response").text( ansAll );
}
});
}
//初回のみ実行
getChoicesGraphData();
//6秒ごとに必要な値を再取得(非同期処理対策)
setInterval(function(){
getResponse();
},20000);
</script>
<script type="text/javascript">
//奇偶によってテーブルを色分け
$(document).ready(function(){
// 奇数行の色を設定
$('.choicesGraph:odd').css('background', '#F6FBFF');
//$('.choicesHeader:odd').css('background', '#d1e7ff');
// 偶数行の色を設定
$('.choicesGraph:even').css('background', '#D1ECFF');
//$('.choicesHeader:even').css('background', '#c6e1ff');
});
</script>
<script type="text/javascript">
//gradient を用いた擬似的グラフ表示を行う
$(function(){
$("#resBtn").click(function(){
for(i = 0 ; i < choice ; i++){
//テーブルの奇数行と偶数行の色分けに合わせた配色を配列に格納
if( (i % 2) == 1){
bgColor = "#F6FBFF";
}
else{
bgColor = "#D1ECFF";
}
30
//jquary による CSS への gradient プロパティ挿入
$(".choicesGraph"+
(i+1) ).css("filter","progid:DXImageTransform.Microsoft.gradient(startColorstr="+ bgColor
+", endColorstr="+bgColor+")");//IE 7,8,9
$(".choicesGraph"+ (i+1) ).css("background",
"-moz-linear-gradient(left , #FFA09E "+ (ansPar[i] * 100 ) +"% , "+ bgColor
+" "+ (ansPar[i] * 100 ) +"% " );//FireFox3.6+
$(".choicesGraph"+ (i+1) ).css("background",
"-o-linear-gradient(left , #FFA09E "+ (ansPar[i] * 100 ) +"% , "+ bgColor +"
"+ (ansPar[i] * 100 ) +"% " );//opera
$(".choicesGraph"+ (i+1) ).css("background",
"-webkit-gradient(linear, left top, right top, from(#FFA09E), color-stop("+
ansPar[i] +", #FFA09E), color-stop("+ ansPar[i] +","+ bgColor +"),to("+ bgColor
+") )");//Chrome
$(".choicesGraph"+ (i+1) ).css("background","linear-gradient(to right,
#FFA09E "+ (ansPar[i] * 100 ) +"% , "+ bgColor +" "+ (ansPar[i] * 100 ) +"%)");//IE10+
$(".choicesAns" + (i+1) ).text( ans[i] );
}
//全体回答数の再表示
$("#response").text( ansAll );
})
})
</script>
</head>
<?php
//リロード時の POST 再送信対策
//セッション値がポストされてる場合,前回保存されたセッション値と比較する
if (isset($_POST["key"])) {
$fpSes = fopen("../data/session.txt", "r");
$compKeyA = $_POST["key"];
$compKeyB = fgets($fpSes);
fclose($fpSes);
if ($compKeyA !== $compKeyB) {
$fpSes = fopen("../data/session.txt", "w");
fwrite($fpSes, $_POST["key"]);
fclose($fpSes);
//answer.csv の中身を消す
$fp = fopen("../data/answer.csv", "w");
fclose($fp);
31
}
}
$updir = "../upload/";
$filename = "question.csv";
//出題ファイル読み込み
//FILES になにも入ってなかった場合(ポストされていない初回起動時)は apload 確認を実行しない
if ($_FILES != NULL) {
//$_FILES にデータは POST されているが,正常でない場合はアップロード失敗メッセージを
表示
if (move_uploaded_file($_FILES['upfile']['tmp_name'], $updir . $filename) == FALSE)
{
print("アップロードに失敗:");
print($_FILES['upfile']['error']);
} else {
//アップロード成功時には特に処理は発生しない
}
} else {
//アップロードがなかった場合は,デフォルトファイルを問題として出題
copy($updir . "default.csv", $updir . $filename);
}
?>
<?php
$fp = fopen($updir . $filename, "r");
//変数初期化
$t = $q = $c = 0;
//文字コードを判別しようとするも断念,決め打ち SiftJIS に
//問題文を要素ごとに分解する
//T 属性,Q 属性,C 属性をそれぞれ別の配列へ格納
//setlocale(LC_ALL, 'ja_JP.UTF-8');
//setlocale(LC_ALL, 'ja_JP.EUC-JP');
//setlocale(LC_ALL, 'ja_JP.Shift_JIS');
for ($i = 0; FALSE != ( $data = fgetcsv($fp,100) ); $i++) {
setlocale(LC_ALL, 'ja_JP');
// 配列 $csv の文字コードを SJIS から UTF-8 に変換
mb_convert_variables("UTF-8", "SJIS-win", $data);
if ($data[0] === "T") {
$tittle[$t] = $data;
32
$t++;
}
if ($data[0] === "Q") {
$question[$q] = $data;
$q++;
}
if ($data[0] === "C") {
$choice[$c] = $data;
$c++;
}
if($data[0] === "CA") {
$choice[$c] = $data;
$c++;
}
}
fclose($fp);
?>
<body>
<div id="bigimage" onclick="changeSmallImage();" style="display:none;" title="ク
リックすると画像を縮小します">
<?php
foreach (glob('uploads/*.jpg') as $filename){
print "<img src='$filename'/>";
}
?>
</div>
<div class="siteBox">
<!--設問描写領域-->
<div id="tittle">
<h1>
<?php
//タイトルを表示する
for ($i = 0; $i < count($tittle); $i++) {
for ($j = 1; $j < count($tittle[$i]); $j++) {
print $tittle[$i][$j];
}
}
?>
</h1>
</div>
33
<script>
function changeBigImage(){
document.getElementById("smallimage").style.display="none";
document.getElementById("bigimage").style.display="block";
}
function changeSmallImage(){
document.getElementById("bigimage").style.display="none";
document.getElementById("smallimage").style.display="block";
}
</script>
<!--csv から読み込んだ問題文の表示-->
<div id="question">
<!--アップロードされた画像の表示-->
<!--<span id="dispimage" url("uploads/uploadImage.jpg");></span>-->
<!--<img id="dispimage" src="uploads/uploadImage.jpg" >-->
<div id="smallimage" onclick="changeBigImage();" title="クリックすると画像を拡大
します">
<?php
foreach (glob('uploads/*.jpg') as $filename){
print "<img src='$filename'/>";
}
?>
</div>
<?php
//問題文を表示する
for ($i = 0; $i < count($question); $i++) {
for ($j = 1; $j < count($question[$i]); $j++) {
print $question[$i][$j];
}
}
?>
</div>
<!--csv から読み込んだ選択肢描画領域-->
<div id="choices">
&nbsp;
34
<?php
print "<table id='ctable'>";
//選択肢をテーブル表示
for ($i = 0; $i < count($choice); $i++) {
//選択肢が正答か誤答かの属性を格納
$choiceType = $choice[$i][0];
//選択肢番号の部分を表示
print "<tr>";
print "<td class = '".$choiceType." choicesHeader'>";
print "<p>" . $choice[$i][1] . "</p>";
//選択肢の内容部分を表示
for ($j = 2; $j < count($choice[$i]); $j++) {
print "<td class= '" .$choiceType." choicesGraph choicesGraph" . ($i + 1) . "'
onClick='changeCol(". ($i + 1 ).")'>";
print $choice[$i][$j];
}
print "</td>";
print "<td class='choicesAns choicesAns" . ($i + 1) . "'>";
print "0";
print "</td>";
//最初だけ縦への連結セルを作成
//ここの連結セルに,回答数を表示する
if ($i == 0) {
print "<td id = 'response' rowspan='" . count($choice) . "'>";
print "<p>0</p>";
print "</td>";
}
print "</tr>";
}
print "</table>";
?>
</div>
<script>
//画像アップロード領域の表示・非表示変更
function show(num){
if (num == 0){
35
document.getElementById("disp").style.display="none";document.getElementById("dispima
ge").style.display="none";
}else{
document.getElementById("disp").style.display="block";
}
}
function koshin(){
location.reload();
}
function changesytle(cssfile) {
document.getElementById('maincss').href = cssfile;
}
</script>
<div id="tools">
<!--ファイルをアップロードする-->
<button id="uploadRange" >アップロード領域表示</button>
<button id="uploadImg" >画像非表示</button>
<button id="resBtn" type="button">集計結果</button>
<button id="caBtn" type="button" onClick="changeColCA()">正解</button>
<button class="dlBtn" onClick="subwin('subwindow.php')">過去問を DL</button>
<button class="dlBtn" onClick="location.href='download.php5'">集計結果を
DL</button>
<div id="dzone"style="display:none;">
<form action="upload.php" class="dropzone" id="drp" ></form>
</div>
</div>
</div>
<script type="text/javascript">
//クリックした選択肢の文字色を変更する
function changeCol(target){
if( $(".choicesGraph"+ target ).css("color") == "rgb(0, 0, 255)"){
$('.choicesGraph'+ target ).css('color', "rgb(0, 0, 0)");
}else{
36
$('.choicesGraph'+ target ).css('color', "rgb(0, 0, 255)");
}
}
//正答の文字色を変更する
function changeColCA(){
$(".CA").css("color" , "rgb(255, 0, 0)");
}
</script>
</body>
</html>
・upload.php(アップロード時の処理)
<?php
if (!is_uploaded_file( $_FILES['file']['tmp_name'])) {
echo "ファイルが選択されていません.";
exit();
}
$file_tmp = $_FILES["file"]["tmp_name"];
$file_name = $_FILES["file"]["name"];
$FileName = date("YmdHis") . "--" . get_name($file_name) .".". get_ext($file_name);
/////////////////////// ここからファイルの仕分けが始まる //////////////////////////
if( preg_match('/.csv/',$FileName) != 1){
// 画像の場合
$file_check = true;
$FilePath = "uploads/images/" . $FileName ;
copy($file_tmp,"uploads/uploadImage.jpg");
}
else{
// 問題の場合
$sessionID = uniqid('');
// セッションキーを作成
$file_check = false;
$csv = "../upload/default.csv";
$answer = "../data/answer.csv";
$copy_name = "../data/reflectionbox/" . date("YmdHis");
$FilePath = "uploads/csv/" . $FileName ;
37
if(copy($csv,$copy_name.".csv")){
// 前回の問題を別フォルダにコ
if(copy($file_tmp,$csv)){
// 新しい問題を default.csv に
ピー
上書き
if(copy($answer,$copy_name . "-a.csv")){
// 集計結果もコピー
$fo = fopen($answer,"w");
// ファイルをクリア
fclose($fo);
$fo = fopen("../data/session.txt","w");
fputs($fo,$sessionID);
// 新たなセッションキーを設定
fclose($fo);
}
else{
echo "集計結果の保存に失敗しました.";
}
}
else{
echo "ファイルのアップロードに失敗しました.";
}
}
else{
echo "前回の問題データの保存に失敗しました.";
}
}
move_uploaded_file($file_tmp,$FilePath);
///////////////////////// ユーザ定義関数 ////////////////////////
//get_name
//ファイル名を取得
function get_name($file_name1){
$name=substr($file_name1,0,strpos($file_name1,"."));
return $name;
}
// get_ext
// ファイルの拡張子を取得
function get_ext($file_name2){
$name=strrev($file_name2);
$ext=substr($name,0,strpos($name,"."));
return strrev($ext);
}
?>
・download.php5(「結果を DL」を実行時の処理)
<?php
38
//ヘッダ情報挿入
header("Cache-Control: public");
header("Pragma: public");
header("Content-Type: text/octet-stream");
$fpReadQuest = fopen("../upload/question.csv", "r");
$fpReadAns = fopen("../data/answer.csv", "r");
$fpWriteDL = fopen("../data/download.csv", "w"); ///書き出したファイルを保存
$ansAll = 0;
$t = $q = $c = 0;
//文字化け対策
setlocale(LC_ALL, 'ja_JP.UTF-8');
setlocale(LC_ALL, 'ja_JP.EUC-JP');
setlocale(LC_ALL, 'ja_JP.Shift_JIS');
//問題文を要素ごとに分解する
//T 属性,Q 属性,C 属性をそれぞれ別の配列へ格納
for ($i = 0; FALSE != ( $data = fgetcsv($fpReadQuest) ); $i++) {
// 配列 $csv の文字コードを SJIS から UTF-8 に変換
mb_convert_variables("UTF-8", "SJIS-win", $data);
if ($data[0] === "T") {
$tittle[$t] = $data;
$t++;
}
if ($data[0] == "Q") {
$question[$q] = $data;
$q++;
}
if ($data[0] === "C" ) {
$choice[$c] = $data;
$sumAns[$c] = 0;
$c++;
//選択肢の数だけ初期化
$sumAns[$c] = 0;
}
if($data[0] === "CA") {
$choice[$c] = $data;
$c++;
}
}
39
unset ( $tittle[0][0]);
$tittleTemp = join( "", $tittle[0] );
$timeNow = date('y 年 m 月 d 日 H 時 i 分');
//タイトルを DL ファイルに加えるため,tittle[]にタイトル格納後,ヘッダ情報を送信
header("Content-Disposition: attachment; filename=" . $tittleTemp ."集計結果_". $timeNow .
".csv");
//header("Content-Disposition: attachment; filename=" . $tittle[0][1] .".csv");
//選択肢ごとの回答数を格納する
for ($i = 0; FALSE != ( $countAns = fgetcsv($fpReadAns) ); $i++) {
//選ばれた選択肢番号に対応した配列のカウントをプラス処理
$sumAns[($countAns[0] - 1)]++;
$ansAll++;
}
$csvTemp = "集計実行時間:,";
mb_convert_variables("SJIS-win", "UTF-8", $csvTemp);
fwrite($fpWriteDL, $csvTemp);
echo ($csvTemp);
$timeNow .= ("\n");
mb_convert_variables("SJIS-win", "UTF-8", $timeNow);
fwrite($fpWriteDL, $timeNow);
echo ($timeNow);
//以下は,$csvTemp に書き込まれたデータを逐次書き出し,ファイル保存していく
$csvTemp = $tittleTemp;
$csvTemp .= ("\n");
mb_convert_variables("SJIS-win", "UTF-8", $csvTemp);
fwrite($fpWriteDL, $csvTemp);
echo ($csvTemp);
for($i=0;$i<count($question);$i++){
unset ( $question[$i][0]);
$questionTemp = join("",$question[$i]);
$csvTemp = $questionTemp;
$csvTemp .= ("\n");
mb_convert_variables("SJIS-win", "UTF-8", $csvTemp);
fwrite($fpWriteDL, $csvTemp);
echo ($csvTemp);
}
$csvTemp = "選択肢,回答数,回答率\n";
40
mb_convert_variables("SJIS-win", "UTF-8", $csvTemp);
fwrite($fpWriteDL, $csvTemp);
echo ($csvTemp);
for ($i = 0; $i < count($choice); $i++) {
unset ( $choice[$i][0]);
$choiceTemp = join("",$choice[$i]);
$csvTemp = $choiceTemp;
$csvTemp .= ",";
mb_convert_variables("SJIS-win", "UTF-8", $csvTemp);
fwrite($fpWriteDL, $csvTemp);
echo ($csvTemp);
$csvTemp = $sumAns[$i];
$csvTemp .= ",";
mb_convert_variables("SJIS-win", "UTF-8", $csvTemp);
fwrite($fpWriteDL, $csvTemp);
echo ($csvTemp);
if ($ansAll != 0) {
$csvTemp = number_format(($sumAns[$i] / $ansAll), 3) * 100;
} else {
$csvTemp = 0;
}
$csvTemp .= "%";
$csvTemp .= "\n";
mb_convert_variables("SJIS-win", "UTF-8", $csvTemp);
fwrite($fpWriteDL, $csvTemp);
echo ($csvTemp);
}
$sessionID = file_get_contents('../data/session.txt');
if(!false==strstr($sessionID,$_COOKIE[sessionID])){
$selfAnswer=$_COOKIE[answerNum];
}
else{
$selfAnswer="無回答";
}
$csvTemp = "合計回答数," .$ansAll."\n"."自己回答は".$selfAnswer."です"."\n"."sID は".
$sessionID."\n"."COKIEID は".$_COOKIE[sessionID];
mb_convert_variables("SJIS-win", "UTF-8", $csvTemp);
fwrite($fpWriteDL, $csvTemp);
echo ($csvTemp);
fclose($fpReadAns);
fclose($fpWriteDL);
41
fclose($fpReadQuest);
?>
・subwindow.php(「過去問を DL」を実行時に生成されるサブウィンドウ)
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<script src="../js/jquery-1.9.0.min.js" ></script>
<script src="../js/function_store.js"></script>
<title>サブウィンドウ</title>
</head>
<body>
<p>日付を選択してください</p>
<form action="<?php $_SERVER['PHP_SELF'] ?>" method="POST">
<select name="year">
<option value="">年を選択してください</option>
<option value="<?php echo $Y=date("Y")-1;?>"><?php echo $Y=date("Y")-1; ?></option>
<option value="<?php echo $Y1=date("Y");?>"><?php echo $Y1=date("Y"); ?></option>
<option value="<?php echo $Y2=date("Y")+1;?>"><?php echo $Y2=date("Y")+1; ?
></option>
</select>
<select name="month">
<option value="">月を選択してください</option>
<option value="01">1</option>
<option value="02">2</option>
<option value="03">3</option>
<option value="04">4</option>
<option value="05">5</option>
<option value="06">6</option>
<option value="07">7</option>
<option value="08">8</option>
<option value="09">9</option>
<option value="10">10</option>
<option value="11">11</option>
<option value="12">12</option>
</select>
<input type="submit" value="検索">
</form>
<?php
if($_POST["year"] != NULL && $_POST["month"] != NULL){
$n = 0;
42
$Y = $_POST["year"];
$M = $_POST["month"];
$YM = "/".$Y . $M."/";
$dir = "../data/reflectionbox/";
echo "<p>現在". $Y . "と" . $M . "で検索しています.</p>\n";
////////////// ディレクトリの内容を読み込む
if($dh = opendir($dir)){
echo "<ul>";
while(($file = readdir($dh)) !== false){
if(preg_match($YM,$file) && !preg_match("/-a.csv/",$file)){
echo "<li class='fileDL'>". $file . "</li>\n";
$n++;
}
}
echo "</ul>\n";
closedir($dh);
}
if($n!=0){
echo "<section>該当ファイルは" . $n . "個あります.<br>\n";
echo "ダウンロードしたいファイルをクリックしてください.</section><br>";
}
else{
echo "<p>該当ファイルはありませんでした.</p>\n";
}
}
?>
<form action="csvDL.php5" method="POST">
<input type="text" id="filename" name="text" value="ファイル名を入力してください"
size="25">
<input type="submit" value="DL">
</form>
</body>
</html>
・default.css
/* ---------------------------------------------------------------------要素のリセット
---------------------------------------------------------------------- */
html, body, div, h1, h2, h3, h4, h5, h6, p {
margin: 0;
padding: 0;
background: transparent; /* 透過 */
color: #000; /* 文字色:黒 */
43
font-family:'ヒラギノ角ゴ Pro W3','Hiragino Kaku Gothic Pro','メイリオ',Meiryo,'MS Pゴシッ
ク',sans-serif; /* 文字フォント指定 */
font-size: 100%;
}
/* ---------------------------------------------------------------------ページ基本設定
---------------------------------------------------------------------- */
html{
height: 100%;
overflow: scroll; /* 常時スクロールバーを表示 */
overflow-x: auto; /* はみ出した内容の横方向の表示方法を設定:自動的に表示 */
line-height: 1.5; /* 行間の間隔 */
background: #25292C;
}
body {
height: 100%;
font-size:14px; /* フォントサイズ:14px */
line-height:1.5; /* 行間 1.5 倍 */
text-align:center;
width:100%;
}
/* ---------------------------------------------------------------------コンテンツ領域
---------------------------------------------------------------------- */
header, footer, nav, section article, figure, aside {
display:block; /* HTML5 から登場した新要素をブロック要素に変換 */
}
header {
width: 780px;
height: 70px;
margin-bottom: 10px;
}
.siteBox{
padding: 1%;
width:98%;
height:95%;
margin: 0 auto;
background: #25292C;
}
#tittle{
background-color:#E6FF96 ;
44
margin-bottom: 0.2%;
text-align: left;
font-size: 25pt;
width:98% ;
height:auto;
padding: 0.2% 1%;
border-radius: 10px 10px 0px 0px;
box-shadow: 0 2px 4px #777;
}
/* ---------------------------------------------------------------------問題画面領域
---------------------------------------------------------------------- */
#question{
background-color:#FFFFD1 ;
margin-bottom:1%;
float:left;
text-align: left;
font-size: 22pt;
width:98%;
height:auto;
padding: 1%;
box-shadow: 0 2px 4px #777;
display:block;
}
#smallimage > img{
margin: 5px;
max-width:300px;
border: 4px solid black;
border-style: double;
float: right;
}
#bigimage > img{
width: 100%;
height:100%;
position:fixed;
left:0;
top:0;
}
/*------------------------------------------------------------------csv から読み込んだ選択描画領域
45
--------------------------------------------------------------------*/
nav {
float: left; /* 左に配置 */
}
ul {
margin: 0;
padding: 0;
list-style: none; /* 行頭記号非表示 */
background-color: #F5F5F5; /* 背景色:lightGray */
}
li {
width: 260px;
height: 20px;
}
li a {
color: #000; /* 文字色:黒 */
display: block; /* ブロック要素に変換 */
text-decoration: none; /* リンクの下線を消す */
padding-left: 10px;
}
li a:hover {
background-color: #000; /* 背景色:黒 */
color: white; /* 文字色:白 */
}
#container {
width: 780px; /* 横幅 800px */
margin: 10px auto 0 auto; /* 上 margin:10px & 中央寄せ */
padding: 10px; /* 余白指定 */
}
#main {
width: 480px;
height: 200px;
padding: 10px; /* 余白指定 */
float: right; /* 右に配置 */
}
.tittleClicker{
background-color:#E6FF96 ;
margin-bottom: 0.2%;
text-align: center;
font-size: 20pt;
46
width:98% ;
height:auto;
padding: 0.2% 1%;
border-radius: 10px 10px 0px 0px;
box-shadow: 0 2px 4px rgba(200,200,200, 0.4);
}
#clickerSpace{
width:100%;
padding: 1% 0% ;
box-shadow: 0 2px 4px rgba(200,200,200, 0.4);
border-radius: 0px 0px 10px 10px;
background: #FFFFD1;
}
#resultMessage{
width:100%;
font-size: 22px;
padding: 1% 0% ;
box-shadow: 0 2px 4px rgba(200,200,200, 0.4);
border-radius: 0px 0px 10px 10px;
background: #FFFFD1;
}
tr{
}
td{
padding: 0% 1%;
}
#choices{
text-align: left;
font-size: 20pt;
width: 100%;
height:auto;
padding-bottom: 1%;
}
#ctable{
width:100%;
font-size: 25pt;
47
border:hidden;
border-spacing: 5px 7px;
}
.choicesHeader{
width:5%;
text-align: center;
border-radius: 10px 0px 0px 10px;
box-shadow: 0 2px 4px rgba(200,200,200, 0.4);
background-color: #E6FF96;
}
.choicesGraph{
width:83%;
box-shadow: 0 2px 4px rgba(240,240,240, 0.4);
}
.choicesGraph:hover{
font-weight:bold;
box-shadow: 0px 0px 4px 8px rgba(255,102,51, 0.6);
}
.choicesAns{
width: 5%;
text-align: center;
box-shadow: 0 2px 4px rgba(200,200,200, 0.4);
background: #FEFFC7;
}
#response{
padding: 1%;
text-align:center;
background: #FEFF96;
width:7%;
box-shadow: 0 2px 4px rgba(200,200,200, 0.4);
border-radius: 0px 10px 10px 0px;
}
/* ---------------------------------------------------------------------ボタン,dropzone 領域
---------------------------------------------------------------------- */
form{
display:inline;/*form タグを重ねた時改行させない*/
48
/*ここで inline にしているので drp の form をアブロック要素に設定*/
}
.ansBtn{
padding:0.5%;
margin : 0.2% 0%;
text-align: left ;
width: 99%;
font-size: 40px;
box-shadow: 0 2px 4px rgba(200,200,200, 0.4);
}
.ansBtnTxt{
margin : 0% ;
text-align: left ;
width: 95%;
font-size: 40px;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
box-shadow: 0 2px 4px rgba(200,200,200, 0.4);}
#tools{
width :100%;
border-radius: 0px 0px 10px 10px;
box-shadow: 0 2px 4px rgba(200,200,200, 0.4);
background: #E6FF96;
}
#questUpload{
float:left;
margin: 0% 2%;
}
#caBtn{
width:15%;
margin: 0.1% 1%;
}
49
#resBtn{
width:15%;
}
.dlBtn{
float: right;
margin: 0.1% 2%;
}
#drp{
border: 2px ;
border-color:black;
width:auto;
height: 200px;
background-color: #ffffff;
border-radius: 0px 0px 10px 10px;
display: block;
border-style: dashed;
}
#drpBtn{
text-align: center;
}
50