В продолжении темы примитивного логгирования. Понадобилось записывать, какой пользователь открывает какие страницы. И если с клиентским отображением в принципе ничего сложного, просто вставил в /view/layouts/main.php код вида:
if (isset(Yii::$app->user->identity)){
if (isset(Yii::$app->user->identity->username)){
Logger::Log(Yii::$app->user->identity->username." >> ".$_SERVER["REQUEST_URI"]);
}
};
Но, к сожалению оный не перехватывает вызов страниц, которые завершаются в контроллере. Ну например всякие ajax запросы на странице. Поступил чуть хитрее: создал свой компонент в папке components (требуется создать папку если нет):
<?php
namespace app\components;
use yii\base\Component;
use app\models\Logger;
class Logging_at_start extends Component{
public function init() {
Logger::Log(" >> ".$_SERVER["REQUEST_URI"]);
parent::init();
}
}
Иногда необходимо в проект добавить логгирование событий работы, однако не всегда удобно тащить для этого кучу сторонних библиотек. Тем более что особых требований и не нужно. Если достаточно что бы:
логи велись «стандартно» для системы на базе Linux, с автоматической ротацией и т.п.
особых тонкостей и настроек для вывода не нужно, достаточно просто текста
То вполне можно написать свою простенькую модель вида:
<?php
namespace app\models;
use Yii;
class Logger {
const Error=1;
const Info=2;
const Warning=3;
const Success=4;
const Fail=5;
public static function Log($message,$type=self::Info){
$prefix="Info:";
if ($type==self::Error) $prefix="Error";
if ($type==self::Info) $prefix="Info";
if ($type==self::Warning) $prefix="Warning";
if ($type==self::Success) $prefix="Success";
if ($type==self::Fail) $prefix="Fail";
/usr/bin/logger "(GEO) $prefix: $message";
}
}
И использовать её далее в любом месте в коде, например так:
Logger::Log("-попытка авторизации в AD $username");
// авторизуемся в AD
$ldapbind = @ldap_bind($ldap_con, $username."@".$value["ldap_server"], $password);
if ($ldapbind==false) {
Logger::Log("--ошибка",Logger::Fail);
return null;
};
Logger::Log("--ok",Logger::Success);
Логи можно будет наблюдать в стандартном /var/log/messages:P.S. Раньше тоже велосипедил с добавлением лога в отдельный файл, а потом подумал «А зачем?». В большинстве случаев достаточно так.
В наличии: файл ovpn. Задача установить соединение.
Решении: напишем скрипт и положим в крон:
# Сей дивный скрипт устанавливает VPN содениение с сервером грибовы.рф и если оное установлено, то включает светодиодик..
result=$(ifconfig | grep tun0)
echo $result
if [[ "$result" == *"tun0"* ]]; then
echo "-ok";
/root/scripts/gpio/led2_on.py
else
echo "-fail";
/usr/sbin/openvpn /root/vpn/malgino.ovpn
fi
Во всех мануалах пишут что бота нужно создавать в боте MasterBot, однако у меня он усиленно пишет что «Сейчас создать бота не получится. Попробуйте позже». Удалось создать только в консоли разработчика из https://business.max.ru/self/#/services, для этого нужно подтвердить организацию при помощи ЭЦП ключа. Простым физическим лицам, похоже пока бота не создать.
Документация по разработке бота тут: https://dev.max.ru/docs-api/ , увы не очень удобная. Как делать некоторые вещи я сделать долго путался, а некоторые так и не удалось, пришлось копаться в исходниках их официального клиента API на Python.
Итак, для начала создал класс для работы с мессенджером, который берет на себя всю рутину:
class TMax {
public $url="";
public $login="";
public $password="";
public function __construct($url,$token) {
$this->url=$url;
$this->token=$token;
}
function Reqwest($reqwest,$params,$type="POST"){
if ($type=="GET"){
$reqwest=$reqwest."?".http_build_query($params);
};
if ($type=="POST"){
$reqwest=$reqwest."?".http_build_query($params);
};
$ch = curl_init($this->url.$reqwest);
$authorization = "Authorization:".$this->token;
$this->PutLog("--(R $type) in $reqwest :".json_encode($params));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/json',$authorization));
if ($type=="POST"){
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($params));
};
if ($type=="PATCH"){
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($params));
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PATCH');
}
curl_setopt($ch, CURLOPT_TIMEOUT, 600);
$res=curl_exec($ch);
if(curl_errno($ch)){
throw new Exception(curl_error($ch));
};
$this->PutLog("--(R) out :".json_encode($res));
$response = json_decode($res);
return $response;
}
function PutLog($txt){
if (DEBUG==true){
$data=Date("m-d-y h:i:s")." ".$txt."\n";
file_put_contents(API_LOG_FILE, $data,FILE_APPEND);
if (DEV_MODE==true){
echo $data."<br/>";
};
};
}
}
Далее необходимо зарегистрировать вебхук, куда платформа будет посылать обновления по по событиям:
$url="https://".$_SERVER["SERVER_NAME"].$_SERVER["SCRIPT_URL"];
echo "-оформляем подписку на текущий URL:$url<br/>";
$params=[];
$params["url"]=$url;
$params["secret"]=secret;
$params["update_types"]=["message_created","bot_started"];
$res=$Max->Reqwest("subscriptions",$params);
if (isset($res->success)){
if ($res->success==true){
echo "-Успешно<br/>";
} else {
echo "-возникла ошибка:".$res->message."<br/>";
};
} else {
echo "-возникла ошибка. Подробности в логах<br/>";
};
die();
Получить информацию о боте можно так:
if (isset($_GET["BotInfo"])){
echo "-информация о боте<br/>";
$params=[];
$res=$Max->Reqwest("me",$params,"GET");
if (isset($res->user_id)){
echo "<pre>";
var_dump($res);
} else {
echo "-возникла ошибка. Подробности в логах<br/>";
};
die();
}
Установить команды бота:
if (isset($_GET["BotCommand"])){ echo "-устанавливаем доступные команды для бота<br/>"; $params=[]; $params[]=["name"=>"Ку","description"=>"Говорить Ку пацаки.."]; $params[]=["name"=>"ЫЫ","description"=>"Говорить ЫЫ пацаки.."]; $params[]=["name"=>"help","description"=>"Тыгыдын"]; $res=$Max->Reqwest("me",["commands"=>$params],"PATCH"); die(); }
Причем установить то я команды установил, но в самом боте в мессенджере они так и не отображаются. Почем? Пока не выяснено.
В самом вебхуке прописал отлов событий присоединения к боту, и пользователь что-то написал. В этом случае отвечаем ему:
Задача: получить по известному индексу почтового отделения, его адрес, GPS координаты и другие данные..
Решение: а просто попарсим страницу почты россии: https://www.pochta.ru/offices, где есть возможность ввода индекса, а в ответ на карте отрисовываються отделения. Чуть нырнув в сетевые запросы, получаем вызов:
который используется самим сайтом почты для получения данных. На выходе очень приятный для парсинга выход. В общем всё оформил в виде простого скрипта:
<?php
$indexs=file_get_contents("posts.list");
$indexs=explode("\n", $indexs);
file_put_contents("res.sql", "", FILE_APPEND | LOCK_EX);
foreach ($indexs as $ind) {
wget https://www.pochta.ru/suggestions/v2/postoffice.find-nearest-by-postalcode-vacancies --header='Content-Type:application/json' --post-data '{"postalCode":"$ind","filters":[],"limit":1,"radius":100,"offset":0,"currentDateTime":"2025-10-28T15:10:00"}' -O tmp.tmp;
$js= json_decode(file_get_contents("tmp.tmp"));
if ($js!=null){
if (count($js)>0){
$otd=$js[0];
$address=$otd->addressSource;
$latitude=$otd->latitude;
$longitude=$otd->longitude;
$sql="udpate posts set name='Почтовое отделение $ind',latitude='$latitude',longitude='$longitude',address='$address' where index='$ind';\n";
echo $sql;
file_put_contents("res.sql", $sql, FILE_APPEND | LOCK_EX);
};
};
};