Skip to content

Commit

Permalink
Emit cache-keys.
Browse files Browse the repository at this point in the history
  • Loading branch information
stooit committed Apr 18, 2024
1 parent 197f315 commit f48040e
Show file tree
Hide file tree
Showing 4 changed files with 165 additions and 1 deletion.
2 changes: 1 addition & 1 deletion modules/quant_purger/config/schema/quant_purger.schema.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ quant_purger.settings:
translatable: false
sequence:
type: string
label: 'String that cannot be present in the ccache tag.'
label: 'String that cannot be present in the cache tag.'
translatable: false
path_blacklist:
label: 'A list of string patterns that will not get queued.'
Expand Down
70 changes: 70 additions & 0 deletions modules/quant_purger/src/Entity/Hash.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
<?php

namespace Drupal\quant_purger\Entity;

/**
* Helper class that centralizes string hashing for security and maintenance.
*/
class Hash {

/**
* Create a hash with the given input and length.
*
* @param string $input
* The input string to be hashed.
* @param int $length
* The length of the hash.
*
* @return string
* Cryptographic hash with the given length.
*/
protected static function hashInput($input, $length) {
// MD5 is the fastest algorithm beyond CRC32 (which is 30% faster, but high
// collision risk), so this is the best bet for now. If collisions are going
// to be a major problem in the future, we might have to consider a hash DB.
$hex = md5($input);
// The produced HEX can be converted to BASE32 number to take less space.
// For example 5 characters HEX can be stored in 4 characters BASE32.
$hash = base_convert(substr($hex, 0, ceil($length * 1.25)), 16, 32);
// Return a hash with consistent length, padding zeroes if needed.
return strtolower(str_pad(substr($hash, 0, $length), $length, '0', STR_PAD_LEFT));
}

/**
* Create unique hashes/IDs for a list of cache tag strings.
*
* @param string[] $tags
* Non-associative array cache tags.
*
* @return string[]
* Non-associative array with hashed copies of the given cache tags.
*/
public static function cacheTags(array $tags) {
$hashes = [];
foreach ($tags as $tag) {
if (strlen($tag) > 4) {
$hashes[] = self::hashInput($tag, 4);
}
else {
$hashes[] = $tag;
}
}
return $hashes;
}

/**
* Create a unique hash that identifies this site.
*
* @param string $site_name
* The identifier of the site on Acquia Cloud.
* @param string $site_path
* The path of the site, e.g. 'site/default' or 'site/database_a'.
*
* @return string
* Cryptographic hash that's long enough to be unique.
*/
public static function siteIdentifier($site_name, $site_path) {
return self::hashInput($site_name . $site_path, 16);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
<?php

namespace Drupal\quant_purger\Plugin\Purge\TagsHeader;

/**
* Provides simple value object for cache tag headers.
*/
class CacheTagsHeaderValue {

/**
* String: separation character used.
*/
const SEPARATOR = ' ';

/**
* List of original cache tags.
*
* @var string[]
*/
protected $tags = [];

/**
* List of hashed cache tags.
*
* @var string[]
*/
protected $tagsHashed = [];

/**
* Constructs a TagsHeaderValue object.
*
* @param string[] $tags
* Non-associative array cache tags.
* @param string[] $tags_hashed
* Non-associative array with hashed cache tags.
*
* @throws \LogicException
* Thrown when both tags arrays aren't of equal length.
*/
public function __construct(array $tags, array $tags_hashed) {
if (count($tags) !== count($tags_hashed)) {
throw new \LogicException("TagsHeaderValue received unequal tag sets!");
}
$this->tags = array_unique($tags);
$this->tagsHashed = array_unique($tags_hashed);
}

/**
* Generate the header value for a cache tags header.
*
* @return string
* String representation of the cache tags for use on headers.
*/
public function __toString() {
return implode(self::SEPARATOR, $this->tagsHashed);
}

/**
* Get an associative array mapping keys.
*
* @return array
* Associative mapping original and hashed cache tags.
*/
public function getTagsMap() {
return array_combine($this->tags, $this->tagsHashed);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?php

namespace Drupal\quant_purger\Plugin\Purge\TagsHeader;

use Drupal\quant_purger\Entity\Hash;
use Drupal\purge\Plugin\Purge\TagsHeader\TagsHeaderInterface;
use Drupal\purge\Plugin\Purge\TagsHeader\TagsHeaderBase;

/**
* Sets and formats the default response header with cache tags.
*
* @PurgeTagsHeader(
* id = "quant_tagsheader",
* header_name = "Cache-Tags",
* )
*/
class QuantCacheTagsHeader extends TagsHeaderBase implements TagsHeaderInterface {

/**
* {@inheritdoc}
*/
public function getValue(array $tags) {
return new CacheTagsHeaderValue($tags, Hash::cacheTags($tags));
}

}

0 comments on commit f48040e

Please sign in to comment.