Skip to content

Instantly share code, notes, and snippets.

@mrladeia
Last active June 12, 2024 15:06
Show Gist options
  • Save mrladeia/fd8b5a4c9251dbe05ff9c521fca9332e to your computer and use it in GitHub Desktop.
Save mrladeia/fd8b5a4c9251dbe05ff9c521fca9332e to your computer and use it in GitHub Desktop.
Clear Cloudflare cache Chevereto
<?php
/*
Cloudflare's purge directly depends on what your url looks like, in my case it's an example: https://s1.domain.com/Akd3X.jpg
That is, with the name of the encoded image.
Within my script I had to place a function to encode the image because the deleted image table does not have its code encoded.
I quickly made this script a while ago, it doesn't follow any good programming practices.
This script is not plug and play in the variables, each case must be analyzed.
*/
//crontab, you need define run every 5 minutes
//database select will pick up images deleted 5 minutes ago
//*/5 * * * * sudo -u nginx php /home/nginx/script/cf-purge.php > /home/nginx/script/cf-purge.log
//salt chevereto
$chvSalt = ""; //you can get salt here https://yourdomain.app/dashboard/settings/system
$chvUrlDirect = "https://s1.domain.com/"; //direct url of images, Example: https://s1.domain.com/xxxxx.png you need put: https://s1.domain.com/
//cloudflare api config
$cfEmail = "your@email.com";
$cfAuthKey = "";
$cfZone = "zone of your cloudflare, you can get on Zone ID in dashboard";
//mysql
$servername = "127.0.0.1";
$username = "user";
$password = "pass";
$dbname = "dbname";
//encode decode image name
//this function was captured within the chevereto code
function chvEncDec($in, $salt, $action = 'encode'){
$cheveretoID = null;
$index = 'abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ';
$id_padding = intval("5000");
// Use a stock version of the hashed values (faster execution)
if (isset($cheveretoID)) {
$passhash = $cheveretoID['passhash'];
$p = $cheveretoID['p'];
$i = $cheveretoID['i'];
} else {
for ($n = 0; $n < strlen($index); ++$n) {
$i[] = substr($index, $n, 1);
}
$passhash = hash('sha256', $salt);
$passhash = (strlen($passhash) < strlen($index)) ? hash('sha512', $salt) : $passhash;
for ($n = 0; $n < strlen($index); ++$n) {
$p[] = substr($passhash, $n, 1);
}
$cheveretoID = [
'passhash' => $passhash,
'p' => $p,
'i' => $i,
];
}
array_multisort($p, SORT_DESC, $i);
$index = implode($i);
$base = strlen($index);
if ($action == 'decode') {
$out = 0;
$len = strlen($in) - 1;
for ($t = 0; $t <= $len; ++$t) {
$bcpow = bcpow((string) $base, (string) ($len - $t));
$out = $out + strpos($index, substr($in, $t, 1)) * $bcpow;
}
if ($id_padding > 0) {
$out = $out / $id_padding;
}
$out = (int) sprintf('%s', $out);
} else {
if ($id_padding > 0) {
$in = $in * $id_padding;
}
$out = '';
for ($t = floor(log((float) $in, $base)); $t >= 0; --$t) {
$bcp = bcpow((string) $base, (string) $t);
$a = floor($in / $bcp) % $base;
$out = $out . substr($index, $a, 1);
$in = $in - ($a * $bcp);
}
}
return $out;
}
function cfPurge($files, $cfEmail, $cfAuthKey, $cfZone){
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => 'https://api.cloudflare.com/client/v4/zones/' . $cfZone . '/purge_cache',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => '',
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 0,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_POSTFIELDS => $files,
CURLOPT_HTTPHEADER => array(
'Content-Type: application/json',
'X-Auth-Email: ' . $cfEmail,
'X-Auth-Key: ' . $cfAuthKey,
),
));
$response = curl_exec($curl);
curl_close($curl);
return $response;
}
try {
$conn = new PDO("mysql:host=$servername;dbname=$dbname", $username, $password);
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
//get images deleted from table chv_deletions
//images deleted with 5 min blocks ago
$stmt = $conn->prepare("
SELECT * FROM chv_deletions WHERE deleted_date_gmt
BETWEEN
date_format(DATE_SUB(NOW(),INTERVAL 10 MINUTE), '%Y-%m-%d %H:%i:00')
AND
date_format(DATE_SUB(NOW(),INTERVAL 5 MINUTE), '%Y-%m-%d %H:%i:00')
ORDER BY deleted_date_gmt DESC;
");
$stmt->execute();
// set the resulting array to associative
//$result = $stmt->setFetchMode(PDO::FETCH_ASSOC);
$result = $stmt->fetchAll();
if(count($result)<1){
echo "nothing for the purge";
exit();
}
#print_r($result);
$allImages = [];
foreach($result as $v){
#$ext = "." . pathinfo($v['deleted_content_original_filename'], PATHINFO_EXTENSION);
//encode image from id
$urlNameDecoded = $chvUrlDirect . chvEncDec($v['deleted_content_id'], $chvSalt);
//set all images variants
$allImages[] = $urlNameDecoded . ".jpg";
$allImages[] = $urlNameDecoded . ".jpeg";
$allImages[] = $urlNameDecoded . ".png";
$allImages[] = $urlNameDecoded . ".bmp";
$allImages[] = $urlNameDecoded . ".gif";
$allImages[] = $urlNameDecoded . ".webp";
$allImages[] = $urlNameDecoded . ".md.jpg";
$allImages[] = $urlNameDecoded . ".md.jpeg";
$allImages[] = $urlNameDecoded . ".md.png";
$allImages[] = $urlNameDecoded . ".md.bmp";
$allImages[] = $urlNameDecoded . ".md.gif";
$allImages[] = $urlNameDecoded . ".md.webp";
$allImages[] = $urlNameDecoded . ".th.jpg";
$allImages[] = $urlNameDecoded . ".th.jpeg";
$allImages[] = $urlNameDecoded . ".th.png";
$allImages[] = $urlNameDecoded . ".th.bmp";
$allImages[] = $urlNameDecoded . ".th.gif";
$allImages[] = $urlNameDecoded . ".th.webp";
}
//create a chuncks of 30 images, beacause the limit of api cloudflare
$imagesChunks = array_chunk($allImages, 30);
foreach($imagesChunks as $v){
$files = json_encode(["files" => $v], JSON_UNESCAPED_SLASHES);
$cfReturn = cfPurge($files, $cfEmail, $cfAuthKey, $cfZone);
echo $cfReturn;
echo $files . "\n\n";
}
} catch(PDOException $e) {
echo "Error: " . $e->getMessage();
}
$conn = null;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment