up
This commit is contained in:
@@ -0,0 +1,143 @@
|
||||
<?php
|
||||
/**
|
||||
* Simple MediaService
|
||||
* - fetchFromGraph(mediaId) -> gets Graph API URL and downloads
|
||||
* - storeContent($bytes, $destPath)
|
||||
* - createThumbnail($srcPath, $thumbPath)
|
||||
*/
|
||||
class MediaService {
|
||||
private $token;
|
||||
private $apiUrl;
|
||||
private $uploadsDir;
|
||||
|
||||
public function __construct() {
|
||||
$this->token = getConfigFromDB('whatsapp_token', '');
|
||||
$this->apiUrl = rtrim(getConfigFromDB('whatsapp_api_url', 'https://graph.facebook.com/v22.0/'), '/');
|
||||
$this->uploadsDir = __DIR__ . '/../uploads/media';
|
||||
if (!is_dir($this->uploadsDir)) mkdir($this->uploadsDir, 0755, true);
|
||||
}
|
||||
|
||||
public function fetchAndStoreFromGraph($mediaId, $subdir = '') {
|
||||
// Obtener metadata (url)
|
||||
$endpoint = "{$this->apiUrl}/{$mediaId}";
|
||||
$ch = curl_init();
|
||||
curl_setopt_array($ch, [
|
||||
CURLOPT_URL => $endpoint,
|
||||
CURLOPT_RETURNTRANSFER => true,
|
||||
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $this->token],
|
||||
CURLOPT_TIMEOUT => 15
|
||||
]);
|
||||
$resp = curl_exec($ch);
|
||||
$http = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||
$err = curl_error($ch);
|
||||
curl_close($ch);
|
||||
|
||||
if ($err || $http >= 400) {
|
||||
throw new Exception('Graph API fetch failed: ' . $err);
|
||||
}
|
||||
$decoded = json_decode($resp, true);
|
||||
$mediaUrl = $decoded['url'] ?? ($decoded['data'][0]['url'] ?? null);
|
||||
if (!$mediaUrl) throw new Exception('No media url from Graph');
|
||||
|
||||
// Descargar contenido (primer intento)
|
||||
$content = $this->downloadUrl($mediaUrl);
|
||||
if ($content === false) {
|
||||
// Reintentar con header Referer (algunos endpoints requieren referer)
|
||||
$content = $this->downloadUrl($mediaUrl, ['Referer: https://graph.facebook.com']);
|
||||
}
|
||||
if ($content === false) throw new Exception('Failed to download media content from ' . $mediaUrl);
|
||||
|
||||
// Detectar extension desde mime o url
|
||||
$mime = $decoded['mime_type'] ?? null;
|
||||
$ext = $this->extensionFromMime($mime) ?: pathinfo(parse_url($mediaUrl, PHP_URL_PATH), PATHINFO_EXTENSION) ?: 'bin';
|
||||
|
||||
$dir = $this->uploadsDir . ($subdir ? '/' . trim($subdir, '/') : '');
|
||||
if (!is_dir($dir)) mkdir($dir, 0755, true);
|
||||
|
||||
$filename = uniqid('m_') . '.' . $ext;
|
||||
$fullPath = $dir . '/' . $filename;
|
||||
file_put_contents($fullPath, $content);
|
||||
|
||||
$result = ['local_file' => 'uploads/media' . ($subdir ? '/' . trim($subdir, '/') : '') . '/' . $filename, 'mime_type' => $mime, 'size' => filesize($fullPath)];
|
||||
|
||||
// Si es imagen, generar miniatura
|
||||
if ($this->isImageMime($mime) || preg_match('#^jpe?g|png|gif$#i', $ext)) {
|
||||
$thumbPath = $dir . '/thumb_' . $filename . '.jpg';
|
||||
$thumbRel = dirname($result['local_file']) . '/thumb_' . $filename . '.jpg';
|
||||
if ($this->createThumbnail($fullPath, $thumbPath)) {
|
||||
$result['local_thumb'] = $thumbRel;
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function downloadUrl($url, $extraHeaders = []) {
|
||||
// Incluir Authorization Bearer si está configurado (necesario para algunos endpoints)
|
||||
$authHeader = [];
|
||||
if (!empty($this->token)) {
|
||||
$authHeader[] = 'Authorization: Bearer ' . $this->token;
|
||||
}
|
||||
$headers = array_merge(['User-Agent: WhatsAppMediaFetcher/1.0', 'Accept: */*'], $authHeader, $extraHeaders);
|
||||
|
||||
$ch = curl_init();
|
||||
curl_setopt_array($ch, [
|
||||
CURLOPT_URL => $url,
|
||||
CURLOPT_RETURNTRANSFER => true,
|
||||
CURLOPT_FOLLOWLOCATION => true,
|
||||
CURLOPT_TIMEOUT => 30,
|
||||
CURLOPT_HTTPHEADER => $headers,
|
||||
]);
|
||||
$content = curl_exec($ch);
|
||||
$err = curl_error($ch);
|
||||
$http = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||
curl_close($ch);
|
||||
if ($err || $http >= 400) return false;
|
||||
return $content;
|
||||
}
|
||||
|
||||
public function extensionFromMime($mime) {
|
||||
if (!$mime) return null;
|
||||
$map = [
|
||||
'image/jpeg' => 'jpg',
|
||||
'image/png' => 'png',
|
||||
'image/gif' => 'gif',
|
||||
'audio/mpeg' => 'mp3',
|
||||
'audio/ogg' => 'ogg',
|
||||
'video/mp4' => 'mp4',
|
||||
'text/csv' => 'csv',
|
||||
'application/pdf' => 'pdf'
|
||||
];
|
||||
return $map[$mime] ?? null;
|
||||
}
|
||||
|
||||
public function isImageMime($mime) {
|
||||
return strpos($mime, 'image/') === 0;
|
||||
}
|
||||
|
||||
public function createThumbnail($src, $dest, $maxW = 400, $maxH = 400) {
|
||||
if (!function_exists('getimagesize')) return false;
|
||||
$info = @getimagesize($src);
|
||||
if (!$info) return false;
|
||||
list($w, $h) = $info;
|
||||
$mime = $info['mime'];
|
||||
|
||||
switch ($mime) {
|
||||
case 'image/jpeg': $srcImg = imagecreatefromjpeg($src); break;
|
||||
case 'image/png': $srcImg = imagecreatefrompng($src); break;
|
||||
case 'image/gif': $srcImg = imagecreatefromgif($src); break;
|
||||
default: return false;
|
||||
}
|
||||
|
||||
$ratio = min($maxW / $w, $maxH / $h, 1);
|
||||
$nw = (int)($w * $ratio);
|
||||
$nh = (int)($h * $ratio);
|
||||
|
||||
$thumb = imagecreatetruecolor($nw, $nh);
|
||||
imagecopyresampled($thumb, $srcImg, 0,0,0,0, $nw, $nh, $w, $h);
|
||||
imagejpeg($thumb, $dest, 85);
|
||||
imagedestroy($thumb);
|
||||
imagedestroy($srcImg);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user