├── LICENSE ├── README.md ├── config.php ├── twitteroauth ├── LICENSE.md ├── README.md ├── autoload.php ├── composer.json └── src │ ├── Config.php │ ├── Consumer.php │ ├── HmacSha1.php │ ├── Request.php │ ├── Response.php │ ├── SignatureMethod.php │ ├── Token.php │ ├── TwitterOAuth.php │ ├── TwitterOAuthException.php │ ├── Util.php │ ├── Util │ └── JsonDecoder.php │ └── cacert.pem └── urtb.php /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Spencer Lowe 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 | # UptimeRobot Twitter Bot 2 | I created this tool to post UptimeRobot alerts to twitter. Everything is customizable
3 | ![alt text](https://i.imgur.com/Q345J02.png "Status") 4 |
5 |
6 |
7 | [Live Example](https://twitter.com/NerdBaggyTest) 8 | 9 | 10 | ## Install 11 | - [Download Latest Release Here](https://github.com/nerdbaggy/uptimerobot-twitter-bot/releases/latest) 12 | - Unzip and upload to a web accessible folder 13 | - Add a new alert in UptimeRobot in the 'Web-Hook' category
14 | For example if your script is at spencerl.com/twitterbot/urtb.php the ***URL to Notify*** will be spencerl.com/twitterbot/urtb.php? 15 | - Configure twitter. See below 16 | 17 | ## Twitter 18 | You need to make 4 keys from twitter to get this working.
19 | [Click Here for Directions](https://themepacific.com/how-to-generate-api-key-consumer-token-access-key-for-twitter-oauth/994/)
20 | Once you have the 4 keys put them in the ***config.php*** 21 | 22 | ## Message 23 | You can customize how the messages look when posting to Twitter. You can customize it to however you would like. Just needs to be below 140 chacters. But it can inculde emoji, ascii, links, hashtags, anything! You can customize the message with the variables below. 24 | 25 | ### Example 26 | 27 | ``` 28 | ✔ {{host}} is now now up after {{downtime}} [{{timestamp}} {{timezone}}] 29 | ✖ {{host}} has gone down [{{timestamp}} {{timezone}}] 30 | ``` 31 | 32 | | Variable | Example | Description | 33 | | ------------- | ------------- | ------------- | 34 | | {{host}} | Website | Name of the check | 35 | | {{id}} | 59426326 | ID of the check| 36 | | {{status}} | Up | Status of the check| 37 | | {{url}} | spencerl.com | Host of the check| 38 | | {{details}} | Timeout | Why the check failed| 39 | | {{downtime}} | 4 Minutes | How long a check was down for| 40 | | {{timestamp}} | 05:24 PM | Current time| 41 | | {{timezone}} | UTC | Timezone to get timestamp| 42 | -------------------------------------------------------------------------------- /config.php: -------------------------------------------------------------------------------- 1 | '', 4 | 'consumerSecret' => '', 5 | 'accessToken' => '', 6 | 'accessTokenSecret' => '', 7 | ); 8 | 9 | // You need to keep the timestamp in or Twitter will block messages 10 | $messages = array( 11 | // Message to send once a check has come back online 12 | "upMessage" => "✔ {{host}} is now now up after {{downtime}} [{{timestamp}} {{timezone}}]", 13 | 14 | // Message to send if a check comes back online but never got a down notification 15 | "upMessageNoDown" => "✔ {{host}} is now now up [{{timestamp}} {{timezone}}]", 16 | 17 | // Message to send when a check has gone down 18 | "downMessage" => "✖ {{host}} has gone down [{{timestamp}} {{timezone}}]", 19 | ); 20 | 21 | // Timestamp to display in the twitter message 22 | // You can format it here: http://php.net/manual/en/function.date.php 23 | $timestampFormat = 'h:i A'; 24 | 25 | // Timezone to display alerts in 26 | // http://php.net/manual/en/timezones.php 27 | $timezone = 'UTC'; 28 | 29 | // Name of the cache file 30 | $cacheFile = 'twitterbot.cache'; 31 | 32 | // What useragent must be present in the request 33 | $userAgentVerify = 'UptimeRobot'; 34 | 35 | // IPs to allow requests to come from. 36 | // These are the engine IPs from https://uptimerobot.com/locations 37 | $uptimeRobotIps = array( 38 | "69.162.124.226", 39 | "69.162.124.227", 40 | "69.162.124.228", 41 | "69.162.124.229", 42 | "69.162.124.230", 43 | "69.162.124.231", 44 | "69.162.124.232", 45 | "69.162.124.233", 46 | "69.162.124.234", 47 | "69.162.124.235", 48 | "69.162.124.236", 49 | "69.162.124.237", 50 | "69.162.124.238" 51 | ); 52 | 53 | // Allows requests to come from non approved sources 54 | // Don't use in production!!!!!!!! 55 | $debug = false; 56 | -------------------------------------------------------------------------------- /twitteroauth/LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright (c) 2009 Abraham Williams - http://abrah.am - abraham@abrah.am 2 | 3 | Permission is hereby granted, free of charge, to any person 4 | obtaining a copy of this software and associated documentation 5 | files (the "Software"), to deal in the Software without 6 | restriction, including without limitation the rights to use, 7 | copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the 9 | Software is furnished to do so, subject to the following 10 | conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 17 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 19 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 20 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /twitteroauth/README.md: -------------------------------------------------------------------------------- 1 | TwitterOAuth [![Build Status](https://img.shields.io/travis/abraham/twitteroauth.svg)](https://travis-ci.org/abraham/twitteroauth) [![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/abraham/twitteroauth/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/abraham/twitteroauth/?branch=master) [![Issues Count](https://img.shields.io/github/issues/abraham/twitteroauth.svg)](https://github.com/abraham/twitteroauth/issues) [![Latest Version](https://img.shields.io/packagist/v/abraham/twitteroauth.svg)](https://packagist.org/packages/abraham/twitteroauth) 2 | ------------ 3 | 4 |

The most popular PHP library for Twitter's OAuth REST API.

5 | 6 | See documentation at https://twitteroauth.com. 7 | 8 | OAuth signing code originally sourced from [here](https://code.google.com/p/oauth/). 9 | 10 | Twitter bird 11 | -------------------------------------------------------------------------------- /twitteroauth/autoload.php: -------------------------------------------------------------------------------- 1 | =5.5.0", 22 | "ext-curl": "*" 23 | }, 24 | "require-dev": { 25 | "phpunit/phpunit": "4.7.*", 26 | "squizlabs/php_codesniffer": "2.3.*", 27 | "phpmd/phpmd": "2.2.*" 28 | }, 29 | "autoload": { 30 | "psr-4": { 31 | "Abraham\\TwitterOAuth\\": "src" 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /twitteroauth/src/Config.php: -------------------------------------------------------------------------------- 1 | 9 | */ 10 | class Config 11 | { 12 | /** @var int How long to wait for a response from the API */ 13 | protected $timeout = 5; 14 | /** @var int how long to wait while connecting to the API */ 15 | protected $connectionTimeout = 5; 16 | /** 17 | * Decode JSON Response as associative Array 18 | * 19 | * @see http://php.net/manual/en/function.json-decode.php 20 | * 21 | * @var bool 22 | */ 23 | protected $decodeJsonAsArray = false; 24 | /** @var string User-Agent header */ 25 | protected $userAgent = 'TwitterOAuth (+https://twitteroauth.com)'; 26 | /** @var array Store proxy connection details */ 27 | protected $proxy = []; 28 | 29 | /** 30 | * Set the connection and response timeouts. 31 | * 32 | * @param int $connectionTimeout 33 | * @param int $timeout 34 | */ 35 | public function setTimeouts($connectionTimeout, $timeout) 36 | { 37 | $this->connectionTimeout = (int)$connectionTimeout; 38 | $this->timeout = (int)$timeout; 39 | } 40 | 41 | /** 42 | * @param bool $value 43 | */ 44 | public function setDecodeJsonAsArray($value) 45 | { 46 | $this->decodeJsonAsArray = (bool)$value; 47 | } 48 | 49 | /** 50 | * @param string $userAgent 51 | */ 52 | public function setUserAgent($userAgent) 53 | { 54 | $this->userAgent = (string)$userAgent; 55 | } 56 | 57 | /** 58 | * @param array $proxy 59 | */ 60 | public function setProxy(array $proxy) 61 | { 62 | $this->proxy = $proxy; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /twitteroauth/src/Consumer.php: -------------------------------------------------------------------------------- 1 | key = $key; 25 | $this->secret = $secret; 26 | $this->callbackUrl = $callbackUrl; 27 | } 28 | 29 | /** 30 | * @return string 31 | */ 32 | public function __toString() 33 | { 34 | return "Consumer[key=$this->key,secret=$this->secret]"; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /twitteroauth/src/HmacSha1.php: -------------------------------------------------------------------------------- 1 | getSignatureBaseString(); 31 | 32 | $parts = [$consumer->secret, null !== $token ? $token->secret : ""]; 33 | 34 | $parts = Util::urlencodeRfc3986($parts); 35 | $key = implode('&', $parts); 36 | 37 | return base64_encode(hash_hmac('sha1', $signatureBase, $key, true)); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /twitteroauth/src/Request.php: -------------------------------------------------------------------------------- 1 | parameters = $parameters; 26 | $this->httpMethod = $httpMethod; 27 | $this->httpUrl = $httpUrl; 28 | } 29 | 30 | /** 31 | * pretty much a helper function to set up the request 32 | * 33 | * @param Consumer $consumer 34 | * @param Token $token 35 | * @param string $httpMethod 36 | * @param string $httpUrl 37 | * @param array $parameters 38 | * 39 | * @return Request 40 | */ 41 | public static function fromConsumerAndToken( 42 | Consumer $consumer, 43 | Token $token = null, 44 | $httpMethod, 45 | $httpUrl, 46 | array $parameters = [] 47 | ) { 48 | $defaults = [ 49 | "oauth_version" => Request::$version, 50 | "oauth_nonce" => Request::generateNonce(), 51 | "oauth_timestamp" => time(), 52 | "oauth_consumer_key" => $consumer->key 53 | ]; 54 | if (null !== $token) { 55 | $defaults['oauth_token'] = $token->key; 56 | } 57 | 58 | $parameters = array_merge($defaults, $parameters); 59 | 60 | return new Request($httpMethod, $httpUrl, $parameters); 61 | } 62 | 63 | /** 64 | * @param string $name 65 | * @param string $value 66 | */ 67 | public function setParameter($name, $value) 68 | { 69 | $this->parameters[$name] = $value; 70 | } 71 | 72 | /** 73 | * @param $name 74 | * 75 | * @return string|null 76 | */ 77 | public function getParameter($name) 78 | { 79 | return isset($this->parameters[$name]) ? $this->parameters[$name] : null; 80 | } 81 | 82 | /** 83 | * @return array 84 | */ 85 | public function getParameters() 86 | { 87 | return $this->parameters; 88 | } 89 | 90 | /** 91 | * @param $name 92 | */ 93 | public function removeParameter($name) 94 | { 95 | unset($this->parameters[$name]); 96 | } 97 | 98 | /** 99 | * The request parameters, sorted and concatenated into a normalized string. 100 | * 101 | * @return string 102 | */ 103 | public function getSignableParameters() 104 | { 105 | // Grab all parameters 106 | $params = $this->parameters; 107 | 108 | // Remove oauth_signature if present 109 | // Ref: Spec: 9.1.1 ("The oauth_signature parameter MUST be excluded.") 110 | if (isset($params['oauth_signature'])) { 111 | unset($params['oauth_signature']); 112 | } 113 | 114 | return Util::buildHttpQuery($params); 115 | } 116 | 117 | /** 118 | * Returns the base string of this request 119 | * 120 | * The base string defined as the method, the url 121 | * and the parameters (normalized), each urlencoded 122 | * and the concated with &. 123 | * 124 | * @return string 125 | */ 126 | public function getSignatureBaseString() 127 | { 128 | $parts = [ 129 | $this->getNormalizedHttpMethod(), 130 | $this->getNormalizedHttpUrl(), 131 | $this->getSignableParameters() 132 | ]; 133 | 134 | $parts = Util::urlencodeRfc3986($parts); 135 | 136 | return implode('&', $parts); 137 | } 138 | 139 | /** 140 | * Returns the HTTP Method in uppercase 141 | * 142 | * @return string 143 | */ 144 | public function getNormalizedHttpMethod() 145 | { 146 | return strtoupper($this->httpMethod); 147 | } 148 | 149 | /** 150 | * parses the url and rebuilds it to be 151 | * scheme://host/path 152 | * 153 | * @return string 154 | */ 155 | public function getNormalizedHttpUrl() 156 | { 157 | $parts = parse_url($this->httpUrl); 158 | 159 | $scheme = $parts['scheme']; 160 | $host = strtolower($parts['host']); 161 | $path = $parts['path']; 162 | 163 | return "$scheme://$host$path"; 164 | } 165 | 166 | /** 167 | * Builds a url usable for a GET request 168 | * 169 | * @return string 170 | */ 171 | public function toUrl() 172 | { 173 | $postData = $this->toPostdata(); 174 | $out = $this->getNormalizedHttpUrl(); 175 | if ($postData) { 176 | $out .= '?' . $postData; 177 | } 178 | return $out; 179 | } 180 | 181 | /** 182 | * Builds the data one would send in a POST request 183 | * 184 | * @return string 185 | */ 186 | public function toPostdata() 187 | { 188 | return Util::buildHttpQuery($this->parameters); 189 | } 190 | 191 | /** 192 | * Builds the Authorization: header 193 | * 194 | * @return string 195 | * @throws TwitterOAuthException 196 | */ 197 | public function toHeader() 198 | { 199 | $first = true; 200 | $out = 'Authorization: OAuth'; 201 | foreach ($this->parameters as $k => $v) { 202 | if (substr($k, 0, 5) != "oauth") { 203 | continue; 204 | } 205 | if (is_array($v)) { 206 | throw new TwitterOAuthException('Arrays not supported in headers'); 207 | } 208 | $out .= ($first) ? ' ' : ', '; 209 | $out .= Util::urlencodeRfc3986($k) . '="' . Util::urlencodeRfc3986($v) . '"'; 210 | $first = false; 211 | } 212 | return $out; 213 | } 214 | 215 | /** 216 | * @return string 217 | */ 218 | public function __toString() 219 | { 220 | return $this->toUrl(); 221 | } 222 | 223 | /** 224 | * @param SignatureMethod $signatureMethod 225 | * @param Consumer $consumer 226 | * @param Token $token 227 | */ 228 | public function signRequest(SignatureMethod $signatureMethod, Consumer $consumer, Token $token = null) 229 | { 230 | $this->setParameter("oauth_signature_method", $signatureMethod->getName()); 231 | $signature = $this->buildSignature($signatureMethod, $consumer, $token); 232 | $this->setParameter("oauth_signature", $signature); 233 | } 234 | 235 | /** 236 | * @param SignatureMethod $signatureMethod 237 | * @param Consumer $consumer 238 | * @param Token $token 239 | * 240 | * @return string 241 | */ 242 | public function buildSignature(SignatureMethod $signatureMethod, Consumer $consumer, Token $token = null) 243 | { 244 | return $signatureMethod->buildSignature($this, $consumer, $token); 245 | } 246 | 247 | /** 248 | * @return string 249 | */ 250 | public static function generateNonce() 251 | { 252 | return md5(microtime() . mt_rand()); 253 | } 254 | } 255 | -------------------------------------------------------------------------------- /twitteroauth/src/Response.php: -------------------------------------------------------------------------------- 1 | 9 | */ 10 | class Response 11 | { 12 | /** @var string|null API path from the most recent request */ 13 | private $apiPath; 14 | /** @var int HTTP status code from the most recent request */ 15 | private $httpCode = 0; 16 | /** @var array HTTP headers from the most recent request */ 17 | private $headers = []; 18 | /** @var array|object Response body from the most recent request */ 19 | private $body = []; 20 | /** @var array HTTP headers from the most recent request that start with X */ 21 | private $xHeaders = []; 22 | 23 | /** 24 | * @param string $apiPath 25 | */ 26 | public function setApiPath($apiPath) 27 | { 28 | $this->apiPath = $apiPath; 29 | } 30 | 31 | /** 32 | * @return string|null 33 | */ 34 | public function getApiPath() 35 | { 36 | return $this->apiPath; 37 | } 38 | 39 | /** 40 | * @param array|object $body 41 | */ 42 | public function setBody($body) 43 | { 44 | $this->body = $body; 45 | } 46 | 47 | /** 48 | * @return array|object|string 49 | */ 50 | public function getBody() 51 | { 52 | return $this->body; 53 | } 54 | 55 | /** 56 | * @param int $httpCode 57 | */ 58 | public function setHttpCode($httpCode) 59 | { 60 | $this->httpCode = $httpCode; 61 | } 62 | 63 | /** 64 | * @return int 65 | */ 66 | public function getHttpCode() 67 | { 68 | return $this->httpCode; 69 | } 70 | 71 | /** 72 | * @param array $headers 73 | */ 74 | public function setHeaders($headers) 75 | { 76 | foreach ($headers as $key => $value) { 77 | if (substr($key, 0, 1) == 'x') { 78 | $this->xHeaders[$key] = $value; 79 | } 80 | } 81 | $this->headers = $headers; 82 | } 83 | 84 | /** 85 | * @return array 86 | */ 87 | public function getsHeaders() 88 | { 89 | return $this->headers; 90 | } 91 | 92 | /** 93 | * @param array $xHeaders 94 | */ 95 | public function setXHeaders($xHeaders) 96 | { 97 | $this->xHeaders = $xHeaders; 98 | } 99 | 100 | /** 101 | * @return array 102 | */ 103 | public function getXHeaders() 104 | { 105 | return $this->xHeaders; 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /twitteroauth/src/SignatureMethod.php: -------------------------------------------------------------------------------- 1 | buildSignature($request, $consumer, $token); 48 | 49 | // Check for zero length, although unlikely here 50 | if (strlen($built) == 0 || strlen($signature) == 0) { 51 | return false; 52 | } 53 | 54 | if (strlen($built) != strlen($signature)) { 55 | return false; 56 | } 57 | 58 | // Avoid a timing leak with a (hopefully) time insensitive compare 59 | $result = 0; 60 | for ($i = 0; $i < strlen($signature); $i++) { 61 | $result |= ord($built{$i}) ^ ord($signature{$i}); 62 | } 63 | 64 | return $result == 0; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /twitteroauth/src/Token.php: -------------------------------------------------------------------------------- 1 | key = $key; 22 | $this->secret = $secret; 23 | } 24 | 25 | /** 26 | * Generates the basic string serialization of a token that a server 27 | * would respond to request_token and access_token calls with 28 | * 29 | * @return string 30 | */ 31 | public function __toString() 32 | { 33 | return sprintf("oauth_token=%s&oauth_token_secret=%s", 34 | Util::urlencodeRfc3986($this->key), 35 | Util::urlencodeRfc3986($this->secret) 36 | ); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /twitteroauth/src/TwitterOAuth.php: -------------------------------------------------------------------------------- 1 | 15 | */ 16 | class TwitterOAuth extends Config 17 | { 18 | const API_VERSION = '1.1'; 19 | const API_HOST = 'https://api.twitter.com'; 20 | const UPLOAD_HOST = 'https://upload.twitter.com'; 21 | const UPLOAD_CHUNK = 40960; // 1024 * 40 22 | 23 | /** @var Response details about the result of the last request */ 24 | private $response; 25 | /** @var string|null Application bearer token */ 26 | private $bearer; 27 | /** @var Consumer Twitter application details */ 28 | private $consumer; 29 | /** @var Token|null User access token details */ 30 | private $token; 31 | /** @var HmacSha1 OAuth 1 signature type used by Twitter */ 32 | private $signatureMethod; 33 | 34 | /** 35 | * Constructor 36 | * 37 | * @param string $consumerKey The Application Consumer Key 38 | * @param string $consumerSecret The Application Consumer Secret 39 | * @param string|null $oauthToken The Client Token (optional) 40 | * @param string|null $oauthTokenSecret The Client Token Secret (optional) 41 | */ 42 | public function __construct($consumerKey, $consumerSecret, $oauthToken = null, $oauthTokenSecret = null) 43 | { 44 | $this->resetLastResponse(); 45 | $this->signatureMethod = new HmacSha1(); 46 | $this->consumer = new Consumer($consumerKey, $consumerSecret); 47 | if (!empty($oauthToken) && !empty($oauthTokenSecret)) { 48 | $this->token = new Token($oauthToken, $oauthTokenSecret); 49 | } 50 | if (empty($oauthToken) && !empty($oauthTokenSecret)) { 51 | $this->bearer = $oauthTokenSecret; 52 | } 53 | } 54 | 55 | /** 56 | * @param string $oauthToken 57 | * @param string $oauthTokenSecret 58 | */ 59 | public function setOauthToken($oauthToken, $oauthTokenSecret) 60 | { 61 | $this->token = new Token($oauthToken, $oauthTokenSecret); 62 | } 63 | 64 | /** 65 | * @return string|null 66 | */ 67 | public function getLastApiPath() 68 | { 69 | return $this->response->getApiPath(); 70 | } 71 | 72 | /** 73 | * @return int 74 | */ 75 | public function getLastHttpCode() 76 | { 77 | return $this->response->getHttpCode(); 78 | } 79 | 80 | /** 81 | * @return array 82 | */ 83 | public function getLastXHeaders() 84 | { 85 | return $this->response->getXHeaders(); 86 | } 87 | 88 | /** 89 | * @return array|object|null 90 | */ 91 | public function getLastBody() 92 | { 93 | return $this->response->getBody(); 94 | } 95 | 96 | /** 97 | * Resets the last response cache. 98 | */ 99 | public function resetLastResponse() 100 | { 101 | $this->response = new Response(); 102 | } 103 | 104 | /** 105 | * Make URLs for user browser navigation. 106 | * 107 | * @param string $path 108 | * @param array $parameters 109 | * 110 | * @return string 111 | */ 112 | public function url($path, array $parameters) 113 | { 114 | $this->resetLastResponse(); 115 | $this->response->setApiPath($path); 116 | $query = http_build_query($parameters); 117 | return sprintf('%s/%s?%s', self::API_HOST, $path, $query); 118 | } 119 | 120 | /** 121 | * Make /oauth/* requests to the API. 122 | * 123 | * @param string $path 124 | * @param array $parameters 125 | * 126 | * @return array 127 | * @throws TwitterOAuthException 128 | */ 129 | public function oauth($path, array $parameters = []) 130 | { 131 | $response = []; 132 | $this->resetLastResponse(); 133 | $this->response->setApiPath($path); 134 | $url = sprintf('%s/%s', self::API_HOST, $path); 135 | $result = $this->oAuthRequest($url, 'POST', $parameters); 136 | 137 | if ($this->getLastHttpCode() != 200) { 138 | throw new TwitterOAuthException($result); 139 | } 140 | 141 | parse_str($result, $response); 142 | $this->response->setBody($response); 143 | 144 | return $response; 145 | } 146 | 147 | /** 148 | * Make /oauth2/* requests to the API. 149 | * 150 | * @param string $path 151 | * @param array $parameters 152 | * 153 | * @return array|object 154 | */ 155 | public function oauth2($path, array $parameters = []) 156 | { 157 | $method = 'POST'; 158 | $this->resetLastResponse(); 159 | $this->response->setApiPath($path); 160 | $url = sprintf('%s/%s', self::API_HOST, $path); 161 | $request = Request::fromConsumerAndToken($this->consumer, $this->token, $method, $url, $parameters); 162 | $authorization = 'Authorization: Basic ' . $this->encodeAppAuthorization($this->consumer); 163 | $result = $this->request($request->getNormalizedHttpUrl(), $method, $authorization, $parameters); 164 | $response = JsonDecoder::decode($result, $this->decodeJsonAsArray); 165 | $this->response->setBody($response); 166 | return $response; 167 | } 168 | 169 | /** 170 | * Make GET requests to the API. 171 | * 172 | * @param string $path 173 | * @param array $parameters 174 | * 175 | * @return array|object 176 | */ 177 | public function get($path, array $parameters = []) 178 | { 179 | return $this->http('GET', self::API_HOST, $path, $parameters); 180 | } 181 | 182 | /** 183 | * Make POST requests to the API. 184 | * 185 | * @param string $path 186 | * @param array $parameters 187 | * 188 | * @return array|object 189 | */ 190 | public function post($path, array $parameters = []) 191 | { 192 | return $this->http('POST', self::API_HOST, $path, $parameters); 193 | } 194 | 195 | /** 196 | * Make DELETE requests to the API. 197 | * 198 | * @param string $path 199 | * @param array $parameters 200 | * 201 | * @return array|object 202 | */ 203 | public function delete($path, array $parameters = []) 204 | { 205 | return $this->http('DELETE', self::API_HOST, $path, $parameters); 206 | } 207 | 208 | /** 209 | * Make PUT requests to the API. 210 | * 211 | * @param string $path 212 | * @param array $parameters 213 | * 214 | * @return array|object 215 | */ 216 | public function put($path, array $parameters = []) 217 | { 218 | return $this->http('PUT', self::API_HOST, $path, $parameters); 219 | } 220 | 221 | /** 222 | * Upload media to upload.twitter.com. 223 | * 224 | * @param string $path 225 | * @param array $parameters 226 | * @param boolean $chunked 227 | * 228 | * @return array|object 229 | */ 230 | public function upload($path, array $parameters = [], $chunked = false) 231 | { 232 | if ($chunked) { 233 | return $this->uploadMediaChunked($path, $parameters); 234 | } else { 235 | return $this->uploadMediaNotChunked($path, $parameters); 236 | } 237 | } 238 | 239 | /** 240 | * Private method to upload media (not chunked) to upload.twitter.com. 241 | * 242 | * @param string $path 243 | * @param array $parameters 244 | * 245 | * @return array|object 246 | */ 247 | private function uploadMediaNotChunked($path, $parameters) 248 | { 249 | $file = file_get_contents($parameters['media']); 250 | $base = base64_encode($file); 251 | $parameters['media'] = $base; 252 | return $this->http('POST', self::UPLOAD_HOST, $path, $parameters); 253 | } 254 | 255 | /** 256 | * Private method to upload media (chunked) to upload.twitter.com. 257 | * 258 | * @param string $path 259 | * @param array $parameters 260 | * 261 | * @return array|object 262 | */ 263 | private function uploadMediaChunked($path, $parameters) 264 | { 265 | // Init 266 | $init = $this->http('POST', self::UPLOAD_HOST, $path, [ 267 | 'command' => 'INIT', 268 | 'media_type' => $parameters['media_type'], 269 | 'total_bytes' => filesize($parameters['media']) 270 | ]); 271 | // Append 272 | $segment_index = 0; 273 | $media = fopen($parameters['media'], 'rb'); 274 | while (!feof($media)) 275 | { 276 | $this->http('POST', self::UPLOAD_HOST, 'media/upload', [ 277 | 'command' => 'APPEND', 278 | 'media_id' => $init->media_id_string, 279 | 'segment_index' => $segment_index++, 280 | 'media_data' => base64_encode(fread($media, self::UPLOAD_CHUNK)) 281 | ]); 282 | } 283 | fclose($media); 284 | // Finalize 285 | $finalize = $this->http('POST', self::UPLOAD_HOST, 'media/upload', [ 286 | 'command' => 'FINALIZE', 287 | 'media_id' => $init->media_id_string 288 | ]); 289 | return $finalize; 290 | } 291 | 292 | /** 293 | * @param string $method 294 | * @param string $host 295 | * @param string $path 296 | * @param array $parameters 297 | * 298 | * @return array|object 299 | */ 300 | private function http($method, $host, $path, array $parameters) 301 | { 302 | $this->resetLastResponse(); 303 | $url = sprintf('%s/%s/%s.json', $host, self::API_VERSION, $path); 304 | $this->response->setApiPath($path); 305 | $result = $this->oAuthRequest($url, $method, $parameters); 306 | $response = JsonDecoder::decode($result, $this->decodeJsonAsArray); 307 | $this->response->setBody($response); 308 | return $response; 309 | } 310 | 311 | /** 312 | * Format and sign an OAuth / API request 313 | * 314 | * @param string $url 315 | * @param string $method 316 | * @param array $parameters 317 | * 318 | * @return string 319 | * @throws TwitterOAuthException 320 | */ 321 | private function oAuthRequest($url, $method, array $parameters) 322 | { 323 | $request = Request::fromConsumerAndToken($this->consumer, $this->token, $method, $url, $parameters); 324 | if (array_key_exists('oauth_callback', $parameters)) { 325 | // Twitter doesn't like oauth_callback as a parameter. 326 | unset($parameters['oauth_callback']); 327 | } 328 | if ($this->bearer === null) { 329 | $request->signRequest($this->signatureMethod, $this->consumer, $this->token); 330 | $authorization = $request->toHeader(); 331 | } else { 332 | $authorization = 'Authorization: Bearer ' . $this->bearer; 333 | } 334 | return $this->request($request->getNormalizedHttpUrl(), $method, $authorization, $parameters); 335 | } 336 | 337 | /** 338 | * Make an HTTP request 339 | * 340 | * @param string $url 341 | * @param string $method 342 | * @param string $authorization 343 | * @param array $postfields 344 | * 345 | * @return string 346 | * @throws TwitterOAuthException 347 | */ 348 | private function request($url, $method, $authorization, $postfields) 349 | { 350 | /* Curl settings */ 351 | $options = [ 352 | // CURLOPT_VERBOSE => true, 353 | CURLOPT_CAINFO => __DIR__ . DIRECTORY_SEPARATOR . 'cacert.pem', 354 | CURLOPT_CONNECTTIMEOUT => $this->connectionTimeout, 355 | CURLOPT_HEADER => true, 356 | CURLOPT_HTTPHEADER => ['Accept: application/json', $authorization, 'Expect:'], 357 | CURLOPT_RETURNTRANSFER => true, 358 | CURLOPT_SSL_VERIFYHOST => 2, 359 | CURLOPT_SSL_VERIFYPEER => true, 360 | CURLOPT_TIMEOUT => $this->timeout, 361 | CURLOPT_URL => $url, 362 | CURLOPT_USERAGENT => $this->userAgent, 363 | CURLOPT_ENCODING => 'gzip', 364 | ]; 365 | 366 | if (!empty($this->proxy)) { 367 | $options[CURLOPT_PROXY] = $this->proxy['CURLOPT_PROXY']; 368 | $options[CURLOPT_PROXYUSERPWD] = $this->proxy['CURLOPT_PROXYUSERPWD']; 369 | $options[CURLOPT_PROXYPORT] = $this->proxy['CURLOPT_PROXYPORT']; 370 | $options[CURLOPT_PROXYAUTH] = CURLAUTH_BASIC; 371 | $options[CURLOPT_PROXYTYPE] = CURLPROXY_HTTP; 372 | } 373 | 374 | switch ($method) { 375 | case 'GET': 376 | break; 377 | case 'POST': 378 | $options[CURLOPT_POST] = true; 379 | $options[CURLOPT_POSTFIELDS] = Util::buildHttpQuery($postfields); 380 | break; 381 | case 'DELETE': 382 | $options[CURLOPT_CUSTOMREQUEST] = 'DELETE'; 383 | break; 384 | case 'PUT': 385 | $options[CURLOPT_CUSTOMREQUEST] = 'PUT'; 386 | break; 387 | } 388 | 389 | if (in_array($method, ['GET', 'PUT', 'DELETE']) && !empty($postfields)) { 390 | $options[CURLOPT_URL] .= '?' . Util::buildHttpQuery($postfields); 391 | } 392 | 393 | 394 | $curlHandle = curl_init(); 395 | curl_setopt_array($curlHandle, $options); 396 | $response = curl_exec($curlHandle); 397 | 398 | // Throw exceptions on cURL errors. 399 | if (curl_errno($curlHandle) > 0) { 400 | throw new TwitterOAuthException(curl_error($curlHandle), curl_errno($curlHandle)); 401 | } 402 | 403 | $this->response->setHttpCode(curl_getinfo($curlHandle, CURLINFO_HTTP_CODE)); 404 | $parts = explode("\r\n\r\n", $response); 405 | $responseBody = array_pop($parts); 406 | $responseHeader = array_pop($parts); 407 | $this->response->setHeaders($this->parseHeaders($responseHeader)); 408 | 409 | curl_close($curlHandle); 410 | 411 | return $responseBody; 412 | } 413 | 414 | /** 415 | * Get the header info to store. 416 | * 417 | * @param string $header 418 | * 419 | * @return array 420 | */ 421 | private function parseHeaders($header) 422 | { 423 | $headers = []; 424 | foreach (explode("\r\n", $header) as $line) { 425 | if (strpos($line, ':') !== false) { 426 | list ($key, $value) = explode(': ', $line); 427 | $key = str_replace('-', '_', strtolower($key)); 428 | $headers[$key] = trim($value); 429 | } 430 | } 431 | return $headers; 432 | } 433 | 434 | /** 435 | * Encode application authorization header with base64. 436 | * 437 | * @param Consumer $consumer 438 | * 439 | * @return string 440 | */ 441 | private function encodeAppAuthorization($consumer) 442 | { 443 | // TODO: key and secret should be rfc 1738 encoded 444 | $key = $consumer->key; 445 | $secret = $consumer->secret; 446 | return base64_encode($key . ':' . $secret); 447 | } 448 | } 449 | -------------------------------------------------------------------------------- /twitteroauth/src/TwitterOAuthException.php: -------------------------------------------------------------------------------- 1 | 7 | */ 8 | class TwitterOAuthException extends \Exception 9 | { 10 | } 11 | -------------------------------------------------------------------------------- /twitteroauth/src/Util.php: -------------------------------------------------------------------------------- 1 | array('b','c'), 'd' => 'e') 40 | * 41 | * @param mixed $input 42 | * 43 | * @return array 44 | */ 45 | public static function parseParameters($input) 46 | { 47 | if (!isset($input) || !$input) { 48 | return []; 49 | } 50 | 51 | $pairs = explode('&', $input); 52 | 53 | $parameters = []; 54 | foreach ($pairs as $pair) { 55 | $split = explode('=', $pair, 2); 56 | $parameter = Util::urldecodeRfc3986($split[0]); 57 | $value = isset($split[1]) ? Util::urldecodeRfc3986($split[1]) : ''; 58 | 59 | if (isset($parameters[$parameter])) { 60 | // We have already recieved parameter(s) with this name, so add to the list 61 | // of parameters with this name 62 | 63 | if (is_scalar($parameters[$parameter])) { 64 | // This is the first duplicate, so transform scalar (string) into an array 65 | // so we can add the duplicates 66 | $parameters[$parameter] = [$parameters[$parameter]]; 67 | } 68 | 69 | $parameters[$parameter][] = $value; 70 | } else { 71 | $parameters[$parameter] = $value; 72 | } 73 | } 74 | return $parameters; 75 | } 76 | 77 | /** 78 | * @param $params 79 | * 80 | * @return string 81 | */ 82 | public static function buildHttpQuery($params) 83 | { 84 | if (!$params) { 85 | return ''; 86 | } 87 | 88 | // Urlencode both keys and values 89 | $keys = Util::urlencodeRfc3986(array_keys($params)); 90 | $values = Util::urlencodeRfc3986(array_values($params)); 91 | $params = array_combine($keys, $values); 92 | 93 | // Parameters are sorted by name, using lexicographical byte value ordering. 94 | // Ref: Spec: 9.1.1 (1) 95 | uksort($params, 'strcmp'); 96 | 97 | $pairs = []; 98 | foreach ($params as $parameter => $value) { 99 | if (is_array($value)) { 100 | // If two or more parameters share the same name, they are sorted by their value 101 | // Ref: Spec: 9.1.1 (1) 102 | // June 12th, 2010 - changed to sort because of issue 164 by hidetaka 103 | sort($value, SORT_STRING); 104 | foreach ($value as $duplicateValue) { 105 | $pairs[] = $parameter . '=' . $duplicateValue; 106 | } 107 | } else { 108 | $pairs[] = $parameter . '=' . $value; 109 | } 110 | } 111 | // For each parameter, the name is separated from the corresponding value by an '=' character (ASCII code 61) 112 | // Each name-value pair is separated by an '&' character (ASCII code 38) 113 | return implode('&', $pairs); 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /twitteroauth/src/Util/JsonDecoder.php: -------------------------------------------------------------------------------- 1 | 7 | */ 8 | class JsonDecoder 9 | { 10 | /** 11 | * Decodes a JSON string to stdObject or associative array 12 | * 13 | * @param string $string 14 | * @param bool $asArray 15 | * 16 | * @return array|object 17 | */ 18 | public static function decode($string, $asArray) 19 | { 20 | if (version_compare(PHP_VERSION, '5.4.0', '>=') && !(defined('JSON_C_VERSION') && PHP_INT_SIZE > 4)) { 21 | return json_decode($string, $asArray, 512, JSON_BIGINT_AS_STRING); 22 | } 23 | 24 | return json_decode($string, $asArray); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /urtb.php: -------------------------------------------------------------------------------- 1 | $_GET['monitorFriendlyName'], 18 | "id" => intval($_GET['monitorID']), 19 | "status" => $_GET['alertTypeFriendlyName'], 20 | "url" => $_GET['monitorURL'], 21 | "details" => $_GET['alertDetails'], 22 | "downtime" => 0, 23 | "timestamp" => date($timestampFormat), 24 | "timezone" => $timezone, 25 | ); 26 | 27 | //If there isnt a usable ID just die 28 | if ($alert['id'] === 0) { 29 | die(); 30 | } 31 | 32 | 33 | // Load which hosts are currently down 34 | $currentDown = getCurrentDown(); 35 | 36 | if ($alert['status'] === "Down"){ 37 | // Make sure check isn't already down 38 | if (array_key_exists($alert['id'], $currentDown)) { 39 | error_log("Check got multiple down alerts, doing nothing"); 40 | //die(); 41 | } 42 | // Add the current down check 43 | $currentDown[$alert['id']] = time(); 44 | 45 | } elseif ($alert['status'] === "Up"){ 46 | // Get downtime 47 | $alert['downtime'] = calcTimeDifference($currentDown[$alert['id']]); 48 | 49 | // Now that its up, delete the down record 50 | unset($currentDown[$alert['id']]); 51 | } 52 | // Write which hosts are currently down 53 | writeCurrentDown($currentDown); 54 | 55 | // Generate the message 56 | $message = getMessage($alert); 57 | 58 | // Post message to twitter 59 | postTwitter($message); 60 | 61 | 62 | /** 63 | * Calculates how long the check was down for. I spent way to much time on this function 64 | * @param int $dt What time the check went down at in seconds since epoch 65 | * @return string Properly formated time difference 66 | */ 67 | function calcTimeDifference($dt){ 68 | // Used if there is no downtime record 69 | if (is_null($dt)){ 70 | return ""; 71 | } 72 | 73 | $downDt = new DateTime("@$dt"); 74 | $nowDt = new DateTime(); 75 | $day = $downDt->diff($nowDt)->format('%a'); 76 | $hour = $downDt->diff($nowDt)->format('%h'); 77 | $min = $downDt->diff($nowDt)->format('%i'); 78 | $sec = $downDt->diff($nowDt)->format('%s'); 79 | $downTime = ""; 80 | 81 | if ($day == 1){ 82 | $downTime .= "1 Day, "; 83 | } elseif ($day > 1){ 84 | $downTime .= "$day Days, "; 85 | } 86 | 87 | if ($hour == 1){ 88 | $downTime .= "1 Hour, "; 89 | } elseif ($hour > 1){ 90 | $downTime .= "$hour Hours, "; 91 | } 92 | 93 | if ($min == 1){ 94 | $downTime .= "1 Minute, "; 95 | } elseif ($min > 1){ 96 | $downTime .= "$min Minutes, "; 97 | } 98 | 99 | if ($sec == 1){ 100 | $downTime .= "1 Second"; 101 | } elseif ($sec > 1){ 102 | $downTime .= "$sec Seconds"; 103 | } 104 | 105 | // Remove last , and space if present 106 | $downTime = rtrim($downTime, ', '); 107 | 108 | // Removes the last , and space and makes it into the word and 109 | $lastPos = strrpos($downTime, ', '); 110 | if ($lastPos != false){ 111 | $downTime = substr_replace($downTime, " and ", $lastPos, 2); 112 | } 113 | 114 | return $downTime; 115 | } 116 | 117 | /** 118 | * Posts the message to twitter 119 | * @param string $message The message to post to twitter 120 | */ 121 | function postTwitter($message){ 122 | global $twitterConfig; 123 | $connection = new TwitterOAuth($twitterConfig['consumerKey'], $twitterConfig['consumerSecret'], $twitterConfig['accessToken'], $twitterConfig['accessTokenSecret']); 124 | $statues = $connection->post("statuses/update", ["status" => $message]); 125 | print_r($statues); 126 | } 127 | 128 | /** 129 | * Creates a properly formated message 130 | * @param mixed[] $alert Current info about the alert called 131 | * @return string Properly formated message 132 | */ 133 | function getMessage($alert){ 134 | global $messages; 135 | 136 | $variableRep = array( 137 | 'variable' => array('{{host}}', '{{id}}', '{{status}}', '{{url}}', '{{details}}', '{{downtime}}', '{{timestamp}}', '{{timezone}}'), 138 | 'replacement' => array($alert['host'], $alert['id'], $alert['status'], $alert['url'], $alert['details'], $alert['downtime'], $alert['timestamp'], $alert['timezone']), 139 | ); 140 | if ($alert['status'] === "Down"){ 141 | return str_replace($variableRep['variable'], $variableRep['replacement'], $messages['downMessage']); 142 | } elseif ($alert['status'] === "Up") { 143 | if ($alert['downtime'] === ""){ 144 | return str_replace($variableRep['variable'], $variableRep['replacement'], $messages['upMessageNoDown']); 145 | } 146 | return str_replace($variableRep['variable'], $variableRep['replacement'], $messages['upMessage']); 147 | } 148 | 149 | } 150 | 151 | /** 152 | * Reads what checks are currently down from the file 153 | * @return mixed[] $currentDown Array of checks and the time they went down 154 | */ 155 | function getCurrentDown(){ 156 | global $cacheFile; 157 | $file = file_get_contents("./$cacheFile"); 158 | if ($file === false){ 159 | // Try and create file with empty array 160 | if (file_put_contents("./$cacheFile", serialize(array())) === false){ 161 | error_log("Not able to write cache file. Manually create and make sure permissions are correct"); 162 | die(); 163 | } 164 | // Reget the file contents 165 | $file = file_get_contents("./$cacheFile"); 166 | } 167 | return unserialize($file); 168 | } 169 | 170 | /** 171 | * Writes which checks are currently down to a file 172 | * @param mixed[] $currentDown Array of checks and the time they went down 173 | */ 174 | function writeCurrentDown($currentDown){ 175 | global $cacheFile; 176 | if (file_put_contents("./$cacheFile", serialize($currentDown)) === false){ 177 | error_log("Not able to write cache file. Manually create and make sure permissions are correct"); 178 | die(); 179 | } 180 | } 181 | 182 | /** 183 | * Verifies that the request came from uptimeRobot 184 | * @return bool true if the request came from uptime robot, false if it did not 185 | */ 186 | function verifyUptimeRobot(){ 187 | global $debug, $uptimeRobotIps, $userAgentVerify; 188 | 189 | // Useful for local debugging 190 | if ($debug){ 191 | return true; 192 | } 193 | 194 | // Make sure useragent string matches 195 | if (strpos($_SERVER['HTTP_USER_AGENT'], $userAgentVerify) === false){ 196 | return false; 197 | } 198 | 199 | // Make sure IPs are from uptimerobot 200 | if (in_array($_SERVER['REMOTE_ADDR'], $uptimeRobotIps) === false){ 201 | return false; 202 | } 203 | 204 | return true; 205 | } 206 | --------------------------------------------------------------------------------