query("SELECT * FROM categories ORDER BY name"); $categories = $stmt->fetchAll(PDO::FETCH_ASSOC); if ($_SERVER['REQUEST_METHOD'] === 'POST') { // Sanitize and validate inputs $title = trim($_POST['title'] ?? ''); $description = trim($_POST['description'] ?? ''); $min_players = filter_input(INPUT_POST, 'min_players', FILTER_VALIDATE_INT); $max_players = filter_input(INPUT_POST, 'max_players', FILTER_VALIDATE_INT); $age_group = trim($_POST['age_group'] ?? ''); $skill_focus = trim($_POST['skill_focus'] ?? ''); $difficulty = trim($_POST['difficulty'] ?? ''); $duration_minutes = filter_input(INPUT_POST, 'duration_minutes', FILTER_VALIDATE_INT); $equipment_required = trim($_POST['equipment_required'] ?? ''); $youtube_url = filter_input(INPUT_POST, 'youtube_url', FILTER_VALIDATE_URL); $is_public = isset($_POST['is_public']) ? 1 : 0; $selected_categories = $_POST['categories'] ?? []; $image_path = null; // Basic validation if (empty($title)) $errors[] = 'Title is required.'; if (empty($description)) $errors[] = 'Description is required.'; if ($min_players === false || $min_players < 1) $errors[] = 'Minimum players must be a positive number.'; if ($max_players === false || $max_players < $min_players) $errors[] = 'Maximum players must be greater than or equal to minimum players.'; if (!in_array($age_group, $age_groups)) $errors[] = 'Invalid age group selected.'; if (!in_array($skill_focus, $skill_focuses)) $errors[] = 'Invalid skill focus selected.'; if (!in_array($difficulty, $difficulties)) $errors[] = 'Invalid difficulty selected.'; if ($duration_minutes === false || $duration_minutes < 1) $errors[] = 'Duration must be a positive number.'; if ($youtube_url === false && !empty($_POST['youtube_url'])) $errors[] = 'YouTube URL is not a valid URL.'; if (empty($selected_categories)) $errors[] = 'At least one category must be selected.'; // Image upload handling if (isset($_FILES['drill_image']) && $_FILES['drill_image']['error'] === UPLOAD_ERR_OK) { $upload_dir = __DIR__ . '/assets/images/drills/'; if (!is_dir($upload_dir)) { mkdir($upload_dir, 0775, true); } $file = $_FILES['drill_image']; $file_ext = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION)); $allowed_exts = ['jpg', 'jpeg', 'png', 'gif']; if (in_array($file_ext, $allowed_exts)) { if ($file['size'] <= 5 * 1024 * 1024) { // 5MB limit $new_filename = uniqid('', true) . '.' . $file_ext; $destination = $upload_dir . $new_filename; if (move_uploaded_file($file['tmp_name'], $destination)) { $image_path = '/assets/images/drills/' . $new_filename; } else { $errors[] = 'Failed to move uploaded file.'; } } else { $errors[] = 'File is too large. Maximum size is 5MB.'; } } else { $errors[] = 'Invalid file type. Only JPG, JPEG, PNG, and GIF are allowed.'; } } if (empty($errors)) { try { $pdo->beginTransaction(); $stmt = $pdo->prepare( 'INSERT INTO drills (title, description, min_players, max_players, age_group, skill_focus, difficulty, duration_minutes, equipment_required, youtube_url, is_public, coach_id, image_path) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)' ); $coach_id = get_user_id(); $stmt->execute([ $title, $description, $min_players, $max_players, $age_group, $skill_focus, $difficulty, $duration_minutes, $equipment_required, $youtube_url ?: null, $is_public, $coach_id, $image_path ]); $newDrillId = $pdo->lastInsertId(); // Insert into drill_categories $stmt = $pdo->prepare('INSERT INTO drill_categories (drill_id, category_id) VALUES (?, ?)'); foreach ($selected_categories as $category_id) { $stmt->execute([$newDrillId, $category_id]); } $pdo->commit(); // Redirect to the new drill page header("Location: drill.php?id=" . $newDrillId . "&created=true"); exit; } catch (PDOException $e) { $pdo->rollBack(); // In a real app, log this error instead of displaying it $errors[] = "Database error: " . $e->getMessage(); } } } ?>

Create a New Drill

Contribute to the Drillex collection by adding your own drill.

Please fix the following errors:

Upload an image for the drill (JPG, PNG, GIF - max 5MB).
Select one or more categories (hold Ctrl or Cmd to select multiple).