[PHP]10進数を任意の文字を使って62進数などのn進数に相互変換する(基数変換)

短縮URL等を発行する際に、データベースなどのIDをURLと関連付けて使うことが多いですが、単純に数字だけのIDを使うと多くの桁数を消費してしまいます。
0-9 に a-f を加えて一桁で16個まで表現できる16進数を使えば少し桁数を節約することができます。

この場合 a が 10 を表し、f が 15 となり、10 が 16 を意味します。
PHP で16進数の変換を行うには hexdec() や dechex() を使います。

16進数ではアルファベットの「f」までしか使いませんでしたが、残りの「g-z」を加えればもっと多くの数値を表現できます。また、URL は大文字小文字を区別するので、「A-Z」を更に加えて62進数にすると一桁だけでもかなりの情報量を扱えるようになります。

<?php
$char = array_merge(range('0','9'), range('a', 'z'), range('A', 'Z'));

$number = 1000000;
echo encode($number, $char) . ', ';

$str = "Test";
echo decode($str, $char);

function encode($number, $char){
	$result = "";
	$base = count($char);
	
	while($number > 0){
		$result = $char[ fmod($number, $base) ] . $result;
		$number = floor($number / $base);
	}
	return ($result == "" ) ? 0 : $result;
}

function decode($str, $char){
	$result = 0;
	$base = count($char);
	$table = array_flip($char);
	$digit = array_reverse(preg_split('//', $str, -1, PREG_SPLIT_NO_EMPTY));

	foreach($digit as $i => $value){
		if(!isset($table[$value])) return false;
		$result += pow($base, $i) * $table[$value];
	}
	
	return $result;
}

[実行結果]

4c92(1000000の62進数化)
13163621(「Test」の10進数化)

変数 char に代入された文字列を使って n 進数に変換します
基数は文字列の種類によって自動的に決められます。

ちなみにこの 62進数に更に2文字を加えたのが Base64 というもので、
PHP では base64encode() などの関数として利用できます。
Base64 は上記の英数字に加えて「+」と「/」が使われます。また、4文字ずつ区切って変換するので余った部分は「=」で埋められます。
Base64 で短縮URLを作る場合は「+」や「/」をURLとして問題の起きない「_」などの文字に置き換える必要があります。

[参考]
http://q.hatena.ne.jp/1222172924/186107/#i186107

[PHP]RGBをLab色空間の座標に変換する

専門外なので公式をPHPに書き換えただけですが、RGB値をもとに l*a*b* に変換することができます。
D50 や D65 というのは昼光色を基準として決められた標準イルミナント(標準となる光)で、
D50 は色温度 5000K を、D65 は 6500K をベースに定められています。
今回は Photoshop CS6 のカラーピッカーに近似する D50 を使い、変換を行いました。

直接 RGB から Lab には変換できないようなので、XYZ 表色系に変換してからそれを Lab にします。

<?php
function xyz2lab($xyz) {
	$threshold = 0.008856;
	
	//Chromatic Adaptation Matrices
	// D50
	$ref_x = 0.96422;
	$ref_y = 1.0000;
	$ref_z = 0.82521;
	
	// D65
	/*
	$ref_x = 0.95047;
	$ref_y = 1.0000;
	$ref_z = 1.0883;
	*/
	
	$var_x = $xyz[0] / ($ref_x * 100);
	$var_y = $xyz[1] / ($ref_y * 100);    
	$var_z = $xyz[2] / ($ref_z * 100);
	
	$var_x = ($var_x > $threshold) ? $var_x = pow($var_x, 1/3 ) : (7.787 * $var_x) + (16 / 116);
	$var_y = ($var_y > $threshold) ? $var_y = pow($var_y, 1/3 ) : (7.787 * $var_y) + (16 / 116);
	$var_z = ($var_z > $threshold) ? $var_z = pow($var_z, 1/3 ) : (7.787 * $var_z) + (16 / 116);
	

	$l = ( 116 * $var_y ) - 16;
	$a = 500 * ( $var_x - $var_y );
	$b = 200 * ( $var_y - $var_z );
	$lab = array();
	
	$lab = array($l, $a, $b);
	
	return $lab;
}

function rgb2xyz($rgb) {

	$r = $rgb[0] / 255;
	$g = $rgb[1] / 255;
	$b = $rgb[2] / 255;

	$r = ($r > 0.04045) ? pow(($r + 0.055) / 1.055, 2.4) : $r / 12.92;
	$g = ($g > 0.04045) ? pow(($g + 0.055) / 1.055, 2.4) : $g / 12.92;
	$b = ($b > 0.04045) ? pow(($b + 0.055) / 1.055, 2.4) : $b / 12.92;

	$r = $r * 100;
	$g = $g * 100;
	$b = $b * 100;
	
	$xyz = array();
	
	//sRGB D50
	$xyz[] = $r * 0.4360747 + $g * 0.3850649 + $b * 0.1430804;
	$xyz[] = $r * 0.2225045 + $g * 0.7168786 + $b * 0.0606169;
	$xyz[] = $r * 0.0139322 + $g * 0.0971045 + $b * 0.7141733;
	
	//sRGB D65
	/*
	$xyz[] = $r * 0.4124564 + $g * 0.3575761 + $b * 0.1804375;
	$xyz[] = $r * 0.2126729 + $g * 0.7151522 + $b * 0.0721750;
	$xyz[] = $r * 0.0193339 + $g * 0.1191920 + $b * 0.9503041;
	*/
	return $xyz;
}

function rgb2lab($rgb) {
	$xyz = rgb2xyz($rgb);
	$lab = xyz2lab($xyz);
	return $lab;
}

//RGB値を 0~255 で指定する
$rgb = array(244,46,32);
var_dump( rgb2lab($rgb) );

参考
http://w3.kcua.ac.jp/~fujiwara/infosci/colorspace/
http://www.brucelindbloom.com/