БлогNot. PHP: простейшее распределение ресурсов по принципу "занято-свободно"

PHP: простейшее распределение ресурсов по принципу "занято-свободно"

Исходная ситуация - типичное распределение ресурсов по принципу "занято-свободно" (номера в гостинице, темы курсового и т.п.), когда повторное занятие ресурса не допускается вплоть до пометки его как свободного.

Скрипт предназначен для небольших объёмов данных, изменения может вносить "вручную" администратор, знающий пароль, просто переключением чекбоксов, по которому происходит автосохранение на стороне сервера.

Ресурсы бьются на категории, имеющие имена (номера комнат, предметные области тем), в каждой категории может быть разное количество ресурсов (записей), но они могут быть занумерованы в естественном порядке 1, 2, 3...

Данные хранятся в обычном текстовом файле, при первом запуске скрипт создаст его себе по массиву data, в котором описаны названия категорий и количество ресурсов в каждой из них (см. листинг).

Другие две настройки - пароль администратора и имя файла, все они показаны в начале листинга.

Наверное, скрипт нетрудно расширить, введя описания для чекбоксов и т.п., но это будет уже программка другого класса сложности. Ниже показаны ссылка на скрипт в работе (с реальными данными) и исходник на момент написания (PHP8, проверен на локалхосте XAMMP). Предполагается, что скрипт будет работать в кодировке Юникода UTF-8 и в ней же сохранять данные.

 Скрипт Topics в работе

<?php
 session_start();
 $password = '123'; //Пароль для отметок, поменяйте на свой
 $data = array ( //Исходные данные
  'Категория 1' => 12, 'Категория 2' => 12, 'Категория 3' => 12, 
  'Игры (И)' => 10, 'Графика (Г)' => 6, 'Калькуляторы (К)' => 4,
  'Утилиты (У)' => 15, 'Редакторы (Р)' => 6, 'Базы данных (БД)' => 4,
  'Обучение (О)' => 4, 'Разработка модулей (М)' => 4
 );
 $filename = 'data.txt'; //Файл с данными
?>
<!DOCTYPE html>
<html lang="ru">
<head>
 <title>Темы</title>
 <meta charset="utf-8">
 <style>
 table {
  margin: auto;
 }
 form {
  text-align: center;
 }
 table, th, td {
  border: 1px solid black;
  border-collapse: collapse;
  text-align: center;
 }
 th, td {
  padding: 5px;
  font-weight: normal;
 }
 tr {
  height: 50px;
 }
 td {
  width: 50px;
 }
 .center {
  text-align: center;
  font-size: small;
 }
 .exist {
  background-color: #cfc;
 }
 </style>
 <script>
  function check (id,e) {
   let elem = document.getElementById(id);
   if (!elem) {
    alert('Нет элемента с id='+id); return;
   }
   if (e.which == 1) {
    location = '?click=' + id;
   }
  }
 </script>
</head><body>	
<?php
 function saveAll ($filename, $fill) {
  $s = '';
  for ($i = 0; $i < count($fill); $i++) {
   $s .= $i."\t".$fill[$i]['name']."\t".$fill[$i]['cnt']."\t".rtrim(implode(' ',$fill[$i]['data']))."\n";
  }
  $res = @file_put_contents ($filename,rtrim($s));
  if ($res === false) {
   exit ('Ошибка создания файла '.$filename.' (метод saveAll), проверьте права');
  }
 }

 if (isset($_POST['admin'])) {
  $pass = htmlspecialchars (trim($_POST['password']),ENT_QUOTES,'UTF-8');
  if ($pass === $password) $_SESSION['admin'] = md5($password);
  if (isset($_GET['click'])) unset($_GET['click']);
 }
 $mn = min(array_values($data));
 $mx = max(array_values($data));
 if ($mn > $mx or $mn < 1 or $mx < 1) {
  exit ('Ошибка в разметке, неверный максимум или минимум');
 }
 $fill = [];
 if (!file_exists($filename)) {
  $s = '';
  $i = 0;
  foreach ($data as $key=>$val) {
   $fill[$i]['name'] = $key;
   $fill[$i]['cnt'] = $val;
   $fill[$i]['data'] = array_fill (0, $val, 0);
   $s .= $i."\t".$fill[$i]['name']."\t".$fill[$i]['cnt']."\t".implode (' ',$fill[$i]['data'])."\n";
   $i++;
  }
  $res = @file_put_contents ($filename,rtrim($s));
  if ($res === false) {
   exit ('Ошибка создания файла '.$filename.', проверьте права');
  }
 }
 else {
  $res = @file ($filename);
  if ($res === false) {
   exit ('Ошибка чтения файла '.$filename.', проверьте права');
  }
  for ($i = 0; $i < count($res); $i++) {
   $arr = explode ("\t",$res[$i]);
   if ($arr === false || count($arr) != 4) {
    exit ('Ошибка формата файла '.$filename.' (нет разделителя), строка '.($i+1));
   }
   $fill[$i]['name'] = $arr[1];
   $fill[$i]['cnt'] = $arr[2];
   $fill[$i]['data'] = explode(' ',$arr[3]);
   if (!array_key_exists($fill[$i]['name'],$data)) {
    exit ('Ошибка формата файла '.$filename.' (нет ключа ['.$fill[$i]['name'].'] в данных), строка '.($i+1));
   }
   $arr = $fill[$i]['data'];
   if ($arr === false || count($arr)!=$data[$fill[$i]['name']]) {
    exit ('Ошибка формата файла '.$filename.' (неверное количество записей), строка '.($i+1));
   }
  }
  if (isset($_GET['click']) and !isset($_POST['exitme'])) {
   $id = htmlspecialchars (trim($_GET['click']),ENT_QUOTES,'UTF-8');
   $parts = explode ('_',$id);
   if (count($parts) == 3) {
    $i = intval($parts[1]); $j = intval($parts[2]);
    if (isset($fill[$i]['data'][$j])) {    
     if ($fill[$i]['data'][$j] == 0) $fill[$i]['data'][$j] = 1;
     else $fill[$i]['data'][$j] = 0;
     saveAll ($filename, $fill);
    }
    else {
     exit ('Неверный ключ '.$_GET['click']);
    }
   }
   else {
    exit ('Неверный ключ '.$_GET['click']);
   }
  }
  if (isset($_POST['exitme'])) {
   saveAll ($filename, $fill);
   $_SESSION['admin'] = '';
   unset($_SESSION['admin']);
  }
 }

 echo '<p class="center">x - тема уже занята, '.
  '<span class="exist">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span> - тема существует</p>';
 echo '<table>'."\n";
 echo '<tr><th>&nbsp;</th>'."\n";
 for ($j = 1; $j <= $mx; $j++) echo '<th>'.$j."</th>\n";
 echo '</tr>'."\n";
 for ($i = 0; $i < count ($fill); $i++) {
  echo '<tr><th>'.$fill[$i]['name']."</th>\n";
  $cnt = $fill[$i]['cnt'];
  for ($j = 0; $j < $mx; $j++) {
   echo '<td';
   if ($j < $cnt) {
    echo ' class="exist">';
    if (isset($_SESSION['admin']) and $_SESSION['admin'] === md5($password)) {
     $id = 'c_'.$i.'_'.$j;
     echo '<input type="checkbox" id="'.$id.'"'.
      ($fill[$i]['data'][$j]==1 ? ' checked' : '').' onclick="check(\''.$id.'\',event);">';
    }
    else {
     echo ($fill[$i]['data'][$j]==1 ? 'x' : '&nbsp;');
    }
   }
   else echo '>&nbsp;';
   echo '</td>'."\n";
  }
  echo '</tr>'."\n";
 }
 echo '</table>'."\n";
 echo '<form method="post"><p>'."\n";
 if (isset($_SESSION['admin']) and $_SESSION['admin'] === md5($password)) {
  echo '<input type="hidden" name="password" value="">'."\n".
   '<input type="submit" name="exitme" value="Выйти">'."\n";
 }
 else {
  echo 'Пароль для изменения: <input type="password" name="password" size="16" maxlength="32" value="">'."\n".
   '<input type="submit" name="admin" value="Войти">'."\n";
 }
 echo '</p></form>'."\n";
?>
</body></html>

13.05.2021, 17:14 [281 просмотр]


теги: числа список php программирование textprocessing учебное