├── Akismet.php ├── Exception.php ├── LICENSE.md └── composer.json /Akismet.php: -------------------------------------------------------------------------------- 1 | 8 | * @version 1.1.0 9 | * @copyright Copyright (c) Tijs Verkoyen. All rights reserved. 10 | * @license BSD License 11 | */ 12 | class Akismet 13 | { 14 | // internal constant to enable/disable debugging 15 | const DEBUG = false; 16 | 17 | // url for the api 18 | const API_URL = 'http://rest.akismet.com'; 19 | 20 | // port for the api 21 | const API_PORT = 80; 22 | 23 | // version of the api 24 | const API_VERSION = '1.1'; 25 | 26 | // current version 27 | const VERSION = '1.1.0'; 28 | 29 | /** 30 | * The key for the API 31 | * @var string 32 | */ 33 | private $apiKey; 34 | 35 | /** 36 | * The timeout 37 | * @var int 38 | */ 39 | private $timeOut = 60; 40 | 41 | /** 42 | * The user agent 43 | * @var string 44 | */ 45 | private $userAgent; 46 | 47 | /** 48 | * The url 49 | * @var string 50 | */ 51 | private $url; 52 | 53 | // class methods 54 | /** 55 | * Default constructor 56 | * Creates an instance of the Akismet Class. 57 | * 58 | * @param string $apiKey API key being verified for use with the API. 59 | * @param string $url The front page or home URL of the instance making 60 | * the request. For a blog or wiki this would be the 61 | * front page. Note: Must be a full URI, including 62 | * http://. 63 | */ 64 | public function __construct($apiKey, $url) 65 | { 66 | $this->setApiKey($apiKey); 67 | $this->setUrl($url); 68 | } 69 | 70 | /** 71 | * Make the call 72 | * @param string $url URL to call. 73 | * @param array[optional] $aParameters The parameters to pass. 74 | * @param bool[optional] $authenticate Should we authenticate? 75 | * @return string 76 | */ 77 | private function doCall($url, $aParameters = array(), $authenticate = true) 78 | { 79 | // redefine 80 | $url = (string) $url; 81 | $aParameters = (array) $aParameters; 82 | $authenticate = (bool) $authenticate; 83 | 84 | // build url 85 | $url = self::API_URL . '/' . self::API_VERSION . '/' . $url; 86 | 87 | // add key in front of url 88 | if ($authenticate) { 89 | // get api key 90 | $apiKey = $this->getApiKey(); 91 | 92 | // validate apiKey 93 | if ($apiKey == '') throw new Exception('Invalid API-key'); 94 | 95 | // prepend key 96 | $url = str_replace('http://', 'http://' . $apiKey . '.', $url); 97 | } 98 | 99 | // add url into the parameters 100 | $aParameters['blog'] = $this->getUrl(); 101 | 102 | // set options 103 | $options[CURLOPT_URL] = $url; 104 | $options[CURLOPT_PORT] = self::API_PORT; 105 | $options[CURLOPT_USERAGENT] = $this->getUserAgent(); 106 | if (ini_get('open_basedir') == '' && ini_get('safe_mode' == 'Off')) { 107 | $options[CURLOPT_FOLLOWLOCATION] = true; 108 | } 109 | $options[CURLOPT_RETURNTRANSFER] = true; 110 | $options[CURLOPT_TIMEOUT] = (int) $this->getTimeOut(); 111 | $options[CURLOPT_POST] = true; 112 | $options[CURLOPT_POSTFIELDS] = $aParameters; 113 | 114 | // speed up things, use HTTP 1.0 115 | $options[CURLOPT_HTTP_VERSION] = CURL_HTTP_VERSION_1_0; 116 | 117 | // init 118 | $curl = curl_init(); 119 | 120 | // set options 121 | curl_setopt_array($curl, $options); 122 | 123 | // execute 124 | $response = curl_exec($curl); 125 | $headers = curl_getinfo($curl); 126 | 127 | // fetch errors 128 | $errorNumber = curl_errno($curl); 129 | $errorMessage = curl_error($curl); 130 | 131 | // close 132 | curl_close($curl); 133 | 134 | // invalid headers 135 | if (!in_array($headers['http_code'], array(0, 200))) { 136 | // should we provide debug information 137 | if (self::DEBUG) { 138 | // make it output proper 139 | echo '
';
140 | 
141 |                 // dump the header-information
142 |                 var_dump($headers);
143 | 
144 |                 // dump the raw response
145 |                 var_dump($response);
146 | 
147 |                 // end proper format
148 |                 echo '
'; 149 | 150 | // stop the script 151 | exit(); 152 | } 153 | 154 | // throw error 155 | throw new Exception(null, (int) $headers['http_code']); 156 | } 157 | 158 | // error? 159 | if ((int) $errorNumber > 0) { 160 | throw new Exception($errorMessage, $errorNumber); 161 | } 162 | 163 | // return 164 | return $response; 165 | } 166 | 167 | /** 168 | * Get the API-key that will be used 169 | * 170 | * @return string 171 | */ 172 | private function getApiKey() 173 | { 174 | return (string) $this->apiKey; 175 | } 176 | 177 | /** 178 | * Get the timeout that will be used 179 | * 180 | * @return int 181 | */ 182 | public function getTimeOut() 183 | { 184 | return (int) $this->timeOut; 185 | } 186 | 187 | /** 188 | * Get the url of the instance making the request 189 | * 190 | * @return string 191 | */ 192 | public function getUrl() 193 | { 194 | return (string) $this->url; 195 | } 196 | 197 | /** 198 | * Get the useragent that will be used. 199 | * Our version will be prepended to yours. It will look like: 200 | * "PHP Akismet/ " 201 | * 202 | * @return string 203 | */ 204 | public function getUserAgent() 205 | { 206 | return (string) 'PHP Akismet/' . self::VERSION . ' ' . $this->userAgent; 207 | } 208 | 209 | /** 210 | * Set API key that has to be used 211 | * 212 | * @param string $apiKey API key to use. 213 | */ 214 | private function setApiKey($apiKey) 215 | { 216 | $this->apiKey = (string) $apiKey; 217 | } 218 | 219 | /** 220 | * Set the timeout 221 | * After this time the request will stop. You should handle any errors 222 | * triggered by this. 223 | * 224 | * @param int $seconds The timeout in seconds. 225 | */ 226 | public function setTimeOut($seconds) 227 | { 228 | $this->timeOut = (int) $seconds; 229 | } 230 | 231 | /** 232 | * Set the url of the instance making the request 233 | * @param string $url The URL making the request. 234 | */ 235 | private function setUrl($url) 236 | { 237 | $this->url = (string) $url; 238 | } 239 | 240 | /** 241 | * Set the user-agent for you application 242 | * It will be appended to ours, the result will look like: 243 | * "PHP Akismet/ " 244 | * 245 | * @param string $userAgent The user-agent, it should look like: 246 | * /. 247 | */ 248 | public function setUserAgent($userAgent) 249 | { 250 | $this->userAgent = (string) $userAgent; 251 | } 252 | 253 | // api methods 254 | /** 255 | * Verifies the key 256 | * @return bool if the key is valid it will return true, otherwise false 257 | * will be returned. 258 | */ 259 | public function verifyKey() 260 | { 261 | // possible answers 262 | $aPossibleResponses = array('valid', 'invalid'); 263 | 264 | // build parameters 265 | $aParameters['key'] = $this->getApiKey(); 266 | 267 | // make the call 268 | $response = $this->doCall('verify-key', $aParameters, false); 269 | 270 | // validate response 271 | if (!in_array($response, $aPossibleResponses)) { 272 | throw new Exception($response, 400); 273 | } 274 | 275 | // valid key 276 | if ($response == 'valid') return true; 277 | 278 | // fallback 279 | return false; 280 | } 281 | 282 | /** 283 | * Check if the comment is spam or not 284 | * This is basically the core of everything. This call takes a number of 285 | * arguments and characteristics about the submitted content and then 286 | * returns a thumbs up or thumbs down. 287 | * Almost everything is optional, but performance can drop dramatically if 288 | * you exclude certain elements. 289 | * REMARK: If you are having trouble triggering you can send 290 | * "viagra-test-123" as the author and it will trigger a true response, 291 | * always. 292 | * 293 | * @param string[optional] $content The content that was submitted. 294 | * @param string[optional] $author The name. 295 | * @param string[optional] $email The email address. 296 | * @param string[optional] $url The URL. 297 | * @param string[optional] $permalink The permanent location of the entry 298 | * the comment was submitted to. 299 | * @param string[optional] $type The type, can be blank, comment, 300 | * trackback, pingback, or a made up 301 | * value like "registration". 302 | * @return bool If the comment is spam true will be 303 | * returned, otherwise false. 304 | */ 305 | public function isSpam( 306 | $content, 307 | $author = null, 308 | $email = null, 309 | $url = null, 310 | $permalink = null, 311 | $type = null 312 | ) 313 | { 314 | // possible answers 315 | $aPossibleResponses = array('true', 'false'); 316 | 317 | // redefine 318 | $content = (string) $content; 319 | $author = (string) $author; 320 | $email = (string) $email; 321 | $url = (string) $url; 322 | $permalink = (string) $permalink; 323 | $type = (string) $type; 324 | 325 | // get stuff from the $_SERVER-array 326 | if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) { 327 | $ip = $_SERVER['HTTP_X_FORWARDED_FOR']; 328 | } elseif (isset($_SERVER['REMOTE_ADDR'])) { 329 | $ip = $_SERVER['REMOTE_ADDR']; 330 | } else $ip = ''; 331 | if (isset($_SERVER['HTTP_USER_AGENT'])) { 332 | $userAgent = (string) $_SERVER['HTTP_USER_AGENT']; 333 | } else $userAgent = ''; 334 | if (isset($_SERVER['HTTP_REFERER'])) { 335 | $referrer = (string) $_SERVER['HTTP_REFERER']; 336 | } else $referrer = ''; 337 | 338 | // build parameters 339 | $aParameters['user_ip'] = $ip; 340 | $aParameters['user_agent'] = $userAgent; 341 | if ($referrer != '') $aParameters['referrer'] = $referrer; 342 | if ($permalink != '') $aParameters['permalink'] = $permalink; 343 | if ($type != '') $aParameters['comment_type'] = $type; 344 | if ($author != '') $aParameters['comment_author'] = $author; 345 | if ($email != '') $aParameters['comment_author_email'] = $email; 346 | if ($url != '') $aParameters['comment_author_url'] = $url; 347 | $aParameters['comment_content'] = $content; 348 | 349 | // add all stuff from $_SERVER 350 | foreach ($_SERVER as $key => $value) { 351 | // keys to ignore 352 | $aKeysToIgnore = array( 353 | 'HTTP_COOKIE', 'HTTP_X_FORWARDED_FOR', 'HTTP_X_FORWARDED_HOST', 354 | 'HTTP_MAX_FORWARDS', 'HTTP_X_FORWARDED_SERVER', 355 | 'REDIRECT_STATUS', 'SERVER_PORT', 'PATH', 'DOCUMENT_ROOT', 356 | 'SERVER_ADMIN', 'QUERY_STRING', 'PHP_SELF', 'argv', 'argc', 357 | 'SCRIPT_FILENAME', 'SCRIPT_NAME' 358 | ); 359 | 360 | // add to parameters if not in ignore list 361 | if (!in_array($key, $aKeysToIgnore)) $aParameters[$key] = $value; 362 | } 363 | 364 | // make the call 365 | $response = $this->doCall('comment-check', $aParameters); 366 | 367 | // validate response 368 | if (!in_array($response, $aPossibleResponses)) { 369 | throw new Exception($response, 400); 370 | } 371 | 372 | // process response 373 | if ($response == 'true') return true; 374 | 375 | // fallback 376 | return false; 377 | } 378 | 379 | /** 380 | * Submit ham to Akismet 381 | * This call is intended for the marking of false positives, things that 382 | * were incorrectly marked as spam. 383 | * @param string $userIp The address of the comment submitter. 384 | * @param string $userAgent The agent information. 385 | * @param string[optional] $content The content that was submitted. 386 | * @param string[optional] $author The name of the author. 387 | * @param string[optional] $email The email address. 388 | * @param string[optional] $url The URL. 389 | * @param string[optional] $permalink The permanent location of the entry 390 | * the comment was submitted to. 391 | * @param string[optional] $type The type, can be blank, comment, 392 | * trackback, pingback, or a made up 393 | * value like "registration". 394 | * @param string[optional] $referrer The content of the HTTP_REFERER 395 | * header should be sent here. 396 | * @param array[optional] $others Extra data (the variables from 397 | * $_SERVER). 398 | * @return bool If everything went fine true will be 399 | * returned, otherwise an exception 400 | * will be triggered. 401 | */ 402 | public function submitHam( 403 | $userIp, 404 | $userAgent, 405 | $content, 406 | $author = null, 407 | $email = null, 408 | $url = null, 409 | $permalink = null, 410 | $type = null, 411 | $referrer = null, 412 | $others = null 413 | ) 414 | { 415 | // possible answers 416 | $aPossibleResponses = array('Thanks for making the web a better place.'); 417 | 418 | // redefine 419 | $userIp = (string) $userIp; 420 | $userAgent = (string) $userAgent; 421 | $content = (string) $content; 422 | $author = (string) $author; 423 | $email = (string) $email; 424 | $url = (string) $url; 425 | $permalink = (string) $permalink; 426 | $type = (string) $type; 427 | $referrer = (string) $referrer; 428 | $others = (array) $others; 429 | 430 | // build parameters 431 | $aParameters['user_ip'] = $userIp; 432 | $aParameters['user_agent'] = $userAgent; 433 | if ($referrer != '') $aParameters['referrer'] = $referrer; 434 | if ($permalink != '') $aParameters['permalink'] = $permalink; 435 | if ($type != '') $aParameters['comment_type'] = $type; 436 | if ($author != '') $aParameters['comment_author'] = $author; 437 | if ($email != '') $aParameters['comment_author_email'] = $email; 438 | if ($url != '') $aParameters['comment_author_url'] = $url; 439 | $aParameters['comment_content'] = $content; 440 | 441 | // add other parameters 442 | foreach ($others as $key => $value) $aParameters[$key] = $value; 443 | 444 | // make the call 445 | $response = $this->doCall('submit-ham', $aParameters); 446 | 447 | // validate response 448 | if (in_array($response, $aPossibleResponses)) return true; 449 | 450 | // fallback 451 | throw new Exception($response); 452 | } 453 | 454 | /** 455 | * Submit spam to Akismet 456 | * This call is for submitting comments that weren't marked as spam but 457 | * should have been. 458 | * @param string $userIp The address of the comment submitter. 459 | * @param string $userAgent The agent information. 460 | * @param string[optional] $content The content that was submitted. 461 | * @param string[optional] $author The name of the author. 462 | * @param string[optional] $email The email address. 463 | * @param string[optional] $url The URL. 464 | * @param string[optional] $permalink The permanent location of the entry 465 | * the comment was submitted to. 466 | * @param string[optional] $type The type, can be blank, comment, 467 | * trackback, pingback, or a made up 468 | * value like "registration". 469 | * @param string[optional] $referrer The content of the HTTP_REFERER 470 | * header should be sent here. 471 | * @param array[optional] $others Extra data (the variables from 472 | * $_SERVER). 473 | * @return bool If everything went fine true will be 474 | * returned, otherwise an exception 475 | * will be triggered. 476 | */ 477 | public function submitSpam( 478 | $userIp, 479 | $userAgent, 480 | $content, 481 | $author = null, 482 | $email = null, 483 | $url = null, 484 | $permalink = null, 485 | $type = null, 486 | $referrer = null, 487 | $others = null 488 | ) 489 | { 490 | // possible answers 491 | $aPossibleResponses = array('Thanks for making the web a better place.'); 492 | 493 | // redefine 494 | $userIp = (string) $userIp; 495 | $userAgent = (string) $userAgent; 496 | $content = (string) $content; 497 | $author = (string) $author; 498 | $email = (string) $email; 499 | $url = (string) $url; 500 | $permalink = (string) $permalink; 501 | $type = (string) $type; 502 | $referrer = (string) $referrer; 503 | $others = (array) $others; 504 | 505 | // build parameters 506 | $aParameters['user_ip'] = $userIp; 507 | $aParameters['user_agent'] = $userAgent; 508 | if ($referrer != '') $aParameters['referrer'] = $referrer; 509 | if ($permalink != '') $aParameters['permalink'] = $permalink; 510 | if ($type != '') $aParameters['comment_type'] = $type; 511 | if ($author != '') $aParameters['comment_author'] = $author; 512 | if ($email != '') $aParameters['comment_author_email'] = $email; 513 | if ($url != '') $aParameters['comment_author_url'] = $url; 514 | $aParameters['comment_content'] = $content; 515 | 516 | // add other parameters 517 | foreach ($others as $key => $value) $aParameters[$key] = $value; 518 | 519 | // make the call 520 | $response = $this->doCall('submit-spam', $aParameters); 521 | 522 | // validate response 523 | if (in_array($response, $aPossibleResponses)) return true; 524 | 525 | // fallback 526 | throw new Exception($response); 527 | } 528 | } 529 | -------------------------------------------------------------------------------- /Exception.php: -------------------------------------------------------------------------------- 1 | 8 | */ 9 | class Exception extends \Exception 10 | { 11 | /** 12 | * Http header-codes 13 | * 14 | * @var array 15 | */ 16 | private $aStatusCodes = array( 17 | 100 => 'Continue', 18 | 101 => 'Switching Protocols', 19 | 200 => 'OK', 20 | 201 => 'Created', 21 | 202 => 'Accepted', 22 | 203 => 'Non-Authoritative Information', 23 | 204 => 'No Content', 24 | 205 => 'Reset Content', 25 | 206 => 'Partial Content', 26 | 300 => 'Multiple Choices', 27 | 301 => 'Moved Permanently', 28 | 301 => 'Status code is received in response to a request other than GET or HEAD, the user agent MUST NOT automatically redirect the request unless it can be confirmed by the user, since this might change the conditions under which the request was issued.', 29 | 302 => 'Found', 30 | 302 => 'Status code is received in response to a request other than GET or HEAD, the user agent MUST NOT automatically redirect the request unless it can be confirmed by the user, since this might change the conditions under which the request was issued.', 31 | 303 => 'See Other', 32 | 304 => 'Not Modified', 33 | 305 => 'Use Proxy', 34 | 306 => '(Unused)', 35 | 307 => 'Temporary Redirect', 36 | 400 => 'Bad Request', 37 | 401 => 'Unauthorized', 38 | 402 => 'Payment Required', 39 | 403 => 'Forbidden', 40 | 404 => 'Not Found', 41 | 405 => 'Method Not Allowed', 42 | 406 => 'Not Acceptable', 43 | 407 => 'Proxy Authentication Required', 44 | 408 => 'Request Timeout', 45 | 409 => 'Conflict', 46 | 411 => 'Length Required', 47 | 412 => 'Precondition Failed', 48 | 413 => 'Request Entity Too Large', 49 | 414 => 'Request-URI Too Long', 50 | 415 => 'Unsupported Media Type', 51 | 416 => 'Requested Range Not Satisfiable', 52 | 417 => 'Expectation Failed', 53 | 500 => 'Internal Server Error', 54 | 501 => 'Not Implemented', 55 | 502 => 'Bad Gateway', 56 | 503 => 'Service Unavailable', 57 | 504 => 'Gateway Timeout', 58 | 505 => 'HTTP Version Not Supported' 59 | ); 60 | 61 | /** 62 | * Default constructor 63 | * 64 | * @param $message string[optional] message. 65 | * @param $code int[optional] error number. 66 | */ 67 | public function __construct($message = null, $code = null) 68 | { 69 | // set message 70 | if ($message === null && isset($this->aStatusCodes[(int) $code])) { 71 | $message = $this->aStatusCodes[(int) $code]; 72 | } 73 | 74 | // call parent 75 | parent::__construct((string) $message, $code); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright (c) Tijs Verkoyen. All rights reserved. 2 | Redistribution and use in source and binary forms, with or without 3 | modification, are permitted provided that the following conditions are met: 4 | 5 | 1. Redistributions of source code must retain the above copyright notice, this 6 | list of conditions and the following disclaimer. 7 | 2. Redistributions in binary form must reproduce the above copyright notice, 8 | this list of conditions and the following disclaimer in the documentation 9 | and/or other materials provided with the distribution. 10 | 3. The name of the author may not be used to endorse or promote products 11 | derived from this software without specific prior written permission. 12 | 13 | This software is provided by the author "as is" and any express or implied 14 | warranties, including, but not limited to, the implied warranties of 15 | merchantability and fitness for a particular purpose are disclaimed. In no event 16 | shall the author be liable for any direct, indirect, incidental, special, 17 | exemplary, or consequential damages (including, but not limited to, procurement 18 | of substitute goods or services; loss of use, data, or profits; or business 19 | interruption) however caused and on any theory of liability, whether in 20 | contract, strict liability, or tort (including negligence or otherwise) arising 21 | in any way out of the use of this software, even if advised of the possibility 22 | of such damage. -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tijsverkoyen/akismet", 3 | "type": "library", 4 | "description": "Akismet is a wrapper-class to communicate with the Akismet API.", 5 | "homepage": "https://github.com/tijsverkoyen/Akismet", 6 | "license": "BSD", 7 | "authors": [ 8 | { 9 | "name": "Tijs Verkoyen", 10 | "email": "akismet@verkoyen.eu", 11 | "role": "Developer" 12 | } 13 | ], 14 | "require": { 15 | "php": ">=5.2.0", 16 | "ext-curl": "*" 17 | }, 18 | "autoload": { 19 | "classmap": [""] 20 | } 21 | } --------------------------------------------------------------------------------