Passed
Push — develop-3.2.x-2.2 ( 647685...52b7f1 )
by Mario
04:22
created

core::compare()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 3
nc 2
nop 3
dl 0
loc 8
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 *
4
 * PayPal Donation extension for the phpBB Forum Software package.
5
 *
6
 * @copyright (c) 2018 Skouat
7
 * @license GNU General Public License, version 2 (GPL-2.0)
8
 *
9
 */
10
11
namespace skouat\ppde\actions;
12
13
use phpbb\config\config;
14
use phpbb\event\dispatcher_interface;
15
use phpbb\language\language;
16
use phpbb\path_helper;
17
use skouat\ppde\operators\compare;
18
19
class core
20
{
21
	const ASCII_RANGE = '1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
22
23
	/**
24
	 * Services properties declaration
25
	 */
26
	public $notification;
27
	protected $config;
28
	protected $dispatcher;
29
	protected $language;
30
	protected $path_helper;
31
	protected $php_ext;
32
	protected $ppde_entity_transaction;
33
	protected $ppde_operator_compare;
34
	protected $ppde_operator_transaction;
35
	protected $transaction_data;
36
37
	/**
38
	 * @var boolean
39
	 */
40
	private $donor_is_member = false;
41
	/**
42
	 * @var boolean
43
	 */
44
	private $is_ipn_test = false;
45
	/**
46
	 * @var array
47
	 */
48
	private $payer_data;
49
	/**
50
	 * phpBB root path
51
	 *
52
	 * @var string
53
	 */
54
	private $root_path;
55
	/**
56
	 * @var string
57
	 */
58
	private $suffix_ipn;
59
60
	/**
61
	 * Constructor
62
	 *
63
	 * @param config                              $config                    Config object
64
	 * @param language                            $language                  Language user object
65
	 * @param \skouat\ppde\notification\core      $notification              PPDE Notification object
66
	 * @param path_helper                         $path_helper               Path helper object
67
	 * @param \skouat\ppde\entity\transactions    $ppde_entity_transaction   Transaction entity object
68
	 * @param compare                             $ppde_operator_compare     Compare operator object
69
	 * @param \skouat\ppde\operators\transactions $ppde_operator_transaction Transaction operator object
70
	 * @param dispatcher_interface                $dispatcher                Dispatcher object
71
	 * @param string                              $php_ext                   phpEx
72
	 *
73
	 * @access public
74
	 */
75
	public function __construct(
76
		config $config,
77
		language $language,
78
		\skouat\ppde\notification\core $notification,
79
		path_helper $path_helper,
80
		\skouat\ppde\entity\transactions $ppde_entity_transaction,
81
		compare $ppde_operator_compare,
82
		\skouat\ppde\operators\transactions $ppde_operator_transaction,
83
		dispatcher_interface $dispatcher,
84
		$php_ext)
85
	{
86
		$this->config = $config;
87
		$this->dispatcher = $dispatcher;
88
		$this->language = $language;
89
		$this->notification = $notification;
90
		$this->path_helper = $path_helper;
91
		$this->ppde_entity_transaction = $ppde_entity_transaction;
92
		$this->ppde_operator_compare = $ppde_operator_compare;
93
		$this->ppde_operator_transaction = $ppde_operator_transaction;
94
		$this->php_ext = $php_ext;
95
96
		$this->root_path = $this->path_helper->get_phpbb_root_path();
97
	}
98
99
	/**
100
	 * Sets properties related to ipn tests
101
	 *
102
	 * @param bool $ipn_test
103
	 *
104
	 * @return void
105
	 * @access public
106
	 */
107
	public function set_ipn_test_properties($ipn_test)
108
	{
109
		$this->set_ipn_test($ipn_test);
110
		$this->set_suffix_ipn($this->is_ipn_test);
111
	}
112
113
	/**
114
	 * Sets the property $this->is_ipn_test
115
	 *
116
	 * @param bool $ipn_test
117
	 *
118
	 * @return void
119
	 * @access private
120
	 */
121
	private function set_ipn_test($ipn_test)
122
	{
123
		$this->is_ipn_test = $ipn_test ? (bool) $ipn_test : false;
124
	}
125
126
	/**
127
	 * Sets the property $this->suffix_ipn
128
	 *
129
	 * @param bool $is_ipn_test
130
	 *
131
	 * @return void
132
	 * @access private
133
	 */
134
	private function set_suffix_ipn($is_ipn_test)
135
	{
136
		$this->suffix_ipn = $is_ipn_test ? '_ipn' : '';
137
	}
138
139
	/**
140
	 * @return string
141
	 */
142
	public function get_suffix_ipn()
143
	{
144
		return ($this->get_ipn_test()) ? $this->suffix_ipn : '';
145
	}
146
147
	/**
148
	 * @return boolean
149
	 */
150
	public function get_ipn_test()
151
	{
152
		return ($this->is_ipn_test) ? (bool) $this->is_ipn_test : false;
153
	}
154
155
	/**
156
	 * Updates the amount of donation raised
157
	 *
158
	 * @return void
159
	 * @access public
160
	 */
161
	public function update_raised_amount()
162
	{
163
		$this->config->set('ppde_raised' . $this->suffix_ipn, (float) $this->config['ppde_raised' . $this->suffix_ipn] + (float) $this->net_amount($this->transaction_data['mc_gross'], $this->transaction_data['mc_fee']), true);
164
	}
165
166
	/**
167
	 * Returns the net amount of a donation
168
	 *
169
	 * @param float  $amount
170
	 * @param float  $fee
171
	 * @param string $dec_point
172
	 * @param string $thousands_sep
173
	 *
174
	 * @return string
175
	 * @access public
176
	 */
177
	public function net_amount($amount, $fee, $dec_point = '.', $thousands_sep = '')
178
	{
179
		return number_format((float) $amount - (float) $fee, 2, $dec_point, $thousands_sep);
180
	}
181
182
	/**
183
	 * Updates the Overview module statistics
184
	 *
185
	 * @return void
186
	 * @access public
187
	 */
188
	public function update_overview_stats()
189
	{
190
		$this->config->set('ppde_anonymous_donors_count' . $this->suffix_ipn, $this->get_count_result('ppde_anonymous_donors_count' . $this->suffix_ipn));
191
		$this->config->set('ppde_known_donors_count' . $this->suffix_ipn, $this->get_count_result('ppde_known_donors_count' . $this->suffix_ipn), true);
192
		$this->config->set('ppde_transactions_count' . $this->suffix_ipn, $this->get_count_result('ppde_transactions_count' . $this->suffix_ipn), true);
193
	}
194
195
	/**
196
	 * Returns count result for updating stats
197
	 *
198
	 * @param string $config_name
199
	 *
200
	 * @return int
201
	 * @access private
202
	 */
203
	private function get_count_result($config_name)
204
	{
205
		if (!$this->config->offsetExists($config_name))
206
		{
207
			trigger_error($this->language->lang('EXCEPTION_INVALID_CONFIG_NAME', $config_name), E_USER_WARNING);
208
		}
209
210
		return $this->ppde_operator_transaction->sql_query_count_result($config_name, $this->is_ipn_test);
211
	}
212
213
	/**
214
	 * Checks if the donor is a member then gets payer_data values
215
	 *
216
	 * @return void
217
	 * @access public
218
	 */
219
220
	public function is_donor_is_member()
221
	{
222
		$anonymous_user = false;
223
224
		// If the user_id is not anonymous
225
		if ($this->transaction_data['user_id'] != ANONYMOUS)
226
		{
227
			$this->donor_is_member = $this->check_donors_status('user', $this->transaction_data['user_id']);
228
229
			if (!$this->donor_is_member)
230
			{
231
				// No results, therefore the user is anonymous...
232
				$anonymous_user = true;
233
			}
234
		}
235
		else
236
		{
237
			// The user is anonymous by default
238
			$anonymous_user = true;
239
		}
240
241
		if ($anonymous_user)
242
		{
243
			// If the user is anonymous, check their PayPal email address with all known email hashes
244
			// to determine if the user exists in the database with that email
245
			$this->donor_is_member = $this->check_donors_status('email', $this->transaction_data['payer_email']);
246
		}
247
	}
248
249
	/**
250
	 * @return boolean
251
	 */
252
	public function get_donor_is_member()
253
	{
254
		return ($this->donor_is_member) ? (bool) $this->donor_is_member : false;
255
	}
256
257
	/**
258
	 * Gets donor informations (user id, username, amount donated) and returns if exists
259
	 *
260
	 * @param string     $type Allowed value : 'user' or 'email'
261
	 * @param string|int $args If $type is set to 'user', $args must be a user id.
262
	 *                         If $type is set to 'email', $args must be an email address
263
	 *
264
	 * @return bool
265
	 * @access private
266
	 */
267
	private function check_donors_status($type, $args)
268
	{
269
		$this->payer_data = $this->ppde_operator_transaction->query_donor_user_data($type, $args);
270
271
		return (bool) count($this->payer_data);
0 ignored issues
show
Bug introduced by
It seems like $this->payer_data can also be of type boolean; however, parameter $var of count() does only seem to accept Countable|array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

271
		return (bool) count(/** @scrutinizer ignore-type */ $this->payer_data);
Loading history...
272
	}
273
274
	/**
275
	 * @return array
276
	 */
277
	public function get_payer_data()
278
	{
279
		return (count($this->payer_data) != 0) ? $this->payer_data : array();
280
	}
281
282
	/**
283
	 * Updates donor member stats
284
	 *
285
	 * @return void
286
	 * @access public
287
	 */
288
	public function update_donor_stats()
289
	{
290
		if ($this->donor_is_member)
291
		{
292
			$this->update_user_stats((int) $this->payer_data['user_id'], (float) $this->payer_data['user_ppde_donated_amount'] + (float) $this->transaction_data['mc_gross']);
293
		}
294
	}
295
296
	/**
297
	 * @param int   $user_id
298
	 * @param float $amount
299
	 */
300
	public function update_user_stats($user_id, $amount)
301
	{
302
		if (!$user_id)
303
		{
304
			trigger_error($this->language->lang('EXCEPTION_INVALID_USER_ID', $user_id), E_USER_WARNING);
305
		}
306
307
		$this->ppde_operator_transaction->sql_update_user_stats($user_id, $amount);
308
	}
309
310
	/**
311
	 * Add donor to the donors group
312
	 *
313
	 * @return void
314
	 * @access public
315
	 */
316
	public function donors_group_user_add()
317
	{
318
		// We add the user to the donors group
319
		$can_use_autogroup = $this->can_use_autogroup();
320
		$group_id = (int) $this->config['ppde_ipn_group_id'];
321
		$payer_id = (int) $this->payer_data['user_id'];
322
		$payer_username = $this->payer_data['username'];
323
		$default_group = $this->config['ppde_ipn_group_as_default'];
324
		$payer_donated_amount = $this->payer_data['user_ppde_donated_amount'];
325
326
		/**
327
		 * Event to modify data before a user is added to the donors group
328
		 *
329
		 * @event skouat.ppde.donors_group_user_add_before
330
		 * @var bool    can_use_autogroup      Whether or not to add the user to the group
331
		 * @var int     group_id               The ID of the group to which the user will be added
332
		 * @var int     payer_id               The ID of the user who will we added to the group
333
		 * @var string  payer_username         The user name
334
		 * @var bool    default_group          Whether or not the group should be made default for the user
335
		 * @var float   payer_donated_amount   The user donated amount
336
		 * @since   1.0.3
337
		 * @changed 2.1.2 Added var $payer_donated_amount
338
		 */
339
		$vars = array(
340
			'can_use_autogroup',
341
			'group_id',
342
			'payer_id',
343
			'payer_username',
344
			'default_group',
345
			'payer_donated_amount',
346
		);
347
		extract($this->dispatcher->trigger_event('skouat.ppde.donors_group_user_add_before', compact($vars)));
348
349
		if ($can_use_autogroup)
350
		{
351
			if (!function_exists('group_user_add'))
352
			{
353
				include($this->root_path . 'includes/functions_user.' . $this->php_ext);
354
			}
355
356
			// Adds the user to the donors group and set as default.
357
			group_user_add($group_id, array($payer_id), array($payer_username), get_group_name($group_id), $default_group);
358
		}
359
	}
360
361
	/**
362
	 * Checks if all required settings are meet for adding the donor to the group of donors
363
	 *
364
	 * @return bool
365
	 * @access private
366
	 */
367
	private function can_use_autogroup()
368
	{
369
		return
370
			$this->autogroup_is_enabled() &&
371
			$this->donor_is_member &&
372
			$this->payment_status_is_completed() &&
373
			$this->minimum_donation_raised();
374
	}
375
376
	/**
377
	 * Checks if Autogroup could be used
378
	 *
379
	 * @return bool
380
	 * @access private
381
	 */
382
	private function autogroup_is_enabled()
383
	{
384
		return $this->config['ppde_ipn_enable'] && $this->config['ppde_ipn_autogroup_enable'];
385
	}
386
387
	/**
388
	 * Checks if payment_status is completed
389
	 *
390
	 * @return bool
391
	 * @access public
392
	 */
393
	public function payment_status_is_completed()
394
	{
395
		return $this->transaction_data['payment_status'] === 'Completed';
396
	}
397
398
	/**
399
	 * Checks if member's donation is upper or equal to the minimum defined
400
	 *
401
	 * @return bool
402
	 * @access public
403
	 */
404
	public function minimum_donation_raised()
405
	{
406
		// Updates payer_data info before checking values
407
		$this->check_donors_status('user', $this->payer_data['user_id']);
408
409
		return (float) $this->payer_data['user_ppde_donated_amount'] >= (float) $this->config['ppde_ipn_min_before_group'] ? true : false;
410
	}
411
412
	/**
413
	 * Log the transaction to the database
414
	 *
415
	 * @param array $data Transaction data array
416
	 *
417
	 * @access public
418
	 */
419
	public function log_to_db($data)
420
	{
421
		// Set the property $this->transaction_data
422
		$this->set_transaction_data($data);
423
424
		// The item number contains the user_id
425
		$this->extract_item_number_data();
426
		$this->validate_user_id();
427
428
		// Set username in extra_data property in $entity
429
		$user_ary = $this->ppde_operator_transaction->query_donor_user_data('user', $this->transaction_data['user_id']);
430
		$this->ppde_entity_transaction->set_username($user_ary['username']);
431
432
		// Set 'net_amount' in $this->transaction_data
433
		$this->transaction_data['net_amount'] = $this->net_amount($this->transaction_data['mc_gross'], $this->transaction_data['mc_fee']);
434
435
		// List the data to be thrown into the database
436
		$data = $this->ppde_operator_transaction->build_data_ary($this->transaction_data);
437
438
		// Load data in the entity
439
		$this->ppde_entity_transaction->set_entity_data($data);
440
		$this->ppde_entity_transaction->set_id($this->ppde_entity_transaction->transaction_exists());
441
442
		// Add or edit transaction data
443
		$this->ppde_entity_transaction->add_edit_data();
444
	}
445
446
	/**
447
	 * Set Transaction Data array
448
	 *
449
	 * @param array $transaction_data Array of the donation transaction.
450
	 *
451
	 * @return void
452
	 * @access public
453
	 */
454
	public function set_transaction_data($transaction_data)
455
	{
456
		if (!empty($this->transaction_data))
457
		{
458
			array_merge($this->transaction_data, $transaction_data);
459
		}
460
		else
461
		{
462
			$this->transaction_data = $transaction_data;
463
		}
464
	}
465
466
	/**
467
	 * Retrieve user_id from item_number args
468
	 *
469
	 * @return void
470
	 * @access private
471
	 */
472
	private function extract_item_number_data()
473
	{
474
		list($this->transaction_data['user_id']) = explode('_', substr($this->transaction_data['item_number'], 4), -1);
475
	}
476
477
	/**
478
	 * Avoid the user_id to be set to 0
479
	 *
480
	 * @return void
481
	 * @access private
482
	 */
483
	private function validate_user_id()
484
	{
485
		if (empty($this->transaction_data['user_id']) || !is_numeric($this->transaction_data['user_id']))
486
		{
487
			$this->transaction_data['user_id'] = ANONYMOUS;
488
		}
489
	}
490
491
	/**
492
	 * Check requirements for data value.
493
	 *
494
	 * @param array $data_ary
495
	 *
496
	 * @access public
497
	 * @return mixed
498
	 */
499
	public function set_post_data_func($data_ary)
500
	{
501
		$value = $data_ary['value'];
502
503
		foreach ($data_ary['force_settings'] as $control_point => $params)
504
		{
505
			// Calling the set_post_data_function
506
			$value = call_user_func_array(array($this, 'set_post_data_' . $control_point), array($data_ary['value'], $params));
507
		}
508
		unset($data_ary, $control_point, $params);
509
510
		return $value;
511
	}
512
513
	/**
514
	 * Check Post data length.
515
	 * Called by $this->check_post_data() method
516
	 *
517
	 * @param string $value
518
	 * @param array  $statement
519
	 *
520
	 * @return bool
521
	 * @access public
522
	 */
523
	public function check_post_data_length($value, $statement)
524
	{
525
		return $this->ppde_operator_compare->compare(strlen($value), $statement['value'], $statement['operator']);
526
	}
527
528
	/**
529
	 * Check if parsed value contains only ASCII chars.
530
	 * Return false if it contains non ASCII chars.
531
	 *
532
	 * @param $value
533
	 *
534
	 * @return bool
535
	 * @access public
536
	 */
537
	public function check_post_data_ascii($value)
538
	{
539
		// We ensure that the value contains only ASCII chars...
540
		$pos = strspn($value, self::ASCII_RANGE);
541
		$len = strlen($value);
542
543
		return $pos != $len ? false : true;
544
	}
545
546
	/**
547
	 * Check Post data content based on an array list.
548
	 * Called by $this->check_post_data() method
549
	 *
550
	 * @param string $value
551
	 * @param array  $content_ary
552
	 *
553
	 * @return bool
554
	 * @access public
555
	 */
556
	public function check_post_data_content($value, $content_ary)
557
	{
558
		return in_array($value, $content_ary) ? true : false;
559
	}
560
561
	/**
562
	 * Check if Post data is empty.
563
	 * Called by $this->check_post_data() method
564
	 *
565
	 * @param string $value
566
	 *
567
	 * @return bool
568
	 * @access public
569
	 */
570
	public function check_post_data_empty($value)
571
	{
572
		return empty($value) ? false : true;
573
	}
574
575
	/**
576
	 * Set Post data length.
577
	 * Called by $this->set_post_data() method
578
	 *
579
	 * @param string  $value
580
	 * @param integer $length
581
	 *
582
	 * @return string
583
	 * @access public
584
	 */
585
	public function set_post_data_length($value, $length)
586
	{
587
		return substr($value, 0, (int) $length);
588
	}
589
590
	/**
591
	 * Set Post data to lowercase.
592
	 * Called by $this->set_post_data() method
593
	 *
594
	 * @param string $value
595
	 * @param bool   $force
596
	 *
597
	 * @return string
598
	 * @access public
599
	 */
600
	public function set_post_data_lowercase($value, $force = false)
601
	{
602
		return $force ? strtolower($value) : $value;
603
	}
604
605
	/**
606
	 * Set Post data to date/time format.
607
	 * Called by $this->set_post_data() method
608
	 *
609
	 * @param string $value
610
	 * @param bool   $force
611
	 *
612
	 * @return string
613
	 * @access public
614
	 */
615
	public function set_post_data_strtotime($value, $force = false)
616
	{
617
		return $force ? strtotime($value) : $value;
618
	}
619
}
620