Skip to content

Instantly share code, notes, and snippets.

@sskaje
Created July 17, 2020 02:10
Show Gist options
  • Save sskaje/acb0bd4606e7b84591086cc0e8f70b8b to your computer and use it in GitHub Desktop.
Save sskaje/acb0bd4606e7b84591086cc0e8f70b8b to your computer and use it in GitHub Desktop.
combine js/css from cdn services
<?php
/**
* cdn proxy for cdnjs/jsdelivr/unpkg/...
*
* @author sskaje
* @usage https://p.rst.im/(js|css)/cdnjs:/path1;/path2;unpkg:/path3;/path4
* @example https://p.rst.im/css/cdnjs:/bootswatch/4.5.0/darkly/bootstrap.min.css;/bootstrap-select/1.13.18/css/bootstrap-select.min.css
* @example https://p.rst.im/js/cdnjs:/jquery/3.4.1/jquery.min.js;/twitter-bootstrap/4.5.0/js/bootstrap.bundle.min.js;/datatables/1.10.21/js/jquery.dataTables.min.js
*/
$request_uri = $_SERVER['REQUEST_URI'];
$max_resource= 20;
$ttl = 86400 * 30;
$file_mode = 'auto';
if (strpos($request_uri, '/css') === 0) {
$request_uri = substr($request_uri, strlen('/css/'));
$file_mode = 'css';
} else if (strpos($request_uri, '/js') === 0) {
$request_uri = substr($request_uri, strlen('/js/'));
$file_mode = 'js';
} else {
$request_uri = substr($request_uri, strlen('/cdn/'));
if (preg_match('#\.js#', $request_uri) || isset($_GET['m']) && $_GET['m'] == 'js') {
$file_mode = 'js';
} else if (preg_match('#\.css#', $request_uri) || isset($_GET['m']) && $_GET['m'] == 'css') {
$file_mode = 'css';
}
}
# format
# cdnjs:/twitter-bootstrap/5.0.0-alpha1/js/bootstrap.min.js;
# jsdelivr:/npm/package@version/file;/gh/user/repo@version/file
#
$prefix = [
'cdnjs' => 'https://cdnjs.cloudflare.com/ajax/libs',
'jsdelivr' => 'https://cdn.jsdelivr.net',
'unpkg' => 'https://unpkg.com',
];
$split = explode(';', $request_uri);
# cdnjs by default
$vendor = 'cdnjs';
$urls = [];
foreach ($split as $line) {
if (empty($line)) continue;
if (strpos($line, ':')) {
list($vendor, $suffix) = explode(':', $line);
} else {
$suffix = $line;
}
if (isset($prefix[$vendor])) {
$urls[] = $prefix[$vendor] . '/' . ltrim($suffix, '/');
}
}
header("Pragma: cache");
header("Cache-Control: public, max-age={$ttl}");
header('Access-Control-Allow-Origin: *');
$response = '';
if (!empty($urls)) {
$urls = array_unique($urls);
$urls = array_slice($urls, 0, $max_resource);
$response = '';
foreach ($urls as $url) {
header('X-proxy-url: ' . $url, false);
if ($file_mode == 'js' || $file_mode == 'css') {
$response .= "/* {$url} */\n\n";
}
$resource_response = http_get($url);
$response .= process_file($resource_response, $file_mode, $url);
$response .= "\n";
}
if ($file_mode == 'css') {
header('content-type: text/css');
} else if ($file_mode == 'js') {
header('content-type: application/javascript');
}
echo $response;
}
function http_get($url)
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.61 Safari/537.36');
curl_setopt($ch, CURLOPT_URL, $url);
$response = curl_exec($ch);
$info = curl_getinfo($ch);
return $response;
}
function process_file($content, $file_mode, $url)
{
if ($file_mode == 'css') {
$content = process_css($content, $url);
}
return $content;
}
function process_css($content, $url)
{
$url_prefix = dirname($url);
$content = preg_replace_callback('#url\s*\(\s*(\'|")?(.......)#si', function($matches) use($url_prefix) {
$object = $matches[2];
if (preg_match('#^https?:#', $object)) {
$prefixed = $object;
} else if (preg_match('#^/#', $object)) {
# find prefix
$prefixed = $url_prefix . $object;
} else {
# prefix + '/' + object
$prefixed = $url_prefix . '/' . $object;
}
return 'url(' . $matches[1] . $prefixed;
}, $content);
$content = preg_replace_callback('#sourceMappingURL=(......)#is', function($matches) use($url_prefix) {
if (preg_match('#^https?:#', $matches[1])) {
return 'sourceMappingURL=' . $matches[1];
} else {
return 'sourceMappingURL=' . $url_prefix . '/' . $matches[1];
}
}, $content);
return $content;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment