source: spip-zone/_plugins_/akismet/Akismet.class.php @ 117558

Last change on this file since 117558 was 22656, checked in by fil@…, 12 years ago

passage a Akismet.class.php v 0.4 http://www.achingbrain.net/stuff/php/akismet

File size: 11.9 KB
Line 
1<?php
2
3/**
4 * Akismet anti-comment spam service
5 *
6 * The class in this package allows use of the {@link http://akismet.com Akismet} anti-comment spam service in any PHP5 application.
7 *
8 * This service performs a number of checks on submitted data and returns whether or not the data is likely to be spam.
9 *
10 * Please note that in order to use this class, you must have a vaild {@link http://wordpress.com/api-keys/ WordPress API key}.  They are free for non/small-profit types and getting one will only take a couple of minutes. 
11 *
12 * For commercial use, please {@link http://akismet.com/commercial/ visit the Akismet commercial licensing page}.
13 *
14 * Please be aware that this class is PHP5 only.  Attempts to run it under PHP4 will most likely fail.
15 *
16 * See the Akismet class documentation page linked to below for usage information.
17 *
18 * @package             akismet
19 * @author              Alex Potsides, {@link http://www.achingbrain.net http://www.achingbrain.net}
20 * @version             0.4
21 * @copyright   Alex Potsides, {@link http://www.achingbrain.net http://www.achingbrain.net}
22 * @license             http://www.opensource.org/licenses/bsd-license.php BSD License
23 */
24
25/**
26 *      The Akismet PHP5 Class
27 *
28 *  This class takes the functionality from the Akismet WordPress plugin written by {@link http://photomatt.net/ Matt Mullenweg} and allows it to be integrated into any PHP5 application or website.
29 *
30 *  The original plugin is {@link http://akismet.com/download/ available on the Akismet website}.
31 *
32 *  <b>Usage:</b>
33 *  <code>
34 *    $akismet = new Akismet('http://www.example.com/blog/', 'aoeu1aoue');
35 *    $akismet->setCommentAuthor($name);
36 *    $akismet->setCommentAuthorEmail($email);
37 *    $akismet->setCommentAuthorURL($url);
38 *    $akismet->setCommentContent($comment);
39 *    $akismet->setPermalink('http://www.example.com/blog/alex/someurl/');
40 *    if($akismet->isCommentSpam())
41 *      // store the comment but mark it as spam (in case of a mis-diagnosis)
42 *    else
43 *      // store the comment normally
44 *  </code>
45 *
46 *  Optionally you may wish to check if your WordPress API key is valid as in the example below.
47 *
48 * <code>
49 *   $akismet = new Akismet('http://www.example.com/blog/', 'aoeu1aoue');
50 *   
51 *   if($akismet->isKeyValid()) {
52 *     // api key is okay
53 *   } else {
54 *     // api key is invalid
55 *   }
56 * </code>
57 *
58 *      @package        akismet
59 *      @name           Akismet
60 *      @version        0.4
61 *  @author             Alex Potsides
62 *  @link               http://www.achingbrain.net/
63 */
64class Akismet
65        {
66        private $version = '0.4';
67        private $wordPressAPIKey;
68        private $blogURL;
69        private $comment;
70        private $apiPort;
71        private $akismetServer;
72        private $akismetVersion;
73       
74        // This prevents some potentially sensitive information from being sent accross the wire.
75        private $ignore = array('HTTP_COOKIE', 
76                                                        'HTTP_X_FORWARDED_FOR', 
77                                                        'HTTP_X_FORWARDED_HOST', 
78                                                        'HTTP_MAX_FORWARDS', 
79                                                        'HTTP_X_FORWARDED_SERVER', 
80                                                        'REDIRECT_STATUS', 
81                                                        'SERVER_PORT', 
82                                                        'PATH',
83                                                        'DOCUMENT_ROOT',
84                                                        'SERVER_ADMIN',
85                                                        'QUERY_STRING',
86                                                        'PHP_SELF' );
87       
88        /**
89         *      @param  string  $blogURL                        The URL of your blog.
90         *      @param  string  $wordPressAPIKey        WordPress API key.
91         */
92        public function __construct($blogURL, $wordPressAPIKey) {
93                $this->blogURL = $blogURL;
94                $this->wordPressAPIKey = $wordPressAPIKey;
95               
96                // Set some default values
97                $this->apiPort = 80;
98                $this->akismetServer = 'rest.akismet.com';
99                $this->akismetVersion = '1.1';
100               
101                // Start to populate the comment data
102                $this->comment['blog'] = $blogURL;
103                $this->comment['user_agent'] = $_SERVER['HTTP_USER_AGENT'];
104               
105                if(isset($_SERVER['HTTP_REFERER'])) {
106                        $this->comment['referrer'] = $_SERVER['HTTP_REFERER'];
107                }
108               
109                /*
110                 * This is necessary if the server PHP5 is running on has been set up to run PHP4 and
111                 * PHP5 concurently and is actually running through a separate proxy al a these instructions:
112                 * http://www.schlitt.info/applications/blog/archives/83_How_to_run_PHP4_and_PHP_5_parallel.html
113                 * and http://wiki.coggeshall.org/37.html
114                 * Otherwise the user_ip appears as the IP address of the PHP4 server passing the requests to the
115                 * PHP5 one...
116                 */
117                $this->comment['user_ip'] = $_SERVER['REMOTE_ADDR'] != getenv('SERVER_ADDR') ? $_SERVER['REMOTE_ADDR'] : getenv('HTTP_X_FORWARDED_FOR');
118        }
119       
120        /**
121         * Makes a request to the Akismet service to see if the API key passed to the constructor is valid.
122         *
123         * Use this method if you suspect your API key is invalid.
124         *
125         * @return bool True is if the key is valid, false if not.
126         */
127        public function isKeyValid() {
128                // Check to see if the key is valid
129                $response = $this->sendRequest('key=' . $this->wordPressAPIKey . '&blog=' . $this->blogURL, $this->akismetServer, '/' . $this->akismetVersion . '/verify-key');
130                return $response[1] == 'valid';
131        }
132       
133        // makes a request to the Akismet service
134        private function sendRequest($request, $host, $path) {
135                $http_request  = "POST " . $path . " HTTP/1.0\r\n";
136                $http_request .= "Host: " . $host . "\r\n";
137                $http_request .= "Content-Type: application/x-www-form-urlencoded; charset=utf-8\r\n";
138                $http_request .= "Content-Length: " . strlen($request) . "\r\n";
139                $http_request .= "User-Agent: Akismet PHP5 Class " . $this->version . " | Akismet/1.11\r\n";
140                $http_request .= "\r\n";
141                $http_request .= $request;
142               
143                $socketWriteRead = new SocketWriteRead($host, $this->apiPort, $http_request);
144                $socketWriteRead->send();
145               
146                return explode("\r\n\r\n", $socketWriteRead->getResponse(), 2);
147        }
148       
149        // Formats the data for transmission
150        private function getQueryString() {
151                foreach($_SERVER as $key => $value) {
152                        if(!in_array($key, $this->ignore)) {
153                                if($key == 'REMOTE_ADDR') {
154                                        $this->comment[$key] = $this->comment['user_ip'];
155                                } else {
156                                        $this->comment[$key] = $value;
157                                }
158                        }
159                }
160
161                $query_string = '';
162               
163                foreach($this->comment as $key => $data) {
164                        if(!is_array($data)) {
165                                $query_string .= $key . '=' . urlencode(stripslashes($data)) . '&';
166                        }
167                }
168               
169                return $query_string;
170        }
171       
172        /**
173         *      Tests for spam.
174         *
175         *      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.
176         *
177         *      @return         bool    True if the comment is spam, false if not
178         *  @throws             Will throw an exception if the API key passed to the constructor is invalid.
179         */
180        public function isCommentSpam() {
181                $response = $this->sendRequest($this->getQueryString(), $this->wordPressAPIKey . '.rest.akismet.com', '/' . $this->akismetVersion . '/comment-check');
182               
183                if($response[1] == 'invalid' && !$this->isKeyValid()) {
184                        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/');
185                }
186               
187                return ($response[1] == 'true');
188        }
189
190        /**
191         *      Submit spam that is incorrectly tagged as ham.
192         *
193         *      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.
194         */
195        public function submitSpam() {
196                $this->sendRequest($this->getQueryString(), $this->wordPressAPIKey . '.' . $this->akismetServer, '/' . $this->akismetVersion . '/submit-spam');
197        }
198       
199        /**
200         *      Submit ham that is incorrectly tagged as spam.
201         *
202         *      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.
203         */
204        public function submitHam() {
205                $this->sendRequest($this->getQueryString(), $this->wordPressAPIKey . '.' . $this->akismetServer, '/' . $this->akismetVersion . '/submit-ham');
206        }
207       
208        /**
209         *      To override the user IP address when submitting spam/ham later on
210         *
211         *      @param string $userip   An IP address.  Optional.
212         */
213        public function setUserIP($userip) {
214                $this->comment['user_ip'] = $userip;
215        }
216       
217        /**
218         *      To override the referring page when submitting spam/ham later on
219         *
220         *      @param string $referrer The referring page.  Optional.
221         */
222        public function setReferrer($referrer) {
223                $this->comment['referrer'] = $referrer;
224        }
225       
226        /**
227         *      A permanent URL referencing the blog post the comment was submitted to.
228         *
229         *      @param string $permalink        The URL.  Optional.
230         */
231        public function setPermalink($permalink) {
232                $this->comment['permalink'] = $permalink;
233        }
234       
235        /**
236         *      The type of comment being submitted. 
237         *
238         *      May be blank, comment, trackback, pingback, or a made up value like "registration" or "wiki".
239         */
240        public function setCommentType($commentType) {
241                $this->comment['comment_type'] = $commentType;
242        }
243       
244        /**
245         *      The name that the author submitted with the comment.
246         */
247        public function setCommentAuthor($commentAuthor) {
248                $this->comment['comment_author'] = $commentAuthor;
249        }
250       
251        /**
252         *      The email address that the author submitted with the comment.
253         *
254         *      The address is assumed to be valid.
255         */
256        public function setCommentAuthorEmail($authorEmail) {
257                $this->comment['comment_author_email'] = $authorEmail;
258        }
259       
260        /**
261         *      The URL that the author submitted with the comment.
262         */     
263        public function setCommentAuthorURL($authorURL) {
264                $this->comment['comment_author_url'] = $authorURL;
265        }
266       
267        /**
268         *      The comment's body text.
269         */
270        public function setCommentContent($commentBody) {
271                $this->comment['comment_content'] = $commentBody;
272        }
273       
274        /**
275         *      Defaults to 80
276         */
277        public function setAPIPort($apiPort) {
278                $this->apiPort = $apiPort;
279        }
280       
281        /**
282         *      Defaults to rest.akismet.com
283         */
284        public function setAkismetServer($akismetServer) {
285                $this->akismetServer = $akismetServer;
286        }
287       
288        /**
289         *      Defaults to '1.1'
290         */
291        public function setAkismetVersion($akismetVersion) {
292                $this->akismetVersion = $akismetVersion;
293        }
294}
295
296/**
297 *      Utility class used by Akismet
298 *
299 *  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.
300 *
301 *  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}.
302 *
303 *      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.
304 *
305 *      @package        akismet
306 *      @name           SocketWriteRead
307 *      @version        0.1
308 *  @author             Alex Potsides
309 *  @link               http://www.achingbrain.net/
310 */
311class SocketWriteRead {
312        private $host;
313        private $port;
314        private $request;
315        private $response;
316        private $responseLength;
317        private $errorNumber;
318        private $errorString;
319       
320        /**
321         *      @param  string  $host                   The host to send/receive data.
322         *      @param  int             $port                   The port on the remote host.
323         *      @param  string  $request                The data to send.
324         *      @param  int             $responseLength The amount of data to read.  Defaults to 1160 bytes.
325         */
326        public function __construct($host, $port, $request, $responseLength = 1160) {
327                $this->host = $host;
328                $this->port = $port;
329                $this->request = $request;
330                $this->responseLength = $responseLength;
331                $this->errorNumber = 0;
332                $this->errorString = '';
333        }
334       
335        /**
336         *  Sends the data to the remote host.
337         *
338         * @throws      An exception is thrown if a connection cannot be made to the remote host.
339         */
340        public function send() {
341                $this->response = '';
342               
343                $fs = fsockopen($this->host, $this->port, $this->errorNumber, $this->errorString, 3);
344               
345                if($this->errorNumber != 0) {
346                        throw new Exception('Error connecting to host: ' . $this->host . ' Error number: ' . $this->errorNumber . ' Error message: ' . $this->errorString);
347                }
348               
349                if($fs !== false) {
350                        @fwrite($fs, $this->request);
351                       
352                        while(!feof($fs)) {
353                                $this->response .= fgets($fs, $this->responseLength);
354                        }
355                       
356                        fclose($fs);
357                }
358        }
359       
360        /**
361         *  Returns the server response text
362         *
363         *  @return     string
364         */
365        public function getResponse() {
366                return $this->response;
367        }
368       
369        /**
370         *      Returns the error number
371         *
372         *      If there was no error, 0 will be returned.
373         *
374         *      @return int
375         */
376        public function getErrorNumner() {
377                return $this->errorNumber;
378        }
379       
380        /**
381         *      Returns the error string
382         *
383         *      If there was no error, an empty string will be returned.
384         *
385         *      @return string
386         */
387        public function getErrorString() {
388                return $this->errorString;
389        }
390}
391
392?>
Note: See TracBrowser for help on using the repository browser.