⬆️ ⬇️

ICQ bug informer for PHP + ActiveMQ

I am the developer and caretaker of a fairly large system of online booking of one of the Moscow tour operators. Since this system has very high requirements in terms of reliability and security, I have to keep track of all the errors that occur in it, but to constantly go in and see if there are any new reports is not very convenient and therefore I need some kind of instant notification tool, and it should support the ability to send messages from both the web part and desktop applications.



In this article I want to talk about my experience in writing a script for instant notification of errors in the system through ICQ messages. The ActiveMQ message broker is used as an intermediate link and report accumulator; I will tell you how to install and configure it to work with MySQL. The main part is an ICQ-bot written in PHP, its duties include listening to a specific channel in the broker and sending messages to the specified ICQ numbers. I will also tell you how to run this PHP script as a Windows service.





The operation of this system is as follows: when an error occurs, an application (web or desktop) generates an XML message containing a brief description of the error and the recipient's ICQ number. This message is sent via the STOMP protocol to the ActiveMQ broker and enters the queue. At the other end of the world, or on the same machine, there is an ICQ bot, which listens to this queue and, if it receives a message, immediately sends it to the specified address. And now in the details.

')

Install and configure ActiveMQ



All programs will be installed under Windows. A few words about ActiceMQ itself, it is a message broker, in which there are 2 basic concepts: queues and topics (Topic).

Topic is designed to notify a large number of subscribers about any event, such as news or the release of the next patch.

Queue is a queue of tasks, several listeners can subscribe to it, but any message will be received by only one of the subscribers, this is exactly what suits us.



First, download the distribution kit . Installation is reduced to unpacking the archive into some distant folder. For convenience, install it as a Windows service, for this you need to run the ActiveMQ script \ bin \ win32 \ InstallService.bat, the presence of the installed JAVA machine is assumed by itself.

You can check the operation via “Administration” -> “Services”, but just wait 10 seconds after launch and update the list, on Win 2003 server I had a problem: the service seemed to start, but immediately fell, a long digging in logs and Google led to a simple solution is to create a work folder in the ActiveMQ \ bin \ win32 directory.



To configure ActiveMQ, you must open the file \ conf \ activemq.xml

We describe our broker:

<broker xmlns = "activemq.apache.org/schema/core" brokerName = "localhost" dataDirectory = "${activemq.base}/data" destroyApplicationContextOnStop = "true" persistent = "true" useShutdownHook = "false" >
<broker xmlns = "activemq.apache.org/schema/core" brokerName = "localhost" dataDirectory = "${activemq.base}/data" destroyApplicationContextOnStop = "true" persistent = "true" useShutdownHook = "false" >


Pay attention to the persistent parameter, it is responsible for the fact that all your messages will be stored in the database and will not be lost after the service is restarted. Whether you have to decide it yourself or not, I have connected this function, and I reconfigured it with built-in kahaDB to a more understandable and transparent MySQL. This is done as follows:

Download the connector for Java , take mysql-connector-java-5.1.14-bin.jar from it and drop it into the \ lib folder. In MySQL itself, we create a database called activemq, for it we will create an activemq user with the same password. We describe it all in the config:

<persistenceAdapter > <br/>

<jdbcPersistenceAdapter dataSource = "#mysql-ds" /> <br/>

</persistenceAdapter > <br/>

<br/>

<bean id = "mysql-ds" class = "org.apache.commons.dbcp.BasicDataSource" destroy-method = "close" > <br/>

<property name = "driverClassName" value = "com.mysql.jdbc.Driver" /> <br/>

<property name = "url" value = "jdbc:mysql://localhost/activemq?relaxAutoCommit=true" /> <br/>

<property name = "username" value = "activemq" /> <br/>

<property name = "password" value = "activemq" /> <br/>

<property name = "poolPreparedStatements" value = "true" /> <br/>

</bean >


The block must be located outside the tag. After restarting the service, 3 tables will have to be created in the database, if it happened, then everything was done correctly.



Go ahead to configure, configure the possible connections:

<transportConnectors > <br/>

<transportConnector name = "openwire" uri = "tcp://0.0.0.0:61616" /> <br/>

<transportConnector name = "openwire2" uri = "stomp://0.0.0.0:61613" /> <br/>

</transportConnectors >
Here I asked 2 different connections for different protocols, this is due to the fact that I use the STOMP library to connect to PHP, and under Delphi I managed to find a component that works steadily over TCP.



Next, let's do authorization, add the following piece to the block:

<plugins > <br/>

<jaasAuthenticationPlugin configuration = "activemq-domain" /> <br/>

<authorizationPlugin > <br/>

<map > <br/>

<authorizationMap > <br/>

<authorizationEntries > <br/>

<authorizationEntry queue = ">" read = "admins" write = "admins" admin = "admins" /> <br/>

<authorizationEntry queue = "icq.>" read = "users" write = "users" admin = "admins" /> <br/>

<authorizationEntry topic = "ActiveMQ.Advisory.>" read = "guests,users" write = "guests,users" admin = "guests,users" /> <br/>

</authorizationEntries > <br/>

</authorizationMap > <br/>

</map > <br/>

</authorizationPlugin > <br/>

</plugins >


Now create the groups.properties file in the / conf folder with the following contents:
admins=system,sslclient,client,broker1,broker2

users=icq

guests=guest



In the same place, create the users.properties file and enter it into it:
system=password

icq=secret
You will also need a login.config file, it is easier to download it entirely and drop it into the / conf folder. After all the settings, restart the service and go to the address http: // localhost: 8161 / admin / , if everything is done correctly, you will be met by the control panel, if so, go to Queues and create a queue called icq.



ICQ bot script



I took the WebIcqPro library as the basis of the bot, it is fairly simple and stable. You will also need a library to send messages to the broker, I found a quite stable solution on the STOMP protocol , but when the connection was broken, it knocked it out, so I had to modify it a bit to make it possible to reconnect. I will not give here all the bot code, to whom it is really interesting you can download the archive.



To test the functionality, run the bot via the command line:

"C: \ Program Files \ PHP \ php" C: \ icqbot \ icq.php

If everything is in order with the settings, he should establish a connection with ActiveMQ and the ICQ server, and then start listening to the “* Waiting for messages ...” channel. To send a test message, you can use the send.php script from the archive:

<?php <br/>

require_once 'Stomp.php' ; <br/>

$c = new StompConnection ( "localhost" ) ; <br/>

$result = $c -> connect ( "icq" , "bot" ) ; <br/>

<br/>

$mess = '<?xml version="1.0" encoding="windows-1251"?><br/>

<reference><br/>

<type>send</type><br/>

<to>111111111</to><br/>

<from>Test send:</from><br/>

<mes> message</mes><br/>

</reference>'
; <br/>

<br/>

$mess = iconv ( 'cp1251' , 'UTF-8' , $mess ) ; <br/>

$c -> send ( "/queue/icq" , $mess , array ( 'persistent' => 'true' ) ) ; <br/>

$c -> disconnect ( ) ; <br/>

?>
I had to mess around with encodings for quite a while so that I could send messages with Russian text, so don’t be surprised when you see cascading conversions to different encodings in scripts, otherwise it didn’t want to work. After calling send.php, a message will be sent to the specified UIN and this fact will also be reflected in the logs.



Run the bot as a Windows service



For this we need a set of Windows NT Resource Kit, who do not have to download . Suppose all the bot files we have are in the C: \ icqbot folder . Open the console and write

“C: \ Program Files \ Windows Resource Kits \ Instsrv.exe” ICQBot “C: \ Program Files \ Windows Resource Kits \ Srvany.exe”

Next, run regedit and go to the HKEY_LOCAL_MACHINE \ SYSTEM \ CurrentControlSet \ Services \ ICQBot section inside it create the Parameters section and in it the Application parameter type REG_SZ with the value "C: \ Program Files \ PHP \ php.exe" C: \ icqbot \ icq. php

Next, go to the service and run our bot from there, now it is completely autonomous.



Error catcher for the site



Our ultimate goal is to catch all the errors, make a detailed report and send a notification about this to ICQ. Thus, it remains to describe only the script for catching these errors, for me it looks like this and is connected to all scripts where control is required:

<?php <br/>

ini_set ( 'display_errors' , 0 ) ; <br/>

error_reporting ( 2 ) ; <br/>

<br/>

if ( $send_report ) { <br/>

include_once ( "Stomp.php" ) ; <br/>

<br/>

function send_report ( $message , $to = '1212312' , $from = 'SENDER' ) { <br/>

global $send_report , $stomp_server , $stomp_url , $stomp_user , $stomp_psw ; <br/>

if ( ! $send_report ) return false ; <br/>

$c = new StompConnection ( $stomp_server ) ; <br/>

$result = $c -> connect ( $stomp_user , $stomp_psw ) ; <br/>

if ( ! is_array ( $to ) ) $to = array ( $to ) ; <br/>

foreach ( $to as $i ) { <br/>

$mess = '<?xml version="1.0" encoding="windows-1251"?><br/>

<reference><br/>

<type>send</type><br/>

<to>'
. $i . '</to><br/>

<from>'
. $from . '</from><br/>

<mes>'
. $message . '</mes><br/>

</reference>'
; <br/>

$c -> send ( $stomp_url , iconv ( 'cp1251' , 'UTF-8' , $mess ) , array ( 'persistent' => 'true' ) ) ; <br/>

} <br/>

$c -> disconnect ( ) ; <br/>

} <br/>

} <br/>

<br/>

function user_log ( $errno , $errmsg , $file , $line ) { <br/>

global $send_report ; <br/>

if ( $errno == 2 ) { <br/>

$filename = strftime ( '%d.%m.%Y %H-%M-%S_' ) . $_REQUEST [ 'PHPSESSID' ] . '.err' ; <br/>

$fl = fopen ( 'errors/' . $filename , 'w' ) ; <br/>

$_SESSION [ 'ERROR_TEXT' ] = 'WARNING: ' . $errmsg . ' in ' . $file . ' on line ' . $line ; <br/>

$_SESSION [ 'ERROR_TIME' ] = strftime ( '%d.%m.%Y %H-%M-%S' ) ; <br/>

$_SESSION [ 'ERROR_PHPSESSID' ] = $_REQUEST [ 'PHPSESSID' ] ; <br/>

$_SESSION [ 'ERROR_TYPE' ] = 'PHP SCRIPT ERROR' ; <br/>

fwrite ( $fl , serialize ( $_SESSION ) ) ; <br/>

fclose ( $fl ) ; <br/>

if ( $send_report ) send_report ( $_SESSION [ 'ERROR_TEXT' ] ) ; <br/>

} <br/>

} <br/>

<br/>

set_error_handler ( 'user_log' ) ; <br/>

?>
For understandable causal reasons, I crypt the entire contents of these reports, which I advise everyone to do.



Thus, a fairly stable, simple and universal notification scheme was obtained, allowing you to send messages to ICQ from any application in any language, if one of the protocols for interacting with ActiveMQ is described for it.



List of used files
  1. ActiveMQ 5.4.2
  2. Configs for ActiveMQ
  3. MySQL Connector
  4. WebICQPro library for PHP
  5. STOMP library for PHP
  6. A complete set of bot scripts and error interceptor
  7. Windows NT Resource Kit

Source: https://habr.com/ru/post/116038/



All Articles