Przejdź do głównej zawartości

Aplikacja ankietowa (XML/JSON)

Stworzycie Aplikację ankietową - system webowy do przeprowadzania ankiet i głosowań. Użytkownicy mogą oddawać głosy na wybrane odpowiedzi, a system zlicza wyniki i prezentuje je w formie procentowej lub liczbowej. To świetny projekt do nauki pracy z danymi i wizualizacji statystyk.

Czego się nauczycie?

  • Obsługi formularzy z polami typu radio
  • Zliczania i agregacji danych (statystyki)
  • Wizualizacji wyników (procenty, wykresy CSS)
  • Blokowania wielokrotnego głosowania (sesje)
  • Praca zespołowa - podział zadań, współpraca, integracja kodu

W prawdziwej firmie...

Systemy ankietowe są wszędzie - od badań satysfakcji klienta, przez głosowania pracownicze, po sondaże wyborcze. Google Forms, SurveyMonkey, Typeform - wszystkie opierają się na podobnych koncepcjach. Umiejętność tworzenia takich systemów to cenny skill.

Umiejętności rynkowe

Nauczycie się agregować dane i prezentować statystyki - kluczowa umiejętność w analityce i dashboardach. Zrozumiecie też mechanizmy ochrony przed manipulacją wyników (blokada wielokrotnego głosowania).

  1. Wyświetlanie ankiety System prezentuje pytanie wraz z listą możliwych odpowiedzi. Użytkownik wybiera jedną opcję za pomocą pól radio i zatwierdza swój głos przyciskiem.

  2. Walidacja i zapis głosu System sprawdza, czy użytkownik wybrał odpowiedź i czy nie głosował już wcześniej (sesja). Poprawny głos zwiększa licznik wybranej odpowiedzi w pliku JSON.

  3. Prezentacja wyników Po oddaniu głosu (lub na osobnej stronie) użytkownik widzi aktualne wyniki - liczbę głosów i procenty dla każdej odpowiedzi. Wyniki mogą być wizualizowane paskami CSS.

  4. Zarządzanie ankietą (B/C) W wyższych wariantach administrator może edytować pytania, dodawać nowe odpowiedzi lub resetować wyniki głosowania.

Strona ankiety

  • Pytanie ankietowe
  • Lista odpowiedzi (radio buttons)
  • Przycisk “Zagłosuj”
  • Komunikaty o błędach

Wyniki głosowania

  • Lista odpowiedzi z licznikami
  • Procenty dla każdej opcji
  • Paski wizualizacji (CSS)
  • Suma wszystkich głosów

Potwierdzenie głosu

  • Komunikat o zapisaniu głosu
  • Link do wyników
  • Informacja o wybranej opcji

Panel admina (C)

  • Edycja pytania/odpowiedzi
  • Reset wyników
  • Statystyki głosowania

Przykładowa struktura pliku JSON (ankieta + wyniki):

{
"poll": {
"id": 1,
"question": "Jaki jest Twój ulubiony język programowania?",
"created_at": "2026-02-13 10:00:00"
},
"options": [
{ "id": "a", "text": "PHP", "votes": 15 },
{ "id": "b", "text": "JavaScript", "votes": 23 },
{ "id": "c", "text": "Python", "votes": 18 },
{ "id": "d", "text": "Java", "votes": 8 }
],
"total_votes": 64
}

Alternatywnie - format XML (wariant C):

<?xml version="1.0" encoding="UTF-8"?>
<poll id="1" created="2026-02-13">
<question>Jaki jest Twój ulubiony język programowania?</question>
<options>
<option id="a" votes="15">PHP</option>
<option id="b" votes="23">JavaScript</option>
<option id="c" votes="18">Python</option>
<option id="d" votes="8">Java</option>
</options>
</poll>

Wymagane funkcjonalności:

  • Wyświetlanie pytania z odpowiedziami (radio buttons)
  • Walidacja PHP - sprawdzenie czy wybrano odpowiedź
  • Minimum 1 walidacja JavaScript (np. czy zaznaczono opcję)
  • Zapis głosu do pliku JSON (zwiększenie licznika)
  • Wyświetlanie wyników (liczby i procenty)
  • Komunikaty o błędach i potwierdzenie głosu
  • Podstawowa wizualizacja wyników

Struktura plików:

  • Folderprojekt/
    • index.php (ankieta + głosowanie)
    • results.php (wyniki)
    • README.md
    • Folderdata/
      • poll.json
    • Foldercss/
      • style.css
    • Folderjs/
      • validation.js
Ocena: 3.0
  1. Użytkownik otwiera stronę ankiety
  2. Widzi pytanie “Jaki jest Twój ulubiony język programowania?”
  3. Zaznacza opcję “JavaScript”
  4. Klika przycisk “Zagłosuj”
  5. System waliduje wybór i zapisuje głos do JSON
  6. Użytkownik widzi potwierdzenie i aktualne wyniki
  7. JavaScript ma teraz 24 głosy (wzrost o 1)

Scenariusz 2: Próba ponownego głosowania (wariant B+)

Dział zatytułowany „Scenariusz 2: Próba ponownego głosowania (wariant B+)”
  1. Użytkownik już zagłosował w tej sesji
  2. Próbuje ponownie oddać głos
  3. System sprawdza sesję i wykrywa flagę voted=true
  4. Wyświetla komunikat “Już oddałeś głos w tej ankiecie”
  5. Przekierowuje do strony wyników
  1. Admin loguje się do panelu
  2. Widzi aktualną ankietę z wynikami
  3. Dodaje nową opcję “TypeScript”
  4. Zapisuje zmiany
  5. Nowa opcja pojawia się w ankiecie z licznikiem 0
  6. Dotychczasowe głosy pozostają bez zmian

Zapis głosu do JSON:

<?php
function addVote(string $optionId): bool {
$filePath = 'data/poll.json';
$data = json_decode(file_get_contents($filePath), true);
foreach ($data['options'] as &$option) {
if ($option['id'] === $optionId) {
$option['votes']++;
$data['total_votes']++;
return file_put_contents(
$filePath,
json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE),
LOCK_EX
) !== false;
}
}
return false;
}
// Użycie:
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['option'])) {
$optionId = $_POST['option'];
if (addVote($optionId)) {
$_SESSION['voted'] = true;
header('Location: results.php');
exit;
}
}

Obliczanie procentów:

<?php
function calculatePercentages(array $options, int $total): array {
if ($total === 0) {
return array_map(fn($o) => ['option' => $o, 'percent' => 0], $options);
}
return array_map(function($option) use ($total) {
return [
'option' => $option,
'percent' => round(($option['votes'] / $total) * 100, 1)
];
}, $options);
}
// Użycie:
$data = json_decode(file_get_contents('data/poll.json'), true);
$results = calculatePercentages($data['options'], $data['total_votes']);
foreach ($results as $result) {
echo $result['option']['text'] . ': ' . $result['percent'] . '%';
}

Blokada ponownego głosowania (sesja):

<?php
session_start();
function hasVoted(): bool {
return isset($_SESSION['voted']) && $_SESSION['voted'] === true;
}
function markAsVoted(): void {
$_SESSION['voted'] = true;
}
// W obsłudze głosowania:
if (hasVoted()) {
$errors[] = 'Już oddałeś głos w tej ankiecie!';
} else {
addVote($_POST['option']);
markAsVoted();
}

Walidacja wyboru w JavaScript:

document.getElementById('pollForm').addEventListener('submit', function(e) {
const selected = document.querySelector('input[name="option"]:checked');
if (!selected) {
e.preventDefault();
alert('Musisz wybrać jedną z odpowiedzi!');
return false;
}
});

CSS dla pasków wyników:

.result-item {
margin-bottom: 16px;
}
.result-label {
display: flex;
justify-content: space-between;
margin-bottom: 4px;
font-weight: 500;
}
.result-bar-container {
background-color: #e5e7eb;
border-radius: 4px;
height: 24px;
overflow: hidden;
}
.result-bar {
background-color: #3b82f6;
height: 100%;
transition: width 0.5s ease;
border-radius: 4px;
}
.result-bar.winner {
background-color: #10b981;
}
.result-votes {
font-size: 0.85em;
color: #6b7280;
margin-top: 4px;
}

Obsługa XML (wariant C):

<?php
function loadPollFromXml(string $filePath): array {
$xml = simplexml_load_file($filePath);
$poll = [
'id' => (int) $xml['id'],
'question' => (string) $xml->question,
'options' => []
];
foreach ($xml->options->option as $option) {
$poll['options'][] = [
'id' => (string) $option['id'],
'text' => (string) $option,
'votes' => (int) $option['votes']
];
}
return $poll;
}
function savePollToXml(array $poll, string $filePath): bool {
$xml = new SimpleXMLElement('<?xml version="1.0" encoding="UTF-8"?><poll/>');
$xml->addAttribute('id', $poll['id']);
$xml->addChild('question', $poll['question']);
$options = $xml->addChild('options');
foreach ($poll['options'] as $opt) {
$option = $options->addChild('option', $opt['text']);
$option->addAttribute('id', $opt['id']);
$option->addAttribute('votes', $opt['votes']);
}
return $xml->asXML($filePath) !== false;
}

To prawdziwy projekt zespołowy!

Aplikacja ankietowa to świetny projekt do portfolio! Nauczycie się agregować dane, prezentować statystyki i chronić system przed manipulacją - umiejętności cenione w każdej firmie.

Pracujcie iteracyjnie - lepiej mieć działający wariant A niż niedziałający C!