db) { $this->db = \Config\Database::connect(); } return $this->db; } /** * Success response */ protected function respondSuccess($data = null, $message = 'Success', $code = ResponseInterface::HTTP_OK) { return $this->respond([ 'success' => true, 'message' => $message, 'data' => $data ], $code); } /** * Error response */ protected function respondError($message = 'Error occurred', $code = ResponseInterface::HTTP_BAD_REQUEST, $errors = null) { return $this->respond([ 'success' => false, 'message' => $message, 'errors' => $errors ], $code); } /** * Get Authorization header from various sources */ protected function getAuthHeader() { // Try standard Authorization header $authHeader = $this->request->getHeaderLine('Authorization'); if (!empty($authHeader)) { return $authHeader; } // Try from $_SERVER (Apache mod_rewrite) if (isset($_SERVER['HTTP_AUTHORIZATION'])) { return $_SERVER['HTTP_AUTHORIZATION']; } // Try from $_SERVER with REDIRECT_ prefix if (isset($_SERVER['REDIRECT_HTTP_AUTHORIZATION'])) { return $_SERVER['REDIRECT_HTTP_AUTHORIZATION']; } // Try from getallheaders() if available if (function_exists('getallheaders')) { $headers = getallheaders(); if (isset($headers['Authorization'])) { return $headers['Authorization']; } if (isset($headers['authorization'])) { return $headers['authorization']; } } return null; } /** * Validate token */ protected function validateToken() { $authHeader = $this->getAuthHeader(); if (empty($authHeader)) { return false; } $token = str_replace('Bearer ', '', $authHeader); if (empty($token)) { return false; } // Check token in database try { $builder = $this->getDB()->table('admin_tokens'); $tokenData = $builder->where('token', $token) ->get() ->getRow(); if (!$tokenData) { return false; } // Check expiration (만료 체크) $expiresAt = strtotime($tokenData->expires_at); $now = time(); if ($expiresAt < $now) { return false; } return $tokenData; } catch (\Exception $e) { log_message('error', 'validateToken error: ' . $e->getMessage()); return false; } } /** * Require authentication */ protected function requireAuth() { $authHeader = $this->getAuthHeader(); // 디버깅: Authorization 헤더 확인 if (empty($authHeader)) { return $this->respondError('No Authorization header', ResponseInterface::HTTP_UNAUTHORIZED); } $token = str_replace('Bearer ', '', $authHeader); if (empty($token)) { return $this->respondError('Empty token', ResponseInterface::HTTP_UNAUTHORIZED); } $tokenData = $this->validateToken(); if (!$tokenData) { return $this->respondError('Token validation failed - token: ' . substr($token, 0, 20) . '...', ResponseInterface::HTTP_UNAUTHORIZED); } return $tokenData; } /** * Get pagination params */ protected function getPaginationParams() { $page = $this->request->getGet('page') ?? 1; $perPage = $this->request->getGet('per_page') ?? 10; $offset = ($page - 1) * $perPage; return [ 'page' => (int)$page, 'per_page' => (int)$perPage, 'offset' => (int)$offset ]; } /** * Build paginated response */ protected function paginatedResponse($builder, $params) { $total = $builder->countAllResults(false); $items = $builder->limit($params['per_page'], $params['offset'])->get()->getResult(); return [ 'items' => $items, 'total' => $total, 'page' => $params['page'], 'per_page' => $params['per_page'], 'total_pages' => ceil($total / $params['per_page']) ]; } /** * Fix localhost URLs to current domain URLs */ protected function fixUrl($url) { if (empty($url)) { return $url; } // 현재 요청의 도메인 감지 $protocol = isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? 'https://' : 'http://'; $currentDomain = $protocol . ($_SERVER['HTTP_HOST'] ?? 'localhost'); $currentBaseUrl = rtrim($currentDomain, '/') . '/'; // localhost 또는 127.0.0.1로 시작하는 URL을 현재 도메인으로 변경 $patterns = [ 'http://localhost:8080/', 'http://localhost/', 'https://localhost:8080/', 'https://localhost/', 'http://127.0.0.1:8080/', 'http://127.0.0.1/', 'https://127.0.0.1:8080/', 'https://127.0.0.1/', ]; foreach ($patterns as $pattern) { if (strpos($url, $pattern) === 0) { $url = str_replace($pattern, $currentBaseUrl, $url); } } // writable/uploads 경로를 uploads로 변경 (심볼릭 링크 대응) $url = str_replace('/writable/uploads/', '/uploads/', $url); $url = str_replace('writable/uploads/', 'uploads/', $url); return $url; } /** * Fix URLs in object/array */ protected function fixUrls($data, $fields = ['image_url', 'file_url', 'url']) { if (is_object($data)) { foreach ($fields as $field) { if (isset($data->$field)) { $data->$field = $this->fixUrl($data->$field); } } } elseif (is_array($data)) { foreach ($data as &$item) { $item = $this->fixUrls($item, $fields); } } return $data; } }