MAX_FILE_SIZE) { error('File too large. Max size: ' . (MAX_FILE_SIZE / 1024 / 1024) . 'MB'); } $ext = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION)); if (!in_array($ext, ALLOWED_EXTENSIONS)) { error('Invalid file type. Only PDF files allowed.'); } // Generate unique ID $job_id = uniqid('pdf_', true); $filename = $job_id . '.pdf'; $filepath = UPLOAD_DIR . '/' . $filename; // Move file if (!move_uploaded_file($file['tmp_name'], $filepath)) { error('Failed to save file'); } // Create job metadata $job_data = [ 'job_id' => $job_id, 'original_filename' => $file['name'], 'uploaded_at' => date('Y-m-d H:i:s'), 'file_size' => $file['size'], 'status' => 'uploaded', 'filepath' => $filepath ]; file_put_contents( RESULTS_DIR . '/' . $job_id . '.meta.json', json_encode($job_data, JSON_PRETTY_PRINT) ); success([ 'job_id' => $job_id, 'filename' => $file['name'], 'message' => 'File uploaded successfully' ]); } /** * Handle PDF accessibility check */ function handleCheck() { $job_id = $_POST['job_id'] ?? ''; if (empty($job_id)) { error('Job ID required'); } $meta_file = RESULTS_DIR . '/' . $job_id . '.meta.json'; if (!file_exists($meta_file)) { error('Job not found'); } $job_data = json_decode(file_get_contents($meta_file), true); // Build command - use venv Python with absolute path $pdf_path = $job_data['filepath']; $output_path = RESULTS_DIR . '/' . $job_id . '.result.json'; // Use absolute venv path for MAMP $venv_python = '/Users/daveporter/Desktop/CODING-2024/PDF-Accessibility-checker/venv/bin/python3'; $python_bin = file_exists($venv_python) ? $venv_python : 'python3'; $cmd = escapeshellcmd($python_bin . ' ' . PYTHON_SCRIPT) . ' ' . escapeshellarg($pdf_path) . ' ' . '--output ' . escapeshellarg($output_path); // Handle quick mode $quick_mode = $_POST['quick_mode'] ?? false; if ($quick_mode) { $cmd .= ' --quick'; } // Handle API keys - accept both formats $anthropic_key = $_POST['anthropic_key'] ?? getenv('ANTHROPIC_API_KEY'); $google_key = $_POST['google_key'] ?? $_POST['google_credentials'] ?? getenv('GOOGLE_API_KEY') ?? getenv('GOOGLE_APPLICATION_CREDENTIALS'); if ($anthropic_key) { $cmd .= ' --anthropic-key ' . escapeshellarg($anthropic_key); } if ($google_key) { // Check if it's a file path or an API key if (file_exists($google_key)) { // It's a JSON credentials file $cmd .= ' --google-credentials ' . escapeshellarg($google_key); } else { // It's an API key string $cmd .= ' --google-key ' . escapeshellarg($google_key); } } // Update status $job_data['status'] = 'processing'; $job_data['started_at'] = date('Y-m-d H:i:s'); $job_data['command'] = $cmd; // Store for debugging file_put_contents($meta_file, json_encode($job_data, JSON_PRETTY_PRINT)); // Log errors to a file for debugging $error_log = RESULTS_DIR . '/' . $job_id . '.error.log'; $cmd .= ' > ' . escapeshellarg($error_log) . ' 2>&1 &'; exec($cmd, $output, $return_code); success([ 'job_id' => $job_id, 'status' => 'processing', 'message' => 'Check started', 'debug' => [ 'command' => $cmd, 'return_code' => $return_code ] ]); } /** * Check job status */ function handleStatus() { $job_id = $_GET['job_id'] ?? ''; if (empty($job_id)) { error('Job ID required'); } $meta_file = RESULTS_DIR . '/' . $job_id . '.meta.json'; $result_file = RESULTS_DIR . '/' . $job_id . '.result.json'; $error_log = RESULTS_DIR . '/' . $job_id . '.error.log'; if (!file_exists($meta_file)) { error('Job not found'); } $job_data = json_decode(file_get_contents($meta_file), true); // Check if result exists if (file_exists($result_file)) { $job_data['status'] = 'completed'; $job_data['completed_at'] = date('Y-m-d H:i:s', filemtime($result_file)); // Update meta file_put_contents($meta_file, json_encode($job_data, JSON_PRETTY_PRINT)); } else if (file_exists($error_log)) { // Check if there are errors $error_content = file_get_contents($error_log); if (!empty($error_content) && $job_data['status'] == 'processing') { // Check if it's been more than 5 minutes $started = strtotime($job_data['started_at']); if (time() - $started > 300) { $job_data['status'] = 'failed'; $job_data['error'] = 'Process timeout or error'; $job_data['error_log'] = substr($error_content, -1000); // Last 1000 chars } } } success($job_data); } /** * Get check results */ function handleResult() { $job_id = $_GET['job_id'] ?? ''; if (empty($job_id)) { error('Job ID required'); } $result_file = RESULTS_DIR . '/' . $job_id . '.result.json'; if (!file_exists($result_file)) { error('Results not found. Check may still be processing.'); } $result = json_decode(file_get_contents($result_file), true); success($result); } /** * List all jobs */ function handleList() { $jobs = []; $files = glob(RESULTS_DIR . '/*.meta.json'); foreach ($files as $file) { $job_data = json_decode(file_get_contents($file), true); // Check if completed $result_file = str_replace('.meta.json', '.result.json', $file); if (file_exists($result_file)) { $job_data['status'] = 'completed'; } $jobs[] = $job_data; } // Sort by upload time (newest first) usort($jobs, function($a, $b) { return strtotime($b['uploaded_at']) - strtotime($a['uploaded_at']); }); success(['jobs' => $jobs]); } /** * Delete a job */ function handleDelete() { $job_id = $_POST['job_id'] ?? $_GET['job_id'] ?? ''; if (empty($job_id)) { error('Job ID required'); } $meta_file = RESULTS_DIR . '/' . $job_id . '.meta.json'; if (!file_exists($meta_file)) { error('Job not found'); } $job_data = json_decode(file_get_contents($meta_file), true); // Delete files @unlink($job_data['filepath']); @unlink($meta_file); @unlink(RESULTS_DIR . '/' . $job_id . '.result.json'); success(['message' => 'Job deleted']); } /** * Debug endpoint */ function handleDebug() { $job_id = $_GET['job_id'] ?? ''; if (empty($job_id)) { error('Job ID required'); } $meta_file = RESULTS_DIR . '/' . $job_id . '.meta.json'; $result_file = RESULTS_DIR . '/' . $job_id . '.result.json'; $error_log = RESULTS_DIR . '/' . $job_id . '.error.log'; $debug_info = [ 'job_id' => $job_id, 'meta_exists' => file_exists($meta_file), 'result_exists' => file_exists($result_file), 'error_log_exists' => file_exists($error_log), 'files' => [] ]; if (file_exists($meta_file)) { $debug_info['meta'] = json_decode(file_get_contents($meta_file), true); } if (file_exists($error_log)) { $debug_info['error_log'] = file_get_contents($error_log); } if (file_exists($result_file)) { $debug_info['result_size'] = filesize($result_file); } // Test Python $venv_python = '/Users/daveporter/Desktop/CODING-2024/PDF-Accessibility-checker/venv/bin/python3'; exec($venv_python . ' --version 2>&1', $python_version); $debug_info['python_version'] = implode("\n", $python_version); success($debug_info); } /** * Send success response */ function success($data) { echo json_encode([ 'success' => true, 'data' => $data ]); exit; } /** * Send error response */ function error($message) { http_response_code(400); echo json_encode([ 'success' => false, 'error' => $message ]); exit; }