1: <?php
2:
3: namespace MaxMind;
4:
5: use MaxMind\Exception\AuthenticationException;
6: use MaxMind\Exception\HttpException;
7: use MaxMind\Exception\InsufficientFundsException;
8: use MaxMind\Exception\InvalidInputException;
9: use MaxMind\Exception\InvalidRequestException;
10: use MaxMind\Exception\WebServiceException;
11: use MaxMind\MinFraud\Validation;
12: use MaxMind\WebService\Client;
13: use \Respect\Validation\Exceptions\ValidationExceptionInterface;
14:
15: /**
16: * Class MinFraud
17: * @package MaxMind
18: *
19: * This class provides a client API for accessing MaxMind minFraud Score
20: * and Insights.
21: *
22: * ## Usage ##
23: *
24: * The constructor takes your MaxMind user ID and license key. The object
25: * returned is immutable. To build up a request, call the `->with*()` methods.
26: * Each of these returns a new object (a clone of the original) with the
27: * additional data. These can be chained together:
28: *
29: * ```
30: * $client = new MinFraud(6, 'LICENSE_KEY');
31: *
32: * $score = $client->withDevice(['ip_address' => '1.1.1.1',
33: * 'accept_language' => 'en-US'])
34: * ->withEmail(['domain' => 'maxmind.com'])
35: * ->score();
36: * ```
37: *
38: * If the request fails, an exception is thrown.
39: */
40: class MinFraud
41: {
42: const VERSION = 'v0.1.0';
43:
44: private $client;
45: private static $host = 'minfraud.maxmind.com';
46:
47: private static $basePath = '/minfraud/v2.0/';
48: private $content;
49: private $locales;
50: private $validateInput = true;
51:
52: /**
53: * @param int $userId Your MaxMind user ID
54: * @param string $licenseKey Your MaxMind license key
55: * @param array $options An array of options. Possible keys:
56: *
57: * * `host` - The host to use when connecting to the web service.
58: * * `userAgent` - The prefix for the User-Agent header to use in the
59: * request.
60: * * `caBundle` - The bundle of CA root certificates to use in the request.
61: * * `connectTimeout` - The connect timeout to use for the request.
62: * * `timeout` - The timeout to use for the request.
63: * * `locales` - An array of locale codes to use for the location name
64: * properties.
65: * * `validateInput` - Default is `true`. Determines whether values passed
66: * to the `with*()` methods are validated. It is recommended that you
67: * leave validation on while developing and only (optionally) disable it
68: * before deployment.
69: */
70: public function __construct(
71: $userId,
72: $licenseKey,
73: $options = array()
74: ) {
75: if (isset($options['locales'])) {
76: $this->locales = $options['locales'];
77: } else {
78: $this->locales = array('en');
79: }
80:
81: if (isset($options['validateInput'])) {
82: $this->validateInput = $options['validateInput'];
83: }
84:
85: if (!isset($options['host'])) {
86: $options['host'] = self::$host;
87: }
88: $options['userAgent'] = $this->userAgent();
89: $this->client = new Client($userId, $licenseKey, $options);
90: }
91:
92: /**
93: * This returns a `MinFraud` object with the array to be sent to the web
94: * service set to `$values`. Existing values will be replaced.
95: * @link http://dev.maxmind.com/minfraud-score-and-insights-api-documentation/ minFraud API docs
96: *
97: * @param $values
98: * @return MinFraud
99: */
100: public function with($values)
101: {
102: $this->validate('Transaction', $values);
103:
104: $new = clone $this;
105: $new->content = $values;
106: return $new;
107: }
108:
109: /**
110: * This returns a `MinFraud` object with the `device` array set to
111: * `$values`. Existing `device` data will be replaced.
112: * @link http://dev.maxmind.com/minfraud-score-and-insights-api-documentation/#Device_device minFraud device API docs
113: *
114: * @param $values
115: * @return MinFraud
116: */
117: public function withDevice($values)
118: {
119: return $this->validateAndAdd('Device', 'device', $values);
120: }
121:
122: /**
123: * This returns a `MinFraud` object with the `events` array set to
124: * `$values`. Existing `event` data will be replaced.
125: * @link http://dev.maxmind.com/minfraud-score-and-insights-api-documentation/#Event_event minFraud event API docs
126: *
127: * @param $values
128: * @return MinFraud
129: */
130: public function withEvent($values)
131: {
132: return $this->validateAndAdd('Event', 'event', $values);
133: }
134:
135: /**
136: * This returns a `MinFraud` object with the `account` array set to
137: * `$values`. Existing `account` data will be replaced.
138: * @link http://dev.maxmind.com/minfraud-score-and-insights-api-documentation/#Account_account minFraud account API docs
139: *
140: * @param $values
141: * @return MinFraud
142: */
143: public function withAccount($values)
144: {
145: return $this->validateAndAdd('Account', 'account', $values);
146: }
147:
148: /**
149: * This returns a `MinFraud` object with the `email` array set to
150: * `$values`. Existing `email` data will be replaced.
151: * @link http://dev.maxmind.com/minfraud-score-and-insights-api-documentation/#Email_email minFraud email API docs
152: *
153: * @param $values
154: * @return MinFraud
155: */
156: public function withEmail($values)
157: {
158: return $this->validateAndAdd('Email', 'email', $values);
159: }
160:
161: /**
162: * This returns a `MinFraud` object with the `billing` array set to
163: * `$values`. Existing `billing` data will be replaced.
164: * @link http://dev.maxmind.com/minfraud-score-and-insights-api-documentation/#Billing_billing minFraud billing API docs
165: *
166: * @param $values
167: * @return MinFraud
168: */
169: public function withBilling($values)
170: {
171: return $this->validateAndAdd('Billing', 'billing', $values);
172: }
173:
174: /**
175: * This returns a `MinFraud` object with the `shipping` array set to
176: * `$values`. Existing `shipping` data will be replaced.
177: * @link http://dev.maxmind.com/minfraud-score-and-insights-api-documentation/#Shipping_shipping minFraud shipping API docs
178: *
179: * @param $values
180: * @return MinFraud
181: */
182: public function withShipping($values)
183: {
184: return $this->validateAndAdd('Shipping', 'shipping', $values);
185: }
186:
187: /**
188: * This returns a `MinFraud` object with the `payment` array set to
189: * `$values`. Existing `payment` data will be replaced.
190: * @link http://dev.maxmind.com/minfraud-score-and-insights-api-documentation/#Payment_payment minFraud payment API docs
191: *
192: * @param $values
193: * @return MinFraud
194: */
195: public function withPayment($values)
196: {
197: return $this->validateAndAdd('Payment', 'payment', $values);
198: }
199:
200: /**
201: * This returns a `MinFraud` object with the `credit_card` array set to
202: * `$values`. Existing `credit_card` data will be replaced.
203: * @link http://dev.maxmind.com/minfraud-score-and-insights-api-documentation/#Credit_Card_credit_card minFraud credit_card API docs
204: *
205: * @param $values
206: * @return MinFraud
207: */
208: public function withCreditCard($values)
209: {
210: return $this->validateAndAdd('CreditCard', 'credit_card', $values);
211: }
212:
213: /**
214: * This returns a `MinFraud` object with the `order` array set to
215: * `$values`. Existing `order` data will be replaced.
216: * @link http://dev.maxmind.com/minfraud-score-and-insights-api-documentation/#Order_order minFraud order API docs
217: *
218: * @param $values
219: * @return MinFraud
220: */
221: public function withOrder($values)
222: {
223: return $this->validateAndAdd('Order', 'order', $values);
224: }
225:
226: /**
227: * This returns a `MinFraud` object with `$values` added to the shopping
228: * cart array.
229: * @link http://dev.maxmind.com/minfraud-score-and-insights-api-documentation/#Shopping_Cart_Item minFraud shopping cart item API docs
230: *
231: * @param $values
232: * @return MinFraud
233: */
234: public function withShoppingCartItem($values)
235: {
236: $this->validate('ShoppingCartItem', $values);
237:
238: $new = clone $this;
239: if (!isset($new->content['shopping_cart'])) {
240: $new->content['shopping_cart'] = array();
241: }
242: array_push($new->content['shopping_cart'], $values);
243: return $new;
244: }
245:
246: /**
247: * This method performs a minFraud Score lookup using the request data in
248: * the current object and returns a model object for minFraud Score.
249: *
250: * @return MinFraud\Model\Score minFraud Score model object.
251: * @throws InvalidInputException when the request has missing or invalid
252: * data.
253: * @throws AuthenticationException when there is an issue authenticating
254: * the request.
255: * @throws InsufficientFundsException when your account is out of funds.
256: * @throws InvalidRequestException when the request is invalid for some
257: * other reason, e.g., invalid JSON in the POST.
258: * @throws HttpException when an unexpected HTTP error occurs.
259: * @throws WebServiceException when some other error occurs. This also
260: * serves as the base class for the above exceptions.
261: */
262: public function score()
263: {
264: return $this->post('Score');
265: }
266:
267: /**
268: * This method performs a minFraud Insights lookup using the request data
269: * in the current object and returns a model object for minFraud Insights.
270: *
271: * @return MinFraud\Model\Insights minFraud Insights model object.
272: * @throws InvalidInputException when the request has missing or invalid
273: * data.
274: * @throws AuthenticationException when there is an issue authenticating
275: * the request.
276: * @throws InsufficientFundsException when your account is out of funds.
277: * @throws InvalidRequestException when the request is invalid for some
278: * other reason, e.g., invalid JSON in the POST.
279: * @throws HttpException when an unexpected HTTP error occurs.
280: * @throws WebServiceException when some other error occurs. This also
281: * serves as the base class for the above exceptions.
282: */
283: public function insights()
284: {
285: return $this->post('Insights');
286: }
287:
288: /**
289: * @param $service $service The name of the service to use.
290: * @return mixed The model class for the service.
291: * @throws InvalidInputException when the request has missing or invalid
292: * data.
293: * @throws AuthenticationException when there is an issue authenticating the
294: * request.
295: * @throws InsufficientFundsException when your account is out of funds.
296: * @throws InvalidRequestException when the request is invalid for some
297: * other reason, e.g., invalid JSON in the POST.
298: * @throws HttpException when an unexpected HTTP error occurs.
299: * @throws WebServiceException when some other error occurs. This also
300: * serves as the base class for the above exceptions.
301: */
302: private function post($service)
303: {
304: if (!isset($this->content['device']['ip_address'])) {
305: throw new InvalidInputException(
306: 'Key ip_address must be present in device'
307: );
308: }
309: $url = self::$basePath . strtolower($service);
310: $class = "MaxMind\\MinFraud\\Model\\" . $service;
311: return new $class(
312: $this->client->post($service, $url, $this->content),
313: $this->locales
314: );
315: }
316:
317: /**
318: * @return string The prefix for the User-Agent header.
319: */
320: private function userAgent()
321: {
322: return 'minFraud-API/' . MinFraud::VERSION;
323: }
324:
325: /**
326: * @param string $className The name of the class (but not the namespace)
327: * @param string $key The key in the transaction array to set
328: * @param array $values The values to validate
329: * @return MinFraud
330: * @throws InvalidInputException when $values does not validate
331: */
332: private function validateAndAdd($className, $key, $values)
333: {
334: if ($this->validateInput) {
335: $this->validate($className, $values);
336: }
337: $new = clone $this;
338: $new->content[$key] = $values;
339: return $new;
340: }
341:
342: /**
343: * @param string $className The name of the class (but not the namespace)
344: * @param array $values The values to validate
345: * @throws InvalidInputException when $values does not validate
346: */
347: private function validate($className, $values)
348: {
349: $class = '\\MaxMind\\MinFraud\\Validation\\Rules\\' . $className;
350: $validator = new $class();
351: try {
352: $validator->check($values);
353: } catch (ValidationExceptionInterface $exception) {
354: throw new InvalidInputException(
355: $exception->getMessage(),
356: $exception->getCode()
357: );
358: }
359: }
360: }
361: