310 lines
11 KiB
PHP
310 lines
11 KiB
PHP
<?php
|
|
/**
|
|
* API - Subir foto de perfil de WhatsApp Business
|
|
*
|
|
* Flujo correcto (Resumable Upload API de Facebook):
|
|
* 1. Crear sesión de upload → obtiene upload_session_id
|
|
* 2. Subir el archivo binario → obtiene file handle (h:...)
|
|
* 3. Actualizar perfil con ese handle
|
|
*/
|
|
|
|
require_once '../config/config.php';
|
|
|
|
header('Content-Type: application/json; charset=utf-8');
|
|
|
|
requireAuthentication();
|
|
|
|
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
|
|
echo json_encode(['success' => false, 'error' => 'Método no permitido']);
|
|
exit;
|
|
}
|
|
|
|
if (empty($_FILES['photo']) || $_FILES['photo']['error'] !== UPLOAD_ERR_OK) {
|
|
$code = $_FILES['photo']['error'] ?? -1;
|
|
echo json_encode(['success' => false, 'error' => "No se recibió archivo válido (código {$code})"]);
|
|
exit;
|
|
}
|
|
|
|
$file = $_FILES['photo'];
|
|
|
|
// Validar tipo MIME
|
|
$allowedMimes = ['image/jpeg', 'image/png'];
|
|
$finfo = new finfo(FILEINFO_MIME_TYPE);
|
|
$mime = $finfo->file($file['tmp_name']);
|
|
if (!in_array($mime, $allowedMimes, true)) {
|
|
echo json_encode(['success' => false, 'error' => 'Solo se permiten imágenes JPG o PNG']);
|
|
exit;
|
|
}
|
|
|
|
// Validar tamaño (máx 5 MB)
|
|
if ($file['size'] > 5 * 1024 * 1024) {
|
|
echo json_encode(['success' => false, 'error' => 'La imagen no puede superar 5 MB']);
|
|
exit;
|
|
}
|
|
|
|
try {
|
|
$config = getWhatsAppConfigFromDB();
|
|
$token = $config['token'] ?? '';
|
|
$phoneId = $config['phone_number_id'] ?? '';
|
|
|
|
// Extraer versión de la API URL (ej. v22.0)
|
|
$apiUrl = rtrim($config['api_url'] ?: 'https://graph.facebook.com/v22.0/', '/');
|
|
$apiVersion = 'v22.0';
|
|
if (preg_match('#/(v\d+\.\d+)#', $apiUrl, $m)) {
|
|
$apiVersion = $m[1];
|
|
}
|
|
|
|
if (empty($token) || empty($phoneId)) {
|
|
echo json_encode(['success' => false, 'error' => 'Token o Phone Number ID no configurado']);
|
|
exit;
|
|
}
|
|
|
|
$fileSize = $file['size'];
|
|
$fileName = basename($file['name']);
|
|
|
|
// ── Paso 1: Crear sesión de upload ────────────────────────────────────────
|
|
// POST https://graph.facebook.com/{version}/app/uploads
|
|
$sessionUrl = "https://graph.facebook.com/{$apiVersion}/app/uploads?"
|
|
. http_build_query([
|
|
'file_name' => $fileName,
|
|
'file_length' => $fileSize,
|
|
'file_type' => $mime,
|
|
'access_token'=> $token,
|
|
]);
|
|
|
|
$ch = curl_init();
|
|
curl_setopt_array($ch, [
|
|
CURLOPT_URL => $sessionUrl,
|
|
CURLOPT_RETURNTRANSFER => true,
|
|
CURLOPT_POST => true,
|
|
CURLOPT_POSTFIELDS => '',
|
|
CURLOPT_TIMEOUT => 20,
|
|
CURLOPT_IPRESOLVE => CURL_IPRESOLVE_V4,
|
|
CURLOPT_SSLVERSION => CURL_SSLVERSION_TLSv1_2,
|
|
]);
|
|
|
|
$sessionResp = curl_exec($ch);
|
|
$sessionCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
|
$sessionErr = curl_error($ch);
|
|
curl_close($ch);
|
|
|
|
if ($sessionErr) throw new Exception("Error creando sesión de upload: {$sessionErr}");
|
|
|
|
$sessionData = json_decode($sessionResp, true);
|
|
if ($sessionCode !== 200 || empty($sessionData['id'])) {
|
|
$msg = $sessionData['error']['message'] ?? $sessionResp;
|
|
throw new Exception("Sesión upload error ({$sessionCode}): {$msg}");
|
|
}
|
|
|
|
$uploadSessionId = $sessionData['id'];
|
|
|
|
// ── Paso 2: Subir el archivo binario ──────────────────────────────────────
|
|
// POST https://graph.facebook.com/{version}/{upload_session_id}
|
|
$fileContent = file_get_contents($file['tmp_name']);
|
|
if ($fileContent === false) throw new Exception("No se pudo leer el archivo temporal");
|
|
|
|
$uploadUrl = "https://graph.facebook.com/{$apiVersion}/{$uploadSessionId}";
|
|
|
|
$ch2 = curl_init();
|
|
curl_setopt_array($ch2, [
|
|
CURLOPT_URL => $uploadUrl,
|
|
CURLOPT_RETURNTRANSFER => true,
|
|
CURLOPT_POST => true,
|
|
CURLOPT_POSTFIELDS => $fileContent,
|
|
CURLOPT_HTTPHEADER => [
|
|
"Authorization: OAuth {$token}",
|
|
"Content-Type: {$mime}",
|
|
"file_offset: 0",
|
|
],
|
|
CURLOPT_TIMEOUT => 60,
|
|
CURLOPT_IPRESOLVE => CURL_IPRESOLVE_V4,
|
|
CURLOPT_SSLVERSION => CURL_SSLVERSION_TLSv1_2,
|
|
]);
|
|
|
|
$uploadResp = curl_exec($ch2);
|
|
$uploadCode = curl_getinfo($ch2, CURLINFO_HTTP_CODE);
|
|
$uploadErr = curl_error($ch2);
|
|
curl_close($ch2);
|
|
|
|
if ($uploadErr) throw new Exception("Error subiendo archivo: {$uploadErr}");
|
|
|
|
$uploadData = json_decode($uploadResp, true);
|
|
if ($uploadCode !== 200 || empty($uploadData['h'])) {
|
|
$msg = $uploadData['error']['message'] ?? $uploadResp;
|
|
throw new Exception("Upload file error ({$uploadCode}): {$msg}");
|
|
}
|
|
|
|
$fileHandle = $uploadData['h']; // ej. "h:abc123..."
|
|
|
|
// ── Paso 3: Aplicar la foto al perfil ─────────────────────────────────────
|
|
$profileUrl = "{$apiUrl}/{$phoneId}/whatsapp_business_profile";
|
|
|
|
$payload = [
|
|
'messaging_product' => 'whatsapp',
|
|
'profile_picture_handle' => $fileHandle,
|
|
];
|
|
|
|
$ch3 = curl_init();
|
|
curl_setopt_array($ch3, [
|
|
CURLOPT_URL => $profileUrl,
|
|
CURLOPT_RETURNTRANSFER => true,
|
|
CURLOPT_POST => true,
|
|
CURLOPT_POSTFIELDS => json_encode($payload),
|
|
CURLOPT_HTTPHEADER => [
|
|
"Authorization: Bearer {$token}",
|
|
"Content-Type: application/json",
|
|
],
|
|
CURLOPT_TIMEOUT => 20,
|
|
CURLOPT_IPRESOLVE => CURL_IPRESOLVE_V4,
|
|
CURLOPT_SSLVERSION => CURL_SSLVERSION_TLSv1_2,
|
|
]);
|
|
|
|
$profileResp = curl_exec($ch3);
|
|
$profileCode = curl_getinfo($ch3, CURLINFO_HTTP_CODE);
|
|
$profileErr = curl_error($ch3);
|
|
curl_close($ch3);
|
|
|
|
if ($profileErr) throw new Exception("Error actualizando foto: {$profileErr}");
|
|
|
|
$profileData = json_decode($profileResp, true);
|
|
if ($profileCode !== 200) {
|
|
$msg = $profileData['error']['message'] ?? $profileResp;
|
|
throw new Exception("Profile photo error ({$profileCode}): {$msg}");
|
|
}
|
|
|
|
echo json_encode(['success' => true, 'message' => 'Foto de perfil actualizada correctamente']);
|
|
|
|
} catch (Exception $e) {
|
|
error_log('[upload_whatsapp_profile_photo] ' . $e->getMessage());
|
|
echo json_encode(['success' => false, 'error' => $e->getMessage()]);
|
|
}
|
|
|
|
|
|
require_once '../config/config.php';
|
|
|
|
header('Content-Type: application/json; charset=utf-8');
|
|
|
|
requireAuthentication();
|
|
|
|
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
|
|
echo json_encode(['success' => false, 'error' => 'Método no permitido']);
|
|
exit;
|
|
}
|
|
|
|
if (empty($_FILES['photo']) || $_FILES['photo']['error'] !== UPLOAD_ERR_OK) {
|
|
$code = $_FILES['photo']['error'] ?? -1;
|
|
echo json_encode(['success' => false, 'error' => "No se recibió archivo válido (código {$code})"]);
|
|
exit;
|
|
}
|
|
|
|
$file = $_FILES['photo'];
|
|
|
|
// Validar tipo MIME
|
|
$allowedMimes = ['image/jpeg', 'image/png'];
|
|
$finfo = new finfo(FILEINFO_MIME_TYPE);
|
|
$mime = $finfo->file($file['tmp_name']);
|
|
if (!in_array($mime, $allowedMimes, true)) {
|
|
echo json_encode(['success' => false, 'error' => 'Solo se permiten imágenes JPG o PNG']);
|
|
exit;
|
|
}
|
|
|
|
// Validar tamaño (máx 5 MB)
|
|
if ($file['size'] > 5 * 1024 * 1024) {
|
|
echo json_encode(['success' => false, 'error' => 'La imagen no puede superar 5 MB']);
|
|
exit;
|
|
}
|
|
|
|
try {
|
|
$config = getWhatsAppConfigFromDB();
|
|
$token = $config['token'] ?? '';
|
|
$phoneId = $config['phone_number_id'] ?? '';
|
|
$apiUrl = rtrim($config['api_url'] ?: 'https://graph.facebook.com/v22.0/', '/');
|
|
|
|
if (empty($token) || empty($phoneId)) {
|
|
echo json_encode(['success' => false, 'error' => 'Token o Phone Number ID no configurado']);
|
|
exit;
|
|
}
|
|
|
|
// ── Paso 1: subir la imagen como media ───────────────────────────────────
|
|
$uploadUrl = "{$apiUrl}/{$phoneId}/media";
|
|
|
|
$cfile = new CURLFile($file['tmp_name'], $mime, basename($file['name']));
|
|
|
|
$ch = curl_init();
|
|
curl_setopt_array($ch, [
|
|
CURLOPT_URL => $uploadUrl,
|
|
CURLOPT_RETURNTRANSFER => true,
|
|
CURLOPT_POST => true,
|
|
CURLOPT_POSTFIELDS => [
|
|
'messaging_product' => 'whatsapp',
|
|
'file' => $cfile,
|
|
'type' => $mime,
|
|
],
|
|
CURLOPT_HTTPHEADER => ["Authorization: Bearer {$token}"],
|
|
CURLOPT_TIMEOUT => 30,
|
|
CURLOPT_IPRESOLVE => CURL_IPRESOLVE_V4,
|
|
CURLOPT_SSLVERSION => CURL_SSLVERSION_TLSv1_2,
|
|
]);
|
|
|
|
$uploadResponse = curl_exec($ch);
|
|
$uploadCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
|
$uploadError = curl_error($ch);
|
|
curl_close($ch);
|
|
|
|
if ($uploadError) {
|
|
throw new Exception("Error al subir imagen: {$uploadError}");
|
|
}
|
|
|
|
$uploadData = json_decode($uploadResponse, true);
|
|
if ($uploadCode !== 200 || empty($uploadData['id'])) {
|
|
$msg = $uploadData['error']['message'] ?? 'Error desconocido al subir';
|
|
throw new Exception("Upload error ({$uploadCode}): {$msg}");
|
|
}
|
|
|
|
$mediaHandle = $uploadData['id'];
|
|
|
|
// ── Paso 2: actualizar la foto de perfil con el handle ───────────────────
|
|
$profileUrl = "{$apiUrl}/{$phoneId}/whatsapp_business_profile";
|
|
|
|
$payload = [
|
|
'messaging_product' => 'whatsapp',
|
|
'profile_picture_handle' => $mediaHandle,
|
|
];
|
|
|
|
$ch2 = curl_init();
|
|
curl_setopt_array($ch2, [
|
|
CURLOPT_URL => $profileUrl,
|
|
CURLOPT_RETURNTRANSFER => true,
|
|
CURLOPT_POST => true,
|
|
CURLOPT_POSTFIELDS => json_encode($payload),
|
|
CURLOPT_HTTPHEADER => [
|
|
"Authorization: Bearer {$token}",
|
|
"Content-Type: application/json",
|
|
],
|
|
CURLOPT_TIMEOUT => 20,
|
|
CURLOPT_IPRESOLVE => CURL_IPRESOLVE_V4,
|
|
CURLOPT_SSLVERSION => CURL_SSLVERSION_TLSv1_2,
|
|
]);
|
|
|
|
$profileResponse = curl_exec($ch2);
|
|
$profileCode = curl_getinfo($ch2, CURLINFO_HTTP_CODE);
|
|
$profileError = curl_error($ch2);
|
|
curl_close($ch2);
|
|
|
|
if ($profileError) {
|
|
throw new Exception("Error al actualizar foto: {$profileError}");
|
|
}
|
|
|
|
$profileData = json_decode($profileResponse, true);
|
|
if ($profileCode !== 200) {
|
|
$msg = $profileData['error']['message'] ?? 'Error desconocido al actualizar foto';
|
|
throw new Exception("Profile photo error ({$profileCode}): {$msg}");
|
|
}
|
|
|
|
echo json_encode(['success' => true, 'message' => 'Foto de perfil actualizada correctamente']);
|
|
|
|
} catch (Exception $e) {
|
|
error_log('[upload_whatsapp_profile_photo] ' . $e->getMessage());
|
|
echo json_encode(['success' => false, 'error' => $e->getMessage()]);
|
|
}
|