Initial commit — Rosary Presenter App
Full source for loveandrosary.com: slide-based Rosary/novena/Divine Mercy Chaplet presentation tool with multi-user roles, SVG bead ring, audio uploads, donate strip, and public session profiles. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,100 @@
|
||||
<?php
|
||||
/**
|
||||
* api/upload_audio.php
|
||||
* POST: upload an audio file for a specific prayer key.
|
||||
* Admin only. Replaces any existing file for that key.
|
||||
*
|
||||
* POST params:
|
||||
* key — audio key string (alphanumeric + underscores)
|
||||
* audio — uploaded file (MP3, M4A, OGG, WAV)
|
||||
*
|
||||
* Returns JSON: {"key": "...", "ext": "mp3"} or {"error": "..."}
|
||||
*/
|
||||
require_once __DIR__ . '/../config/db.php';
|
||||
require_once __DIR__ . '/../includes/auth.php';
|
||||
|
||||
header('Content-Type: application/json');
|
||||
require_auth();
|
||||
|
||||
if (!has_role('admin')) {
|
||||
http_response_code(403);
|
||||
echo json_encode(['error' => 'Permission denied']);
|
||||
exit;
|
||||
}
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
|
||||
http_response_code(405);
|
||||
echo json_encode(['error' => 'Method not allowed']);
|
||||
exit;
|
||||
}
|
||||
|
||||
$key = trim($_POST['key'] ?? '');
|
||||
if (!preg_match('/^[a-z0-9_]+$/', $key) || strlen($key) > 100) {
|
||||
http_response_code(400);
|
||||
echo json_encode(['error' => 'Invalid audio key']);
|
||||
exit;
|
||||
}
|
||||
|
||||
if (!isset($_FILES['audio']) || $_FILES['audio']['error'] !== UPLOAD_ERR_OK) {
|
||||
$codes = [
|
||||
UPLOAD_ERR_INI_SIZE => 'File exceeds server limit',
|
||||
UPLOAD_ERR_FORM_SIZE => 'File exceeds form limit',
|
||||
UPLOAD_ERR_PARTIAL => 'File only partially uploaded',
|
||||
UPLOAD_ERR_NO_FILE => 'No file uploaded',
|
||||
];
|
||||
$code = $_FILES['audio']['error'] ?? UPLOAD_ERR_NO_FILE;
|
||||
http_response_code(400);
|
||||
echo json_encode(['error' => $codes[$code] ?? 'Upload error']);
|
||||
exit;
|
||||
}
|
||||
|
||||
$file = $_FILES['audio'];
|
||||
$max_size = 50 * 1024 * 1024; // 50 MB
|
||||
|
||||
if ($file['size'] > $max_size) {
|
||||
http_response_code(400);
|
||||
echo json_encode(['error' => 'File too large (max 50 MB)']);
|
||||
exit;
|
||||
}
|
||||
|
||||
$finfo = new finfo(FILEINFO_MIME_TYPE);
|
||||
$mime = $finfo->file($file['tmp_name']);
|
||||
$allowed = [
|
||||
'audio/mpeg' => 'mp3',
|
||||
'audio/mp3' => 'mp3',
|
||||
'audio/mp4' => 'm4a',
|
||||
'audio/x-m4a' => 'm4a',
|
||||
'audio/ogg' => 'ogg',
|
||||
'audio/wav' => 'wav',
|
||||
'audio/x-wav' => 'wav',
|
||||
'audio/wave' => 'wav',
|
||||
'audio/webm' => 'webm',
|
||||
];
|
||||
|
||||
if (!isset($allowed[$mime])) {
|
||||
http_response_code(400);
|
||||
echo json_encode(['error' => 'Invalid format. Allowed: MP3, M4A, OGG, WAV']);
|
||||
exit;
|
||||
}
|
||||
|
||||
$ext = $allowed[$mime];
|
||||
$audio_dir = UPLOADS_DIR . 'audio/';
|
||||
|
||||
if (!is_dir($audio_dir)) {
|
||||
mkdir($audio_dir, 0755, true);
|
||||
}
|
||||
|
||||
// Delete any existing file for this key (regardless of extension)
|
||||
foreach (glob($audio_dir . $key . '.*') ?: [] as $old) {
|
||||
unlink($old);
|
||||
}
|
||||
|
||||
$dest = $audio_dir . $key . '.' . $ext;
|
||||
|
||||
if (!move_uploaded_file($file['tmp_name'], $dest)) {
|
||||
http_response_code(500);
|
||||
echo json_encode(['error' => 'Failed to save file']);
|
||||
exit;
|
||||
}
|
||||
|
||||
echo json_encode(['key' => $key, 'ext' => $ext]);
|
||||
Reference in New Issue
Block a user