こんにちは。はじめまして。tarokamiakzeです。
PHPのsort系関数の結果と、MySQL のorder by指定を比較する機会がありまして。
記号の扱いが一致しなくて泣きたくなりました。
(PHPUnitで、検索系APIが本当にソートされているか検証したかっただけなのに...)
ので、怒りに任せて記事を書きます。LAMP環境とはなんだったのか!!
再現方法
MySQL編
# MySQL
CREATE TABLE `sort_test` (
`name` varchar(255) NOT NULL,
PRIMARY KEY (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `sort_test`(`name`) VALUES ("0"),("1"),("a"),("_");
SELECT `name` as `MySQL_SORT` FROM `sort_test` ORDER BY `name` ASC;
PHP編
<?php
$arr = ["0","1","a","_"];
// 通常のソート.
sort($arr);
var_dump($arr);
// sort_flag を指定。この例だと、何を指定しても同じだった
sort($arr,SORT_STRING); // see http://php.net/manual/ja/function.sort.php
var_dump($arr);
// "自然順"アルゴリズムで配列をソート
natsort($arr);
var_dump($arr);
結果
MySQL_SORT | PHP_SORT |
---|---|
0 | "0" |
1 | "1" |
"a" | "_" |
"_" | "a" |
"_" と "a" が逆になってますがな!!!
解決方法
MySQLデフォルトのutf8_general_ciだと、どーーーしても一致しないらしい。
ためしにutf8_binに変えてみたら、順番が合った。が、そんなの使いたくない。
よってSELECT時だけCOLLATEを変える。
SELECT `name` as `MySQL_SORT` FROM `sort_test` ORDER BY `name` COLLATE utf8_bin ASC;
MySQL_SORT | PHP_SORT |
---|---|
0 | "0" |
1 | "1" |
"_" | "_" |
"a" | "a" |
でも、他に弊害がある気がしてならない。
php側であわせたほうがよさそう。
// see http://stackoverflow.com/questions/21416765/php-sort-filenames-with-an-underscore
function cmp($a, $b) {
$aTemp = str_replace('_', '0', $a);
$bTemp = str_replace('_', '0', $b);
return strcmp($aTemp,$bTemp);
}
usort($arr, "cmp");
でも、きっと他の記号もなんかあるんだろうなぁ。辛い。