File "class-wc-webhook.php"

Full path: /home/kosmetik/public_html/wp-content/plugins/woocommerce/includes/class-wc-webhook.php
File size: 18.49 B
MIME-type: text/x-php
Charset: utf-8

Download   Open   Edit   Advanced Editor   Back

<?php

use Automattic\Jetpack\Constants;
use Automattic\WooCommerce\Utilities\NumberUtil;
defined('ABSPATH') || exit;
require_once __DIR__ . '/legacy/class-wc-legacy-webhook.php';
class WC_Webhook extends WC_Legacy_Webhook
{
    protected $processed = array();
    protected $data = array('date_created' => null, 'date_modified' => null, 'status' => 'disabled', 'delivery_url' => '', 'secret' => '', 'name' => '', 'topic' => '', 'hooks' => '', 'resource' => '', 'event' => '', 'failure_count' => 0, 'user_id' => 0, 'api_version' => 3, 'pending_delivery' => false);
    public function __construct($data = 0)
    {
        parent::__construct($data);
        if ($data instanceof WC_Webhook) {
            $this->set_id(absint($data->get_id()));
        } elseif (is_numeric($data)) {
            $this->set_id($data);
        }
        $this->data_store = WC_Data_Store::load('webhook');
        if ($this->get_id()) {
            try {
                $this->data_store->read($this);
            } catch (Exception $e) {
                $this->set_id(0);
                $this->set_object_read(true);
            }
        } else {
            $this->set_object_read(true);
        }
    }
    public function enqueue()
    {
        $hooks = $this->get_hooks();
        $url = $this->get_delivery_url();
        if (is_array($hooks) && !empty($url)) {
            foreach ($hooks as $hook) {
                add_action($hook, array($this, 'process'));
            }
        }
    }
    public function process($arg)
    {
        if (!$this->should_deliver($arg)) {
            return;
        }
        $this->processed[] = $arg;
        do_action('woocommerce_webhook_process_delivery', $this, $arg);
        return $arg;
    }
    private function should_deliver($arg)
    {
        $should_deliver = $this->is_active() && $this->is_valid_topic() && $this->is_valid_action($arg) && $this->is_valid_resource($arg) && !$this->is_already_processed($arg);
        return apply_filters('woocommerce_webhook_should_deliver', $should_deliver, $this, $arg);
    }
    private function is_active()
    {
        return 'active' === $this->get_status();
    }
    private function is_valid_topic()
    {
        return wc_is_webhook_valid_topic($this->get_topic());
    }
    private function is_valid_action($arg)
    {
        $current_action = current_action();
        $return = true;
        switch ($current_action) {
            case 'delete_post':
            case 'wp_trash_post':
            case 'untrashed_post':
                $return = $this->is_valid_post_action($arg);
                break;
            case 'delete_user':
                $return = $this->is_valid_user_action($arg);
                break;
        }
        if (0 === strpos($current_action, 'woocommerce_process_shop') || 0 === strpos($current_action, 'woocommerce_process_product')) {
            $return = $this->is_valid_processing_action($arg);
        }
        return $return;
    }
    private function is_valid_post_action($arg)
    {
        if (isset($GLOBALS['post_type']) && !in_array($GLOBALS['post_type'], array('shop_coupon', 'shop_order', 'product'), true)) {
            return false;
        }
        if (isset($GLOBALS['post_type']) && str_replace('shop_', '', $GLOBALS['post_type']) !== $this->get_resource()) {
            return false;
        }
        return true;
    }
    private function is_valid_user_action($arg)
    {
        $user = get_userdata(absint($arg));
        if (!$user || !in_array('customer', (array) $user->roles, true)) {
            return false;
        }
        return true;
    }
    private function is_valid_processing_action($arg)
    {
        $resource = get_post(absint($arg));
        $gmt_date = get_gmt_from_date($resource->post_date);
        $resource_created = time() - 10 <= strtotime($gmt_date);
        if ('created' === $this->get_event() && !$resource_created) {
            return false;
        } elseif ('updated' === $this->get_event() && $resource_created) {
            return false;
        }
        return true;
    }
    private function is_valid_resource($arg)
    {
        $resource = $this->get_resource();
        if (in_array($resource, array('order', 'product', 'coupon'), true)) {
            $status = get_post_status(absint($arg));
            if (in_array($status, array('auto-draft', 'new'), true)) {
                return false;
            }
            if ('order' === $resource && 'draft' === $status) {
                return false;
            }
            if ('order' === $resource && !in_array(get_post_type(absint($arg)), wc_get_order_types('order-webhooks'), true)) {
                return false;
            }
        }
        return true;
    }
    protected function is_already_processed($arg)
    {
        return false !== array_search($arg, $this->processed, true);
    }
    public function deliver($arg)
    {
        $start_time = microtime(true);
        $payload = $this->build_payload($arg);
        $http_args = array('method' => 'POST', 'timeout' => MINUTE_IN_SECONDS, 'redirection' => 0, 'httpversion' => '1.0', 'blocking' => true, 'user-agent' => sprintf('WooCommerce/%s Hookshot (WordPress/%s)', Constants::get_constant('WC_VERSION'), $GLOBALS['wp_version']), 'body' => trim(wp_json_encode($payload)), 'headers' => array('Content-Type' => 'application/json'), 'cookies' => array());
        $http_args = apply_filters('woocommerce_webhook_http_args', $http_args, $arg, $this->get_id());
        $delivery_id = $this->get_new_delivery_id();
        $http_args['headers']['X-WC-Webhook-Source'] = home_url('/');
        $http_args['headers']['X-WC-Webhook-Topic'] = $this->get_topic();
        $http_args['headers']['X-WC-Webhook-Resource'] = $this->get_resource();
        $http_args['headers']['X-WC-Webhook-Event'] = $this->get_event();
        $http_args['headers']['X-WC-Webhook-Signature'] = $this->generate_signature($http_args['body']);
        $http_args['headers']['X-WC-Webhook-ID'] = $this->get_id();
        $http_args['headers']['X-WC-Webhook-Delivery-ID'] = $delivery_id;
        $response = wp_safe_remote_request($this->get_delivery_url(), $http_args);
        $duration = NumberUtil::round(microtime(true) - $start_time, 5);
        $this->log_delivery($delivery_id, $http_args, $response, $duration);
        do_action('woocommerce_webhook_delivery', $http_args, $response, $duration, $arg, $this->get_id());
    }
    private function get_legacy_api_payload($resource, $resource_id, $event)
    {
        WC()->api->includes();
        WC()->api->register_resources(new WC_API_Server('/'));
        switch ($resource) {
            case 'coupon':
                $payload = WC()->api->WC_API_Coupons->get_coupon($resource_id);
                break;
            case 'customer':
                $payload = WC()->api->WC_API_Customers->get_customer($resource_id);
                break;
            case 'order':
                $payload = WC()->api->WC_API_Orders->get_order($resource_id, null, apply_filters('woocommerce_webhook_order_payload_filters', array()));
                break;
            case 'product':
                if ('updated' === $event && is_a($resource_id, 'WC_Product')) {
                    $resource_id = $resource_id->get_id();
                }
                $payload = WC()->api->WC_API_Products->get_product($resource_id);
                break;
            case 'action':
                $payload = array('action' => current($this->get_hooks()), 'arg' => $resource_id);
                break;
            default:
                $payload = array();
                break;
        }
        return $payload;
    }
    private function get_wp_api_payload($resource, $resource_id, $event)
    {
        switch ($resource) {
            case 'coupon':
            case 'customer':
            case 'order':
            case 'product':
                if ('product' === $resource && 'updated' === $event && is_a($resource_id, 'WC_Product')) {
                    $resource_id = $resource_id->get_id();
                }
                $version = str_replace('wp_api_', '', $this->get_api_version());
                $payload = wc()->api->get_endpoint_data("/wc/{$version}/{$resource}s/{$resource_id}");
                break;
            case 'action':
                $payload = array('action' => current($this->get_hooks()), 'arg' => $resource_id);
                break;
            default:
                $payload = array();
                break;
        }
        return $payload;
    }
    public function build_payload($resource_id)
    {
        $current_user = get_current_user_id();
        wp_set_current_user($this->get_user_id());
        $resource = $this->get_resource();
        $event = $this->get_event();
        if ('deleted' === $event) {
            $payload = array('id' => $resource_id);
        } else {
            if (in_array($this->get_api_version(), wc_get_webhook_rest_api_versions(), true)) {
                $payload = $this->get_wp_api_payload($resource, $resource_id, $event);
            } else {
                $payload = $this->get_legacy_api_payload($resource, $resource_id, $event);
            }
        }
        wp_set_current_user($current_user);
        return apply_filters('woocommerce_webhook_payload', $payload, $resource, $resource_id, $this->get_id());
    }
    public function generate_signature($payload)
    {
        $hash_algo = apply_filters('woocommerce_webhook_hash_algorithm', 'sha256', $payload, $this->get_id());
        return base64_encode(hash_hmac($hash_algo, $payload, wp_specialchars_decode($this->get_secret(), ENT_QUOTES), true));
    }
    public function get_new_delivery_id()
    {
        return wp_hash($this->get_id() . strtotime('now'));
    }
    public function log_delivery($delivery_id, $request, $response, $duration)
    {
        $logger = wc_get_logger();
        $message = array('Webhook Delivery' => array('Delivery ID' => $delivery_id, 'Date' => date_i18n(__('M j, Y @ G:i', 'woocommerce'), strtotime('now'), true), 'URL' => $this->get_delivery_url(), 'Duration' => $duration, 'Request' => array('Method' => $request['method'], 'Headers' => array_merge(array('User-Agent' => $request['user-agent']), $request['headers'])), 'Body' => wp_slash($request['body'])));
        if (is_wp_error($response)) {
            $response_code = $response->get_error_code();
            $response_message = $response->get_error_message();
            $response_headers = array();
            $response_body = '';
        } else {
            $response_code = wp_remote_retrieve_response_code($response);
            $response_message = wp_remote_retrieve_response_message($response);
            $response_headers = wp_remote_retrieve_headers($response);
            $response_body = wp_remote_retrieve_body($response);
        }
        $message['Webhook Delivery']['Response'] = array('Code' => $response_code, 'Message' => $response_message, 'Headers' => $response_headers, 'Body' => $response_body);
        if (!Constants::is_true('WP_DEBUG')) {
            $message['Webhook Delivery']['Body'] = 'Webhook body is not logged unless WP_DEBUG mode is turned on. This is to avoid the storing of personal data in the logs.';
            $message['Webhook Delivery']['Response']['Body'] = 'Webhook body is not logged unless WP_DEBUG mode is turned on. This is to avoid the storing of personal data in the logs.';
        }
        $logger->info(wc_print_r($message, true), array('source' => 'webhooks-delivery'));
        if (intval($response_code) >= 200 && intval($response_code) < 303) {
            $this->set_failure_count(0);
            $this->save();
        } else {
            $this->failed_delivery();
        }
    }
    private function failed_delivery()
    {
        $failures = $this->get_failure_count();
        if ($failures > apply_filters('woocommerce_max_webhook_delivery_failures', 5)) {
            $this->set_status('disabled');
            do_action('woocommerce_webhook_disabled_due_delivery_failures', $this->get_id());
        } else {
            $this->set_failure_count(++$failures);
        }
        $this->save();
    }
    public function get_delivery_logs()
    {
        return esc_url(add_query_arg('log_file', wc_get_log_file_name('webhooks-delivery'), admin_url('admin.php?page=wc-status&tab=logs')));
    }
    public function get_delivery_log($delivery_id)
    {
        wc_deprecated_function('WC_Webhook::get_delivery_log', '3.3');
    }
    public function deliver_ping()
    {
        $args = array('user-agent' => sprintf('WooCommerce/%s Hookshot (WordPress/%s)', Constants::get_constant('WC_VERSION'), $GLOBALS['wp_version']), 'body' => 'webhook_id=' . $this->get_id());
        $test = wp_safe_remote_post($this->get_delivery_url(), $args);
        $response_code = wp_remote_retrieve_response_code($test);
        if (is_wp_error($test)) {
            return new WP_Error('error', sprintf(__('Error: Delivery URL cannot be reached: %s', 'woocommerce'), $test->get_error_message()));
        }
        if (200 !== $response_code) {
            return new WP_Error('error', sprintf(__('Error: Delivery URL returned response code: %s', 'woocommerce'), absint($response_code)));
        }
        $this->set_pending_delivery(false);
        $this->save();
        return true;
    }
    public function get_name($context = 'view')
    {
        return apply_filters('woocommerce_webhook_name', $this->get_prop('name', $context), $this->get_id());
    }
    public function get_status($context = 'view')
    {
        return apply_filters('woocommerce_webhook_status', $this->get_prop('status', $context), $this->get_id());
    }
    public function get_date_created($context = 'view')
    {
        return $this->get_prop('date_created', $context);
    }
    public function get_date_modified($context = 'view')
    {
        return $this->get_prop('date_modified', $context);
    }
    public function get_secret($context = 'view')
    {
        return apply_filters('woocommerce_webhook_secret', $this->get_prop('secret', $context), $this->get_id());
    }
    public function get_topic($context = 'view')
    {
        return apply_filters('woocommerce_webhook_topic', $this->get_prop('topic', $context), $this->get_id());
    }
    public function get_delivery_url($context = 'view')
    {
        return apply_filters('woocommerce_webhook_delivery_url', $this->get_prop('delivery_url', $context), $this->get_id());
    }
    public function get_user_id($context = 'view')
    {
        return $this->get_prop('user_id', $context);
    }
    public function get_api_version($context = 'view')
    {
        $version = $this->get_prop('api_version', $context);
        return 0 < $version ? 'wp_api_v' . $version : 'legacy_v3';
    }
    public function get_failure_count($context = 'view')
    {
        return $this->get_prop('failure_count', $context);
    }
    public function get_pending_delivery($context = 'view')
    {
        return $this->get_prop('pending_delivery', $context);
    }
    public function set_name($name)
    {
        $this->set_prop('name', $name);
    }
    public function set_date_created($date = null)
    {
        $this->set_date_prop('date_created', $date);
    }
    public function set_date_modified($date = null)
    {
        $this->set_date_prop('date_modified', $date);
    }
    public function set_status($status)
    {
        if (!array_key_exists($status, wc_get_webhook_statuses())) {
            $status = 'disabled';
        }
        $this->set_prop('status', $status);
    }
    public function set_secret($secret)
    {
        $this->set_prop('secret', $secret);
    }
    public function set_topic($topic)
    {
        $topic = wc_clean($topic);
        if (!wc_is_webhook_valid_topic($topic)) {
            $topic = '';
        }
        $this->set_prop('topic', $topic);
    }
    public function set_delivery_url($url)
    {
        $this->set_prop('delivery_url', esc_url_raw($url, array('http', 'https')));
    }
    public function set_user_id($user_id)
    {
        $this->set_prop('user_id', (int) $user_id);
    }
    public function set_api_version($version)
    {
        if (!is_numeric($version)) {
            $version = $this->data_store->get_api_version_number($version);
        }
        $this->set_prop('api_version', (int) $version);
    }
    public function set_pending_delivery($pending_delivery)
    {
        $this->set_prop('pending_delivery', (bool) $pending_delivery);
    }
    public function set_failure_count($failure_count)
    {
        $this->set_prop('failure_count', intval($failure_count));
    }
    private function get_topic_hooks($topic)
    {
        $topic_hooks = array('coupon.created' => array('woocommerce_process_shop_coupon_meta', 'woocommerce_new_coupon'), 'coupon.updated' => array('woocommerce_process_shop_coupon_meta', 'woocommerce_update_coupon'), 'coupon.deleted' => array('wp_trash_post'), 'coupon.restored' => array('untrashed_post'), 'customer.created' => array('user_register', 'woocommerce_created_customer', 'woocommerce_new_customer'), 'customer.updated' => array('profile_update', 'woocommerce_update_customer'), 'customer.deleted' => array('delete_user'), 'order.created' => array('woocommerce_new_order'), 'order.updated' => array('woocommerce_update_order', 'woocommerce_order_refunded'), 'order.deleted' => array('wp_trash_post'), 'order.restored' => array('untrashed_post'), 'product.created' => array('woocommerce_process_product_meta', 'woocommerce_new_product', 'woocommerce_new_product_variation'), 'product.updated' => array('woocommerce_process_product_meta', 'woocommerce_update_product', 'woocommerce_update_product_variation'), 'product.deleted' => array('wp_trash_post'), 'product.restored' => array('untrashed_post'));
        $topic_hooks = apply_filters('woocommerce_webhook_topic_hooks', $topic_hooks, $this);
        return isset($topic_hooks[$topic]) ? $topic_hooks[$topic] : array();
    }
    public function get_hooks()
    {
        if ('action' === $this->get_resource()) {
            $hooks = array($this->get_event());
        } else {
            $hooks = $this->get_topic_hooks($this->get_topic());
        }
        return apply_filters('woocommerce_webhook_hooks', $hooks, $this->get_id());
    }
    public function get_resource()
    {
        $topic = explode('.', $this->get_topic());
        return apply_filters('woocommerce_webhook_resource', $topic[0], $this->get_id());
    }
    public function get_event()
    {
        $topic = explode('.', $this->get_topic());
        return apply_filters('woocommerce_webhook_event', isset($topic[1]) ? $topic[1] : '', $this->get_id());
    }
    public function get_i18n_status()
    {
        $status = $this->get_status();
        $statuses = wc_get_webhook_statuses();
        return isset($statuses[$status]) ? $statuses[$status] : $status;
    }
}