├── LICENSE ├── README.md ├── avatar.png ├── bot.php ├── itr.php └── service.php /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 bitrix24com 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Where to find Bitrix24 bot-related documentation? # 2 | 3 | The documentation is available at: https://training.bitrix24.com/support/training/course/index.php?COURSE_ID=115&INDEX=Y 4 | 5 | ### What are contents of this repository? ### 6 | 7 | Contains three completed chatbots: 8 | * EchoBot: bot repeats incoming messages and supports all key platform features. 9 | * ITR Bot: bot for Open Channels, with multi-level menu constructor available in the code. 10 | * ServiceBot: service bot for chats. This bot type tracks all messages in a chat. 11 | 12 | ### How should I update the bot? ### 13 | 14 | *First, you need to understand what do you want to do with this bot :)* 15 | 16 | When this bot responds only when initiated by users: 17 | * In basic version, no changes needed 18 | * However, you can think about security and change methods for storage of logs, cache and app settings 19 | 20 | *When this bot sometimes may initiate contact with users:* 21 | * Change constants CLIENT_ID and CLIENT_SECRET to be issued to you inside partner account or in local applications 22 | * you can also ensure security and change storage methods for message logs, cache and app settings 23 | 24 | ### Attention ### 25 | 26 | Bots are presented for informational purposes only and you can use them in your projects. However, you are fully responsible for operation of your applications. 27 | -------------------------------------------------------------------------------- /avatar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bitrix24com/bots/7f64bc6ba664ce28c2a4260143673d5a6de84e7d/avatar.png -------------------------------------------------------------------------------- /bot.php: -------------------------------------------------------------------------------- 1 | 60? (round($latency/60)).'m': $latency."s"; 33 | 34 | if ($_REQUEST['data']['PARAMS']['CHAT_ENTITY_TYPE'] == 'LINES') 35 | { 36 | list($message) = explode(" ", $_REQUEST['data']['PARAMS']['MESSAGE']); 37 | if ($message == '1') 38 | { 39 | $result = restCommand('imbot.message.add', Array( 40 | "DIALOG_ID" => $_REQUEST['data']['PARAMS']['DIALOG_ID'], 41 | "MESSAGE" => 'Im EchoBot, i can repeat message after you and send menu in Open Channels![br]Look new chat-bot created specifically for Open Channels - [b]ITR Bot[/b] http://birix24.ru/~bot-itr', 42 | ), $_REQUEST["auth"]); 43 | } 44 | else if ($message == '0') 45 | { 46 | $result = restCommand('imbot.message.add', Array( 47 | "DIALOG_ID" => $_REQUEST['data']['PARAMS']['DIALOG_ID'], 48 | "MESSAGE" => 'Wait for an answer!', 49 | ), $_REQUEST["auth"]); 50 | } 51 | } 52 | else 53 | { 54 | // send answer message 55 | $result = restCommand('imbot.message.add', Array( 56 | "DIALOG_ID" => $_REQUEST['data']['PARAMS']['DIALOG_ID'], 57 | "MESSAGE" => "Message from bot", 58 | "ATTACH" => Array( 59 | Array("MESSAGE" => "reply: ".$_REQUEST['data']['PARAMS']['MESSAGE']), 60 | Array("MESSAGE" => "latency: ".$latency) 61 | ) 62 | ), $_REQUEST["auth"]); 63 | } 64 | 65 | // write debug log 66 | writeToLog($result, 'ImBot Event message add'); 67 | } 68 | // receive event "new command for bot" 69 | if ($_REQUEST['event'] == 'ONIMCOMMANDADD') 70 | { 71 | // check the event - authorize this event or not 72 | if (!isset($appsConfig[$_REQUEST['auth']['application_token']])) 73 | return false; 74 | 75 | // response time 76 | $latency = (time()-$_REQUEST['ts']); 77 | $latency = $latency > 60? (round($latency/60)).'m': $latency."s"; 78 | 79 | $result = false; 80 | foreach ($_REQUEST['data']['COMMAND'] as $command) 81 | { 82 | if ($command['COMMAND'] == 'echo') 83 | { 84 | $result = restCommand('imbot.command.answer', Array( 85 | "COMMAND_ID" => $command['COMMAND_ID'], 86 | "MESSAGE_ID" => $command['MESSAGE_ID'], 87 | "MESSAGE" => "Answer command", 88 | "ATTACH" => Array( 89 | Array("MESSAGE" => "reply: /".$command['COMMAND'].' '.$command['COMMAND_PARAMS']), 90 | Array("MESSAGE" => "latency: ".$latency), 91 | ) 92 | ), $_REQUEST["auth"]); 93 | } 94 | else if ($command['COMMAND'] == 'echoList') 95 | { 96 | $initList = false; 97 | if (!$command['COMMAND_PARAMS']) 98 | { 99 | $initList = true; 100 | $command['COMMAND_PARAMS'] = 1; 101 | } 102 | 103 | $attach = Array(); 104 | if ($command['COMMAND_PARAMS'] == 1) 105 | { 106 | $attach[] = Array("GRID" => Array( 107 | Array("VALUE" => "RED","DISPLAY" => "LINE", "WIDTH" => 100), 108 | Array("VALUE" => "#df532d","COLOR" => "#df532d","DISPLAY" => "LINE"), 109 | )); 110 | $attach[] = Array("GRID" => Array( 111 | Array("VALUE" => "GRAPHITE", "DISPLAY" => "LINE", "WIDTH" => 100), 112 | Array("VALUE" => "#3a403e", "COLOR" => "#3a403e", "DISPLAY" => "LINE"), 113 | )); 114 | } 115 | else if ($command['COMMAND_PARAMS'] == 2) 116 | { 117 | $attach[] = Array("GRID" => Array( 118 | Array("VALUE" => "MINT","DISPLAY" => "LINE", "WIDTH" => 100), 119 | Array("VALUE" => "#4ba984","COLOR" => "#4ba984","DISPLAY" => "LINE"), 120 | )); 121 | $attach[] = Array("GRID" => Array( 122 | Array("VALUE" => "LIGHT BLUE", "DISPLAY" => "LINE", "WIDTH" => 100), 123 | Array("VALUE" => "#6fc8e5", "COLOR" => "#6fc8e5", "DISPLAY" => "LINE"), 124 | )); 125 | } 126 | else if ($command['COMMAND_PARAMS'] == 3) 127 | { 128 | $attach[] = Array("GRID" => Array( 129 | Array("VALUE" => "PURPLE","DISPLAY" => "LINE", "WIDTH" => 100), 130 | Array("VALUE" => "#8474c8","COLOR" => "#8474c8","DISPLAY" => "LINE"), 131 | )); 132 | $attach[] = Array("GRID" => Array( 133 | Array("VALUE" => "AQUA", "DISPLAY" => "LINE", "WIDTH" => 100), 134 | Array("VALUE" => "#1eb4aa", "COLOR" => "#1eb4aa", "DISPLAY" => "LINE"), 135 | )); 136 | } 137 | else if ($command['COMMAND_PARAMS'] == 4) 138 | { 139 | $attach[] = Array("GRID" => Array( 140 | Array("VALUE" => "PINK","DISPLAY" => "LINE", "WIDTH" => 100), 141 | Array("VALUE" => "#e98fa6","COLOR" => "#e98fa6","DISPLAY" => "LINE"), 142 | )); 143 | $attach[] = Array("GRID" => Array( 144 | Array("VALUE" => "LIME", "DISPLAY" => "LINE", "WIDTH" => 100), 145 | Array("VALUE" => "#85cb7b", "COLOR" => "#85cb7b", "DISPLAY" => "LINE"), 146 | )); 147 | } 148 | else if ($command['COMMAND_PARAMS'] == 5) 149 | { 150 | $attach[] = Array("GRID" => Array( 151 | Array("VALUE" => "AZURE","DISPLAY" => "LINE", "WIDTH" => 100), 152 | Array("VALUE" => "#29619b","COLOR" => "#29619b","DISPLAY" => "LINE"), 153 | )); 154 | $attach[] = Array("GRID" => Array( 155 | Array("VALUE" => "ORANGE", "DISPLAY" => "LINE", "WIDTH" => 100), 156 | Array("VALUE" => "#e8a441", "COLOR" => "#e8a441", "DISPLAY" => "LINE"), 157 | )); 158 | } 159 | $keyboard = Array( 160 | Array("TEXT" => $command['COMMAND_PARAMS'] == 1? "· 1 ·": "1", "COMMAND" => "echoList", "COMMAND_PARAMS" => "1", "DISPLAY" => "LINE", "BLOCK" => "Y"), 161 | Array("TEXT" => $command['COMMAND_PARAMS'] == 2? "· 2 ·": "2", "COMMAND" => "echoList", "COMMAND_PARAMS" => "2", "DISPLAY" => "LINE", "BLOCK" => "Y"), 162 | Array("TEXT" => $command['COMMAND_PARAMS'] == 3? "· 3 ·": "3", "COMMAND" => "echoList", "COMMAND_PARAMS" => "3", "DISPLAY" => "LINE", "BLOCK" => "Y"), 163 | Array("TEXT" => $command['COMMAND_PARAMS'] == 4? "· 4 ·": "4", "COMMAND" => "echoList", "COMMAND_PARAMS" => "4", "DISPLAY" => "LINE", "BLOCK" => "Y"), 164 | Array("TEXT" => $command['COMMAND_PARAMS'] == 5? "· 5 ·": "5", "COMMAND" => "echoList", "COMMAND_PARAMS" => "5", "DISPLAY" => "LINE", "BLOCK" => "Y"), 165 | ); 166 | 167 | if (!$initList && $command['COMMAND_CONTEXT'] == 'KEYBOARD') 168 | { 169 | $result = restCommand('imbot.message.update', Array( 170 | "BOT_ID" => $command['BOT_ID'], 171 | "MESSAGE_ID" => $command['MESSAGE_ID'], 172 | "ATTACH" => $attach, 173 | "KEYBOARD" => $keyboard 174 | ), $_REQUEST["auth"]); 175 | } 176 | else 177 | { 178 | $result = restCommand('imbot.command.answer', Array( 179 | "COMMAND_ID" => $command['COMMAND_ID'], 180 | "MESSAGE_ID" => $command['MESSAGE_ID'], 181 | "MESSAGE" => "List of colors", 182 | "ATTACH" => $attach, 183 | "KEYBOARD" => $keyboard 184 | ), $_REQUEST["auth"]); 185 | } 186 | } 187 | else if ($command['COMMAND'] == 'help') 188 | { 189 | $keyboard = Array( 190 | Array( 191 | "TEXT" => "Bitrix24", 192 | 'LINK' => "http://bitrix24.com", 193 | "BG_COLOR" => "#29619b", 194 | "TEXT_COLOR" => "#fff", 195 | "DISPLAY" => "LINE", 196 | ), 197 | Array( 198 | "TEXT" => "BitBucket", 199 | "LINK" => "https://bitbucket.org/Bitrix24com/rest-bot-echotest", 200 | "BG_COLOR" => "#2a4c7c", 201 | "TEXT_COLOR" => "#fff", 202 | "DISPLAY" => "LINE", 203 | ), 204 | Array("TYPE" => "NEWLINE"), 205 | Array("TEXT" => "Echo", "COMMAND" => "echo", "COMMAND_PARAMS" => "test from keyboard", "DISPLAY" => "LINE"), 206 | Array("TEXT" => "List", "COMMAND" => "echoList", "DISPLAY" => "LINE"), 207 | Array("TEXT" => "Help", "COMMAND" => "help", "DISPLAY" => "LINE"), 208 | ); 209 | 210 | $result = restCommand('imbot.command.answer', Array( 211 | "COMMAND_ID" => $command['COMMAND_ID'], 212 | "MESSAGE_ID" => $command['MESSAGE_ID'], 213 | "MESSAGE" => "Hello! My name is EchoBot :)[br] I designed to answer your questions!", 214 | "KEYBOARD" => $keyboard 215 | ), $_REQUEST["auth"]); 216 | } 217 | } 218 | 219 | // write debug log 220 | writeToLog($result, 'ImBot Event message add'); 221 | } 222 | // receive event "open private dialog with bot" or "join bot to group chat" 223 | else if ($_REQUEST['event'] == 'ONIMBOTJOINCHAT') 224 | { 225 | // check the event - authorize this event or not 226 | if (!isset($appsConfig[$_REQUEST['auth']['application_token']])) 227 | return false; 228 | 229 | if ($_REQUEST['data']['PARAMS']['CHAT_ENTITY_TYPE'] == 'LINES') 230 | { 231 | $message = 232 | 'ITR Menu:[br]'. 233 | '[send=1]1. find out more about me[/send][br]'. 234 | '[send=0]0. wait for operator response[/send]'; 235 | 236 | // send help message how to use chat-bot. For private chat and for group chat need send different instructions. 237 | $result = restCommand('imbot.message.add', Array( 238 | "DIALOG_ID" => $_REQUEST['data']['PARAMS']['DIALOG_ID'], 239 | "MESSAGE" => $message, 240 | ), $_REQUEST["auth"]); 241 | } 242 | else 243 | { 244 | // send help message how to use chat-bot. For private chat and for group chat need send different instructions. 245 | $result = restCommand('imbot.message.add', Array( 246 | "DIALOG_ID" => $_REQUEST['data']['PARAMS']['DIALOG_ID'], 247 | "MESSAGE" => "Welcome message from bot.", 248 | "ATTACH" => Array( 249 | Array("MESSAGE" => ($_REQUEST['data']['PARAMS']['CHAT_TYPE'] == 'P'? 'Private instructions': 'Chat instructions')), 250 | Array("MESSAGE" => ($_REQUEST['data']['PARAMS']['CHAT_TYPE'] == 'P'? '[send=send message]Click for send[/send] or [put=something...]write something[/put]': "[send=send message]click for send[/send] or [put=put message to textarea]click for put[/put]")), 251 | ), 252 | "KEYBOARD" => Array( 253 | Array("TEXT" => "Help", "COMMAND" => "help"), 254 | ) 255 | ), $_REQUEST["auth"]); 256 | } 257 | 258 | 259 | // write debug log 260 | writeToLog($result, 'ImBot Event join chat'); 261 | } 262 | // receive event "delete chat-bot" 263 | else if ($_REQUEST['event'] == 'ONIMBOTDELETE') 264 | { 265 | // check the event - authorize this event or not 266 | if (!isset($appsConfig[$_REQUEST['auth']['application_token']])) 267 | return false; 268 | 269 | // unset application variables 270 | unset($appsConfig[$_REQUEST['auth']['application_token']]); 271 | 272 | // save params 273 | saveParams($appsConfig); 274 | 275 | // write debug log 276 | writeToLog($_REQUEST['event'], 'ImBot unregister'); 277 | } 278 | // execute custom action 279 | else if ($_REQUEST['event'] == 'PUBLISH') 280 | { 281 | // This event is a CUSTOM event and is not sent from platform Bitrix24 282 | // Example: https://example.com/bot.php?event=PUBLISH&application_token=XXX&PARAMS[DIALOG_ID]=1&PARAMS[MESSAGE]=Hello! 283 | // example.com - change to you domain name with bot script 284 | // XXX - change to you application token from config.php 285 | 286 | // check the event - authorize this event or not 287 | if (!isset($appsConfig[$_REQUEST['application_token']])) 288 | return false; 289 | 290 | // send answer message 291 | $result = restCommand('imbot.message.add', $_REQUEST['PARAMS'], $appsConfig[$_REQUEST['application_token']]['AUTH']); 292 | 293 | // write debug log 294 | writeToLog($result, 'ImBot Event message add'); 295 | 296 | echo 'Method executed'; 297 | } 298 | // receive event "Application install" 299 | else if ($_REQUEST['event'] == 'ONAPPINSTALL') 300 | { 301 | // handler for events 302 | $handlerBackUrl = ($_SERVER['SERVER_PORT']==443||$_SERVER["HTTPS"]=="on"? 'https': 'http')."://".$_SERVER['SERVER_NAME'].(in_array($_SERVER['SERVER_PORT'], Array(80, 443))?'':':'.$_SERVER['SERVER_PORT']).$_SERVER['SCRIPT_NAME']; 303 | 304 | // If your application supports different localizations 305 | // use $_REQUEST['data']['LANGUAGE_ID'] to load correct localization 306 | 307 | // register new bot 308 | $result = restCommand('imbot.register', Array( 309 | 'CODE' => 'echobot', 310 | 'TYPE' => 'B', 311 | 'EVENT_MESSAGE_ADD' => $handlerBackUrl, 312 | 'EVENT_WELCOME_MESSAGE' => $handlerBackUrl, 313 | 'EVENT_BOT_DELETE' => $handlerBackUrl, 314 | 'OPENLINE' => 'Y', // this flag only for Open Channel mode http://bitrix24.ru/~bot-itr 315 | 'PROPERTIES' => Array( 316 | 'NAME' => 'EchoBot '.(count($appsConfig)+1), 317 | 'COLOR' => 'GREEN', 318 | 'EMAIL' => 'test@test.ru', 319 | 'PERSONAL_BIRTHDAY' => '2016-03-11', 320 | 'WORK_POSITION' => 'My first echo bot', 321 | 'PERSONAL_WWW' => 'http://bitrix24.com', 322 | 'PERSONAL_GENDER' => 'M', 323 | 'PERSONAL_PHOTO' => base64_encode(file_get_contents(__DIR__.'/avatar.png')), 324 | ) 325 | ), $_REQUEST["auth"]); 326 | $botId = $result['result']; 327 | 328 | $result = restCommand('imbot.command.register', Array( 329 | 'BOT_ID' => $botId, 330 | 'COMMAND' => 'echo', 331 | 'COMMON' => 'Y', 332 | 'HIDDEN' => 'N', 333 | 'EXTRANET_SUPPORT' => 'N', 334 | 'LANG' => Array( 335 | Array('LANGUAGE_ID' => 'en', 'TITLE' => 'Get echo message', 'PARAMS' => 'some text'), 336 | ), 337 | 'EVENT_COMMAND_ADD' => $handlerBackUrl, 338 | ), $_REQUEST["auth"]); 339 | $commandEcho = $result['result']; 340 | 341 | $result = restCommand('imbot.command.register', Array( 342 | 'BOT_ID' => $botId, 343 | 'COMMAND' => 'echoList', 344 | 'COMMON' => 'N', 345 | 'HIDDEN' => 'N', 346 | 'EXTRANET_SUPPORT' => 'N', 347 | 'LANG' => Array( 348 | Array('LANGUAGE_ID' => 'en', 'TITLE' => 'Get list of colors', 'PARAMS' => ''), 349 | ), 350 | 'EVENT_COMMAND_ADD' => $handlerBackUrl, 351 | ), $_REQUEST["auth"]); 352 | $commandList = $result['result']; 353 | 354 | $result = restCommand('imbot.command.register', Array( 355 | 'BOT_ID' => $botId, 356 | 'COMMAND' => 'help', 357 | 'COMMON' => 'N', 358 | 'HIDDEN' => 'N', 359 | 'EXTRANET_SUPPORT' => 'N', 360 | 'LANG' => Array( 361 | Array('LANGUAGE_ID' => 'en', 'TITLE' => 'Get help message', 'PARAMS' => 'some text'), 362 | ), 363 | 'EVENT_COMMAND_ADD' => $handlerBackUrl, 364 | ), $_REQUEST["auth"]); 365 | $commandHelp = $result['result']; 366 | 367 | $result = restCommand('event.bind', Array( 368 | 'EVENT' => 'OnAppUpdate', 369 | 'HANDLER' => $handlerBackUrl 370 | ), $_REQUEST["auth"]); 371 | 372 | // save params 373 | $appsConfig[$_REQUEST['auth']['application_token']] = Array( 374 | 'BOT_ID' => $botId, 375 | 'COMMAND_ECHO' => $commandEcho, 376 | 'COMMAND_HELP' => $commandHelp, 377 | 'COMMAND_LIST' => $commandList, 378 | 'LANGUAGE_ID' => $_REQUEST['data']['LANGUAGE_ID'], 379 | 'AUTH' => $_REQUEST['auth'], 380 | ); 381 | saveParams($appsConfig); 382 | 383 | // write debug log 384 | writeToLog(Array($botId, $commandEcho, $commandHelp, $commandList), 'ImBot register'); 385 | } 386 | // receive event "Application install" 387 | else if ($_REQUEST['event'] == 'ONAPPUPDATE') 388 | { 389 | // check the event - authorize this event or not 390 | if (!isset($appsConfig[$_REQUEST['auth']['application_token']])) 391 | return false; 392 | 393 | if ($_REQUEST['data']['VERSION'] == 2) 394 | { 395 | // Some logic in update event for VERSION 2 396 | // You can execute any method RestAPI, BotAPI or ChatAPI, for example delete or add a new command to the bot 397 | /* 398 | $result = restCommand('...', Array( 399 | '...' => '...', 400 | ), $_REQUEST["auth"]); 401 | */ 402 | 403 | /* 404 | For example delete "Echo" command: 405 | 406 | $result = restCommand('imbot.command.unregister', Array( 407 | 'COMMAND_ID' => $appsConfig[$_REQUEST['auth']['application_token']]['COMMAND_ECHO'], 408 | ), $_REQUEST["auth"]); 409 | */ 410 | } 411 | else 412 | { 413 | // send answer message 414 | $result = restCommand('app.info', array(), $_REQUEST["auth"]); 415 | } 416 | 417 | // write debug log 418 | writeToLog($result, 'ImBot update event'); 419 | } 420 | 421 | /** 422 | * Save application configuration. 423 | * WARNING: this method is only created for demonstration, never store config like this 424 | * 425 | * @param $params 426 | * @return bool 427 | */ 428 | function saveParams($params) 429 | { 430 | $config = ""; 433 | 434 | file_put_contents(__DIR__."/config.php", $config); 435 | 436 | return true; 437 | } 438 | 439 | /** 440 | * Send rest query to Bitrix24. 441 | * 442 | * @param $method - Rest method, ex: methods 443 | * @param array $params - Method params, ex: Array() 444 | * @param array $auth - Authorize data, received from event 445 | * @param boolean $authRefresh - If authorize is expired, refresh token 446 | * @return mixed 447 | */ 448 | function restCommand($method, array $params = Array(), array $auth = Array(), $authRefresh = true) 449 | { 450 | $queryUrl = $auth["client_endpoint"].$method; 451 | $queryData = http_build_query(array_merge($params, array("auth" => $auth["access_token"]))); 452 | 453 | writeToLog(Array('URL' => $queryUrl, 'PARAMS' => array_merge($params, array("auth" => $auth["access_token"]))), 'ImBot send data'); 454 | 455 | $curl = curl_init(); 456 | 457 | curl_setopt_array($curl, array( 458 | CURLOPT_POST => 1, 459 | CURLOPT_HEADER => 0, 460 | CURLOPT_RETURNTRANSFER => 1, 461 | CURLOPT_SSL_VERIFYPEER => 1, 462 | CURLOPT_URL => $queryUrl, 463 | CURLOPT_POSTFIELDS => $queryData, 464 | )); 465 | 466 | $result = curl_exec($curl); 467 | curl_close($curl); 468 | 469 | $result = json_decode($result, 1); 470 | 471 | if ($authRefresh && isset($result['error']) && in_array($result['error'], array('expired_token', 'invalid_token'))) 472 | { 473 | $auth = restAuth($auth); 474 | if ($auth) 475 | { 476 | $result = restCommand($method, $params, $auth, false); 477 | } 478 | } 479 | 480 | return $result; 481 | } 482 | 483 | /** 484 | * Get new authorize data if you authorize is expire. 485 | * 486 | * @param array $auth - Authorize data, received from event 487 | * @return bool|mixed 488 | */ 489 | function restAuth($auth) 490 | { 491 | if (!CLIENT_ID || !CLIENT_SECRET) 492 | return false; 493 | 494 | if(!isset($auth['refresh_token'])) 495 | return false; 496 | 497 | $queryUrl = 'https://oauth.bitrix.info/oauth/token/'; 498 | $queryData = http_build_query($queryParams = array( 499 | 'grant_type' => 'refresh_token', 500 | 'client_id' => CLIENT_ID, 501 | 'client_secret' => CLIENT_SECRET, 502 | 'refresh_token' => $auth['refresh_token'], 503 | )); 504 | 505 | writeToLog(Array('URL' => $queryUrl, 'PARAMS' => $queryParams), 'ImBot request auth data'); 506 | 507 | $curl = curl_init(); 508 | 509 | curl_setopt_array($curl, array( 510 | CURLOPT_HEADER => 0, 511 | CURLOPT_RETURNTRANSFER => 1, 512 | CURLOPT_URL => $queryUrl.'?'.$queryData, 513 | )); 514 | 515 | $result = curl_exec($curl); 516 | curl_close($curl); 517 | 518 | $result = json_decode($result, 1); 519 | if (!isset($result['error'])) 520 | { 521 | $appsConfig = Array(); 522 | if (file_exists(__DIR__.'/config.php')) 523 | include(__DIR__.'/config.php'); 524 | 525 | $result['application_token'] = $auth['application_token']; 526 | $appsConfig[$auth['application_token']]['AUTH'] = $result; 527 | saveParams($appsConfig); 528 | } 529 | else 530 | { 531 | $result = false; 532 | } 533 | 534 | return $result; 535 | } 536 | 537 | /** 538 | * Write data to log file. (by default disabled) 539 | * WARNING: this method is only created for demonstration, never store log file in public folder 540 | * 541 | * @param mixed $data 542 | * @param string $title 543 | * @return bool 544 | */ 545 | function writeToLog($data, $title = '') 546 | { 547 | if (!DEBUG_FILE_NAME) 548 | return false; 549 | 550 | $log = "\n------------------------\n"; 551 | $log .= date("Y.m.d G:i:s")."\n"; 552 | $log .= (strlen($title) > 0 ? $title : 'DEBUG')."\n"; 553 | $log .= print_r($data, 1); 554 | $log .= "\n------------------------\n"; 555 | 556 | file_put_contents(__DIR__."/".DEBUG_FILE_NAME, $log, FILE_APPEND); 557 | 558 | return true; 559 | } -------------------------------------------------------------------------------- /itr.php: -------------------------------------------------------------------------------- 1 | 'itrbot', 74 | 'TYPE' => 'O', 75 | 'EVENT_MESSAGE_ADD' => $handlerBackUrl, 76 | 'EVENT_WELCOME_MESSAGE' => $handlerBackUrl, 77 | 'EVENT_BOT_DELETE' => $handlerBackUrl, 78 | 'OPENLINE' => 'Y', 79 | 'PROPERTIES' => Array( 80 | 'NAME' => 'ITR Bot for Open Channels #'.(count($appsConfig)+1), 81 | 'WORK_POSITION' => "Get ITR menu for you open channel", 82 | 'COLOR' => 'RED', 83 | ) 84 | ), $_REQUEST["auth"]); 85 | $botId = $result['result']; 86 | 87 | $result = restCommand('event.bind', Array( 88 | 'EVENT' => 'OnAppUpdate', 89 | 'HANDLER' => $handlerBackUrl 90 | ), $_REQUEST["auth"]); 91 | 92 | // save params 93 | $appsConfig[$_REQUEST['auth']['application_token']] = Array( 94 | 'BOT_ID' => $botId, 95 | 'LANGUAGE_ID' => $_REQUEST['data']['LANGUAGE_ID'], 96 | 'AUTH' => $_REQUEST['auth'], 97 | ); 98 | saveParams($appsConfig); 99 | 100 | // write debug log 101 | writeToLog(Array($botId), 'ImBot register'); 102 | } 103 | // receive event "Application install" 104 | else if ($_REQUEST['event'] == 'ONAPPUPDATE') 105 | { 106 | // check the event - authorize this event or not 107 | if (!isset($appsConfig[$_REQUEST['auth']['application_token']])) 108 | return false; 109 | 110 | if ($_REQUEST['data']['VERSION'] == 2) 111 | { 112 | // Some logic in update event for VERSION 2 113 | // You can execute any method RestAPI, BotAPI or ChatAPI, for example delete or add a new command to the bot 114 | /* 115 | $result = restCommand('...', Array( 116 | '...' => '...', 117 | ), $_REQUEST["auth"]); 118 | */ 119 | 120 | /* 121 | For example delete "Echo" command: 122 | 123 | $result = restCommand('imbot.command.unregister', Array( 124 | 'COMMAND_ID' => $appsConfig[$_REQUEST['auth']['application_token']]['COMMAND_ECHO'], 125 | ), $_REQUEST["auth"]); 126 | */ 127 | } 128 | else 129 | { 130 | // send answer message 131 | $result = restCommand('app.info', array(), $_REQUEST["auth"]); 132 | } 133 | 134 | // write debug log 135 | writeToLog($result, 'ImBot update event'); 136 | } 137 | 138 | /** 139 | * Run ITR menu 140 | * 141 | * @param $portalId 142 | * @param $dialogId 143 | * @param $userId 144 | * @param string $message 145 | * @return bool 146 | */ 147 | function itrRun($portalId, $dialogId, $userId, $message = '') 148 | { 149 | if ($userId <= 0) 150 | return false; 151 | 152 | $menu0 = new ItrMenu(0); 153 | $menu0->setText('Main menu (#0)'); 154 | $menu0->addItem(1, 'Text', ItrItem::sendText('Text message (for #USER_NAME#)')); 155 | $menu0->addItem(2, 'Text without menu', ItrItem::sendText('Text message without menu', true)); 156 | $menu0->addItem(3, 'Open menu #1', ItrItem::openMenu(1)); 157 | $menu0->addItem(0, 'Wait operator answer', ItrItem::sendText('Wait operator answer', true)); 158 | 159 | $menu1 = new ItrMenu(1); 160 | $menu1->setText('Second menu (#1)'); 161 | $menu1->addItem(2, 'Transfer to queue', ItrItem::transferToQueue('Transfer to queue')); 162 | $menu1->addItem(3, 'Transfer to user', ItrItem::transferToUser(1, false, 'Transfer to user #1')); 163 | $menu1->addItem(4, 'Transfer to bot', ItrItem::transferToBot('marta', true, 'Transfer to bot Marta', 'Marta not found :(')); 164 | $menu1->addItem(5, 'Finish session', ItrItem::finishSession('Finish session')); 165 | $menu1->addItem(6, 'Exec function', ItrItem::execFunction(function($context){ 166 | $result = restCommand('imbot.message.add', Array( 167 | "DIALOG_ID" => $_REQUEST['data']['PARAMS']['DIALOG_ID'], 168 | "MESSAGE" => 'Function executed (action)', 169 | ), $_REQUEST["auth"]); 170 | writeToLog($result, 'Exec function'); 171 | }, 'Function executed (text)')); 172 | $menu1->addItem(9, 'Back to main menu', ItrItem::openMenu(0)); 173 | 174 | $itr = new Itr($portalId, $dialogId, 0, $userId); 175 | $itr->addMenu($menu0); 176 | $itr->addMenu($menu1); 177 | $itr->run(prepareText($message)); 178 | 179 | return true; 180 | } 181 | 182 | 183 | /** 184 | * Save application configuration. 185 | * WARNING: this method is only created for demonstration, never store config like this 186 | * 187 | * @param $params 188 | * @return bool 189 | */ 190 | function saveParams($params) 191 | { 192 | $config = ""; 195 | 196 | file_put_contents(__DIR__."/config.php", $config); 197 | 198 | return true; 199 | } 200 | 201 | /** 202 | * Send rest query to Bitrix24. 203 | * 204 | * @param $method - Rest method, ex: methods 205 | * @param array $params - Method params, ex: Array() 206 | * @param array $auth - Authorize data, received from event 207 | * @param boolean $authRefresh - If authorize is expired, refresh token 208 | * @return mixed 209 | */ 210 | function restCommand($method, array $params = Array(), array $auth = Array(), $authRefresh = true) 211 | { 212 | $queryUrl = $auth["client_endpoint"].$method; 213 | $queryData = http_build_query(array_merge($params, array("auth" => $auth["access_token"]))); 214 | 215 | writeToLog(Array('URL' => $queryUrl, 'PARAMS' => array_merge($params, array("auth" => $auth["access_token"]))), 'ImBot send data'); 216 | 217 | $curl = curl_init(); 218 | 219 | curl_setopt_array($curl, array( 220 | CURLOPT_POST => 1, 221 | CURLOPT_HEADER => 0, 222 | CURLOPT_RETURNTRANSFER => 1, 223 | CURLOPT_SSL_VERIFYPEER => 1, 224 | CURLOPT_URL => $queryUrl, 225 | CURLOPT_POSTFIELDS => $queryData, 226 | )); 227 | 228 | $result = curl_exec($curl); 229 | curl_close($curl); 230 | 231 | $result = json_decode($result, 1); 232 | 233 | if ($authRefresh && isset($result['error']) && in_array($result['error'], array('expired_token', 'invalid_token'))) 234 | { 235 | $auth = restAuth($auth); 236 | if ($auth) 237 | { 238 | $result = restCommand($method, $params, $auth, false); 239 | } 240 | } 241 | 242 | return $result; 243 | } 244 | 245 | /** 246 | * Get new authorize data if you authorize is expire. 247 | * 248 | * @param array $auth - Authorize data, received from event 249 | * @return bool|mixed 250 | */ 251 | function restAuth($auth) 252 | { 253 | if (!CLIENT_ID || !CLIENT_SECRET) 254 | return false; 255 | 256 | if(!isset($auth['refresh_token'])) 257 | return false; 258 | 259 | $queryUrl = 'https://oauth.bitrix.info/oauth/token/'; 260 | $queryData = http_build_query($queryParams = array( 261 | 'grant_type' => 'refresh_token', 262 | 'client_id' => CLIENT_ID, 263 | 'client_secret' => CLIENT_SECRET, 264 | 'refresh_token' => $auth['refresh_token'], 265 | )); 266 | 267 | writeToLog(Array('URL' => $queryUrl, 'PARAMS' => $queryParams), 'ImBot request auth data'); 268 | 269 | $curl = curl_init(); 270 | 271 | curl_setopt_array($curl, array( 272 | CURLOPT_HEADER => 0, 273 | CURLOPT_RETURNTRANSFER => 1, 274 | CURLOPT_URL => $queryUrl.'?'.$queryData, 275 | )); 276 | 277 | $result = curl_exec($curl); 278 | curl_close($curl); 279 | 280 | $result = json_decode($result, 1); 281 | if (!isset($result['error'])) 282 | { 283 | $appsConfig = Array(); 284 | if (file_exists(__DIR__.'/config.php')) 285 | include(__DIR__.'/config.php'); 286 | 287 | $result['application_token'] = $auth['application_token']; 288 | $appsConfig[$auth['application_token']]['AUTH'] = $result; 289 | saveParams($appsConfig); 290 | } 291 | else 292 | { 293 | $result = false; 294 | } 295 | 296 | return $result; 297 | } 298 | 299 | /** 300 | * Write data to log file. (by default disabled) 301 | * WARNING: this method is only created for demonstration, never store log file in public folder 302 | * 303 | * @param mixed $data 304 | * @param string $title 305 | * @return bool 306 | */ 307 | function writeToLog($data, $title = '') 308 | { 309 | if (!DEBUG_FILE_NAME) 310 | return false; 311 | 312 | $log = "\n------------------------\n"; 313 | $log .= date("Y.m.d G:i:s")."\n"; 314 | $log .= (strlen($title) > 0 ? $title : 'DEBUG')."\n"; 315 | $log .= print_r($data, 1); 316 | $log .= "\n------------------------\n"; 317 | 318 | file_put_contents(__DIR__."/".DEBUG_FILE_NAME, $log, FILE_APPEND); 319 | 320 | return true; 321 | } 322 | 323 | /** 324 | * Clean text before select ITR item 325 | * 326 | * @param $message 327 | * @return string 328 | */ 329 | function prepareText($message) 330 | { 331 | $message = preg_replace("/\[s\].*?\[\/s\]/i", "-", $message); 332 | $message = preg_replace("/\[[bui]\](.*?)\[\/[bui]\]/i", "$1", $message); 333 | $message = preg_replace("/\\[url\\](.*?)\\[\\/url\\]/i", "$1", $message); 334 | $message = preg_replace("/\\[url\\s*=\\s*((?:[^\\[\\]]++|\\[ (?: (?>[^\\[\\]]+) | (?:\\1) )* \\])+)\\s*\\](.*?)\\[\\/url\\]/ixs", "$2", $message); 335 | $message = preg_replace("/\[USER=([0-9]{1,})\](.*?)\[\/USER\]/i", "$2", $message); 336 | $message = preg_replace("/\[CHAT=([0-9]{1,})\](.*?)\[\/CHAT\]/i", "$2", $message); 337 | $message = preg_replace("/\[PCH=([0-9]{1,})\](.*?)\[\/PCH\]/i", "$2", $message); 338 | $message = preg_replace('#\-{54}.+?\-{54}#s', "", str_replace(array("#BR#"), Array(" "), $message)); 339 | $message = strip_tags($message); 340 | 341 | return trim($message); 342 | } 343 | 344 | 345 | /** 346 | * Class Itr 347 | * @package Bitrix\ImBot\Bot 348 | */ 349 | class Itr 350 | { 351 | public $botId = 0; 352 | public $userId = 0; 353 | public $dialogId = ''; 354 | public $portalId = ''; 355 | 356 | private $cacheId = ''; 357 | private static $executed = false; 358 | 359 | private $menuItems = Array(); 360 | private $menuText = Array(); 361 | 362 | private $currentMenu = 0; 363 | private $skipShowMenu = false; 364 | 365 | public function __construct($portalId, $dialogId, $botId, $userId) 366 | { 367 | $this->portalId = $portalId; 368 | $this->userId = $userId; 369 | $this->botId = $botId; 370 | $this->dialogId = $dialogId; 371 | 372 | $this->getCurrentMenu(); 373 | } 374 | 375 | public function addMenu(ItrMenu $items) 376 | { 377 | $this->menuText[$items->getId()] = $items->getText(); 378 | $this->menuItems[$items->getId()] = $items->getItems(); 379 | 380 | return true; 381 | } 382 | 383 | /** 384 | * Get menu state. 385 | * WARNING: this method is only created for demonstration, never store cache like this 386 | */ 387 | private function getCurrentMenu() 388 | { 389 | $this->cacheId = md5($this->portalId.$this->botId.$this->dialogId); 390 | 391 | if (file_exists(__DIR__.'/cache') && file_exists(__DIR__.'/cache/'.$this->cacheId.'.cache')) 392 | { 393 | $this->currentMenu = intval(file_get_contents(__DIR__.'/cache/'.$this->cacheId.'.cache')); 394 | } 395 | else 396 | { 397 | if (!file_exists(__DIR__.'/cache')) 398 | { 399 | mkdir(__DIR__.'/cache'); 400 | chmod(__DIR__.'/cache', 0777); 401 | } 402 | file_put_contents(__DIR__.'/cache/'.$this->cacheId.'.cache', 0); 403 | } 404 | } 405 | 406 | /** 407 | * Save menu state. 408 | * WARNING: this method is only created for demonstration, never store cache like this 409 | */ 410 | private function setCurrentMenu($id) 411 | { 412 | $this->currentMenu = intval($id); 413 | file_put_contents(__DIR__.'/cache/'.$this->cacheId.'.cache', $this->currentMenu); 414 | } 415 | 416 | private function execMenuItem($itemId = '') 417 | { 418 | if ($itemId === '') 419 | { 420 | return true; 421 | } 422 | else if ($itemId === "0") 423 | { 424 | $this->skipShowMenu = true; 425 | } 426 | 427 | if (!isset($this->menuItems[$this->currentMenu][$itemId])) 428 | { 429 | return false; 430 | } 431 | 432 | $menuItemAction = $this->menuItems[$this->currentMenu][$itemId]['ACTION']; 433 | 434 | if ($menuItemAction['HIDE_MENU']) 435 | { 436 | $this->skipShowMenu = true; 437 | } 438 | 439 | if (isset($menuItemAction['TEXT'])) 440 | { 441 | $messageText = str_replace('#USER_NAME#', $_REQUEST["data"]["USER"]["NAME"], $menuItemAction['TEXT']); 442 | restCommand('imbot.message.add', Array( 443 | "DIALOG_ID" => $this->dialogId, 444 | "MESSAGE" => $messageText, 445 | ), $_REQUEST["auth"]); 446 | } 447 | 448 | if ($menuItemAction['TYPE'] == ItrItem::TYPE_MENU) 449 | { 450 | $this->setCurrentMenu($menuItemAction['MENU']); 451 | } 452 | else if ($menuItemAction['TYPE'] == ItrItem::TYPE_QUEUE) 453 | { 454 | restCommand('imopenlines.bot.session.operator', Array( 455 | "CHAT_ID" => substr($this->dialogId, 4), 456 | ), $_REQUEST["auth"]); 457 | } 458 | else if ($menuItemAction['TYPE'] == ItrItem::TYPE_USER) 459 | { 460 | restCommand('imopenlines.bot.session.transfer', Array( 461 | "CHAT_ID" => substr($this->dialogId, 4), 462 | "USER_ID" => $menuItemAction['USER_ID'], 463 | "LEAVE" => $menuItemAction['LEAVE']? 'Y': 'N', 464 | ), $_REQUEST["auth"]); 465 | } 466 | else if ($menuItemAction['TYPE'] == ItrItem::TYPE_BOT) 467 | { 468 | $botId = 0; 469 | $result = restCommand('imbot.bot.list', Array(), $_REQUEST["auth"]); 470 | foreach ($result['result'] as $botData) 471 | { 472 | if ($botData['CODE'] == $menuItemAction['BOT_CODE'] && $botData['OPENLINE'] == 'Y') 473 | { 474 | $botId = $botData['ID']; 475 | break; 476 | } 477 | } 478 | if ($botId) 479 | { 480 | restCommand('imbot.chat.user.add', Array( 481 | 'CHAT_ID' => substr($this->dialogId, 4), 482 | 'USERS' => Array($botId) 483 | ), $_REQUEST["auth"]); 484 | if ($menuItemAction['LEAVE']) 485 | { 486 | restCommand('imbot.chat.leave', Array( 487 | 'CHAT_ID' => substr($this->dialogId, 4) 488 | ), $_REQUEST["auth"]); 489 | } 490 | } 491 | else if ($menuItemAction['ERROR_TEXT']) 492 | { 493 | $messageText = str_replace('#USER_NAME#', $_REQUEST["data"]["USER"]["NAME"], $menuItemAction['ERROR_TEXT']); 494 | restCommand('imbot.message.add', Array( 495 | "DIALOG_ID" => $this->dialogId, 496 | "MESSAGE" => $messageText, 497 | ), $_REQUEST["auth"]); 498 | $this->skipShowMenu = false; 499 | } 500 | } 501 | else if ($menuItemAction['TYPE'] == ItrItem::TYPE_FINISH) 502 | { 503 | restCommand('imopenlines.bot.session.finish', Array( 504 | "CHAT_ID" => substr($this->dialogId, 4) 505 | ), $_REQUEST["auth"]); 506 | } 507 | else if ($menuItemAction['TYPE'] == ItrItem::TYPE_FUNCTION) 508 | { 509 | $menuItemAction['FUNCTION']($this); 510 | } 511 | 512 | return true; 513 | } 514 | 515 | private function getMenuItems() 516 | { 517 | $messageText = ''; 518 | if ($this->skipShowMenu) 519 | { 520 | $this->skipShowMenu = false; 521 | return $messageText; 522 | } 523 | 524 | if (isset($this->menuText[$this->currentMenu])) 525 | { 526 | $messageText = $this->menuText[$this->currentMenu].'[br]'; 527 | } 528 | 529 | foreach ($this->menuItems[$this->currentMenu] as $itemId => $data) 530 | { 531 | $messageText .= '[send='.$itemId.']'.$itemId.'. '.$data['TITLE'].'[/send][br]'; 532 | } 533 | 534 | $messageText = str_replace('#USER_NAME#', $_REQUEST["data"]["USER"]["NAME"], $messageText); 535 | restCommand('imbot.message.add', Array( 536 | "DIALOG_ID" => $this->dialogId, 537 | "MESSAGE" => $messageText, 538 | ), $_REQUEST["auth"]); 539 | 540 | return true; 541 | } 542 | 543 | public function run($text) 544 | { 545 | if (self::$executed) 546 | return false; 547 | 548 | list($itemId) = explode(" ", $text); 549 | 550 | $this->execMenuItem($itemId); 551 | 552 | $this->getMenuItems(); 553 | 554 | self::$executed = true; 555 | 556 | return true; 557 | } 558 | } 559 | 560 | class ItrMenu 561 | { 562 | private $id = 0; 563 | private $text = ''; 564 | private $items = Array(); 565 | 566 | /** 567 | * ItrMenu constructor. 568 | * @param $id 569 | */ 570 | public function __construct($id) 571 | { 572 | $this->id = intval($id); 573 | } 574 | 575 | public function getId() 576 | { 577 | return $this->id; 578 | } 579 | 580 | public function getText() 581 | { 582 | return $this->text; 583 | } 584 | 585 | public function getItems() 586 | { 587 | return $this->items; 588 | } 589 | 590 | public function setText($text) 591 | { 592 | $this->text = trim($text); 593 | } 594 | 595 | public function addItem($id, $title, array $action) 596 | { 597 | $id = intval($id); 598 | if ($id <= 0 && !in_array($action['TYPE'], Array(ItrItem::TYPE_VOID, ItrItem::TYPE_TEXT))) 599 | { 600 | return false; 601 | } 602 | 603 | $title = trim($title); 604 | 605 | $this->items[$id] = Array( 606 | 'ID' => $id, 607 | 'TITLE' => $title, 608 | 'ACTION' => $action 609 | ); 610 | 611 | return true; 612 | } 613 | } 614 | 615 | class ItrItem 616 | { 617 | const TYPE_VOID = 'VOID'; 618 | const TYPE_TEXT = 'TEXT'; 619 | const TYPE_MENU = 'MENU'; 620 | const TYPE_USER = 'USER'; 621 | const TYPE_BOT = 'BOT'; 622 | const TYPE_QUEUE = 'QUEUE'; 623 | const TYPE_FINISH = 'FINISH'; 624 | const TYPE_FUNCTION = 'FUNCTION'; 625 | 626 | public static function void($hideMenu = true) 627 | { 628 | return Array( 629 | 'TYPE' => self::TYPE_VOID, 630 | 'HIDE_MENU' => $hideMenu? true: false 631 | ); 632 | } 633 | 634 | public static function sendText($text = '', $hideMenu = false) 635 | { 636 | return Array( 637 | 'TYPE' => self::TYPE_TEXT, 638 | 'TEXT' => $text, 639 | 'HIDE_MENU' => $hideMenu? true: false 640 | ); 641 | } 642 | 643 | public static function openMenu($menuId) 644 | { 645 | return Array( 646 | 'TYPE' => self::TYPE_MENU, 647 | 'MENU' => $menuId 648 | ); 649 | } 650 | 651 | public static function transferToQueue($text = '', $hideMenu = true) 652 | { 653 | return Array( 654 | 'TYPE' => self::TYPE_QUEUE, 655 | 'TEXT' => $text, 656 | 'HIDE_MENU' => $hideMenu? true: false 657 | ); 658 | } 659 | 660 | public static function transferToUser($userId, $leave = false, $text = '', $hideMenu = true) 661 | { 662 | return Array( 663 | 'TYPE' => self::TYPE_USER, 664 | 'TEXT' => $text, 665 | 'HIDE_MENU' => $hideMenu? true: false, 666 | 'USER_ID' => $userId, 667 | 'LEAVE' => $leave? true: false, 668 | ); 669 | } 670 | 671 | public static function transferToBot($botCode, $leave = true, $text = '', $errorText = '') 672 | { 673 | return Array( 674 | 'TYPE' => self::TYPE_BOT, 675 | 'TEXT' => $text, 676 | 'ERROR_TEXT' => $errorText, 677 | 'HIDE_MENU' => true, 678 | 'BOT_CODE' => $botCode, 679 | 'LEAVE' => $leave? true: false, 680 | ); 681 | } 682 | 683 | public static function finishSession($text = '') 684 | { 685 | return Array( 686 | 'TYPE' => self::TYPE_FINISH, 687 | 'TEXT' => $text, 688 | 'HIDE_MENU' => true 689 | ); 690 | } 691 | 692 | public static function execFunction($function, $text = '', $hideMenu = false) 693 | { 694 | return Array( 695 | 'TYPE' => self::TYPE_FUNCTION, 696 | 'FUNCTION' => $function, 697 | 'TEXT' => $text, 698 | 'HIDE_MENU' => $hideMenu? true: false 699 | ); 700 | } 701 | } 702 | -------------------------------------------------------------------------------- /service.php: -------------------------------------------------------------------------------- 1 | 'servicebot', 91 | 'TYPE' => 'S', 92 | 'EVENT_MESSAGE_ADD' => $handlerBackUrl, 93 | 'EVENT_MESSAGE_UPDATE' => $handlerBackUrl, 94 | 'EVENT_MESSAGE_DELETE' => $handlerBackUrl, 95 | 'EVENT_WELCOME_MESSAGE' => $handlerBackUrl, 96 | 'EVENT_BOT_DELETE' => $handlerBackUrl, 97 | 'PROPERTIES' => Array( 98 | 'NAME' => 'ServiceBot '.(count($appsConfig)+1), 99 | 'COLOR' => 'GREEN', 100 | 'EMAIL' => 'test@test.ru', 101 | 'PERSONAL_BIRTHDAY' => '2016-03-11', 102 | 'WORK_POSITION' => 'My first service bot', 103 | 'PERSONAL_WWW' => 'http://bitrix24.com', 104 | 'PERSONAL_GENDER' => 'M', 105 | 'PERSONAL_PHOTO' => base64_encode(file_get_contents(__DIR__.'/avatar.png')), 106 | ) 107 | ), $_REQUEST["auth"]); 108 | $botId = $result['result']; 109 | 110 | $result = restCommand('event.bind', Array( 111 | 'EVENT' => 'OnAppUpdate', 112 | 'HANDLER' => $handlerBackUrl 113 | ), $_REQUEST["auth"]); 114 | 115 | // save params 116 | $appsConfig[$_REQUEST['auth']['application_token']] = Array( 117 | 'BOT_ID' => $botId, 118 | 'COMMAND_ECHO' => $commandEcho, 119 | 'COMMAND_HELP' => $commandHelp, 120 | 'COMMAND_LIST' => $commandList, 121 | 'LANGUAGE_ID' => $_REQUEST['data']['LANGUAGE_ID'], 122 | 'AUTH' => $_REQUEST['auth'], 123 | ); 124 | saveParams($appsConfig); 125 | 126 | // write debug log 127 | writeToLog(Array($botId, $commandEcho, $commandHelp, $commandList), 'ImBot register'); 128 | } 129 | // receive event "Application install" 130 | else if ($_REQUEST['event'] == 'ONAPPUPDATE') 131 | { 132 | // check the event - authorize this event or not 133 | if (!isset($appsConfig[$_REQUEST['auth']['application_token']])) 134 | return false; 135 | 136 | if ($_REQUEST['data']['VERSION'] == 2) 137 | { 138 | // Some logic in update event for VERSION 2 139 | // You can execute any method RestAPI, BotAPI or ChatAPI, for example delete or add a new command to the bot 140 | /* 141 | $result = restCommand('...', Array( 142 | '...' => '...', 143 | ), $_REQUEST["auth"]); 144 | */ 145 | 146 | /* 147 | For example delete "Echo" command: 148 | 149 | $result = restCommand('imbot.command.unregister', Array( 150 | 'COMMAND_ID' => $appsConfig[$_REQUEST['auth']['application_token']]['COMMAND_ECHO'], 151 | ), $_REQUEST["auth"]); 152 | */ 153 | } 154 | else 155 | { 156 | // send answer message 157 | $result = restCommand('app.info', array(), $_REQUEST["auth"]); 158 | } 159 | 160 | // write debug log 161 | writeToLog($result, 'ImBot update event'); 162 | } 163 | 164 | /** 165 | * Save application configuration. 166 | * WARNING: this method is only created for demonstration, never store config like this 167 | * 168 | * @param $params 169 | * @return bool 170 | */ 171 | function saveParams($params) 172 | { 173 | $config = ""; 176 | 177 | file_put_contents(__DIR__."/config.php", $config); 178 | 179 | return true; 180 | } 181 | 182 | /** 183 | * Send rest query to Bitrix24. 184 | * 185 | * @param $method - Rest method, ex: methods 186 | * @param array $params - Method params, ex: Array() 187 | * @param array $auth - Authorize data, received from event 188 | * @param boolean $authRefresh - If authorize is expired, refresh token 189 | * @return mixed 190 | */ 191 | function restCommand($method, array $params = Array(), array $auth = Array(), $authRefresh = true) 192 | { 193 | $queryUrl = $auth["client_endpoint"].$method; 194 | $queryData = http_build_query(array_merge($params, array("auth" => $auth["access_token"]))); 195 | 196 | writeToLog(Array('URL' => $queryUrl, 'PARAMS' => array_merge($params, array("auth" => $auth["access_token"]))), 'ImBot send data'); 197 | 198 | $curl = curl_init(); 199 | 200 | curl_setopt_array($curl, array( 201 | CURLOPT_POST => 1, 202 | CURLOPT_HEADER => 0, 203 | CURLOPT_RETURNTRANSFER => 1, 204 | CURLOPT_SSL_VERIFYPEER => 1, 205 | CURLOPT_URL => $queryUrl, 206 | CURLOPT_POSTFIELDS => $queryData, 207 | )); 208 | 209 | $result = curl_exec($curl); 210 | curl_close($curl); 211 | 212 | $result = json_decode($result, 1); 213 | 214 | if ($authRefresh && isset($result['error']) && in_array($result['error'], array('expired_token', 'invalid_token'))) 215 | { 216 | $auth = restAuth($auth); 217 | if ($auth) 218 | { 219 | $result = restCommand($method, $params, $auth, false); 220 | } 221 | } 222 | 223 | return $result; 224 | } 225 | 226 | /** 227 | * Get new authorize data if you authorize is expire. 228 | * 229 | * @param array $auth - Authorize data, received from event 230 | * @return bool|mixed 231 | */ 232 | function restAuth($auth) 233 | { 234 | if (!CLIENT_ID || !CLIENT_SECRET) 235 | return false; 236 | 237 | if(!isset($auth['refresh_token'])) 238 | return false; 239 | 240 | $queryUrl = 'https://oauth.bitrix.info/oauth/token/'; 241 | $queryData = http_build_query($queryParams = array( 242 | 'grant_type' => 'refresh_token', 243 | 'client_id' => CLIENT_ID, 244 | 'client_secret' => CLIENT_SECRET, 245 | 'refresh_token' => $auth['refresh_token'], 246 | )); 247 | 248 | writeToLog(Array('URL' => $queryUrl, 'PARAMS' => $queryParams), 'ImBot request auth data'); 249 | 250 | $curl = curl_init(); 251 | 252 | curl_setopt_array($curl, array( 253 | CURLOPT_HEADER => 0, 254 | CURLOPT_RETURNTRANSFER => 1, 255 | CURLOPT_URL => $queryUrl.'?'.$queryData, 256 | )); 257 | 258 | $result = curl_exec($curl); 259 | curl_close($curl); 260 | 261 | $result = json_decode($result, 1); 262 | if (!isset($result['error'])) 263 | { 264 | $appsConfig = Array(); 265 | if (file_exists(__DIR__.'/config.php')) 266 | include(__DIR__.'/config.php'); 267 | 268 | $result['application_token'] = $auth['application_token']; 269 | $appsConfig[$auth['application_token']]['AUTH'] = $result; 270 | saveParams($appsConfig); 271 | } 272 | else 273 | { 274 | $result = false; 275 | } 276 | 277 | return $result; 278 | } 279 | 280 | /** 281 | * Write data to log file. (by default disabled) 282 | * WARNING: this method is only created for demonstration, never store log file in public folder 283 | * 284 | * @param mixed $data 285 | * @param string $title 286 | * @return bool 287 | */ 288 | function writeToLog($data, $title = '') 289 | { 290 | if (!DEBUG_FILE_NAME) 291 | return false; 292 | 293 | $log = "\n------------------------\n"; 294 | $log .= date("Y.m.d G:i:s")."\n"; 295 | $log .= (strlen($title) > 0 ? $title : 'DEBUG')."\n"; 296 | $log .= print_r($data, 1); 297 | $log .= "\n------------------------\n"; 298 | 299 | file_put_contents(__DIR__."/".DEBUG_FILE_NAME, $log, FILE_APPEND); 300 | 301 | return true; 302 | } 303 | --------------------------------------------------------------------------------