Рецепт разбора SOAP ответа

Проблема: бывает так, что при вызове soap, ответ на стороне клиента не собирается в объект, это может быть и из-за wsdl или из-за неверного ответа от сервер.

Решение: распарсить ответ от сервере как XML

// выполняем функцию SOAP
$response = $this->client->__soapCall("getParam", $param);

// костыль, так как первый response ничего не вернул, будем тупо парсить  XML ответ
$response = $this->client->__getLastResponse();

// xml парсеру не нравится тег с неймспейсами, вырезаем их
$response = str_ireplace(array('soapenv:', 'tem:', 'SOAP-ENV:', 'rpc:'), '', $response);
$xml = simplexml_load_string($response, "SimpleXMLElement", LIBXML_NOCDATA);

$json = json_encode($xml);
$arrayResponse = json_decode($json,TRUE);

Если есть ошибка при разборе, можно поиграть с параметрами

$xml = simplexml_load_string($response, «SimpleXMLElement», LIBXML_COMPACT | LIBXML_PARSEHUGE);

Асинхронное выполнение кода PHP (нет)

В книге «Symfony 5. Быстрый старт» есть хороший пример, когда нам надо выполнить какие то долгие действия  (отправить почту, вызвать сторонний API) но не заставлять пользователя ждать. Для этого используется очередь. Мы в очередь записываем действие, сразу отправляем ответ пользователю а дальше уже, в другом скрипте делаем задачи из очереди.

Но если по каким то причинам, вы не можете поставить rabbitmq или вам это будет «ДОРОГО», считай излишни, можно обойтись таким асинхронным выполнением. Суть его в том, что все действия делаем быстро, отдаем ответ клиенту, а потом уже, когда он отключился, продолжаем выполнять свои задачи:

<?php

// Игнорирует отключение пользователя 
ignore_user_abort(true);
//позволяет скрипту быть запущенным постоянно
set_time_limit(0);

// старт буфиризации
ob_start();
// вывести результат в буфер
echo $result;
$length = ob_get_length();


header('Connection: close');
header("Content-Length: " . $length);
header("Content-Encoding: none");
header("Accept-Ranges: bytes");
// отключаем буфиризацию
ob_end_flush();
// сбросить (отправить) буфер вывода
ob_flush();
// сброс системного буфера вывода
flush();


// а вот тут уже делаем все остальное

По такому принципу у меня работает Telegram бот, он на входе принимает сообщение с внешнего источника, и тут же отключает этот источник от себя, а уже дальше отправляет сообщение в телегу

Yandex поступает подло

Уже с месяц Яндекс блокирует строку поиска для тех, у кого включена блокировка Яндекс метрики. Выглядит это вот так:

ya1

 

Довольно подло. Стоит отключить блокировщик, как все работает

ya2

 

Мы не гордые, пойдем в гугл.

 

Дайджест-аутентификация (Digest access authentication)

Ранее я описывал алгоритм авторизации Digest, как самому собрать пакет данных

Для  PHP все оказалось проще,  в  CURL уже есть готовый механизм, который делает 2 запроса для правильной авторизации

Это параметр CURLOPT_HTTPAUTH => CURLAUTH_DIGEST,

 

 

Полностью запрос:


$request =[
    'SOAPAction: "http://yandex.ru/"',
    'Content-Type: text/xml;charset=UTF-8',
];


$options = array(
    CURLOPT_URL            => $url,
    CURLOPT_HEADER         => true,
    CURLOPT_VERBOSE        => true,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_FOLLOWLOCATION => true,
    CURLOPT_SSL_VERIFYPEER => false,    // for https
    CURLOPT_USERPWD        => $username . ":" . $password,
    CURLOPT_HTTPAUTH       => CURLAUTH_DIGEST,
    CURLOPT_HTTPHEADER     => $request,
    CURLOPT_POST           => true,

    CURLOPT_POSTFIELDS     =>"xmlRequest=" . $input_xml // если нужно передать xml в теле POST
);

$ch = curl_init();

curl_setopt_array( $ch, $options );

try {
    $raw_response  = curl_exec( $ch );


    // validate CURL status
    if(curl_errno($ch))
        throw new Exception(curl_error($ch), 500);

    // validate HTTP status code (user/password credential issues)
    $status_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);

    if ($status_code != 200)
        throw new Exception("Response with Status Code [" . $status_code . "].", 500);

} catch(Exception $ex) {
    if ($ch != null) curl_close($ch);
    throw new Exception($ex);
}

if ($ch != null) curl_close($ch);

echo "raw response: " . $raw_response;



The Twelve-Factor App

https://12factor.net/ru/

Understanding your Symfony app with Prometheus:

https://blog.4xxi.com/understanding-your-symfony-app-with-prometheus-fdb4b0124d99

 

 

Сбор и анализ логов с Fluentd:

 

 

https://habr.com/ru/company/selectel/blog/250969/

 

О сборке метриков:

https://www.youtube.com/watch?v=RPK5fp9-4yI

Fluentd

https://mcs.mail.ru/help/ru_RU/cases-logs/case-swarm

Fluentd docker

https://docs.docker.com/config/containers/logging/fluentd/

PUSHGATWAY

Про PUSHGATWAY очень мало написано в инете, особенно под PHP

Для установки локально PUSHGATWAY docker-compose.yml:

    pushgateway:
        image: prom/pushgateway
        restart: always
        container_name: app2022-pushgateway
        ports:
            - 9091:9091
            - 9090:9090
        networks:
            - front
            - backend

 

Есть библиотека для работы с pushgateway

https://github.com/PromPHP/prometheus_push_gateway_php ->
promphp/prometheus_push_gateway_php

 

Однако, нашел хороший простой класс, который основан на GuzzleHttp\Client:

https://github.com/markarik/wnl-platform/blob/9f4383e850373e1849f04f6d1487268cf91fa615/app/Console/PrometheusPushgateway.php

Немного модифицировал его под свои нужды, и получилось вот такое

<?php
namespace App\Handler;


use GuzzleHttp\Client;
use GuzzleHttp\Exception\GuzzleException;

class PrometheusPushgateway
{
   public function notify($count, $code=200)
   {

        $url = 'http://pushgateway:9091/metrics/job/symfony/instance/sender';
        $url = getenv('PUSHGATWAY_URL');

      $client = new Client();
      try {
         $bodyLines = [
            "# HELP response_symfony_code_count",
            "# TYPE response_symfony_code_count",
            "response_symfony_code_count {code=\"${code}\"} ${count}"
         ];
         $body = implode("\n", $bodyLines) . "\n";
         $client->request('POST', $url, [
            'body' => $body
         ]);
      } catch (GuzzleException $exception) {
          exit('error');
      }
   }
}

 

 

Symfony full info

#!/bin/bash
php -i
php bin/console debug:config framework profiler
php bin/console debug:config web_profiler
php bin/console debug:container profiler --show-arguments
php bin/console debug:container web_profiler.debug_toolbar --show-arguments
php bin/console debug:event-dispatcher kernel.response
php bin/console about
php bin/console debug:router