Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
186 changes: 65 additions & 121 deletions index.php
Original file line number Diff line number Diff line change
@@ -1,126 +1,85 @@
<?php

class TDTCloudinaryForwarder
class CloudinaryForwarder
{
private $cloudName;
private $cloudMapping;
private $cloudUploadEndpoint;

private $resourceRequestURL;
private $resourceRequestRegex = "/wp-content\/uploads\/(.*?)\.(jpe?g|png|gif|webp|avif|tiff|mp4|webm|pdf)/i";

private $resourceName;
private $resourceExtension;
private $resourceSize;
private $resourceSize = ['width' => 0, 'height' => 0];

private $enableImgHeightVerify = false;
private $wp_image_sizes = [
'medium' => 300,
'large' => 1024,
'enigma-mobile' => 325,
'enigma-mobile-2x' => 650,
'enigma-mobile-3x' => 975,
'enigma-desktop' => 750,
'enigma-desktop-2x' => 1500,
'enigma-desktop-3x' => 2250,
];

// Constructor
public function __construct()
{
$this->cloudName = getenv('CLOUDINARY_CLOUD_NAME') ?: CLOUDINARY_CLOUD_NAME;
$this->cloudMapping = getenv('CLOUDINARY_CLOUD_MAPPING') ?: CLOUDINARY_CLOUD_MAPPING;
$this->cloudUploadEndpoint = 'https://res.cloudinary.com/' . $this->cloudName;
$this->cloudName = getenv('CLOUDINARY_CLOUD_NAME') ?: defined('CLOUDINARY_CLOUD_NAME') ? CLOUDINARY_CLOUD_NAME : '';
$this->cloudMapping = getenv('CLOUDINARY_CLOUD_MAPPING') ?: defined('CLOUDINARY_CLOUD_MAPPING') ? CLOUDINARY_CLOUD_MAPPING : '';

if (empty($this->cloudName) || empty($this->cloudMapping)) {
if (!$this->cloudName || !$this->cloudMapping) {
throw new Exception('Cloudinary configuration is missing');
}

$this->enableImgHeightVerify = false;
$this->cloudUploadEndpoint = 'https://res.cloudinary.com/' . $this->cloudName;

$this->getRequestedImg();
}

private function getRequestedURL($is_forwarded = false)
private function getRequestedURL($isForwarded = false)
{
$ssl = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on');
$port = $_SERVER['SERVER_PORT'];
$port = ((!$ssl && $port == '80') || ($ssl && $port == '443')) ? '' : ':' . $port;
$http_host = isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : null;
$host = ($is_forwarded && isset($_SERVER['HTTP_X_FORWARDED_HOST'])) ? $_SERVER['HTTP_X_FORWARDED_HOST'] : $http_host;
$host = isset($host) ? $host : $_SERVER['SERVER_NAME'] . $port;
return 'https://' . $host . $_SERVER['REQUEST_URI'];
$ssl = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on');
$port = ($_SERVER['SERVER_PORT'] != '80' && $_SERVER['SERVER_PORT'] != '443') ? ':' . $_SERVER['SERVER_PORT'] : '';
$host = $isForwarded && isset($_SERVER['HTTP_X_FORWARDED_HOST']) ? $_SERVER['HTTP_X_FORWARDED_HOST'] : $_SERVER['HTTP_HOST'];

return 'https://' . $host . $port . $_SERVER['REQUEST_URI'];
}

private function getCloudinaryURL()
{
// From /2022/01/cloudflare-chrome.png to tuandev-s3/2022/01/cloudflare-chrome.png
$theURL = $this->cloudMapping . '/' . $this->resourceName . '.' . $this->resourceExtension;

// From tuandev-s3/2022/01/cloudflare-chrome.png to f_auto/tuandev-s3/2022/01/cloudflare-chrome.png
$theURL = $this->getImageSizing() . $this->getImageFormatByAcceptHeader() . '/' . $theURL;

// Prepend /upload/ to the URL
$theURL = '/upload/' . $theURL;

$theURL = $this->cloudUploadEndpoint . ($this->isVideoRequest() ? '/video' : '/image') . $theURL;
$url = '/upload/' . $this->getImageSizing() . $this->getImageFormat() . '/' . $this->cloudMapping . '/' . $this->resourceName . '.' . $this->resourceExtension;

return $theURL;
return $this->cloudUploadEndpoint . ($this->isVideoRequest() ? '/video' : '/image') . $url;
}

private function isValidImageSize()
{
$wp_image_sizes = array(
'medium' => array(
'width' => 300,
),
'large' => array(
'width' => 1024,
),
'enigma-mobile' => array(
'width' => 325,
),
'enigma-mobile-2x' => array(
'width' => 650,
),
'enigma-mobile-3x' => array(
'width' => 975,
),
'enigma-desktop' => array(
'width' => 750,
),
'enigma-desktop-2x' => array(
'width' => 1500,
),
'enigma-desktop-3x' => array(
'width' => 2250,
),
);

// Check if match any in WordPress's registered size
foreach ($wp_image_sizes as $size => $size_info) {
if ($this->resourceSize['width'] == $size_info['width']) {
return true;
}

if ($this->enableImgHeightVerify && $this->resourceSize['height'] == $size_info['height']) {
return true;
}
}

return false;
return isset($this->wp_image_sizes[$this->resourceSize['width']]);
}

private function getImageSizing()
{
if ($this->isResizeRequest() === false) {
if (!$this->isResizeRequest()) {
return '';
}

$sizing = '';
$sizing .= $this->resourceSize['width'] > 0 ? ',w_' . $this->resourceSize['width'] : '';
$sizing .= ($this->enableImgHeightVerify && $this->resourceSize['height'] > 0) ? ',h_' . $this->resourceSize['height'] : '';
$sizing = 'c_scale';
$sizing .= $this->resourceSize['width'] ? ',w_' . $this->resourceSize['width'] : '';
$sizing .= $this->enableImgHeightVerify && $this->resourceSize['height'] ? ',h_' . $this->resourceSize['height'] : '';

return 'c_scale' . $sizing . '/';
return $sizing . '/';
}

private function getImageFormatByAcceptHeader()
private function getImageFormat()
{
if ($this->isVideoRequest()) {
return 'f_auto,q_auto';
}
return $this->CloudinaryMapByAcceptHeader();
}

private function CloudinaryMapByAcceptHeader()
{
switch (true) {
case $this->resourceExtension == 'gif':
return 'f_auto,q_auto:best';
Expand All @@ -137,34 +96,26 @@ private function getRequestedImg()
{
$this->resourceRequestURL = $this->getRequestedURL();

if (preg_match_all($this->resourceRequestRegex, $this->resourceRequestURL, $matches)) {
$this->resourceName = $matches[1][0];
if (preg_match($this->resourceRequestRegex, $this->resourceRequestURL, $matches)) {
$this->resourceName = $matches[1];
$this->resourceExtension = strtolower($matches[2]);

$this->resourceSize = [];
if (preg_match_all('/-([0-9]+)x([0-9]+)$/', $this->resourceName, $s_matches)) {
if (preg_match('/-([0-9]+)x([0-9]+)$/', $this->resourceName, $sizeMatches)) {
$this->resourceSize = [
'width' => $s_matches[1][0],
'height' => $s_matches[2][0]
'width' => $sizeMatches[1],
'height' => $sizeMatches[2]
];

if ($this->isValidImageSize() === false) {
if (!$this->isValidImageSize()) {
http_response_code(404);
die();
exit;
}

// To remove the size from the filename
$this->resourceName = preg_replace('/-([0-9]+)x([0-9]+)$/', '', $this->resourceName);
} else {
$this->resourceSize = [
'width' => 0,
'height' => 0
];
}

$this->resourceExtension = strtolower($matches[2][0]);
} else {
http_response_code(404);
die();
exit;
}
}

Expand All @@ -173,52 +124,45 @@ public function saveImg()
$ch = curl_init();
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'GET');
curl_setopt($ch, CURLOPT_URL, $this->getCloudinaryURL());
$response_headers = [];
curl_setopt(
$ch,
CURLOPT_HEADERFUNCTION,
function ($curl, $header) use (&$response_headers) {
$len = strlen($header);
$header = explode(':', $header, 2);
if (count($header) < 2) {
return $len;
}
$response_headers[strtolower(trim($header[0]))][] = trim($header[1]);

$responseHeaders = [];
curl_setopt($ch, CURLOPT_HEADERFUNCTION, function ($curl, $header) use (&$responseHeaders) {
$len = strlen($header);
$header = explode(':', $header, 2);
if (count($header) < 2) {
return $len;
}
);
$response_body = curl_exec($ch);
$response_code = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
$responseHeaders[strtolower(trim($header[0]))][] = trim($header[1]);
return $len;
});

$responseBody = curl_exec($ch);
$responseCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
http_response_code($response_code);
foreach ($response_headers as $name => $values) {

http_response_code($responseCode);
foreach ($responseHeaders as $name => $values) {
foreach ($values as $value) {
header($name . ': ' . $value);
}
}

header("x-service: cloudinary-forwarder");
echo $response_body;
echo $responseBody;
}

private function isResizeRequest()
{
if ($this->resourceSize['height'] > 0 && $this->resourceSize['width'] > 0) {
return true;
}
return false;
return $this->resourceSize['width'] > 0 && $this->resourceSize['height'] > 0;
}

// If the extension is video format, return true
private function isVideoRequest()
{
if (in_array($this->resourceExtension, ['mp4', 'webm', 'ogg', 'ogv', 'mp3', 'wav', 'flac', 'aac', 'm4a', 'm4v', 'mov', 'wmv', 'avi', 'mkv', 'mpg', 'mpeg', '3gp', '3g2'])) {
return true;
}
return false;
$videoExtensions = ['mp4', 'webm', 'ogg', 'ogv', 'mp3', 'wav', 'flac', 'aac', 'm4a', 'm4v', 'mov', 'wmv', 'avi', 'mkv', 'mpg', 'mpeg', '3gp', '3g2'];
return in_array($this->resourceExtension, $videoExtensions);
}
}

$newWPImgCloudinary = new TDTCloudinaryForwarder();
$newWPImgCloudinary->saveImg();
$cloudinaryForwarder = new CloudinaryForwarder();
$cloudinaryForwarder->saveImg();