1C:Enterprise 8.3 Remote Administrative Client Utility для веб приложения

в 14:16, , рубрики: , javascript, json, php

В связи с переходом на отечественное ПО в организации пришлось искать замену Windows утилиты администрирования кластера. После изучения вопроса выяснилось, что для администрирования кластера 1С существует 3 подхода:

  1. Внешняя обработка внутри 1С — графический интерфейс, кроссплатформенная. В ситуации если все пользовательские лицензии заняты, но нужно посмотреть кем и при необходимости отключить пользователей, забывших выйти из 1с, эта обработка бесполезна.

  2. Windows утилита администрирования кластера — графический интерфейс, только под Windows. Достаточно удобная, но под российскими операционными системами она не работает (может под каким-нибудь wine и запуститься, но этот вариант не всегда приемлем).

  3. Консольная утилита rac (Remote Administrative Client) — кроссплатформенная, но консольная. Конечно, весь функционал присутствует, но не сказать, чтобы это было прямо сильно удобно.

Изучив альтернативные варианты, был найден только один вариант, написанный на java. Кроссплатформенный, с красивым веб-интерфейсом и очень богатый функциями. Весьма не- плохой вариант, но мне его функционала было слишком много (один сервер, два десятка пользователей).

Решил сделать что-то своё с необходимым минимальным количеством функций. Для начала нужно было определиться, как получать данные из 1с. Немного изучив консольное приложение, решил, что проще всего будет сделать небольшой php скрипт (на сервере уже крутилась публикация приложений 1с под apache2), который будет возвращать ответы от консольной утилиты в виде json, а для интерфейса пользователя использовать приложение на javascript.

Когда выбор инструментария был сделан, осталось придумать, в каком виде передавать запросы и параметры для консольной утилиты (rac).

После изучения синтаксиса командной строки оказалось вполне логично передавать все данные запроса через GET запрос. Причём команды удобно передавать как часть URL — путь к ресурсу, а параметры в виде параметров. Таким образом получился следующий формат запроса:

http://localhost/192.168.1.2/infobase/summary/list?cluster=00000000-0000-0000-0000-000000000000

который преобразовывался в командную строку вида:

rac 192.168.1.2 infobase summary list —cluster=00000000-0000-0000-0000-000000000000

Таким образом, можно давать любые команды консольной утилите через URL.

Далее, изучая ответы утилиты администрирования, стало понятно, что нужно делить строки на имя параметра и его значение по символу двоеточия «:», а отделять один блок информации от другого по пустой строке между блоками.

Спустя некоторое время я написал небольшой скрипт, выполняющий задуманное. Чтобы постоянно не писать адрес сервера администрирования, решил его внести в сборку командной строки через определение константы admServer. При необходимости её можно выкинуть из скрипта (ниже привожу листинг моего файла index.php с небольшими комментариями).

<?php
define('pathToRac', '/opt/1cv8/x86_64/8.3.22.2106/rac');
define('admServer', '192.168.1.2');

Определяем константы: pathToRac — путь в утилите администрирования, admServer — IP адрес сервера администрирования (порт стандартный, но можно и указать).

function responseToArray($response)
{
   $result = array();
   $object = array();

   if (count($response) > 0) {
      for ($i = 0; $i < count($response); $i++) {
         if ($response[$i] !== '') {
            preg_match('/(?<key>[^:]*)[ ]*:(?<value>.*)/', $response[$i], $matches);
            $object[trim($matches['key'])] = trim($matches['value']);
         } else {
            $result[] = $object;
            $object = array();
         }
      }
   }

   return $result;
}

Основная функция responseToArray, которая в качестве параметра берёт массив строк ответа от сервера администрирования. В цикле все строки через регулярное выражение разбираются на имя параметра и значение параметра, помещаются во временный массив, а при обнаружении пустой строки элементы временного массива помещаются группой в результирующий массив. После окончания цикла возвращается результирующий массив.

$request = explode('?', $_SERVER['REQUEST_URI']);
$request = array_filter($request, 'strlen');
$parts = explode('/', $request[0]);
$parts = array_filter($parts, 'strlen');

Здесь глобальная переменная REQUEST_URI разделяется по знаку вопроса на две части: адрес и параметры. Удаляются пустые элементы массива ($request). Берётся первая часть ($request[0]) — адрес и разделяется на отдельные команды для утилиты администрирования. Так же удаляются пустые элемента массива ($parts).

if (count($parts) > 0) {
   $commandLine = implode(' ', $parts);
   $params = '';
   foreach ($_GET as $key => $value) {
      if ($key !== '' && $value !== '') {
         $params .= ' ' . '--' . $key . '=' . $value;
      }
   }

   $commandLine = pathToRac . ' ' . admServer . ' ' . $commandLine . $params;
   exec($commandLine, $outputArray, $retval);

Если есть команды для rac, то собираем командную строку. Вначале объединяем в строку все команды через пробел. Далее перебираем все параметры переданные через GET запрос из глобального массива $_GET и собираем их в строковую переменную $params, предварительно добавляя перед именем параметра два знака минус «--», а после знак равно «=» и значение параметра. Следом собираем всю командную строку в переменную $commandLine и передаём на выполнение.

   if ($retval == 0) {
      preg_match('/Remote Administrative Client Utility/', $outputArray[0], $matches);
      if (count($matches) > 0) {
         $result['error'] = -1;
         $result['output'] = $outputArray;
      } else {
         $result['error'] = 0;
         $result['objects'] = responseToArray($outputArray);
      }
   } else {
      $result['error'] = $retval;
      $result['output'] = $outputArray;
   }

В этой части происходит обработка результата выполнения команды. Если получаем код выхода из консольной утилиты равным нулю, значит утилита отработала нормально, и можно разбирать результаты. Если в результате выполнения в первую строку ответа утилиты управления попала подстрока «Remote Administrative Client Utility», то будем считать, что это не результат, который нам нужен, и выставив флажок ($result['error']) успешности выполнения в значение «-1», вернём весь вывод консоли. А если нет выше указанной подстроки, то вывод из консоли обрабатываем нашей функцией responseToArray. При возникновении ошибки значение переменной $retval будет больше 0, значит ставим флажок ($result['error']) в значение вернувшееся после выполнения утилиты администрирования и передаём весь массив строк вывода консоли.

   header('Content-Type: application/json; charset=utf-8');
   echo json_encode($result);
} else {
   include_once('app.php');
}
?>

Оборачиваем ответ в json и передаём на клиентскую сторону. Если никаких параметров в URL не передано, то подключаем скрипт отвечающий за frontend.

Для работы вышеуказанного скрипта ещё нужно настроить веб сервер (у меня настройка для сервера apache2). Содержимое файла .htaccess:

Options -Indexes
ErrorDocument 403 /

<Files *.php>
    deny from all
</Files>

<Files index.php>
    allow from all
</Files>

<IfModule mod_rewrite.c>
    RewriteEngine On
    Options +FollowSymlinks
    RewriteBase /

    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule ^(.*)$ index.php [L,QSA]
</IfModule>

Таким образом получилась обёртка над консольной утилитой, позволяющая создать полноценное веб-приложение.

Поскольку утилита удалённого администрирования консольная и не предоставляет данных в реальном времени, клиентскому веб приложению придётся периодически запрашивать данные.

Надеюсь мой опыт кому-то пригодиться. Спасибо за потраченное на чтение время.

Автор: fr1703

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js