File: /home/xedaptot/ai.naniguide.com/app/Http/Controllers/Refactor/BuilderRssProxyController.php
<?php
namespace App\Http\Controllers\Refactor;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Http;
class BuilderRssProxyController extends Controller
{
/**
* Fetch and parse an RSS feed server-side (avoids CORS restrictions in the browser).
* Used by BuilderJS RSSElement.
*/
public function fetch(Request $request)
{
$url = $request->query('url');
if (!$url) {
return response()->json(['error' => 'RSS URL is required.'], 400);
}
if (!filter_var($url, FILTER_VALIDATE_URL)) {
return response()->json(['error' => 'Invalid RSS URL.'], 400);
}
try {
$response = Http::timeout(10)
->withUserAgent('Acelle RSS Reader/1.0')
->get($url);
if ($response->failed()) {
return response()->json(['error' => 'Failed to fetch RSS feed. Please check the URL.'], 502);
}
$content = $response->body();
libxml_use_internal_errors(true);
$xml = simplexml_load_string($content);
if ($xml === false) {
return response()->json(['error' => 'The URL does not contain a valid RSS feed.'], 422);
}
libxml_clear_errors();
$namespaces = $xml->getNamespaces(true);
$items = [];
// Handle RSS 2.0 and Atom
$feedItems = [];
if (isset($xml->channel->item)) {
$feedItems = $xml->channel->item;
} elseif (isset($xml->entry)) {
$feedItems = $xml->entry;
}
foreach ($feedItems as $item) {
try {
$title = (string) $item->title;
$link = (string) $item->link;
$rawDescription = (string) ($item->description ?? $item->summary ?? '');
$description = trim(strip_tags($rawDescription));
$pubDate = (string) ($item->pubDate ?? $item->published ?? $item->updated ?? '');
// Extract image
$image = null;
if (isset($namespaces['media'])) {
$media = $item->children($namespaces['media']);
if (isset($media->content)) {
$attrs = $media->content->attributes();
if (isset($attrs['url'])) {
$image = (string) $attrs['url'];
}
}
if (!$image && isset($media->thumbnail)) {
$attrs = $media->thumbnail->attributes();
if (isset($attrs['url'])) {
$image = (string) $attrs['url'];
}
}
}
if (!$image && isset($item->enclosure)) {
$encAttrs = $item->enclosure->attributes();
$encType = (string) ($encAttrs['type'] ?? '');
if (strpos($encType, 'image/') === 0 && isset($encAttrs['url'])) {
$image = (string) $encAttrs['url'];
}
}
if (!$image) {
$htmlContent = (string) ($item->description ?? '');
if (isset($namespaces['content'])) {
$contentNs = $item->children($namespaces['content']);
if (isset($contentNs->encoded)) {
$htmlContent = (string) $contentNs->encoded;
}
}
if (preg_match('/<img[^>]+src=["\']([^"\']+)["\']/i', $htmlContent, $matches)) {
$image = $matches[1];
}
}
// Extract author
$author = null;
if (isset($namespaces['dc'])) {
$dc = $item->children($namespaces['dc']);
if (isset($dc->creator) && (string) $dc->creator !== '') {
$author = (string) $dc->creator;
}
}
if (!$author && isset($item->author)) {
$authorVal = $item->author;
if (isset($authorVal->name)) {
$author = (string) $authorVal->name;
} else {
$author = (string) $authorVal;
}
}
// Extract categories
$categories = [];
if (isset($item->category)) {
foreach ($item->category as $cat) {
$catStr = trim((string) $cat);
if ($catStr !== '') {
$categories[] = $catStr;
}
}
}
// Handle Atom link (href attribute)
if (!$link && isset($item->link)) {
$linkAttrs = $item->link->attributes();
if (isset($linkAttrs['href'])) {
$link = (string) $linkAttrs['href'];
}
}
$items[] = [
'title' => $title,
'link' => $link,
'description' => $description,
'pubDate' => $pubDate,
'image' => $image,
'author' => $author,
'categories' => implode(', ', $categories),
];
} catch (\Exception $e) {
continue;
}
}
return response()->json(['items' => $items, 'count' => count($items)]);
} catch (\Exception $e) {
return response()->json(['error' => 'Failed to fetch RSS feed.'], 500);
}
}
}