Files
kupshop/bundles/KupShop/CDNBundle/Controller/CDNController.php
2025-08-02 16:30:27 +02:00

142 lines
4.1 KiB
PHP

<?php
namespace KupShop\CDNBundle\Controller;
use KupShop\KupShopBundle\Util\System\UrlFinder;
use Psr\Log\LoggerInterface;
use Query\Operator;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\EventListener\AbstractSessionListener;
use Symfony\Component\Routing\Annotation\Route;
class CDNController extends AbstractController
{
/** @var LoggerInterface */
protected $logger;
/**
* @required
*/
public function setLogger(LoggerInterface $logger): void
{
$this->logger = $logger;
}
/**
* @Route("/_cdn/", methods={"POST"})
*
* @return Response
*/
public function WebhookAction(Request $request)
{
if (0 === strpos($request->headers->get('Content-Type'), 'application/json')) {
$data = json_decode($request->getContent(), true);
$this->logger->notice('CDN Webhook Request', [
'url' => $request->getUri(),
'data' => $data,
]);
/* Status finished */
if ($data['Status'] === 3) {
$photo = sqlQueryBuilder()
->select('p.id id, p.filename, p.descr, v.id_cdn id_video')
->from('photos', 'p')
->innerJoin('p', 'videos', 'v', 'p.id = v.id_photo')
->where(Operator::equals(['id_cdn' => $data['VideoGuid']]))
->execute()
->fetch();
if ($photo) {
$img = new \Photos();
$img->newImage($photo['id']);
if (!$img->refreshVideoThumbnail($photo)) {
$this->logger->notice('CDN Webhook Failed', [
'url' => $request->getUri(),
'data' => $data,
]);
}
}
}
return new Response('OK', 200);
}
return new Response('', 400);
}
/**
* @Route("/_cdn/typekit/{id}")
*
* @return Response
*/
public function typekitAction(string $id, UrlFinder $urlFinder)
{
$url = "https://use.typekit.net/{$id}.css";
$response = $this->downloadToResponse($url);
$css = $response->getContent();
// Remove tracking url
$css = preg_replace('@^.*https://p\.typekit\.net.*$@m', '', $css);
if ($urlFinder->hasCDN()) {
// Replace font urls
$css = preg_replace('@https://use\.typekit\.net@m', $urlFinder->staticUrlAbsolute('/_cdn/font'), $css);
}
$response->setContent($css);
return $response;
}
/**
* @Route("/_cdn/font/{path}", requirements={"path":".*"})
*
* @return Response
*/
public function typekitFontAction(Request $request, string $path)
{
$url = "https://use.typekit.net/{$path}?{$request->getQueryString()}";
return $this->downloadToResponse($url);
}
protected function downloadToResponse(string $url): Response
{
$ch = curl_init();
$headers = [];
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
// this function is called by curl for each header received
curl_setopt($ch, CURLOPT_HEADERFUNCTION,
function ($curl, $header) use (&$headers) {
$len = strlen($header);
$header = explode(':', $header, 2);
if (count($header) < 2) { // ignore invalid headers
return $len;
}
$headers[strtolower(trim($header[0]))][] = trim($header[1]);
return $len;
}
);
$data = curl_exec($ch);
unset($headers['content-length']);
$response = new Response($data);
$response->headers->replace($headers);
// Force cacheable
$response->headers->set(AbstractSessionListener::NO_AUTO_CACHE_CONTROL_HEADER, 'true');
$response->setPublic();
$response->setMaxAge(3600);
return $response;
}
}