int, 'per_page' => int, 'limit' => int, 'offset' => int] */ function paginate_params(int $defaultPerPage = 25, int $maxPerPage = 100): array { $page = max(1, (int)($_GET['page'] ?? 1)); $perPage = min($maxPerPage, max(1, (int)($_GET['per_page'] ?? $defaultPerPage))); $offset = ($page - 1) * $perPage; return [ 'page' => $page, 'per_page' => $perPage, 'limit' => $perPage, 'offset' => $offset, ]; } } if (!function_exists('json_paginated')) { /** * Return a paginated JSON response with metadata. * * @param array $items The current page of results * @param int $total Total count of all matching records * @param array $pagination Output from paginate_params() * @param string $message Optional success message */ function json_paginated(array $items, int $total, array $pagination, string $message = 'Success'): void { $totalPages = (int)ceil($total / max(1, $pagination['per_page'])); json_success([ 'items' => $items, 'pagination' => [ 'page' => $pagination['page'], 'per_page' => $pagination['per_page'], 'total' => $total, 'total_pages' => $totalPages, 'has_next' => $pagination['page'] < $totalPages, 'has_prev' => $pagination['page'] > 1, ], ], $message); } }