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;
}
}