<?xml version="1.0" encoding="utf-8"?> 
<rss version="2.0"
  xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd"
  xmlns:atom="http://www.w3.org/2005/Atom">

<channel>

<title>Воронин: заметки с тегом php</title>
<link>https://voronin.one/tags/php/</link>
<description>воронин, voronin, it</description>
<author></author>
<language>ru</language>
<generator>Aegea 11.4 (v4171)</generator>

<itunes:subtitle>воронин, voronin, it</itunes:subtitle>
<itunes:image href="" />
<itunes:explicit></itunes:explicit>

<item>
<title>Увеличиваем размер принимаемого сообщения в iRedMail</title>
<guid isPermaLink="false">43</guid>
<link>https://voronin.one/all/uvelichivaem-razmer-prinimaemogo-soobscheniya-v-iredmail/</link>
<pubDate>Wed, 03 May 2023 13:18:44 +0300</pubDate>
<author></author>
<comments>https://voronin.one/all/uvelichivaem-razmer-prinimaemogo-soobscheniya-v-iredmail/</comments>
<description>
&lt;p&gt;Увеличим размер почтового сообщения до 35Мб&lt;/p&gt;
&lt;p&gt;меняем настройки postfix&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;postconf -e message_size_limit=36700160
postconf -e mailbox_size_limit=36700160&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;перечитываем изменения службой postfix&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;sudo systemctl reload postfix&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;редактируем php.ini&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;sudo mcedit /etc/php/7.4/fpm/php.ini&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;ищем переменные и меняем значения на нужные нам&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;memory_limit = 256M;
upload_max_filesize = 35M;
post_max_size = 37M;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;рестартим php&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;sudo systemctl restart php7.4-fpm&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;редактируем конфиг roundcube&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;sudo mcedit /opt/www/roundcubemail/config/config.inc.php&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;ищем настройку максимального размера сообщения и меняем значение&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;$config[&amp;#039;max_message_size&amp;#039;] = &amp;#039;35M&amp;#039;;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;редактируем конфиг nginx&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;sudo mcedit /etc/nginx/conf-enabled/client_max_body_size.conf&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;ищем переменную и меняем значение на своё&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;client_max_body_size 100m;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;проверяем правильность конфига&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;sudo nginx -t&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;перечитываем изменения службой nginx&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;sudo systemctl reload nginx&lt;/code&gt;&lt;/pre&gt;</description>
</item>

<item>
<title>Прощай Яндекс почта</title>
<guid isPermaLink="false">38</guid>
<link>https://voronin.one/all/proschay-yandeks-pochta/</link>
<pubDate>Tue, 02 May 2023 18:04:43 +0300</pubDate>
<author></author>
<comments>https://voronin.one/all/proschay-yandeks-pochta/</comments>
<description>
&lt;p&gt;Была у меня почта на Яндексе, уже была, т. к. последний сделал её платной. Что же, я перевёз свои 12 ящиков, и вы справитесь.&lt;/p&gt;
&lt;p&gt;Схема самая простая, сначала разворачиваем свой почтовый сервер (настраиваем его), затем перевозим ящики (по одному), бонусом тюним web-интерфейс Roundcube.&lt;/p&gt;
&lt;p&gt;Все представленные здесь решения являются бесплатными для личного пользования, ваша задача только оплата VDS.&lt;/p&gt;
&lt;p&gt;Системные требования для моих задач (12 ящиков, 1 основной домен и 3 элиаса):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;OC Linux&lt;/li&gt;
&lt;li&gt;CPU 1&lt;/li&gt;
&lt;li&gt;RAM 4 Гб&lt;/li&gt;
&lt;li&gt;HDD 100 Гб&lt;/li&gt;
&lt;li&gt;IP 1&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Возможно вам потребуется больше, тут всё зависит от бюджета и нагрузки, системные требования для iRedMail предполагают от 4Гб оперативной памяти, а для поддержки 500 клиентов так все 16Гб.&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://voronin.one/pictures/image-38.png" width="538" height="224" alt="" /&gt;
&lt;/div&gt;
&lt;p&gt;Я не буду останавливаться на развёртывание системы, в моём примере debian 11, многие хостеры это сделаю для вас автоматически.&lt;br /&gt;
Не забудьте прописать в DNS зону A, например mail.{domain}.ru&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://voronin.one/pictures/image-39.png" width="447" height="35" alt="" /&gt;
&lt;/div&gt;
&lt;p&gt;Прошу обратить внимание, зону MX мы не трогаем, чтобы пока мы настраиваем новый сервер, не потерять сообщения приходящие на старый.&lt;/p&gt;
&lt;p&gt;коннектимся в консоль сервера и создаем пользователя с sudo&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;su -
apt update
apt install mc sudo -y
useradd {username}
passwd {username}
usermod -aG sudo {username}&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;
&lt;li&gt;mc ставлю ради mcedit&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Логинимся под свеже созданным пользователем и назначаем серверу его имя как указывали в DNS&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;sudo hostnamectl set-hostname mail.{domain}.ru&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;в файле «/etc/hosts» руками правим имя локалхоста&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;sudo mcedit /etc/hosts&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;должно получиться так&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;127.0.0.1       mail.{domain}.ru localhost&lt;/code&gt;&lt;/pre&gt;&lt;div class="e2-text-picture"&gt;
&lt;img src="https://voronin.one/pictures/pereezd-pochty-s-yandeksa.png" width="486" height="132" alt="" /&gt;
&lt;/div&gt;
&lt;p&gt;проверяем&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;hostname -f&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Начинаем непосредственно установку сервера, для этого определяем ссылку на актуальный дистрибутив, переходим сюда: &lt;a href="https://iredmail.com/download.html"&gt;https://iredmail.com/download.html&lt;/a&gt; , кликаем правой кнопкой мыши на стабильной версии и копируем ссылку на скачивание&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://voronin.one/pictures/pereezd-pochty-s-yandeksa-1.png" width="800" height="254.01207937877" alt="" /&gt;
&lt;/div&gt;
&lt;p&gt;в консоли идем в домашнюю папку и скачиваем дистрибутив&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;cd ~
wget https://github.com/iredmail/iRedMail/archive/refs/tags/1.6.2.tar.gz&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;распаковываем его, переходим в полученную папку делаем файл «iRedMail-1.6.2» исполняемым и запускаем установку&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;tar xvf 1.6.2.tar.gz
cd iRedMail-1.6.2/
chmod +x iRedMail.sh
sudo bash iRedMail.sh&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;после того как скрипт скачет необходимые пакеты запустится визард, который поможет провести первоначальную настройку&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://voronin.one/pictures/pereezd-pochty-s-yandeksa-2.png" width="639" height="349" alt="" /&gt;
&lt;/div&gt;
&lt;p&gt;указываем путь, где будут храниться почтовые сообщения и бэкапы базы данных&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://voronin.one/pictures/pereezd-pochty-s-yandeksa-3.png" width="637" height="351" alt="" /&gt;
&lt;/div&gt;
&lt;p&gt;выбираем какой web-сервер будет установлен, ну как выбираем, соглашаемся с nginx&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://voronin.one/pictures/pereezd-pochty-s-yandeksa-4.png" width="631" height="339" alt="" /&gt;
&lt;/div&gt;
&lt;p&gt;далее выбираем какую базу данных будет использовать почтовый сервер (я выбираю MariaDB)&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://voronin.one/pictures/pereezd-pochty-s-yandeksa-5.png" width="635" height="346" alt="" /&gt;
&lt;/div&gt;
&lt;p&gt;придумываем и указываем пароль для администратора базы данных, можно сейчас записать, а можно дождаться окончания установки и получить все логины и пароли в первом письме&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://voronin.one/pictures/pereezd-pochty-s-yandeksa-6.png" width="637" height="349" alt="" /&gt;
&lt;/div&gt;
&lt;p&gt;указываем имя домена, не имя сервера, а имя домена!&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://voronin.one/pictures/pereezd-pochty-s-yandeksa-7.png" width="638" height="350" alt="" /&gt;
&lt;/div&gt;
&lt;p&gt;задаём пароль администратора почтового сервера&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://voronin.one/pictures/pereezd-pochty-s-yandeksa-8.png" width="639" height="347" alt="" /&gt;
&lt;/div&gt;
&lt;p&gt;указываем необходимые нам компоненты, для простого и лёгкого сервера я бы рекомендовал остановиться на почтовом web-клиенте Roundcube, web-панели администратора iRedAdmin и fail2ban для защиты от подбора паролей пользователей&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://voronin.one/pictures/pereezd-pochty-s-yandeksa-9.png" width="634" height="347" alt="" /&gt;
&lt;/div&gt;
&lt;p&gt;проверяем настройки и подтверждаем их&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://voronin.one/pictures/pereezd-pochty-s-yandeksa-10.png" width="586" height="367" alt="" /&gt;
&lt;/div&gt;
&lt;p&gt;теперь остаётся ждать, пока инсталляционный скрипт завершит свою работу&lt;/p&gt;
&lt;p&gt;после завершения установки подтвердите настройки файервола&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://voronin.one/pictures/pereezd-pochty-s-yandeksa-11.png" width="592" height="95" alt="" /&gt;
&lt;/div&gt;
&lt;p&gt;Я вас поздравляю, теперь можно получить доступ к ресурсам сервера по следующим адресам:&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;- Roundcube webmail: https://mail.{domain}.ru/mail/
- Web admin panel (iRedAdmin): https://mail.{domain}.ru/iredadmin/

- Username: postmaster@{domain}.ru
- Password: BTAyZswFv4VroUP2oPTUkaikMETc6pyY&lt;/code&gt;&lt;/pre&gt;&lt;hr /&gt;
&lt;p&gt;Если захотите добавить элиас домена через бесплатную админку этого сделать не получится, но можно внести значения напрямую в базу (работает как с MySQL, так и с PostgreSQL)&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;mysql -u root
sql&amp;gt; USE `vmail`;
sql&amp;gt; INSERT INTO `alias_domain` (`alias_domain`, `target_domain`) VALUES (&amp;#039;{alias}.ru&amp;#039;, &amp;#039;{domain}.ru&amp;#039;);&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;удалить элиас так:&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;mysql -u root
sql&amp;gt; USE `vmail`;
sql&amp;gt; DELETE FROM `alias_domain` WHERE `alias_domain` = &amp;#039;{alias}.ru&amp;#039;;&lt;/code&gt;&lt;/pre&gt;&lt;hr /&gt;
&lt;p&gt;На этом можно было бы и закончить, но есть моменты на которых я предлагаю остановиться, назовём это улучшения вашего сервера&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;a href="https://voronin.one/drafts/cistema-indeksacii-lucene-dlya-dovecot-debian/"&gt;Система индексации lucene для Dovecot (debian)&lt;/a&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;a href="https://voronin.one/all/otklyuchaem-protokol-pop3-iredmail/"&gt;Отключаем протокол pop3 (делал чисто для себя, т.к .не пользуюсь им, слишком устаревший)&lt;/a&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;a href="https://voronin.one/all/vypuskaem-sertifikat-lets-encrypt-i-nastraivaem-avtomaticheskiy/"&gt;Выпускаем подтверждённый сертификат Let’s encrypt и настраиваем автоматический перевыпуск сертификата&lt;/a&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;a href="https://voronin.one/all/uvelichivaem-razmer-prinimaemogo-soobscheniya-v-iredmail/"&gt;Как увеличить размер принимаемого сообщения, например до 35Мб?&lt;/a&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;a href="https://voronin.one/all/obnovlyaem-clamav-na-territorii-rf/"&gt;Есть проблемы с антивирусом clamav на территории РФ, после первоначальной установки он у вас просто не запустится, т. к. не сможет обновить свои базы, как решить?&lt;/a&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;готово! наш сервер готов принять письма&lt;/p&gt;
&lt;p&gt;Через Админку создаём пользовательские ящики, которые готовы принять письма&lt;/p&gt;
&lt;p&gt;Меняем запись MX в DNS, чтобы новые сообщения попадали уже на наш сервер&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://voronin.one/pictures/proschay-yandeks-pochta-1.png" width="466" height="35" alt="" /&gt;
&lt;/div&gt;
&lt;p&gt;Ждём когда изменения вступят в силу, максимум 3 часа, вы увидите, как сообщения появятся в ящиках на новом сервере, всё — это значит пора перевозить старые письма. Для этого воспользуемся моим скриптом: &lt;a href="https://voronin.one/all/skript-dlya-perenosa-elektronnoy-pochty-iz-odnogo-yaschika-v-dru/"&gt;https://voronin.one/all/skript-dlya-perenosa-elektronnoy-pochty-iz-odnogo-yaschika-v-dru/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Адресную книгу без проблем перенесёте через экспорт/импорт.&lt;br /&gt;
А вот правила фильтрации в яндексе «фильдеперсовые», их только вручную можно перенести, хоть в Roundcube есть возможность подгрузить правила sieve из файла.&lt;/p&gt;
</description>
</item>

<item>
<title>скрипт для переноса электронной почты из одного ящика в другой</title>
<guid isPermaLink="false">39</guid>
<link>https://voronin.one/all/skript-dlya-perenosa-elektronnoy-pochty-iz-odnogo-yaschika-v-dru/</link>
<pubDate>Tue, 02 May 2023 18:04:04 +0300</pubDate>
<author></author>
<comments>https://voronin.one/all/skript-dlya-perenosa-elektronnoy-pochty-iz-odnogo-yaschika-v-dru/</comments>
<description>
&lt;p&gt;Скрипт максимально простой, написан на php, так же потребуется модуль php-imap, работает из командной строки любого устройства (сервера). Принцип простой, скрипт подключается к исходному ящику по протоколу IMAP сканирует структуру почтовых папок, подключается к целевому ящику IMAP, воссоздаёт папки которых нет и загружает в них письма. Опционально может создать структуру папок локально и скачать в них письма в формате eml.&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;&amp;lt;?php

//папка, куда будет сохраняться структура ящика с письмами
$path_to_mail = &amp;#039;boxes&amp;#039;;

//сохранять локально копию ящика
$save_local_copy = 0;

//декодировать имя папки или нет для локальной копии
$decode_folder_name = 1;

//данные ящика откуда переезжаем (например яндекс)
$source_server = &amp;#039;imap.yandex.ru&amp;#039;;
$source_port = &amp;#039;993&amp;#039;;
$source_user = &amp;#039;{user}@{domain}.ru&amp;#039;;
$source_pass = &amp;#039;P@$$word&amp;#039;;

//данные ящика куда переезжаем
$target_server = &amp;#039;mail.{domain}.ru&amp;#039;;
$target_port = &amp;#039;993&amp;#039;;
$target_user = &amp;#039;{user}@{domain}.ru&amp;#039;;
$target_pass = &amp;#039;P@$$word&amp;#039;;

function check_folder_exist($folders_list, $check_folder_name) {
  $fl_exist = false;
  foreach ($folders_list as $val) {
    if ($val-&amp;gt;name == $check_folder_name) {
      $fl_exist = true;
    }
  }
  return $fl_exist;
}

$path_to_mail .= DIRECTORY_SEPARATOR.$source_user.DIRECTORY_SEPARATOR;

$source_server_str = &amp;quot;{&amp;quot;.$source_server.&amp;quot;:&amp;quot;.$source_port.&amp;quot;/imap/ssl}&amp;quot;;
$source_mbox = imap_open($source_server_str,$source_user,$source_pass)
      or die(&amp;quot;can&amp;#039;t connect: &amp;quot; . imap_last_error());

$target_server_str = &amp;quot;{&amp;quot;.$target_server.&amp;quot;:&amp;quot;.$target_port.&amp;quot;/imap/ssl}&amp;quot;;
$target_mbox = imap_open($target_server_str,$target_user,$target_pass)
      or die(&amp;quot;can&amp;#039;t connect: &amp;quot; . imap_last_error());

$target_list = imap_getmailboxes($target_mbox, $target_server_str, &amp;quot;*&amp;quot;);
if (is_array($target_list)) {
    foreach ($target_list as $key =&amp;gt; $val) {
      $folder_name = str_replace($target_server_str,&amp;#039;&amp;#039;,$val-&amp;gt;name);
      $target_delimiter = $val-&amp;gt;delimiter;
    }
} else {
    echo &amp;quot;imap_getmailboxes failed: &amp;quot;.imap_last_error().&amp;quot;\n&amp;quot;;
}

$source_list = imap_getmailboxes($source_mbox, $source_server_str, &amp;quot;*&amp;quot;);
if (is_array($source_list)) {
    foreach ($source_list as $key =&amp;gt; $val) {
        $source_full_folder_name = $val-&amp;gt;name;
        $source_delimiter = $val-&amp;gt;delimiter;
        $con=imap_open($source_full_folder_name, $source_user, $source_pass);
        $number_msg=imap_num_msg($con);
        $folder_name = str_replace($source_server_str,&amp;#039;&amp;#039;,$source_full_folder_name);
        if ($decode_folder_name) {
          $current_folder_name = mb_convert_encoding($folder_name, &amp;quot;UTF8&amp;quot;, &amp;quot;UTF7-IMAP&amp;quot;);
        } else {
          $current_folder_name = $folder_name;
        }
        $full_new_folder_name = $target_server_str.str_replace($source_delimiter,$target_delimiter,$folder_name);
        echo $full_new_folder_name.&amp;quot;\n&amp;quot;;
        if (!(check_folder_exist($target_list, $full_new_folder_name))) {
          echo &amp;#039;папка &amp;quot;&amp;#039;.mb_convert_encoding($folder_name, &amp;quot;UTF8&amp;quot;, &amp;quot;UTF7-IMAP&amp;quot;).&amp;#039;&amp;quot; отсутствует на сервере, создаём&amp;#039;.&amp;quot;\n&amp;quot;;
          
          imap_createmailbox($target_mbox, $full_new_folder_name);
        }
        if ((!file_exists($path_to_mail.str_replace($source_delimiter,DIRECTORY_SEPARATOR,$current_folder_name))) and ($save_local_copy)) {
            mkdir($path_to_mail.str_replace($source_delimiter,DIRECTORY_SEPARATOR,$current_folder_name), 0777, true);
        }
        echo mb_convert_encoding($folder_name, &amp;quot;UTF8&amp;quot;, &amp;quot;UTF7-IMAP&amp;quot;).&amp;quot;: &amp;quot;;
        echo $number_msg.&amp;quot;\n&amp;quot;;
        for ($i = 1; $i &amp;lt;= $number_msg; $i++) {
          if (!imap_ping($con)) {
              // если вдруг связь первалась, восстанавливаем
              echo &amp;quot;$i ой, reconnect $source_server\n&amp;quot;;
              $i--;
              $con=imap_open($val-&amp;gt;name, $source_user, $source_pass);
          }
          if (!imap_ping($target_mbox)) {
              // если вдруг связь первалась, восстанавливаем
              echo &amp;quot;$i ой, reconnect $target_server\n&amp;quot;;
              $target_mbox = imap_open($target_server_str,$target_user,$target_pass);
          }
          echo &amp;quot;.&amp;quot;;
          $headers = imap_fetchheader($con, $i, FT_PREFETCHTEXT);
          $body = imap_body($con, $i);
          imap_append($target_mbox, $full_new_folder_name, $headers.&amp;quot;\n\n&amp;quot;.$body,&amp;quot;\\Seen&amp;quot;);
          if ($save_local_copy) {
            file_put_contents($path_to_mail.str_replace($val-&amp;gt;delimiter,DIRECTORY_SEPARATOR,$current_folder_name).DIRECTORY_SEPARATOR.str_pad($i, 8, &amp;quot;0&amp;quot;, STR_PAD_LEFT).&amp;quot;.eml&amp;quot;, $headers.&amp;quot;\n\n&amp;quot;.$body);
          }
        }
        echo &amp;quot;\n&amp;quot;;
      imap_close($con);
    }
} else {
    echo &amp;quot;imap_getmailboxes failed: &amp;quot;.imap_last_error().&amp;quot;\n&amp;quot;;
}
imap_close($source_mbox);
imap_close($target_mbox);

?&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;$path_to_mail — относительный путь к папке, где будет храниться локальная копия ящика, актуально когда «$save_local_copy = 1»&lt;/p&gt;
&lt;p&gt;$save_local_copy = 1 будет сохраняться локальная копия писем на жёстком диске, соответственно, если «0» — не будет&lt;/p&gt;
&lt;p&gt;$decode_folder_name = 1 имена папок будут декодированы в нормальный вид, если «0» — то будет использован формат UTF7, как они хранятся на сервере.&lt;/p&gt;
&lt;p&gt;Все письма, которые будут перенесены в новый ящик получат статус прочитанных, извините, я не заморачивался с перенесением флагов.&lt;/p&gt;
&lt;p&gt;Перед прочтением сообщения пингуется соединение с сервером IMAP, в случае его обрыва — соединение восстанавливается. Замедление совсем небольшое, зато надёжность вырастает многократно.&lt;/p&gt;
&lt;p&gt;Учитываются разделители вложенности папок (например у яндекса это «|», в iRedMail «/»).&lt;/p&gt;
&lt;p&gt;Копирование писем допускается один раз, если вы прервёте процесс и запустите снова, часть сообщений задублируется.&lt;/p&gt;
</description>
</item>

<item>
<title>автоматизируем очистку почтового ящика по-расписанию</title>
<guid isPermaLink="false">33</guid>
<link>https://voronin.one/all/avtomatiziruem-ochistku-pochtovogo-yaschika-po-raspisaniyu/</link>
<pubDate>Thu, 08 Sep 2022 17:13:44 +0300</pubDate>
<author></author>
<comments>https://voronin.one/all/avtomatiziruem-ochistku-pochtovogo-yaschika-po-raspisaniyu/</comments>
<description>
&lt;p&gt;собственно subj, на примере яндекса&lt;/p&gt;
&lt;p&gt;я хочу удалять с сервера старые письма (старше недели) с уведомлениями, которые у меня накапливаются в отдельной папке&lt;/p&gt;
&lt;p&gt;для начала идём в настройки безопасности &lt;a href="https://id.yandex.ru/security"&gt;https://id.yandex.ru/security&lt;/a&gt;&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://voronin.one/pictures/image-23.png" width="625" height="323" alt="" /&gt;
&lt;/div&gt;
&lt;p&gt;выбираем «Пароли приложений» &lt;a href="https://id.yandex.ru/profile/apppasswords-list"&gt;https://id.yandex.ru/profile/apppasswords-list&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;и создаем новый пароль для приложения, нам требуется сгенерить пароль для доступа к Почте, указываем понятное нам название и генерим пароль&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://voronin.one/pictures/image-25.png" width="668" height="395" alt="" /&gt;
&lt;/div&gt;
&lt;p&gt;на самом деле — это очень правильно, т. к. мы не будем хранить в ком-то скрипте свой основной пароль в открытом виде&lt;/p&gt;
&lt;p&gt;а дальше, собственно, сам скрипт&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;&amp;lt;?php
$auth_mail = &amp;#039;user@yandex.ru&amp;#039;; // логин
$auth_pass = &amp;#039;$tr0ngP@$$w0rd&amp;#039;; // пароль
$server = &amp;#039;{imap.yandex.ru:993/imap/ssl}&amp;#039;.&amp;#039;INBOX&amp;#039;; // подключение к серверу к папке входящие
$filter_str = &amp;#039;BEFORE &amp;quot;&amp;#039;.date(&amp;#039;d-M-Y&amp;#039;, strtotime(&amp;#039;-7 days&amp;#039;)).&amp;#039;&amp;quot;&amp;#039;; // фильтр, чтобы получить письма старше 7 дней

$imap = imap_open($server, $auth_mail, $auth_pass) or die(&amp;quot;Не удалось подключиться: &amp;quot;.imap_last_error());
// подключаемся
$some = imap_search($imap, $filter_str);
// применяем фильтр
if ($some !== false) {
// если что-то нашли - в цикле обходим
foreach ($some as $msg_id)
{ //  и помечаем на удаление каждое письмо с его id
echo &amp;quot;delete message #&amp;quot;.$msg_id.&amp;quot;\n&amp;quot;;
imap_delete($imap, $msg_id);
}
}
// окончательно удаляем отмеченные письма и отключаемся
imap_expunge($imap);
imap_close($imap);
?&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;обратите внимание, я в переменную «$server» добавил строку из двух частей, вторая чать в примере подключит вас к папке «Входящие», если вам надо выбрать другую папку — укажите свой путь, например:&lt;/p&gt;
&lt;p&gt;&lt;b&gt;INBOX|&amp;BCEEPgRGBEEENQRCBDg-&lt;/b&gt; — это папка &lt;b&gt;Входящие — Соцсети&lt;/b&gt;, записанная в кодировке UTF7-IMAP&lt;/p&gt;
&lt;p&gt;список папок можно получить командой&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;$list = imap_list($imap, &amp;quot;{imap.yandex.ru}&amp;quot;, &amp;quot;*&amp;quot;);
if (is_array($list)) {
foreach ($list as $val) {
echo mb_convert_encoding($val, &amp;quot;UTF-8&amp;quot;, &amp;quot;UTF7-IMAP&amp;quot;).&amp;quot;\n&amp;quot;;
echo $val.&amp;quot;\n\n&amp;quot;;
}
}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;первой строкой будет выводится декодированное (читабельное) название, второй строкой исходное, которое и надо будет подставлять в свой скрипт выше&lt;/p&gt;
</description>
</item>

<item>
<title>php пинг устройств</title>
<guid isPermaLink="false">22</guid>
<link>https://voronin.one/all/php-ping-ustroystv/</link>
<pubDate>Wed, 17 Nov 2021 11:16:52 +0300</pubDate>
<author></author>
<comments>https://voronin.one/all/php-ping-ustroystv/</comments>
<description>
&lt;p&gt;проверим скриптом доступно ли устройство&lt;/p&gt;
&lt;p&gt;нашёл функцию на просторах:&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;function ping($host, $timeout = 1) {
    /* ICMP ping packet with a pre-calculated checksum */
    $package = &amp;quot;\x08\x00\x7d\x4b\x00\x00\x00\x00PingHost&amp;quot;;
    $socket  = socket_create(AF_INET, SOCK_RAW, 1);
    socket_set_option($socket, SOL_SOCKET, SO_RCVTIMEO, array(&amp;#039;sec&amp;#039; =&amp;gt; $timeout, &amp;#039;usec&amp;#039; =&amp;gt; 0));
    socket_connect($socket, $host, null);
    $ts = microtime(true);
    socket_send($socket, $package, strLen($package), 0);
    if (socket_read($socket, 255)) {
        $result = microtime(true) - $ts;
    } else {
        $result = false;
    }
    socket_close($socket);
    return $result;
}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;возвращает в миллисекундах время ответа устройства или ничего не возвращает, если устройство выключено&lt;/p&gt;
&lt;p&gt;Внимание! требует повышение прав&lt;/p&gt;
</description>
</item>

<item>
<title>Synology chat bot (download)</title>
<guid isPermaLink="false">10</guid>
<link>https://voronin.one/all/synology-chat-bot-download/</link>
<pubDate>Thu, 07 Oct 2021 16:09:09 +0300</pubDate>
<author></author>
<comments>https://voronin.one/all/synology-chat-bot-download/</comments>
<description>
&lt;p&gt;сижу, допиливаю функцию, чтобы бот в ответ присылал пользователю файл...&lt;br /&gt;
файл, само собой, будет генериться на лету, за это отвечает скрипт php и будет выдавать примерно следующее:&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;header(&amp;quot;Content-type: text/plain&amp;quot;);
header(&amp;quot;Content-Disposition: attachment; filename=список посещений офиса за &amp;quot;.$monthes[date(&amp;#039;n&amp;#039;, strtotime($_REQUEST[&amp;#039;month&amp;#039;]))].&amp;quot; &amp;quot;.date(&amp;#039;Y&amp;#039;, strtotime($_REQUEST[&amp;#039;month&amp;#039;])).&amp;quot;.log&amp;quot;);
echo $log_str;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;а в самом боте есть вызов этой url, когда-то давно написал функцию&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;function answer_file($user_id,$text,$file,$bot_token)
# $user_id - массив с id
# $text - комментарий к файлу
# $file - url на сам файл
# $bot_token - токен бота
{
    $data = array (
    &amp;#039;text&amp;#039;    =&amp;gt; $text,
    &amp;#039;user_ids&amp;#039;=&amp;gt; $user_id,
&amp;#039;file_url&amp;#039;=&amp;gt; $file
    );
    $options = array(
    &amp;#039;http&amp;#039; =&amp;gt; array(
        &amp;#039;method&amp;#039;  =&amp;gt; &amp;#039;POST&amp;#039;,
        &amp;#039;content&amp;#039; =&amp;gt; &amp;#039;payload=&amp;#039;.json_encode( $data ),
        &amp;#039;header&amp;#039;=&amp;gt;  &amp;quot;Content-Type: application/json\r\n&amp;quot; .
                    &amp;quot;Accept: application/json\r\n&amp;quot;
        )
    );
    $context  = stream_context_create( $options );
    $result = file_get_contents( &amp;#039;https://server/webapi/entry.cgi?api=SYNO.Chat.External&amp;amp;method=chatbot&amp;amp;version=2&amp;amp;token=%22&amp;#039;.$bot_token.&amp;#039;%22&amp;#039;, false, $context );
    $response = json_decode($result);
    return $result;
}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;ну, в целом работает, только я же запрашиваю не существующий файл, а скрипт с параметрами, типа:&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;https://server/bots/get_tabel.php?action=get_log&amp;amp;login=axl&amp;amp;month=2021-09&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;и получаю файл с именем &lt;b&gt;get_tabel.php&lt;/b&gt;&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://voronin.one/pictures/izobrazhenie_2021-10-07_152636.png" width="605" height="230" alt="" /&gt;
&lt;/div&gt;
&lt;p&gt;не такого результата я хотел, ох не такого&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://voronin.one/pictures/izobrazhenie_2021-10-07_154131.png" width="300" height="248" alt="" /&gt;
&lt;/div&gt;
&lt;p&gt;Хорошо, переходим к радикальному методу... т. е. с nginx на apache и используем .htaccess&lt;br /&gt;
в результате нам надо получить url вида:&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;https://server/bots/logs/axl/2021-09/список посещений офиса за сентябрь 2021.log&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;приступим...&lt;/p&gt;
&lt;p&gt;накидаем .htassess, учтем что нам надо использовать скрипт, только когда запрашивается папка logs&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;RewriteEngine On
 
RewriteCond %{SCRIPT_FILENAME} !-d
RewriteCond %{SCRIPT_FILENAME} !-f
 
RewriteRule ^logs/.*$ ./parse.php [L]&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;я временно сделал parse.php чтобы отладить, потом, конечно же перенаправлю на основной скрипт&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;&amp;lt;?php

$path = $_SERVER[&amp;#039;REQUEST_URI&amp;#039;];
$paths = explode(&amp;#039;/&amp;#039;, $path);

echo &amp;quot;&amp;lt;pre&amp;gt;&amp;quot;;
print_r ($paths);
echo &amp;quot;&amp;lt;/pre&amp;gt;&amp;quot;;

?&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;и результат запроса&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;Array
(
    [0] =&amp;gt; 
    [1] =&amp;gt; logs
    [2] =&amp;gt; axl
    [3] =&amp;gt; 2021-09
    [4] =&amp;gt; %D1%81%D0%BF%D0%B8%D1%81%D0%BE%D0%BA%20%D0%BF%D0%BE%D1%81%D0%B5%D1%89%D0%B5%D0%BD%D0%B8%D0%B9%20%D0%BE%D1%84%D0%B8%D1%81%D0%B0%20%D0%B7%D0%B0%20%D1%81%D0%B5%D0%BD%D1%82%D1%8F%D0%B1%D1%80%D1%8C%202021.log
)&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;вы не поверите, самое крутое, что htassecc заработал с первого раза 😁&lt;/p&gt;
&lt;p&gt;ну вот... после небольших манипуляций получился красивый результат:&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://voronin.one/pictures/izobrazhenie_2021-10-07_160516.png" width="623" height="236" alt="" /&gt;
&lt;/div&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://voronin.one/pictures/izobrazhenie_2021-10-07_160736.png" width="351" height="318" alt="" /&gt;
&lt;/div&gt;
</description>
</item>

<item>
<title>Synology chat</title>
<guid isPermaLink="false">9</guid>
<link>https://voronin.one/all/synology-chat-2/</link>
<pubDate>Thu, 07 Oct 2021 14:54:19 +0300</pubDate>
<author></author>
<comments>https://voronin.one/all/synology-chat-2/</comments>
<description>
&lt;p&gt;Сегодня сел писать очередного бота и был неприятно удивлён!  А их количество ограничено!!!&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://voronin.one/pictures/izobrazhenie_2021-10-07_144545.png" width="297" height="234" alt="" /&gt;
&lt;/div&gt;
&lt;p&gt;полез в документацию и правда, всего 5 штук можно создавать.&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://voronin.one/pictures/izobrazhenie_2021-10-07_144635.png" width="506" height="136" alt="" /&gt;
&lt;/div&gt;
&lt;p&gt;мдя....  печалька... 🤔&lt;/p&gt;
&lt;p&gt;Ладно, поудалял, так сказать, временных, для экспериментов и создал «Мариванну». Почему такое имя? Она будет заведовать кадровыми делами, вернее автоматизировать кадровые дела...&lt;/p&gt;
&lt;p&gt;Начнём со статистики нашей СКУД. А закончим табелями... или ещё чем-нибудь.&lt;/p&gt;
</description>
</item>

<item>
<title>3 часть, «кропотливая работа и долгожданный успех»</title>
<guid isPermaLink="false">3</guid>
<link>https://voronin.one/all/kropotlivaya-rabota-i-dolgozhdanny-uspeh/</link>
<pubDate>Fri, 24 Sep 2021 17:22:16 +0300</pubDate>
<author></author>
<comments>https://voronin.one/all/kropotlivaya-rabota-i-dolgozhdanny-uspeh/</comments>
<description>
&lt;p&gt;&lt;a href="https://voronin.one/all/kak-nelzya-otnositsya-k-korporativnym-klientam/"&gt;1 часть, «как нельзя относиться к корпоративным клиентам»&lt;/a&gt;&lt;br /&gt;
&lt;a href="https://voronin.one/all/analiz-poluchenie-ishodnyh-dannyh/"&gt;2 часть, «анализ, получение исходных данных»&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Сделай шаг — дорога появится сама собой…&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://voronin.one/pictures/izobrazhenie_2021-09-24_163318.png" width="300" height="225" alt="" /&gt;
&lt;/div&gt;
&lt;p&gt;и мы приступим...&lt;/p&gt;
&lt;p&gt;вот требования graphisoft к сложности паролей:&lt;br /&gt;
Ваш пароль должен:&lt;/p&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;содержать не менее 6 символов&lt;/li&gt;
&lt;li&gt;содержать не менее одной буквы&lt;/li&gt;
&lt;li&gt;содержать не менее одной заглавной буквы&lt;/li&gt;
&lt;li&gt;содержать не менее одной цифры&lt;/li&gt;
&lt;li&gt;отличаться от вашего адреса электронной почты&lt;/li&gt;
&lt;li&gt;не содержать пробелов, знаков препинания, специальных или национальных символов.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;для начала хочу показать небольшую функцию для генерации паролей, фишка в том, что &lt;b&gt;пароль должен содержать минимум две цифры&lt;/b&gt;, да-да... хрен вы зарегистрируетесь с одной цифрой, короче ловите функцию&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;function randomPassword() {
    $alphabet = &amp;quot;abcdefghijklmnopqrstuwxyzABCDEFGHIJKLMNOPQRSTUWXYZ0123456789&amp;quot;;
    $pass = array();
    $alphaLength = strlen($alphabet) - 1;
    for ($i = 0; $i &amp;lt; 10; $i++) {
        $n = rand(0, $alphaLength);
        $pass[] = $alphabet[$n];
    }
$password = implode($pass);
$password = substr_replace($password, rand(0,9), rand(1,3), 0);
$password = substr_replace($password, rand(0,9), rand(4,7), 0);
    return $password;
}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;сразу оговорюсь, при регистрации 150 учёток ни разу не споткнулась 😇&lt;/p&gt;
&lt;p&gt;ну, вроде всё готово для реализации проекта.&lt;/p&gt;
&lt;p&gt;Настоятельно рекомендую зайти на первую страницу и сохранить cookie, чтобы было максимально похоже на действия человека. Так же часто не отправляйте запросы, я регистрировал по одному сотруднику раз в пять минут,  все таки есть опасность словить captcha. Большая активность — подозрительна. А так, раз в пять минут за ночь и пол дня всех зарегистрировал.&lt;/p&gt;
&lt;p&gt;Не буду грузить, расписывая каждое действие, пройдусь по самым главным моментам.&lt;br /&gt;
При отправке данных используется три метода передачи:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;GET&lt;/li&gt;
&lt;li&gt;POST&lt;/li&gt;
&lt;li&gt;PUT&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;пришлось их все учитывать в одной функции, чтобы не плодить сущностей&lt;/p&gt;
&lt;p&gt;так же данные формируются разными форматами&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;application/json&lt;/li&gt;
&lt;li&gt;application/x-www-form-urlencoded&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;я сейчас выложу мою монстровую функцию&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;function get_url($url, $method, $ctype, $referer, $data) {
// $url - ссылка, на страницу
// $method - метод передачи (GET, POST или PUT)
// $ctype - 1, 2 или 3, смотри ниже
// $referer - страница, с которой мы, якобы, перешли
// $data - данные, если отправляем форму
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
if ($data!==&amp;#039;&amp;#039;) {
if ($ctype == 1) {
// если тип данных json
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
} else if ($ctype == 2) {
// если тип данных www-form
curl_setopt($ch, CURLOPT_POSTFIELDS,http_build_query($data));
} else if ($ctype == 3) {
// сложная конструкция, когда нам надо работать с полученным заголовком, чтобы вытащить оттуда token авторизации
curl_setopt($ch, CURLOPT_HEADER, 1);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, FALSE);
curl_setopt($ch, CURLOPT_POSTFIELDS,http_build_query($data));
}
}
curl_setopt($ch, CURLOPT_ENCODING, &amp;#039;gzip, deflate&amp;#039;);
// формируем заголовок запроса
$headers = array();
$headers[] = &amp;#039;Connection: keep-alive&amp;#039;;
$headers[] = &amp;#039;Sec-Ch-Ua: \&amp;quot; Not;A Brand\&amp;quot;;v=\&amp;quot;99\&amp;quot;, \&amp;quot;Opera\&amp;quot;;v=\&amp;quot;79\&amp;quot;, \&amp;quot;Chromium\&amp;quot;;v=\&amp;quot;93\&amp;quot;&amp;#039;;
$headers[] = &amp;#039;Dnt: 1&amp;#039;;
$headers[] = &amp;#039;Sec-Ch-Ua-Mobile: ?0&amp;#039;;
$headers[] = &amp;#039;User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.63 Safari/537.36 OPR/79.0.4143.22&amp;#039;;
if ($ctype == 1) {
// если тип данных json
$headers[] = &amp;#039;Content-Type: application/json; charset=UTF-8&amp;#039;;
} else {
// если тип данных www-form
$headers[] = &amp;#039;Content-Type: application/x-www-form-urlencoded; charset=UTF-8&amp;#039;;
}
$headers[] = &amp;#039;Accept: application/json, text/javascript, */*; q=0.01&amp;#039;;
$headers[] = &amp;#039;X-Requested-With: XMLHttpRequest&amp;#039;;
$headers[] = &amp;#039;Sec-Ch-Ua-Platform: \&amp;quot;Windows\&amp;quot;&amp;#039;;
$headers[] = &amp;#039;Sec-Fetch-Site: same-origin&amp;#039;;
$headers[] = &amp;#039;Sec-Fetch-Mode: cors&amp;#039;;
$headers[] = &amp;#039;Sec-Fetch-Dest: empty&amp;#039;;
$headers[] = &amp;#039;Accept-Language: ru-RU,ru;q=0.9,en-US;q=0.8,en;q=0.7&amp;#039;;
$headers[] = &amp;#039;Origin: &amp;#039;.$referer;
$headers[] = &amp;#039;Referer: &amp;#039;.$referer;
// используем сформированный заголовок
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
// подключаем файл с cookie, сразу в него сохраняем и из него читаем
curl_setopt($ch, CURLOPT_COOKIEFILE, dirname(__FILE__).&amp;#039;/cookie.txt&amp;#039;);
curl_setopt($ch, CURLOPT_COOKIEJAR, dirname(__FILE__).&amp;#039;/cookie.txt&amp;#039;);
$response = curl_exec($ch);
// используем глобальную переменную, чтобы получить token авторизации, который возвращается в header
global $header;
$header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
$header = substr($response, 0, $header_size);
// возвращаем результатом полученный текст
return $response;
if (curl_errno($ch)) {
echo &amp;#039;Error:&amp;#039; . curl_error($ch);
}
curl_close($ch);
}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;вот такая страхолюдина получилась в итоге&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://voronin.one/pictures/izobrazhenie_2021-09-24_165916.png" width="300" height="190" alt="" /&gt;
&lt;/div&gt;
&lt;p&gt;все действия по шагам:&lt;/p&gt;
&lt;ol start="1"&gt;
&lt;li&gt;заполняем форму регистрации и отправляем запрос
&lt;ul&gt;
  &lt;li&gt;открываем главную страницу&lt;/li&gt;
  &lt;li&gt;переходим на страницу личного кабинета&lt;/li&gt;
  &lt;li&gt;проверяем, зарегистрирован ли уже e-mail&lt;/li&gt;
  &lt;li&gt;генерируем пароль&lt;/li&gt;
  &lt;li&gt;отправляем форму с данными&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;подтверждаем регистрацию
&lt;ul&gt;
  &lt;li&gt;результатом отправки регистрационной формы будет json с кодом подтверждения регистрации (ура! не надо лезть в почту пользователя и искать письмо)&lt;/li&gt;
  &lt;li&gt;в этом же json получаем graphisoft id пользователя, потребуется позже&lt;/li&gt;
  &lt;li&gt;подтверждаем регистрацию двумя запросами, как оказалось второй запрос тоже необходим&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;заходим в кабинет администратора и отправляем запрос на присоединение пользователя
&lt;ul&gt;
  &lt;li&gt;аккуратно логинемся в кабинет, получаем json с данными организации, на потребуется graphisoft id организации, для создания запроса на присоединение пользователя&lt;/li&gt;
  &lt;li&gt;формируем и отправляем запрос&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;заходим в кабинет пользователя и подтверждаем запрос
&lt;ul&gt;
  &lt;li&gt;аккуратно логинемся в кабинет пользователя&lt;/li&gt;
  &lt;li&gt;формируем запрос и подтверждаем присоединение к компании&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;ну и сам код:&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;&amp;lt;?php

// данные регистрируемого сотрудника
$fname = &amp;#039;Иван&amp;#039;;
$sname = &amp;#039;Петров&amp;#039;;
$email = &amp;#039;user@domain.ru&amp;#039;;
$pasword = &amp;#039;koo0ovo5Kamu&amp;#039;;

// данные администратора компании
$admin_login = &amp;#039;admin@domain.ru&amp;#039;;
$admin_password = &amp;#039;P@5$w0rD&amp;#039;;

$header = &amp;#039;&amp;#039;;

function get_url($url, $method, $ctype, $referer, $data) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
if ($data!==&amp;#039;&amp;#039;) {
if ($ctype == 1) {
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
} else if ($ctype == 2) {
curl_setopt($ch, CURLOPT_POSTFIELDS,http_build_query($data));
} else if ($ctype == 3) {
curl_setopt($ch, CURLOPT_HEADER, 1);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, FALSE);
curl_setopt($ch, CURLOPT_POSTFIELDS,http_build_query($data));
}
}
curl_setopt($ch, CURLOPT_ENCODING, &amp;#039;gzip, deflate&amp;#039;);
$headers = array();
$headers[] = &amp;#039;Connection: keep-alive&amp;#039;;
$headers[] = &amp;#039;Sec-Ch-Ua: \&amp;quot; Not;A Brand\&amp;quot;;v=\&amp;quot;99\&amp;quot;, \&amp;quot;Opera\&amp;quot;;v=\&amp;quot;79\&amp;quot;, \&amp;quot;Chromium\&amp;quot;;v=\&amp;quot;93\&amp;quot;&amp;#039;;
$headers[] = &amp;#039;Dnt: 1&amp;#039;;
$headers[] = &amp;#039;Sec-Ch-Ua-Mobile: ?0&amp;#039;;
$headers[] = &amp;#039;User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.63 Safari/537.36 OPR/79.0.4143.22&amp;#039;;
if ($ctype == 1) {
$headers[] = &amp;#039;Content-Type: application/json; charset=UTF-8&amp;#039;;
} else {
$headers[] = &amp;#039;Content-Type: application/x-www-form-urlencoded; charset=UTF-8&amp;#039;;
}
$headers[] = &amp;#039;Accept: application/json, text/javascript, */*; q=0.01&amp;#039;;
$headers[] = &amp;#039;X-Requested-With: XMLHttpRequest&amp;#039;;
$headers[] = &amp;#039;Sec-Ch-Ua-Platform: \&amp;quot;Windows\&amp;quot;&amp;#039;;
$headers[] = &amp;#039;Sec-Fetch-Site: same-origin&amp;#039;;
$headers[] = &amp;#039;Sec-Fetch-Mode: cors&amp;#039;;
$headers[] = &amp;#039;Sec-Fetch-Dest: empty&amp;#039;;
$headers[] = &amp;#039;Accept-Language: ru-RU,ru;q=0.9,en-US;q=0.8,en;q=0.7&amp;#039;;
$headers[] = &amp;#039;Origin: &amp;#039;.$referer;
$headers[] = &amp;#039;Referer: &amp;#039;.$referer;
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_COOKIEFILE, dirname(__FILE__).&amp;#039;/cookie.txt&amp;#039;);
curl_setopt($ch, CURLOPT_COOKIEJAR, dirname(__FILE__).&amp;#039;/cookie.txt&amp;#039;);
$response = curl_exec($ch);
global $header;
$header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
$header = substr($response, 0, $header_size);
return $response;
if (curl_errno($ch)) {
echo &amp;#039;Error:&amp;#039; . curl_error($ch);
}
curl_close($ch);
}

// удаляем старые куки
if (file_exists(dirname(__FILE__).&amp;#039;/cookie.txt&amp;#039;)) {
   unlink(dirname(__FILE__).&amp;#039;/cookie.txt&amp;#039;);
}
// заходим на главную
get_url(&amp;#039;https://graphisoft.com/ru&amp;#039;,&amp;#039;GET&amp;#039;,1,&amp;#039;&amp;#039;,&amp;#039;&amp;#039;);
// переходим на форму пользователя
get_url(&amp;#039;https://graphisoftid.graphisoft.com/Account/ServiceLogin?Application=GRAPHISOFT&amp;amp;ReturnUrl=https://graphisoft.com/ru&amp;#039;,&amp;#039;GET&amp;#039;,1,&amp;#039;https://graphisoftid.graphisoft.com/&amp;#039;,&amp;#039;&amp;#039;);
// переходим на форму регистрации
get_url(&amp;#039;https://graphisoftid.graphisoft.com/#/register/3/https%3a%2f%2fgraphisoft.com%2fru&amp;#039;,&amp;#039;GET&amp;#039;,1,&amp;#039;https://graphisoftid.graphisoft.com/&amp;#039;,&amp;#039;&amp;#039;);

//проверяем e-mail
$check_mail = get_url(&amp;#039;https://graphisoftid.graphisoft.com/api/user/CheckEmail/&amp;#039;,&amp;#039;PUT&amp;#039;,2,&amp;#039;https://graphisoftid.graphisoft.com/&amp;#039;,array(&amp;quot;EmailAddress&amp;quot; =&amp;gt; $email));
if ($check_mail == &amp;#039;true&amp;#039;) {
$data = array(&amp;#039;applicationName&amp;#039; =&amp;gt; null,
  &amp;#039;customDataObject&amp;#039; =&amp;gt; null,
  &amp;#039;redirectUrl&amp;#039; =&amp;gt; null,
  &amp;#039;emailHintLocalizationKey&amp;#039; =&amp;gt; null,
  &amp;#039;firstName&amp;#039; =&amp;gt; $fname,
  &amp;#039;lastName&amp;#039; =&amp;gt; $sname,
  &amp;#039;isValidated&amp;#039; =&amp;gt; true,
  &amp;#039;email&amp;#039; =&amp;gt; $email,
  &amp;#039;password&amp;#039; =&amp;gt; $pasword,
  &amp;#039;confirmPassword&amp;#039; =&amp;gt; $pasword,
  &amp;#039;isPrivacyPolicyAccepted&amp;#039; =&amp;gt; true,
  &amp;#039;companyName&amp;#039; =&amp;gt; &amp;#039;ООО &amp;quot;Рога и Копыта&amp;quot;&amp;#039;,
  &amp;#039;countryId&amp;#039; =&amp;gt; 186,
  &amp;#039;federated&amp;#039; =&amp;gt; false,
  &amp;#039;callbackUrl&amp;#039; =&amp;gt; &amp;#039;https://graphisoft.com/ru&amp;#039;,
  &amp;#039;isDirty&amp;#039; =&amp;gt; true,
  &amp;#039;errors&amp;#039; =&amp;gt; array());

//echo json_encode($data).&amp;quot;\n&amp;quot;;

$ecoded_json = get_url(&amp;#039;https://graphisoftid.graphisoft.com/api/user/CreateUser&amp;#039;,&amp;#039;POST&amp;#039;,1,&amp;#039;https://graphisoftid.graphisoft.com/&amp;#039;,$data);

$jsonObj = json_decode($ecoded_json);

if ($jsonObj === null &amp;amp;&amp;amp; json_last_error() !== JSON_ERROR_NONE) {
   echo &amp;quot;у меня не получилось отправить регистрационную форму с данными...  извините\n&amp;quot;;
} else {
// удаляем старые куки
unlink(dirname(__FILE__).&amp;#039;/cookie.txt&amp;#039;);
get_url($jsonObj-&amp;gt;{&amp;#039;VerificationURL&amp;#039;}.$jsonObj-&amp;gt;{&amp;#039;VerificationCode&amp;#039;},&amp;#039;GET&amp;#039;,1,&amp;#039;&amp;#039;,&amp;#039;&amp;#039;);
$gsid_url = get_url(&amp;#039;https://graphisoftid.graphisoft.com/api/user/VerifyUser&amp;#039;,&amp;#039;PUT&amp;#039;,2,&amp;#039;https://graphisoftid.graphisoft.com/&amp;#039;,array(&amp;quot;code&amp;quot; =&amp;gt; $jsonObj-&amp;gt;{&amp;#039;VerificationCode&amp;#039;}));
$parts = parse_url($gsid_url);
parse_str($parts[&amp;#039;query&amp;#039;], $query);
$user_gsid = $query[&amp;#039;gsid&amp;#039;];
if ($user_gsid !== &amp;#039;&amp;#039;) {
echo &amp;quot;пользователь &amp;quot;.$email.&amp;quot; успешно зарегистрирован (Graphisoft sid: &amp;quot;.$user_gsid.&amp;quot;)\n&amp;quot;;
// удаляем старые куки
unlink(dirname(__FILE__).&amp;#039;/cookie.txt&amp;#039;);
// заходим на главную
get_url(&amp;#039;https://graphisoft.com/ru&amp;#039;,&amp;#039;GET&amp;#039;,1,&amp;#039;&amp;#039;,&amp;#039;&amp;#039;);
get_url(&amp;#039;https://graphisoftid.graphisoft.com/&amp;#039;,&amp;#039;GET&amp;#039;,1,&amp;#039;&amp;#039;,&amp;#039;&amp;#039;);
// авторизуемся под пользователем
$data = array(&amp;#039;email&amp;#039; =&amp;gt; $admin_login,
  &amp;#039;errors&amp;#039; =&amp;gt; array(),
  &amp;#039;isDirty&amp;#039; =&amp;gt; true,
  &amp;#039;isNullo&amp;#039; =&amp;gt; false,
  &amp;#039;password&amp;#039; =&amp;gt; $admin_password);
$json_response = get_url(&amp;#039;https://graphisoftid.graphisoft.com/api/Authenticate/Login&amp;#039;,&amp;#039;POST&amp;#039;,1,&amp;#039;https://graphisoftid.graphisoft.com/&amp;#039;,$data);
$obj = json_decode($json_response);
$companyGsId = $obj-&amp;gt;{&amp;#039;Company&amp;#039;}-&amp;gt;{&amp;#039;GsId&amp;#039;};
// Загружаем список подключенных пользователей
foreach ($obj-&amp;gt;{&amp;#039;Company&amp;#039;}-&amp;gt;{&amp;#039;CompanyUsers&amp;#039;} as $user) {
$users_list[] = array(&amp;quot;FirstName&amp;quot; =&amp;gt; $user-&amp;gt;{&amp;#039;FirstName&amp;#039;},&amp;quot;LastName&amp;quot; =&amp;gt; $user-&amp;gt;{&amp;#039;LastName&amp;#039;},&amp;quot;EmailAddress&amp;quot; =&amp;gt; $user-&amp;gt;{&amp;#039;EmailAddress&amp;#039;},&amp;quot;GsId&amp;quot; =&amp;gt; $user-&amp;gt;{&amp;#039;GsId&amp;#039;});
}


$data = array(&amp;#039;companyGsId&amp;#039; =&amp;gt; $companyGsId,
  &amp;#039;email&amp;#039; =&amp;gt; $email,
  &amp;#039;errors&amp;#039; =&amp;gt; array(),
  &amp;#039;isDirty&amp;#039; =&amp;gt; true,
  &amp;#039;requestedGraphisoftUserId&amp;#039; =&amp;gt; $user_gsid);
get_url(&amp;#039;https://graphisoftid.graphisoft.com/api/user/SendInvitation&amp;#039;,&amp;#039;PUT&amp;#039;,2,&amp;#039;https://graphisoftid.graphisoft.com/&amp;#039;,$data);
echo &amp;quot;выслано приглашение присоединиться к компании\n&amp;quot;;
// удаляем старые куки
unlink(dirname(__FILE__).&amp;#039;/cookie.txt&amp;#039;);
// переходим на форму пользователя
get_url(&amp;#039;https://graphisoftid.graphisoft.com/&amp;#039;,&amp;#039;GET&amp;#039;,1,&amp;#039;&amp;#039;,&amp;#039;&amp;#039;);
// авторизуемся под пользователем
$data = array(&amp;#039;email&amp;#039; =&amp;gt; $email,
  &amp;#039;errors&amp;#039; =&amp;gt; array(),
  &amp;#039;isDirty&amp;#039; =&amp;gt; true,
  &amp;#039;isNullo&amp;#039; =&amp;gt; false,
  &amp;#039;password&amp;#039; =&amp;gt; $pasword);
$json_response = get_url(&amp;#039;https://graphisoftid.graphisoft.com/api/Authenticate/Login&amp;#039;,&amp;#039;POST&amp;#039;,1,&amp;#039;https://graphisoftid.graphisoft.com/&amp;#039;,$data);
$obj = json_decode($json_response);
$user_gsid = $obj-&amp;gt;{&amp;#039;GraphisoftUser&amp;#039;}-&amp;gt;{&amp;#039;GsId&amp;#039;};
if ($user_gsid == &amp;#039;&amp;#039;) {
echo &amp;quot;не смог зайти под пользователем в личный кабинет\n&amp;quot;;
} else {
$data = array(&amp;#039;actionId&amp;#039; =&amp;gt; 2,
  &amp;#039;companyGsId&amp;#039; =&amp;gt; $companyGsId,
  &amp;#039;graphisoftUserGsId&amp;#039; =&amp;gt; $user_gsid,
  &amp;#039;reactionId&amp;#039; =&amp;gt; 1);
get_url(&amp;#039;https://graphisoftid.graphisoft.com/api/user/ProcessingPendingRequest&amp;#039;,&amp;#039;PUT&amp;#039;,1,&amp;#039;https://graphisoftid.graphisoft.com/&amp;#039;,$data);
echo &amp;quot;сотрудник подтвердил приглашение\n&amp;quot;;
}
} else {
echo &amp;quot;у меня не получилось подтвердить регистрацию...  извините\n&amp;quot;;
}
}
} else {
echo &amp;quot;$email уже зарегистрирован в системе\n&amp;quot;;
}
// удаляем старые куки
unlink(dirname(__FILE__).&amp;#039;/cookie.txt&amp;#039;);
?&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;спасибо тем, кто дочитал до конца&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://voronin.one/pictures/izobrazhenie_2021-09-24_172110.png" width="300" height="225" alt="" /&gt;
&lt;/div&gt;
</description>
</item>

<item>
<title>2 часть, «анализ, получение исходных данных»</title>
<guid isPermaLink="false">2</guid>
<link>https://voronin.one/all/analiz-poluchenie-ishodnyh-dannyh/</link>
<pubDate>Fri, 24 Sep 2021 12:30:50 +0300</pubDate>
<author></author>
<comments>https://voronin.one/all/analiz-poluchenie-ishodnyh-dannyh/</comments>
<description>
&lt;p&gt;&lt;a href="https://voronin.one/all/kak-nelzya-otnositsya-k-korporativnym-klientam/"&gt;1 часть, «как нельзя относиться к корпоративным клиентам»&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Всегда начинайте со сбора информации, это важно! Исходные данные определят направление и общую схему работы вашего решения.&lt;/p&gt;
&lt;p&gt;Любая задача решается по принципу «от общего к частному».&lt;/p&gt;
&lt;p&gt;давайте рассмотрим алгоритм действия администратора:&lt;/p&gt;
&lt;ol start="1"&gt;
&lt;li&gt;регистрация пользователя на сайте graphisoft.com&lt;/li&gt;
&lt;li&gt;подтверждение регистрации в посте пользователя&lt;/li&gt;
&lt;li&gt;авторизация на сайте graphisoft.com под административной учетной записью&lt;/li&gt;
&lt;li&gt;отправка приглашения пользователю&lt;/li&gt;
&lt;li&gt;авторизация  на сайте graphisoft.com под пользовательской учетной записью&lt;/li&gt;
&lt;li&gt;подтверждение приглашения&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://voronin.one/pictures/izobrazhenie_2021-09-24_111857.png" width="300" height="179" alt="" /&gt;
&lt;/div&gt;
&lt;p&gt;Вроде, не сложно...  да и в процессе тестовой регистрации я не заметил использования captcha. Это очень важно, иначе полная автоматизация была бы невозможна.&lt;/p&gt;
&lt;p&gt;Какие данные нам нужны, чтобы проделать весь вышеописанный алгоритм?&lt;br /&gt;
данные пользователя:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;имя&lt;/li&gt;
&lt;li&gt;фамилия&lt;/li&gt;
&lt;li&gt;e-mail&lt;/li&gt;
&lt;li&gt;пароль (пароль будем генерировать с учетом требований безопасности graphisoft)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;данные администратора:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;e-mail&lt;/li&gt;
&lt;li&gt;пароль&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://voronin.one/pictures/izobrazhenie_2021-09-24_112041.png" width="300" height="236" alt="" /&gt;
&lt;/div&gt;
&lt;p&gt;Осталось выбрать инструмент для реализации задуманного, я решил остановиться на php, т. к. у нас уже есть некий фундамент автоматизации рутинных процессов, который имеет web интерфейс и уже написан на php. В качестве хранилища информации выступит база MariaDB 10.&lt;/p&gt;
&lt;p&gt;Использовать будем curl, это «наше всё» для работы с web серверами.&lt;/p&gt;
&lt;p&gt;Начнем аккуратно, тут спешка не нужна, будем максимально повторять действия пользователя:&lt;br /&gt;
для начала откроем главную страницу и сохраним все cookies. Они будут, при первом открытии сайта вам сразу предложат принять cookie.&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://voronin.one/pictures/izobrazhenie_2021-09-24_120651.png" width="677" height="142" alt="" /&gt;
&lt;/div&gt;
&lt;p&gt;файл для хранения cookie так и назовём «cookie.txt»&lt;/p&gt;
&lt;p&gt;очень удобно в браузере копировать все необходимые ключи для curl сразу в буфер обмена&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://voronin.one/pictures/izobrazhenie_2021-09-24_121005.png" width="767" height="557" alt="" /&gt;
&lt;/div&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;curl &amp;#039;https://graphisoftid.graphisoft.com/&amp;#039; \
  -H &amp;#039;Connection: keep-alive&amp;#039; \
  -H &amp;#039;sec-ch-ua: &amp;quot; Not;A Brand&amp;quot;;v=&amp;quot;99&amp;quot;, &amp;quot;Opera&amp;quot;;v=&amp;quot;79&amp;quot;, &amp;quot;Chromium&amp;quot;;v=&amp;quot;93&amp;quot;&amp;#039; \
  -H &amp;#039;sec-ch-ua-mobile: ?0&amp;#039; \
  -H &amp;#039;sec-ch-ua-platform: &amp;quot;Windows&amp;quot;&amp;#039; \
  -H &amp;#039;DNT: 1&amp;#039; \
  -H &amp;#039;Upgrade-Insecure-Requests: 1&amp;#039; \
  -H &amp;#039;User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.82 Safari/537.36 OPR/79.0.4143.50&amp;#039; \
  -H &amp;#039;Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9&amp;#039; \
  -H &amp;#039;Sec-Fetch-Site: none&amp;#039; \
  -H &amp;#039;Sec-Fetch-Mode: navigate&amp;#039; \
  -H &amp;#039;Sec-Fetch-User: ?1&amp;#039; \
  -H &amp;#039;Sec-Fetch-Dest: document&amp;#039; \
  -H &amp;#039;Accept-Language: ru-RU,ru;q=0.9,en-US;q=0.8,en;q=0.7&amp;#039; \
  --compressed&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;для ленивых предлагаю воспользоваться online сервисом &lt;a href="https://incarnate.github.io/curl-to-php/"&gt;https://incarnate.github.io/curl-to-php/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Сконвертируем ключи командной строки curl в код php и получим следующее:&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;// Generated by curl-to-PHP: http://incarnate.github.io/curl-to-php/
$ch = curl_init();

curl_setopt($ch, CURLOPT_URL, &amp;#039;https://graphisoftid.graphisoft.com/&amp;#039;);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, &amp;#039;GET&amp;#039;);

curl_setopt($ch, CURLOPT_ENCODING, &amp;#039;gzip, deflate&amp;#039;);

$headers = array();
$headers[] = &amp;#039;Connection: keep-alive&amp;#039;;
$headers[] = &amp;#039;Sec-Ch-Ua: \&amp;quot; Not;A Brand\&amp;quot;;v=\&amp;quot;99\&amp;quot;, \&amp;quot;Opera\&amp;quot;;v=\&amp;quot;79\&amp;quot;, \&amp;quot;Chromium\&amp;quot;;v=\&amp;quot;93\&amp;quot;&amp;#039;;
$headers[] = &amp;#039;Sec-Ch-Ua-Mobile: ?0&amp;#039;;
$headers[] = &amp;#039;Sec-Ch-Ua-Platform: \&amp;quot;Windows\&amp;quot;&amp;#039;;
$headers[] = &amp;#039;Dnt: 1&amp;#039;;
$headers[] = &amp;#039;Upgrade-Insecure-Requests: 1&amp;#039;;
$headers[] = &amp;#039;User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.82 Safari/537.36 OPR/79.0.4143.50&amp;#039;;
$headers[] = &amp;#039;Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9&amp;#039;;
$headers[] = &amp;#039;Sec-Fetch-Site: none&amp;#039;;
$headers[] = &amp;#039;Sec-Fetch-Mode: navigate&amp;#039;;
$headers[] = &amp;#039;Sec-Fetch-User: ?1&amp;#039;;
$headers[] = &amp;#039;Sec-Fetch-Dest: document&amp;#039;;
$headers[] = &amp;#039;Accept-Language: ru-RU,ru;q=0.9,en-US;q=0.8,en;q=0.7&amp;#039;;
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);

$result = curl_exec($ch);
if (curl_errno($ch)) {
    echo &amp;#039;Error:&amp;#039; . curl_error($ch);
}
curl_close($ch);&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;осталось рассмотреть механизм php работы с почтовым ящиком, нам нужен по сути только механизм IMAP, не буду вас сильно грузить, оставлю готовый скрипт, который открывает почтовый ящик пользователя в режиме readonly и находит последнее письмо (если их несколько) от «register-noreply@graphisoft.com», расшифровывает тело письма и вытаскивает код подтверждения. Результатом работы скрипта будет ссылка на подтверждение регистрации или ничего, если письма не было.&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;&amp;lt;?php

$auth_mail = &amp;#039;username@mail.com&amp;#039;;
$auth_pass = &amp;#039;P@$$woRd&amp;#039;;

function get_string_between($string, $start, $end){
    $string = &amp;#039; &amp;#039; . $string;
    $ini = strpos($string, $start);
    if ($ini == 0) return &amp;#039;&amp;#039;;
    $ini += strlen($start);
    $len = strpos($string, $end, $ini) - $ini;
    return substr($string, $ini, $len);
}

$imap   = imap_open(&amp;#039;{imap.mail.com:993/imap/ssl}INBOX&amp;#039;, $auth_mail, $auth_pass, OP_READONLY);
if ($imap) {
$some = imap_search($imap, &amp;#039;FROM &amp;quot;register-noreply@graphisoft.com&amp;quot;&amp;#039;, SE_UID);
if (count($some)&amp;gt;0) {
$mail_body = base64_decode(imap_body($imap, $some[0]));
$key = get_string_between($mail_body,&amp;#039;&amp;lt;span style=&amp;quot;font-weight:bold;&amp;quot;&amp;gt;&amp;#039;,&amp;#039;&amp;lt;/span&amp;gt;&amp;#039;);
echo &amp;#039;https://graphisoftid.graphisoft.com/#/verification/&amp;#039;.$key.&amp;quot;\n&amp;quot;;
}
}
?&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Вроде, все попробовали, ко всему готовы... В процессе реализации обязательно что-то всплывёт... но, в целом мы готовы!&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://voronin.one/pictures/izobrazhenie_2021-09-24_122739.png" width="300" height="230" alt="" /&gt;
&lt;/div&gt;
&lt;p&gt;&lt;a href="https://voronin.one/all/kropotlivaya-rabota-i-dolgozhdanny-uspeh/"&gt;3 часть, «кропотливая работа и долгожданный успех»&lt;/a&gt;&lt;/p&gt;
</description>
</item>


</channel>
</rss>