БлогNot. Пишем простой тест на PHP

Пишем простой тест на PHP

Этот учебный скрипт на PHP показывает, как можно описать некий тест в виде единственного массива вопросов и ответов. Поскольку типов вопросов может быть несколько (выбор "да"-"нет", выбор одного из нескольких вариантов, ввод числа или строки в качестве ответа), нам понадобится не просто массив, а массив массивов, каждый элемент которого будет описывать всё, что нужно для вывода и проверки очередного вопроса. Это будут записи со следующими ключами:

  • 'q' - отображаемый текст вопроса;
  • 't' - тип вопроса, соответствующий нужному тегу HTML: 'checkbox' для галочек "да/нет", 'text' для строки или числа в качестве ответа, 'select' - для списка, в котором нужно выбрать одно значение из нескольких. Выбор более одного значения реализуем придуманным нами элементом 'multiselect', представляющим из собой группу вместе обрабатываемых checkbox'ов. На самом деле, стандартный список <select> с атрибутом multiple тоже позволяет решить эту задачу, но не хотелось бы загружать пользователя необходимостью помнить, что множественный выбор из списка делается при зажатой клавише Ctrl;
  • 'a' - правильный ответ, для checkbox это значение '1' или '0' (нужно ли включать галочку), для text - строка с ответом (длину поля будем генерировать равной длине строки с правильным ответом, так что контроль лишних разделителей и проч. опустим), для select - номер варианта в списке, который является правильным ответом (варианты нумеруются с нуля!), для multiselect - строка из единиц и нулей, разделённых символом "|", показывающая, какие по порядку чекбоксы нужно включить, а какие не нужно;
  • 'i' - элементы списка, нужные только для типов вопроса select и multiselect, значение содержит строки, разделённые символом "|" (элементы списка или варианты утверждений).

За каждый правильный ответ, в том числе, выбор всех "правильных" чекбоксов в 'multiselect', будет начисляться 1 балл, а в конце скрипт выдаст резюме о количестве и проценте правильных ответов.

В отличие от простого конвертера, в этом скрипте мы не ставили задачи сохранить пользовательский ввод, поэтому ссылка "Ещё раз!" на странице с результатами позволяет просто пройти тест повторно, введя все результаты и отметив все чекбоксы заново. Несмотря на это, программке понадобилось 2 дополнительных функции:

  • error_check проверяет, всё ли хорошо с очередным элементом массива $test, и, если что-то не так, завершает выполнение скрипта. Это может пригодиться при отладке;
  • strlwr_ переводит в нижний регистр строки, введённые пользователем в качестве ответов. Предполагается кодировка Windows-1251, но можно, конечно, вставить текст скрипта в файл с другой кодировкой и поменять мета-тег кодировки в заголовке.

Вот полный исходник приложения, содержащий тест всех 4 типов вопросов:

<!DOCTYPE html PUBLIC "–//W3C//DTD HTML 4.01//EN">
<html><head>
<meta http–equiv="Content–Type" content="text/html; charset=Windows–1251" /><title>Тест на PHP</title>
</head><body>
<h3>Тест на PHP</h3>
<?php
 $test = array (
  array ('q'=>'Первым космонавтом был Юрий Гагарин','t'=>'checkbox','a'=>'1'),
  array ('q'=>'Первым президентом РФ был Михаил Горбачёв','t'=>'checkbox','a'=>'0'),
  array ('q'=>'Сколько уровней прикладных протоколов в стандартной сетевой модели OSI?','t'=>'text','a'=>'7'),
  array ('q'=>'Жириновский возглавляет партию ','t'=>'select','i'=>'КПРФ|ЛДПР|ЕР','a'=>'1'),
  array ('q'=>'Выберите верные утверждения','t'=>'multiselect',
   'i'=>'2*2=4|Волга впадает в Каспийское море|Луна дальше от Земли, чем Солнце','a'=>'1|1|0')
 );
 if (!empty($_POST['action'])) { //считаем правильные и выводим резюме
  $ball = 0;
  foreach ($test as $key=>$val) {
   switch ($val['t']) {
    case 'checkbox':
     if (isset($_POST[$key]) and $val['a']==1 or !isset($_POST[$key]) and $val['a']==0) $ball++;
    break;
    case 'text':
     if (isset($_POST[$key]) and strlwr_($_POST[$key])==strlwr_($val['a'])) $ball++;
    break;
    case 'select':
     if (isset($_POST[$key]) and $_POST[$key]==$val['a']) $ball++;
    break;
    case 'multiselect':
     $i = explode ('|',$val['a']);
     $cnt = 0;
     foreach ($i as $number=>$answer)
      if (isset($_POST[$key.'_'.$number]) and $answer==1 or 
        !isset($_POST[$key.'_'.$number]) and $answer==0) $cnt++;
     if ($cnt==count($i)) $ball++;
    break;
   }
  }
  $p = round ($ball/count($test)*100);
  echo '<p>Верных ответов: '.$ball.' из '.count($test).', '.$p.'%.</p>';
  echo '<p><a href="'.$_SERVER['PHP_SELF'].'">Ещё раз!</a></p>';
 }
 else { //предложить форму
  echo '<p>Отметьте верные утверждения или введите ответ или выберите верный вариант из списка.</p>';
  $counter = 1;
  echo '<form method="post">';
  foreach ($test as $key=>$val) {
   error_check ($val);
   echo ($counter++).'. ';
   switch ($val['t']) {
    case 'checkbox':
     echo $val['q'].' <input type="checkbox" name="'.$key.'" value="1">';
    break;
    case 'text':
     $len = strlen ($val['a']);
     echo $val['q'].' <input type="text" name="'.$key.'" value="" maxlength="'.$len.'" size="'.($len+1).'">'; 
    break;
    case 'select':
     echo $val['q'].' <select name="'.$key.'" size="1">';
     $i = explode ('|',$val['i']);
     foreach ($i as $number=>$item) echo '<option value="'.$number.'">'.$item;
     echo '</select>';
    break;
    case 'multiselect':
     $i = explode ('|',$val['i']);	 
     echo $val['q'].':&nbsp;&nbsp;&nbsp;';
     foreach ($i as $number=>$item)
      echo $item.' <input type="checkbox" name="'.$key.'_'.$number.'" value="1">&nbsp;&nbsp;&nbsp;';
    break;
   }
   echo '<br>';
  }
  echo '<input type="submit" name="action" value="Ответить"></form>';
 }

 function error_check ($q) {
  $question_types = array ('checkbox', 'text', 'select', 'multiselect');
  $error = '';
  if (!isset($q['q']) or empty($q['q'])) $error='Нет текста вопроса или он пуст';
  else if (!isset($q['t']) or empty($q['t'])) $error='Не указан или пуст тип вопроса';
  else if (!in_array($q['t'],$question_types)) $error='Указан неверный тип вопроса';
  else if (!isset($q['a']) or empty($q['a']) and $q['a']!='0') $error='Нет текста ответа или он пуст';
  else {
   if ($q['t']=='checkbox' and !($q['a']=='0' or $q['a']=='1')) 
    $error = 'Для переключателя разрешены ответы 0 или 1';
   else if ($q['t']=='select' || $q['t']=='multiselect') {
    if (!isset($q['i']) or empty($q['i'])) $error='Не указаны элементы списка';
    else {
     $i = explode ('|',$q['i']);
     if (count($i)<2) $error='Нет хотя бы 2 элементов списка вариантов ответа с разделителем |';
     foreach ($i as $s) if (strlen($s)<1) { $error = 'Вариант ответа короче 1 символа'; break; }
     else {
      if ($q['t']=='select' and !array_key_exists($q['a'],$i)) $error='Ответ не является номером элемента списка';
      if ($q['t']=='multiselect' ) {
       $a = explode ('|',$q['a']);
       if (count($i)!=count($a)) $error='Число утверждений и ответов не совпадает';
       foreach ($a as $s) if ($s!='0' and $s!='1') { 
        $error = 'Утверждение не отмечено как верное или неверное'; break; 
       }
      }
     }
    }
   }
  }
  if (!empty($error)) {
   echo '<p>Найдена ошибка теста: '.$error.'</p><p>Отладочная информация:</p>';
   print_r ($q);
   exit;
  }
 }
 
 function strlwr_($s){
  $hi = "ABCDEFGHIJKLMNOPQRSTUVWXYZАБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ";
  $lo = "abcdefghijklmnopqrstuvwxyzабвгдеёжзийклмнопрстуфхцчшщъыьэюя";
  $len = strlen ($s);
  $d='';
  for ($i=0; $i<$len; $i++) {
   $c = substr($s,$i,1);
   $n = strpos($c,$hi); 
   if ($n!==FALSE) $c = substr ($lo,$n,1);
   $d .= $c;
  }
  return $d;
 }
?>
</body></html>

Ниже показан вид теста и результат его прохождения.

простой тест на PHP, будет выведен на одной странице, но типы вопросов могут быть разными
простой тест на PHP, будет выведен на одной странице, но типы вопросов могут быть разными
простой тест на PHP, страница с результатами :)
простой тест на PHP, страница с результатами :)

 Скрипт-пример в работе

05.10.2015, 18:14 [28642 просмотра]


теги: учебное php тест

К этой статье пока нет комментариев, Ваш будет первым