予め正しい答えを全て配列の0に入れておき、click functionで正しいか正誤判定しています。選択肢はシャッフルして表示し、最後に、正解率を表示させています。
reference
Autoloading Classes:The spl_autoload_register() function registers any number of autoloaders, enabling for classes and interfaces to be automatically loaded if they are currently not defined. By registering autoloaders, PHP is given a last chance to load the class or interface before it fails with an error.
index.php
<?php
require_once(__DIR__ . '/config.php');
$quiz = new MyApp\Quiz();
if(!$quiz->isFinished()) {
$data = $quiz->getCurrentQuiz();
shuffle($data['a']);
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Intractive Art</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="styles.css">
</head>
<body>
<?php if ($quiz->isFinished()) : ?>
<div id="container">
<div id="result">
your score ...
<div><?= h($quiz->getScore()); ?>%</div>
</div>
<a href=""><div id="btn">Replay</div></a>
</div>
<?php $quiz->reset(); ?>
<?php else : ?>
<div id="container">
<h1>Q. <?= h($data['q']); ?></h1>
<ul>
<?php foreach ($data['a'] as $a) : ?>
<li class="answer"><?= h($a); ?></li>
<!-- <li class="answer">A1</li>
<li class="answer">A2</li>
<li class="answer">A3</li> -->
<?php endforeach; ?>
</ul>
<div id="btn" class="disabled"><?= $quiz->isLast() ? 'Show Result' : 'Next Question'; ?></div>
<input type="hidden" id="token" value="<?= h($_SESSION['token']); ?>">
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<script src="quiz.js"></script>
<?php endif; ?>
</body>
</html>
autoload.php
<?php
spl_autoload_register(function($class){
$prefix = 'MyApp\\';
if (strpos($class, $prefix) === 0){
$className = substr($class, strlen($prefix));
$classFilePath = __DIR__ . '/' . $className . '.php';
if (file_exists($classFilePath)){
require $classFilePath;
} else {
echo 'No such class' . $className;
exit;
}
}
});
[/php]
_answer.php
[php]
<?php
require_once(__DIR__ . '/config.php');
$quiz = new MyApp\Quiz();
try{
$correctAnswer = $quiz->checkAnswer();
} catch (Exception $e) {
header($_SERVER['SERVER_PROTOCOL']. ' 403 Forbidden', true, 403);
echo $e->getMessage();
exit;
}
header('Content-Type: application/json; charset=UTF-8');
echo json_encode([
'correct_answer' => $correctAnswer
]);
Token.php
<?php
require_once(__DIR__ . '/config.php');
$quiz = new MyApp\Quiz();
try{
$correctAnswer = $quiz->checkAnswer();
} catch (Exception $e) {
header($_SERVER['SERVER_PROTOCOL']. ' 403 Forbidden', true, 403);
echo $e->getMessage();
exit;
}
header('Content-Type: application/json; charset=UTF-8');
echo json_encode([
'correct_answer' => $correctAnswer
]);
Quiz.php
<?php
namespace MyApp;
class Quiz{
private $_quizSet = [];
public function __construct(){
$this->_setup();
Token::create();
if(!isset($_SESSION['current_num'])){
$this->_initSession();
}
}
public function checkAnswer(){
Token::validate('token');
$correctAnswer = $this->_quizSet[$_SESSION['current_num']]['a'][0];
if (!isset($_POST['answer'])){
throw new \Exception('answer not set!');
}
if($correctAnswer === $_POST['answer']){
$_SESSION['correct_count']++;
}
$_SESSION['current_num']++;
return $correctAnswer;
}
public function isFinished(){
return count($this->_quizSet) === $_SESSION['current_num'];
}
public function getScore() {
return round($_SESSION['correct_count'] / count($this->_quizSet) * 100);
}
public function isLast(){
return count($this->_quizSet) === $_SESSION['current_num'] + 1;
}
public function reset(){
$this->_initSession();
// $_SESSION['current_num'] = 0;
// $_SESSION['correct_count'] = 0;
}
private function _initSession(){
$_SESSION['current_num'] = 0;
$_SESSION['correct_count'] = 0;
}
public function getCurrentQuiz() {
return $this->_quizSet[$_SESSION['current_num']];
}
private function _setup(){
$this->_quizSet[] = [
'q' => '1543年は、ある物が日本に伝えられた年でもある。それは何か?',
'a' => ['鉄砲', 'キリスト教', '貿易', '忍法']
];
$this->_quizSet[] = [
'q' => '海上交通の要地に作られた港町で有名なのはどこ?',
'a' => ['堺', '伊丹', '京都', '江戸']
];
$this->_quizSet[] = [
'q' => '1639年に鎖国は完成する。この年から、来航を禁止された国はどこ?',
'a' => ['ポルトガル', 'イギリス', '清', 'オランダ']
];
}
}
config.php
quiz.js
$(function() {
'use strict';
$('.answer').on('click', function() {
var $selected = $(this);
if ($selected.hasClass('correct') || $selected.hasClass('wrong')) {
return;
}
$selected.addClass('selected');
var answer = $selected.text();
$.post('/_answer.php', {
answer: answer,
token: $('#token').val()
}).done(function(res) {
$('.answer').each(function() {
if ($(this).text() === res.correct_answer) {
$(this).addClass('correct');
} else {
$(this).addClass('wrong');
}
});
// alert(res.correct_answer);
if (answer === res.correct_answer) {
// correct!
$selected.text(answer + ' ... CORRECT!');
} else {
// wrong!
$selected.text(answer + ' ... WRONG!');
}
$('#btn').removeClass('disabled');
});
});
$('#btn').on('click', function() {
if (!$(this).hasClass('disabled')) {
location.reload();
}
});
});
body {
font-size: 16px;
font-family: Arial, sans-serif;
}
#container {
width: 500px;
margin: 15px auto;
}
h1, ul > li {
border: 1px solid #ddd;
border-radius: 5px;
}
h1 {
padding: 10px;
height: 50px;
font-size: 18px;
margin: 0 0 10px;
}
ul {
list-style: none;
margin: 0 0 10px;
padding: 0;
}
ul > li {
margin-bottom: 7px;
padding: 7px 10px;
cursor: pointer;
}
#btn {
text-align: center;
float: right;
width: 100px;
padding: 7px;
color: #fff;
border-radius: 5px;
background: #00aaff;
box-shadow: 0 4px 0 #0088cc;
cursor: pointer;
font-size: 14px;
}
#btn.disabled {
opacity: 0.5;
}
.correct{
color: limegreen;
font-weight: bold;
}
.wrong {
color: #ddd;
}
.selected {
font-weight: bold;
}
#result {
border: 1px solid #ddd;
border-radius: 5px;
margin-bottom: 15px;
text-align: center;
padding: 30px 0 50px;
}
#result > div {
font-size: 64px;
font-weight: bold;
margin-top: 30px;
}