156 lines
4.1 KiB
PHP
156 lines
4.1 KiB
PHP
<?php
|
|
namespace Formipay;
|
|
use Exception;
|
|
|
|
if (!defined('ABSPATH')) exit;
|
|
|
|
class Token {
|
|
|
|
private $table_name;
|
|
|
|
public function __construct() {
|
|
|
|
global $wpdb;
|
|
$this->table_name = $wpdb->prefix . 'formipay_tokens';
|
|
|
|
add_action( 'init', [$this, 'create_db'] );
|
|
// Setup cleanup hook
|
|
add_action( 'formipay_daily_cleanup', [$this, 'cleanup_expired_tokens']);
|
|
|
|
if (!wp_next_scheduled('formipay_daily_cleanup')) {
|
|
wp_schedule_event(time(), 'daily', 'formipay_daily_cleanup');
|
|
}
|
|
|
|
}
|
|
|
|
public function create_db() {
|
|
global $wpdb;
|
|
$table_name = $wpdb->prefix . 'formipay_tokens';
|
|
|
|
$sql = "CREATE TABLE $table_name (
|
|
token CHAR(64) NOT NULL,
|
|
form_id BIGINT UNSIGNED NOT NULL,
|
|
order_id BIGINT UNSIGNED NOT NULL,
|
|
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
expires_at DATETIME NOT NULL,
|
|
used TINYINT(1) NOT NULL DEFAULT 0,
|
|
use_count INT NOT NULL DEFAULT 0,
|
|
PRIMARY KEY (token),
|
|
KEY expires_at_idx (expires_at),
|
|
KEY order_id_idx (order_id)
|
|
) {$wpdb->get_charset_collate()};";
|
|
|
|
require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
|
|
dbDelta($sql);
|
|
}
|
|
|
|
/**
|
|
* Generate cryptographically secure token
|
|
*
|
|
* @param int $order_id
|
|
* @param int $form_id
|
|
* @param int $expires_in Seconds until expiration (default: 900 = 15 mins)
|
|
* @return string
|
|
*/
|
|
public function generate(int $order_id, int $form_id, int $expires_in = 900): string {
|
|
global $wpdb;
|
|
|
|
$token = bin2hex(random_bytes(32)); // 64-character token
|
|
$expires_at = formipay_date('Y-m-d H:i:s', time() + $expires_in);
|
|
|
|
$wpdb->insert($this->table_name, [
|
|
'token' => $token,
|
|
'form_id' => $form_id,
|
|
'order_id' => $order_id,
|
|
'expires_at' => $expires_at,
|
|
'created_at' => formipay_date('Y-m-d H:i:s')
|
|
]);
|
|
|
|
return $token;
|
|
}
|
|
|
|
/**
|
|
* Validate token and retrieve order data
|
|
*
|
|
* @param string $token
|
|
* @return array|false
|
|
*/
|
|
public function validate(string $token) {
|
|
global $wpdb;
|
|
|
|
// Validate token format
|
|
if (!preg_match('/^[a-f0-9]{64}$/', $token)) return false;
|
|
|
|
$query = $wpdb->prepare(
|
|
"SELECT form_id, order_id
|
|
FROM {$this->table_name}
|
|
WHERE token = %s
|
|
AND expires_at > NOW()
|
|
AND used = 0",
|
|
$token
|
|
);
|
|
|
|
return $wpdb->get_row($query, ARRAY_A);
|
|
}
|
|
|
|
/**
|
|
* Mark token as used
|
|
*
|
|
* @param string $token
|
|
* @return bool
|
|
*/
|
|
public function mark_used(string $token): bool {
|
|
global $wpdb;
|
|
return (bool) $wpdb->update(
|
|
$this->table_name,
|
|
['used' => 1],
|
|
['token' => $token]
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Cleanup expired tokens
|
|
*/
|
|
public function cleanup_expired_tokens() {
|
|
global $wpdb;
|
|
$wpdb->query("DELETE FROM {$this->table_name} WHERE expires_at < NOW()");
|
|
}
|
|
|
|
/**
|
|
* Get token usage count
|
|
*
|
|
* @param string $token
|
|
* @return int
|
|
*/
|
|
public function get_usage_count(string $token): int {
|
|
global $wpdb;
|
|
return (int) $wpdb->get_var($wpdb->prepare(
|
|
"SELECT use_count FROM {$this->table_name} WHERE token = %s",
|
|
$token
|
|
));
|
|
}
|
|
|
|
/**
|
|
* Increment token usage
|
|
*
|
|
* @param string $token
|
|
* @param int $max_uses
|
|
* @return bool
|
|
* @throws Exception
|
|
*/
|
|
public function increment_usage(string $token, int $max_uses = 5): bool {
|
|
global $wpdb;
|
|
|
|
$current_count = $this->get_usage_count($token);
|
|
if ($current_count >= $max_uses) {
|
|
throw new Exception('Token usage limit reached');
|
|
}
|
|
|
|
return (bool) $wpdb->update(
|
|
$this->table_name,
|
|
['use_count' => $current_count + 1],
|
|
['token' => $token]
|
|
);
|
|
}
|
|
}
|