Show sourcecode
The following files exists in this folder. Click to view.
admin_data.php
complete_session.php
export_csv.php
save_maze.php
save_reaction.php
save_simon.php
start_session.php
admin_data.php
173 lines ASCII Unix (LF)
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
<?php
session_start();
if (empty($_SESSION['admin_logged_in'])) {
http_response_code(403);
header('Content-Type: application/json');
echo json_encode(['error' => 'Unauthorized']);
exit;
}
require __DIR__ . '/../config.php';
$pdo = getDB();
// --- Fetch all data ---
$participants = $pdo->query("
SELECT p.id, p.email, p.group_type, p.created_at, p.completed_at
FROM participants p
ORDER BY p.created_at DESC
")->fetchAll();
$reactions = $pdo->query("
SELECT r.participant_id, p.group_type, r.round_number, r.reaction_ms, r.was_premature, r.delay_ms
FROM reaction_times r
JOIN participants p ON p.id = r.participant_id
ORDER BY r.participant_id, r.round_number
")->fetchAll();
$mazes = $pdo->query("
SELECT m.participant_id, p.group_type, m.total_time_ms, m.total_moves
FROM maze_results m
JOIN participants p ON p.id = m.participant_id
ORDER BY m.participant_id
")->fetchAll();
$simons = $pdo->query("
SELECT s.participant_id, p.group_type, s.max_level, s.total_time_ms
FROM simon_results s
JOIN participants p ON p.id = s.participant_id
ORDER BY s.participant_id
")->fetchAll();
$simonRounds = $pdo->query("
SELECT sr.participant_id, sr.level_number, sr.success, sr.response_times_json
FROM simon_rounds sr
ORDER BY sr.participant_id, sr.level_number
")->fetchAll();
// --- Build per-participant data structure ---
$participantData = [];
foreach ($participants as $p) {
$participantData[$p['id']] = [
'id' => $p['id'],
'email' => $p['email'],
'group' => $p['group_type'],
'created_at' => $p['created_at'],
'completed_at' => $p['completed_at'],
'reaction_rounds' => [],
'reaction_avg' => null,
'reaction_best' => null,
'maze' => null,
'simon' => null,
'simon_rounds' => [],
];
}
foreach ($reactions as $r) {
$pid = $r['participant_id'];
if (!isset($participantData[$pid])) continue;
$participantData[$pid]['reaction_rounds'][] = $r;
}
foreach ($participantData as $pid => &$pd) {
$valid = array_filter($pd['reaction_rounds'], fn($r) => !$r['was_premature']);
if (count($valid) > 0) {
$times = array_column($valid, 'reaction_ms');
$pd['reaction_avg'] = round(array_sum($times) / count($times));
$pd['reaction_best'] = min($times);
}
}
unset($pd);
foreach ($mazes as $m) {
$pid = $m['participant_id'];
if (!isset($participantData[$pid])) continue;
$participantData[$pid]['maze'] = $m;
}
foreach ($simons as $s) {
$pid = $s['participant_id'];
if (!isset($participantData[$pid])) continue;
$participantData[$pid]['simon'] = $s;
}
foreach ($simonRounds as $sr) {
$pid = $sr['participant_id'];
if (!isset($participantData[$pid])) continue;
$participantData[$pid]['simon_rounds'][] = $sr;
}
// --- Build chart data ---
$reactionByGroup = ['placebo' => [], 'control' => []];
$mazeTimeByGroup = ['placebo' => [], 'control' => []];
$mazeMovesByGroup = ['placebo' => [], 'control' => []];
$simonByGroup = ['placebo' => [], 'control' => []];
foreach ($participantData as $pid => $pd) {
$g = $pd['group'];
if ($pd['reaction_avg'] !== null) {
$reactionByGroup[$g][] = $pd['reaction_avg'];
}
if ($pd['maze']) {
$mazeTimeByGroup[$g][] = round($pd['maze']['total_time_ms'] / 1000, 1);
$mazeMovesByGroup[$g][] = (int)$pd['maze']['total_moves'];
}
if ($pd['simon']) {
$simonByGroup[$g][] = (int)$pd['simon']['max_level'];
}
}
function groupAvg($arr) {
return count($arr) > 0 ? round(array_sum($arr) / count($arr), 1) : 0;
}
// Leaderboards
$leaderboardPlacebo = [];
$leaderboardControl = [];
foreach ($participantData as $pid => $pd) {
if ($pd['reaction_avg'] === null) continue;
$entry = ['email' => $pd['email'], 'avg' => $pd['reaction_avg']];
if ($pd['group'] === 'placebo') {
$leaderboardPlacebo[] = $entry;
} else {
$leaderboardControl[] = $entry;
}
}
usort($leaderboardPlacebo, fn($a, $b) => $a['avg'] - $b['avg']);
usort($leaderboardControl, fn($a, $b) => $a['avg'] - $b['avg']);
// Groups for participant lists
$groups = ['placebo' => [], 'control' => []];
foreach ($participantData as $pid => $pd) {
$groups[$pd['group']][] = $pd;
}
$totalParticipants = count($participants);
$completedCount = count(array_filter($participants, fn($p) => $p['completed_at'] !== null));
header('Content-Type: application/json');
echo json_encode([
'summary' => [
'total_participants' => $totalParticipants,
'completed' => $completedCount,
'reaction_avg_placebo' => groupAvg($reactionByGroup['placebo']),
'reaction_avg_control' => groupAvg($reactionByGroup['control']),
'simon_avg_placebo' => groupAvg($simonByGroup['placebo']),
'simon_avg_control' => groupAvg($simonByGroup['control']),
'maze_time_avg_placebo' => groupAvg($mazeTimeByGroup['placebo']),
'maze_time_avg_control' => groupAvg($mazeTimeByGroup['control']),
'maze_moves_avg_placebo' => groupAvg($mazeMovesByGroup['placebo']),
'maze_moves_avg_control' => groupAvg($mazeMovesByGroup['control']),
],
'charts' => [
'reaction_by_group' => $reactionByGroup,
'maze_time_by_group' => $mazeTimeByGroup,
'maze_moves_by_group' => $mazeMovesByGroup,
'simon_by_group' => $simonByGroup,
],
'leaderboard_placebo' => array_values($leaderboardPlacebo),
'leaderboard_control' => array_values($leaderboardControl),
'groups' => $groups,
]);