1<?php
2/**
3 * Mollom class
4 *
5 * This source file can be used to communicate with mollom (http://mollom.com)
6 *
7 * The class is documented in the file itself, but you can find more documentation and examples on the docs-page (http://mollom.crsolutions.be/docs).
8 * If you find any bugs help me out and report them. Reporting can be done by sending an email to php-mollom-bugs[at]verkoyen[dot]eu. If you report a bug, make sure you give me enough information (include your code).
9 * If you have questions, try the Mollom-forum, don't send them by mail, I won't read them.
10 *
11 * Changelog since 1.0.1
12 * - Fixed a nasty bug. Possible infinite loop in doCall().
13 * - Fixed getServerList. I misinterpreted the documentation, so now the defaultserver is xmlrpc.mollom.com instead of the first fallback-server.
14 * - Fixed the timeout-issue. With fsockopen the timeout on connect wasn't respected. Rewrote the doCall function to use CURL over sockets.
15 *
16 * Changelog since 1.1.0
17 * - Fixed a problem with the IP-addresses. see http://blog.verkoyen.eu/2008/07/12/important-php-mollom-update/
18 *
19 * Changelog since 1.1.1
20 * - PHPMollom was using HTTP 1.1, now HTTP 1.0.
21 * - Fallbackserver are hardcoded, when no servers could be retrieved the fallbacks are used
22 *
23 * Changelog since 1.1.2
24 * - Typo
25 * - New Licence: BSD Modified
26 *
27 * License
28 * Copyright (c) 2008, Tijs Verkoyen. All rights reserved.
29 *
30 * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
31 *
32 * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
33 * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
34 * 3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission.
35 *
36 * This software is provided by the author ``as is'' and any express or implied warranties, including, but not limited to, the implied warranties of merchantability and fitness for a particular purpose are disclaimed. In no event shall the author be liable for any direct, indirect, incidental, special, exemplary, or consequential damages (including, but not limited to, procurement of substitute goods or services; loss of use, data, or profits; or business interruption) however caused and on any theory of liability, whether in contract, strict liability, or tort (including negligence or otherwise) arising in any way out of the use of this software, even if advised of the possibility of such damage.
37 *
38 * @author			Tijs Verkoyen <mollom@verkoyen.eu>
39 * @version			1.1.3
40 *
41 * @copyright		Copyright (c) 2008, Tijs Verkoyen. All rights reserved.
42 * @license			http://mollom.local/license BSD License
43 */
44class Mollom
45{
46	/**
47	 * The allowed reverse proxy addresses
48	 *
49	 * @var	array
50	 */
51	private static $allowedReverseProxyAddresses = array();
52
53
54	/**
55	 * Your private key
56	 *
57	 * Set it by calling Mollom::setPrivateKey('<your-key>');
58	 *
59	 * @var	string
60	 */
61	private static $privateKey;
62
63
64	/**
65	 * Your public key
66	 *
67	 * Set it by calling Mollom::setPublicKey('<your-key>');
68	 *
69	 * @var	string
70	 */
71	private static $publicKey;
72
73
74	/**
75	 * Reverse proxy allowed?
76	 *
77	 * @var	bool
78	 */
79	private static $reverseProxy = false;
80
81
82	/**
83	 * The default server
84	 *
85	 * No need to change
86	 *
87	 * @var	string
88	 */
89	private static $serverHost = 'xmlrpc.mollom.com';
90
91
92	/**
93	 * The cache for the serverlist
94	 *
95	 * No need to change
96	 *
97	 * @var	array
98	 */
99	private static $serverList = array();
100
101
102	/**
103	 * Default timeout
104	 *
105	 * @var	int
106	 */
107	private static $timeout = 10;
108
109
110	/**
111	 * The default user-agent
112	 *
113	 * Change it by calling Mollom::setUserAgent('<your-user-agent>');
114	 *
115	 * @var	string
116	 */
117	private static $userAgent = 'MollomPHP/1.1.3';
118
119
120	/**
121	 * The current Mollom-version
122	 *
123	 * No need to change
124	 *
125	 * @var	string
126	 */
127	private static $version = '1.0';
128
129
130	/**
131	 * Build the value so we can use it in XML-RPC requests
132	 *
133	 * @return	string
134	 * @param	mixed $value
135	 */
136	private function buildValue($value)
137	{
138		// get type
139		$type = gettype($value);
140
141		// build value
142		switch ($type)
143		{
144			case 'string':
145				// escape it, cause Mollom can't handle CDATA (no pun intended)
146				$value = htmlspecialchars($value, ENT_QUOTES, 'ISO-8859-15');
147				return '<value><string>'. $value .'</string></value>'."\n";
148
149			case 'array':
150				// init struct
151				$struct = '<value>'."\n";
152				$struct .= '	<struct>'."\n";
153
154				// loop array
155				foreach ($value as $key => $value) $struct .= str_replace("\n", '', '<member>'. "\n" .'<name>'. $key .'</name>'. mollom::buildValue($value) .'</member>') . "\n";
156
157				$struct .= '	</struct>'."\n";
158				$struct .= '</value>'."\n";
159
160				// return
161				return $struct;
162
163			default:
164				return '<value>'. $value .'</value>'."\n";
165		}
166	}
167
168
169	/**
170	 * Validates the answer for a CAPTCHA
171	 *
172	 * When the answer is false, you should request a new image- or audio-CAPTCHA, make sure your provide the current Mollom-sessionid.
173	 * The sessionid will be used to track spambots that try to solve CAPTHCA's by brute force.
174	 *
175	 * @return	bool
176	 * @param	string $sessionId
177	 * @param	string $solution
178	 */
179	public static function checkCaptcha($sessionId, $solution)
180	{
181		// redefine
182		$sessionId = (string) $sessionId;
183		$solution = (string) $solution;
184
185		// set autor ip
186		$authorIp = self::getIpAddress();
187
188		// set parameters
189		$parameters['session_id'] = $sessionId;
190		$parameters['solution'] = $solution;
191		if($authorIp != null) $parameters['author_ip'] = (string) $authorIp;
192
193		// do the call
194		$responseString = self::doCall('checkCaptcha', $parameters);
195		// validate
196		if(!isset($responseString->params->param->value->boolean)) throw new Exception('Invalid response in checkCapthca.');
197
198		// return
199		if((string) $responseString->params->param->value->boolean == '1') return true;
200
201		// fallback
202		return false;
203	}
204
205
206	/**
207	 * Check if the data is spam or not, and gets an assessment of the datas quality
208	 *
209	 * This function will be used most. The more data you submit the more accurate the claasification will be.
210	 * If the spamstatus is 'unsure', you could send the user an extra check (eg. a captcha).
211	 *
212	 * REMARK: the Mollom-sessionid is NOT related to HTTP-session, so don't send 'session_id'.
213	 *
214	 * The function will return an array with 3 elements:
215	 * - spam			the spam-status (unknown/ham/spam/unsure)
216	 * - quality		an assessment of the content's quality (between 0 and 1)
217	 * - session_id		Molloms session_id
218	 *
219	 * @return	array
220	 * @param	string[optional] $sessionId
221	 * @param	string[optional] $postTitle
222	 * @param	string[optional] $postBody
223	 * @param	string[optional] $authorName
224	 * @param	string[optional] $authorUrl
225	 * @param	string[optional] $authorEmail
226	 * @param	string[optional] $authorOpenId
227	 * @param	string[optional] $authorId
228	 */
229	public static function checkContent($sessionId = null, $postTitle = null, $postBody = null, $authorName = null, $authorUrl = null, $authorEmail = null, $authorOpenId = null, $authorId = null, $ips = array())
230	{
231		// validate
232		if($sessionId === null && $postTitle === null && $postBody === null && $authorName === null && $authorUrl === null && $authorEmail === null && $authorOpenId === null && $authorId === null) throw new Exception('Specify at least on argument');
233
234		// init var
235		$parameters = array();
236		$aReturn = array();
237
238		// add parameters
239		if($sessionId !== null) $parameters['session_id'] = (string) $sessionId;
240		if($postTitle !== null) $parameters['post_title'] = (string) $postTitle;
241		if($postBody !== null) $parameters['post_body'] = (string) $postBody;
242		if($authorName !== null) $parameters['author_name'] = (string) $authorName;
243		if($authorUrl !== null) $parameters['author_url'] = (string) $authorUrl;
244		if($authorEmail !== null) $parameters['author_mail'] = (string) $authorEmail;
245		if($authorOpenId != null) $parameters['author_openid'] = (string) $authorOpenId;
246		if($authorId != null) $parameters['author_id'] = (string) $authorId;
247
248		// set autor ip
249    if (!sizeof($ips)) {
250      $authorIp = self::getIpAddress();
251    } else {
252      $authorIp = $ips[0];
253    }
254		if($authorIp != null) $parameters['author_ip'] = (string) $authorIp;
255
256		// do the call
257		$responseString = self::doCall('checkContent', $parameters);
258
259		// validate
260		if(!isset($responseString->params->param->value->struct->member)) throw new Exception('Invalid response in checkContent.');
261
262		// loop parts
263		foreach ($responseString->params->param->value->struct->member as $part)
264		{
265			// get key
266			$key = $part->name;
267
268			// get value
269			switch ($part->name)
270			{
271				case 'spam':
272					$value = (string) $part->value->int;
273
274					switch($value)
275					{
276						case '0':
277							$aReturn['spam'] = 'unknown';
278						break;
279
280						case '1':
281							$aReturn['spam'] = 'ham';
282						break;
283
284						case '2':
285							$aReturn['spam'] = 'spam';
286						break;
287
288						case '3':
289							$aReturn['spam'] = 'unsure';
290						break;
291					}
292				break;
293
294				case 'quality':
295					$aReturn['quality'] = (float) $part->value->double;
296				break;
297
298				case 'session_id':
299					$aReturn['session_id'] = (string) $part->value->string;
300				break;
301			}
302		}
303
304		// return
305		return $aReturn;
306	}
307
308
309	/**
310	 * Make the call
311	 *
312	 * @return	SimpleXMLElement
313	 * @param	string $method
314	 * @param	array[optional] $parameters
315	 */
316	private static function doCall($method, $parameters = array(), $server = null, $counter = 0)
317	{
318		// count available servers
319		$countServerList = count(self::$serverList);
320
321		if($server === null && $countServerList == 0) throw new Exception('No servers found, populate the serverlist. See setServerList().');
322
323		// redefine var
324		$method = (string) $method;
325		$parameters = (array) $parameters;
326
327		// possible methods
328		$aPossibleMethods = array('checkCaptcha', 'checkContent', 'getAudioCaptcha', 'getImageCaptcha', 'getServerList', 'getStatistics', 'sendFeedback', 'verifyKey');
329
330		// check if method is valid
331		if(!in_array($method, $aPossibleMethods)) throw new Exception('Invalid method. Only '. implode(', ', $aPossibleMethods) .' are possible methods.');
332
333		// check if public key is set
334		if(self::$publicKey === null) throw new Exception('Public key wasn\'t set.');
335
336		// check if private key is set
337		if(self::$privateKey === null) throw new Exception('Private key wasn\'t set.');
338
339		// still null
340		if($server === null) $server = self::$serverList[$counter];
341
342		// cleanup server string
343		$server = str_replace(array('http://', 'https://'), '', $server);
344
345		// create timestamp
346		$time = gmdate("Y-m-d\TH:i:s.\\0\\0\\0O", time());
347
348		// create nonce
349		$nonce = md5(time());
350
351		// create has
352		$hash = base64_encode(
353					pack("H*", sha1((str_pad(self::$privateKey, 64, chr(0x00)) ^ (str_repeat(chr(0x5c), 64))) .
354					pack("H*", sha1((str_pad(self::$privateKey, 64, chr(0x00)) ^ (str_repeat(chr(0x36), 64))) .
355					$time . ':'. $nonce .':'. self::$privateKey))))
356				);
357
358		// add parameters
359		$parameters['public_key'] = self::$publicKey;
360		$parameters['time'] = $time;
361		$parameters['hash'] = $hash;
362		$parameters['nonce'] = $nonce;
363
364		// build request
365		$requestBody = '<?xml version="1.0"?>' ."\n";
366		$requestBody .= '<methodCall>' ."\n";
367		$requestBody .= '	<methodName>mollom.'. $method .'</methodName>' ."\n";
368		$requestBody .= '	<params>' ."\n";
369		$requestBody .= '		<param>'."\n";
370		$requestBody .= '			'. self::buildValue($parameters) ."\n";
371		$requestBody .= '		</param>'."\n";
372		$requestBody .= '	</params>' ."\n";
373		$requestBody .= '</methodCall>' ."\n";
374
375		// create curl
376		$curl = @curl_init();
377
378		// set useragent
379		@curl_setopt($curl, CURLOPT_USERAGENT, self::$userAgent);
380
381		// set options
382		@curl_setopt($curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
383		@curl_setopt($curl, CURLOPT_POST, true);
384		@curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);
385		@curl_setopt($curl, CURLOPT_HEADER, true);
386		@curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
387		@curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, self::$timeout);
388		@curl_setopt($curl, CURLOPT_TIMEOUT, self::$timeout);
389
390		// set url
391		@curl_setopt($curl, CURLOPT_URL, $server .'/'. self::$version);
392
393		// set body
394		@curl_setopt($curl, CURLOPT_POSTFIELDS, $requestBody);
395
396		// get response
397		$response = @curl_exec($curl);
398
399		// get errors
400		$errorNumber = (int) @curl_errno($curl);
401		$errorString = @curl_error($curl);
402
403		// close
404		@curl_close($curl);
405
406		// validate response
407		if($response === false || $errorNumber != 0)
408		{
409			// increment counter
410			$counter++;
411
412			// no servers left
413			if($errorNumber == 28 && !isset(self::$serverList[$counter]) && $countServerList != 0) throw new Exception('No more servers available, try to increase the timeout.');
414
415			// timeout
416			elseif($errorNumber == 28 && isset(self::$serverList[$counter])) return self::doCall($method, $parameters, self::$serverList[$counter], $counter);
417
418			// other error
419			else throw new Exception('Something went wrong. Maybe the following message can be handy.<br />'. $errorString, $errorNumber);
420		}
421
422		// process response
423		$parts = explode("\r\n\r\n", $response);
424
425		// validate
426		if(!isset($parts[0]) || !isset($parts[1])) throw new Exception('Invalid response in doCall.');
427
428		// get headers
429		$headers = $parts[0];
430
431		// rebuild body
432		array_shift($parts);
433		$body = implode('', $parts);
434
435		// validate header
436		$aValidHeaders = array('HTTP/1.0 200', 'HTTP/1.1 200');
437		if(!in_array(substr($headers, 0, 12), $aValidHeaders)) throw new Exception('Invalid headers.');
438
439		// do some validation
440		$responseXML = @simplexml_load_string($body);
441		if($responseXML === false) throw new Exception('Invalid body.');
442
443		if(isset($responseXML->fault))
444		{
445			$code = (isset($responseXML->fault->value->struct->member[0]->value->int)) ? (int) $responseXML->fault->value->struct->member[0]->value->int : 'unknown';
446			$message = (isset($responseXML->fault->value->struct->member[1]->value->string)) ? (string) $responseXML->fault->value->struct->member[1]->value->string : 'unknown';
447
448			// handle errors
449			switch ($code)
450			{
451				// code 1000 (Parse error or internal problem)
452				case 1000:
453					throw new Exception('[error '.$code .'] '. $message, $code);
454
455				// code 1100 (Serverlist outdated)
456				case 1100:
457					throw new Exception('[error '.$code .'] '. $message, $code);
458
459				// code 1200 (Server too busy)
460				case 1200:
461					if(self::$serverList === null) self::getServerList();
462
463					// do call again
464					return self::doCall($method, $parameters, self::$serverList[$counter], $counter++);
465				break;
466
467				default:
468					throw new Exception('[error '.$code .'] '. $message, $code);
469			}
470		}
471
472		// return
473		return $responseXML;
474	}
475
476
477	/**
478	 * Get a CAPTCHA-mp3 generated by Mollom
479	 *
480	 * If your already called getAudioCaptcha make sure you provide at least the $sessionId. It will be used
481	 * to identify visitors that are trying to break a CAPTCHA with brute force.
482	 *
483	 * REMARK: the Mollom-sessionid is NOT related to HTTP-session, so don't send 'session_id'.
484	 *
485	 * The function will return an array with 3 elements:
486	 * - session_id		the session_id from Mollom
487	 * - url			the url to the mp3-file
488	 * - html			html that can be used on your website to display the CAPTCHA
489	 *
490	 * @return	array
491	 * @param	string[optional] $sessionId
492	 */
493	public static function getAudioCaptcha($sessionId = null)
494	{
495		// init vars
496		$aReturn = array();
497		$parameters = array();
498
499		// set autor ip
500		$authorIp = self::getIpAddress();
501
502		// set parameters
503		if($sessionId != null) $parameters['session_id'] = (string) $sessionId;
504		if($authorIp != null) $parameters['author_ip'] = (string) $authorIp;
505
506		// do the call
507		$responseString = self::doCall('getAudioCaptcha', $parameters);
508
509		// validate
510		if(!isset($responseString->params->param->value->struct->member)) throw new Exception('Invalid response in getAudioCaptcha.');
511
512		// loop elements
513		foreach ($responseString->params->param->value->struct->member as $part) $aReturn[(string) $part->name] = (string) $part->value->string;
514
515		// add image html
516		$aReturn['html'] = '<object type="audio/mpeg" data="'. $aReturn['url'] .'" width="50" height="16">'."\n"
517								."\t".'<param name="autoplay" value="false" />'."\n"
518								."\t".'<param name="controller" value="true" />'."\n"
519							.'</object>';
520
521		// return
522		return $aReturn;
523	}
524
525
526	/**
527	 * Get a CAPTCHA-image generated by Mollom
528	 *
529	 * If your already called getImageCaptcha make sure you provide at least the $sessionId. It will be used
530	 * to identify visitors that are trying to break a CAPTCHA with brute force.
531	 *
532	 * REMARK: the Mollom-sessionid is NOT related to HTTP-session, so don't send 'session_id'.
533	 *
534	 * The function will return an array with 3 elements:
535	 * - session_id		the session_id from Mollom
536	 * - url			the url to the image
537	 * - html			html that can be used on your website to display the CAPTCHA
538	 *
539	 * @return	array
540	 * @param	string[optional] $sessionId
541	 */
542	public static function getImageCaptcha($sessionId = null)
543	{
544		// init vars
545		$aReturn = array();
546		$parameters = array();
547
548		// set autor ip
549		$authorIp = self::getIpAddress();
550
551		// set parameters
552		if($sessionId !== null) $parameters['session_id'] = (string) $sessionId;
553		if($authorIp !== null) $parameters['author_ip'] = (string) $authorIp;
554
555		// do the call
556		$responseString = self::doCall('getImageCaptcha', $parameters);
557
558		// validate
559		if(!isset($responseString->params->param->value->struct->member)) throw new Exception('Invalid response in getImageCaptcha.');
560
561		// loop elements
562		foreach ($responseString->params->param->value->struct->member as $part) $aReturn[(string) $part->name] = (string) $part->value->string;
563
564		// add image html
565		$aReturn['html'] = '<img src="'. $aReturn['url'] .'" alt="Mollom CAPTCHA" />';
566
567		// return
568		return $aReturn;
569	}
570
571
572	/**
573	 * Get the real IP-address
574	 *
575	 * @return	string
576	 */
577	public static function getIpAddress()
578	{
579		// pre check
580		if(!isset($_SERVER['REMOTE_ADDR'])) return null;
581
582		// get ip
583		$ipAddress = $_SERVER['REMOTE_ADDR'];
584
585		if(self::$reverseProxy)
586		{
587			if(isset($_SERVER['HTTP_X_FORWARDED_FOR']))
588			{
589				if(!empty(self::$allowedReverseProxyAddresses) && in_array($ipAddress, self::$allowedProxyAddresses, true))
590				{
591					return array_pop(explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']));
592				}
593   			}
594
595   			// running in a cluster environment
596			if(isset($_SERVER['HTTP_X_CLUSTER_CLIENT_IP'])) return $_SERVER['HTTP_X_CLUSTER_CLIENT_IP'];
597		}
598
599		// fallback
600    print 'IP:'.$ipAddress;
601		return $ipAddress;
602	}
603
604
605	/**
606	 * Obtains a list of valid servers
607	 *
608	 * @return	array
609	 */
610	public static function getServerList($counter = 0)
611	{
612		// do the call
613		$responseString = self::doCall('getServerList', array(), self::$serverHost, $counter);
614
615		// validate
616		if(!isset($responseString->params->param->value->array->data->value)) throw new Exception('Invalid response in getServerList.');
617
618		// loop servers and add them
619		foreach ($responseString->params->param->value->array->data->value as $server) self::$serverList[] = (string) $server->string;
620
621		if(count(self::$serverList) == 0) self::$serverList = array('http://xmlrpc3.mollom.com', 'http://xmlrpc2.mollom.com', 'http://xmlrpc1.mollom.com');
622
623		// return
624		return self::$serverList;
625	}
626
627
628	/**
629	 * Retrieve statistics from Mollom
630	 *
631	 * Allowed types are listed below:
632	 * - total_days				Number of days Mollom has been used
633	 * - total_accepted			Total of blocked spam
634	 * - total_rejected			Total accepted posts (not working?)
635	 * - yesterday_accepted		Amount of spam blocked yesterday
636	 * - yesterday_rejected		Number of posts accepted yesterday (not working?)
637	 * - today_accepted			Amount of spam blocked today
638	 * - today_rejected			Number of posts accepted today (not working?)
639	 *
640	 * @return	int
641	 * @param	string $type
642	 */
643	public static function getStatistics($type)
644	{
645		// possible types
646		$aPossibleTypes = array('total_days', 'total_accepted', 'total_rejected', 'yesterday_accepted', 'yesterday_rejected', 'today_accepted', 'today_rejected');
647
648		// redefine
649		$type = (string) $type;
650
651		// validate
652		if(!in_array($type, $aPossibleTypes)) throw new Exception('Invalid type. Only '. implode(', ', $aPossibleTypes) .' are possible types.');
653
654		// do the call
655		$responseString = self::doCall('getStatistics', array('type' => $type));
656
657		// validate
658		if(!isset($responseString->params->param->value->int)) throw new Exception('Invalid response in getStatistics.');
659
660		// return
661		return (int) $responseString->params->param->value->int;
662	}
663
664
665	/**
666	 * Send feedback to Mollom.
667	 *
668	 * With this method you can help train Mollom. Implement this method if possible. The more feedback is provided the more accurate
669	 * Mollom will be.
670	 *
671	 * Allowed feedback-strings are listed below:
672	 * - spam			Spam or unsolicited advertising
673	 * - profanity		Obscene, violent or profane content
674	 * - low-quality	Low-quality content or writing
675	 * - unwanted		Unwanted, taunting or off-topic content
676	 *
677	 * @return	bool
678	 * @param	string $sessionId
679	 * @param	string $feedback
680	 */
681	public static function sendFeedback($sessionId, $feedback)
682	{
683		// possible feedback
684		$aPossibleFeedback = array('spam', 'profanity', 'low-quality', 'unwanted');
685
686		// redefine
687		$sessionId = (string) $sessionId;
688		$feedback = (string) $feedback;
689
690		// validate
691		if(!in_array($feedback, $aPossibleFeedback)) throw new Exception('Invalid feedback. Only '. implode(', ', $aPossibleFeedback) .' are possible feedback-strings.');
692
693		// build parameters
694		$parameters['session_id'] = $sessionId;
695		$parameters['feedback'] = $feedback;
696
697		// do the call
698		$responseString = self::doCall('sendFeedback', $parameters);
699
700		// validate
701		if(!isset($responseString->params->param->value->boolean)) throw new Exception('Invalid response in sendFeedback.');
702
703		// return
704		if((string) $responseString->params->param->value->boolean == 1) return true;
705
706		// fallback
707		return false;
708	}
709
710
711	/**
712	 * Set the allowed reverse proxy Addresses
713	 *
714	 * @return	void
715	 * @param	array $addresses
716	 */
717	public static function setAllowedReverseProxyAddresses($addresses)
718	{
719		// store allowed ip-addresses
720		self::$allowedReverseProxyAddresses = (array) $addresses;
721
722		// set reverse proxy
723		self::$reverseProxy = (!empty($addresses)) ? true : false;
724	}
725
726
727	/**
728	 * Set the private key
729	 *
730	 * @return	void
731	 * @param	string $key
732	 */
733	public static function setPrivateKey($key)
734	{
735		self::$privateKey = (string) $key;
736	}
737
738
739	/**
740	 * Set the public key
741	 *
742	 * @return	void
743	 * @param	string $key
744	 */
745	public static function setPublicKey($key)
746	{
747		self::$publicKey = (string) $key;
748	}
749
750
751	/**
752	 * Set the server list
753	 *
754	 * @return	void
755	 * @param	array $servers
756	 */
757	public static function setServerList($servers)
758	{
759		// redefine
760		$server = (array) $servers;
761
762		// loop servers
763		foreach ($servers as $server) self::$serverList[] = $server;
764	}
765
766
767	/**
768	 * Set timeout
769	 *
770	 * @return	void
771	 * @param	int $timeout
772	 */
773	public static function setTimeOut($timeout)
774	{
775		// redefine
776		$timeout = (int) $timeout;
777
778		// validate
779		if($timeout == 0) throw new Exception('Invalid timeout. Timeout shouldn\'t be 0.');
780
781		// set property
782		self::$timeout = $timeout;
783	}
784
785
786	/**
787	 * Set the user agent
788	 *
789	 * @return	void
790	 * @param	string $newUserAgent
791	 */
792	public static function setUserAgent($newUserAgent)
793	{
794		self::$userAgent .=  ' '. (string) $newUserAgent;
795	}
796
797
798	/**
799	 * Verifies your key
800	 *
801	 * Returns information about the status of your key. Mollom will respond with a boolean value (true/false).
802	 * False means that your keys is disabled or doesn't exists. True means the key is enabled and working properly.
803	 *
804	 * @return	bool
805	 */
806	public static function verifyKey()
807	{
808		// do the call
809		$responseString = self::doCall('verifyKey');
810
811		// validate
812		if(!isset($responseString->params->param->value->boolean)) throw new Exception('Invalid response in verifyKey.');
813
814		// return
815		if((string) $responseString->params->param->value->boolean == '1') return true;
816
817		// fallback
818		return false;
819	}
820
821}
822
823?>
824