Windows: Ошибка при установке YII через composer

Ошибка вида:

In CurlDownloader.php line 372:

  curl error 60 while downloading https://asset-packagist.org/packages.json: SSL certificate problem: self-signed certificate in certificate chain

Решение:

скачать сертификат curl.haxx.se/ca/cacert.pem и подлогжить его в php.ini:

[curl]
curl.cainfo ="e:\cacert.pem"

PHP: интересное поведение сложения чисел типа float

Был немножно удивлен сегодня, когда пытался сложить два числа типа float обычным оператором +. Например сложение чисел вида 59.86601 + 0,01 успешно выполнялось, а 59.86601+0,001 уже нет. Т.е. результирующее число оставалось прежним. Оказывается для точного сложения чисел, в PHP нужно использовать специальные операторы:

bcadd — Сложить 2 числа произвольной точности
bccomp — Сравнение двух чисел произвольной точности
bcdiv — Операция деления для чисел произвольной точности
bcmod — Получает остаток от деления чисел с произвольной точностью
bcmul — Умножение двух чисел с произвольной точностью
bcpow — Возведение в степень чисел с произвольной точностью
bcpowmod — Возводит одно число в степень другого и возвращает остаток от деления результата на третье число
bcscale — Задает количество чисел после десятичной точки по умолчанию для всех bc math функций.
bcsqrt — Извлекает квадратный корень из числа с произвольной точностью
bcsub — Вычитает одно число с произвольной точностью из другого

Например:

$point2["lat"]=Bcadd($point2["lat"],$cnt,8);

Rbot: парсер данных с госуслуг

На днях довелось попробовать в работе специализированную платформу для написания «роботов» — RPA Bot. По сути это хорошо документированная надстройка на Selenium. В базе позволяет писать «роботов» на Python, Node.js и PHP. На сайте ОЧЕНЬ хорошая документация по всему функционалу с примерами, а потому роботов писать гораздо приятнее чем при использовании «чистого» Selenium. Это плюс. Из минусов — отсутствие версии под Linux и конский ценник. Ну если первое разработчики усиленно пилят, то второе лично мне фиолетово (босс платит 😉 )

В ходе реализации очень понравилась функция save_url_to_file, аналога которой в Selenium я не нашел в своё время, а потому приходилось изобретать велосипед. Ну скорее всего конечно это то-же «велосипед» (ну логично, проект то на основе Selenium), но сделанный «штатно». К сожалению функция не отрабатывает, если закачька происходит с использованием Redirect 301. потому в случае необходимости можно воспользоваться таким вариантом закачки:

                       $browser->set_default_download($mySettings['work_path']);
                       $browser->enable_download_file_dialog(false);
                       $browser->navigate("https://www.gosuslugi.ru/api/lk/geps/file/download/$a_aid");                       
                       wait_on_file($a_name, 120);  

function wait_on_file($path, $wait=120, $pause=1)
{
    global $file_os;
	$a=0;

	while(!$file_os->is_exist($path))
	{
		sleep($pause);
		if($a>$wait)
		{
			debug_mess("ОШИБКА: не дождались появление файла по заданному пути $path!");
			return false;   
		}

		$a++;

	}

	return true;   
} 

Быстрый поиск разницы файлов

Ну собственно это история одной маленькой победы, которые происходят обычно у ИТишников каждый день 😉

Предыстория: при работе скрипта по заливке данных в БД из файла произошло зависание сервера. Скрипт работал в несколько потоков с одним файлом. Потому определить на каком именно месте файла произошла остановка не представлялось возможным. Удалять уже залитое в БД и стартовать скрипт заново — не вариант, скрипт и так работал двое суток, и терять их снова — ну так себе решение.

Решение №1. «В лоб». Ну думаю доработаю скрипт так, что если данные уже есть, то просто пропускаем. Т.е. перед вставкой выполняем проверку функцией вида:

function lsYet($period,$ls){
    global $db;
  $res=false;
  $sql="select posting_addresses.id from posting_addresses
    inner join ls on ls.id=posting_addresses.ls
    where 
    posting_addresses.period='$period' and ls.ls='$ls'";
    $query = $db->connection->prepare($sql);
    $query->execute();
    while ($row99 = $query->fetch()) {
      $res=true;
    };        
 return $res;
}

И без проблем дозальем то, чего нет в БД. Да не тут то было, оказывается операция select в этом случае весьма дорогостоящая, и т.к. в БД записей порядка 600тыс, и индексы проставлены на ls и period корректно, но всёж скорость проверки крайне низкая, и т.о. скорость «дозалития» сокращается с двух суток до суток. Ну что собственно не устраивает.

Решение №2. Вдумчивое. Решил было выгрузить ключевые строки (лицевой счет) в файлы: файл ls_in_base.txt — лицевые счета которые уже в БД и ls_all.txt — файл со всеми лицевыми счетами, которые должны быть в БД, отсортировав их командой sort:

sort ls_in_base.txt > ls_in_base.txt
sort ls_all.txt > ls_all.txt

Далее воспользуемся Linux командой comm, вычленив уникальные записи файла ls_all которые не содержаться в файле ls_in_base:

comm -23 ls_all.txt ls_in_base.txt > no_in_base.txt

И далее уже в скрипте вместо проверки наличия лс в БД при помощи запроса, проверяем наличие лс в БД при помощи in_array:

$no_in_base_ls=file_get_contents("no_in_base.txt");
$no_in_base_arr=explode("\n",$no_in_base_ls);
...
if (in_array($ls, $no_in_base_arr)==true){
...
заливаем данные в БД
...
}

В результате скорость увеличилась в разы, и БД дозалить удалось в течении часа

PHP: нормализация номера телефона

Задача: на входе строка, которая может содержать номер, или номер + какие то комментарии к нему. Необходимо нормализовать номер, что бы были только цифры.

Решение:

Сначала напишем функцию проверки наличия букв в строке:

function LeetterYet($mobile){
    $yet=false;            
        if (preg_match('/[а-яё]/iu',    $mobile)) {$yet=true;};    // символ ё, отдельно проверяем
        if (preg_match('/[a-zA-Z]/',    $mobile)) {$yet=true;};    // английский алфавит
        if (preg_match('/[^a-zA-Z\d]/',    $mobile)) {$yet=true;}; // специальные символы
    return $yet;
}

Далее, если есть буквы, то удалим их, и ограничим длинну поля 11 символами..

function NormalizeMobile($mobile){
  $mobile=preg_replace('/[^0-9]/', '', $mobile);
  $mobile = substr($mobile, 0,11);
  return $mobile;
};

И общий результат:

        $mobile=$res->result->mobile;            
        if (LeetterYet($mobile)==false){                
          $mobile=  NormalizeMobile($mobile);
        };
1 5 6 7 8 9 29