Skip to content

Instantly share code, notes, and snippets.

@pmeulen
Created August 19, 2017 11:51
Show Gist options
  • Save pmeulen/69c48b702407cf1a915b4e048670669a to your computer and use it in GitHub Desktop.
Save pmeulen/69c48b702407cf1a915b4e048670669a to your computer and use it in GitHub Desktop.
Making random opaque strings much more easy to compare by giving them a backgroud color that is derived from the value of the sring
<?php
/** Making opaque values like GUIDs or session identifiers easier to compare and distinguish
*
* By giving each opaque value a background color that is derived from the value itself, it
* becomes much easier to eyeball whether two values are likely to be the same. This really helps
* when reading logs or other diagnostic output that contain opaque identifiers like GUIDs or other
* opaque identifiers.
*
* Testing:
* - Start PHP buildin webserver: php -S 127.0.0.1:8080
* - browse to http://127.0.0.1:8080/HTMLColorFingerprint.php
*/
/** Derive a HTML color from a string value
*
* The same string value will always generate the same color. The returned color is suitable for use
* as a background color for text on a light (white) background with dark (black) text.
*
* @param string $value The value to fingerprint
* @return string HTML hexadecimal RGB color format: #RRGGBB
*/
function HTMLColorFingerprint($value)
{
// We want to generate a color that is suitable to use as a background color on a light (white)
// background for black text, so we want a to pick color with both a minimum and maximum brightness
// so there is enough contrast between the back text and the background color, and the coloring is
// still visible.
// Pick a random color in the Hue, Saturation and Lightness (HSL) color space
// with a Lightness value between minL and maxL
$minL = 50.0 / 100.0; // 0 .. 1
$maxL = 80.0 / 100.0; // 0 .. 1
// Since the md5 mixes the bits of $value into the fingerprint that it returns, we arbitrarily cut
// three 4 digit hex numbers (0..65535) from the md5 fingerprint and scale them to appropriate values
// for H, S and L
$hexFingerprint=md5($value); // 32 character hex string
$h = (1.0 / 65535.0) * intval(substr($hexFingerprint, 0, 4), 16); // 0 .. 1
$s = (1.0 / 65535.0) * intval(substr($hexFingerprint, 4, 4), 16); // 0 .. 1
$l = $minL + $maxL * (1.0-$minL) * (1.0 / 65535.0) * intval(substr($hexFingerprint, 8, 4), 16); // $minLightness .. 100 (%)
// Convert from HSL to Red, Green and Blue (RGB) color space
// Source: https://stackoverflow.com/questions/20423641/php-function-to-convert-hsl-to-rgb-or-hex
$r=$l; $g=$l; $b=$l;
$v = ($l <= 0.5) ? ($l * (1.0 + $s)) : ($l + $s - $l * $s);
if ($v > 0){
$m = $l + $l - $v;
$sv = ($v - $m ) / $v;
$h *= 6.0;
$sextant = floor($h);
$fract = $h - $sextant;
$vsf = $v * $sv * $fract;
$mid1 = $m + $vsf;
$mid2 = $v - $vsf;
switch ($sextant) {
case 0:
$r = $v; $g = $mid1; $b = $m;
break;
case 1:
$r = $mid2; $g = $v; $b = $m;
break;
case 2:
$r = $m; $g = $v; $b = $mid1;
break;
case 3:
$r = $m; $g = $mid2; $b = $v;
break;
case 4:
$r = $mid1; $g = $m; $b = $v;
break;
case 5:
$r = $v; $g = $m; $b = $mid2;
break;
}
}
// Convert from RGB values (0 .. 1) to hex (00 .. FF)
$color='#' .str_pad(dechex($r*256),2,'0',STR_PAD_LEFT)
.str_pad(dechex($g*256),2,'0',STR_PAD_LEFT)
.str_pad(dechex($b*256),2,'0',STR_PAD_LEFT);
return $color;
}
/** Generate a HTML test page with random text with random hex nonces injected that
* are can be colored with HTMLColorFingerprint()
*/
echo "<!doctype HTML><html><body><h1>Can you spot which values are the same?</h1>";
$plain = ($_REQUEST['plain'] == 1) ? 1 : 0;
$seed = intval($_REQUEST['seed']);
echo "Colors ";
echo $plain ? "<a href='?plain=0&seed=$seed'>on</a> <b>off</b></a>" : "<b>on</b> <a href='?plain=1&seed=$seed'>off</a>";
echo "<br />Seed";
for ($i=0;$i<20;$i++) {
if ($i==$seed)
echo " <b>$seed</b>";
else
echo $seeds[]=" <a href='?plain=$plain&seed=$i'>$i</a>";
}
mt_srand($seed); // Seed RNG so we always get the same output
$wordList=array('lorem', 'ipsum', 'dolor', 'sit', 'amet', 'consectetuer', 'adipiscing', 'elit', 'aenean',
'commodo', 'ligula', 'eget', 'massa', 'cum', 'sociis', 'natoque', 'penatibus', 'et', 'magnis', 'dis',
'parturient', 'montes', 'nascetur', 'ridiculus', 'mus', 'donec', 'quam', 'felis', 'ultricies', 'nec');
// Generate $nrNonces nonces to be inserted at random locations in the text
$nrNonces=10;
$nonces=array();
for ($i=0;$i<$nrNonces;$i++) {
$value='';
for ($j = 0; $j < 10; $j++) {
$value .= str_pad(dechex(mt_rand(0, 255)), 2, '0', STR_PAD_LEFT);
}
$nonces[]=$value;
}
// Generate random paragraphs, sentences, phrases and words based on $wordList above and inject nonces
// from $nonces
$nrParagraphs=5; // Number of paragraphs to generate
$paragraphs=array();
for ($paragraph=0;$paragraph<$nrParagraphs;$paragraph++) {
$nrSentences = mt_rand(3, 7); // Number of sentences per paragraph
$sentences = array();
for ($sentence = 0; $sentence < $nrSentences; $sentence++) {
$nrPhrases = mt_rand(1, 5); // Number of phrases per sentence
$phrases = array();
for ($phrase = 0; $phrase < $nrPhrases; $phrase++) {
$nrWords = mt_rand(1, 10); // Number of words per phrase
$words = array();
$randWords = $wordList;
for ($word = 0; $word < $nrWords; $word++) {
$randWord = mt_rand(0, sizeof($randWords) - 1); // Choose random word
$words[] = $randWords[$randWord];
array_splice($randWords, $randWord,1); // Remove chosen word so we don't choose the same word twice in a phrase
}
if (mt_rand(0, 5)==0) {
// Insert a random nonce in the phrase
$value=$nonces[mt_rand(0, sizeof($nonces)-1)]; // Pick random nonce
$color=($_REQUEST['plain'] == 1) ? '#CCCCCC' : HTMLColorFingerprint($value);
$nonceHTML = "<code style='background-color: $color'>$value</code>";
array_splice($words, mt_rand(0,sizeof($words)), 0, $nonceHTML);
}
$phrases[] = join(' ', $words);
}
$sentences[] = ucfirst(join(', ', $phrases));
}
echo '<p>'.join('. ', $sentences).'.</p>';
}
echo "</body></html>";
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment