payfrit-api/api/auth/avatar.php
John Mizerek 4a4a098551 Fix upload paths to use Lucee webroot and accept uppercase OTP keys
Upload endpoints were saving files to PHP's DOCUMENT_ROOT instead of
the Lucee webroot where the Android app loads them from. Also fix
verifyLoginOTP and verifyOTP to accept both UUID/OTP and uuid/otp keys.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-14 22:04:27 -07:00

113 lines
3.5 KiB
PHP

<?php
require_once __DIR__ . '/../helpers.php';
runAuth();
/*
Avatar Upload/Get API
GET: Returns avatar URL for authenticated user
POST: Uploads new avatar image (multipart form data)
Stores images as: /uploads/users/{UserID}.jpg
*/
global $userId;
if ($userId <= 0) {
apiAbort(['OK' => false, 'ERROR' => 'not_logged_in', 'MESSAGE' => 'Authentication required']);
}
$webroot = isDev()
? '/opt/lucee/tomcat/webapps/ROOT'
: '/var/www/biz.payfrit.com';
$uploadsDir = $webroot . '/uploads/users';
$avatarUrl = baseUrl() . '/uploads/users/';
// Find existing avatar (check multiple extensions)
function findAvatarFile(string $dir, int $uid): ?string {
foreach (['jpg', 'jpeg', 'png', 'gif', 'webp'] as $ext) {
$path = "$dir/$uid.$ext";
if (file_exists($path)) return $path;
}
return null;
}
$existingAvatar = findAvatarFile($uploadsDir, $userId);
// GET — return current avatar URL
if ($_SERVER['REQUEST_METHOD'] === 'GET') {
$hasAvatar = $existingAvatar !== null;
$filename = $hasAvatar ? basename($existingAvatar) : '';
jsonResponse([
'OK' => true,
'HAS_AVATAR' => $hasAvatar,
'AVATAR_URL' => $hasAvatar ? $avatarUrl . $filename . '?t=' . time() : '',
]);
}
// POST — upload new avatar
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
if (!isset($_FILES['avatar']) || $_FILES['avatar']['error'] !== UPLOAD_ERR_OK) {
apiAbort(['OK' => false, 'ERROR' => 'missing_file', 'MESSAGE' => 'No avatar file provided']);
}
$file = $_FILES['avatar'];
$allowed = ['image/jpeg', 'image/png', 'image/gif', 'image/webp'];
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$mime = finfo_file($finfo, $file['tmp_name']);
finfo_close($finfo);
if (!in_array($mime, $allowed, true)) {
apiAbort(['OK' => false, 'ERROR' => 'invalid_type', 'MESSAGE' => 'Only JPEG, PNG, GIF, or WebP images are accepted']);
}
if (!is_dir($uploadsDir)) {
mkdir($uploadsDir, 0755, true);
}
$destPath = "$uploadsDir/$userId.jpg";
// Load, resize, and save as JPEG
$img = match ($mime) {
'image/jpeg' => imagecreatefromjpeg($file['tmp_name']),
'image/png' => imagecreatefrompng($file['tmp_name']),
'image/gif' => imagecreatefromgif($file['tmp_name']),
'image/webp' => imagecreatefromwebp($file['tmp_name']),
};
if ($img) {
$w = imagesx($img);
$h = imagesy($img);
if ($w > 500 || $h > 500) {
$ratio = min(500 / $w, 500 / $h);
$newW = (int) ($w * $ratio);
$newH = (int) ($h * $ratio);
$resized = imagecreatetruecolor($newW, $newH);
imagecopyresampled($resized, $img, 0, 0, 0, 0, $newW, $newH, $w, $h);
imagedestroy($img);
$img = $resized;
}
imagejpeg($img, $destPath, 85);
imagedestroy($img);
} else {
// Fallback: just move the file
move_uploaded_file($file['tmp_name'], $destPath);
}
// Delete old avatar with different extension
if ($existingAvatar && $existingAvatar !== $destPath && file_exists($existingAvatar)) {
unlink($existingAvatar);
}
// Update DB
queryTimed("UPDATE Users SET ImageExtension = 'jpg' WHERE ID = ?", [$userId]);
jsonResponse([
'OK' => true,
'MESSAGE' => 'Avatar uploaded successfully',
'AVATAR_URL' => $avatarUrl . $userId . '.jpg?t=' . time(),
]);
}
apiAbort(['OK' => false, 'ERROR' => 'bad_method', 'MESSAGE' => 'Use GET or POST']);