[6.x] Fix HTTP 500 on out-of-range front-end pagination page number#14981
Open
mynetx wants to merge 1 commit into
Open
[6.x] Fix HTTP 500 on out-of-range front-end pagination page number#14981mynetx wants to merge 1 commit into
mynetx wants to merge 1 commit into
Conversation
A page number large enough to overflow the offset arithmetic in Query\Builder::forPage() silently promotes the offset to a float. offset() preserved that float, so the Stache driver's array_slice() call threw a TypeError instead of returning an empty page. Clamp the overflow in offset() itself, since forPage(), chunk(), and the Stache limitKeys() read all route through it. Also hardened OrderedQueryBuilder's own offset() override, which had the same unclamped max(0, $value) shape. Fixes statamic#14979 Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #14979
Summary
A large but valid
?page=value on any front-end paginated listing returns HTTP 500 instead of an empty page.Query\Builder::forPage()computes the offset as($page - 1) * $perPagewith no clamp. Once the product overflowsPHP_INT_MAX, PHP silently promotes it to a float.offset()only didmax(0, $value), which preserves the float, and the Stache driver passes it straight toarray_slice(), which throws:The overflow is reachable through a real request: Laravel's pagination resolver validates
?page=withfilter_var($page, FILTER_VALIDATE_INT), so any value up toPHP_INT_MAXpasses through as-is. A crawler following a malformed link, or a scanner probing for this exact class of bug, can trigger it with?page=9223372036854775807.Fix
Clamp the overflow in
offset()itself rather than inforPage(). Every path that can produce an out-of-range offset routes through it:forPage(),chunk(), and the Stache driver'slimitKeys()read$this->offsetthatoffset()sets. One fix covers all three.Also hardened
OrderedQueryBuilder's ownoffset()override, which had the identical unclampedmax(0, $value)shape. It isn't reachable through any first-party call path today (nothing calls->offset()directly on that wrapper), but it's the same footgun in a siblingBuilderimplementation and costs nothing to close now.Test plan
EntryQueryBuilderTest::it_returns_an_empty_page_when_the_offset_overflows, exercising the real Stache path (forPage(PHP_INT_MAX, 6)→ offset-as-float →array_slice). Fails with theTypeErrorbefore the fix, passes after.EntryQueryBuilderTest,OrderedQueryBuilderTest, and sibling Stache-backed builder suites (Assets/Terms/Users/Forms) pass.Entry::query()->forPage(PHP_INT_MAX, 6)->get()threw before the fix, returns an empty collection after../vendor/bin/pintclean on changed files.🤖 Generated with Claude Code