На дворе 21 век, а функцию двунаправленной обратимой транслитерации на основе ГОСТ 16876-71 я так и не нашел! Поэтому написал собственную.
<?php
/**
* Функция обратимой транслитерации на основе ГОСТ 16876-71
* @author http://space1000.zxcv.one
*/
function translit_url($text,$decode = false)
{
// Split text into array of unicode chars.
preg_match_all('/./u', $text, $text);
$text = $text[0];
$simplePairs = array(
'а' => 'a' , 'л' => 'l' , 'у' => 'u' ,
'б' => 'b' , 'м' => 'm' , 'т' => 't' ,
'в' => 'v' , 'н' => 'n' , 'ы' => 'y' ,
'г' => 'g' , 'о' => 'o' , 'ф' => 'f' ,
'д' => 'd' , 'п' => 'p' ,
'и' => 'i' , 'р' => 'r' ,
'А' => 'A' , 'Л' => 'L' , 'У' => 'U' ,
'Б' => 'B' , 'М' => 'M' , 'Т' => 'T' ,
'В' => 'V' , 'Н' => 'N' , 'Ы' => 'Y' ,
'Г' => 'G' , 'О' => 'O' , 'Ф' => 'F' ,
'Д' => 'D' , 'П' => 'P' ,
'И' => 'I' , 'Р' => 'R' ,
);
$complexPairs = array(
'ж' => 'zh' , 'ч' => 'ch' , 'х' => 'kh' ,
'з' => 'z' , 'ц' => 'c' , 'к' => 'k' ,
'я' => 'ja' ,
'щ' => 'shh' , 'ю' => 'ju' ,
'э' => 'eh' , 'ш' => 'sh' , 'й' => 'jj' ,
'е' => 'e' , 'с' => 's' , 'ё' => 'jo' ,
'Ж' => 'ZH' , 'Ч' => 'CH' , 'Х' => 'KH' ,
'З' => 'Z' , 'Ц' => 'C' , 'К' => 'K' ,
'Я' => 'JA' ,
'Щ' => 'SHH' , 'Ю' => 'JU' ,
'Э' => 'EH' , 'Ш' => 'SH' , 'Й' => 'JJ' ,
'Е' => 'E' , 'С' => 'S' , 'Ё' => 'JO' ,
'Ь' => "^'" , 'Ъ' => "^`" ,
'ь' => "'" , 'ъ' => "`" ,
);
$specialSymbols = array(
"_" => "__",
"-" => "_-",
"'" => "_'",
"`" => "_`",
"^" => "_^",
" " => "-",
);
$translitLatSymbols = array(
'a','l','u','b','m','t','v','n','y','g','o',
'f','d','p','i','r','z','c','k','e','s',
'A','L','U','B','M','T','V','N','Y','G','O',
'F','D','P','I','R','Z','C','K','E','S',
);
$simplePairsFlip = array_flip($simplePairs);
$complexPairsFlip = array_flip($complexPairs);
$specialSymbolsFlip = array_flip($specialSymbols);
$charsToTranslit = array_merge(
array_keys($simplePairs),
array_keys($complexPairs)
);
$translitTable = array();
foreach($simplePairs as $key => $val) $translitTable[$key] = $simplePairs[$key];
foreach($complexPairs as $key => $val) $translitTable[$key] = $complexPairs[$key];
foreach($specialSymbols as $key => $val) $translitTable[$key] = $specialSymbols[$key];
$result = "";
if($decode)
{
$char = array();
$translitDisabled = false;
for($pos = 0; $pos < count($text); $pos++)
{
$char[0] = $text[$pos];
$char[1] = isset($text[$pos+1]) ? $text[$pos+1] : null;
$char[2] = isset($text[$pos+2]) ? $text[$pos+2] : null;
// Decoding specsymbols: [_-'`^ ]
foreach($specialSymbolsFlip as $key => $val)
{
$search = "";
for($j = 0; $j < strlen($key) ; $j++) $search.= $char[$j];
if($search == $key)
{
$result.= $val;
$pos += strlen($key) - 1;
continue 2;
}
}
// Lone '_' symbol disables or enables translitting.
if($char[0] == '_')
{
$translitDisabled = !$translitDisabled;
continue;
}
// When translit is disabled, simply add char to result.
if($translitDisabled)
{
$result.= $char[0];
}
else
{
if(in_array($char[0],$simplePairs))
{
$result.= $simplePairsFlip[$char[0]];
continue;
}
foreach($complexPairsFlip as $key => $val)
{
$search = "";
for($j = 0; $j < strlen($key); $j++) $search.= $char[$j];
if($search == $key)
{
$result.= $val;
$pos += strlen($key) - 1;
continue 2;
}
}
// if nothing up worked
$result.= $char[0];
continue;
}
}
}
else
{
$translitDisabled = false;
foreach($text as $char)
{
if(in_array($char,array_keys($specialSymbols)))
{
$result.= $translitTable[$char];
}
elseif(in_array($char,$charsToTranslit))
{
if($translitDisabled)
{
$result.= "_";
$translitDisabled = false;
}
$result.= $translitTable[$char];
}
else
{
if(!$translitDisabled
&& in_array($char,$translitLatSymbols))
{
$result.= "_";
$translitDisabled = true;
}
$result.= $char;
}
}
}
return $result;
}