Completed
Push — develop-3.2.x ( 543170...49f962 )
by Mario
02:11
created

ipn_paypal   A

Complexity

Total Complexity 35

Size/Duplication

Total Lines 352
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 2

Importance

Changes 0
Metric Value
wmc 35
lcom 1
cbo 2
dl 0
loc 352
rs 9.6
c 0
b 0
f 0

16 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 8 1
A initiate_paypal_connection() 0 12 2
A curl_post() 0 41 3
A is_remote_detected() 0 12 2
A set_u_paypal() 0 4 1
A get_remote_used() 0 4 1
A get_report_response() 0 4 1
A get_response_status() 0 4 1
A check_response_status() 0 4 1
A is_curl_strcmp() 0 4 2
A check_curl() 0 20 5
A check_tls() 0 21 4
B check_https() 0 20 6
A set_remote_detected() 0 5 1
A check_curl_info() 0 9 2
A set_curl_info() 0 9 2
1
<?php
2
/**
3
 *
4
 * PayPal Donation extension for the phpBB Forum Software package.
5
 *
6
 * @copyright (c) 2015 Skouat
7
 * @license GNU General Public License, version 2 (GPL-2.0)
8
 *
9
 * Special Thanks to the following individuals for their inspiration:
10
 *    David Lewis (Highway of Life) http://startrekguide.com
11
 *    Micah Carrick ([email protected]) http://www.micahcarrick.com
12
 */
13
14
namespace skouat\ppde\controller;
15
16
use phpbb\config\config;
17
use phpbb\language\language;
18
use phpbb\request\request;
19
20
class ipn_paypal
21
{
22
	protected $config;
23
	protected $language;
24
	protected $ppde_ext_manager;
25
	protected $ppde_ipn_log;
26
	protected $request;
27
	/**
28
	 * @var array
29
	 */
30
	private $curl_fsock = array('curl' => false,
31
								'none' => true);
32
	/**
33
	 * Full PayPal response for include in text report
34
	 *
35
	 * @var string
36
	 */
37
	private $report_response = '';
38
	/**
39
	 * PayPal response (VERIFIED or INVALID)
40
	 *
41
	 * @var string
42
	 */
43
	private $response = '';
44
	/**
45
	 * PayPal response status (code 200 or other)
46
	 *
47
	 * @var string
48
	 */
49
	private $response_status = '';
50
	/**
51
	 * PayPal URL
52
	 * Could be Sandbox URL ou normal PayPal URL.
53
	 *
54
	 * @var string
55
	 */
56
	private $u_paypal = '';
57
58
	/**
59
	 * Constructor
60
	 *
61
	 * @param config            $config           Config object
62
	 * @param language          $language         Language user object
63
	 * @param extension_manager $ppde_ext_manager Extension manager object
64
	 * @param ipn_log           $ppde_ipn_log     IPN log
65
	 * @param request           $request          Request object
66
	 *
67
	 * @access public
68
	 */
69
	public function __construct(config $config, language $language, extension_manager $ppde_ext_manager, ipn_log $ppde_ipn_log, request $request)
70
	{
71
		$this->config = $config;
72
		$this->language = $language;
73
		$this->ppde_ext_manager = $ppde_ext_manager;
74
		$this->ppde_ipn_log = $ppde_ipn_log;
75
		$this->request = $request;
76
	}
77
78
	/**
79
	 * Select the appropriate method to communicate with PayPal
80
	 * We use cURL. If it is not available we log an error
81
	 *
82
	 * @param string $args_return_uri
83
	 * @param array  $data
84
	 *
85
	 * @return void
86
	 * @access public
87
	 */
88
	public function initiate_paypal_connection($args_return_uri, $data)
89
	{
90
		if ($this->curl_fsock['curl'])
91
		{
92
			$this->curl_post($args_return_uri);
93
			$this->response;
94
		}
95
		else
96
		{
97
			$this->ppde_ipn_log->log_error($this->language->lang('NO_CONNECTION_DETECTED'), $this->ppde_ipn_log->is_use_log_error(), true, E_USER_ERROR, $data);
98
		}
99
	}
100
101
	/**
102
	 * Post Back Using cURL
103
	 *
104
	 * Sends the post back to PayPal using the cURL library. Called by
105
	 * the validate_transaction() method if the curl_fsock['curl'] property is true.
106
	 * Throws an exception if the post fails. Populates the response and response_status properties on success.
107
	 *
108
	 * @param  string $encoded_data The post data as a URL encoded string
109
	 *
110
	 * @return void
111
	 * @access private
112
	 */
113
	private function curl_post($encoded_data)
114
	{
115
		$ch = curl_init($this->u_paypal);
116
		curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
117
		curl_setopt($ch, CURLOPT_POST, true);
118
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
119
		curl_setopt($ch, CURLOPT_POSTFIELDS, $encoded_data);
120
		curl_setopt($ch, CURLOPT_SSLVERSION, 6);
121
		curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 1);
122
		curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
123
		curl_setopt($ch, CURLOPT_FORBID_REUSE, true);
124
		curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 30);
125
		curl_setopt($ch, CURLOPT_HTTPHEADER, array(
126
			'User-Agent: PHP-IPN-Verification-Script',
127
			'Connection: Close',
128
		));
129
130
		if ($this->ppde_ipn_log->is_use_log_error())
131
		{
132
			curl_setopt($ch, CURLOPT_HEADER, true);
133
			curl_setopt($ch, CURLINFO_HEADER_OUT, true);
134
		}
135
136
		$this->report_response = $this->response = curl_exec($ch);
137
		if (curl_errno($ch) != 0)
138
		{
139
			// cURL error
140
			$this->ppde_ipn_log->log_error($this->language->lang('CURL_ERROR', curl_errno($ch) . ' (' . curl_error($ch) . ')'), $this->ppde_ipn_log->is_use_log_error());
141
			curl_close($ch);
142
		}
143
		else
144
		{
145
			$info = curl_getinfo($ch);
146
			$this->response_status = $info['http_code'];
147
			curl_close($ch);
148
		}
149
150
		// Split response headers and payload, a better way for strcmp
151
		$tokens = explode("\r\n\r\n", trim($this->response));
152
		$this->response = trim(end($tokens));
153
	}
154
155
	/**
156
	 * Set property 'curl_fsock' to use cURL.
157
	 * If cURL is not available we use default value of the property 'curl_fsock'.
158
	 *
159
	 * @return bool
0 ignored issues
show
Documentation introduced by
Should the return type not be false|integer|string?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
160
	 * @access public
161
	 */
162
	public function is_remote_detected()
163
	{
164
		if ($this->config['ppde_curl_detected'])
165
		{
166
			$this->curl_fsock = array(
167
				'curl' => (bool) true,
168
				'none' => (bool) false,
169
			);
170
		}
171
172
		return array_search(true, $this->curl_fsock);
173
	}
174
175
	/**
176
	 * Set the property '$u_paypal'
177
	 *
178
	 * @param string $u_paypal
179
	 *
180
	 * @return void
181
	 * @access public
182
	 */
183
	public function set_u_paypal($u_paypal)
184
	{
185
		$this->u_paypal = (string) $u_paypal;
186
	}
187
188
	/**
189
	 * Get the service that will be used to contact PayPal
190
	 * Returns the name of the key that is set to true.
191
	 *
192
	 * @return string
193
	 * @access public
194
	 */
195
	public function get_remote_used()
196
	{
197
		return array_search(true, $this->curl_fsock);
198
	}
199
200
	/**
201
	 * Full PayPal response for include in text report
202
	 *
203
	 * @return string
204
	 * @access public
205
	 */
206
	public function get_report_response()
207
	{
208
		return $this->report_response;
209
	}
210
211
	/**
212
	 * PayPal response status
213
	 *
214
	 * @return string
215
	 * @access public
216
	 */
217
	public function get_response_status()
218
	{
219
		return $this->response_status;
220
	}
221
222
	/**
223
	 * Check if the response status is equal to "200".
224
	 *
225
	 * @return bool
226
	 * @access public
227
	 */
228
	public function check_response_status()
229
	{
230
		return $this->response_status != 200;
231
	}
232
233
	/**
234
	 * If cURL is available we use strcmp() to get the Pay
235
	 *
236
	 * @param string $arg
237
	 *
238
	 * @return bool
239
	 * @access public
240
	 */
241
	public function is_curl_strcmp($arg)
242
	{
243
		return $this->curl_fsock['curl'] && (strcmp($this->response, $arg) === 0);
244
	}
245
246
	/**
247
	 * Check if cURL is available
248
	 *
249
	 * @return bool
250
	 * @access public
251
	 */
252
	public function check_curl()
253
	{
254
		if (function_exists('curl_init') && function_exists('curl_exec'))
255
		{
256
			$ext_meta = $this->ppde_ext_manager->get_ext_meta();
257
258
			$ch = curl_init($ext_meta['extra']['version-check']['host']);
259
260
			curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
261
262
			$this->response = curl_exec($ch);
263
			$this->response_status = strval(curl_getinfo($ch, CURLINFO_HTTP_CODE));
264
265
			curl_close($ch);
266
267
			return ($this->response !== false || $this->response_status !== '0') ? true : false;
268
		}
269
270
		return false;
271
	}
272
273
	/**
274
	 * Check if PayPal connection use TLS 1.2 and HTTP 1.1
275
	 *
276
	 * @access public
277
	 */
278
	public function check_tls()
279
	{
280
		// Reset settings to false
281
		$this->config->set('ppde_tls_detected', false);
282
283
		if (function_exists('curl_init') && function_exists('curl_exec'))
284
		{
285
			$ch = curl_init('https://tlstest.paypal.com/');
286
287
			curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
288
289
			$response = curl_exec($ch);
290
291
			curl_close($ch);
292
293
			if ($response === 'PayPal_Connection_OK')
294
			{
295
				$this->config->set('ppde_tls_detected', true);
296
			}
297
		}
298
	}
299
300
	/**
301
	 * Check if HTTPS Protocol is enabled
302
	 *
303
	 * @return array|bool
304
	 * @access public
305
	 */
306
	public function check_https()
307
	{
308
		if ($this->request->is_set('HTTPS', \phpbb\request\request_interface::SERVER))
309
		{
310
			if ('on' == strtolower($this->request->variable('HTTPS', \phpbb\request\request_interface::SERVER)))
311
			{
312
				return true;
313
			}
314
315
			if ('1' == $this->request->variable('HTTPS', \phpbb\request\request_interface::SERVER))
316
			{
317
				return true;
318
			}
319
		}
320
		else if ($this->request->is_set('SERVER_PORT', \phpbb\request\request_interface::SERVER) && ('443' == $this->request->variable('SERVER_PORT', \phpbb\request\request_interface::SERVER)))
321
		{
322
			return true;
323
		}
324
		return false;
325
	}
326
327
328
	/**
329
	 * Set config value for cURL and HTTPS
330
	 *
331
	 * @return void
332
	 * @access public
333
	 */
334
	public function set_remote_detected()
335
	{
336
		$this->config->set('ppde_curl_detected', $this->check_curl());
337
		$this->config->set('ppde_https_detected', $this->check_https());
338
	}
339
340
	/**
341
	 * Get cURL version if available
342
	 *
343
	 * @return array|bool
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use array|false.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
344
	 * @access public
345
	 */
346
	public function check_curl_info()
347
	{
348
		if (function_exists('curl_version'))
349
		{
350
			return curl_version();
351
		}
352
353
		return false;
354
	}
355
356
	/**
357
	 * Set config value for cURL version
358
	 *
359
	 * @return void
360
	 * @access public
361
	 */
362
	public function set_curl_info()
363
	{
364
		// Get cURL version informations
365
		if ($curl_info = $this->check_curl_info())
366
		{
367
			$this->config->set('ppde_curl_version', $curl_info['version']);
368
			$this->config->set('ppde_curl_ssl_version', $curl_info['ssl_version']);
369
		}
370
	}
371
}
372