Download the PHP package guszandy/php-aprs without Composer

On this page you can find all versions of the php package guszandy/php-aprs. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.

FAQ

After the download, you have to make one include require_once('vendor/autoload.php');. After that you have to import the classes with use statements.

Example:
If you use only one package a project is not needed. But if you use more then one package, without a project it is not possible to import the classes with use statements.

In general, it is recommended to use always a project to download your libraries. In an application normally there is more than one library needed.
Some PHP packages are not free to download and because of that hosted in private repositories. In this case some credentials are needed to access such packages. Please use the auth.json textarea to insert credentials, if a package is coming from a private repository. You can look here for more information.

  • Some hosting areas are not accessible by a terminal or SSH. Then it is not possible to use Composer.
  • To use Composer is sometimes complicated. Especially for beginners.
  • Composer needs much resources. Sometimes they are not available on a simple webspace.
  • If you are using private repositories you don't need to share your credentials. You can set up everything on our site and then you provide a simple download link to your team member.
  • Simplify your Composer build process. Use our own command line tool to download the vendor folder as binary. This makes your build process faster and you don't need to expose your credentials for private repositories.
Please rate this library. Is it a good library?

Informations about the package php-aprs

php-aprs

Tests Packagist PHP

APRS (Automatic Packet Reporting System) for PHP — a packet parser, an APRS-IS client and a packet encoder, with no runtime dependencies beyond PHP itself.

PHP has had no actively maintained APRS library, so anyone building ham radio tooling on it has been hand-rolling packet parsing. This fills that gap.

What it does: decodes every position format APRS uses (uncompressed, compressed base91, Mic-E) plus messages, status, weather, objects, items and telemetry; connects to APRS-IS with server-side filtering and automatic reconnection; and builds valid packets for transmission.

What it does not do (yet): AX.25 KISS/TNC framing over serial or a sound modem, digipeater or igate server roles, and base91 telemetry in comments.

Contents

Installation · Receiving from APRS-IS · Building packets · Compressed and Mic-E · Other packet types · Error handling · Extending the parser · Contributing

Packet type support

APRS defines 22 data type identifiers. This library decodes 13 of them, covering everything in routine use on a live feed:

Identifier Decoded as
✅ ! = / @ position PositionPacket
✅ ` ' Mic-E | MicEPacket
✅ : message, ack, bulletin MessagePacket
✅ ; object, ) item ObjectPacket
✅ > status StatusPacket
✅ _ weather WeatherPacket
✅ T telemetry TelemetryPacket
✅ } third-party ThirdPartyPacket
⬜ ? query, < capabilities UnknownPacket
⬜ $ raw GPS, [ Maidenhead beacon UnknownPacket
⬜ # * Peet Bros, % Agrelo DF UnknownPacket
⬜ { user-defined, , test data UnknownPacket

Undecoded types are not errors: you still get the envelope and the payload verbatim, so nothing is lost. The remaining nine are queries (only relevant if you answer them), 1990s weather hardware, and ,, which the specification defines as invalid by design.

Requirements

Installation

Quickstart

Messages, acknowledgements and bulletins come back as MessagePacket:

Receiving from APRS-IS

A read-only login needs no passcode and can never transmit — use it for anything that only listens. To inject packets you need a real passcode, which is derived from your callsign:

The passcode is not a secret — it is a deterministic hash of the base callsign that anyone can compute, so it proves identity only in the weakest sense. Only log in with a callsign you are licensed to use.

run() takes two more optional callbacks: one for malformed lines (which never interrupt the loop) and one fired whenever a read times out, which is where you would put keepalive or shutdown checks.

Server comment lines (# banners and keepalives) are not packets and are routed separately:

run() propagates a ConnectionException when the link drops, leaving retry policy to you. If you would rather the client handled it, use runForever().

Filters

Server-side filters are how you avoid pulling the whole world feed. Clauses combine as a logical OR, so each one you add widens the stream:

Method Clause Selects
range($lat, $lon, $km) r/ Everything within a radius of a point
within($coordinate, $km) r/ The same, taking a Coordinate
area($n, $w, $s, $e) a/ Everything inside a lat/lon box
budlist(...$calls) b/ Named stations, wildcards allowed
prefix(...$prefixes) p/ Callsigns starting with a prefix
object(...$names) o/ Objects and items by name
digipeater(...$calls) d/ Packets relayed by these digipeaters
entryStation(...$calls) e/ Packets gated in by these stations
group(...$calls) g/ Messages addressed to these stations
type($letters) t/ Packet types: position, object, item, message, query, status, telemetry, user-defined, nws, weather
symbol($primary, ...) s/ Particular map symbols
myRange($km) m/ Near your own last reported position
friendRange($call, $km) f/ Near another station's position
unproto(...$tocalls) u/ By destination, so by originating software
qConstruct($letters) q/ By how the packet entered APRS-IS
raw($clause) — Anything not modelled above

Building packets

PositionEncoder builds uncompressed position reports. Every method returns a new instance, so a configured encoder makes a convenient beacon template:

You never pick the Data Type Identifier yourself — it follows from whether a timestamp is set and whether the station is messaging-capable:

no timestamp timestamp
not messaging ! /
messaging capable = @

Course/speed, PHG and range are mutually exclusive — a position report carries at most one data extension — so setting one replaces any previous one.

MessageEncoder handles messages, acks, rejections and bulletins:

Passing a message number is what requests an acknowledgement; omit it for fire-and-forget messages. Encoding validates as it goes and throws EncodeException rather than emitting a malformed packet — a bad packet on air wastes channel time and may be re-digipeated widely before anyone notices.

Sending one is then just:

By default packets go out as SOURCE>APZPHP,WIDE1-1,WIDE2-1:.... APZ is the reserved tocall prefix for experimental and unregistered software; the default path is one local plus one wide hop, which is the polite maximum on the congested 2 m channel.

Compressed and Mic-E positions

Both formats parse into the same PositionPacket you already handle, so code written against the uncompressed format keeps working:

Compressed reports pack the position into 13 base91 bytes instead of 19 ASCII ones, and are far more precise — about 0.3 m against 18 m. Prefer them unless you need position ambiguity, which the format cannot express.

Course and speed share two bytes with the radio range, so only one can be sent, and both come back quantised: course to 4 degrees, speed to about 8%.

Mic-E hides the latitude and several flag bits inside the destination callsign, which is why a Mic-E packet appears to be addressed to gibberish like SUSUR1. The encoder therefore generates the destination for you:

Mic-E adds a message type, including an emergency state worth checking explicitly:

Two quirks are inherent to Mic-E rather than to this library: it has no timestamp field at all, and some positions encode to bytes below 0x20, which look like control characters in a TNC monitor but are perfectly valid on air.

Other packet types

Payload Class Notes
> status StatusPacket Optional zulu timestamp or Maidenhead grid + symbol
_ weather WeatherPacket Positionless observation
; object, ) item ObjectPacket Check alive before displaying
T# telemetry TelemetryPacket Sequence, 5 analog channels, 8 digital bits
} third-party ThirdPartyPacket A relayed packet; read inner for the original

Relayed traffic

An igate passing an RF packet to APRS-IS wraps it in a } envelope. The envelope names the gateway, not the station that sent it:

Attributing a position to $packet->source would credit every relayed packet to the igate. innermost() unwraps nested envelopes, which occur when traffic crosses more than one gateway; nesting beyond three deep is rejected as a probable relay loop.

Watch the order of your instanceof checks

MicEPacket and ObjectPacket both extend PositionPacket, so that everything which works on a position works on them too. The catch is that a PositionPacket branch placed first will swallow both:

The failure is silent: you get a position with no object name and no message type, rather than an error. If you only care about coordinates, a single PositionPacket check is correct and covers all three.

Weather also rides along with positions that use the _ symbol, in which case it appears on the PositionPacket:

APRS transmits weather in US customary units, so WeatherData keeps the raw values (temperatureF, windSpeedMph, rainfall in hundredths of an inch) and offers metric equivalents as methods — nothing is lost to conversion before you decide what you want. Every field is nullable, because stations report only the sensors they have.

Objects and items can be killed, meaning receivers should remove them:

Staying connected

runForever() reconnects with exponential backoff when the link drops:

A successful reconnection resets the backoff, so a link that fails once an hour retries quickly each time instead of creeping towards the ceiling. Delays are jittered by default — without that, every client that lost the same server reconnects in lockstep and hammers its replacement.

Tests can skip the waiting entirely with setSleeper().

Error handling

Nothing is dropped silently. There are two distinct outcomes for a packet this library cannot fully decode:

In a receive loop, tryParse() returns null instead of throwing:

API reference

Value objects

All immutable; every mutator returns a new instance.

Class Purpose
Aprs\Value\Callsign Base callsign + SSID, validation, isSameStation()
Aprs\Value\Coordinate Decimal degrees ⇄ DDMM.MM, position ambiguity, distance/bearing
Aprs\Value\Digipeater One path hop, has-been-repeated flag, alias and q-construct detection
Aprs\Value\Path Ordered, immutable, iterable digipeater path
Aprs\Value\WeatherData An observation in APRS units, with metric accessors

Packets

Packet is the immutable base type; every packet exposes source, destination, path, payload, raw and toTnc2().

Class Extends Notes
Aprs\Packet\PositionPacket Packet Coordinate, symbol, course/speed, altitude, weather
Aprs\Packet\MicEPacket PositionPacket Adds message type and isEmergency()
Aprs\Packet\ObjectPacket PositionPacket Adds name, alive, isItem
Aprs\Packet\MessagePacket Packet Addressee, text, message number, bulletins
Aprs\Packet\StatusPacket Packet Text, timestamp or Maidenhead grid
Aprs\Packet\WeatherPacket Packet Positionless observation
Aprs\Packet\TelemetryPacket Packet Sequence, analog channels, digital bits
Aprs\Packet\ThirdPartyPacket Packet Relayed traffic; inner, originalSource()
Aprs\Packet\UnknownPacket Packet Envelope parsed, payload not decoded

Enums: DataType, MessageKind, MicEMessageType.

Parsers

Class Handles
Aprs\Parser\PacketParser Entry point: parse(), tryParse(), register()
Aprs\Parser\PositionParser ! = / @, compressed and uncompressed
Aprs\Parser\MicEParser ` '
Aprs\Parser\MessageParser :
Aprs\Parser\ObjectParser ; )
Aprs\Parser\StatusParser >
Aprs\Parser\WeatherParser _
Aprs\Parser\TelemetryParser T
Aprs\Parser\ThirdPartyParser }
Aprs\Parser\PayloadParser Interface for your own parsers
Aprs\Parser\ParserAware Opt-in interface to receive the PacketParser

Client

Class Purpose
Aprs\Client\AprsIsClient Connect, log in, stream packets, send
Aprs\Client\ClientOptions Server, callsign, passcode, filter, timeouts, login line
Aprs\Client\Filter Fluent server-side filter builder
Aprs\Client\Passcode Passcode derivation and verification
Aprs\Client\ReconnectPolicy Backoff, jitter and attempt limits
Aprs\Client\Connection Transport interface — swap in a double for testing
Aprs\Client\StreamConnection TCP transport over core PHP streams

Encoders

Class Purpose
Aprs\Encoder\PositionEncoder Fluent builder for uncompressed position reports
Aprs\Encoder\CompressedPositionEncoder Base91 compressed position reports
Aprs\Encoder\MicEEncoder Mic-E reports, including the destination callsign
Aprs\Encoder\MessageEncoder Messages, acks, rejections and bulletins
Aprs\Encoder\PacketEncoder Wraps a payload in a TNC2 envelope
Aprs\Encoder\TimestampFormat The three APRS timestamp forms

Exceptions

All implement Aprs\Exception\AprsException, so one catch covers the library.

Class Thrown when
Aprs\Exception\ParseException A packet cannot be decoded; carries raw and reason
Aprs\Exception\EncodeException Structured data cannot make a valid packet
Aprs\Exception\ConnectionException Connection, login or send fails
Aprs\Exception\InvalidCallsignException A string is not a valid callsign

Codec

Aprs\Codec\Base91 — the base91 representation APRS uses for compressed positions, Mic-E altitude and telemetry.

Position ambiguity

APRS lets a station blank up to four low-order digits to deliberately reduce precision. Coordinate decodes the position as the centre of the ambiguous area while remembering how many digits were blanked, so the original text can be reproduced exactly:

Extending the parser

Payload decoding is pluggable. Implement Aprs\Parser\PayloadParser and register it — parsers registered later win over the built-in ones, so this is also how you override a built-in decoder:

If your parser needs to parse packets itself — as third-party traffic does — also implement Aprs\Parser\ParserAware, and the PacketParser will hand itself over. That keeps nested packets going through the same set of parsers rather than a fresh default one.

Roadmap

Phase Scope Status
1 Value objects, TNC2 header, uncompressed position, messages done
2 APRS-IS client: connect, login, passcode, read loop, filters done
3 Encoder: uncompressed position and message packets done
4 Compressed (base91) positions, Mic-E parse and encode done
5 Status, weather, object/item, telemetry; reconnect logic done
6 Packagist 1.0, documentation, examples done

Beyond 1.0, in rough order of usefulness: base91 telemetry in comments, the !DAO! precision extension, query and station-capability packets, and AX.25 KISS/TNC framing for talking to real radios — which is large enough that it may belong in a separate package.

Development

CI runs a fast syntax lint first, then the suite on PHP 8.1, 8.2 and 8.3, plus PHPStan level 6 and the PSR-12 check.

The suite is 290 tests and about 2,500 assertions, with no network access required — the APRS-IS client is tested through a scripted Connection double.

Contributing

See CONTRIBUTING.md. Short version: composer check must pass, and new test vectors should come from real packets with independently published decodes rather than from this library's own output.

Bug reports for decoding problems are especially welcome — please include the raw packet exactly as received, since without it there is usually no way to reproduce the issue.

Accuracy and provenance

Decoders are validated against published decodes from independent implementations, not only against this library's own encoders. That approach caught two real bugs before release: a floating-point error in coordinate round-tripping, and a Mic-E longitude encoding fault affecting everything below 10 degrees.

Where the APRS specification and its addenda disagree — and they do, notably on the Mic-E destination table — this library follows real packets and says so in a comment.

License

MIT — see LICENSE.

Test vectors are derived from the APRS 1.0.1 protocol specification, from published decodes of other implementations, and from packets observed on air. No code is ported from GPL-licensed reference implementations such as libfap.

References


All versions of php-aprs with dependencies

PHP Build Version
Package Version
Requires php Version >=8.1
Composer command for our command line client (download client) This client runs in each environment. You don't need a specific PHP version etc. The first 20 API calls are free. Standard composer command

The package guszandy/php-aprs contains the following files

Loading the files please wait ...