Initial commit
This commit is contained in:
143
ipn/PaypalIPN.php
Normal file
143
ipn/PaypalIPN.php
Normal file
@@ -0,0 +1,143 @@
|
||||
<?php
|
||||
|
||||
class PaypalIPN
|
||||
{
|
||||
/** @var bool Indicates if the sandbox endpoint is used. */
|
||||
private $use_sandbox = false;
|
||||
/** @var bool Indicates if the local certificates are used. */
|
||||
private $use_local_certs = false;
|
||||
|
||||
/** Production Postback URL */
|
||||
const VERIFY_URI = 'https://ipnpb.paypal.com/cgi-bin/webscr';
|
||||
/** Sandbox Postback URL */
|
||||
const SANDBOX_VERIFY_URI = 'https://ipnpb.sandbox.paypal.com/cgi-bin/webscr';
|
||||
|
||||
/** Response from PayPal indicating validation was successful */
|
||||
const VALID = 'VERIFIED';
|
||||
/** Response from PayPal indicating validation failed */
|
||||
const INVALID = 'INVALID';
|
||||
|
||||
/**
|
||||
* Sets the IPN verification to sandbox mode (for use when testing,
|
||||
* should not be enabled in production).
|
||||
* @return void
|
||||
*/
|
||||
public function useSandbox()
|
||||
{
|
||||
$this->use_sandbox = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets curl to use php curl's built in certs (may be required in some
|
||||
* environments).
|
||||
* @return void
|
||||
*/
|
||||
public function usePHPCerts()
|
||||
{
|
||||
$this->use_local_certs = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine endpoint to post the verification data to.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getPaypalUri()
|
||||
{
|
||||
if ($this->use_sandbox) {
|
||||
return self::SANDBOX_VERIFY_URI;
|
||||
} else {
|
||||
return self::VERIFY_URI;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Verification Function
|
||||
* Sends the incoming post data back to PayPal using the cURL library.
|
||||
*
|
||||
* @return bool
|
||||
* @throws Exception
|
||||
*/
|
||||
public function verifyIPN()
|
||||
{
|
||||
if ( ! count($_POST)) {
|
||||
throw new Exception("Missing POST Data");
|
||||
}
|
||||
|
||||
$raw_post_data = file_get_contents('php://input');
|
||||
$raw_post_array = explode('&', $raw_post_data);
|
||||
$myPost = array();
|
||||
foreach ($raw_post_array as $keyval) {
|
||||
$keyval = explode('=', $keyval);
|
||||
if (count($keyval) == 2) {
|
||||
// Since we do not want the plus in the datetime string to be encoded to a space, we manually encode it.
|
||||
if ($keyval[0] === 'payment_date') {
|
||||
if (substr_count($keyval[1], '+') === 1) {
|
||||
$keyval[1] = str_replace('+', '%2B', $keyval[1]);
|
||||
}
|
||||
}
|
||||
$myPost[$keyval[0]] = urldecode($keyval[1]);
|
||||
}
|
||||
}
|
||||
|
||||
// Build the body of the verification post request, adding the _notify-validate command.
|
||||
$req = 'cmd=_notify-validate';
|
||||
$get_magic_quotes_exists = false;
|
||||
if (function_exists('get_magic_quotes_gpc')) {
|
||||
$get_magic_quotes_exists = true;
|
||||
}
|
||||
foreach ($myPost as $key => $value) {
|
||||
if ($get_magic_quotes_exists == true && get_magic_quotes_gpc() == 1) {
|
||||
$value = urlencode(stripslashes($value));
|
||||
} else {
|
||||
$value = urlencode($value);
|
||||
}
|
||||
$req .= "&$key=$value";
|
||||
}
|
||||
|
||||
// Post the data back to PayPal, using curl. Throw exceptions if errors occur.
|
||||
$ch = curl_init($this->getPaypalUri());
|
||||
curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
|
||||
curl_setopt($ch, CURLOPT_POST, 1);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, $req);
|
||||
curl_setopt($ch, CURLOPT_SSLVERSION, 6);
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 1);
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
|
||||
|
||||
// This is often required if the server is missing a global cert bundle, or is using an outdated one.
|
||||
if ($this->use_local_certs) {
|
||||
curl_setopt($ch, CURLOPT_CAINFO, __DIR__ . "/cert/cacert.pem");
|
||||
}
|
||||
curl_setopt($ch, CURLOPT_FORBID_REUSE, 1);
|
||||
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 30);
|
||||
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
|
||||
'User-Agent: PHP-IPN-Verification-Script',
|
||||
'Connection: Close',
|
||||
));
|
||||
$res = curl_exec($ch);
|
||||
if ( ! ($res)) {
|
||||
$errno = curl_errno($ch);
|
||||
$errstr = curl_error($ch);
|
||||
curl_close($ch);
|
||||
throw new Exception("cURL error: [$errno] $errstr");
|
||||
}
|
||||
|
||||
$info = curl_getinfo($ch);
|
||||
$http_code = $info['http_code'];
|
||||
if ($http_code != 200) {
|
||||
throw new Exception("PayPal responded with http code $http_code");
|
||||
}
|
||||
|
||||
curl_close($ch);
|
||||
|
||||
// Check if PayPal verifies the IPN data, and if so, return true.
|
||||
if ($res == self::VALID) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
423
ipn/ipn.php
Normal file
423
ipn/ipn.php
Normal file
@@ -0,0 +1,423 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
|
||||
Copyright 2018 Murray Hayes
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
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.
|
||||
|
||||
3. Neither the name of the copyright holder nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"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
|
||||
COPYRIGHT HOLDER OR CONTRIBUTORS 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.
|
||||
|
||||
*/
|
||||
|
||||
namespace Listener;
|
||||
|
||||
include_once '../consts.php';
|
||||
include_once '../database.php';
|
||||
|
||||
// Set this to true to use the sandbox endpoint during testing:
|
||||
$enable_sandbox = true;
|
||||
|
||||
// Use this to specify all of the email addresses that you have attached to paypal:
|
||||
// $my_email_addresses = array("my_email_address@gmail.com", "my_email_address2@gmail.com", "my_email_address3@gmail.com");
|
||||
|
||||
// Set this to true to send a confirmation email:
|
||||
$send_confirmation_email = false;
|
||||
$confirmation_email_address = "My Name <my_email_address@gmail.com>";
|
||||
$from_email_address = "My Name <my_email_address@gmail.com>";
|
||||
|
||||
// Set this to true to save a log file:
|
||||
$save_log_file = true;
|
||||
$log_file_dir = __DIR__ . "/logs";
|
||||
|
||||
|
||||
require('PaypalIPN.php');
|
||||
|
||||
use PaypalIPN;
|
||||
|
||||
$ipn = new PaypalIPN();
|
||||
|
||||
date_default_timezone_set($timeZone);
|
||||
|
||||
// Use the sandbox endpoint during testing.
|
||||
if ($enable_sandbox)
|
||||
$ipn->useSandbox();
|
||||
|
||||
//$verified = $ipn->verifyIPN();
|
||||
$verified = TRUE;
|
||||
if ($verified)
|
||||
{
|
||||
/*
|
||||
* Process IPN
|
||||
* A list of variables is available here:
|
||||
* https://developer.paypal.com/webapps/developer/docs/classic/ipn/integration-guide/IPNandPDTVariables/
|
||||
*/
|
||||
|
||||
/*
|
||||
if (isset($_POST['protection_eligibility']) && isset($_POST['payer_id']) &&
|
||||
isset($_POST['payment_date']) && isset($_POST['payment_status']) &&
|
||||
isset($_POST['first_name']) && isset($_POST['last_name']) &&
|
||||
isset($_POST['notify_version']) && isset($_POST['verify_sign']) &&
|
||||
isset($_POST['payer_email']) && isset($_POST['txn_id']) &&
|
||||
isset($_POST['payment_type']) && isset($_POST['receiver_email']) &&
|
||||
isset($_POST['receiver_id']) && isset($_POST['txn_type']))
|
||||
{
|
||||
if ($_POST['protection_eligibility'] === 'Eligible')
|
||||
$protection_eligibility = TRUE;
|
||||
else
|
||||
$protection_eligibility = FALSE;
|
||||
$payer_id = $_POST['payer_id'];
|
||||
$payment_date = $_POST['payment_date'];
|
||||
if ($_POST['payment_status'] === 'Completed')
|
||||
$payment_status = TRUE;
|
||||
else
|
||||
$payment_status = FALSE;
|
||||
$first_name = $_POST['first_name'];
|
||||
$last_name = $_POST['last_name'];
|
||||
$notify_version = $_POST['notify_version'];
|
||||
$verify_sign = $_POST['verify_sign'];
|
||||
$payer_email = $_POST['payer_email'];
|
||||
$txn_id = $_POST['txn_id'];
|
||||
$payment_type = $_POST['payment_type'];
|
||||
$receiver_email = $_POST['receiver_email'];
|
||||
$receiver_id = $_POST['receiver_id'];
|
||||
$txn_type = $_POST['txn_type'];
|
||||
|
||||
if (isset($_POST['mc_gross']))
|
||||
$mc_gross = (float) $_POST['mc_gross'];
|
||||
else
|
||||
$mc_gross = (float) 0.0;
|
||||
|
||||
if (isset($_POST['address_status']) && $_POST['address_status'] === 'confirmed')
|
||||
$address_status = TRUE;
|
||||
else
|
||||
$address_status = FALSE;
|
||||
|
||||
if (isset($_POST['tax']))
|
||||
$tax = (float) $_POST['tax'];
|
||||
else
|
||||
$tax = (float) 0.00;
|
||||
|
||||
if (isset($_POST['address_street']))
|
||||
$address_street = $_POST['address_street'];
|
||||
else
|
||||
$address_street = NULL;
|
||||
|
||||
if (isset($_POST['charset']))
|
||||
$charset = $_POST['charset'];
|
||||
else
|
||||
$charset = 'utf-8';
|
||||
|
||||
if (isset($_POST['address_zip']))
|
||||
$address_zip = $_POST['address_zip'];
|
||||
else
|
||||
$address_zip = NULL;
|
||||
|
||||
if (isset($_POST['mc_fee']))
|
||||
$mc_fee = (float) $_POST['mc_fee'];
|
||||
else
|
||||
$mc_fee = (float) 0.0;
|
||||
|
||||
if (isset($_POST['address_country_code']))
|
||||
$address_country_code = $_POST['address_country_code'];
|
||||
else
|
||||
$address_country_code = 'CA';
|
||||
|
||||
if (isset($_POST['address_name']))
|
||||
$address_name = $_POST['address_name'];
|
||||
else
|
||||
$address_name = NULL;
|
||||
|
||||
if (isset($_POST['cusom']))
|
||||
$custom = $_POST['custom'];
|
||||
else
|
||||
$custom = NULL;
|
||||
|
||||
if (isset($_POST['payer_satus']) && $_POST['payer_satus'] === 'verified')
|
||||
$payer_status = TRUE;
|
||||
else
|
||||
$payer_status = FALSE;
|
||||
|
||||
if (isset($_POST['address_country']))
|
||||
$address_country = $_POST['address_country'];
|
||||
else
|
||||
$address_country = NULL;
|
||||
|
||||
if (isset($_POST['address_city']))
|
||||
$address_city = $_POST['address_city'];
|
||||
else
|
||||
$address_city = NULL;
|
||||
|
||||
if (isset($_POST['quantity']))
|
||||
$quantity = (int) $_POST['quantity'];
|
||||
else
|
||||
$quantity = (int) -1;
|
||||
|
||||
if (isset($_POST['address_state']))
|
||||
$address_state = $_POST['address_state'];
|
||||
else
|
||||
$address_state = NULL;
|
||||
|
||||
if (isset($_POST['payment_fee']))
|
||||
$payment_fee = (float) $_POST['payment_fee'];
|
||||
else
|
||||
$payment_fee = (float) 0.00;
|
||||
|
||||
if (isset($_POST['item_name']))
|
||||
$item_name = $_POST['item_name'];
|
||||
else
|
||||
$item_name = NULL;
|
||||
|
||||
if (isset($_POST['mc_currency']))
|
||||
$mc_currency = $_POST['mc_currency'];
|
||||
else
|
||||
$mc_currency = 'CAD';
|
||||
|
||||
if (isset($_POST['item_number']))
|
||||
$item_number = $_POST['item_number'];
|
||||
else
|
||||
$item_number = NULL;
|
||||
|
||||
if (isset($_POST['residence_country']))
|
||||
$residence_country = $_POST['residence_country'];
|
||||
else
|
||||
$residence_country = 'CA';
|
||||
|
||||
if (isset($_POST['test_ipn']))
|
||||
$test_ipn = $_POST['test_ipn'];
|
||||
else
|
||||
$test_ipn = NULL;
|
||||
|
||||
if (isset($_POST['handling_amount']))
|
||||
$handling_amount = (float) $_POST['handling_amount'];
|
||||
else
|
||||
$handling_amount = (float) 0.00;
|
||||
|
||||
if (isset($_POST['transaction_subject']))
|
||||
$transaction_subject = $_POST['transaction_subject'];
|
||||
else
|
||||
$transaction_subject = NULL;
|
||||
|
||||
if (isset($_POST['payment_gross']))
|
||||
$payment_gross = (float) $_POST['payment_gross'];
|
||||
else
|
||||
$payment_gross = (float) 0.00;
|
||||
|
||||
if (isset($_POST['shipping']))
|
||||
$shipping = $_POST['shipping'];
|
||||
else
|
||||
$shippling = (float) 0.00;
|
||||
|
||||
$ipnID = receiveInstantPaypalNotification($item_name, $item_number, (int) $quantity,
|
||||
$mc_currency, $mc_gross, $mc_fee, $payment_type, $payment_date,
|
||||
$payment_gross, $payment_fee, $shipping, $handling_amount, $tax,
|
||||
$payment_status, $protection_eligibility, $payer_id, $payer_email,
|
||||
$first_name, $last_name, $address_street, $address_city, $address_state,
|
||||
$address_country, $address_country_code, $address_zip, $address_status,
|
||||
$address_name, $payer_status, $residence_country, $receiver_id,
|
||||
$receiver_email, $transaction_subject, $custom, $charset, $txn_id,
|
||||
$txn_type, $notify_version, $verify_sign, $test_ipn);
|
||||
processInstantPaypalNotification($ipnID);
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
* Attempt number 2
|
||||
*/
|
||||
|
||||
$data = file_get_contents('php://input');
|
||||
if (isset($_POST['txn_type']) && isset($_POST['verify_sign']) && ($data !== FALSE))
|
||||
{
|
||||
$txn_type = $_POST['txn_type'];
|
||||
$verify_sign = $_POST['verify_sign'];
|
||||
if (isset($_POST['txn_id']))
|
||||
$txn_id = $_POST['txn_id'];
|
||||
else
|
||||
$txn_id = NULL;
|
||||
|
||||
$ipnID = receiveInstantPaypalNotification($txn_type, $txn_id, $verify_sign, $data);
|
||||
//print ("ipnID: $ipnID");
|
||||
if (isset($_POST['payer_id']))
|
||||
$payer_id = $_POST['payer_id'];
|
||||
else
|
||||
$payer_id = NULL;
|
||||
if (isset($_POST['payment_date']))
|
||||
$payment_date = date_format(date_create($_POST['payment_date']), $dbDateTimeFormat);
|
||||
else
|
||||
$payment_date = NULL;
|
||||
if (isset($_POST['payment_status']))
|
||||
$payment_status = $_POST['payment_status'];
|
||||
else
|
||||
$payment_status = NULL;
|
||||
if (isset($_POST['first_name']))
|
||||
$first_name = $_POST['first_name'];
|
||||
else
|
||||
$first_name = NULL;
|
||||
if (isset($_POST['last_name']))
|
||||
$last_name = $_POST['last_name'];
|
||||
else
|
||||
$last_name = NULL;
|
||||
if (isset($_POST['payer_email']))
|
||||
$payer_email = $_POST['payer_email'];
|
||||
else
|
||||
$payer_email = NULL;
|
||||
if (isset($_POST['mc_currency']))
|
||||
$mc_currency = $_POST['mc_currency'];
|
||||
else
|
||||
$mc_currency = NULL;
|
||||
if (isset($_POST['mc_gross']))
|
||||
$mc_gross = $_POST['mc_gross'];
|
||||
else
|
||||
$mc_gross = NULL;
|
||||
if (isset($_POST['mc_fee']))
|
||||
$mc_fee = $_POST['mc_fee'];
|
||||
else
|
||||
$mc_fee = NULL;
|
||||
if (isset($_POST['address_street']))
|
||||
$address_street = $_POST['address_street'];
|
||||
else
|
||||
$address_street = NULL;
|
||||
if (isset($_POST['address_city']))
|
||||
$address_city = $_POST['address_city'];
|
||||
else
|
||||
$address_city = NULL;
|
||||
if (isset($_POST['address_state']))
|
||||
$address_state = $_POST['address_state'];
|
||||
else
|
||||
$address_state = NULL;
|
||||
if (isset($_POST['address_country']))
|
||||
$address_country = $_POST['address_country'];
|
||||
else
|
||||
$address_country = NULL;
|
||||
if (isset($_POST['address_country_code']))
|
||||
$address_country_code = $_POST['address_country_code'];
|
||||
else
|
||||
$address_country_code = NULL;
|
||||
if (isset($_POST['address_zip']))
|
||||
$address_zip = $_POST['address_zip'];
|
||||
else
|
||||
$address_zip = NULL;
|
||||
if (isset($_POST['address_country']))
|
||||
$address_country = $_POST['address_country'];
|
||||
else
|
||||
$address_country = NULL;
|
||||
if (isset($_POST['contact_phone']))
|
||||
$contact_phone = $_POST['contact_phone'];
|
||||
else
|
||||
$contact_phone = NULL;
|
||||
if (isset($_POST['custom']))
|
||||
$custom = $_POST['custom'];
|
||||
else
|
||||
$custom = NULL;
|
||||
if (isset($_POST['receipt_id']))
|
||||
$receipt_id = $_POST['receipt_id'];
|
||||
else
|
||||
$receipt_id = NULL;
|
||||
if (isset($_POST['payer_status']))
|
||||
$payer_status = $_POST['payer_status'];
|
||||
else
|
||||
$payer_status = NULL;
|
||||
if (isset($_POST['quantity']))
|
||||
$quantity = $_POST['quantity'];
|
||||
else
|
||||
$quantity = NULL;
|
||||
if (isset($_POST['payment_type']))
|
||||
$payment_type = $_POST['payment_type'];
|
||||
else
|
||||
$payment_type = NULL;
|
||||
if (isset($_POST['receiver_email']))
|
||||
$receiver_email = $_POST['receiver_email'];
|
||||
else
|
||||
$receiver_email = NULL;
|
||||
if (isset($_POST['receiver_id']))
|
||||
$receiver_id = $_POST['receiver_id'];
|
||||
else
|
||||
$receiver_id = NULL;
|
||||
if (isset($_POST['item_name']))
|
||||
$item_name = $_POST['item_name'];
|
||||
else
|
||||
$item_name = NULL;
|
||||
if (isset($_POST['item_number']))
|
||||
$item_number = $_POST['item_number'];
|
||||
else
|
||||
$item_number = NULL;
|
||||
if (isset($_POST['residence_country']))
|
||||
$residence_country = $_POST['residence_country'];
|
||||
else
|
||||
$residence_country = NULL;
|
||||
if (isset($_POST['charset']))
|
||||
$charset = $_POST['charset'];
|
||||
else
|
||||
$charset = NULL;
|
||||
if (isset($_POST['transaction_subject']))
|
||||
$transaction_subject = $_POST['transaction_subject'];
|
||||
else
|
||||
$transaction_subject = NULL;
|
||||
if (isset($_POST['memo']))
|
||||
$memo = $_POST['memo'];
|
||||
else
|
||||
$memo = NULL;
|
||||
if (isset($_POST['test_ipn']))
|
||||
$test_ipn = $_POST['test_ipn'];
|
||||
else
|
||||
$test_ipn = NULL;
|
||||
if (isset($_POST['notify_version']))
|
||||
$notify_version = $_POST['notify_version'];
|
||||
else
|
||||
$notify_version = NULL;
|
||||
if (isset($_POST['parent_txn_id']))
|
||||
$parent_txn_id = $_POST['parent_txn_id'];
|
||||
else
|
||||
$parent_txn_id = NULL;
|
||||
if (isset($_POST['initial_payment_txn_id']))
|
||||
$initial_payment_txn_id = $_POST['initial_payment_txn_id'];
|
||||
else
|
||||
$initial_payment_txn_id = NULL;
|
||||
if (isset($_POST['recurring_payment_id']))
|
||||
$recurring_payment_id = $_POST['recurring_payment_id'];
|
||||
else
|
||||
$recurring_payment_id = NULL;
|
||||
/* if (isset($_POST['address_country']))
|
||||
$address_country = $_POST['address_country'];
|
||||
else
|
||||
$address_country = NULL;*/
|
||||
insertInstantPaypalNotificationData($ipnID, $payer_id, $payment_date,
|
||||
$payment_status, $first_name, $last_name, $payer_email, $mc_currency,
|
||||
$mc_gross, $mc_fee, $address_street, $address_city, $address_country,
|
||||
$address_state, $address_country_code, $address_zip, $contact_phone,
|
||||
$custom, $receipt_id, $payer_status, $quantity, $payment_type,
|
||||
$receiver_email, $receiver_id, $item_name, $item_number,
|
||||
$residence_country, $charset, $transaction_subject, $memo, $test_ipn,
|
||||
$notify_version, $parent_txn_id, $initial_payment_txn_id, $recurring_payment_id);
|
||||
}
|
||||
}
|
||||
|
||||
// Reply with an empty 200 response to indicate to paypal the IPN was received correctly.
|
||||
header("HTTP/1.1 200 OK");
|
||||
|
||||
|
||||
?>
|
Reference in New Issue
Block a user