802 lines
29 KiB
PHP
802 lines
29 KiB
PHP
<?php
|
|
|
|
require_once __DIR__ . '/config.php';
|
|
|
|
function scmanutention_column_exists(PDO $db, string $table, string $column): bool
|
|
{
|
|
$stmt = $db->query("SHOW COLUMNS FROM `{$table}` LIKE " . $db->quote($column));
|
|
|
|
return (bool) $stmt->fetch();
|
|
}
|
|
|
|
function scmanutention_index_exists(PDO $db, string $table, string $index): bool
|
|
{
|
|
$stmt = $db->query("SHOW INDEX FROM `{$table}` WHERE Key_name = " . $db->quote($index));
|
|
|
|
return (bool) $stmt->fetch();
|
|
}
|
|
|
|
function scmanutention_foreign_key_exists(PDO $db, string $table, string $constraint): bool
|
|
{
|
|
$stmt = $db->prepare(
|
|
"SELECT COUNT(*)
|
|
FROM information_schema.TABLE_CONSTRAINTS
|
|
WHERE TABLE_SCHEMA = DATABASE()
|
|
AND TABLE_NAME = :table_name
|
|
AND CONSTRAINT_NAME = :constraint_name
|
|
AND CONSTRAINT_TYPE = 'FOREIGN KEY'"
|
|
);
|
|
$stmt->execute([
|
|
'table_name' => $table,
|
|
'constraint_name' => $constraint,
|
|
]);
|
|
|
|
return (int) $stmt->fetchColumn() > 0;
|
|
}
|
|
|
|
function scmanutention_bootstrap(): void
|
|
{
|
|
static $bootstrapped = false;
|
|
|
|
if ($bootstrapped) {
|
|
return;
|
|
}
|
|
|
|
$db = db();
|
|
|
|
$db->exec(
|
|
"CREATE TABLE IF NOT EXISTS tbl_scmanutentions (
|
|
cl_scmanutention_id INT UNSIGNED NOT NULL AUTO_INCREMENT,
|
|
cl_scmanutention_owner_auth_id INT UNSIGNED NOT NULL,
|
|
cl_scmanutention_title VARCHAR(190) NOT NULL,
|
|
cl_scmanutention_type VARCHAR(120) NOT NULL DEFAULT '',
|
|
cl_scmanutention_subtype VARCHAR(120) NOT NULL DEFAULT '',
|
|
cl_scmanutention_description TEXT DEFAULT NULL,
|
|
cl_scmanutention_share_token VARCHAR(64) NOT NULL,
|
|
cl_scmanutention_share_enabled TINYINT(1) NOT NULL DEFAULT 0,
|
|
cl_scmanutention_created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
cl_scmanutention_updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
|
PRIMARY KEY (cl_scmanutention_id),
|
|
UNIQUE KEY uq_scmanutention_share_token (cl_scmanutention_share_token),
|
|
KEY idx_scmanutention_owner (cl_scmanutention_owner_auth_id),
|
|
KEY idx_scmanutention_title (cl_scmanutention_title),
|
|
CONSTRAINT fk_scmanutention_owner_auth FOREIGN KEY (cl_scmanutention_owner_auth_id)
|
|
REFERENCES tbl_auth (cl_auth_id)
|
|
ON DELETE CASCADE
|
|
ON UPDATE CASCADE
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci"
|
|
);
|
|
|
|
if (!scmanutention_column_exists($db, 'tbl_scmanutentions', 'cl_scmanutention_owner_auth_id')) {
|
|
$db->exec(
|
|
'ALTER TABLE tbl_scmanutentions
|
|
ADD COLUMN cl_scmanutention_owner_auth_id INT UNSIGNED NULL AFTER cl_scmanutention_id'
|
|
);
|
|
}
|
|
|
|
if (!scmanutention_column_exists($db, 'tbl_scmanutentions', 'cl_scmanutention_type')) {
|
|
$db->exec(
|
|
"ALTER TABLE tbl_scmanutentions
|
|
ADD COLUMN cl_scmanutention_type VARCHAR(120) NOT NULL DEFAULT '' AFTER cl_scmanutention_title"
|
|
);
|
|
}
|
|
|
|
if (!scmanutention_column_exists($db, 'tbl_scmanutentions', 'cl_scmanutention_subtype')) {
|
|
$db->exec(
|
|
"ALTER TABLE tbl_scmanutentions
|
|
ADD COLUMN cl_scmanutention_subtype VARCHAR(120) NOT NULL DEFAULT '' AFTER cl_scmanutention_type"
|
|
);
|
|
}
|
|
|
|
if (!scmanutention_column_exists($db, 'tbl_scmanutentions', 'cl_scmanutention_description')) {
|
|
$db->exec(
|
|
'ALTER TABLE tbl_scmanutentions
|
|
ADD COLUMN cl_scmanutention_description TEXT NULL AFTER cl_scmanutention_subtype'
|
|
);
|
|
}
|
|
|
|
if (!scmanutention_column_exists($db, 'tbl_scmanutentions', 'cl_scmanutention_share_token')) {
|
|
$db->exec(
|
|
"ALTER TABLE tbl_scmanutentions
|
|
ADD COLUMN cl_scmanutention_share_token VARCHAR(64) NOT NULL DEFAULT '' AFTER cl_scmanutention_description"
|
|
);
|
|
}
|
|
|
|
if (!scmanutention_column_exists($db, 'tbl_scmanutentions', 'cl_scmanutention_share_enabled')) {
|
|
$db->exec(
|
|
'ALTER TABLE tbl_scmanutentions
|
|
ADD COLUMN cl_scmanutention_share_enabled TINYINT(1) NOT NULL DEFAULT 0 AFTER cl_scmanutention_share_token'
|
|
);
|
|
}
|
|
|
|
if (!scmanutention_index_exists($db, 'tbl_scmanutentions', 'idx_scmanutention_owner')) {
|
|
$db->exec(
|
|
'ALTER TABLE tbl_scmanutentions
|
|
ADD INDEX idx_scmanutention_owner (cl_scmanutention_owner_auth_id)'
|
|
);
|
|
}
|
|
|
|
if (!scmanutention_index_exists($db, 'tbl_scmanutentions', 'idx_scmanutention_title')) {
|
|
$db->exec(
|
|
'ALTER TABLE tbl_scmanutentions
|
|
ADD INDEX idx_scmanutention_title (cl_scmanutention_title)'
|
|
);
|
|
}
|
|
|
|
if (!scmanutention_index_exists($db, 'tbl_scmanutentions', 'uq_scmanutention_share_token')) {
|
|
$db->exec(
|
|
'ALTER TABLE tbl_scmanutentions
|
|
ADD UNIQUE KEY uq_scmanutention_share_token (cl_scmanutention_share_token)'
|
|
);
|
|
}
|
|
|
|
if (!scmanutention_foreign_key_exists($db, 'tbl_scmanutentions', 'fk_scmanutention_owner_auth')) {
|
|
$db->exec(
|
|
'ALTER TABLE tbl_scmanutentions
|
|
ADD CONSTRAINT fk_scmanutention_owner_auth FOREIGN KEY (cl_scmanutention_owner_auth_id)
|
|
REFERENCES tbl_auth (cl_auth_id)
|
|
ON DELETE CASCADE
|
|
ON UPDATE CASCADE'
|
|
);
|
|
}
|
|
|
|
$db->exec(
|
|
"CREATE TABLE IF NOT EXISTS tbl_scmanutentionitems (
|
|
cl_scmanutentionitem_id INT UNSIGNED NOT NULL AUTO_INCREMENT,
|
|
cl_scmanutentionitem_manutention_id INT UNSIGNED NOT NULL,
|
|
cl_scmanutentionitem_source ENUM('base', 'custom') NOT NULL DEFAULT 'base',
|
|
cl_scmanutentionitem_scobjs_id INT UNSIGNED DEFAULT NULL,
|
|
cl_scmanutentionitem_scitemcustom_id INT(11) DEFAULT NULL,
|
|
cl_scmanutentionitem_quantity INT UNSIGNED NOT NULL DEFAULT 1,
|
|
cl_scmanutentionitem_extra_info TEXT DEFAULT NULL,
|
|
cl_scmanutentionitem_sort_order INT UNSIGNED NOT NULL DEFAULT 0,
|
|
cl_scmanutentionitem_created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
cl_scmanutentionitem_updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
|
PRIMARY KEY (cl_scmanutentionitem_id),
|
|
KEY idx_scmanutentionitem_sheet (cl_scmanutentionitem_manutention_id),
|
|
KEY idx_scmanutentionitem_scobjs (cl_scmanutentionitem_scobjs_id),
|
|
KEY idx_scmanutentionitem_scitemcustom (cl_scmanutentionitem_scitemcustom_id),
|
|
KEY idx_scmanutentionitem_sheet_sort (cl_scmanutentionitem_manutention_id, cl_scmanutentionitem_sort_order, cl_scmanutentionitem_id),
|
|
CONSTRAINT fk_scmanutentionitem_sheet FOREIGN KEY (cl_scmanutentionitem_manutention_id)
|
|
REFERENCES tbl_scmanutentions (cl_scmanutention_id)
|
|
ON DELETE CASCADE
|
|
ON UPDATE CASCADE,
|
|
CONSTRAINT fk_scmanutentionitem_scobjs FOREIGN KEY (cl_scmanutentionitem_scobjs_id)
|
|
REFERENCES tbl_scobjs (cl_scobjs_id)
|
|
ON DELETE SET NULL
|
|
ON UPDATE CASCADE,
|
|
CONSTRAINT fk_scmanutentionitem_scitemcustom FOREIGN KEY (cl_scmanutentionitem_scitemcustom_id)
|
|
REFERENCES tbl_scitemcustom (cl_scitemcustom_id)
|
|
ON DELETE SET NULL
|
|
ON UPDATE CASCADE
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci"
|
|
);
|
|
|
|
if (!scmanutention_column_exists($db, 'tbl_scmanutentionitems', 'cl_scmanutentionitem_source')) {
|
|
$db->exec(
|
|
"ALTER TABLE tbl_scmanutentionitems
|
|
ADD COLUMN cl_scmanutentionitem_source ENUM('base', 'custom') NOT NULL DEFAULT 'base' AFTER cl_scmanutentionitem_manutention_id"
|
|
);
|
|
}
|
|
|
|
if (!scmanutention_column_exists($db, 'tbl_scmanutentionitems', 'cl_scmanutentionitem_scobjs_id')) {
|
|
$db->exec(
|
|
'ALTER TABLE tbl_scmanutentionitems
|
|
ADD COLUMN cl_scmanutentionitem_scobjs_id INT UNSIGNED NULL AFTER cl_scmanutentionitem_source'
|
|
);
|
|
}
|
|
|
|
if (!scmanutention_column_exists($db, 'tbl_scmanutentionitems', 'cl_scmanutentionitem_scitemcustom_id')) {
|
|
$db->exec(
|
|
'ALTER TABLE tbl_scmanutentionitems
|
|
ADD COLUMN cl_scmanutentionitem_scitemcustom_id INT(11) NULL AFTER cl_scmanutentionitem_scobjs_id'
|
|
);
|
|
}
|
|
|
|
if (!scmanutention_column_exists($db, 'tbl_scmanutentionitems', 'cl_scmanutentionitem_quantity')) {
|
|
$db->exec(
|
|
'ALTER TABLE tbl_scmanutentionitems
|
|
ADD COLUMN cl_scmanutentionitem_quantity INT UNSIGNED NOT NULL DEFAULT 1 AFTER cl_scmanutentionitem_scitemcustom_id'
|
|
);
|
|
}
|
|
|
|
if (!scmanutention_column_exists($db, 'tbl_scmanutentionitems', 'cl_scmanutentionitem_extra_info')) {
|
|
$db->exec(
|
|
'ALTER TABLE tbl_scmanutentionitems
|
|
ADD COLUMN cl_scmanutentionitem_extra_info TEXT NULL AFTER cl_scmanutentionitem_quantity'
|
|
);
|
|
}
|
|
|
|
if (!scmanutention_column_exists($db, 'tbl_scmanutentionitems', 'cl_scmanutentionitem_sort_order')) {
|
|
$db->exec(
|
|
'ALTER TABLE tbl_scmanutentionitems
|
|
ADD COLUMN cl_scmanutentionitem_sort_order INT UNSIGNED NOT NULL DEFAULT 0 AFTER cl_scmanutentionitem_extra_info'
|
|
);
|
|
}
|
|
|
|
if (!scmanutention_index_exists($db, 'tbl_scmanutentionitems', 'idx_scmanutentionitem_sheet')) {
|
|
$db->exec(
|
|
'ALTER TABLE tbl_scmanutentionitems
|
|
ADD INDEX idx_scmanutentionitem_sheet (cl_scmanutentionitem_manutention_id)'
|
|
);
|
|
}
|
|
|
|
if (!scmanutention_index_exists($db, 'tbl_scmanutentionitems', 'idx_scmanutentionitem_scobjs')) {
|
|
$db->exec(
|
|
'ALTER TABLE tbl_scmanutentionitems
|
|
ADD INDEX idx_scmanutentionitem_scobjs (cl_scmanutentionitem_scobjs_id)'
|
|
);
|
|
}
|
|
|
|
if (!scmanutention_index_exists($db, 'tbl_scmanutentionitems', 'idx_scmanutentionitem_scitemcustom')) {
|
|
$db->exec(
|
|
'ALTER TABLE tbl_scmanutentionitems
|
|
ADD INDEX idx_scmanutentionitem_scitemcustom (cl_scmanutentionitem_scitemcustom_id)'
|
|
);
|
|
}
|
|
|
|
if (!scmanutention_index_exists($db, 'tbl_scmanutentionitems', 'idx_scmanutentionitem_sheet_sort')) {
|
|
$db->exec(
|
|
'ALTER TABLE tbl_scmanutentionitems
|
|
ADD INDEX idx_scmanutentionitem_sheet_sort (cl_scmanutentionitem_manutention_id, cl_scmanutentionitem_sort_order, cl_scmanutentionitem_id)'
|
|
);
|
|
}
|
|
|
|
if (!scmanutention_foreign_key_exists($db, 'tbl_scmanutentionitems', 'fk_scmanutentionitem_sheet')) {
|
|
$db->exec(
|
|
'ALTER TABLE tbl_scmanutentionitems
|
|
ADD CONSTRAINT fk_scmanutentionitem_sheet FOREIGN KEY (cl_scmanutentionitem_manutention_id)
|
|
REFERENCES tbl_scmanutentions (cl_scmanutention_id)
|
|
ON DELETE CASCADE
|
|
ON UPDATE CASCADE'
|
|
);
|
|
}
|
|
|
|
if (!scmanutention_foreign_key_exists($db, 'tbl_scmanutentionitems', 'fk_scmanutentionitem_scobjs')) {
|
|
$db->exec(
|
|
'ALTER TABLE tbl_scmanutentionitems
|
|
ADD CONSTRAINT fk_scmanutentionitem_scobjs FOREIGN KEY (cl_scmanutentionitem_scobjs_id)
|
|
REFERENCES tbl_scobjs (cl_scobjs_id)
|
|
ON DELETE SET NULL
|
|
ON UPDATE CASCADE'
|
|
);
|
|
}
|
|
|
|
if (!scmanutention_foreign_key_exists($db, 'tbl_scmanutentionitems', 'fk_scmanutentionitem_scitemcustom')) {
|
|
$db->exec(
|
|
'ALTER TABLE tbl_scmanutentionitems
|
|
ADD CONSTRAINT fk_scmanutentionitem_scitemcustom FOREIGN KEY (cl_scmanutentionitem_scitemcustom_id)
|
|
REFERENCES tbl_scitemcustom (cl_scitemcustom_id)
|
|
ON DELETE SET NULL
|
|
ON UPDATE CASCADE'
|
|
);
|
|
}
|
|
|
|
$stmt_missing_tokens = $db->query(
|
|
"SELECT cl_scmanutention_id
|
|
FROM tbl_scmanutentions
|
|
WHERE cl_scmanutention_share_token = ''
|
|
OR cl_scmanutention_share_token IS NULL"
|
|
);
|
|
|
|
foreach ($stmt_missing_tokens->fetchAll(PDO::FETCH_COLUMN) as $sheet_id) {
|
|
$stmt_update = $db->prepare(
|
|
'UPDATE tbl_scmanutentions
|
|
SET cl_scmanutention_share_token = :token
|
|
WHERE cl_scmanutention_id = :id'
|
|
);
|
|
$stmt_update->execute([
|
|
'token' => scmanutention_generate_share_token(),
|
|
'id' => (int) $sheet_id,
|
|
]);
|
|
}
|
|
|
|
$bootstrapped = true;
|
|
}
|
|
|
|
function scmanutention_generate_share_token(int $length = 32): string
|
|
{
|
|
$length = max(16, min(64, $length));
|
|
|
|
return bin2hex(random_bytes((int) ceil($length / 2)));
|
|
}
|
|
|
|
function scmanutention_clean_text(?string $value): string
|
|
{
|
|
return trim((string) $value);
|
|
}
|
|
|
|
function scmanutention_normalize_quantity($value): int
|
|
{
|
|
$quantity = (int) $value;
|
|
|
|
if ($quantity <= 0) {
|
|
return 1;
|
|
}
|
|
|
|
return min($quantity, 999999);
|
|
}
|
|
|
|
function scmanutention_is_valid_source(string $value): bool
|
|
{
|
|
return in_array($value, ['base', 'custom'], true);
|
|
}
|
|
|
|
function scmanutention_escape_like(string $value): string
|
|
{
|
|
return strtr($value, [
|
|
'\\' => '\\\\',
|
|
'%' => '\\%',
|
|
'_' => '\\_',
|
|
]);
|
|
}
|
|
|
|
function scmanutention_sheet_share_url(string $token): string
|
|
{
|
|
$is_https = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off')
|
|
|| (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https')
|
|
|| ((string) ($_SERVER['SERVER_PORT'] ?? '') === '443');
|
|
|
|
$scheme = $is_https ? 'https' : 'http';
|
|
$host = trim((string) ($_SERVER['HTTP_HOST'] ?? ''));
|
|
|
|
if ($host === '') {
|
|
$host = '127.0.0.1';
|
|
}
|
|
|
|
return $scheme . '://' . $host . '/scmanutentionpublic.php?share=' . rawurlencode($token);
|
|
}
|
|
|
|
function scmanutention_find_owned_sheet(PDO $db, int $sheet_id, int $owner_auth_id): ?array
|
|
{
|
|
if ($sheet_id <= 0 || $owner_auth_id <= 0) {
|
|
return null;
|
|
}
|
|
|
|
$stmt = $db->prepare(
|
|
'SELECT *
|
|
FROM tbl_scmanutentions
|
|
WHERE cl_scmanutention_id = :id
|
|
AND cl_scmanutention_owner_auth_id = :owner_auth_id
|
|
LIMIT 1'
|
|
);
|
|
$stmt->execute([
|
|
'id' => $sheet_id,
|
|
'owner_auth_id' => $owner_auth_id,
|
|
]);
|
|
|
|
$row = $stmt->fetch();
|
|
|
|
return $row ?: null;
|
|
}
|
|
|
|
function scmanutention_find_public_sheet_by_token(PDO $db, string $share_token): ?array
|
|
{
|
|
$share_token = trim($share_token);
|
|
if ($share_token === '') {
|
|
return null;
|
|
}
|
|
|
|
$stmt = $db->prepare(
|
|
'SELECT m.*, COALESCE(NULLIF(TRIM(a.cl_auth_user), \'\'), \'Inconnu\') AS cl_scmanutention_owner_name
|
|
FROM tbl_scmanutentions m
|
|
LEFT JOIN tbl_auth a ON a.cl_auth_id = m.cl_scmanutention_owner_auth_id
|
|
WHERE m.cl_scmanutention_share_token = :share_token
|
|
AND m.cl_scmanutention_share_enabled = 1
|
|
LIMIT 1'
|
|
);
|
|
$stmt->execute(['share_token' => $share_token]);
|
|
|
|
$row = $stmt->fetch();
|
|
|
|
return $row ?: null;
|
|
}
|
|
|
|
function scmanutention_next_item_sort_order(PDO $db, int $sheet_id): int
|
|
{
|
|
$stmt = $db->prepare(
|
|
'SELECT COALESCE(MAX(cl_scmanutentionitem_sort_order), 0)
|
|
FROM tbl_scmanutentionitems
|
|
WHERE cl_scmanutentionitem_manutention_id = :sheet_id'
|
|
);
|
|
$stmt->execute(['sheet_id' => $sheet_id]);
|
|
|
|
return ((int) $stmt->fetchColumn()) + 1;
|
|
}
|
|
|
|
function scmanutention_reindex_items(PDO $db, int $sheet_id): void
|
|
{
|
|
if ($sheet_id <= 0) {
|
|
return;
|
|
}
|
|
|
|
$stmt = $db->prepare(
|
|
'SELECT cl_scmanutentionitem_id
|
|
FROM tbl_scmanutentionitems
|
|
WHERE cl_scmanutentionitem_manutention_id = :sheet_id
|
|
ORDER BY cl_scmanutentionitem_sort_order ASC, cl_scmanutentionitem_id ASC'
|
|
);
|
|
$stmt->execute(['sheet_id' => $sheet_id]);
|
|
$ids = $stmt->fetchAll(PDO::FETCH_COLUMN);
|
|
|
|
$position = 1;
|
|
$stmt_update = $db->prepare(
|
|
'UPDATE tbl_scmanutentionitems
|
|
SET cl_scmanutentionitem_sort_order = :sort_order
|
|
WHERE cl_scmanutentionitem_id = :id'
|
|
);
|
|
|
|
foreach ($ids as $id) {
|
|
$stmt_update->execute([
|
|
'sort_order' => $position++,
|
|
'id' => (int) $id,
|
|
]);
|
|
}
|
|
}
|
|
|
|
function scmanutention_find_owned_item(PDO $db, int $item_id, int $owner_auth_id): ?array
|
|
{
|
|
if ($item_id <= 0 || $owner_auth_id <= 0) {
|
|
return null;
|
|
}
|
|
|
|
$stmt = $db->prepare(
|
|
"SELECT
|
|
mi.*,
|
|
m.cl_scmanutention_owner_auth_id
|
|
FROM tbl_scmanutentionitems mi
|
|
INNER JOIN tbl_scmanutentions m ON m.cl_scmanutention_id = mi.cl_scmanutentionitem_manutention_id
|
|
WHERE mi.cl_scmanutentionitem_id = :item_id
|
|
AND m.cl_scmanutention_owner_auth_id = :owner_auth_id
|
|
LIMIT 1"
|
|
);
|
|
$stmt->execute([
|
|
'item_id' => $item_id,
|
|
'owner_auth_id' => $owner_auth_id,
|
|
]);
|
|
|
|
$row = $stmt->fetch();
|
|
|
|
return $row ?: null;
|
|
}
|
|
|
|
function scmanutention_validate_item_reference(PDO $db, int $owner_auth_id, string $source, int $scobjs_id, int $scitemcustom_id): ?array
|
|
{
|
|
if (!scmanutention_is_valid_source($source)) {
|
|
return null;
|
|
}
|
|
|
|
if ($source === 'base') {
|
|
if ($scobjs_id <= 0) {
|
|
return null;
|
|
}
|
|
|
|
$stmt = $db->prepare(
|
|
'SELECT cl_scobjs_id, cl_scobjs_name, cl_scobjs_type, cl_scobjs_subtype, cl_scobjs_uuid, cl_scobjs_rarity
|
|
FROM tbl_scobjs
|
|
WHERE cl_scobjs_id = :id
|
|
LIMIT 1'
|
|
);
|
|
$stmt->execute(['id' => $scobjs_id]);
|
|
$row = $stmt->fetch();
|
|
|
|
if (!$row) {
|
|
return null;
|
|
}
|
|
|
|
return [
|
|
'source' => 'base',
|
|
'scobjs_id' => (int) $row['cl_scobjs_id'],
|
|
'scitemcustom_id' => 0,
|
|
'name' => (string) $row['cl_scobjs_name'],
|
|
'type' => (string) ($row['cl_scobjs_type'] ?? ''),
|
|
'subtype' => (string) ($row['cl_scobjs_subtype'] ?? ''),
|
|
'uuid' => (string) ($row['cl_scobjs_uuid'] ?? ''),
|
|
'rarity' => (string) ($row['cl_scobjs_rarity'] ?? ''),
|
|
];
|
|
}
|
|
|
|
if ($scitemcustom_id <= 0 || $owner_auth_id <= 0) {
|
|
return null;
|
|
}
|
|
|
|
$stmt = $db->prepare(
|
|
"SELECT
|
|
c.cl_scitemcustom_id,
|
|
o.cl_scobjs_id,
|
|
o.cl_scobjs_name,
|
|
o.cl_scobjs_type,
|
|
o.cl_scobjs_subtype,
|
|
o.cl_scobjs_uuid,
|
|
o.cl_scobjs_rarity
|
|
FROM tbl_scitemcustom c
|
|
INNER JOIN tbl_scobjs o ON o.cl_scobjs_id = c.cl_scitemcustom_obj_id
|
|
WHERE c.cl_scitemcustom_id = :itemcustom_id
|
|
AND c.cl_scitemcustom_owner_auth_id = :owner_auth_id
|
|
LIMIT 1"
|
|
);
|
|
$stmt->execute([
|
|
'itemcustom_id' => $scitemcustom_id,
|
|
'owner_auth_id' => $owner_auth_id,
|
|
]);
|
|
$row = $stmt->fetch();
|
|
|
|
if (!$row) {
|
|
return null;
|
|
}
|
|
|
|
return [
|
|
'source' => 'custom',
|
|
'scobjs_id' => (int) $row['cl_scobjs_id'],
|
|
'scitemcustom_id' => (int) $row['cl_scitemcustom_id'],
|
|
'name' => (string) $row['cl_scobjs_name'],
|
|
'type' => (string) ($row['cl_scobjs_type'] ?? ''),
|
|
'subtype' => (string) ($row['cl_scobjs_subtype'] ?? ''),
|
|
'uuid' => (string) ($row['cl_scobjs_uuid'] ?? ''),
|
|
'rarity' => (string) ($row['cl_scobjs_rarity'] ?? ''),
|
|
];
|
|
}
|
|
|
|
function scmanutention_search_available_items(PDO $db, int $owner_auth_id, string $query, ?int $limit = 25, int $offset = 0): array
|
|
{
|
|
$query = trim($query);
|
|
if ($query === '') {
|
|
return [];
|
|
}
|
|
|
|
$escaped = scmanutention_escape_like($query);
|
|
$exact = $escaped;
|
|
$prefix = $escaped . '%';
|
|
$contains = '%' . $escaped . '%';
|
|
$limit_clause = '';
|
|
$offset = max(0, $offset);
|
|
if ($limit !== null && $limit > 0) {
|
|
$limit = max(1, min(100, $limit));
|
|
$limit_clause = ' LIMIT ' . (int) $limit . ' OFFSET ' . (int) $offset;
|
|
}
|
|
|
|
$sql = "
|
|
SELECT *
|
|
FROM (
|
|
SELECT
|
|
CONCAT('base:', o.cl_scobjs_id) AS result_key,
|
|
'base' AS result_source,
|
|
o.cl_scobjs_id AS result_scobjs_id,
|
|
NULL AS result_scitemcustom_id,
|
|
o.cl_scobjs_name AS result_name,
|
|
COALESCE(o.cl_scobjs_type, '') AS result_type,
|
|
COALESCE(o.cl_scobjs_subtype, '') AS result_subtype,
|
|
COALESCE(o.cl_scobjs_uuid, '') AS result_uuid,
|
|
COALESCE(o.cl_scobjs_rarity, '') AS result_rarity
|
|
FROM tbl_scobjs o
|
|
WHERE (
|
|
o.cl_scobjs_name LIKE :contains_name_base
|
|
OR o.cl_scobjs_type LIKE :contains_type_base
|
|
OR o.cl_scobjs_subtype LIKE :contains_subtype_base
|
|
OR o.cl_scobjs_uuid LIKE :contains_uuid_base
|
|
)
|
|
|
|
UNION ALL
|
|
|
|
SELECT
|
|
CONCAT('custom:', c.cl_scitemcustom_id) AS result_key,
|
|
'custom' AS result_source,
|
|
o.cl_scobjs_id AS result_scobjs_id,
|
|
c.cl_scitemcustom_id AS result_scitemcustom_id,
|
|
o.cl_scobjs_name AS result_name,
|
|
COALESCE(o.cl_scobjs_type, '') AS result_type,
|
|
COALESCE(o.cl_scobjs_subtype, '') AS result_subtype,
|
|
COALESCE(o.cl_scobjs_uuid, '') AS result_uuid,
|
|
COALESCE(o.cl_scobjs_rarity, '') AS result_rarity
|
|
FROM tbl_scitemcustom c
|
|
INNER JOIN tbl_scobjs o ON o.cl_scobjs_id = c.cl_scitemcustom_obj_id
|
|
WHERE c.cl_scitemcustom_owner_auth_id = :owner_auth_id
|
|
AND (
|
|
o.cl_scobjs_name LIKE :contains_name_custom
|
|
OR o.cl_scobjs_type LIKE :contains_type_custom
|
|
OR o.cl_scobjs_subtype LIKE :contains_subtype_custom
|
|
OR o.cl_scobjs_uuid LIKE :contains_uuid_custom
|
|
)
|
|
) search_results
|
|
ORDER BY
|
|
CASE
|
|
WHEN result_name = :exact_name THEN 0
|
|
WHEN result_name LIKE :prefix_name THEN 1
|
|
WHEN result_source = 'custom' THEN 2
|
|
WHEN result_uuid = :exact_uuid THEN 3
|
|
WHEN result_uuid LIKE :prefix_uuid THEN 4
|
|
WHEN result_type LIKE :prefix_type THEN 5
|
|
WHEN result_subtype LIKE :prefix_subtype THEN 6
|
|
ELSE 7
|
|
END ASC,
|
|
CHAR_LENGTH(result_name) ASC,
|
|
result_name ASC,
|
|
result_key ASC
|
|
{$limit_clause}";
|
|
|
|
$stmt = $db->prepare($sql);
|
|
$stmt->execute([
|
|
'owner_auth_id' => $owner_auth_id,
|
|
'contains_name_base' => $contains,
|
|
'contains_type_base' => $contains,
|
|
'contains_subtype_base' => $contains,
|
|
'contains_uuid_base' => $contains,
|
|
'contains_name_custom' => $contains,
|
|
'contains_type_custom' => $contains,
|
|
'contains_subtype_custom' => $contains,
|
|
'contains_uuid_custom' => $contains,
|
|
'exact_name' => $exact,
|
|
'prefix_name' => $prefix,
|
|
'exact_uuid' => $exact,
|
|
'prefix_uuid' => $prefix,
|
|
'prefix_type' => $prefix,
|
|
'prefix_subtype' => $prefix,
|
|
]);
|
|
|
|
return $stmt->fetchAll() ?: [];
|
|
}
|
|
|
|
|
|
function scmanutention_sortable_item_name(array $item_row): string
|
|
{
|
|
$name = (string) ((($item_row['cl_scmanutentionitem_source'] ?? '') === 'custom')
|
|
? ($item_row['cl_scmanutentionitem_custom_name'] ?? '')
|
|
: ($item_row['cl_scmanutentionitem_base_name'] ?? ''));
|
|
$name = trim($name);
|
|
|
|
if ($name === '') {
|
|
return '';
|
|
}
|
|
|
|
if (function_exists('iconv')) {
|
|
$ascii_name = @iconv('UTF-8', 'ASCII//TRANSLIT//IGNORE', $name);
|
|
if ($ascii_name !== false) {
|
|
$name = $ascii_name;
|
|
}
|
|
}
|
|
|
|
return function_exists('mb_strtolower')
|
|
? mb_strtolower($name, 'UTF-8')
|
|
: strtolower($name);
|
|
}
|
|
|
|
function scmanutention_fetch_items(PDO $db, int $sheet_id): array
|
|
{
|
|
if ($sheet_id <= 0) {
|
|
return [];
|
|
}
|
|
|
|
scmanutention_reindex_items($db, $sheet_id);
|
|
|
|
$stmt = $db->prepare(
|
|
"SELECT
|
|
mi.*,
|
|
bo.cl_scobjs_name AS cl_scmanutentionitem_base_name,
|
|
bo.cl_scobjs_type AS cl_scmanutentionitem_base_type,
|
|
bo.cl_scobjs_subtype AS cl_scmanutentionitem_base_subtype,
|
|
bo.cl_scobjs_uuid AS cl_scmanutentionitem_base_uuid,
|
|
bo.cl_scobjs_rarity AS cl_scmanutentionitem_base_rarity,
|
|
co.cl_scitemcustom_id AS cl_scmanutentionitem_custom_ref_id,
|
|
oo.cl_scobjs_name AS cl_scmanutentionitem_custom_name,
|
|
oo.cl_scobjs_type AS cl_scmanutentionitem_custom_type,
|
|
oo.cl_scobjs_subtype AS cl_scmanutentionitem_custom_subtype,
|
|
oo.cl_scobjs_uuid AS cl_scmanutentionitem_custom_uuid,
|
|
oo.cl_scobjs_rarity AS cl_scmanutentionitem_custom_rarity
|
|
FROM tbl_scmanutentionitems mi
|
|
LEFT JOIN tbl_scobjs bo ON bo.cl_scobjs_id = mi.cl_scmanutentionitem_scobjs_id
|
|
LEFT JOIN tbl_scitemcustom co ON co.cl_scitemcustom_id = mi.cl_scmanutentionitem_scitemcustom_id
|
|
LEFT JOIN tbl_scobjs oo ON oo.cl_scobjs_id = co.cl_scitemcustom_obj_id
|
|
WHERE mi.cl_scmanutentionitem_manutention_id = :sheet_id
|
|
ORDER BY mi.cl_scmanutentionitem_sort_order ASC, mi.cl_scmanutentionitem_id ASC"
|
|
);
|
|
$stmt->execute(['sheet_id' => $sheet_id]);
|
|
|
|
$items = $stmt->fetchAll() ?: [];
|
|
foreach ($items as $index => &$item_row) {
|
|
$item_row['__alpha_sort_name'] = scmanutention_sortable_item_name($item_row);
|
|
$item_row['__alpha_sort_index'] = $index;
|
|
}
|
|
unset($item_row);
|
|
|
|
usort($items, static function (array $left, array $right): int {
|
|
$name_compare = strnatcasecmp((string) ($left['__alpha_sort_name'] ?? ''), (string) ($right['__alpha_sort_name'] ?? ''));
|
|
if ($name_compare !== 0) {
|
|
return $name_compare;
|
|
}
|
|
|
|
$sort_order_compare = ((int) ($left['cl_scmanutentionitem_sort_order'] ?? 0)) <=> ((int) ($right['cl_scmanutentionitem_sort_order'] ?? 0));
|
|
if ($sort_order_compare !== 0) {
|
|
return $sort_order_compare;
|
|
}
|
|
|
|
$id_compare = ((int) ($left['cl_scmanutentionitem_id'] ?? 0)) <=> ((int) ($right['cl_scmanutentionitem_id'] ?? 0));
|
|
if ($id_compare !== 0) {
|
|
return $id_compare;
|
|
}
|
|
|
|
return ((int) ($left['__alpha_sort_index'] ?? 0)) <=> ((int) ($right['__alpha_sort_index'] ?? 0));
|
|
});
|
|
|
|
foreach ($items as &$item_row) {
|
|
unset($item_row['__alpha_sort_name'], $item_row['__alpha_sort_index']);
|
|
}
|
|
unset($item_row);
|
|
|
|
return $items;
|
|
}
|
|
|
|
function scmanutention_fetch_custom_stats_map(PDO $db, array $item_rows): array
|
|
{
|
|
$custom_ids = [];
|
|
foreach ($item_rows as $row) {
|
|
if (($row['cl_scmanutentionitem_source'] ?? '') === 'custom' && !empty($row['cl_scmanutentionitem_scitemcustom_id'])) {
|
|
$custom_ids[] = (int) $row['cl_scmanutentionitem_scitemcustom_id'];
|
|
}
|
|
}
|
|
|
|
$custom_ids = array_values(array_unique(array_filter($custom_ids)));
|
|
if ($custom_ids === []) {
|
|
return [];
|
|
}
|
|
|
|
$placeholders = implode(',', array_fill(0, count($custom_ids), '?'));
|
|
$stmt = $db->prepare(
|
|
"SELECT
|
|
cs.cl_scitemcustomstat_itemcustom_id,
|
|
st.cl_scstatsitem_name,
|
|
st.cl_scstatsitem_unit,
|
|
cs.cl_scitemcustomstat_sign,
|
|
cs.cl_scitemcustomstat_value
|
|
FROM tbl_scitemcustomstat cs
|
|
INNER JOIN tbl_scstatsitem st ON st.cl_scstatsitem_id = cs.cl_scitemcustomstat_stat_id
|
|
WHERE cs.cl_scitemcustomstat_itemcustom_id IN ({$placeholders})
|
|
ORDER BY st.cl_scstatsitem_name ASC, cs.cl_scitemcustomstat_id ASC"
|
|
);
|
|
$stmt->execute($custom_ids);
|
|
|
|
$stats_map = [];
|
|
foreach ($stmt->fetchAll() as $row) {
|
|
$itemcustom_id = (int) $row['cl_scitemcustomstat_itemcustom_id'];
|
|
if (!isset($stats_map[$itemcustom_id])) {
|
|
$stats_map[$itemcustom_id] = [];
|
|
}
|
|
$stats_map[$itemcustom_id][] = $row;
|
|
}
|
|
|
|
return $stats_map;
|
|
}
|
|
|
|
function scmanutention_fetch_custom_stats_preview_map(PDO $db, array $custom_ids): array
|
|
{
|
|
$custom_ids = array_values(array_unique(array_map('intval', array_filter($custom_ids))));
|
|
if ($custom_ids === []) {
|
|
return [];
|
|
}
|
|
|
|
$placeholders = implode(',', array_fill(0, count($custom_ids), '?'));
|
|
$stmt = $db->prepare(
|
|
"SELECT
|
|
cs.cl_scitemcustomstat_itemcustom_id,
|
|
st.cl_scstatsitem_name,
|
|
st.cl_scstatsitem_unit,
|
|
cs.cl_scitemcustomstat_sign,
|
|
cs.cl_scitemcustomstat_value
|
|
FROM tbl_scitemcustomstat cs
|
|
INNER JOIN tbl_scstatsitem st ON st.cl_scstatsitem_id = cs.cl_scitemcustomstat_stat_id
|
|
WHERE cs.cl_scitemcustomstat_itemcustom_id IN ({$placeholders})
|
|
ORDER BY st.cl_scstatsitem_name ASC, cs.cl_scitemcustomstat_id ASC"
|
|
);
|
|
$stmt->execute($custom_ids);
|
|
|
|
$stats_map = [];
|
|
foreach ($stmt->fetchAll() as $row) {
|
|
$itemcustom_id = (int) $row['cl_scitemcustomstat_itemcustom_id'];
|
|
if (!isset($stats_map[$itemcustom_id])) {
|
|
$stats_map[$itemcustom_id] = [];
|
|
}
|
|
$stats_map[$itemcustom_id][] = $row;
|
|
}
|
|
|
|
return $stats_map;
|
|
}
|