653 lines
21 KiB
PHP
653 lines
21 KiB
PHP
<?php
|
|
require_once __DIR__ . '/config.php';
|
|
|
|
if (session_status() === PHP_SESSION_NONE && !headers_sent()) {
|
|
@session_start();
|
|
}
|
|
|
|
function clm_cfg($key = null)
|
|
{
|
|
$config = clm_config();
|
|
return $key === null ? $config : ($config[$key] ?? null);
|
|
}
|
|
|
|
function clm_safe_identifier($value): string
|
|
{
|
|
return preg_replace('/[^a-zA-Z0-9_]/', '', (string)$value);
|
|
}
|
|
|
|
function clm_tables(): array
|
|
{
|
|
$prefix = clm_safe_identifier(clm_cfg('table_prefix') ?: 'clm_');
|
|
|
|
return [
|
|
'apps' => $prefix . 'apps',
|
|
'licenses' => $prefix . 'licenses',
|
|
'activations' => $prefix . 'activations',
|
|
];
|
|
}
|
|
|
|
function clm_table(string $name): string
|
|
{
|
|
$tables = clm_tables();
|
|
return $tables[$name] ?? clm_safe_identifier((clm_cfg('table_prefix') ?: 'clm_') . $name);
|
|
}
|
|
|
|
function clm_html($value): string
|
|
{
|
|
return htmlspecialchars((string)$value, ENT_QUOTES, 'UTF-8');
|
|
}
|
|
|
|
function clm_base_url(): string
|
|
{
|
|
if (PHP_SAPI === 'cli') {
|
|
return '';
|
|
}
|
|
|
|
$scheme = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? 'https' : 'http';
|
|
$host = $_SERVER['HTTP_HOST'] ?? 'localhost';
|
|
$dir = rtrim(str_replace('\\', '/', dirname($_SERVER['SCRIPT_NAME'] ?? '/central_license_manager/index.php')), '/');
|
|
|
|
if ($dir === '.' || $dir == '/') {
|
|
$dir = '';
|
|
}
|
|
|
|
return $scheme . '://' . $host . $dir;
|
|
}
|
|
|
|
function clm_using_parent_db(): bool
|
|
{
|
|
$config = clm_cfg();
|
|
|
|
return $config['db_host'] === ''
|
|
&& $config['db_name'] === ''
|
|
&& $config['db_user'] === ''
|
|
&& file_exists(__DIR__ . '/../db/config.php');
|
|
}
|
|
|
|
function clm_db(): PDO
|
|
{
|
|
static $pdo = null;
|
|
|
|
if ($pdo instanceof PDO) {
|
|
return $pdo;
|
|
}
|
|
|
|
$config = clm_cfg();
|
|
|
|
if (clm_using_parent_db()) {
|
|
require_once __DIR__ . '/../db/config.php';
|
|
$pdo = db();
|
|
return $pdo;
|
|
}
|
|
|
|
if ($config['db_host'] === '' || $config['db_name'] === '' || $config['db_user'] === '') {
|
|
throw new RuntimeException('Central License Manager DB is not configured. Set CLM_DB_HOST, CLM_DB_NAME, CLM_DB_USER and CLM_DB_PASS in config.php or the environment before moving this folder to another server.');
|
|
}
|
|
|
|
$dsn = 'mysql:host=' . $config['db_host'] . ';dbname=' . $config['db_name'] . ';charset=' . ($config['db_charset'] ?: 'utf8mb4');
|
|
$pdo = new PDO($dsn, $config['db_user'], $config['db_pass'], [
|
|
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
|
|
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
|
|
]);
|
|
|
|
return $pdo;
|
|
}
|
|
|
|
function clm_column_exists(string $table, string $column): bool
|
|
{
|
|
$table = clm_safe_identifier($table);
|
|
$column = clm_safe_identifier($column);
|
|
$stmt = clm_db()->prepare("SHOW COLUMNS FROM `{$table}` LIKE ?");
|
|
$stmt->execute([$column]);
|
|
return (bool)$stmt->fetch();
|
|
}
|
|
|
|
function clm_ensure_schema(): void
|
|
{
|
|
static $ready = false;
|
|
|
|
if ($ready) {
|
|
return;
|
|
}
|
|
|
|
$ready = true;
|
|
$pdo = clm_db();
|
|
$tables = clm_tables();
|
|
$apps = $tables['apps'];
|
|
$licenses = $tables['licenses'];
|
|
$activations = $tables['activations'];
|
|
|
|
$pdo->exec("CREATE TABLE IF NOT EXISTS `{$apps}` (
|
|
`id` INT AUTO_INCREMENT PRIMARY KEY,
|
|
`slug` VARCHAR(120) NOT NULL UNIQUE,
|
|
`name` VARCHAR(190) NOT NULL,
|
|
`status` ENUM('active', 'inactive') NOT NULL DEFAULT 'active',
|
|
`notes` TEXT DEFAULT NULL,
|
|
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4");
|
|
|
|
$pdo->exec("CREATE TABLE IF NOT EXISTS `{$licenses}` (
|
|
`id` INT AUTO_INCREMENT PRIMARY KEY,
|
|
`app_id` INT NOT NULL,
|
|
`license_key` VARCHAR(255) NOT NULL UNIQUE,
|
|
`max_activations` INT NOT NULL DEFAULT 1,
|
|
`max_counters` INT NOT NULL DEFAULT 1,
|
|
`status` ENUM('active', 'suspended', 'expired') NOT NULL DEFAULT 'active',
|
|
`owner` VARCHAR(255) DEFAULT NULL,
|
|
`address` TEXT DEFAULT NULL,
|
|
`customer_name` VARCHAR(255) DEFAULT NULL,
|
|
`customer_email` VARCHAR(255) DEFAULT NULL,
|
|
`notes` TEXT DEFAULT NULL,
|
|
`expires_at` DATETIME DEFAULT NULL,
|
|
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
|
INDEX `idx_clm_app_id` (`app_id`),
|
|
FOREIGN KEY (`app_id`) REFERENCES `{$apps}`(`id`) ON DELETE CASCADE
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4");
|
|
|
|
$pdo->exec("CREATE TABLE IF NOT EXISTS `{$activations}` (
|
|
`id` INT AUTO_INCREMENT PRIMARY KEY,
|
|
`license_id` INT NOT NULL,
|
|
`fingerprint` VARCHAR(255) NOT NULL,
|
|
`domain` VARCHAR(255) DEFAULT NULL,
|
|
`product` VARCHAR(255) DEFAULT NULL,
|
|
`product_version` VARCHAR(120) DEFAULT NULL,
|
|
`app_slug` VARCHAR(120) DEFAULT NULL,
|
|
`status` ENUM('active', 'deactivated') NOT NULL DEFAULT 'active',
|
|
`activation_token` VARCHAR(255) DEFAULT NULL,
|
|
`activated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
`last_seen_at` DATETIME DEFAULT NULL,
|
|
`deactivated_at` DATETIME DEFAULT NULL,
|
|
UNIQUE KEY `uniq_clm_license_machine` (`license_id`, `fingerprint`),
|
|
INDEX `idx_clm_activation_status` (`status`),
|
|
INDEX `idx_clm_activation_domain` (`domain`),
|
|
FOREIGN KEY (`license_id`) REFERENCES `{$licenses}`(`id`) ON DELETE CASCADE
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4");
|
|
|
|
$licenseAlterMap = [
|
|
'customer_name' => "ALTER TABLE `{$licenses}` ADD COLUMN `customer_name` VARCHAR(255) DEFAULT NULL AFTER `address`",
|
|
'customer_email' => "ALTER TABLE `{$licenses}` ADD COLUMN `customer_email` VARCHAR(255) DEFAULT NULL AFTER `customer_name`",
|
|
'notes' => "ALTER TABLE `{$licenses}` ADD COLUMN `notes` TEXT DEFAULT NULL AFTER `customer_email`",
|
|
'expires_at' => "ALTER TABLE `{$licenses}` ADD COLUMN `expires_at` DATETIME DEFAULT NULL AFTER `notes`",
|
|
'max_counters' => "ALTER TABLE `{$licenses}` ADD COLUMN `max_counters` INT NOT NULL DEFAULT 1 AFTER `max_activations`",
|
|
];
|
|
|
|
foreach ($licenseAlterMap as $column => $sql) {
|
|
if (!clm_column_exists($licenses, $column)) {
|
|
$pdo->exec($sql);
|
|
}
|
|
}
|
|
|
|
$activationAlterMap = [
|
|
'product_version' => "ALTER TABLE `{$activations}` ADD COLUMN `product_version` VARCHAR(120) DEFAULT NULL AFTER `product`",
|
|
'app_slug' => "ALTER TABLE `{$activations}` ADD COLUMN `app_slug` VARCHAR(120) DEFAULT NULL AFTER `product_version`",
|
|
'status' => "ALTER TABLE `{$activations}` ADD COLUMN `status` ENUM('active', 'deactivated') NOT NULL DEFAULT 'active' AFTER `app_slug`",
|
|
'activation_token' => "ALTER TABLE `{$activations}` ADD COLUMN `activation_token` VARCHAR(255) DEFAULT NULL AFTER `status`",
|
|
'last_seen_at' => "ALTER TABLE `{$activations}` ADD COLUMN `last_seen_at` DATETIME DEFAULT NULL AFTER `activated_at`",
|
|
'deactivated_at' => "ALTER TABLE `{$activations}` ADD COLUMN `deactivated_at` DATETIME DEFAULT NULL AFTER `last_seen_at`",
|
|
];
|
|
|
|
foreach ($activationAlterMap as $column => $sql) {
|
|
if (!clm_column_exists($activations, $column)) {
|
|
$pdo->exec($sql);
|
|
}
|
|
}
|
|
|
|
clm_resolve_app((string)clm_cfg('default_app_slug'), (string)clm_cfg('default_app_name'), true);
|
|
}
|
|
|
|
function clm_slugify($value): string
|
|
{
|
|
$value = strtolower(trim((string)$value));
|
|
$value = preg_replace('/[^a-z0-9]+/', '-', $value);
|
|
$value = trim((string)$value, '-');
|
|
|
|
if ($value === '') {
|
|
$value = strtolower((string)(clm_cfg('default_app_slug') ?: 'legacy'));
|
|
}
|
|
|
|
return $value;
|
|
}
|
|
|
|
function clm_secret_valid($secret): bool
|
|
{
|
|
return hash_equals((string)clm_cfg('api_secret'), (string)$secret);
|
|
}
|
|
|
|
function clm_resolve_app(string $slug = '', string $name = '', bool $createIfMissing = false): ?array
|
|
{
|
|
clm_ensure_schema();
|
|
|
|
$tables = clm_tables();
|
|
$apps = $tables['apps'];
|
|
$slug = clm_slugify($slug !== '' ? $slug : ($name !== '' ? $name : (string)clm_cfg('default_app_slug')));
|
|
$name = trim($name) !== '' ? trim($name) : ucwords(str_replace('-', ' ', $slug));
|
|
|
|
$stmt = clm_db()->prepare("SELECT * FROM `{$apps}` WHERE slug = ? LIMIT 1");
|
|
$stmt->execute([$slug]);
|
|
$app = $stmt->fetch();
|
|
|
|
if ($app) {
|
|
return $app;
|
|
}
|
|
|
|
if (!$createIfMissing) {
|
|
return null;
|
|
}
|
|
|
|
$stmt = clm_db()->prepare("INSERT INTO `{$apps}` (slug, name, status) VALUES (?, ?, 'active')");
|
|
$stmt->execute([$slug, $name]);
|
|
|
|
$stmt = clm_db()->prepare("SELECT * FROM `{$apps}` WHERE slug = ? LIMIT 1");
|
|
$stmt->execute([$slug]);
|
|
return $stmt->fetch() ?: null;
|
|
}
|
|
|
|
function clm_app_by_id(int $id): ?array
|
|
{
|
|
clm_ensure_schema();
|
|
|
|
$apps = clm_table('apps');
|
|
$stmt = clm_db()->prepare("SELECT * FROM `{$apps}` WHERE id = ? LIMIT 1");
|
|
$stmt->execute([$id]);
|
|
$row = $stmt->fetch();
|
|
|
|
return $row ?: null;
|
|
}
|
|
|
|
function clm_update_app_record(array $app, array $data): array
|
|
{
|
|
clm_ensure_schema();
|
|
|
|
$apps = clm_table('apps');
|
|
$fields = [];
|
|
$params = [];
|
|
|
|
if (array_key_exists('name', $data) || array_key_exists('slug', $data)) {
|
|
$name = trim((string)($data['name'] ?? (string)$app['name']));
|
|
$slugInput = trim((string)($data['slug'] ?? (string)$app['slug']));
|
|
|
|
if ($name === '' && $slugInput === '') {
|
|
throw new RuntimeException('App name or slug is required.');
|
|
}
|
|
|
|
$slug = clm_slugify($slugInput !== '' ? $slugInput : $name);
|
|
$name = $name !== '' ? $name : ucwords(str_replace('-', ' ', $slug));
|
|
|
|
$check = clm_db()->prepare("SELECT id FROM `{$apps}` WHERE slug = ? AND id <> ? LIMIT 1");
|
|
$check->execute([$slug, (int)$app['id']]);
|
|
if ($check->fetch()) {
|
|
throw new RuntimeException('Another app already uses this slug.');
|
|
}
|
|
|
|
$fields[] = '`name` = ?';
|
|
$params[] = $name;
|
|
$fields[] = '`slug` = ?';
|
|
$params[] = $slug;
|
|
}
|
|
|
|
if (isset($data['status'])) {
|
|
$status = strtolower(trim((string)$data['status']));
|
|
if (in_array($status, ['active', 'inactive'], true)) {
|
|
$fields[] = '`status` = ?';
|
|
$params[] = $status;
|
|
}
|
|
}
|
|
|
|
if (empty($fields)) {
|
|
return clm_app_by_id((int)$app['id']) ?: $app;
|
|
}
|
|
|
|
$params[] = (int)$app['id'];
|
|
$stmt = clm_db()->prepare("UPDATE `{$apps}` SET " . implode(', ', $fields) . " WHERE id = ?");
|
|
$stmt->execute($params);
|
|
|
|
return clm_app_by_id((int)$app['id']) ?: $app;
|
|
}
|
|
|
|
function clm_license_with_app_by_key(string $licenseKey): ?array
|
|
{
|
|
clm_ensure_schema();
|
|
|
|
$tables = clm_tables();
|
|
$licenses = $tables['licenses'];
|
|
$apps = $tables['apps'];
|
|
|
|
$stmt = clm_db()->prepare("SELECT l.*, a.slug AS app_slug, a.name AS app_name
|
|
FROM `{$licenses}` l
|
|
INNER JOIN `{$apps}` a ON a.id = l.app_id
|
|
WHERE l.license_key = ?
|
|
LIMIT 1");
|
|
$stmt->execute([strtoupper(trim($licenseKey))]);
|
|
$row = $stmt->fetch();
|
|
|
|
return $row ?: null;
|
|
}
|
|
|
|
function clm_license_with_app_by_id(int $id): ?array
|
|
{
|
|
clm_ensure_schema();
|
|
|
|
$tables = clm_tables();
|
|
$licenses = $tables['licenses'];
|
|
$apps = $tables['apps'];
|
|
|
|
$stmt = clm_db()->prepare("SELECT l.*, a.slug AS app_slug, a.name AS app_name
|
|
FROM `{$licenses}` l
|
|
INNER JOIN `{$apps}` a ON a.id = l.app_id
|
|
WHERE l.id = ?
|
|
LIMIT 1");
|
|
$stmt->execute([$id]);
|
|
$row = $stmt->fetch();
|
|
|
|
return $row ?: null;
|
|
}
|
|
|
|
function clm_generate_license_key(string $prefix = 'FLAT'): string
|
|
{
|
|
$prefix = preg_replace('/[^A-Z0-9]/', '', strtoupper(trim($prefix))) ?: 'FLAT';
|
|
|
|
do {
|
|
$key = $prefix
|
|
. '-' . strtoupper(bin2hex(random_bytes(2)))
|
|
. '-' . strtoupper(bin2hex(random_bytes(2)))
|
|
. '-' . strtoupper(bin2hex(random_bytes(2)));
|
|
} while (clm_license_with_app_by_key($key));
|
|
|
|
return $key;
|
|
}
|
|
|
|
function clm_make_token(string $licenseKey, string $fingerprint): string
|
|
{
|
|
return hash_hmac('sha256', strtoupper(trim($licenseKey)) . $fingerprint, (string)clm_cfg('api_secret'));
|
|
}
|
|
|
|
function clm_active_activation_count(int $licenseId): int
|
|
{
|
|
clm_ensure_schema();
|
|
|
|
$activations = clm_table('activations');
|
|
$stmt = clm_db()->prepare("SELECT COUNT(*) FROM `{$activations}` WHERE license_id = ? AND status = 'active'");
|
|
$stmt->execute([$licenseId]);
|
|
|
|
return (int)$stmt->fetchColumn();
|
|
}
|
|
|
|
function clm_license_is_expired(array $license): bool
|
|
{
|
|
if (empty($license['expires_at'])) {
|
|
return false;
|
|
}
|
|
|
|
$expiresAt = strtotime((string)$license['expires_at']);
|
|
return $expiresAt !== false && $expiresAt < time();
|
|
}
|
|
|
|
function clm_upsert_activation(array $license, string $fingerprint, string $domain = '', string $product = '', string $productVersion = ''): array
|
|
{
|
|
clm_ensure_schema();
|
|
|
|
$activations = clm_table('activations');
|
|
$pdo = clm_db();
|
|
$token = clm_make_token((string)$license['license_key'], $fingerprint);
|
|
$product = trim($product) !== '' ? trim($product) : (string)$license['app_name'];
|
|
|
|
$stmt = $pdo->prepare("SELECT * FROM `{$activations}` WHERE license_id = ? AND fingerprint = ? LIMIT 1");
|
|
$stmt->execute([(int)$license['id'], $fingerprint]);
|
|
$existing = $stmt->fetch();
|
|
$currentActive = clm_active_activation_count((int)$license['id']);
|
|
|
|
if ($existing) {
|
|
if (($existing['status'] ?? 'active') !== 'active' && $currentActive >= (int)$license['max_activations']) {
|
|
return [
|
|
'success' => false,
|
|
'error' => 'Maximum activation limit reached.'
|
|
];
|
|
}
|
|
|
|
$stmt = $pdo->prepare("UPDATE `{$activations}`
|
|
SET domain = ?,
|
|
product = ?,
|
|
product_version = ?,
|
|
app_slug = ?,
|
|
status = 'active',
|
|
activation_token = ?,
|
|
last_seen_at = NOW(),
|
|
deactivated_at = NULL
|
|
WHERE id = ?");
|
|
$stmt->execute([
|
|
$domain !== '' ? $domain : null,
|
|
$product,
|
|
$productVersion !== '' ? $productVersion : null,
|
|
(string)$license['app_slug'],
|
|
$token,
|
|
(int)$existing['id'],
|
|
]);
|
|
} else {
|
|
if ($currentActive >= (int)$license['max_activations']) {
|
|
return [
|
|
'success' => false,
|
|
'error' => 'Maximum activation limit reached.'
|
|
];
|
|
}
|
|
|
|
$stmt = $pdo->prepare("INSERT INTO `{$activations}`
|
|
(license_id, fingerprint, domain, product, product_version, app_slug, status, activation_token, last_seen_at)
|
|
VALUES (?, ?, ?, ?, ?, ?, 'active', ?, NOW())");
|
|
$stmt->execute([
|
|
(int)$license['id'],
|
|
$fingerprint,
|
|
$domain !== '' ? $domain : null,
|
|
$product,
|
|
$productVersion !== '' ? $productVersion : null,
|
|
(string)$license['app_slug'],
|
|
$token,
|
|
]);
|
|
}
|
|
|
|
return [
|
|
'success' => true,
|
|
'activation_token' => $token,
|
|
];
|
|
}
|
|
|
|
function clm_request_data(): array
|
|
{
|
|
$data = [];
|
|
$raw = file_get_contents('php://input');
|
|
|
|
if (is_string($raw) && trim($raw) !== '') {
|
|
$decoded = json_decode($raw, true);
|
|
if (is_array($decoded)) {
|
|
$data = $decoded;
|
|
}
|
|
}
|
|
|
|
if (!empty($_POST)) {
|
|
$data = array_merge($data, $_POST);
|
|
}
|
|
|
|
if (!empty($_GET)) {
|
|
$data = array_merge($data, $_GET);
|
|
}
|
|
|
|
return $data;
|
|
}
|
|
|
|
function clm_json(array $data, int $status = 200): void
|
|
{
|
|
if (!headers_sent()) {
|
|
http_response_code($status);
|
|
header('Content-Type: application/json; charset=UTF-8');
|
|
}
|
|
|
|
echo json_encode($data, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
|
|
exit;
|
|
}
|
|
|
|
function clm_issue_license_record(array $data): array
|
|
{
|
|
clm_ensure_schema();
|
|
|
|
$tables = clm_tables();
|
|
$licenses = $tables['licenses'];
|
|
$app = clm_resolve_app((string)($data['app_slug'] ?? ''), (string)($data['app_name'] ?? ''), true);
|
|
|
|
if (!$app) {
|
|
throw new RuntimeException('Unable to resolve app.');
|
|
}
|
|
|
|
$licenseKey = strtoupper(trim((string)($data['license_key'] ?? '')));
|
|
if ($licenseKey === '') {
|
|
$licenseKey = clm_generate_license_key((string)($data['prefix'] ?? 'FLAT'));
|
|
}
|
|
|
|
$maxActivations = max(1, (int)($data['max_activations'] ?? 1));
|
|
$maxCounters = max(1, (int)($data['max_counters'] ?? 1));
|
|
$owner = trim((string)($data['owner'] ?? ''));
|
|
$address = trim((string)($data['address'] ?? ''));
|
|
$customerName = trim((string)($data['customer_name'] ?? $owner));
|
|
$customerEmail = trim((string)($data['customer_email'] ?? ''));
|
|
$notes = trim((string)($data['notes'] ?? ''));
|
|
$expiresAt = trim((string)($data['expires_at'] ?? ''));
|
|
|
|
$stmt = clm_db()->prepare("INSERT INTO `{$licenses}`
|
|
(app_id, license_key, max_activations, max_counters, status, owner, address, customer_name, customer_email, notes, expires_at)
|
|
VALUES (?, ?, ?, ?, 'active', ?, ?, ?, ?, ?, ?)");
|
|
$stmt->execute([
|
|
(int)$app['id'],
|
|
$licenseKey,
|
|
$maxActivations,
|
|
$maxCounters,
|
|
$owner !== '' ? $owner : null,
|
|
$address !== '' ? $address : null,
|
|
$customerName !== '' ? $customerName : null,
|
|
$customerEmail !== '' ? $customerEmail : null,
|
|
$notes !== '' ? $notes : null,
|
|
$expiresAt !== '' ? $expiresAt : null,
|
|
]);
|
|
|
|
$license = clm_license_with_app_by_key($licenseKey);
|
|
|
|
if (!$license) {
|
|
throw new RuntimeException('License was created but could not be reloaded.');
|
|
}
|
|
|
|
return $license;
|
|
}
|
|
|
|
function clm_update_license_record(array $license, array $data): array
|
|
{
|
|
clm_ensure_schema();
|
|
|
|
$licenses = clm_table('licenses');
|
|
$fields = [];
|
|
$params = [];
|
|
|
|
if (isset($data['status'])) {
|
|
$status = strtolower(trim((string)$data['status']));
|
|
if (in_array($status, ['active', 'suspended', 'expired'], true)) {
|
|
$fields[] = '`status` = ?';
|
|
$params[] = $status;
|
|
}
|
|
}
|
|
|
|
if (isset($data['max_activations']) && (int)$data['max_activations'] > 0) {
|
|
$fields[] = '`max_activations` = ?';
|
|
$params[] = max(1, (int)$data['max_activations']);
|
|
}
|
|
|
|
if (isset($data['max_counters']) && (int)$data['max_counters'] > 0) {
|
|
$fields[] = '`max_counters` = ?';
|
|
$params[] = max(1, (int)$data['max_counters']);
|
|
}
|
|
|
|
if (array_key_exists('owner', $data)) {
|
|
$fields[] = '`owner` = ?';
|
|
$owner = trim((string)$data['owner']);
|
|
$params[] = $owner !== '' ? $owner : null;
|
|
}
|
|
|
|
if (array_key_exists('address', $data)) {
|
|
$fields[] = '`address` = ?';
|
|
$address = trim((string)$data['address']);
|
|
$params[] = $address !== '' ? $address : null;
|
|
}
|
|
|
|
if (array_key_exists('customer_name', $data)) {
|
|
$fields[] = '`customer_name` = ?';
|
|
$customerName = trim((string)$data['customer_name']);
|
|
$params[] = $customerName !== '' ? $customerName : null;
|
|
}
|
|
|
|
if (array_key_exists('customer_email', $data)) {
|
|
$fields[] = '`customer_email` = ?';
|
|
$customerEmail = trim((string)$data['customer_email']);
|
|
$params[] = $customerEmail !== '' ? $customerEmail : null;
|
|
}
|
|
|
|
if (array_key_exists('notes', $data)) {
|
|
$fields[] = '`notes` = ?';
|
|
$notes = trim((string)$data['notes']);
|
|
$params[] = $notes !== '' ? $notes : null;
|
|
}
|
|
|
|
if (array_key_exists('expires_at', $data)) {
|
|
$fields[] = '`expires_at` = ?';
|
|
$expiresAt = trim((string)$data['expires_at']);
|
|
$params[] = $expiresAt !== '' ? $expiresAt : null;
|
|
}
|
|
|
|
if (isset($data['app_slug']) || isset($data['app_name'])) {
|
|
$app = clm_resolve_app((string)($data['app_slug'] ?? ''), (string)($data['app_name'] ?? ''), true);
|
|
if ($app) {
|
|
$fields[] = '`app_id` = ?';
|
|
$params[] = (int)$app['id'];
|
|
}
|
|
}
|
|
|
|
if (empty($fields)) {
|
|
return clm_license_with_app_by_id((int)$license['id']) ?: $license;
|
|
}
|
|
|
|
$params[] = (int)$license['id'];
|
|
$sql = "UPDATE `{$licenses}` SET " . implode(', ', $fields) . " WHERE id = ?";
|
|
$stmt = clm_db()->prepare($sql);
|
|
$stmt->execute($params);
|
|
|
|
return clm_license_with_app_by_id((int)$license['id']) ?: $license;
|
|
}
|
|
|
|
function clm_set_flash(string $type, string $message): void
|
|
{
|
|
$_SESSION['clm_flash'] = [
|
|
'type' => $type,
|
|
'message' => $message,
|
|
];
|
|
}
|
|
|
|
function clm_get_flash(): ?array
|
|
{
|
|
if (empty($_SESSION['clm_flash'])) {
|
|
return null;
|
|
}
|
|
|
|
$flash = $_SESSION['clm_flash'];
|
|
unset($_SESSION['clm_flash']);
|
|
|
|
return is_array($flash) ? $flash : null;
|
|
}
|
|
|
|
function clm_redirect(string $location): void
|
|
{
|
|
header('Location: ' . $location);
|
|
exit;
|
|
}
|
|
|
|
function clm_manager_mode_label(): string
|
|
{
|
|
return clm_using_parent_db() ? 'Using current app database' : 'Using standalone CLM database settings';
|
|
}
|