File "class-wc-gateway-paypal-ipn-handler.php"

Full path: /home/kosmetik/public_html/wp-content/plugins/woocommerce/includes/gateways/paypal/includes/class-wc-gateway-paypal-ipn-handler.php
File size: 9.84 B
MIME-type: text/x-php
Charset: utf-8

Download   Open   Edit   Advanced Editor   Back

<?php

if (!defined('ABSPATH')) {
    exit;
}
require_once dirname(__FILE__) . '/class-wc-gateway-paypal-response.php';
class WC_Gateway_Paypal_IPN_Handler extends WC_Gateway_Paypal_Response
{
    protected $receiver_email;
    public function __construct($sandbox = false, $receiver_email = '')
    {
        add_action('woocommerce_api_wc_gateway_paypal', array($this, 'check_response'));
        add_action('valid-paypal-standard-ipn-request', array($this, 'valid_response'));
        $this->receiver_email = $receiver_email;
        $this->sandbox = $sandbox;
    }
    public function check_response()
    {
        if (!empty($_POST) && $this->validate_ipn()) {
            $posted = wp_unslash($_POST);
            do_action('valid-paypal-standard-ipn-request', $posted);
            exit;
        }
        wp_die('PayPal IPN Request Failure', 'PayPal IPN', array('response' => 500));
    }
    public function valid_response($posted)
    {
        $order = !empty($posted['custom']) ? $this->get_paypal_order($posted['custom']) : false;
        if ($order) {
            $posted['payment_status'] = strtolower($posted['payment_status']);
            WC_Gateway_Paypal::log('Found order #' . $order->get_id());
            WC_Gateway_Paypal::log('Payment status: ' . $posted['payment_status']);
            if (method_exists($this, 'payment_status_' . $posted['payment_status'])) {
                call_user_func(array($this, 'payment_status_' . $posted['payment_status']), $order, $posted);
            }
        }
    }
    public function validate_ipn()
    {
        WC_Gateway_Paypal::log('Checking IPN response is valid');
        $validate_ipn = wp_unslash($_POST);
        $validate_ipn['cmd'] = '_notify-validate';
        $params = array('body' => $validate_ipn, 'timeout' => 60, 'httpversion' => '1.1', 'compress' => false, 'decompress' => false, 'user-agent' => 'WooCommerce/' . WC()->version);
        $response = wp_safe_remote_post($this->sandbox ? 'https://www.sandbox.paypal.com/cgi-bin/webscr' : 'https://www.paypal.com/cgi-bin/webscr', $params);
        WC_Gateway_Paypal::log('IPN Response: ' . wc_print_r($response, true));
        if (!is_wp_error($response) && $response['response']['code'] >= 200 && $response['response']['code'] < 300 && strstr($response['body'], 'VERIFIED')) {
            WC_Gateway_Paypal::log('Received valid response from PayPal IPN');
            return true;
        }
        WC_Gateway_Paypal::log('Received invalid response from PayPal IPN');
        if (is_wp_error($response)) {
            WC_Gateway_Paypal::log('Error response: ' . $response->get_error_message());
        }
        return false;
    }
    protected function validate_transaction_type($txn_type)
    {
        $accepted_types = array('cart', 'instant', 'express_checkout', 'web_accept', 'masspay', 'send_money', 'paypal_here');
        if (!in_array(strtolower($txn_type), $accepted_types, true)) {
            WC_Gateway_Paypal::log('Aborting, Invalid type:' . $txn_type);
            exit;
        }
    }
    protected function validate_currency($order, $currency)
    {
        if ($order->get_currency() !== $currency) {
            WC_Gateway_Paypal::log('Payment error: Currencies do not match (sent "' . $order->get_currency() . '" | returned "' . $currency . '")');
            $order->update_status('on-hold', sprintf(__('Validation error: PayPal currencies do not match (code %s).', 'woocommerce'), $currency));
            exit;
        }
    }
    protected function validate_amount($order, $amount)
    {
        if (number_format($order->get_total(), 2, '.', '') !== number_format($amount, 2, '.', '')) {
            WC_Gateway_Paypal::log('Payment error: Amounts do not match (gross ' . $amount . ')');
            $order->update_status('on-hold', sprintf(__('Validation error: PayPal amounts do not match (gross %s).', 'woocommerce'), $amount));
            exit;
        }
    }
    protected function validate_receiver_email($order, $receiver_email)
    {
        if (strcasecmp(trim($receiver_email), trim($this->receiver_email)) !== 0) {
            WC_Gateway_Paypal::log("IPN Response is for another account: {$receiver_email}. Your email is {$this->receiver_email}");
            $order->update_status('on-hold', sprintf(__('Validation error: PayPal IPN response from a different email address (%s).', 'woocommerce'), $receiver_email));
            exit;
        }
    }
    protected function payment_status_completed($order, $posted)
    {
        if ($order->has_status(wc_get_is_paid_statuses())) {
            WC_Gateway_Paypal::log('Aborting, Order #' . $order->get_id() . ' is already complete.');
            exit;
        }
        $this->validate_transaction_type($posted['txn_type']);
        $this->validate_currency($order, $posted['mc_currency']);
        $this->validate_amount($order, $posted['mc_gross']);
        $this->validate_receiver_email($order, $posted['receiver_email']);
        $this->save_paypal_meta_data($order, $posted);
        if ('completed' === $posted['payment_status']) {
            if ($order->has_status('cancelled')) {
                $this->payment_status_paid_cancelled_order($order, $posted);
            }
            if (!empty($posted['mc_fee'])) {
                $order->add_meta_data('PayPal Transaction Fee', wc_clean($posted['mc_fee']));
            }
            $this->payment_complete($order, !empty($posted['txn_id']) ? wc_clean($posted['txn_id']) : '', __('IPN payment completed', 'woocommerce'));
        } else {
            if ('authorization' === $posted['pending_reason']) {
                $this->payment_on_hold($order, __('Payment authorized. Change payment status to processing or complete to capture funds.', 'woocommerce'));
            } else {
                $this->payment_on_hold($order, sprintf(__('Payment pending (%s).', 'woocommerce'), $posted['pending_reason']));
            }
        }
    }
    protected function payment_status_pending($order, $posted)
    {
        $this->payment_status_completed($order, $posted);
    }
    protected function payment_status_failed($order, $posted)
    {
        $order->update_status('failed', sprintf(__('Payment %s via IPN.', 'woocommerce'), wc_clean($posted['payment_status'])));
    }
    protected function payment_status_denied($order, $posted)
    {
        $this->payment_status_failed($order, $posted);
    }
    protected function payment_status_expired($order, $posted)
    {
        $this->payment_status_failed($order, $posted);
    }
    protected function payment_status_voided($order, $posted)
    {
        $this->payment_status_failed($order, $posted);
    }
    protected function payment_status_paid_cancelled_order($order, $posted)
    {
        $this->send_ipn_email_notification(sprintf(__('Payment for cancelled order %s received', 'woocommerce'), '<a class="link" href="' . esc_url($order->get_edit_order_url()) . '">' . $order->get_order_number() . '</a>'), sprintf(__('Order #%s has been marked paid by PayPal IPN, but was previously cancelled. Admin handling required.', 'woocommerce'), $order->get_order_number()));
    }
    protected function payment_status_refunded($order, $posted)
    {
        if ($order->get_total() === wc_format_decimal($posted['mc_gross'] * -1, wc_get_price_decimals())) {
            $order->update_status('refunded', sprintf(__('Payment %s via IPN.', 'woocommerce'), strtolower($posted['payment_status'])));
            $this->send_ipn_email_notification(sprintf(__('Payment for order %s refunded', 'woocommerce'), '<a class="link" href="' . esc_url($order->get_edit_order_url()) . '">' . $order->get_order_number() . '</a>'), sprintf(__('Order #%1$s has been marked as refunded - PayPal reason code: %2$s', 'woocommerce'), $order->get_order_number(), $posted['reason_code']));
        }
    }
    protected function payment_status_reversed($order, $posted)
    {
        $order->update_status('on-hold', sprintf(__('Payment %s via IPN.', 'woocommerce'), wc_clean($posted['payment_status'])));
        $this->send_ipn_email_notification(sprintf(__('Payment for order %s reversed', 'woocommerce'), '<a class="link" href="' . esc_url($order->get_edit_order_url()) . '">' . $order->get_order_number() . '</a>'), sprintf(__('Order #%1$s has been marked on-hold due to a reversal - PayPal reason code: %2$s', 'woocommerce'), $order->get_order_number(), wc_clean($posted['reason_code'])));
    }
    protected function payment_status_canceled_reversal($order, $posted)
    {
        $this->send_ipn_email_notification(sprintf(__('Reversal cancelled for order #%s', 'woocommerce'), $order->get_order_number()), sprintf(__('Order #%1$s has had a reversal cancelled. Please check the status of payment and update the order status accordingly here: %2$s', 'woocommerce'), $order->get_order_number(), esc_url($order->get_edit_order_url())));
    }
    protected function save_paypal_meta_data($order, $posted)
    {
        if (!empty($posted['payment_type'])) {
            update_post_meta($order->get_id(), 'Payment type', wc_clean($posted['payment_type']));
        }
        if (!empty($posted['txn_id'])) {
            update_post_meta($order->get_id(), '_transaction_id', wc_clean($posted['txn_id']));
        }
        if (!empty($posted['payment_status'])) {
            update_post_meta($order->get_id(), '_paypal_status', wc_clean($posted['payment_status']));
        }
    }
    protected function send_ipn_email_notification($subject, $message)
    {
        $new_order_settings = get_option('woocommerce_new_order_settings', array());
        $mailer = WC()->mailer();
        $message = $mailer->wrap_message($subject, $message);
        $woocommerce_paypal_settings = get_option('woocommerce_paypal_settings');
        if (!empty($woocommerce_paypal_settings['ipn_notification']) && 'no' === $woocommerce_paypal_settings['ipn_notification']) {
            return;
        }
        $mailer->send(!empty($new_order_settings['recipient']) ? $new_order_settings['recipient'] : get_option('admin_email'), strip_tags($subject), $message);
    }
}