avvertix/liteparse-php
Composer 安装命令:
composer require avvertix/liteparse-php
包简介
PHP FFI bindings for LiteParse, fast local PDF and document parsing with spatial text extraction
README 文档
README
Native PHP bindings for LiteParse, local PDF and document parsing with spatial text extraction powered by Rust and PDFium.
Given a PDF this package extracts text with bounding boxes and renders it as structured JSON, plain text, or layout-aware Markdown (headings, lists, tables, figure references). The parsing happens directly from PHP, via a compiled Rust cdylib loaded through PHP's FFI extension.
Note
The native bindings are tested only for PDF files. Support for DOC/DOCX/XLS/XLSX/PPT/PPTX, and images is not tested and not provided so far.
Requirements
- PHP 8.3+ with
ext-ffienabled (ffi.enable=Onin php.ini; CLI defaults to on) - A compiled
liteparse_phpnative library for your platform (see Installation) - Optional, for OCR: an HTTP OCR server implementing
LiteParse OCR_API_SPEC.md(reference servers for EasyOCR/PaddleOCR/SuryaOCR ship in the LiteParse repo). This binding does not bundle the Tesseract engine as would increase the complexity of the build and distribution pipeline, pointConfig::$ocrServerUrlat a server instead.
Installation
Get the package via Composer and install the native library for your platform.
composer require avvertix/liteparse-php vendor/bin/liteparse-php install
install downloads the compiled liteparse_php library and its PDFium dependency for your platform from the package's GitHub Releases into vendor/avvertix/liteparse-php/lib/. The specific installed versions are recorded in a natives.lock file in the root of your project, commit this alongside composer.lock to install the same version of the compiled binary. Run vendor/bin/liteparse-php update after upgrading the package to fetch the matching native library.
Quick start
use LiteParse\Config; use LiteParse\OutputFormat; use LiteParse\LiteParse; $parser = new LiteParse(new Config(outputFormat: OutputFormat::Markdown)); $result = $parser->parseFile('/path/to/document.pdf'); echo $result->pageCount(); // int echo $result->text(); // plain text, "--- Page N ---" headers echo $result->markdown(); // headings/lists/tables/figure refs reconstructed from layout echo json_encode($result->json()); // structured per-page text items: bbox + font size + fill/stroke color, per item echo json_encode($result->lines()); // structured per-page projected lines: merged bbox + style + column geometry
json() returns liteparse's full per-item TextItem — not the lean {text, x, y, width, height} shape the upstream lit CLI's own --format json produces. Each item carries its bounding box together with font_size and fill_color/stroke_color (ARGB hex, e.g. "ff000000") on the same record, plus rotation, links, strikethrough, and OCR confidence where applicable. Font/color fields are only populated for native PDF text; OCR-derived items carry null there instead.
lines() sits between json() and markdown(): each entry is a merged visual line (one or more TextItems sharing a baseline) carrying its own bounding box, dominant font/style, and region_path — the xy-cut column/region position liteparse uses internally to group paragraphs and tables. Each line's spans field keeps the original TextItems that merged into it, so per-run font/color survives even where the line's own text concatenates multiple items. Unlike markdown(), nothing here is reformatted or dropped when the heuristic table/heading detection misfires — you get the raw geometry and can reconstruct rows/columns/headings yourself from region_path and bbox positions. There is no heading/paragraph/list "role" label at this layer.
Every ParseResult accessor (text(), markdown(), json(), lines()) renders on demand from the same underlying parsed pages.
Features
LiteParse::parseFile()/parseBytes()— parse from a file path or an in-memory buffer (e.g. a PDF downloaded over the network).LiteParse::isComplexFile()/isComplexBytes()— a cheap per-page pre-check (no OCR, no rendering) reporting whether each page looks scanned, sparse, garbled, or image-heavy — useful for deciding whether a document needs OCR before committing to a full parse.LiteParse::screenshotFile()/screenshotBytes()— render selected pages (or the whole document) to PNG bytes.ParseResult::search()— search already-parsed text for phrase matches, with bounding boxes, merged across text items that were split mid-phrase.
// Complexity pre-check $stats = $parser->isComplexFile('scan.pdf'); $needsOcr = array_filter($stats, fn ($page) => $page['needs_ocr']); // Screenshots $screenshots = $parser->screenshotFile('doc.pdf', pageNumbers: [1, 2]); // null = all pages foreach ($screenshots as $shot) { file_put_contents("page-{$shot->pageNumber}.png", $shot->bytes); } // Search $result = $parser->parseFile('doc.pdf'); foreach ($result->search('quarterly revenue') as $match) { printf("page %d at (%.0f, %.0f)\n", $match['page_number'], $match['x'], $match['y']); }
See examples/ for runnable scripts.
Configuration
Config mirrors liteparse's Rust LiteParseConfig field-for-field:
| Field | Default | Notes |
|---|---|---|
ocrLanguage |
'eng' |
Tesseract-format language code |
ocrEnabled |
false |
Requires ocrServerUrl — this binding has no built-in OCR engine |
ocrServerUrl |
null |
HTTP OCR server URL |
ocrServerHeaders |
[] |
[[name, value], ...] sent with every OCR request |
maxPages |
1000 |
|
targetPages |
null |
e.g. "1-5,10,15-20"; null = all pages |
dpi |
150.0 |
Used for OCR and screenshots |
outputFormat |
OutputFormat::Json |
Informational only in this binding — text()/markdown()/json() are always available regardless |
preserveVerySmallText |
false |
|
password |
null |
For encrypted/protected documents |
quiet |
true |
Suppresses liteparse's stderr progress logging (Rust default is false) |
numWorkers |
1 |
Concurrent OCR requests to the HTTP server |
imageMode |
ImageMode::Placeholder |
Affects markdown() image references only |
extractLinks |
true |
Hyperlinks as [text](url) in markdown |
ocrFailureFatal |
true |
Abort the whole parse on systemic OCR failure vs. return degraded results |
ocrHedgeDelaysMs |
[] |
Request-hedging schedule for the HTTP OCR engine |
emitWordBoxes |
false |
Per-word sub-boxes on each text item (roughly doubles payload size) |
How it works
LiteParse Rust create is exposed as C library to be consumed by the PHP Foreign Function Interface (FFI). The shared library is defined in rust/ exposing handles for the parser/result/screenshot-list lifecycle, plus configuration and exceptions. LiteParse's API is async (tokio-based); the FFI layer owns a single process-wide tokio runtime and block_ons each call, since PHP FFI calls are synchronous. cbindgen generates the committed include/liteparse_php.h header that PHP's FFI::cdef() loads.
PDFium (a separate native dependency liteparse links against) is discovered at runtime by pdfium-sys's loader relative to whichever shared library loaded it.
Development
./scripts/build.sh # cargo build --release, stage lib/ composer install composer test # PHPUnit, against the compiled library composer lint # PHPStan
Adding a new FFI function: add the extern "C" function in rust/src/ffi/, rebuild (cbindgen regenerates include/liteparse_php.h automatically via build.rs), add the corresponding @method annotation to LiteParseFfi, and wrap it in a PHP class.
Building from source
If you're working in this repository directly (or no prebuilt release exists yet for your platform):
./scripts/build.sh release # cargo build --release + stage lib/liteparse_php.* and lib/libpdfium.* composer install composer test
scripts/build.sh compiles the Rust crate in rust/ and copies the resulting native library, plus its PDFium runtime dependency, into lib/.
License
The project is dual licenced. The PHP wrapper code is licenced under MIT. The Rust binding to expose via FFI are licenced under Apache-2.0.
统计信息
- 总下载量: 0
- 月度下载量: 0
- 日度下载量: 0
- 收藏数: 0
- 点击次数: 1
- 依赖项目数: 0
- 推荐数: 0
其他信息
- 授权协议: MIT
- 更新时间: 2026-07-07