File: //home/slfopp7cb1df/www/sitepacket.com/system/app/Libraries/Paypal.php
<?php
namespace App\Libraries;
class Paypal {
private $paypal_live_url = "https://api-m.paypal.com/v1";
private $paypal_sandbox_url = "https://api-m.sandbox.paypal.com/v1";
private $paypal_url = "";
private $paypal_config;
private $Payment_methods_model;
private $Invoices_model;
public function __construct() {
$this->Payment_methods_model = model("App\Models\Payment_methods_model");
$this->paypal_config = $this->Payment_methods_model->get_oneline_payment_method("paypal_payments_standard");
$this->Invoices_model = model("App\Models\Invoices_model");
if ($this->paypal_config->paypal_live == "1") {
$this->paypal_url = $this->paypal_live_url;
} else {
$this->paypal_url = $this->paypal_sandbox_url;
}
}
public function get_paypal_checkout_url($data = array(), $login_user = 0) {
$invoice_id = get_array_value($data, "invoice_id");
$currency = get_array_value($data, "currency");
$payment_amount = get_array_value($data, "payment_amount");
$description = get_array_value($data, "description");
$verification_code = get_array_value($data, "verification_code");
$contact_user_id = $login_user ? $login_user : get_array_value($data, "contact_user_id");
$client_id = get_array_value($data, "client_id");
$payment_method_id = get_array_value($data, "payment_method_id");
$balance_due = get_array_value($data, "balance_due");
if (!$invoice_id) {
return false;
}
$invoice_info = $this->Invoices_model->get_one($invoice_id);
//validate public invoice information
if (!$login_user && !validate_invoice_verification_code($verification_code, array("invoice_id" => $invoice_id, "client_id" => $client_id, "contact_id" => $contact_user_id))) {
return false;
}
//check if partial payment allowed or not
if (get_setting("allow_partial_invoice_payment_from_clients")) {
$payment_amount = unformat_currency($payment_amount);
} else {
$payment_amount = $balance_due;
}
$redirect_to = "invoices/preview/$invoice_id";
if ($verification_code) {
$redirect_to = "pay_invoice/index/$verification_code";
}
//validate payment amount
if ($payment_amount < $this->paypal_config->minimum_payment_amount * 1) {
$error_message = app_lang('minimum_payment_validation_message') . " " . to_currency($this->paypal_config->minimum_payment_amount, $currency . " ");
$session = \Config\Services::session();
$session->setFlashdata("error_message", $error_message);
app_redirect($redirect_to);
}
//we'll verify the transaction with a random string code after completing the transaction
$payment_verification_code = make_random_string();
$paypal_ipn_data = array(
"verification_code" => $verification_code,
"invoice_id" => $invoice_id,
"contact_user_id" => $contact_user_id,
"client_id" => $client_id,
"payment_method_id" => $payment_method_id,
"payment_verification_code" => $payment_verification_code
);
$paypal_payment_data = array(
"intent" => "sale",
"payer" => array(
"payment_method" => "paypal"
),
"transactions" => array(
array(
"amount" => array(
"total" => $payment_amount,
"currency" => $currency,
),
"description" => $description,
"invoice_number" => $invoice_info->display_id . " - " . strtoupper(make_random_string()), //it'll give duplication error if any client wants to pay multiple times on a same invoice like partial payment
"payment_options" => array(
"allowed_payment_method" => "INSTANT_FUNDING_SOURCE"
),
),
),
"redirect_urls" => array(
"return_url" => get_uri("paypal_redirect/index/$payment_verification_code"),
"cancel_url" => get_uri($redirect_to)
)
);
$checkout_info = $this->do_request("POST", "/payments/payment", $paypal_payment_data);
if ($checkout_info->id) {
/**
so, the checkout creation is success
save ipn data to db
*/
$paypal_ipn_model = model("App\Models\Paypal_ipn_model");
$paypal_ipn_model->ci_save($paypal_ipn_data);
$checkout_url = get_array_value($checkout_info->links, "1");
$checkout_url = $checkout_url->href;
return $checkout_url;
}
}
private function common_error_handling_for_curl($result, $err) {
try {
$result = json_decode($result);
} catch (\Exception $ex) {
echo json_encode(array("success" => false, 'message' => $ex->getMessage()));
exit();
}
if ($err) {
//got curl error
echo json_encode(array("success" => false, 'message' => "cURL Error #:" . $err));
exit();
}
if (isset($result->error_description) && $result->error_description) {
//got error message from curl
echo json_encode(array("success" => false, 'message' => $result->error_description));
exit();
}
if (isset($result->error) && $result->error &&
isset($result->error->message) && $result->error->message &&
isset($result->error->code) && $result->error->code !== "InvalidAuthenticationToken") {
//got error message from curl
echo json_encode(array("success" => false, 'message' => $result->error->message));
exit();
}
return $result;
}
private function headers($access_token) {
return array(
'Authorization: Bearer ' . $access_token,
'Content-Type: application/json'
);
}
//get access token everytime since we won't get refresh token
private function get_access_token() {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $this->paypal_url . '/oauth2/token');
curl_setopt($ch, CURLOPT_HEADER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_USERPWD, $this->paypal_config->client_id . ':' . $this->paypal_config->client_secret);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query(array(
'grant_type' => 'client_credentials'
)));
$result = curl_exec($ch);
$err = curl_error($ch);
curl_close($ch);
$result = $this->common_error_handling_for_curl($result, $err);
return $result->access_token;
}
private function do_request($method, $path, $body = array()) {
if (is_array($body)) {
// Treat an empty array in the body data as if no body data was set
if (!count($body)) {
$body = '';
} else {
$body = json_encode($body);
}
}
$method = strtoupper($method);
$url = $this->paypal_url . $path;
$access_token = $this->get_access_token();
if (!$access_token) {
echo json_encode(array("success" => false, 'message' => app_lang('error_occurred')));
exit();
}
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HTTPHEADER, $this->headers($access_token));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
if (in_array($method, array('DELETE', 'PATCH', 'POST', 'PUT', 'GET'))) {
// All except DELETE can have a payload in the body
if ($method != 'DELETE' && strlen($body)) {
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
}
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
}
$result = curl_exec($ch);
$err = curl_error($ch);
curl_close($ch);
$result = $this->common_error_handling_for_curl($result, $err);
return $result;
}
public function is_valid_ipn($payment_info) {
$payment_id = get_array_value($payment_info, "paymentId");
$payer_id = get_array_value($payment_info, "PayerID");
$checkout_info = $this->do_request("POST", "/payments/payment/$payment_id/execute", array("payer_id" => $payer_id));
if (!($checkout_info && $checkout_info->id)) {
return false;
}
if ($checkout_info && $checkout_info->state === "approved") {
//so the payment is successful
return $checkout_info;
}
}
}