korin / gedcom
Lossless GEDCOM 5.5–7.0 reader, validator, converter and writer for PHP
Requires
- php: ~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0 || ~8.6.0
Requires (Dev)
- friendsofphp/php-cs-fixer: ^3.95
- korin/gedcom-corpus: dev-main
- phpbench/phpbench: ^1.4
- phpstan/phpstan: ^2.1
- phpstan/phpstan-strict-rules: ^2.0
- phpunit/phpunit: ^11.5 || ^12.5 || ^13
- rector/rector: ^2.0
- symfony/yaml: ^6.4 || ^7.0
Suggests
- ext-intl: Exact Unicode normalization (NFC) for ANSEL input
- ext-mbstring: Faster UTF-16 and single-byte decoding
- ext-zip: GEDZIP (.gdz) support
Provides
None
Conflicts
None
Replaces
None
This package is auto-updated.
Last update: 2026-11-15 19:14:28 UTC
README
Read, validate, convert and write GEDCOM 5.5, 5.5.1, 5.5.5 and 7.0 — without losing a single tag. Every unavoidable loss is reported.
Status: 0.2 — early development. Reading, lossless writing, editing and validation against the profiles of 5.5, 5.5.1, 5.5.5 and 7.0 work today; conversion, the typed model, GEDZIP and streaming are planned — see the specification for the roadmap and CHANGELOG.md for releases. Until 1.0 a minor release may break the API.
use Korin\Gedcom\Gedcom; $doc = Gedcom::read('family.ged'); // version and encoding detected automatically echo $doc->version()->value; // "5.5.1" echo $doc->encoding()->value; // "Windows-1251" $name = $doc->find('@I1@/NAME'); echo $name?->value(); // "Анна /Коваль/" $name?->setValue('Анна /Ковальова/'); Gedcom::write($doc, 'family.ged'); // only the changed line is rewritten
Why Korin
- Lossless. Unknown and vendor tags (
_UID,_FSFTID, …) are kept. Writing an unmodified document reproduces the input byte for byte: BOM, line endings, spacing. - Encodings that real files use. UTF-8, UTF-16 LE/BE, ANSEL with combining diacritics,
ASCII, Windows-1250/1251/1252, CP437, CP850, MacRoman — including files that declare
CHAR ANSIor contradict their ownCHAR. - No runtime dependencies.
ext-intlandext-mbstringare used when present. - Tested against a shared corpus — gedcom-corpus, including the gedcom7code test files.
Requirements
PHP 8.2–8.6, 64-bit.
Installation
composer require korin/gedcom
Diagnostics
Reading reports syntax problems, validation checks the document against its version's rules. Problems are reported, not thrown, unless you ask for strict mode:
use Korin\Gedcom\ReadOptions; use Korin\Gedcom\Validation\ValidationOptions; foreach ($doc->diagnostics() as $d) { echo $d, PHP_EOL; // KV1101 warning line 6 (HEAD/CHAR): Non-standard CHAR value; … } Gedcom::read('family.ged', (new ReadOptions())->withStrict()); // throws ParseException on errors $report = Gedcom::validate($doc); // structure, values and references of every version $report->isValid(); // false if there are errors Gedcom::validate($doc, (new ValidationOptions())->withPlausibility()); // also births after deaths, cycles echo json_encode($report); // code, severity, message, line, path, reference
All codes are listed in docs/diagnostics.md.
Performance
Measured with PHPBench on generated, fictional 5.5.1 files (PHP 8.5, Apple M-series, no opcache):
| Scenario | Peak memory | Time |
|---|---|---|
| Full read, 10 MB UTF-8 | 70 MB | 0.32 s |
| Full read, 10 MB Windows-1251 | 105 MB | 0.49 s |
| Full read, 50 MB UTF-8 (2.4 million lines) | 426 MB | 1.6 s |
| Preserve-mode write of 10 MB, unchanged / 10% of surnames edited | 76 MB | 104 ms / 121 ms |
The 1.0 target for a full read of 50 MB is ≤ 512 MB and ≤ 20 s.
Streaming and indexed modes for large files are planned. Run the benchmarks with composer bench.
A baseline comparison with liberu-genealogy/php-gedcom is in docs/comparison.
License and trademarks
Apache-2.0. GEDCOM is a trademark of Intellectual Reserve, Inc. Korin is not affiliated with or endorsed by FamilySearch.