如何修改PHP JSON API以支持含文件的CURL上传请求?
Alright, let's tackle this problem head-on. Your existing PHP API handles JSON-only requests and stores data in a database, but now you need it to accept both JSON data and file uploads (like a profile picture) via PHP CURL calls. Here's a practical, secure solution that maintains backward compatibility:
1. Modify the API Endpoint to Handle Multipart Requests
File uploads require the multipart/form-data content type—you can't send files in a pure JSON request. We'll adjust the API to accept JSON as a form field alongside the file, while keeping support for your original JSON-only requests.
Here's the updated API code:
<?php // Set response headers header("Access-Control-Allow-Origin: *"); // Optional, if you need CORS support header("Content-Type: application/json"); if ($_SERVER['REQUEST_METHOD'] !== 'POST') { echo json_encode(['error' => 'Only POST requests are allowed']); exit; } // Determine request type to maintain backward compatibility $contentType = $_SERVER['CONTENT_TYPE'] ?? ''; if (str_starts_with($contentType, 'application/json')) { // Original JSON-only handling (for existing requests) $jsonData = json_decode(file_get_contents('php://input'), true); if (json_last_error() !== JSON_ERROR_NONE) { echo json_encode(['error' => 'Invalid JSON data']); exit; } // Your existing logic to store JSON data in the database goes here echo json_encode(['success' => true, 'message' => 'JSON data saved']); } elseif (str_starts_with($contentType, 'multipart/form-data')) { // Handle JSON + File upload // 1. Parse JSON data from form field if (!isset($_POST['json_data'])) { echo json_encode(['error' => 'JSON data field is missing']); exit; } $jsonData = json_decode($_POST['json_data'], true); if (json_last_error() !== JSON_ERROR_NONE) { echo json_encode(['error' => 'Invalid JSON data in form field']); exit; } // 2. Handle file upload if (!isset($_FILES['profile_picture'])) { echo json_encode(['error' => 'Profile picture file is missing']); exit; } $file = $_FILES['profile_picture']; if ($file['error'] !== UPLOAD_ERR_OK) { $errorMessages = [ UPLOAD_ERR_INI_SIZE => 'File exceeds server upload limit', UPLOAD_ERR_FORM_SIZE => 'File exceeds request upload limit', UPLOAD_ERR_PARTIAL => 'File was only partially uploaded', UPLOAD_ERR_NO_FILE => 'No file was selected', UPLOAD_ERR_NO_TMP_DIR => 'Temporary upload directory missing', UPLOAD_ERR_CANT_WRITE => 'Failed to write file to disk', UPLOAD_ERR_EXTENSION => 'File upload blocked by extension' ]; $errorMsg = $errorMessages[$file['error']] ?? 'Unknown upload error'; echo json_encode(['error' => $errorMsg]); exit; } // Validate file type (adjust allowed types as needed) $allowedMimes = ['image/jpeg', 'image/png', 'image/gif']; $fileMime = mime_content_type($file['tmp_name']); if (!in_array($fileMime, $allowedMimes)) { echo json_encode(['error' => 'Invalid file type. Only JPG, PNG, GIF are allowed.']); exit; } // Validate file size (e.g., max 5MB) $maxSize = 5 * 1024 * 1024; // 5MB if ($file['size'] > $maxSize) { echo json_encode(['error' => 'File size exceeds 5MB limit']); exit; } // Move file to permanent storage $uploadDir = './uploads/'; if (!is_dir($uploadDir)) { mkdir($uploadDir, 0755, true); // Create directory if it doesn't exist } $fileName = uniqid('profile_') . '_' . basename($file['name']); $targetPath = $uploadDir . $fileName; if (!move_uploaded_file($file['tmp_name'], $targetPath)) { echo json_encode(['error' => 'Failed to save uploaded file']); exit; } // 3. Store JSON data + file path in database // Example using PDO (replace with your DB logic) // $pdo = new PDO('mysql:host=localhost;dbname=your_db', 'username', 'password'); // $stmt = $pdo->prepare("INSERT INTO users (name, email, profile_pic_path) VALUES (?, ?, ?)"); // $stmt->execute([$jsonData['name'], $jsonData['email'], $fileName]); // Return success response echo json_encode([ 'success' => true, 'message' => 'Data and file uploaded successfully', 'profile_picture_path' => $fileName ]); } else { echo json_encode(['error' => 'Unsupported Content-Type. Use application/json or multipart/form-data']); } ?>
2. PHP CURL Call to Send JSON + File
Here's how to send the combined request from your PHP client using CURL. We'll use CURLFile to attach the file and pass the JSON data as a form field:
<?php // Sample JSON data to send $userData = [ 'name' => 'Shan Biswas', 'email' => 'shan@example.com', 'bio' => 'Web developer' ]; // Path to the profile picture file $picturePath = './path/to/your/profile.jpg'; // Prepare multipart form data $postFields = [ 'json_data' => json_encode($userData), 'profile_picture' => new CURLFile($picturePath) ]; // Initialize CURL $ch = curl_init(); // Set CURL options curl_setopt($ch, CURLOPT_URL, 'https://your-api-domain.com/your-endpoint.php'); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, $postFields); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); // No need to manually set Content-Type: CURL automatically handles this for multipart data // Execute the request $response = curl_exec($ch); $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); // Handle response if ($response === false) { echo 'CURL Error: ' . curl_error($ch); } else { $responseData = json_decode($response, true); if ($httpCode === 200 && $responseData['success']) { echo "Success! Profile picture saved as: " . $responseData['profile_picture_path']; } else { echo "Error: " . ($responseData['error'] ?? 'Unknown error'); } } // Cleanup curl_close($ch); ?>
Key Security & Reliability Tips
- File Validation: Always check file type with
mime_content_type(don't trust file extensions) and enforce size limits to prevent abuse. - Backward Compatibility: The API still supports pure JSON requests, so your existing CURL calls won't break.
- File Storage: Store uploaded files outside the web root if possible, or restrict access via
.htaccessto prevent execution of malicious files. - Database Safety: Use prepared statements when inserting data into your database to avoid SQL injection.
内容的提问来源于stack exchange,提问作者Shan Biswas

