корректировать ключи для хранения в битовом поле
* @return void
*/
public static function sortByPriority(array &$data, string $key = 'priority', $preserveKeys = false)
{
if (empty($data)) {
return;
}
if ($preserveKeys === 2) {
if (sizeof($data) > 32) {
$data = array_slice($data, 0, 32, true);
}
}
$order = [];
$i = 1;
foreach ($data as $k => &$v) {
$order[$k] = (!empty($v[$key]) ? $v[$key] : $i++);
} unset($v);
if ($preserveKeys) {
if ($preserveKeys === 2) {
$data2 = [];
$last = 0;
foreach ($data as $k => $v) {
if (($k > 1 && ($k % 2)) || substr_count(decbin($k), '1') > 1) {
for ($i = $last; $i <= 32; $i++) {
$j = pow(2, $i);
if (!isset($data[$j]) && !isset($data2[$j])) {
$k = $j;
$last = $i;
break;
}
}
}
$data2[$k] = $v;
}
$data = $data2;
}
$keys = array_keys($data);
array_multisort($order, SORT_ASC, SORT_NUMERIC, $data, $keys);
$data = array_combine($keys, $data);
} else {
array_multisort($order, SORT_ASC, $data);
}
}
/**
* Парсинг даты/времени
* @param string $datetime дата/время
* @return array
*/
public static function parse_datetime(string $datetime = '2006-04-05 01:50:00'): array
{
$arr = explode(' ', $datetime, 2);
$result = ['year' => '', 'month' => '', 'day' => '', 'hour' => '', 'min' => '', 'sec' => ''];
if (isset($arr[0])) {
$date = explode('-', $arr[0], 3);
if (count($date) == 3) {
$result['year'] = $date[0];
$result['month'] = $date[1];
$result['day'] = $date[2];
}
}
if (isset($arr[1])) {
$time = explode(':', $arr[1], 3);
if (count($time) == 3) {
$result['hour'] = $time[0];
$result['min'] = $time[1];
$result['sec'] = $time[2];
}
}
return $result;
}
/**
* Генератор случайной последовательности символов
* @param int $length кол-во символов (1-32)
* @param bool $numbersOnly только числа
* @return string
*/
public static function generator(int $length = 10, bool $numbersOnly = false): string
{
if ($length > 32) {
$length = 32;
}
if ($numbersOnly) {
return mt_rand(($length > 1 ? pow(10, $length - 1) : 1), ($length > 1 ? pow(10, $length) - 1 : 9));
}
return substr(md5(uniqid(mt_rand(), true)), 0, $length);
}
/**
* Генератор случайной буквенно-числовой последовательности
* @param int $length кол-во символов
* @param string $letters строка разрешенных символов для генерации
* @param callable|null $checkExist функция для проверки сгенерированного кода на совпадение с уже раннее созданным
* function ($result - сгенерированный код) {
* return true; - код существует, false - сгенерировать новый
* }
* @param int $attempts максимальное количество попыток для генерации кода
* @return bool|string
*/
public static function generatorLetters(
int $length = 10,
string $letters = '',
callable $checkExist = null,
int $attempts = 5
) {
if (empty($letters)) {
$letters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
}
$max = mb_strlen($letters) - 1;
$i = 0;
$exist = false;
do {
$result = '';
for ($j = 0; $j < $length; $j++) {
$result .= mb_substr($letters, rand(0, $max), 1);
}
if ($checkExist) {
$exist = call_user_func($checkExist, $result);
}
if ($i++ > $attempts) {
return false;
}
} while ($exist);
return $result;
}
/**
* Транслитерация cyr->lat
* @param string $text текст для транслитерации
* @param bool $isURL адаптировать для URL
* @param string|null $in кодировка входящий строки
* @param string|null $out кодировка выходящий строки
* @return string
*/
public static function translit(string $text, bool $isURL = true, ?string $in = null, ?string $out = null): string
{
if (empty($in)) {
$in = 'utf-8';
}
if (empty($out)) {
$out = 'utf-8';
}
if ($in === 'utf-8') {
TextParser::cleanUtf8($text);
}
$text = iconv($in, 'utf-8', $text);
$convert = bff::filter('utils.func.translit.convert', [
# Russian (RU), Ukrainian (UK)
'Щ' => 'Shh','Ш' => 'Sh','Ч' => 'Ch','Ц' => 'C','Ю' => 'Ju','Я' => 'Ja','Ж' => 'Zh','А' => 'A','Б' => 'B',
'В' => 'V','Г' => 'G','Д' => 'D','Е' => 'Je','Ё' => 'Jo','З' => 'Z','И' => 'I','І' => 'I','Й' => 'J',
'К' => 'K','Л' => 'L','М' => 'M','Н' => 'N','О' => 'O','П' => 'P','Р' => 'R','С' => 'S','Т' => 'T',
'У' => 'U','Ф' => 'F','Х' => 'Kh','Ь' => '\'','Ы' => 'Y','Ъ' => '`','Э' => 'E','Є' => 'Je','Ї' => 'Ji',
'щ' => 'shh','ш' => 'sh','ч' => 'ch','ц' => 'c','ю' => 'ju','я' => 'ja','ж' => 'zh','а' => 'a','б' => 'b',
'в' => 'v','г' => 'g','д' => 'd','е' => 'je','ё' => 'jo','з' => 'z','и' => 'i','і' => 'i','й' => 'j',
'к' => 'k','л' => 'l','м' => 'm','н' => 'n','о' => 'o','п' => 'p','р' => 'r','с' => 's','т' => 't',
'у' => 'u','ф' => 'f','х' => 'kh','ь' => '\'','ы' => 'y','ъ' => '`','э' => 'e','є' => 'je','ї' => 'ji',
# Georgian (KA)
'ა' => 'a','ბ' => 'b','გ' => 'g','დ' => 'd','ე' => 'e','ვ' => 'v','ზ' => 'z','თ' => 't',
'ი' => 'i','კ' => 'k','ლ' => 'l','მ' => 'm','ნ' => 'n','ო' => 'o','პ' => 'p\'','ჟ' => 'zh',
'რ' => 'r','ს' => 's','ტ' => 't\'','უ' => 'u','ფ' => 'p','ქ' => 'q','ღ' => 'gh','ყ' => 'y\'',
'შ' => 'sh','ჩ' => 'ch','ც' => 'c','ძ' => 'dz','წ' => 'w\'','ჭ' => 'ch\'','ხ' => 'x','ჯ' => 'j',
'ჰ' => 'h',
]);
$textBefore = $text;
$text = str_replace(
array_keys($convert),
array_values($convert),
$text
);
if ($text !== $textBefore) {
$text = preg_replace("/([qwrtpsdfghklzxcvbnmQWRTPSDFGHKLZXCVBNM]+)[jJ]e/", "\${1}e", $text);
$text = preg_replace("/([qwrtpsdfghklzxcvbnmQWRTPSDFGHKLZXCVBNM]+)[jJ]/", "\${1}'", $text);
$text = preg_replace("/([eyuioaEYUIOA]+)[Kk]h/", "\${1}h", $text);
$text = preg_replace("/^kh/", "h", $text);
$text = preg_replace("/^Kh/", "H", $text);
}
if ($isURL) {
$text = TextParser::toASCII($text);
$text = preg_replace('/[\?&\']+/', '', $text);
$text = preg_replace('/[\s,\?&]+/', '-', $text);
$text = preg_replace('/[\/\'\"\(\)\=\\\]+/', '', $text);
$text = preg_replace('/[^a-zA-Z0-9_\-]/', '', $text);
$text = preg_replace("/\-+/", "-", $text); //сжимаем двойные "-"
}
return bff::filter('utils.func.translit', iconv('utf-8', $out, $text));
}
/**
* Формирование JSON
* @param mixed $data данные
* @param array $opts [
* bool|string 'escape' - эскейпим строку: 'html' (true), 'js', false
* bool 'numericCheck' - не обворачивать число в кавычки
* ]
* @return string
*/
public static function php2js($data, $opts = []): string
{
if (! is_array($opts)) { # for backward compability
$opts = ['numericCheck' => !empty($opts)];
}
$opts = array_merge([
'escape' => false,
'numericCheck' => false,
'asObject' => false,
], $opts);
$jsonOptions = JSON_UNESCAPED_UNICODE;
if ($opts['numericCheck']) {
$jsonOptions += JSON_NUMERIC_CHECK;
}
if ($opts['asObject']) {
$jsonOptions += JSON_FORCE_OBJECT;
}
return HTML::escape(json_encode($data, $jsonOptions), $opts['escape']);
}
/**
* Вставка необходимой строки в текст с учетом позиции найденной строки
* @param string $text текст
* @param string $search строка поиска
* @param string $insert строка для вставки
* @param bool $after после найденной строки (true), перед (false)
* @return string
*/
public static function stringInsert(string $text, string $search, string $insert, bool $after = true): string
{
$index = mb_strpos($text, $search);
if ($index === false) {
return $text;
}
if ($after) {
return substr_replace($text, $search . $insert, $index, mb_strlen($search));
}
return mb_substr($text, 0, $index) . $insert . mb_substr($text, $index);
}
/**
* Safe unserialize
* @param mixed $data данные в сериализованном виде
* @param mixed $default значение по-умолчанию
* @param array $opts
* @return mixed
*/
public static function unserialize($data, $default = [], array $opts = [])
{
if (is_array($default)) {
if (empty($data)) {
return $default;
}
if (is_array($data)) {
return $data;
}
$data = strval($data);
if (mb_strpos($data, 'a:') !== 0) {
if (preg_match('/^[a-zA-Z0-9\/\r\n+]*={0,2}$/', $data)) {
$data = base64_decode($data, true);
if (empty($data) || !static::isSerialized($data)) {
return $default;
}
} else {
return $default;
}
}
$data = unserialize($data, $opts);
if ($data === false) {
bff::log('func::unserialize failed: ' . (new Exception())->getTraceAsString());
}
return ( ! empty($data) ? $data : $default );
}
return ( ! empty($data) ? unserialize(strval($data), $opts) : $default );
}
/**
* Проверка является ли строка сериализованной строкой
* @param mixed $data
* @return bool
*/
public static function isSerialized($data): bool
{
if (!is_string($data)) {
return false;
}
$data = trim($data);
if ('N;' == $data) {
return true;
}
if ($data[1] !== ':' || mb_strlen($data) < 4) {
return false;
}
if (!preg_match('/^([adObis]):/', $data, $matches)) {
return false;
}
switch ($matches[1]) {
case 'a':
case 'O':
case 's':
if (preg_match("/^{$matches[1]}:[0-9]+:.*[;}]\$/s", $data)) {
return true;
}
break;
case 'b':
case 'i':
case 'd':
if (preg_match("/^{$matches[1]}:[0-9.E-]+;\$/", $data)) {
return true;
}
break;
}
return false;
}
}