1 | <?php |
||
2 | namespace Gothick\AkismetClient; |
||
3 | |||
4 | use \Gothick\AkismetClient\Result\VerifyKeyResult; |
||
0 ignored issues
–
show
|
|||
5 | use \Gothick\AkismetClient\Result\CommentCheckResult; |
||
0 ignored issues
–
show
The type
\Gothick\AkismetClient\Result\CommentCheckResult was not found. Maybe you did not declare it correctly or list all dependencies?
The issue could also be caused by a filter entry in the build configuration.
If the path has been excluded in your configuration, e.g. filter:
dependency_paths: ["lib/*"]
For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths ![]() |
|||
6 | use \Gothick\AkismetClient\Result\SubmitHamResult; |
||
0 ignored issues
–
show
The type
\Gothick\AkismetClient\Result\SubmitHamResult was not found. Maybe you did not declare it correctly or list all dependencies?
The issue could also be caused by a filter entry in the build configuration.
If the path has been excluded in your configuration, e.g. filter:
dependency_paths: ["lib/*"]
For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths ![]() |
|||
7 | use \Gothick\AkismetClient\Result\SubmitSpamResult; |
||
0 ignored issues
–
show
The type
\Gothick\AkismetClient\Result\SubmitSpamResult was not found. Maybe you did not declare it correctly or list all dependencies?
The issue could also be caused by a filter entry in the build configuration.
If the path has been excluded in your configuration, e.g. filter:
dependency_paths: ["lib/*"]
For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths ![]() |
|||
8 | |||
9 | /** |
||
10 | * Akismet API client. |
||
11 | * @author matt |
||
12 | * |
||
13 | */ |
||
14 | class Client |
||
15 | { |
||
16 | const VERB_VERIFY_KEY = 'verify-key'; |
||
17 | const VERB_COMMENT_CHECK = 'comment-check'; |
||
18 | const VERB_SUBMIT_SPAM = 'submit-spam'; |
||
19 | const VERB_SUBMIT_HAM = 'submit-ham'; |
||
20 | /** |
||
21 | * Akismet API key |
||
22 | * |
||
23 | * @var string |
||
24 | */ |
||
25 | private $api_key; |
||
26 | |||
27 | /** |
||
28 | * Our Guzzle client. |
||
29 | * This can be passed in for DI, or if not we'll create a default one ouselves. |
||
30 | * |
||
31 | * @var \GuzzleHttp\Client |
||
32 | */ |
||
33 | private $guzzle_client; |
||
34 | |||
35 | /** |
||
36 | * URL of the site using us. |
||
37 | * Akismet calls this "blog", because WordPress. |
||
38 | * |
||
39 | * @var string |
||
40 | */ |
||
41 | private $blog; |
||
42 | |||
43 | /** |
||
44 | * Name of the site using us. |
||
45 | * |
||
46 | * @var string |
||
47 | */ |
||
48 | private $app_name; |
||
49 | |||
50 | /** |
||
51 | * Version string of the site using us. |
||
52 | * |
||
53 | * @var string |
||
54 | */ |
||
55 | private $app_version; |
||
56 | |||
57 | /** |
||
58 | * Version of this Client. |
||
59 | * Akismet likes to know. We should bump this every time |
||
60 | * we package a new version. |
||
61 | * |
||
62 | * @var string |
||
63 | */ |
||
64 | const VERSION = '0.1'; |
||
65 | |||
66 | /** |
||
67 | * Make an Akismet API client. |
||
68 | * Typically you'd provide an API key in $api_key, at which point you can make any call. Without the optional |
||
69 | * $api_key you're limited to calling verifyApiKey. Once you've verified a key you can call setApiKey() |
||
70 | * later and start using the rest of the API. |
||
71 | * |
||
72 | * @param string $app_url |
||
73 | * e.g. http://forum.example.com/ |
||
74 | * @param string $app_name |
||
75 | * e.g. phpBB |
||
76 | * @param string $app_version |
||
77 | * e.g. 3.2.1 |
||
78 | * @param string $api_key |
||
79 | * (optional) Akismet API key |
||
80 | * @param |
||
81 | * \GuzzleHttp\Client (optional) $guzzle_client. You can inject a mock, or a non-Curl-using Guzzle |
||
82 | * client here, say. Otherwise we'll just make one. |
||
83 | * @throws \Gothick\AkismetClient\AkismetException |
||
84 | */ |
||
85 | 69 | public function __construct($app_url, $app_name, $app_version, $api_key = null, $guzzle_client = null) |
|
86 | { |
||
87 | 69 | if ((empty($app_url)) || (empty($app_name)) || (empty($app_version))) |
|
88 | { |
||
89 | 6 | throw new AkismetException('Must supply app URL, name and version in ' . __METHOD__); |
|
90 | } |
||
91 | // The Akismet API calls it a blog, so keep consistent. |
||
92 | 63 | $this->blog = $app_url; |
|
93 | |||
94 | 63 | $this->app_name = $app_name; |
|
95 | 63 | $this->app_version = $app_version; |
|
96 | 63 | $this->api_key = $api_key; |
|
97 | |||
98 | // Our client is passed in, as dependency injection is helpful for |
||
99 | // testing, but in the normal course of things we'll probably just |
||
100 | // create it ourselves. |
||
101 | 63 | $this->guzzle_client = $guzzle_client; |
|
102 | 63 | if (!isset($this->guzzle_client)) |
|
103 | { |
||
104 | 9 | $this->guzzle_client = new \GuzzleHttp\Client(); |
|
105 | } |
||
106 | } |
||
107 | |||
108 | /** |
||
109 | * Headers to be sent on every API call |
||
110 | * |
||
111 | * @return string[] |
||
112 | */ |
||
113 | 51 | private function getStandardHeaders() |
|
114 | { |
||
115 | // I'd use Guzzle middleware for this, as we want to add it on |
||
116 | // every request, but how do I do that and support dependency |
||
117 | // injection of our client? You can't add middleware to a |
||
118 | // Guzzle client after it's been constructed, right? |
||
119 | 51 | return array( |
|
120 | 51 | 'User-Agent' => $this->getOurUserAgent() |
|
121 | 51 | ); |
|
122 | } |
||
123 | |||
124 | /** |
||
125 | * From the docs: |
||
126 | * Setting your user agent If possible, your user agent string should always use the following format: Application Name/Version | Plugin Name/Version |
||
127 | * e.g. WordPress/4.4.1 | Akismet/3.1.7 |
||
128 | * |
||
129 | * @return string |
||
130 | */ |
||
131 | 51 | private function getOurUserAgent() |
|
132 | { |
||
133 | 51 | return "{$this->app_name}/{$this->app_version} | Gothick\\AkismetClient/" . self::VERSION; |
|
134 | } |
||
135 | |||
136 | /** |
||
137 | * You may want to verify a key before you use it. To do that, construct a Client without an API |
||
138 | * key, then use verifyKey($key) to verify the key, then use setKey($key) to set the validated |
||
139 | * key. You can call verifyKey without a key set, but you must set a key before calling any other |
||
140 | * API method. |
||
141 | * |
||
142 | * @param string $api_key |
||
143 | * @throws \Gothick\AkismetClient\AkismetException |
||
144 | */ |
||
145 | 11 | public function setKey($api_key) |
|
146 | { |
||
147 | 11 | if (empty($api_key)) |
|
148 | { |
||
149 | 2 | throw new AkismetException('Must provide an API key in ' . __METHOD__); |
|
150 | } |
||
151 | 9 | $this->api_key = $api_key; |
|
152 | } |
||
153 | |||
154 | /** |
||
155 | * Verify an Akismet API key. |
||
156 | * @param string $api_key |
||
157 | * @param string[] $params Optional parameters. In verify-key, the only useful parameter is "is_test", |
||
158 | * which you should only pass when testing. To be honest, it's not even clear |
||
159 | * from the documentation if that parameter is used in verify-key, but better |
||
160 | * safe than sorry... |
||
161 | * @throws \Gothick\AkismetClient\AkismetException |
||
162 | * @return \Gothick\AkismetClient\Result\VerifyKeyResult |
||
163 | */ |
||
164 | 15 | public function verifyKey($api_key = null, $params = array()) |
|
165 | { |
||
166 | 15 | $key_to_verify = empty($api_key) ? $this->api_key : $api_key; |
|
167 | |||
168 | 15 | if (empty($key_to_verify)) |
|
169 | { |
||
170 | 1 | throw new AkismetException('Must provide or pre-configure a key in ' . __METHOD__); |
|
171 | } |
||
172 | |||
173 | try |
||
174 | { |
||
175 | 14 | $params = array_merge( |
|
176 | 14 | $params, |
|
177 | 14 | [ |
|
178 | 14 | "key" => $key_to_verify, |
|
179 | 14 | "blog" => $this->blog |
|
180 | 14 | ] |
|
181 | 14 | ); |
|
182 | 14 | $response = $this->callApiMethod(self::VERB_VERIFY_KEY, $params); |
|
183 | 1 | } catch (\Exception $e) |
|
184 | { |
||
185 | // Wrap whatever exception we caught up in a new exception of our |
||
186 | // own type and throw it along up the line. |
||
187 | 1 | throw new AkismetException('Unexpected exception in ' . __METHOD__, 0, $e); |
|
188 | } |
||
189 | 13 | return new VerifyKeyResult($response); |
|
190 | } |
||
191 | |||
192 | /** |
||
193 | * Check a comment for spam. |
||
194 | * See the Akismet API documentation for full details: |
||
195 | * https://akismet.com/development/api/#comment-check. |
||
196 | * Returns a valid CommentCheckResult object or throws an exception. |
||
197 | * |
||
198 | * @param string[] $params |
||
199 | * User IP, User-Agent, the message, etc. See the Akismet API |
||
200 | * documentation for details. |
||
201 | * @param string[] $server_params |
||
202 | * This can just be $_SERVER, if you have access to it |
||
203 | * @return \Gothick\AkismetClient\Result\CommentCheckResult |
||
204 | */ |
||
205 | 18 | public function commentCheck($params = array(), $server_params = array()) |
|
206 | { |
||
207 | 18 | return new CommentCheckResult($this->callSpamMethod(self::VERB_COMMENT_CHECK, $params, $server_params)); |
|
208 | } |
||
209 | |||
210 | /** |
||
211 | * Submit a comment as spam. This must use the same parameters as those used when checking the |
||
212 | * comment with commetnCheck. |
||
213 | * See the Akismet API documentation for full details: |
||
214 | * https://akismet.com/development/api/#comment-check. |
||
215 | * Returns a valid SubmitSpamResult object or throws an exception. |
||
216 | * |
||
217 | * @param string[] $params |
||
218 | * User IP, User-Agent, the message, etc. See the Akismet API |
||
219 | * documentation for details. |
||
220 | * @param string[] $server_params |
||
221 | * This can just be $_SERVER, if you have access to it |
||
222 | * @return \Gothick\AkismetClient\Result\SubmitSpamResult |
||
223 | */ |
||
224 | 14 | public function submitSpam($params = array(), $server_params = array()) |
|
225 | { |
||
226 | 14 | return new SubmitSpamResult($this->callSpamMethod(self::VERB_SUBMIT_SPAM, $params, $server_params)); |
|
227 | } |
||
228 | |||
229 | /** |
||
230 | * Submit a comment as ham. This must use the same parameters as those used when checking the |
||
231 | * comment with commetnCheck. |
||
232 | * See the Akismet API documentation for full details: |
||
233 | * https://akismet.com/development/api/#comment-check. |
||
234 | * Returns a valid SubmitHamResult object or throws an exception. |
||
235 | * |
||
236 | * @param string[] $params |
||
237 | * User IP, User-Agent, the message, etc. See the Akismet API |
||
238 | * documentation for details. |
||
239 | * @param string[] $server_params |
||
240 | * This can just be $_SERVER, if you have access to it |
||
241 | * @return \Gothick\AkismetClient\Result\SubmitHamResult |
||
242 | */ |
||
243 | 14 | public function submitHam($params = array(), $server_params = array()) |
|
244 | { |
||
245 | 14 | return new SubmitHamResult($this->callSpamMethod(self::VERB_SUBMIT_HAM, $params, $server_params)); |
|
246 | } |
||
247 | |||
248 | /** |
||
249 | * Common code for calling check-comment, submit-ham and submit-spam; these all |
||
250 | * work in the same way, just returning slightly different results. |
||
251 | * @param string $verb |
||
252 | * @param string[] $params |
||
253 | * @param string[] $server_params |
||
254 | * @throws \Gothick\AkismetClient\AkismetException |
||
255 | */ |
||
256 | 46 | protected function callSpamMethod($verb, $params, $server_params) |
|
257 | { |
||
258 | // comment-check, submit-spam and submit-ham all work the same way and take |
||
259 | // the same arguments, so this handles them all. |
||
260 | 46 | if (empty($params[ 'user_ip' ]) || empty($params[ 'user_agent' ])) |
|
261 | { |
||
262 | 6 | throw new AkismetException(__METHOD__ . ' requires user_ip and user_agent in $params (' . $verb . ')'); |
|
263 | } |
||
264 | 40 | $params = array_merge($server_params, $params); |
|
265 | 40 | $params = array_merge($params, [ |
|
266 | 40 | 'blog' => $this->blog |
|
267 | 40 | ]); |
|
268 | |||
269 | try |
||
270 | { |
||
271 | 40 | $response = $this->callApiMethod($verb, $params); |
|
272 | 3 | } catch (\Exception $e) |
|
273 | { |
||
274 | 3 | throw new AkismetException('Unexpected exception in ' . __METHOD__ . ' (' . $verb . ')', 0, $e); |
|
275 | } |
||
276 | 37 | return $response; |
|
277 | } |
||
278 | /** |
||
279 | * Call an Akisemet API method. |
||
280 | * @param string $verb |
||
281 | * @param array $params |
||
282 | * @return \GuzzleHttp\Psr7\Response |
||
283 | */ |
||
284 | 54 | private function callApiMethod($verb, $params) |
|
285 | { |
||
286 | 54 | return $this->guzzle_client->request( |
|
287 | 54 | 'POST', |
|
288 | 54 | $this->apiUri($verb), |
|
289 | 54 | [ |
|
290 | 54 | 'form_params' => $params, |
|
291 | 54 | 'headers' => $this->getStandardHeaders() |
|
292 | 54 | ]); |
|
293 | } |
||
294 | |||
295 | /** |
||
296 | * Work out the Akismet API URL given the REST verb and our configured key. This would |
||
297 | * be far less of a pain if Akismet just had you pass the API key as a parameter or |
||
298 | * a header. Gawd knows why they change the host for authenticated calls. |
||
299 | * @param string $verb |
||
300 | * @throws \Gothick\AkismetClient\AkismetException |
||
301 | * @return string |
||
302 | */ |
||
303 | 54 | private function apiUri($verb) |
|
304 | { |
||
305 | 54 | if ($verb == self::VERB_VERIFY_KEY) |
|
306 | { |
||
307 | 14 | return "https://rest.akismet.com/1.1/verify-key"; |
|
308 | } else |
||
309 | { |
||
310 | 40 | if (empty($this->api_key)) |
|
311 | { |
||
312 | 3 | throw new AkismetException("Can't call authenticated method without setting an API key in " . __METHOD__); |
|
313 | } |
||
314 | 37 | return "https://{$this->api_key}.rest.akismet.com/1.1/$verb"; |
|
315 | } |
||
316 | } |
||
317 | } |
The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g.
excluded_paths: ["lib/*"]
, you can move it to the dependency path list as follows:For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths