![]() Server : Apache/2 System : Linux server-15-235-50-60 5.15.0-164-generic #174-Ubuntu SMP Fri Nov 14 20:25:16 UTC 2025 x86_64 User : gositeme ( 1004) PHP Version : 8.2.29 Disable Function : exec,system,passthru,shell_exec,proc_close,proc_open,dl,popen,show_source,posix_kill,posix_mkfifo,posix_getpwuid,posix_setpgid,posix_setsid,posix_setuid,posix_setgid,posix_seteuid,posix_setegid,posix_uname Directory : /home/gositeme/domains/soundstudiopro.com/public_html/api/ |
<?php
session_start();
header('Content-Type: application/json');
// Check if user is logged in
if (!isset($_SESSION['user_id'])) {
echo json_encode([
'success' => false,
'message' => 'User not logged in'
]);
exit;
}
// SECURITY: Validate and sanitize track_id parameter
$track_id_raw = $_GET['track_id'] ?? null;
if (!$track_id_raw) {
echo json_encode([
'success' => false,
'message' => 'Track ID required'
]);
exit;
}
// SECURITY: Validate that track_id is a positive integer
if (!is_numeric($track_id_raw) || (int)$track_id_raw <= 0) {
error_log("SECURITY: Invalid track_id attempt in check_track_status.php: " . htmlspecialchars($track_id_raw, ENT_QUOTES, 'UTF-8'));
echo json_encode([
'success' => false,
'message' => 'Invalid track ID'
]);
exit;
}
$track_id = (int)$track_id_raw;
try {
require_once '../config/database.php';
$pdo = getDBConnection();
// Get track from database
$stmt = $pdo->prepare("
SELECT id, title, prompt, status, audio_url, duration, created_at, api_task_id, task_id, metadata
FROM music_tracks
WHERE id = ? AND user_id = ?
");
$stmt->execute([$track_id, $_SESSION['user_id']]);
$track = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$track) {
echo json_encode([
'success' => false,
'message' => 'Track not found'
]);
exit;
}
// Extract error message from metadata if track is failed
$error_message = null;
if ($track['status'] === 'failed' && !empty($track['metadata'])) {
$metadata = json_decode($track['metadata'], true);
if ($metadata) {
$raw_message = $metadata['msg'] ??
$metadata['error'] ??
$metadata['error_msg'] ??
$metadata['message'] ??
null;
// Format error message - ONLY remove API.Box references, keep exact error
if ($raw_message) {
// Remove any references to API.Box or supplier names ONLY
$raw_message = preg_replace('/\b(API\.Box|api\.box|API\.box|not found on API\.Box|not found in API\.Box|Task not found in API\.Box|Track.*not found on API\.Box)\b/i', '', $raw_message);
$raw_message = trim($raw_message);
// Clean up multiple spaces
$raw_message = preg_replace('/\s+/', ' ', $raw_message);
// Check if this is actually a success message (not an error)
$is_success_message = preg_match('/\b(successfully|success|complete|done|ready|finished)\b/i', $raw_message);
// Only treat as error if it's NOT a success message
if (!$is_success_message && !empty($raw_message)) {
$error_message = $raw_message;
}
// If it's a success message, leave $error_message as null (don't show anything)
// Special handling for timeout errors (override any previous assignment)
if (isset($metadata['code']) && $metadata['code'] == 408) {
$error_message = "Track generation timed out after 5 minutes. Please try again.";
}
}
// If no error message found and track is failed, use default
// But only if we didn't find a success message (which would leave $error_message as null)
if ($error_message === null && empty($raw_message ?? null) && $track['status'] === 'failed') {
$error_message = "Track generation failed. Please try again.";
}
}
}
// If track is processing and has API task ID, ALWAYS check service status
// This ensures we catch failures even if callback wasn't received
$task_id_to_check = $track['task_id'] ?? $track['api_task_id'] ?? null;
$force_check = isset($_GET['force_check']) && $_GET['force_check'] == '1';
if (($track['status'] === 'processing' || $force_check) && !empty($task_id_to_check) && $task_id_to_check !== 'unknown' && !str_starts_with($task_id_to_check, 'temp_') && !str_starts_with($task_id_to_check, 'retry_')) {
$api_key = '63edba40620216c5aa2c04240ac41dbd';
$api_url = 'https://api.api.box/api/v1/status/' . $task_id_to_check;
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $api_url);
curl_setopt($ch, CURLOPT_HTTPGET, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Authorization: Bearer ' . $api_key,
'Content-Type: application/json',
'User-Agent: SoundStudioPro/1.0'
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
$response = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($http_code === 200 && $response) {
$api_data = json_decode($response, true);
if ($api_data) {
// Check for error codes first (most reliable indicator)
$has_error_code = isset($api_data['code']) && ($api_data['code'] == 400 || $api_data['code'] == 531 || $api_data['code'] >= 400);
$has_error_message = !empty($api_data['error']) || !empty($api_data['msg']) || !empty($api_data['error_msg']);
$api_status = $api_data['status'] ?? null;
// Determine if this is a failure
$is_failed = false;
$api_error_msg = null;
$error_code = null;
if ($has_error_code) {
$is_failed = true;
$error_code = $api_data['code'];
$api_error_msg = $api_data['msg'] ?? $api_data['error'] ?? $api_data['error_msg'] ?? 'Generation failed';
} elseif ($api_status === 'failed' || $api_status === 'error' || $api_status === 'rejected') {
$is_failed = true;
$api_error_msg = $api_data['error'] ?? $api_data['msg'] ?? $api_data['error_msg'] ?? 'Generation failed';
$error_code = $api_data['code'] ?? 531;
} elseif ($has_error_message && ($api_status === null || $api_status === 'processing')) {
// If we have an error message but status is still processing, it likely failed
// Check if there's a clear error indicator
$temp_error_msg = $api_data['error'] ?? $api_data['msg'] ?? $api_data['error_msg'] ?? '';
$error_text = strtolower($temp_error_msg);
if (strpos($error_text, 'failed') !== false ||
strpos($error_text, 'error') !== false ||
strpos($error_text, 'violation') !== false ||
strpos($error_text, 'rejected') !== false ||
strpos($error_text, 'contained artist name') !== false ||
strpos($error_text, 'song description') !== false) {
$is_failed = true;
$api_error_msg = $temp_error_msg ?: 'Generation failed';
$error_code = $api_data['code'] ?? 400; // Default to 400 for content violations
}
}
// Also check for content violation patterns in the response
if (!$is_failed && !empty($api_data['msg'])) {
$msg_lower = strtolower($api_data['msg']);
if (strpos($msg_lower, 'contained artist name') !== false ||
strpos($msg_lower, 'song description') !== false ||
strpos($msg_lower, 'content violation') !== false) {
$is_failed = true;
$api_error_msg = $api_data['msg'];
$error_code = 400; // Content violation
}
}
// Map API.Box status to our status
$new_status = $track['status']; // Default to current status
if ($is_failed) {
$new_status = 'failed';
// Extract error message from API response
if (!$api_error_msg) {
$api_error_msg = $api_data['error'] ?? $api_data['msg'] ?? $api_data['error_msg'] ?? 'Generation failed';
}
// Sanitize error message - remove any references to API.Box or supplier names
$api_error_msg = preg_replace('/\b(API\.Box|api\.box|API\.box|not found on API\.Box|not found in API\.Box|Task not found in API\.Box|Track.*not found on API\.Box)\b/i', '', $api_error_msg);
$api_error_msg = trim($api_error_msg);
if (empty($api_error_msg)) {
$api_error_msg = 'Generation failed';
}
$error_metadata = json_encode([
'code' => $error_code ?? 531,
'msg' => $api_error_msg,
'error_type' => ($error_code == 400) ? 'content_violation' : 'generation_failed',
'data' => $api_data,
'timestamp' => date('Y-m-d H:i:s'),
'detected_via' => 'status_check'
]);
// Update database with failed status and error metadata
$update_stmt = $pdo->prepare("
UPDATE music_tracks
SET status = ?, metadata = ?, updated_at = NOW()
WHERE id = ?
");
$update_stmt->execute([$new_status, $error_metadata, $track_id]);
// Refund credit for failed track
$refund_stmt = $pdo->prepare("UPDATE users SET credits = credits + 1 WHERE id = ?");
$refund_stmt->execute([$_SESSION['user_id']]);
// Record refund transaction (check if already exists)
$check_stmt = $pdo->prepare("SELECT COUNT(*) FROM credit_transactions WHERE user_id = ? AND type = 'refund' AND description LIKE ?");
$check_stmt->execute([$_SESSION['user_id'], "%Track failed: {$track_id}%"]);
if ($check_stmt->fetchColumn() == 0) {
$trans_stmt = $pdo->prepare("
INSERT INTO credit_transactions (user_id, amount, type, description, created_at)
VALUES (?, 1, 'refund', 'Track failed: {$track_id}', NOW())
");
$trans_stmt->execute([$_SESSION['user_id']]);
}
$track['status'] = $new_status;
$track['metadata'] = $error_metadata;
$error_message = $api_error_msg;
error_log("✅ Track $track_id marked as FAILED via status check. Error: $api_error_msg (Code: " . ($error_code ?? 'N/A') . ")");
} elseif ($api_status === 'completed' || $api_status === 'complete') {
// Check if we have audio URL or complete metadata
$audioUrl = $api_data['result']['audio_url'] ??
$api_data['data']['data'][0]['audio_url'] ??
$api_data['data']['data'][0]['source_audio_url'] ??
$api_data['data']['data'][0]['stream_audio_url'] ?? null;
// Extract metadata to check if track is ready
$title = $api_data['result']['title'] ??
$api_data['data']['data'][0]['title'] ??
$api_data['title'] ?? null;
$duration = $api_data['result']['duration'] ??
$api_data['data']['data'][0]['duration'] ??
$api_data['duration'] ?? null;
$tags = $api_data['result']['tags'] ??
$api_data['data']['data'][0]['tags'] ??
$api_data['tags'] ?? null;
$modelName = $api_data['result']['model_name'] ??
$api_data['data']['data'][0]['model_name'] ??
$api_data['model_name'] ?? null;
// Mark as complete if we have audio URL OR complete metadata (matching callback logic)
$hasAudio = !empty($audioUrl);
$hasCompleteMetadata = !empty($title) && !empty($duration) && (!empty($tags) || !empty($modelName));
if ($hasAudio || $hasCompleteMetadata) {
$new_status = 'complete';
// Update database with new status
$update_stmt = $pdo->prepare("
UPDATE music_tracks
SET status = ?, updated_at = NOW()
" . ($hasAudio ? ", audio_url = ?, duration = ?" : "") . "
WHERE id = ?
");
if ($hasAudio) {
$update_stmt->execute([
$new_status,
$audioUrl,
$duration,
$track_id
]);
$track['audio_url'] = $audioUrl;
$track['duration'] = $duration;
} else {
$update_stmt->execute([
$new_status,
$track_id
]);
}
$track['status'] = $new_status;
error_log("✅ Track $track_id marked as COMPLETE via status check. Has audio: " . ($hasAudio ? 'YES' : 'NO') . ", Has metadata: " . ($hasCompleteMetadata ? 'YES' : 'NO'));
}
}
// Log the status check
error_log("Track $track_id: Service status = " . ($api_status ?? 'N/A') . ", Local status = $new_status, Has error code = " . ($has_error_code ? 'YES' : 'NO'));
} else {
error_log("⚠️ Track $track_id: Service returned invalid JSON response");
}
} else {
error_log("Service check failed for track $track_id: HTTP $http_code" . ($response ? " - Response: " . substr($response, 0, 200) : ""));
// If API check failed but track is still processing, check task_results file
if ($track['status'] === 'processing' && !empty($task_id_to_check)) {
$taskResultFile = "../task_results/{$task_id_to_check}.json";
if (file_exists($taskResultFile)) {
$taskResultData = json_decode(file_get_contents($taskResultFile), true);
if ($taskResultData) {
// Check if we have audio URL or complete metadata in task_results
$audioUrl = null;
$title = null;
$duration = null;
$tags = null;
$modelName = null;
if (isset($taskResultData['data']['data']) && is_array($taskResultData['data']['data'])) {
foreach ($taskResultData['data']['data'] as $item) {
if (!$audioUrl) {
$audioUrl = (!empty($item['audio_url'])) ? $item['audio_url'] :
((!empty($item['source_audio_url'])) ? $item['source_audio_url'] :
((!empty($item['stream_audio_url'])) ? $item['stream_audio_url'] : null));
}
if (!$title && !empty($item['title'])) {
$title = $item['title'];
}
if (!$duration && !empty($item['duration'])) {
$duration = $item['duration'];
}
if (!$tags && !empty($item['tags'])) {
$tags = $item['tags'];
}
if (!$modelName && !empty($item['model_name'])) {
$modelName = $item['model_name'];
}
}
}
// Mark as complete if we have audio URL OR complete metadata
$hasAudio = !empty($audioUrl);
$hasCompleteMetadata = !empty($title) && !empty($duration) && (!empty($tags) || !empty($modelName));
if ($hasAudio || $hasCompleteMetadata) {
$new_status = 'complete';
$update_stmt = $pdo->prepare("
UPDATE music_tracks
SET status = ?, updated_at = NOW()
" . ($hasAudio ? ", audio_url = ?, duration = ?" : "") . "
WHERE id = ?
");
if ($hasAudio) {
$update_stmt->execute([
$new_status,
$audioUrl,
$duration,
$track_id
]);
$track['audio_url'] = $audioUrl;
$track['duration'] = $duration;
} else {
$update_stmt->execute([
$new_status,
$track_id
]);
}
$track['status'] = $new_status;
error_log("✅ Track $track_id marked as COMPLETE via task_results check. Has audio: " . ($hasAudio ? 'YES' : 'NO') . ", Has metadata: " . ($hasCompleteMetadata ? 'YES' : 'NO'));
}
}
}
}
}
}
// Prepare response data
$response_data = $track;
if ($error_message) {
$response_data['error_message'] = $error_message;
}
echo json_encode([
'success' => true,
'status' => $track['status'],
'data' => $response_data
]);
} catch (Exception $e) {
error_log("Track status check error: " . $e->getMessage());
echo json_encode([
'success' => false,
'message' => 'Database error occurred'
]);
}
?>