Передача Журнала и форматирование для 1С

«Посещаемость» поддерживает передачу журнала по HTTP-запросу в формате CSV.

Подробное описание строки содержится в руководстве по эксплуатации «Посещаемость».

Принятый журнал счетчиков возможно импортировать в 1С и т.д.

Рассмотрим пример PHP-скрипта для запроса журналов от нескольких счетчиков, фильтрации событий и записи в файлы для импорта в 1С.

В параметрах запуска скрипта передаются IP-адреса, сетевые имена, порт подключения счетчиков. К примеру, php.exe guestget.php 192.168.0.70 guest.advrouter.asuscomm.com:8009

В начале скрипта константами задаются основные настройки: расположения записываемых файлов, учетная запись для доступа к счетчикам, фильтр событий, шаблон изменения формата строки для записи в CSV-файл.

В скрипте применяется ООП для описания объекта взаимодействия с счетчиком. Далее создается количество объектов в соответствии с количеством переданных IP и сетевых имен.

Из счетчика запрашивается серийный номер, затем журнал работы. Для ускорения работы с несколькими счетчиками HTTP-запросы выполняются одновременно. Обработка журнала выполняется поочереди в момент завершения приема данных.

Принятый журнал в формате CSV в кодировке CP1251 разбивается на строки. Затем применяется фильтр событий, изменение формата полей строки и записывается в файл. Имя файла содержит идентификатор счетчика.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
<?php 
/*****************************************************
	Guestget
Module:
	Guest Get MultiCURL
TIGRA electronic Inc.
Copyright, 02.2019
*****************************************************/

# Скрипт для запроса от счетчиков журнала, преобразования к формату 1С и записи в файл.
# В параметрах запуска указываются IP адреса или имена счетчиков в сети
# Скрипт использует многопоточный доступ к счетчикам, требуется PHP версия не ниже 5.3, модуль CURL
# Строка запуска: php.exe guestget.php guestance guestance1 guestance2 192.168.0.70

define( 'GUESTGET_DIRECTORY', 'reports\\' );					# директория для обработанных файлов
define( 'GUESTGET_LOG', GUESTGET_DIRECTORY.'\\guestget.log' );	# расположение журнала работы программы

define( 'GUESTGET_URL_JOURNAL', '/journal.cgi?t=a&f=c&d=a');	# запрос журнала
#define( 'GUEST_URL_CARDS', '/cards.cgi?f=c');					# запрос карт
define( 'GUESTGET_URL_ID', '/id.xml');							# запрос id

define( 'GUESTGET_ACCESS', 'guest:guest' );		# учетная запись счетчика

#******************* Основные события счетчика **************
define( 'EVENT_ON', 1 );
define( 'EVENT_OFF', 2 );
define( 'EVENT_TIME', 3 );

define( 'EVENT_PASSWORD', 4 );
define( 'EVENT_LOGIN', 5 );
define( 'EVENT_CARD_CHANGE', 6 );

define( 'EVENT_UPDATE_LOAD', 7 );
define( 'EVENT_UPDATE_COMPLETE', 8 );
define( 'EVENT_UPDATE_FAIL', 9 );

define( 'EVENT_INNOW', 10 );
define( 'EVENT_INOUT', 11 );

define( 'EVENT_EMITTER_SHOW', 12 );
define( 'EVENT_EMITTER_HIDE', 13 );

define( 'EVENT_EMAIL', 23 );
define( 'EVENT_CARD', 25 );

#********************* Фильтр событий *******************
define( 'GUESTGET_FILTER', [EVENT_INNOW, EVENT_INOUT] );

#********************* Первая строка в файле *******************
define( 'GUESTGET_FILE_START', "52-3-3\r\n" );

#********************** Изменение строки в журнале для импорта в 1С **********
define( 'GUESTGET_PATTERN', '/(\d+)\/(\d+)\/(\d+) ([\d: ]+),(\d+),(\d*),(\d*).*/' );
define( 'GUESTGET_REPLACE', "$1.$2.$3 $4:00	$6	$7\r\n" );

	ob_implicit_flush();
	date_default_timezone_set('Europe/Moscow');

class Guestget {
	public $id, $idx, $ip, $mh, $chs, $callback;
	function __construct( $idx, $ip, $mh, &$chs ) {
		$this->idx = $idx;
		$this->ip = $ip;
		$this->mh = $mh;
		$this->chs = &$chs;
		$this->request( GUESTGET_URL_ID );		# запрос id счетчика
		$this->callback = "process_id";			# функция обработчика id
	}
	function process_id() {
		if( !preg_match( "/<serial>([0-9]+)<\/serial>/",  $this->get(), $m ) ) {	// взять id счетчика
			$this->slog( "id error\n" );
			return;
		}
		$this->id = $m[1];
		$this->request( GUESTGET_URL_JOURNAL );	# запрос журнала
		$this->callback = "process_journal";	# функция обработчика журнала
	}
	
	function process_journal() {
		$result = explode( "\n", $this->get() );# разделение строк в журнале
		if( $result == NULL )
			return;
		$csv = GUESTGET_FILE_START;			# первая строка в файле
		$filter = GUESTGET_FILTER;
		foreach( $result as $line ) {		# разделение строк и цикл обработки для каждой строки
			if( strlen($line) < 10 )		# для удаления некорректных строк
				continue;
			if( !in_array( explode(',', $line)[1], $filter ) )	# фильтр событий
				continue;
			$csv .= preg_replace(GUESTGET_PATTERN, GUESTGET_REPLACE, $line);	# замена формата строки
		}
		file_put_contents( GUESTGET_DIRECTORY.$this->id."_journal.csv", $csv );		# запись результата в файл
		$this->slog("work complete");
	}
		
	function request( $url ) {				# создание запроса файла
		$this->slog( "request $url" );
		$ch = curl_init( "http://".$this->ip.$url );
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
		curl_setopt($ch, CURLOPT_HEADER, 0);
		curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 30);		# таймаут соединения
		curl_setopt($ch, CURLOPT_TIMEOUT, 30);
		curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
		curl_setopt($ch, CURLOPT_USERPWD, GUESTGET_ACCESS);	# логин и пароль
		curl_multi_add_handle( $this->mh, $ch );
		$this->chs[$this->idx] = $this->ch = $ch;			# записали дескриптор нового запроса
	}
	
	function get() {						# чтение данных и закрытие запроса
		$result = curl_multi_getcontent( $this->ch );
		$info = curl_getinfo($this->ch);
		curl_multi_remove_handle( $this->mh, $this->ch );
		curl_close($this->ch);
		
		if( !$result || $info['http_code'] != 200 ) {
			$this->slog( "HTTP error ".$info['http_code'] );
			return NULL;
		}
		$this->slog("request complete");
		return $result;
	}
	function process() {					# вызов функции-обработчика
		call_user_func( array( $this, $this->callback) );
	}
	function slog( $msg ) {				# вывод сообщение на экран и в файл
		$str = date("r")." <".$this->ip."> $msg\r\n";
		echo $str;
		file_put_contents(GUESTGET_LOG, $str, FILE_APPEND);
    }
}

	$mh = curl_multi_init();	# инициализация мультизапросов
	$threads = [];				# массив счетчиков
	$chs = [];					# дескрипторы запросов

	foreach( array_slice($argv, 1) as $ip )		# просмотреть все IP или имена
		array_push( $threads, new Guestget(count($threads), $ip, $mh, $chs) );	# создать поток работы со счетчиком

	$active = $prev_active = count($chs);
	while( 1 ) {
		curl_multi_exec( $mh, $active );	# количество текущих запросов
		if( $active != $prev_active ) {		# если изменилось количество активных запросов
			$prev_active = $active;
			do {
				$infos = curl_multi_info_read( $mh, $queue );		# выбрать завершившийся запрос
				if( is_array($infos) && ($ch = $infos['handle']) )
					$threads[array_search( $ch, $chs )]->process( $ch );# обработать полученные данные
			} while( $queue );
		} else if( !$active )			# если запросы отсутствуют
			break;
		usleep( 1000 );
	}
	curl_multi_close( $mh );
?>