├── .gitignore ├── examples ├── endpoint.php ├── index.php ├── MyBotServer.php └── MyBotClient.php ├── src ├── Libs │ ├── Helpers.php │ ├── Options.php │ └── CommonExceptionHandler.php ├── Bot │ ├── TestBot.php │ ├── BotException.php │ ├── SkypeBot.php │ ├── EmailBot.php │ ├── SlackBot.php │ ├── TelegramBot.php │ ├── FacebookBot.php │ └── WebchatBot.php ├── Auth │ ├── AuthException.php │ └── Auth.php ├── Http │ ├── HttpException.php │ └── Http.php └── Bot.php ├── phpunit.php ├── readme.md ├── LICENSE └── composer.json /.gitignore: -------------------------------------------------------------------------------- 1 | /vendor 2 | composer.phar 3 | composer.lock 4 | .DS_Store 5 | Thumbs.db 6 | -------------------------------------------------------------------------------- /examples/endpoint.php: -------------------------------------------------------------------------------- 1 | init(); -------------------------------------------------------------------------------- /examples/index.php: -------------------------------------------------------------------------------- 1 | sendMessage( $to, "Hey! What's up! Here goes a duck picture!" ); 10 | 11 | $server->sendImage( $to, 'http://www.publicdomainpictures.net/pictures/30000/t2/duck-on-a-rock.jpg' ); -------------------------------------------------------------------------------- /src/Libs/Helpers.php: -------------------------------------------------------------------------------- 1 | code}]: {$this->message}\n"; 30 | } 31 | 32 | } -------------------------------------------------------------------------------- /src/Auth/AuthException.php: -------------------------------------------------------------------------------- 1 | code}]: {$this->message}\n"; 30 | } 31 | 32 | } -------------------------------------------------------------------------------- /phpunit.php: -------------------------------------------------------------------------------- 1 | **Note:** This repository contains the php library for the Bot framework. If you want to build a bot in another language, visit the oficial web [Bot Framework](https://dev.botframework.com/). 4 | 5 | ## Bot Framework 6 | 7 | Bot Framework allow you build and connect intelligent bots to interact with your users naturally wherever they are — from your website or app to text/SMS, Skype, Slack, Facebook Messenger, Office 365 mail, Teams and other popular services. 8 | 9 | This is the implementation non-oficial of the Bot Framework api in php. 10 | 11 | ## Official Documentation 12 | 13 | Documentation for the bot framework can be found on the [Bot framework](https://docs.botframework.com/). 14 | 15 | ## Security Vulnerabilities 16 | 17 | If you discover a security vulnerability within Bot, please send an e-mail to Andrés Téllez at a.tellez@neversyn.com. All security vulnerabilities will be promptly addressed. 18 | 19 | ### License 20 | 21 | The Bot framework is open-sourced software licensed under the [MIT license](http://opensource.org/licenses/MIT) 22 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 Andrés Téllez 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 | -------------------------------------------------------------------------------- /src/Libs/CommonExceptionHandler.php: -------------------------------------------------------------------------------- 1 | code}]: {$this->message}\n"; 29 | } 30 | 31 | /** 32 | * [funciónPersonalizada description] 33 | * @return [type] [description] 34 | */ 35 | public function funciónPersonalizada() { 36 | echo "Una función personalizada para este tipo de excepción\n"; 37 | } 38 | 39 | } -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hatxor/bot-framework-php", 3 | "description": "A complete bot framework library write in php, plug and play!", 4 | "homepage": "https://github.com/hatxor/bot-framework-php", 5 | "license": "MIT", 6 | "type": "library", 7 | "keywords": [ 8 | "Microsoft", 9 | "Bot", 10 | "Microsoft Bot", 11 | "Skype", 12 | "Skype Bot", 13 | "Facebook", 14 | "Facebook Bot", 15 | "Telegram", 16 | "Telegram Bot", 17 | "Slack", 18 | "Slack Bot", 19 | "Email", 20 | "Email Bot", 21 | "Webchat", 22 | "Webchat Bot" 23 | ], 24 | "authors": [ 25 | { 26 | "name": "Andrés Téllez", 27 | "email": "a.tellez@neversyn.com", 28 | "homepage": "https://github.com/hatxor" 29 | } 30 | ], 31 | "require": { 32 | "php": ">=5.5.0" 33 | }, 34 | "require-dev": { 35 | "monolog/monolog": "~1.17", 36 | "squizlabs/php_codesniffer": "~2.3", 37 | "phpunit/phpunit": ">=5.2", 38 | "phpunit/php-code-coverage": "~3.3" 39 | }, 40 | "autoload": { 41 | "psr-4": { 42 | "hatxor\\BotFramework\\": "src" 43 | } 44 | }, 45 | "autoload-dev": { 46 | "psr-4": { 47 | "hatxor\\BotFramework\\tests\\": "tests" 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /examples/MyBotServer.php: -------------------------------------------------------------------------------- 1 | loadConfig( $config ); 35 | 36 | // 2. Init our bot depending of the channel 37 | $this->bot = Bot::getBotByChannel( $channelID, $this->client, $this->secret, $config, $config ); // TODO Try / catch para controlar los errores de que no encuentre la clase 38 | 39 | // 3. Do the auth 40 | $this->bot->authenticate(); 41 | 42 | } 43 | 44 | 45 | /** 46 | * Load the configuration from the config.php file 47 | */ 48 | private function loadConfig( $config = [] ) { 49 | 50 | $this->hash = ( isset( $config['hash'] ) ) ? $config['hash'] : null; 51 | 52 | $this->client = ( isset( $config['app_client_id'] ) ) ? $config['app_client_id'] : null; 53 | 54 | $this->secret = ( isset( $config['app_secret_id'] ) ) ? $config['app_secret_id'] : null; 55 | 56 | } 57 | 58 | /** 59 | * ###################################### 60 | * YOU CAN CREATE FROM HERE 61 | * ###################################### 62 | */ 63 | 64 | 65 | /** 66 | * Send a normal message with text to the given user 67 | * @param string $to Recipient ID 68 | * @param string $message The message to send 69 | * @return array HTTP response 70 | */ 71 | public function sendMessage( $to, $message ) { 72 | 73 | return $this->bot->addMessage( $to, $message ); 74 | 75 | } 76 | 77 | } 78 | -------------------------------------------------------------------------------- /src/Bot/EmailBot.php: -------------------------------------------------------------------------------- 1 | serviceUrl . '/' . $this->serviceVersion . '/conversations/' . $to . '/activities'; 36 | 37 | $params = array( 38 | 39 | 'type' => $this->type_text_message, 40 | "text" => $message, 41 | 42 | ); 43 | 44 | $httpResponse = $this->do_request( $url, 'POST_RAW', $params, array( 'Content-Type: application/json' ) ); 45 | 46 | return $httpResponse; 47 | 48 | } 49 | 50 | 51 | /** 52 | * [addAttachment description] 53 | * @param string $to [description] 54 | * @param string $message [description] 55 | * @return array [description] 56 | */ 57 | public function addAttachment( $to, $type, $content, $extra = array(), $options = array() ) { 58 | 59 | if( !isset( $this->type_attachment[ $type ] ) ) 60 | 61 | throw new BotException( "Wuops! The media type doesn't exist.", 1 ); 62 | 63 | // Execute 64 | $url = $this->serviceUrl . '/' . $this->serviceVersion . '/conversations/' . $to . '/activities'; 65 | 66 | $methodName = "_create" . $type; 67 | 68 | $params = array( 69 | 70 | 'type' => $this->type_attachment[ $type ], 71 | "attachments" => $this->$methodName( $content, $extra, $options ), 72 | 73 | ); 74 | 75 | if( isset( $options['summary'] ) ) 76 | 77 | $params['summary'] = $options['summary']; 78 | 79 | $httpResponse = $this->do_request( $url, 'POST_RAW', $params, array( 'Content-Type: application/json' ) ); 80 | 81 | return $httpResponse; 82 | 83 | } 84 | 85 | } 86 | -------------------------------------------------------------------------------- /src/Bot/SlackBot.php: -------------------------------------------------------------------------------- 1 | serviceUrl . '/' . $this->serviceVersion . '/conversations/' . $to . '/activities'; 36 | 37 | $params = array( 38 | 39 | 'type' => $this->type_text_message, 40 | "text" => $message, 41 | 42 | ); 43 | 44 | $httpResponse = $this->do_request( $url, 'POST_RAW', $params, array( 'Content-Type: application/json' ) ); 45 | 46 | return $httpResponse; 47 | 48 | } 49 | 50 | 51 | /** 52 | * [addAttachment description] 53 | * @param string $to [description] 54 | * @param string $message [description] 55 | * @return array [description] 56 | */ 57 | public function addAttachment( $to, $type, $content, $extra = array(), $options = array() ) { 58 | 59 | if( !isset( $this->type_attachment[ $type ] ) ) 60 | 61 | throw new BotException( "Wuops! The media type doesn't exist.", 1 ); 62 | 63 | // Execute 64 | $url = $this->serviceUrl . '/' . $this->serviceVersion . '/conversations/' . $to . '/activities'; 65 | 66 | $methodName = "_create" . $type; 67 | 68 | $params = array( 69 | 70 | 'type' => $this->type_attachment[ $type ], 71 | "attachments" => $this->$methodName( $content, $extra, $options ), 72 | 73 | ); 74 | 75 | if( isset( $options['summary'] ) ) 76 | 77 | $params['summary'] = $options['summary']; 78 | 79 | $httpResponse = $this->do_request( $url, 'POST_RAW', $params, array( 'Content-Type: application/json' ) ); 80 | 81 | return $httpResponse; 82 | 83 | } 84 | 85 | } 86 | -------------------------------------------------------------------------------- /src/Bot/TelegramBot.php: -------------------------------------------------------------------------------- 1 | serviceUrl . '/' . $this->serviceVersion . '/conversations/' . $to . '/activities'; 36 | 37 | $params = array( 38 | 39 | 'type' => $this->type_text_message, 40 | "text" => $message, 41 | 42 | ); 43 | 44 | $httpResponse = $this->do_request( $url, 'POST_RAW', $params, array( 'Content-Type: application/json' ) ); 45 | 46 | return $httpResponse; 47 | 48 | } 49 | 50 | 51 | /** 52 | * [addAttachment description] 53 | * @param string $to [description] 54 | * @param string $message [description] 55 | * @return array [description] 56 | */ 57 | public function addAttachment( $to, $type, $content, $extra = array(), $options = array() ) { 58 | 59 | if( !isset( $this->type_attachment[ $type ] ) ) 60 | 61 | throw new BotException( "Wuops! The media type doesn't exist.", 1 ); 62 | 63 | // Execute 64 | $url = $this->serviceUrl . '/' . $this->serviceVersion . '/conversations/' . $to . '/activities'; 65 | 66 | $methodName = "_create" . $type; 67 | 68 | $params = array( 69 | 70 | 'type' => $this->type_attachment[ $type ], 71 | "attachments" => $this->$methodName( $content, $extra, $options ), 72 | 73 | ); 74 | 75 | if( isset( $options['summary'] ) ) 76 | 77 | $params['summary'] = $options['summary']; 78 | 79 | $httpResponse = $this->do_request( $url, 'POST_RAW', $params, array( 'Content-Type: application/json' ) ); 80 | 81 | return $httpResponse; 82 | 83 | } 84 | 85 | } 86 | -------------------------------------------------------------------------------- /src/Auth/Auth.php: -------------------------------------------------------------------------------- 1 | http = new Http; 22 | 23 | try { 24 | $this->getToken( $client, $secret ); 25 | } 26 | 27 | catch (AuthException $e) { 28 | 29 | die( __CLASS__ . ' Wuops! ' . $e->getMessage() ); 30 | 31 | } 32 | 33 | } 34 | 35 | /** 36 | * [auth description] 37 | * @param [type] $client [description] 38 | * @param [type] $secret [description] 39 | * @return [type] [description] 40 | */ 41 | public function getToken( $client, $secret ) { 42 | 43 | $params = array( 44 | 'grant_type' => 'client_credentials', 45 | 'client_id' => $client, 46 | 'client_secret' => $secret, 47 | 'scope' => 'https://graph.microsoft.com/.default', 48 | ); 49 | 50 | try { 51 | 52 | $httpResponse = $this->http->request( $this->authURL, 'POST', $params ); 53 | 54 | if( $httpResponse['status'] == 200 ) { 55 | 56 | $httpResponseObj = json_decode( $httpResponse['result'] ); 57 | 58 | if( isset( $httpResponseObj->access_token ) && $httpResponseObj->access_token != '' ) { 59 | 60 | $this->token = $httpResponseObj->access_token; 61 | 62 | return $this->token; 63 | 64 | } 65 | 66 | else 67 | 68 | throw new AuthException( 'Error getting the access token!' ); 69 | 70 | } 71 | 72 | throw new AuthException( 'Error getting the access token!' ); 73 | 74 | } catch (HttpException $e) { 75 | 76 | if( $e->getCode() == 401 ) 77 | 78 | throw new AuthException( 'Unauthorized - The authentication information is not provided or is invalid.' ); 79 | 80 | else if( $e->getCode() == 403 ) 81 | 82 | throw new AuthException( 'Forbidden - The provided credentials do not grant the client permission to access the resource. For example: a recognized user attempted to access restricted content..' ); 83 | 84 | else 85 | 86 | die( $e->manageError() ); 87 | 88 | } 89 | 90 | } 91 | 92 | } -------------------------------------------------------------------------------- /src/Bot/FacebookBot.php: -------------------------------------------------------------------------------- 1 | serviceUrl . '/' . $this->serviceVersion . '/conversations/' . $to . '/activities'; 36 | 37 | $params = array( 38 | 39 | 'type' => $this->type_text_message, 40 | "text" => $message, 41 | "from" => array( "id" => $this->config['fb_bot_id'], "name" => $this->config['fb_bot_name'] ), 42 | 43 | ); 44 | 45 | $httpResponse = $this->do_request( $url, 'POST_RAW', $params, array( 'Content-Type: application/json' ) ); 46 | 47 | return $httpResponse; 48 | 49 | } 50 | 51 | 52 | /** 53 | * [addAttachment description] 54 | * @param string $to [description] 55 | * @param string $message [description] 56 | * @return array [description] 57 | */ 58 | public function addAttachment( $to, $type, $content, $extra = array(), $options = array() ) { 59 | 60 | if( !isset( $this->type_attachment[ $type ] ) ) 61 | 62 | throw new BotException( "Wuops! The media type doesn't exist.", 1 ); 63 | 64 | // Execute 65 | $url = $this->serviceUrl . '/' . $this->serviceVersion . '/conversations/' . $to . '/activities'; 66 | 67 | $methodName = "_create" . $type; 68 | 69 | $params = array( 70 | 71 | 'type' => $this->type_attachment[ $type ], 72 | "attachments" => $this->$methodName( $content, $extra, $options ), 73 | "from" => array( "id" => $this->config['fb_bot_id'], "name" => $this->config['fb_bot_name'] ), 74 | 75 | ); 76 | 77 | if( isset( $options['summary'] ) ) 78 | 79 | $params['summary'] = $options['summary']; 80 | 81 | $httpResponse = $this->do_request( $url, 'POST_RAW', $params, array( 'Content-Type: application/json' ) ); 82 | 83 | return $httpResponse; 84 | 85 | } 86 | 87 | } 88 | -------------------------------------------------------------------------------- /src/Http/HttpException.php: -------------------------------------------------------------------------------- 1 | alt_message = $message; 19 | 20 | parent::__construct( "Wuops! Error in curl call!", $code, $previous); 21 | 22 | } 23 | 24 | 25 | /** 26 | * [__toString description] 27 | * @return string [description] 28 | */ 29 | public function __toString() { 30 | return __CLASS__ . ": [{$this->code}]: {$this->message}\n"; 31 | } 32 | 33 | /** 34 | * [funciónPersonalizada description] 35 | * @return [type] [description] 36 | */ 37 | public function manageError() { 38 | 39 | if( $this->getCode() == 400 ) 40 | 41 | $this->alt_message['known_error'] = 'Bad Request - The request can’t be fulfilled because of bad syntax.'; 42 | 43 | else if( $this->getCode() == 401 ) 44 | 45 | $this->alt_message['known_error'] = 'Unauthorized - The authentication information is not provided or is invalid.'; 46 | 47 | else if( $this->getCode() == 403 ) 48 | 49 | $this->alt_message['known_error'] = 'Forbidden - The provided credentials do not grant the client permission to access the resource. For example: a recognized user attempted to access restricted content..'; 50 | 51 | // Make the http error message 52 | $html = "

".__CLASS__ ." Wuops! Curl error: ".$this->alt_message['curl_string_error']." [".$this->alt_message['http_code']."]

"; 53 | 54 | $html .= ""; 81 | 82 | return $html; 83 | 84 | } 85 | 86 | } -------------------------------------------------------------------------------- /src/Bot/WebchatBot.php: -------------------------------------------------------------------------------- 1 | serviceUrl . '/' . $this->serviceVersion . '/conversations/' . $to . '/activities'; 36 | 37 | $params = array( 38 | 39 | 'type' => $this->type_text_message, 40 | "text" => $message, 41 | "conversation" => array( "id" => $to), 42 | "from" => array( "id" => ( isset( $extra['from'] ) ) ? $extra['from'] : $this->config['webchat_name'] ), 43 | 44 | ); 45 | 46 | $httpResponse = $this->do_request( $url, 'POST_RAW', $params, array( 'Content-Type: application/json' ) ); 47 | 48 | return $httpResponse; 49 | 50 | } 51 | 52 | 53 | /** 54 | * [addAttachment description] 55 | * @param string $to [description] 56 | * @param string $message [description] 57 | * @return array [description] 58 | */ 59 | public function addAttachment( $to, $type, $content, $extra = array(), $options = array() ) { 60 | 61 | if( !isset( $this->type_attachment[ $type ] ) ) 62 | 63 | throw new BotException( "Wuops! The media type doesn't exist.", 1 ); 64 | 65 | // Execute 66 | $url = $this->serviceUrl . '/' . $this->serviceVersion . '/conversations/' . $to . '/activities'; 67 | 68 | $methodName = "_create" . $type; 69 | 70 | $params = array( 71 | 72 | 'type' => $this->type_attachment[ $type ], 73 | "attachments" => $this->$methodName( $content, $extra, $options ), 74 | "conversation" => array( "id" => $to), 75 | "from" => array( "id" => ( isset( $extra['from'] ) ) ? $extra['from'] : $this->config['webchat_name'] ), 76 | 77 | ); 78 | 79 | if( isset( $options['summary'] ) ) 80 | 81 | $params['summary'] = $options['summary']; 82 | 83 | $httpResponse = $this->do_request( $url, 'POST_RAW', $params, array( 'Content-Type: application/json' ) ); 84 | 85 | return $httpResponse; 86 | 87 | } 88 | 89 | } 90 | -------------------------------------------------------------------------------- /src/Http/Http.php: -------------------------------------------------------------------------------- 1 | connection = curl_init(); 19 | 20 | } 21 | 22 | 23 | /** 24 | * [request description] 25 | * @param [type] $url [description] 26 | * @param string $method [description] 27 | * @param array $params [description] 28 | * @param boolean $secure [description] 29 | * @return [type] [description] 30 | */ 31 | public function request( $url, $method = 'GET', $params = array(), $headers = array(), $secure = true, $excludePermHeaders = false, $debug = false ) { 32 | 33 | curl_setopt( $this->connection, CURLOPT_URL, $url ); 34 | curl_setopt( $this->connection, CURLOPT_RETURNTRANSFER, true ); 35 | curl_setopt( $this->connection, CURLOPT_MAXREDIRS, 10 ); 36 | curl_setopt( $this->connection, CURLOPT_FOLLOWLOCATION, 1 ); 37 | 38 | $original_method = $method; 39 | 40 | // Secure opts 41 | if( $secure == false ) { 42 | curl_setopt( $this->connection, CURLOPT_SSL_VERIFYHOST, 0 ); 43 | curl_setopt( $this->connection, CURLOPT_SSL_VERIFYPEER, 0 ); 44 | } 45 | 46 | // Debug 47 | if( $debug === true ) { 48 | 49 | curl_setopt( $this->connection, CURLOPT_VERBOSE, true ); 50 | $verbose = fopen( $this->debugFile, 'a+' ); 51 | curl_setopt( $this->connection, CURLOPT_STDERR, $verbose ); 52 | 53 | } 54 | 55 | // Headers 56 | if ( $excludePermHeaders == false && $this->permHeaders !== null && count( $this->permHeaders ) > 0 ) 57 | 58 | $headers = array_merge( $headers, $this->permHeaders ); 59 | 60 | if( isset( $headers ) && count( $headers ) > 0 ) 61 | 62 | curl_setopt( $this->connection, CURLOPT_HTTPHEADER, $headers ); 63 | 64 | // POST || PUT 65 | if( $method == 'POST' || $method == 'PUT' ) { 66 | 67 | curl_setopt( $this->connection, CURLOPT_CUSTOMREQUEST, $method ); 68 | curl_setopt( $this->connection, CURLOPT_POST, count( $params ) ); 69 | curl_setopt( $this->connection, CURLOPT_POSTFIELDS, http_build_query ( $params ) ); 70 | 71 | } 72 | 73 | // POST RAW 74 | else if( $method == 'POST_RAW' ) { 75 | 76 | $params = json_encode ( $params ); 77 | 78 | curl_setopt( $this->connection, CURLOPT_POSTFIELDS, $params ); 79 | curl_setopt( $this->connection, CURLOPT_CUSTOMREQUEST, "POST" ); 80 | 81 | //die( "Es: " . json_encode ( $headers ) ); 82 | 83 | } 84 | 85 | // DELETE 86 | else if( $method == 'DELETE' ) { 87 | 88 | curl_setopt( $this->connection, CURLOPT_CUSTOMREQUEST, $method ); 89 | curl_setopt( $this->connection, CURLOPT_POST, count( $params ) ); 90 | curl_setopt( $this->connection, CURLOPT_POSTFIELDS, $fields_string ); 91 | 92 | } 93 | 94 | // GET 95 | else { 96 | 97 | if( isset( $params ) && count( $params ) > 0 ) 98 | 99 | curl_setopt( $this->connection, CURLOPT_URL, $url . '?' . $fields_string ); 100 | 101 | else 102 | 103 | curl_setopt( $this->connection, CURLOPT_URL, $url ); 104 | 105 | } 106 | 107 | // Exec 108 | $result = curl_exec( $this->connection ); 109 | 110 | $http_code = curl_getinfo( $this->connection, CURLINFO_HTTP_CODE); 111 | 112 | if ( $errno = curl_errno( $this->connection ) || substr ( $http_code, 0, 1) != 2 ) { 113 | 114 | $error_params = array( 115 | 116 | 'url' => $url, 117 | 'method' => $original_method, 118 | 'secure' => $secure, 119 | 'headers' => $headers, 120 | 'response' => $result, 121 | 'http_code' => $http_code, 122 | 'curl_string_error' => curl_strerror( $errno ), 123 | 'params' => $params, 124 | 'debug_mode' => $debug, 125 | 126 | ); 127 | 128 | throw new HttpException( $error_params, $http_code ); 129 | 130 | } 131 | 132 | else 133 | 134 | return array( 'result' => $result, 'status' => $http_code ); 135 | 136 | } 137 | 138 | 139 | /** 140 | * [__destruct description] 141 | */ 142 | public function __destruct() { 143 | 144 | curl_close( $this->connection ); 145 | 146 | $this->connection = null; 147 | 148 | } 149 | 150 | 151 | } -------------------------------------------------------------------------------- /examples/MyBotClient.php: -------------------------------------------------------------------------------- 1 | loadConfig( $config ); 36 | 37 | // 2. We take the input data 38 | $this->input = $this->getPostRaw(); 39 | 40 | // 3. Check the hash 41 | if( !isset( $_GET['hash'] ) || $_GET['hash'] != $this->hash ) 42 | 43 | die("Unauthorized!"); // TODO Change by an exception 44 | 45 | // 4. Check the channel 46 | if( !isset( $this->input->channelId ) ) 47 | 48 | die("Channel not found."); // TODO Change by an exception 49 | 50 | // 5. Init our bot depending of the channel 51 | $this->bot = Bot::getBotByChannel( $this->input->channelId, $this->client, $this->secret, $config ); // TODO Try / catch to manage other errors 52 | 53 | } 54 | 55 | /** 56 | * [init description] 57 | * @return [type] [description] 58 | */ 59 | public function init() { 60 | 61 | if( !isset( $this->input->type ) ) 62 | 63 | die("Method not found."); // TODO Cambiar por una excepcion 64 | 65 | // Get the type of request and execute the right method 66 | return $this->fireEventHandler( $this->input->type ); 67 | 68 | } 69 | 70 | 71 | /** 72 | * Load the configuration from the config.php file 73 | */ 74 | private function loadConfig( $config = [] ) { 75 | 76 | $this->hash = ( isset( $config['hash'] ) ) ? $config['hash'] : null; 77 | 78 | $this->client = ( isset( $config['app_client_id'] ) ) ? $config['app_client_id'] : null; 79 | 80 | $this->secret = ( isset( $config['app_secret_id'] ) ) ? $config['app_secret_id'] : null; 81 | 82 | } 83 | 84 | 85 | /** 86 | * Get the info from the bot response 87 | * @param boolean $to_object To enable if the response must ve given in object or in raw 88 | * @return mixed String or Object depending. Response from the bot api. 89 | */ 90 | private function getPostRaw( $to_object = true ) { 91 | 92 | $postRaw = file_get_contents('php://input'); 93 | 94 | if( $to_object === true && Helpers::isJson( $postRaw ) === true ) 95 | 96 | return json_decode( $postRaw ); 97 | 98 | else 99 | 100 | return $postRaw; 101 | 102 | } 103 | 104 | 105 | /** 106 | * Manage the event firing the right method 107 | * @param string $type Method to fire 108 | * @return mixed The response of the selected method 109 | */ 110 | private function fireEventHandler ( $type ) { 111 | 112 | $methodName = $type . 'EventHandler'; 113 | 114 | $specificMethodName = $this->input->channelId . ucfirst($type) . 'EventHandler'; 115 | 116 | if ( !method_exists( $this, $specificMethodName ) ) { 117 | 118 | if ( !method_exists( $this, $methodName ) ) { 119 | 120 | $botClassName = Bot::getBotName( $this->input->channelId ); 121 | 122 | // If not exist in the client, we search for it in the Bot 123 | if ( !method_exists( $this->bot, $methodName ) ) 124 | 125 | die("No se encuentra el método!!"); // TODO Cambiar por una excepcion 126 | 127 | else 128 | 129 | return $this->bot->$methodName( $this->input ); 130 | 131 | } 132 | 133 | else 134 | 135 | return $this->$methodName(); 136 | 137 | } 138 | 139 | else 140 | 141 | return $this->$specificMethodName(); 142 | 143 | } 144 | 145 | /** 146 | * ###################################### 147 | * YOU CAN CREATE FROM HERE 148 | * ###################################### 149 | */ 150 | 151 | 152 | /** 153 | * Default skype message event handler 154 | */ 155 | public function skypeMessageEventHandler() { 156 | 157 | $to = $this->input->from->id; 158 | 159 | $message = "I have received \"" . $this->input->text . "\" from " . $this->input->from->name . "."; 160 | 161 | $this->bot->addMessage( $to, $message ); 162 | 163 | return 0; 164 | 165 | } 166 | 167 | 168 | /** 169 | * Default skype conversation update event handlers 170 | */ 171 | public function skypeConversationUpdateEventHandler() { 172 | 173 | // Members added in group 174 | if( isset( $this->input->conversation->isGroup ) && $this->input->conversation->isGroup == true ) { 175 | 176 | $to = $this->input->conversation->id; 177 | 178 | if( isset( $this->input->membersAdded ) ) { 179 | 180 | $message = "Hi guys!! :)"; 181 | 182 | $this->bot->addMessage( $to, $message ); 183 | 184 | } 185 | 186 | } 187 | 188 | return 0; 189 | 190 | } 191 | 192 | /** 193 | * Default skype contact relation update event handlers 194 | * @return [type] [description] 195 | */ 196 | public function skypeContactRelationUpdateEventHandler() { 197 | 198 | $to = $this->input->from->id; 199 | 200 | $name = explode(" ", $this->input->from->name)[0]; 201 | 202 | $message = "Hey " . $name . "! What's up?? :)"; 203 | 204 | $this->bot->addMessage( $to, $message ); 205 | 206 | return 0; 207 | 208 | } 209 | 210 | } 211 | -------------------------------------------------------------------------------- /src/Bot.php: -------------------------------------------------------------------------------- 1 | "message/image", 37 | "audio" => "message/audio", 38 | "video" => "message/video", 39 | "card" => "message/card.carousel", 40 | 41 | ); 42 | 43 | 44 | /** 45 | * [__construct description] 46 | * @param [type] $client [description] 47 | * @param [type] $secret [description] 48 | */ 49 | public function __construct( $client, $secret, $config ) { 50 | 51 | $this->client = $client; 52 | 53 | $this->secret = $secret; 54 | 55 | $this->config = $config; 56 | 57 | $this->http = new Http(); 58 | 59 | } 60 | 61 | 62 | /** 63 | * [getBotByChannel description] 64 | * @param [type] $channelID [description] 65 | * @param [type] $client [description] 66 | * @param [type] $secret [description] 67 | * @return [type] [description] 68 | */ 69 | public static function getBotByChannel( $channelID, $client, $secret, $config ) { 70 | 71 | $botClassName = self::getBotName( $channelID ); 72 | 73 | if( !class_exists( $botClassName ) ) 74 | 75 | throw new BotException( "Wuops! Not exist a bot for the channelId '" . $channelID . "' (".$botClassName.")", 1 ); 76 | 77 | else { 78 | 79 | //file_put_contents('/var/www/cartasian/public/microsoft-bot/tmp/debug.txt', PHP_EOL . PHP_EOL . date("\[d-m-Y H:m:i\]") . ': '. $botClassName . PHP_EOL, FILE_APPEND ); 80 | 81 | return new $botClassName( $client, $secret, $config ); // TODO Lanzar excepcion si no se encuentra la clase 82 | 83 | } 84 | 85 | } 86 | 87 | 88 | /** 89 | * [getBotName description] 90 | * @param [type] $channelID [description] 91 | * @return [type] [description] 92 | */ 93 | public static function getBotName( $channelID ) { 94 | 95 | return __NAMESPACE__ . "\\" . ucfirst( $channelID ) . 'Bot'; 96 | 97 | } 98 | 99 | 100 | /** 101 | * [authenticate description] 102 | * @param [type] $client [description] 103 | * @param [type] $secret [description] 104 | * @return [type] [description] 105 | */ 106 | public function authenticate( $client = null, $secret = null ) { 107 | 108 | if( $client == null ) 109 | 110 | $client = $this->client; 111 | 112 | if( $secret == null ) 113 | 114 | $secret = $this->secret; 115 | 116 | $auth = new Auth( $client, $secret ); 117 | 118 | $this->token = $auth->token; 119 | 120 | $this->http->permHeaders = array( 'Authorization: Bearer ' . $this->token ); 121 | 122 | } 123 | 124 | 125 | /** 126 | * [authenticate description] 127 | * @param [type] $client [description] 128 | * @param [type] $secret [description] 129 | * @return [type] [description] 130 | */ 131 | protected function do_request( $url, $method = 'GET', $params = array(), $headers = array(), $secure = true, $excludePermHeaders = false, $debug = false ) { 132 | 133 | try { 134 | 135 | // We check by the auth 136 | if( $this->token == null) 137 | 138 | $this->authenticate(); 139 | 140 | // Do request 141 | $result = $this->http->request( $url, $method, $params, $headers, $secure, $excludePermHeaders, $debug ); 142 | 143 | return $result; 144 | 145 | } catch (HttpException $e) { 146 | 147 | if( $e->getCode() == 401 ) 148 | 149 | throw new AuthException( 'Unauthorized - The authentication information is not provided or is invalid.' ); 150 | 151 | else if( $e->getCode() == 403 ) 152 | 153 | throw new AuthException( 'Forbidden - The provided credentials do not grant the client permission to access the resource. For example: a recognized user attempted to access restricted content..' ); 154 | 155 | else 156 | 157 | die( $e->manageError() ); 158 | 159 | } 160 | 161 | } 162 | 163 | /** 164 | * COMMUNICATION METHODS 165 | */ 166 | 167 | 168 | /** 169 | * [addMessage description] 170 | * @param string $to [description] 171 | * @param string $message [description] 172 | * @return array [description] 173 | */ 174 | public function addMessage( $to, $message, $extra = array() ) { 175 | 176 | // Execute 177 | $url = $this->serviceUrl . '/' . $this->serviceVersion . '/conversations/' . $to . '/activities'; 178 | 179 | $params = array( 180 | 181 | 'type' => $this->type_text_message, 182 | "text" => $message, 183 | 184 | ); 185 | 186 | $httpResponse = $this->do_request( $url, 'POST_RAW', $params, array( 'Content-Type: application/json' ) ); 187 | 188 | return $httpResponse; 189 | 190 | } 191 | 192 | 193 | /** 194 | * [addAttachment description] 195 | * @param string $to [description] 196 | * @param string $message [description] 197 | * @return array [description] 198 | */ 199 | public function addAttachment( $to, $type, $content, $extra = array(), $options = array() ) { 200 | 201 | if( !isset( $this->type_attachment[ $type ] ) ) 202 | 203 | throw new BotException( "Wuops! The media type doesn't exist.", 1 ); 204 | 205 | // Execute 206 | $url = $this->serviceUrl . '/' . $this->serviceVersion . '/conversations/' . $to . '/activities'; 207 | 208 | $methodName = "_create" . $type; 209 | 210 | $params = array( 211 | 212 | 'type' => $this->type_attachment[ $type ], 213 | "attachments" => $this->$methodName( $content, $extra, $options ), 214 | 215 | ); 216 | 217 | if( isset( $options['summary'] ) ) 218 | 219 | $params['summary'] = $options['summary']; 220 | 221 | $httpResponse = $this->do_request( $url, 'POST_RAW', $params, array( 'Content-Type: application/json' ) ); 222 | 223 | return $httpResponse; 224 | 225 | } 226 | 227 | 228 | /** 229 | * [_createImage description] 230 | * @param [type] $content [description] 231 | * @param [type] $extra [description] 232 | * @param [type] $options [description] 233 | */ 234 | protected function _createImage( $content, $extra, $options ) { 235 | 236 | // Manipulate depending of the mode 237 | if( isset( $content['tmp_name'] ) ) { 238 | 239 | $imageEncoded = file_get_contents( $content['tmp_name'] ); 240 | 241 | $mimeType = $content['type']; 242 | 243 | $imageEncoded = 'data:image/' . $mimeType . ';base64,' . base64_encode( $image ); 244 | 245 | $response = array( 246 | 247 | "contentUrl" => $imageEncoded, 248 | "contentType" => $mimeType, 249 | 250 | ); 251 | 252 | } 253 | 254 | else if( file_exists( $content ) ) { 255 | 256 | $fileInfo = new \finfo( FILEINFO_MIME_TYPE ); 257 | 258 | $image = file_get_contents( $content ); 259 | 260 | $mimeType = $fileInfo->buffer( $image ); 261 | 262 | $imageEncoded = 'data:image/' . $mimeType . ';base64,' . base64_encode( $image ); 263 | 264 | $response = array( 265 | 266 | "contentUrl" => $imageEncoded, 267 | "contentType" => $mimeType, 268 | 269 | ); 270 | 271 | } 272 | 273 | else if( strpos( $content, 'http://' ) !== false || strpos( $content, 'https://' ) !== false ) { 274 | 275 | $fileInfo = new \finfo( FILEINFO_MIME_TYPE ); 276 | 277 | $image = file_get_contents( $content ); 278 | 279 | $mimeType = $fileInfo->buffer( $image ); 280 | 281 | $imageEncoded = 'data:' . $mimeType . ';base64,' . base64_encode( $image ); 282 | 283 | $response = array( 284 | 285 | "contentUrl" => $imageEncoded, 286 | "contentType" => $mimeType, 287 | 288 | ); 289 | 290 | } 291 | 292 | else if( strpos( $content, 'data:image' ) !== false ) { 293 | 294 | $imageEncoded = $content; 295 | 296 | $mimeTypeAlt1 = strpos( $content, ';' ); 297 | 298 | $mimeType = explode( ':', substr( $content, 0, $mimeTypeAlt1 ) )[1]; 299 | 300 | $response = array( 301 | 302 | "contentUrl" => $content, 303 | "contentType" => $mimeType, 304 | 305 | ); 306 | 307 | } 308 | 309 | else 310 | 311 | throw new BotException( "Wuops! The media type doesn't exist.", 1 ); 312 | 313 | // Extra 314 | $response = array_merge( $response, $extra ); 315 | 316 | return array( $response ); 317 | 318 | } 319 | 320 | 321 | /** 322 | * [_createAudio description] 323 | * @param [type] $content [description] 324 | * @param [type] $extra [description] 325 | * @param [type] $options [description] 326 | */ 327 | protected function _createAudio( $content, $extra, $options ) { 328 | 329 | //TODO 330 | 331 | } 332 | 333 | 334 | /** 335 | * [_createVideo description] 336 | * @param [type] $content [description] 337 | * @param [type] $extra [description] 338 | * @param [type] $options [description] 339 | */ 340 | protected function _createVideo( $content, $extra, $options ) { 341 | 342 | //TODO 343 | 344 | } 345 | 346 | 347 | /** 348 | * [_createVideo description] 349 | * @param [type] $content [description] 350 | * @param [type] $extra [description] 351 | * @param [type] $options [description] 352 | */ 353 | protected function _createCard( $content, $extra, $options ) { 354 | 355 | if( !is_array( $content ) ) 356 | 357 | $content = array( $content ); 358 | 359 | if( !isset( $content[0] ) || !is_array( $content[0] ) || isset( $content['type'] ) ) 360 | 361 | $content = array( $content ); 362 | 363 | $final_response = array(); 364 | 365 | foreach ($content as $key => $value) { 366 | 367 | //die( json_encode( $value ) ); 368 | 369 | // General check 370 | if( !isset( $value['content'] ) || !is_array( $value['content'] ) || count( $value['content'] ) == 0 ) 371 | 372 | throw new BotException( "Wuops! You need to provide an array with the content key.", 1 ); 373 | 374 | if( !isset( $value['content']['title'] ) || $value['content']['title'] == '' ) 375 | 376 | throw new BotException( "Wuops! You need to provide a title.", 1 ); 377 | 378 | // Check by type 379 | if( $value['type'] == 'thumbnail' ) { 380 | 381 | // Image 382 | if( !isset( $value['content']['image'] ) || $value['content']['image'] == '' ) 383 | 384 | throw new BotException( "Wuops! In card thumbnail, you need to provide a image url.", 1 ); 385 | 386 | } 387 | 388 | if( $value['type'] == 'hero' ) { 389 | 390 | // Text 391 | if( !isset( $value['content']['text'] ) || $value['content']['text'] == '' ) 392 | 393 | throw new BotException( "Wuops! In card hero, you need to provide a text.", 1 ); 394 | 395 | } 396 | 397 | $response = array( 398 | 399 | 'contentType' => 'application/vnd.microsoft.card.' . $value['type'], // thumbnail / hero / 400 | 'content' => array( 401 | 402 | 'title' => $value['content']['title'], 403 | 404 | ), 405 | 406 | ); 407 | 408 | // Other values 409 | // Images 410 | if( isset( $value['content']['image'] ) ) { 411 | 412 | $response['content']['images'] = array(); 413 | 414 | if( is_array( $value['content']['image'] ) ) { 415 | 416 | $image = array( 'url' => $value['content']['image']['url'] ); 417 | 418 | if( isset( $value['content']['image']['alt'] ) ) 419 | 420 | $image['alt'] = $value['content']['image']['alt']; 421 | 422 | } 423 | 424 | else 425 | 426 | $image = array( 'url' => $value['content']['image'] ); 427 | 428 | $response['content']['images'][] = $image; 429 | 430 | } 431 | 432 | // Buttons 433 | if( isset( $value['content']['buttons'] ) ) { 434 | 435 | if( !is_array( $value['content']['buttons'] ) ) 436 | 437 | throw new BotException( "Wuops! The buttons of the card must be in an array.", 1 ); 438 | 439 | $response['content']['buttons'] = array(); 440 | 441 | foreach ($value['content']['buttons'] as $key => $button) { 442 | 443 | if( !is_array( $button ) || !isset( $button['type'] ) || !isset( $button['title'] ) || !isset( $button['value'] ) ) 444 | 445 | throw new BotException( "Wuops! Each button of the card must to have the fields type, titlle and value.", 1 ); 446 | 447 | $response['content']['buttons'][] = $button; 448 | 449 | } 450 | 451 | } 452 | 453 | // Text 454 | if( isset( $value['content']['text'] ) ) 455 | 456 | $response['content']['text'] = $value['content']['text']; 457 | 458 | // Subtitle 459 | if( isset( $value['content']['text'] ) ) 460 | 461 | $response['content']['subtitle'] = $value['content']['subtitle']; 462 | 463 | // Extra 464 | if( isset( $extra[$key] ) ) 465 | 466 | $response['content'] = array_merge( $response['content'], $extra[$key] ); 467 | 468 | $final_response[] = $response; 469 | 470 | } 471 | 472 | return $final_response; 473 | 474 | } 475 | 476 | } 477 | --------------------------------------------------------------------------------