Option to disable strict dictionary key ordering in decoder
Summary
The decoder currently enforces lexicographic key ordering in bencode dictionaries (BEP 3 spec-compliant). While this is correct for encoding, applying this constraint to decoding breaks interoperability with real-world BitTorrent trackers that routinely emit out-of-order keys.
Affected version: 4.3.2
Reproduction
use Arokettu\Bencode\Bencode;
use Arokettu\Bencode\Bencode\Collection;
// ✅ Spec-compliant: keys in lexicographic order
$correct = 'd8:completei5e10:incompletei2e8:intervali1800e5:peers0:e';
var_dump(Bencode::decode($correct, dictType: Collection::ARRAY));
// Works fine
// ❌ Non-compliant: 'peers' before 'complete' — real output from chihaya tracker
$incorrect = 'd8:intervali1800e5:peers0:e8:completei5e10:incompletei2ee';
var_dump(Bencode::decode($incorrect, dictType: Collection::ARRAY));
// ParseErrorException: Invalid order of dictionary keys: 'complete' after 'peers'
To reproduce with a live tracker, run chihaya via Docker and capture its raw response:
docker run -d -p 6969:6969 quay.io/jzelinskie/chihaya-git:latest
curl -s "http://localhost:6969/announce?info_hash=aaaaaaaaaaaaaaaaaaaa&peer_id=bbbbbbbbbbbbbbbbbbbb&port=1234&uploaded=0&downloaded=0&left=0&compact=1" | xxd
# Output: d8:intervali10e12:min intervali5e5:peers6:...8:completei1e10:incompletei0ee
# ^^^^^ ^^^^^^^^^
# 'peers' comes before 'complete' — invalid order
Expected behavior
An option to decode leniently, tolerating out-of-order dictionary keys:
// Proposed API (naming up for discussion)
Bencode::decode($data, dictType: Collection::ARRAY, strictDictOrder: false);
The fix in Engine/Reader.php is minimal — a single guard on line 193:
// Current:
if ($prevKey && strcmp($prevKey, $dictKey) >= 0) {
throw new ParseErrorException("Invalid order of dictionary keys: ...");
}
// With option:
if ($this->strictDictOrder && $prevKey && strcmp($prevKey, $dictKey) >= 0) {
throw new ParseErrorException("Invalid order of dictionary keys: ...");
}
Context
Tested against two popular tracker implementations:
- opentracker (C) — outputs correctly sorted keys ✅
- chihaya (Go) — outputs unsorted keys ❌ (e.g.
peers before complete)
The BEP 3 spec requires sorted keys for encoding but says nothing about decoding strictness. A lenient decoder is necessary for any PHP client that wants to communicate with real-world trackers.
Default behaviour should remain unchanged (strict = true) for backward compatibility.
Option to disable strict dictionary key ordering in decoder
Summary
The decoder currently enforces lexicographic key ordering in bencode dictionaries (BEP 3 spec-compliant). While this is correct for encoding, applying this constraint to decoding breaks interoperability with real-world BitTorrent trackers that routinely emit out-of-order keys.
Affected version: 4.3.2
Reproduction
To reproduce with a live tracker, run chihaya via Docker and capture its raw response:
Expected behavior
An option to decode leniently, tolerating out-of-order dictionary keys:
The fix in
Engine/Reader.phpis minimal — a single guard on line 193:Context
Tested against two popular tracker implementations:
peersbeforecomplete)The BEP 3 spec requires sorted keys for encoding but says nothing about decoding strictness. A lenient decoder is necessary for any PHP client that wants to communicate with real-world trackers.
Default behaviour should remain unchanged (
strict = true) for backward compatibility.