KXStudio Website https://kx.studio/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

Akismet.php 10KB

9 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342
  1. <?php
  2. /**
  3. * Akismet anti-comment spam service
  4. *
  5. * @package akismet
  6. * @name Akismet
  7. * @author Alex Potsides
  8. * @link http://www.achingbrain.net/
  9. * @version 0.4
  10. * @copyright Alex Potsides
  11. * @license http://www.opensource.org/licenses/bsd-license.php BSD License
  12. */
  13. class Akismet
  14. {
  15. private $version = '0.4';
  16. private $wordPressAPIKey;
  17. private $blogURL;
  18. private $comment;
  19. private $apiPort;
  20. private $akismetServer;
  21. private $akismetVersion;
  22. // This prevents some potentially sensitive information from being sent accross the wire.
  23. private $ignore = array('HTTP_COOKIE',
  24. 'HTTP_X_FORWARDED_FOR',
  25. 'HTTP_X_FORWARDED_HOST',
  26. 'HTTP_MAX_FORWARDS',
  27. 'HTTP_X_FORWARDED_SERVER',
  28. 'REDIRECT_STATUS',
  29. 'SERVER_PORT',
  30. 'PATH',
  31. 'DOCUMENT_ROOT',
  32. 'SERVER_ADMIN',
  33. 'QUERY_STRING',
  34. 'PHP_SELF' );
  35. /**
  36. * @param string $blogURL The URL of your blog.
  37. * @param string $wordPressAPIKey WordPress API key.
  38. */
  39. public function __construct($blogURL, $wordPressAPIKey) {
  40. $this->blogURL = $blogURL;
  41. $this->wordPressAPIKey = $wordPressAPIKey;
  42. // Set some default values
  43. $this->apiPort = 80;
  44. $this->akismetServer = 'rest.akismet.com';
  45. $this->akismetVersion = '1.1';
  46. // Start to populate the comment data
  47. $this->comment['blog'] = $blogURL;
  48. $this->comment['user_agent'] = $_SERVER['HTTP_USER_AGENT'];
  49. if(isset($_SERVER['HTTP_REFERER'])) {
  50. $this->comment['referrer'] = $_SERVER['HTTP_REFERER'];
  51. }
  52. /*
  53. * This is necessary if the server PHP5 is running on has been set up to run PHP4 and
  54. * PHP5 concurently and is actually running through a separate proxy al a these instructions:
  55. * http://www.schlitt.info/applications/blog/archives/83_How_to_run_PHP4_and_PHP_5_parallel.html
  56. * and http://wiki.coggeshall.org/37.html
  57. * Otherwise the user_ip appears as the IP address of the PHP4 server passing the requests to the
  58. * PHP5 one...
  59. */
  60. $this->comment['user_ip'] = $_SERVER['REMOTE_ADDR'] != getenv('SERVER_ADDR') ? $_SERVER['REMOTE_ADDR'] : getenv('HTTP_X_FORWARDED_FOR');
  61. }
  62. /**
  63. * Makes a request to the Akismet service to see if the API key passed to the constructor is valid.
  64. *
  65. * Use this method if you suspect your API key is invalid.
  66. *
  67. * @return bool True is if the key is valid, false if not.
  68. */
  69. public function isKeyValid() {
  70. // Check to see if the key is valid
  71. $response = $this->sendRequest('key=' . $this->wordPressAPIKey . '&blog=' . $this->blogURL, $this->akismetServer, '/' . $this->akismetVersion . '/verify-key');
  72. return $response[1] == 'valid';
  73. }
  74. // makes a request to the Akismet service
  75. private function sendRequest($request, $host, $path) {
  76. $http_request = "POST " . $path . " HTTP/1.0\r\n";
  77. $http_request .= "Host: " . $host . "\r\n";
  78. $http_request .= "Content-Type: application/x-www-form-urlencoded; charset=utf-8\r\n";
  79. $http_request .= "Content-Length: " . strlen($request) . "\r\n";
  80. $http_request .= "User-Agent: Akismet PHP5 Class " . $this->version . " | Akismet/1.11\r\n";
  81. $http_request .= "\r\n";
  82. $http_request .= $request;
  83. $socketWriteRead = new SocketWriteRead($host, $this->apiPort, $http_request);
  84. $socketWriteRead->send();
  85. return explode("\r\n\r\n", $socketWriteRead->getResponse(), 2);
  86. }
  87. // Formats the data for transmission
  88. private function getQueryString() {
  89. foreach($_SERVER as $key => $value) {
  90. if(!in_array($key, $this->ignore)) {
  91. if($key == 'REMOTE_ADDR') {
  92. $this->comment[$key] = $this->comment['user_ip'];
  93. } else {
  94. $this->comment[$key] = $value;
  95. }
  96. }
  97. }
  98. $query_string = '';
  99. foreach($this->comment as $key => $data) {
  100. if(!is_array($data)) {
  101. $query_string .= $key . '=' . urlencode(stripslashes($data)) . '&';
  102. }
  103. }
  104. return $query_string;
  105. }
  106. /**
  107. * Tests for spam.
  108. *
  109. * Uses the web service provided by {@link http://www.akismet.com Akismet} to see whether or not the submitted comment is spam. Returns a boolean value.
  110. *
  111. * @return bool True if the comment is spam, false if not
  112. * @throws Will throw an exception if the API key passed to the constructor is invalid.
  113. */
  114. public function isCommentSpam() {
  115. $response = $this->sendRequest($this->getQueryString(), $this->wordPressAPIKey . "." . $this->akismetServer, '/' . $this->akismetVersion . '/comment-check');
  116. if($response[1] == 'invalid' && !$this->isKeyValid()) {
  117. throw new exception('The Wordpress API key passed to the Akismet constructor is invalid. Please obtain a valid one from http://wordpress.com/api-keys/');
  118. }
  119. return ($response[1] == 'true');
  120. }
  121. /**
  122. * Submit spam that is incorrectly tagged as ham.
  123. *
  124. * Using this function will make you a good citizen as it helps Akismet to learn from its mistakes. This will improve the service for everybody.
  125. */
  126. public function submitSpam() {
  127. $this->sendRequest($this->getQueryString(), $this->wordPressAPIKey . '.' . $this->akismetServer, '/' . $this->akismetVersion . '/submit-spam');
  128. }
  129. /**
  130. * Submit ham that is incorrectly tagged as spam.
  131. *
  132. * Using this function will make you a good citizen as it helps Akismet to learn from its mistakes. This will improve the service for everybody.
  133. */
  134. public function submitHam() {
  135. $this->sendRequest($this->getQueryString(), $this->wordPressAPIKey . '.' . $this->akismetServer, '/' . $this->akismetVersion . '/submit-ham');
  136. }
  137. /**
  138. * To override the user IP address when submitting spam/ham later on
  139. *
  140. * @param string $userip An IP address. Optional.
  141. */
  142. public function setUserIP($userip) {
  143. $this->comment['user_ip'] = $userip;
  144. }
  145. /**
  146. * To override the referring page when submitting spam/ham later on
  147. *
  148. * @param string $referrer The referring page. Optional.
  149. */
  150. public function setReferrer($referrer) {
  151. $this->comment['referrer'] = $referrer;
  152. }
  153. /**
  154. * A permanent URL referencing the blog post the comment was submitted to.
  155. *
  156. * @param string $permalink The URL. Optional.
  157. */
  158. public function setPermalink($permalink) {
  159. $this->comment['permalink'] = $permalink;
  160. }
  161. /**
  162. * The type of comment being submitted.
  163. *
  164. * May be blank, comment, trackback, pingback, or a made up value like "registration" or "wiki".
  165. */
  166. public function setCommentType($commentType) {
  167. $this->comment['comment_type'] = $commentType;
  168. }
  169. /**
  170. * The name that the author submitted with the comment.
  171. */
  172. public function setCommentAuthor($commentAuthor) {
  173. $this->comment['comment_author'] = $commentAuthor;
  174. }
  175. /**
  176. * The email address that the author submitted with the comment.
  177. *
  178. * The address is assumed to be valid.
  179. */
  180. public function setCommentAuthorEmail($authorEmail) {
  181. $this->comment['comment_author_email'] = $authorEmail;
  182. }
  183. /**
  184. * The URL that the author submitted with the comment.
  185. */
  186. public function setCommentAuthorURL($authorURL) {
  187. $this->comment['comment_author_url'] = $authorURL;
  188. }
  189. /**
  190. * The comment's body text.
  191. */
  192. public function setCommentContent($commentBody) {
  193. $this->comment['comment_content'] = $commentBody;
  194. }
  195. /**
  196. * Defaults to 80
  197. */
  198. public function setAPIPort($apiPort) {
  199. $this->apiPort = $apiPort;
  200. }
  201. /**
  202. * Defaults to rest.akismet.com
  203. */
  204. public function setAkismetServer($akismetServer) {
  205. $this->akismetServer = $akismetServer;
  206. }
  207. /**
  208. * Defaults to '1.1'
  209. */
  210. public function setAkismetVersion($akismetVersion) {
  211. $this->akismetVersion = $akismetVersion;
  212. }
  213. }
  214. /**
  215. * Utility class used by Akismet
  216. *
  217. * This class is used by Akismet to do the actual sending and receiving of data. It opens a connection to a remote host, sends some data and the reads the response and makes it available to the calling program.
  218. *
  219. * The code that makes up this class originates in the Akismet WordPress plugin, which is {@link http://akismet.com/download/ available on the Akismet website}.
  220. *
  221. * N.B. It is not necessary to call this class directly to use the Akismet class. This is included here mainly out of a sense of completeness.
  222. *
  223. * @package akismet
  224. * @name SocketWriteRead
  225. * @version 0.1
  226. * @author Alex Potsides
  227. * @link http://www.achingbrain.net/
  228. */
  229. class SocketWriteRead {
  230. private $host;
  231. private $port;
  232. private $request;
  233. private $response;
  234. private $responseLength;
  235. private $errorNumber;
  236. private $errorString;
  237. /**
  238. * @param string $host The host to send/receive data.
  239. * @param int $port The port on the remote host.
  240. * @param string $request The data to send.
  241. * @param int $responseLength The amount of data to read. Defaults to 1160 bytes.
  242. */
  243. public function __construct($host, $port, $request, $responseLength = 1160) {
  244. $this->host = $host;
  245. $this->port = $port;
  246. $this->request = $request;
  247. $this->responseLength = $responseLength;
  248. $this->errorNumber = 0;
  249. $this->errorString = '';
  250. }
  251. /**
  252. * Sends the data to the remote host.
  253. *
  254. * @throws An exception is thrown if a connection cannot be made to the remote host.
  255. */
  256. public function send() {
  257. $this->response = '';
  258. $fs = fsockopen($this->host, $this->port, $this->errorNumber, $this->errorString, 3);
  259. if($this->errorNumber != 0) {
  260. throw new Exception('Error connecting to host: ' . $this->host . ' Error number: ' . $this->errorNumber . ' Error message: ' . $this->errorString);
  261. }
  262. if($fs !== false) {
  263. @fwrite($fs, $this->request);
  264. while(!feof($fs)) {
  265. $this->response .= fgets($fs, $this->responseLength);
  266. }
  267. fclose($fs);
  268. }
  269. }
  270. /**
  271. * Returns the server response text
  272. *
  273. * @return string
  274. */
  275. public function getResponse() {
  276. return $this->response;
  277. }
  278. /**
  279. * Returns the error number
  280. *
  281. * If there was no error, 0 will be returned.
  282. *
  283. * @return int
  284. */
  285. public function getErrorNumner() {
  286. return $this->errorNumber;
  287. }
  288. /**
  289. * Returns the error string
  290. *
  291. * If there was no error, an empty string will be returned.
  292. *
  293. * @return string
  294. */
  295. public function getErrorString() {
  296. return $this->errorString;
  297. }
  298. }
  299. ?>