163 lines
5.4 KiB
PHP
163 lines
5.4 KiB
PHP
<?php
|
|
|
|
namespace App\Services\Admin\Log;
|
|
|
|
use App\Repositories\Admin\Log\MemberPasswdModifyLogRepository;
|
|
|
|
final class MemberPasswdModifyLogService
|
|
{
|
|
public function __construct(
|
|
private readonly MemberPasswdModifyLogRepository $repo,
|
|
) {}
|
|
|
|
public function indexData(array $query = []): array
|
|
{
|
|
$filters = [
|
|
'date_from' => $this->safeDate($query['date_from'] ?? ''),
|
|
'date_to' => $this->safeDate($query['date_to'] ?? ''),
|
|
|
|
'state' => $this->safeEnum($query['state'] ?? '', ['S','E']), // S 직접, E 찾기
|
|
'mem_no' => $this->safeInt($query['mem_no'] ?? null),
|
|
|
|
'type' => $this->safeStr($query['type'] ?? '', 40), // 신포맷 type
|
|
'email' => $this->safeStr($query['email'] ?? '', 80), // 구포맷 user_email
|
|
'ip' => $this->safeIpPrefix($query['ip'] ?? ''), // remote_addr or auth_key contains
|
|
'q' => $this->safeStr($query['q'] ?? '', 120), // info 전체 like
|
|
];
|
|
|
|
if ($filters['date_from'] && $filters['date_to']) {
|
|
if (strcmp($filters['date_from'], $filters['date_to']) > 0) {
|
|
[$filters['date_from'], $filters['date_to']] = [$filters['date_to'], $filters['date_from']];
|
|
}
|
|
}
|
|
|
|
$page = $this->repo->paginate($filters, 30);
|
|
|
|
$items = [];
|
|
foreach ($page->items() as $it) {
|
|
$r = is_array($it) ? $it : (array)$it;
|
|
|
|
$infoRaw = (string)($r['info'] ?? '');
|
|
$infoArr = $this->decodeJson($infoRaw);
|
|
|
|
$state = (string)($r['state'] ?? '');
|
|
$memNo = (int)($infoArr['mem_no'] ?? 0);
|
|
|
|
$type = trim((string)($infoArr['type'] ?? ''));
|
|
$eventType = $type !== '' ? $type : ($state === 'E' ? '비밀번호찾기 변경' : '비밀번호변경');
|
|
|
|
$eventTime = trim((string)($infoArr['redate'] ?? ''));
|
|
if ($eventTime === '') $eventTime = (string)($r['rgdate'] ?? '');
|
|
|
|
$ip = trim((string)($infoArr['remote_addr'] ?? ''));
|
|
if ($ip === '') {
|
|
$ip = $this->extractIpFromAuthKey((string)($infoArr['auth_key'] ?? '')) ?: '';
|
|
}
|
|
|
|
$email = trim((string)($infoArr['user_email'] ?? ''));
|
|
if ($email === '') $email = trim((string)($infoArr['email'] ?? ''));
|
|
|
|
$agent = trim((string)($infoArr['agent'] ?? ''));
|
|
|
|
$items[] = array_merge($r, [
|
|
'info_arr' => $infoArr,
|
|
|
|
'mem_no_int' => $memNo,
|
|
'mem_link' => $memNo > 0 ? ('/members/' . $memNo) : null,
|
|
|
|
'state_label' => $state === 'E' ? '비번찾기' : '직접변경',
|
|
'state_badge' => $state === 'E' ? 'badge--warn' : 'badge--ok',
|
|
|
|
'event_type' => $eventType,
|
|
'event_time' => $eventTime,
|
|
|
|
'ip_norm' => $ip,
|
|
'email_norm' => $email,
|
|
'agent_norm' => $agent,
|
|
|
|
// 펼침용(구포맷 핵심 필드)
|
|
'auth_key' => (string)($infoArr['auth_key'] ?? ''),
|
|
'auth_effective_time' => (string)($infoArr['auth_effective_time'] ?? ''),
|
|
|
|
// raw pretty
|
|
'info_pretty' => $this->prettyJson($infoArr, $infoRaw),
|
|
]);
|
|
}
|
|
|
|
return [
|
|
'filters' => $filters,
|
|
'page' => $page,
|
|
'items' => $items,
|
|
|
|
'stateMap' => [
|
|
'S' => '직접변경',
|
|
'E' => '비번찾기',
|
|
],
|
|
];
|
|
}
|
|
|
|
private function decodeJson(string $raw): array
|
|
{
|
|
$raw = trim($raw);
|
|
if ($raw === '') return [];
|
|
$arr = json_decode($raw, true);
|
|
return is_array($arr) ? $arr : [];
|
|
}
|
|
|
|
private function prettyJson(array $arr, string $fallbackRaw): string
|
|
{
|
|
if (!empty($arr)) {
|
|
return (string)json_encode($arr, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
|
|
}
|
|
return $fallbackRaw;
|
|
}
|
|
|
|
private function extractIpFromAuthKey(string $authKey): ?string
|
|
{
|
|
$authKey = trim($authKey);
|
|
if ($authKey === '') return null;
|
|
|
|
// auth_key 끝에 "1.85.101.111" 같은 IP가 붙는 케이스 대응 (마지막 매치 사용)
|
|
if (preg_match_all('/(\d{1,3}(?:\.\d{1,3}){3})/', $authKey, $m) && !empty($m[1])) {
|
|
return (string)end($m[1]);
|
|
}
|
|
return null;
|
|
}
|
|
|
|
private function safeStr(mixed $v, int $max): string
|
|
{
|
|
$s = trim((string)$v);
|
|
if ($s === '') return '';
|
|
if (mb_strlen($s) > $max) $s = mb_substr($s, 0, $max);
|
|
return $s;
|
|
}
|
|
|
|
private function safeEnum(mixed $v, array $allowed): string
|
|
{
|
|
$s = trim((string)$v);
|
|
return in_array($s, $allowed, true) ? $s : '';
|
|
}
|
|
|
|
private function safeInt(mixed $v): ?int
|
|
{
|
|
if ($v === null || $v === '') return null;
|
|
if (!is_numeric($v)) return null;
|
|
$n = (int)$v;
|
|
return $n >= 0 ? $n : null;
|
|
}
|
|
|
|
private function safeDate(mixed $v): ?string
|
|
{
|
|
$s = trim((string)$v);
|
|
if ($s === '') return null;
|
|
return preg_match('/^\d{4}-\d{2}-\d{2}$/', $s) ? $s : null;
|
|
}
|
|
|
|
private function safeIpPrefix(mixed $v): string
|
|
{
|
|
$s = trim((string)$v);
|
|
if ($s === '') return '';
|
|
return preg_match('/^[0-9.]+$/', $s) ? $s : '';
|
|
}
|
|
}
|