installed plugin Easy Digital Downloads
version 3.1.0.3
This commit is contained in:
@ -0,0 +1,227 @@
|
||||
<?php
|
||||
/**
|
||||
* EnvironmentChecker.php
|
||||
*
|
||||
* Checks to see if the environment matches the passed conditions.
|
||||
* Supported conditions include:
|
||||
*
|
||||
* - EDD version number -- either specific versions or wildcards (e.g. "2.x").
|
||||
* - Type of license (pass level, à la carte, free).
|
||||
*
|
||||
* @package easy-digital-downloads
|
||||
* @copyright Copyright (c) 2021, Easy Digital Downloads
|
||||
* @license GPL2+
|
||||
* @since 2.11.4
|
||||
*/
|
||||
|
||||
namespace EDD\Utils;
|
||||
|
||||
use EDD\Admin\Pass_Manager;
|
||||
|
||||
class EnvironmentChecker {
|
||||
|
||||
/**
|
||||
* @var Pass_Manager
|
||||
*/
|
||||
protected $passManager;
|
||||
|
||||
/**
|
||||
* Types of license/pass conditions that we support.
|
||||
* The key is the condition slug and the value is the corresponding
|
||||
* method to call in the `Pass_Manager` class to check the condition.
|
||||
*
|
||||
* @since 2.11.4
|
||||
*
|
||||
* @var string[]
|
||||
*/
|
||||
protected $validLicenseConditions = array(
|
||||
'free' => 'isFree',
|
||||
'ala-carte' => 'hasIndividualLicense',
|
||||
'pass-personal' => 'hasPersonalPass',
|
||||
'pass-extended' => 'hasExtendedPass',
|
||||
'pass-professional' => 'hasProfessionalPass',
|
||||
'pass-all-access' => 'hasAllAccessPass',
|
||||
'pass-any' => 'has_pass',
|
||||
);
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
$this->passManager = new Pass_Manager();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks to see if this environment meets the specified condition.
|
||||
*
|
||||
* @since 2.11.4
|
||||
*
|
||||
* @param string $condition Condition to check. Can either be a type of license/pass or a version number.
|
||||
*
|
||||
* @return bool
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function meetsCondition( $condition ) {
|
||||
if ( array_key_exists( $condition, $this->validLicenseConditions ) ) {
|
||||
return $this->hasLicenseType( $condition );
|
||||
} elseif ( $this->isPaymentGateway( $condition ) ) {
|
||||
return $this->paymentGatewayMatch( array_keys( edd_get_enabled_payment_gateways() ), $condition );
|
||||
} elseif ( $this->isVersionNumber( $condition ) ) {
|
||||
return $this->versionNumbersMatch( EDD_VERSION, $condition );
|
||||
}
|
||||
|
||||
throw new \InvalidArgumentException( 'Invalid condition. Must either be a type of license or a version number.' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks to see if this environment meets all the specified conditions. If any one condition
|
||||
* is not met then this returns false.
|
||||
*
|
||||
* @since 2.11.4
|
||||
*
|
||||
* @param array $conditions
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function meetsConditions( $conditions ) {
|
||||
foreach ( $conditions as $condition ) {
|
||||
if ( ! $this->meetsCondition( $condition ) ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the site has the specified pass condition.
|
||||
*
|
||||
* @see EnvironmentChecker::$validLicenseConditions
|
||||
*
|
||||
* @since 2.11.4
|
||||
*
|
||||
* @param string $passLevel License type that we're checking to see if the system has.
|
||||
*
|
||||
* @return bool
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
protected function hasLicenseType( $passLevel ) {
|
||||
$method = isset( $this->validLicenseConditions[ $passLevel ] )
|
||||
? $this->validLicenseConditions[ $passLevel ]
|
||||
: false;
|
||||
|
||||
if ( ! $method || ! method_exists( $this->passManager, $method ) ) {
|
||||
throw new \InvalidArgumentException( sprintf( 'Method %s not found in Pass_Manager.', $method ) );
|
||||
}
|
||||
|
||||
return call_user_func( array( $this->passManager, $method ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the provided condition is a payment gateway.
|
||||
*
|
||||
* @since 2.11.4
|
||||
*
|
||||
* @param string $condition
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function isPaymentGateway( $condition ) {
|
||||
return 'gateway-' === substr( $condition, 0, 8 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the supplied gateway condition is applicable to this site.
|
||||
* Will return `true` if the condition is the slug of a payment gateway (potentially with a `gateway-` prefix)
|
||||
* that's enabled on this site.
|
||||
*
|
||||
* @since 2.11.4
|
||||
*
|
||||
* @param array $enabledGateways Gateways that are enabled on this site.
|
||||
* @param string $condition Gateway we're checking to see if it's enabled.
|
||||
*
|
||||
* @return bool True if the gateway is enabled, false if not.
|
||||
*/
|
||||
public function paymentGatewayMatch( $enabledGateways, $condition ) {
|
||||
$gatewayToCheck = str_replace( 'gateway-', '', $condition );
|
||||
|
||||
return in_array( $gatewayToCheck, $enabledGateways, true );
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the provided condition is a version number.
|
||||
*
|
||||
* @since 2.11.4
|
||||
*
|
||||
* @param string $condition
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function isVersionNumber( $condition ) {
|
||||
// First character should always be numeric.
|
||||
if ( ! is_numeric( substr( $condition, 0, 1 ) ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Must contain at least one `.` or `-`.
|
||||
return false !== strpos( $condition, '.' ) || false !== strpos( $condition, '-' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if two version numbers match, or if the `$currentVersion` falls within the wildcard
|
||||
* range specified by `$compareVersion`.
|
||||
*
|
||||
* @since 2.11.4
|
||||
*
|
||||
* @param string $currentVersion Version number currently in use. This must be a full, exact version number.
|
||||
* @param string $compareVersion Version to compare with. This can either be an exact version number or a
|
||||
* wildcard (e.g. `2.11.3` or `2.x`). Hyphens are also accepted in lieu of
|
||||
* full stops (e.g. `2-11-3` or `2-x`).
|
||||
*
|
||||
* @return bool
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function versionNumbersMatch( $currentVersion, $compareVersion ) {
|
||||
$currentVersionPieces = explode( '.', $currentVersion );
|
||||
|
||||
if ( false !== strpos( $compareVersion, '.' ) ) {
|
||||
$compareVersionPieces = explode( '.', $compareVersion );
|
||||
} else if ( false !== strpos( $compareVersion, '-' ) ) {
|
||||
$compareVersionPieces = explode( '-', $compareVersion );
|
||||
} else {
|
||||
throw new \InvalidArgumentException( sprintf(
|
||||
'Invalid version number: %s',
|
||||
$compareVersion
|
||||
) );
|
||||
}
|
||||
|
||||
$numberCurrentVersionParts = count( $currentVersionPieces );
|
||||
$numberCompareVersionParts = count( $compareVersionPieces );
|
||||
|
||||
/*
|
||||
* Normalize the two parts so that they have the same lengths and
|
||||
* wildcards (`x`) are removed.
|
||||
*/
|
||||
for ( $i = 0; $i < $numberCurrentVersionParts || $i < $numberCompareVersionParts; $i ++ ) {
|
||||
if ( isset( $compareVersionPieces[ $i ] ) && 'x' === strtolower( $compareVersionPieces[ $i ] ) ) {
|
||||
unset( $compareVersionPieces[ $i ] );
|
||||
}
|
||||
|
||||
if ( ! isset( $currentVersionPieces[ $i ] ) ) {
|
||||
unset( $compareVersionPieces[ $i ] );
|
||||
} elseif ( ! isset( $compareVersionPieces[ $i ] ) ) {
|
||||
unset( $currentVersionPieces[ $i ] );
|
||||
}
|
||||
}
|
||||
|
||||
// Now make sure all the numbers match.
|
||||
foreach ( $compareVersionPieces as $index => $versionPiece ) {
|
||||
if ( ! isset( $currentVersionPieces[ $index ] ) || $currentVersionPieces[ $index ] !== $versionPiece ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,228 @@
|
||||
<?php
|
||||
/**
|
||||
* NotificationImporter.php
|
||||
*
|
||||
* @package easy-digital-downloads
|
||||
* @copyright Copyright (c) 2021, Easy Digital Downloads
|
||||
* @license GPL2+
|
||||
* @since 2.11.4
|
||||
*/
|
||||
|
||||
namespace EDD\Utils;
|
||||
|
||||
class NotificationImporter {
|
||||
|
||||
/**
|
||||
* @var EnvironmentChecker
|
||||
*/
|
||||
protected $environmentChecker;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public function __construct() {
|
||||
$this->environmentChecker = new EnvironmentChecker();
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches notifications from the API and imports them locally.
|
||||
*
|
||||
* @since 2.11.4
|
||||
*/
|
||||
public function run() {
|
||||
edd_debug_log( 'Fetching notifications via ' . $this->getApiEndpoint() );
|
||||
|
||||
try {
|
||||
$notifications = $this->fetchNotifications();
|
||||
} catch ( \Exception $e ) {
|
||||
edd_debug_log( sprintf( 'Notification fetch exception: %s', $e->getMessage() ) );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ( $notifications as $notification ) {
|
||||
$notificationId = isset( $notification->id ) ? $notification->id : 'unknown';
|
||||
|
||||
edd_debug_log( sprintf( 'Processing notification ID %s', $notificationId ) );
|
||||
|
||||
try {
|
||||
$this->validateNotification( $notification );
|
||||
|
||||
$existingId = EDD()->notifications->get_column_by( 'id', 'remote_id', $notification->id );
|
||||
if ( $existingId ) {
|
||||
edd_debug_log( '-- Updating existing notification.' );
|
||||
|
||||
$this->updateExistingNotification( $existingId, $notification );
|
||||
} else {
|
||||
edd_debug_log( '-- Inserting new notification.' );
|
||||
|
||||
$this->insertNewNotification( $notification );
|
||||
}
|
||||
} catch ( \Exception $e ) {
|
||||
edd_debug_log( sprintf( '-- Notification processing failure for ID %s: %s', $notificationId, $e->getMessage() ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the API endpoint to query.
|
||||
*
|
||||
* @since 2.11.4
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getApiEndpoint() {
|
||||
if ( defined( 'EDD_NOTIFICATIONS_API_URL' ) ) {
|
||||
return EDD_NOTIFICATIONS_API_URL;
|
||||
}
|
||||
|
||||
return 'https://plugin.easydigitaldownloads.com/wp-content/notifications.json';
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves notifications from the remote API endpoint.
|
||||
*
|
||||
* @since 2.11.4
|
||||
*
|
||||
* @return array
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function fetchNotifications() {
|
||||
$response = wp_remote_get( $this->getApiEndpoint() );
|
||||
|
||||
if ( is_wp_error( $response ) ) {
|
||||
throw new \Exception( $response->get_error_message() );
|
||||
}
|
||||
|
||||
$notifications = wp_remote_retrieve_body( $response );
|
||||
|
||||
return ! empty( $notifications ) ? json_decode( $notifications ) : array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the notification from the remote API to make sure we actually
|
||||
* want to save it.
|
||||
*
|
||||
* @since 2.11.4
|
||||
*
|
||||
* @param object $notification
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function validateNotification( $notification ) {
|
||||
// Make sure we have all the required data.
|
||||
$requiredProperties = array(
|
||||
'id',
|
||||
'title',
|
||||
'content',
|
||||
);
|
||||
|
||||
$missing = array_diff( $requiredProperties, array_keys( get_object_vars( $notification ) ) );
|
||||
if ( $missing ) {
|
||||
throw new \Exception( sprintf( 'Missing required properties: %s', json_encode( array_values( $missing ) ) ) );
|
||||
}
|
||||
|
||||
// Don't save the notification if it has expired.
|
||||
if ( ! empty( $notification->end ) && time() > strtotime( $notification->end ) ) {
|
||||
throw new \Exception( 'Notification has expired.' );
|
||||
}
|
||||
|
||||
// Ignore if notification was created before EDD was installed.
|
||||
if ( ! empty( $notification->start ) && edd_get_activation_date() > strtotime( $notification->start ) ) {
|
||||
throw new \Exception( 'Notification created prior to EDD activation.' );
|
||||
}
|
||||
|
||||
if (
|
||||
! empty( $notification->type ) &&
|
||||
is_array( $notification->type ) &&
|
||||
! $this->environmentChecker->meetsConditions( $notification->type )
|
||||
) {
|
||||
throw new \Exception( 'Condition(s) not met.' );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the array of notification data to insert into the database.
|
||||
* Use in both inserts and updates.
|
||||
*
|
||||
* @since 2.11.4
|
||||
*
|
||||
* @param object $notification
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getNotificationData( $notification ) {
|
||||
return array(
|
||||
'remote_id' => $notification->id,
|
||||
'title' => $notification->title,
|
||||
'content' => $notification->content,
|
||||
'buttons' => $this->parseButtons( $notification ),
|
||||
'type' => ! empty( $notification->notification_type ) ? $notification->notification_type : 'success',
|
||||
'conditions' => ! empty( $notification->type ) ? $notification->type : null,
|
||||
'start' => ! empty( $notification->start ) ? $notification->start : null,
|
||||
'end' => ! empty( $notification->end ) ? $notification->end : null,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses and formats buttons from the remote notification object.
|
||||
*
|
||||
* @since 2.11.4
|
||||
*
|
||||
* @param object $notification
|
||||
*
|
||||
* @return array|null
|
||||
*/
|
||||
protected function parseButtons( $notification ) {
|
||||
if ( empty( $notification->btns ) ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$buttons = array();
|
||||
|
||||
foreach ( (array) $notification->btns as $buttonType => $buttonInfo ) {
|
||||
if ( empty( $buttonInfo->url ) || empty( $buttonInfo->text ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$buttons[] = array(
|
||||
'type' => ( 'main' === $buttonType ) ? 'primary' : 'secondary',
|
||||
'url' => $buttonInfo->url,
|
||||
'text' => $buttonInfo->text,
|
||||
);
|
||||
}
|
||||
|
||||
return ! empty( $buttons ) ? $buttons : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts a new notification into the database.
|
||||
*
|
||||
* @since 2.11.4
|
||||
*
|
||||
* @param object $notification
|
||||
* @throws \Exception
|
||||
*/
|
||||
protected function insertNewNotification( $notification ) {
|
||||
$result = EDD()->notifications->insert( $this->getNotificationData( $notification ) );
|
||||
|
||||
if ( ! $result ) {
|
||||
throw new \Exception( 'Failed to insert into database.' );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates an existing notification.
|
||||
*
|
||||
* @since 2.11.4
|
||||
*
|
||||
* @param int $existingId
|
||||
* @param object $notification
|
||||
*/
|
||||
protected function updateExistingNotification( $existingId, $notification ) {
|
||||
EDD()->notifications->update( $existingId, wp_parse_args( $this->getNotificationData( $notification ), array(
|
||||
'date_updated' => gmdate( 'Y-m-d H:i:s' ),
|
||||
) ) );
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,115 @@
|
||||
<?php
|
||||
/**
|
||||
* Class for date management
|
||||
*
|
||||
* @package EDD
|
||||
* @subpackage Classes/Date
|
||||
* @copyright Copyright (c) 2018, Easy Digital Downloads, LLC
|
||||
* @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
|
||||
* @since 3.0
|
||||
*/
|
||||
namespace EDD\Utils;
|
||||
|
||||
if ( ! class_exists( '\\Carbon\\Carbon' ) ) {
|
||||
require_once EDD_PLUGIN_DIR . 'includes/libraries/Carbon.php';
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements date formatting helpers for EDD.
|
||||
*
|
||||
* @since 3.0
|
||||
*
|
||||
* @see \Carbon\Carbon
|
||||
* @see \DateTime
|
||||
*/
|
||||
final class Date extends \Carbon\Carbon {
|
||||
|
||||
/**
|
||||
* Sets up the date.
|
||||
*
|
||||
* @since 3.0
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function __construct( $time = null, $timezone = null ) {
|
||||
if ( null === $timezone ) {
|
||||
$timezone = new \DateTimeZone( edd_get_timezone_id() );
|
||||
}
|
||||
|
||||
parent::__construct( $time, $timezone );
|
||||
|
||||
// Apply the WP offset based on the WP timezone that was set.
|
||||
$offset = $this->getOffset();
|
||||
$interval = \DateInterval::createFromDateString( "{$offset} seconds" );
|
||||
$this->add( $interval );
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats a given date string according to WP date and time formats and timezone.
|
||||
*
|
||||
* @since 3.0
|
||||
*
|
||||
* @param string|true $format Optional. How to format the date string. Accepts 'date',
|
||||
* 'time', 'datetime', 'mysql', 'timestamp', 'wp_timestamp',
|
||||
* 'object', or any valid date_format() string. If true, 'datetime'
|
||||
* will be used. Default 'datetime'.
|
||||
* @return string|int|\DateTime Formatted date string, timestamp if `$type` is timestamp,
|
||||
* or a DateTime object if `$type` is 'object'.
|
||||
*/
|
||||
public function format( $format = 'datetime' ) {
|
||||
|
||||
if ( empty( $format ) || true === $format ) {
|
||||
$format = 'datetime';
|
||||
}
|
||||
|
||||
switch( $format ) {
|
||||
|
||||
// jQuery UI Datepicker formats
|
||||
case 'date-attribute':
|
||||
case 'date-js':
|
||||
case 'date-mysql':
|
||||
case 'time-mysql':
|
||||
|
||||
// WordPress Formats
|
||||
case 'date':
|
||||
case 'time':
|
||||
case 'datetime':
|
||||
case 'mysql':
|
||||
$formatted = parent::format( edd_get_date_format( $format ) );
|
||||
break;
|
||||
|
||||
case 'object':
|
||||
$formatted = $this;
|
||||
break;
|
||||
|
||||
case 'timestamp':
|
||||
$formatted = $this->getTimestamp();
|
||||
break;
|
||||
|
||||
case 'wp_timestamp':
|
||||
/*
|
||||
* Note: Even if the timezone has been changed, getTimestamp() will still
|
||||
* return the original timestamp because DateTime doesn't directly allow
|
||||
* conversion of the timestamp in terms of offset; it's immutable.
|
||||
*/
|
||||
$formatted = $this->getWPTimestamp();
|
||||
break;
|
||||
|
||||
default:
|
||||
$formatted = parent::format( $format );
|
||||
break;
|
||||
}
|
||||
|
||||
return $formatted;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the date timestamp with the WordPress offset applied.
|
||||
*
|
||||
* @since 3.0
|
||||
*
|
||||
* @return int WordPress "local" timestamp.
|
||||
*/
|
||||
public function getWPTimestamp() {
|
||||
return $this->getTimestamp() + EDD()->utils->get_gmt_offset();
|
||||
}
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
<?php
|
||||
/**
|
||||
* Namespaced exception object for EDD
|
||||
*
|
||||
* @package EDD
|
||||
* @subpackage Classes/Utilities/Exceptions
|
||||
* @copyright Copyright (c) 2018, Easy Digital Downloads, LLC
|
||||
* @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
|
||||
* @since 3.0
|
||||
*/
|
||||
namespace EDD\Utils;
|
||||
|
||||
/**
|
||||
* Implements a namespaced EDD-specific exception object.
|
||||
*
|
||||
* Implements the EDD_Exception marker interface to make it easier to catch
|
||||
* EDD-specific exceptions under one umbrella.
|
||||
*
|
||||
* @since 3.0
|
||||
*
|
||||
* @see \Exception
|
||||
* @see \EDD_Exception
|
||||
*/
|
||||
class Exception extends \Exception implements \EDD_Exception {}
|
@ -0,0 +1,151 @@
|
||||
<?php
|
||||
/**
|
||||
* Registry utility superclass
|
||||
*
|
||||
* This class should be extended to create object registries.
|
||||
*
|
||||
* @package EDD
|
||||
* @subpackage Classes/Utilities
|
||||
* @copyright Copyright (c) 2018, Easy Digital Downloads, LLC
|
||||
* @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
|
||||
* @since 3.0
|
||||
*/
|
||||
namespace EDD\Utils;
|
||||
|
||||
use EDD\Utils\Exceptions;
|
||||
|
||||
/**
|
||||
* Defines the construct for building an item registry.
|
||||
*
|
||||
* @since 3.0.0
|
||||
* @abstract
|
||||
*/
|
||||
abstract class Registry extends \ArrayObject {
|
||||
|
||||
/**
|
||||
* Item error label.
|
||||
*
|
||||
* Used for customizing exception messages to the current registry instance. Default 'item'.
|
||||
*
|
||||
* @since 3.0
|
||||
* @var string
|
||||
*/
|
||||
public static $item_error_label = 'item';
|
||||
|
||||
/**
|
||||
* Adds an item to the registry.
|
||||
*
|
||||
* @since 3.0
|
||||
*
|
||||
* @throws \EDD_Exception If the `$attributes` array is empty.
|
||||
*
|
||||
* @param string $item_id Item ID.
|
||||
* @param array $attributes Array of item attributes. Each extending registry will
|
||||
* handle item ID and attribute building in different ways.
|
||||
* @return bool True if `$attributes` is not empty, otherwise false.
|
||||
*/
|
||||
public function add_item( $item_id, $attributes ) {
|
||||
$result = false;
|
||||
|
||||
if ( ! empty( $attributes ) ) {
|
||||
|
||||
$this->offsetSet( $item_id, $attributes );
|
||||
|
||||
$result = true;
|
||||
|
||||
} else {
|
||||
|
||||
$message = sprintf(
|
||||
'The attributes were missing when attempting to add the \'%1$s\' %2$s.',
|
||||
$item_id,
|
||||
static::$item_error_label
|
||||
);
|
||||
|
||||
throw new Exception( $message );
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes an item from the registry by ID.
|
||||
*
|
||||
* @since 3.0
|
||||
*
|
||||
* @param string $item_id Item ID.
|
||||
*/
|
||||
public function remove_item( $item_id ) {
|
||||
if ( $this->offsetExists( $item_id ) ) {
|
||||
$this->offsetUnset( $item_id );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves an item and its associated attributes.
|
||||
*
|
||||
* @since 3.0
|
||||
*
|
||||
* @throws \EDD_Exception if the item does not exist.
|
||||
*
|
||||
* @param string $item_id Item ID.
|
||||
* @return array Array of attributes for the item if the item is set,
|
||||
* otherwise an empty array.
|
||||
*/
|
||||
public function get_item( $item_id ) {
|
||||
|
||||
$item = array();
|
||||
|
||||
if ( $this->offsetExists( $item_id ) ) {
|
||||
|
||||
$item = $this->offsetGet( $item_id );
|
||||
|
||||
} else {
|
||||
|
||||
$message = sprintf(
|
||||
'The \'%1$s\' %2$s does not exist.',
|
||||
$item_id,
|
||||
static::$item_error_label
|
||||
);
|
||||
|
||||
throw new Exception( $message );
|
||||
}
|
||||
|
||||
return $item;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves registered items.
|
||||
*
|
||||
* @since 3.0
|
||||
*
|
||||
* @return array The list of registered items.
|
||||
*/
|
||||
public function get_items() {
|
||||
return $this->getArrayCopy();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the value of a given attribute for a given item.
|
||||
*
|
||||
* @since 3.0
|
||||
*
|
||||
* @throws \EDD_Exception if the item does not exist.
|
||||
* @throws \EDD_Exception if the attribute and/or item does not exist.
|
||||
*
|
||||
* @param string $key Key of the attribute to retrieve.
|
||||
* @param string $item_id Collection to retrieve the attribute from.
|
||||
* @return mixed|null The attribute value if set, otherwise null.
|
||||
*/
|
||||
public function get_attribute( $key, $item_id ) {
|
||||
$attribute = null;
|
||||
$item = $this->get_item( $item_id );
|
||||
|
||||
if ( ! empty( $item[ $key ] ) ) {
|
||||
$attribute = $item[ $key ];
|
||||
} else {
|
||||
throw Exceptions\Attribute_Not_Found::from_attr( $key, $item_id );
|
||||
}
|
||||
|
||||
return $attribute;
|
||||
}
|
||||
}
|
@ -0,0 +1,120 @@
|
||||
<?php
|
||||
/**
|
||||
* Tokenizer
|
||||
*
|
||||
* A class for generating tokens as an alternative to nonce verification.
|
||||
* This is designed to work a little better with full page caching.
|
||||
*
|
||||
* @package easy-digital-downloads
|
||||
* @copyright Copyright (c) 2021, Sandhills Development, LLC
|
||||
* @license GPL2+
|
||||
* @since 2.11
|
||||
*/
|
||||
|
||||
namespace EDD\Utils;
|
||||
|
||||
class Tokenizer {
|
||||
|
||||
/**
|
||||
* @var mixed Data to tokenize.
|
||||
*/
|
||||
private $data;
|
||||
|
||||
/**
|
||||
* Tokenizer constructor.
|
||||
*
|
||||
* @param string|int|float $data Data to be tokenized.
|
||||
*/
|
||||
public function __construct( $data ) {
|
||||
$this->data = $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the signing key.
|
||||
*
|
||||
* @since 2.11
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function get_signing_key() {
|
||||
$key = get_option( 'edd_tokenizer_signing_key' );
|
||||
if ( empty( $key ) ) {
|
||||
$key = $this->generate_and_save_signing_key();
|
||||
}
|
||||
|
||||
return $key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates and saves a new signing key.
|
||||
*
|
||||
* @since 2.11
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function generate_and_save_signing_key() {
|
||||
if ( function_exists( 'random_bytes' ) ) {
|
||||
try {
|
||||
$key = bin2hex( random_bytes( 32 ) );
|
||||
} catch ( \Exception $e ) {
|
||||
// If this failed for some reason, we'll generate using the fallback below.
|
||||
}
|
||||
}
|
||||
|
||||
if ( empty( $key ) ) {
|
||||
$key = function_exists( 'openssl_random_pseudo_bytes' ) ? bin2hex( openssl_random_pseudo_bytes( 32 ) ) : md5( uniqid() );
|
||||
}
|
||||
|
||||
update_option( 'edd_tokenizer_signing_key', $key );
|
||||
|
||||
return $key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a token from the data.
|
||||
*
|
||||
* @since 2.11
|
||||
*
|
||||
* @return string|false
|
||||
*/
|
||||
public function generate_token() {
|
||||
return hash_hmac( 'sha256', $this->data, $this->get_signing_key() );
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether or not the supplied token is valid for the
|
||||
* supplied data.
|
||||
*
|
||||
* @since 2.11
|
||||
*
|
||||
* @param string $token Token to check.
|
||||
* @param string|int|float $data Data that's been tokenized.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function is_token_valid( $token, $data ) {
|
||||
$real_token = self::tokenize( $data );
|
||||
|
||||
return hash_equals( $token, $real_token );
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a token for the supplied data.
|
||||
*
|
||||
* @since 2.11
|
||||
*
|
||||
* @param string|int|float $data
|
||||
*
|
||||
* @return string|false
|
||||
*/
|
||||
public static function tokenize( $data ) {
|
||||
if ( is_array( $data ) ) {
|
||||
$data = json_encode( $data );
|
||||
}
|
||||
|
||||
$generator = new Tokenizer( $data );
|
||||
|
||||
return $generator->generate_token();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
<?php
|
||||
/**
|
||||
* Attribute_Not_Found exception class
|
||||
*
|
||||
* @package EDD
|
||||
* @subpackage Classes/Utilities
|
||||
* @copyright Copyright (c) 2018, Easy Digital Downloads, LLC
|
||||
* @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
|
||||
* @since 3.0
|
||||
*/
|
||||
namespace EDD\Utils\Exceptions;
|
||||
|
||||
/**
|
||||
* Implements an Attribute_Not_Found exception thrown when a given
|
||||
* attribute is not found.
|
||||
*
|
||||
* @since 3.0
|
||||
*
|
||||
* @see \OutOfBoundsException
|
||||
* @see \EDD_Exception
|
||||
*/
|
||||
class Attribute_Not_Found extends \OutOfBoundsException implements \EDD_Exception {
|
||||
|
||||
/**
|
||||
* Retrieves an informed Attribute_Not_Found instance via late-static binding.
|
||||
*
|
||||
* @since 3.0
|
||||
*
|
||||
* @param string $attribute_name Attribute resulting in the exception.
|
||||
* @param string $collection Collection the attribute belongs to.
|
||||
* @param int $code Optional. Exception code. Default null.
|
||||
* @param \Exception $previous Optional. Previous exception (used for chaining).
|
||||
* Default null.
|
||||
* @return \EDD\Utils\Exceptions\Attribute_Not_Found Exception instance.
|
||||
*/
|
||||
public static function from_attr( $attribute_name, $collection, $code = null, $previous = null ) {
|
||||
$message = sprintf( 'The \'%1$s\' attribute does not exist for \'%2$s\'.',
|
||||
$attribute_name,
|
||||
$collection
|
||||
);
|
||||
|
||||
return new static( $message, $code, $previous);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,88 @@
|
||||
<?php
|
||||
/**
|
||||
* Invalid_Argument exception class
|
||||
*
|
||||
* @package EDD
|
||||
* @subpackage Classes/Utilities
|
||||
* @copyright Copyright (c) 2018, Easy Digital Downloads, LLC
|
||||
* @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
|
||||
* @since 3.0
|
||||
*/
|
||||
namespace EDD\Utils\Exceptions;
|
||||
|
||||
/**
|
||||
* Implements an Invalid_Argument exception thrown when a given
|
||||
* argument or parameter is invalid.
|
||||
*
|
||||
* @since 3.0
|
||||
*
|
||||
* @see \InvalidArgumentException
|
||||
* @see \EDD_Exception
|
||||
*/
|
||||
class Invalid_Argument extends \InvalidArgumentException implements \EDD_Exception {
|
||||
|
||||
/**
|
||||
* Type of value.
|
||||
*
|
||||
* @since 3.0
|
||||
* @var string
|
||||
*/
|
||||
public static $type = 'argument';
|
||||
|
||||
/**
|
||||
* Exception message.
|
||||
*
|
||||
* @since 3.0
|
||||
* @var string|null
|
||||
*/
|
||||
public static $error_message;
|
||||
|
||||
/**
|
||||
* Retrieves an informed Invalid_Argument instance via late-static binding.
|
||||
*
|
||||
* @since 3.0
|
||||
*
|
||||
* @param string $argument_name Argument or parameter resulting in the exception.
|
||||
* @param string $method Function or method name the argument or parameter was passed to.
|
||||
* @param string $context Further context under which to build the exception message. To be
|
||||
* used by sub-classes when overriding build_message(). Default null.
|
||||
* @param int $code Optional. Exception code. Default null.
|
||||
* @param \Exception $previous Optional. Previous exception (used for chaining).
|
||||
* Default null.
|
||||
* @return \EDD\Utils\Exceptions\Invalid_Argument Exception instance.
|
||||
*/
|
||||
public static function from( $argument_name, $method, $context = null ) {
|
||||
static::build_message( $argument_name, $method, $context );
|
||||
|
||||
return new static( static::$error_message );
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the Invalid_Argument exception message.
|
||||
*
|
||||
* Abstracted to allow for completely overriding the exception message in a subclass.
|
||||
*
|
||||
* @since 3.0
|
||||
*
|
||||
* @param string $argument_name Argument or parameter resulting in the exception.
|
||||
* @param string $method Function or method name the argument or parameter was passed to.
|
||||
* @param string $context Further context under which to build the exception message. To be
|
||||
* used by sub-classes when overriding build_message(). Default null.
|
||||
* @return string Informed Invalid_Argument message.
|
||||
*/
|
||||
public static function build_message( $argument_name, $method, $context = null ) {
|
||||
if ( ! isset( static::$error_message ) ) {
|
||||
|
||||
if ( ! isset( self::$type ) ) {
|
||||
self::$type = 'argument';
|
||||
}
|
||||
|
||||
self::$error_message = sprintf( 'The \'%1$s\' %2$s is missing or invalid for \'%3$s\'.',
|
||||
$argument_name,
|
||||
static::$type,
|
||||
$method
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
<?php
|
||||
/**
|
||||
* Invalid_Parameter exception class
|
||||
*
|
||||
* @package EDD
|
||||
* @subpackage Classes/Utilities
|
||||
* @copyright Copyright (c) 2018, Easy Digital Downloads, LLC
|
||||
* @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
|
||||
* @since 3.0
|
||||
*/
|
||||
namespace EDD\Utils\Exceptions;
|
||||
|
||||
/**
|
||||
* Implements an Invalid_Argument exception thrown when a given
|
||||
* argument or parameter is invalid.
|
||||
*
|
||||
* @since 3.0
|
||||
*
|
||||
* @see \InvalidArgumentException
|
||||
* @see \EDD_Exception
|
||||
*/
|
||||
class Invalid_Parameter extends Invalid_Argument implements \EDD_Exception {
|
||||
|
||||
/**
|
||||
* Type of value.
|
||||
*
|
||||
* @since 3.0
|
||||
* @var string
|
||||
*/
|
||||
public static $type = 'parameter';
|
||||
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
<?php
|
||||
namespace EDD\Utils;
|
||||
|
||||
/**
|
||||
* Defines error logging methods for use by an implementing class.
|
||||
*
|
||||
* @since 3.0
|
||||
*/
|
||||
interface Error_Logger_Interface {
|
||||
|
||||
/**
|
||||
* Determines whether the object has generated errors during instantiation.
|
||||
*
|
||||
* @since 3.0
|
||||
*
|
||||
* @return bool True if errors have been logged, otherwise false.
|
||||
*/
|
||||
public function has_errors();
|
||||
|
||||
/**
|
||||
* Retrieves any logged errors for the object.
|
||||
*
|
||||
* @since 3.0
|
||||
*
|
||||
* @return \WP_Error WP_Error object for the current object.
|
||||
*/
|
||||
public function get_errors();
|
||||
|
||||
/**
|
||||
* Sets up the errors instance.
|
||||
*
|
||||
* @since 3.0
|
||||
*/
|
||||
public function setup_error_logger();
|
||||
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
<?php
|
||||
/**
|
||||
* Static_Registry interface
|
||||
*
|
||||
* @package EDD
|
||||
* @subpackage Interfaces/Utilities
|
||||
* @copyright Copyright (c) 2018, Easy Digital Downloads, LLC
|
||||
* @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
|
||||
* @since 3.0
|
||||
*/
|
||||
namespace EDD\Utils;
|
||||
|
||||
/**
|
||||
* Defines the contract for a static (singleton) registry object.
|
||||
*
|
||||
* @since 3.0
|
||||
*/
|
||||
interface Static_Registry {
|
||||
|
||||
/**
|
||||
* Retrieves the one true registry instance.
|
||||
*
|
||||
* @since 3.0
|
||||
*
|
||||
* @return \EDD\Utils\Static_Registry Registry instance.
|
||||
*/
|
||||
public static function instance();
|
||||
|
||||
}
|
Reference in New Issue
Block a user