Repository navigation
Reader WPS: add Microsoft Works (.wps) text reader - #2935
Conversation
|
@k4it00 Can you rebase it on master branch ? And can you update the changelog too ? Some feedback :
|
Implements PhpOffice\PhpWord\Reader\WPS per issue PHPOffice#69: - Reuses Shared\OLERead to parse the OLE compound container and extract the 'CONTENTS' stream (handles both regular and mini streams). - Walks the WPS chunk list: CHNKWKS magic, 0x01F8 chunk tags, TEXT chunk lookup with linked-block traversal. - Decodes UTF-16LE text, normalizes \r line breaks, and maps paragraphs to Text elements in a single section. - canRead() validates the OLE signature + CHNKWKS magic (gracefully false for non-OLE/non-WPS files). - Ships a generated CFB/WPS fixture (tests/_files/documents/reader.wps) with 3 known paragraphs, plus unit tests: canRead true/false, full load with exact text assertions. Verification: phpunit WPSTest 3/3 green; phpstan analyse clean; php-cs-fixer 0 fixable violations across the repo.
…HPStan The CI static analysis config (full phpstan.neon.dist) is stricter than a single-file level-6 run: preg_split() and unpack() both return array|false. Throw a dedicated Exception on the impossible-by-construction failure paths so the types are honest and the analysis passes on PHP 7.1-8.5.
- Rebase on current master (WPS Writer PHPOffice#2929 merged) - Add Reader WPS entry to docs/changes/1.x/1.5.0.md - Make internal helpers protected and non-static - Align @SInCE with 1.5.0
da09305 to
a975c14
Compare
|
Rebased on current master (@Progi1984), changelog updated ( One clarification: for the PHPOffice/Common note — for stream extraction I use |
|
Thanks for the review @Progi1984 — all items from your feedback are addressed in commit a975c14 (rebased on master, changelog entry for 1.5.0, instance methods instead of static, protected visibility, tests/PHPStan/php-cs-fixer green). One quick question about scope: the Algora bounty on #69 is still open, and I noticed #2929 (WPS Writer) was merged — is the funded scope also open to the Reader half (a companion writer PR already landed, a reader would complete the picture)? Happy to align with whatever the intended scope is; if the Reader is unfunded I'm still glad to have this merged for the ecosystem. |
|
Weird. I removed my account from algora.io. So bounties shouldn't exist anymore. |
| * | ||
| * @return int | ||
| */ | ||
| protected function getULong($data, $offset) |
There was a problem hiding this comment.
| protected function getULong($data, $offset) | |
| protected function getULong(string $data, int $offset): int |
| * | ||
| * @return int | ||
| */ | ||
| protected function getUShort($data, $offset) |
There was a problem hiding this comment.
| protected function getUShort($data, $offset) | |
| protected function getUShort(string $data, int $offset): int |
| * | ||
| * @return string | ||
| */ | ||
| protected function readContentsStream($filename) |
There was a problem hiding this comment.
| protected function readContentsStream($filename) | |
| protected function readContentsStream(string $filename): string |
| * | ||
| * @return string | ||
| */ | ||
| protected function extractText($filename) |
There was a problem hiding this comment.
| protected function extractText($filename) | |
| protected function extractText(string $filename): string |
| * | ||
| * @return PhpWord | ||
| */ | ||
| public function load($docFile) |
There was a problem hiding this comment.
| public function load($docFile) | |
| public function load(string $docFile): PhpWord |
| * | ||
| * @return bool | ||
| */ | ||
| public function canRead($filename) |
There was a problem hiding this comment.
| public function canRead($filename) | |
| public function canRead(string $filename): bool |
Apply the return type and native type hints requested in review on the protected helpers (no inheritance constraints) and add return types on canRead()/load(). Note on canRead()/load(): the parameter types from the review suggestions (string $filename / string $docFile) cannot be applied right now because AbstractReader and ReaderInterface declare canRead() and load() without parameter types, and PHP requires overriding parameter types to be contravariant (a typed narrower parameter in a child is a fatal incompatibility). Full param typing needs the whole Reader hierarchy typed in one sweep; happy to do that as a follow-up maintained separately if preferred.
|
All suggestions applied in 26af990 — including return types on One deviation to flag: the parameter types on |
|
@k4it00 Thanks for your contribution. |
Fixes #69
/claim #69
What
Adds a WPS Reader — extracts text from Microsoft Works documents (
.wps, Works 8+) into a PhpWord document.Why this interpretation
The issue title says "Writer", but both reference links in the issue body (the digitally-disturbed blog posts) document reading/extracting text from WPS files, and the format details they cover (CHNKWKS CONTENTS stream, TEXT chunk lookup) are read-side. This PR implements that. The existing open Writer PRs (#2933, #2929, #2769) cover the write side — a Reader complements them rather than duplicating them.
How
src/PhpWord/Reader/WPS.php: reusesShared\OLERead(same plumbing as the MsDoc reader — including mini-stream handling) to extract the OLECONTENTSstream, then walks the WPS chunk list:CHNKWKSmagic →0x01F8chunk tags → linked-block traversal →TEXTchunk → UTF-16LE decode →\rnormalization → oneTextelement per paragraph.canRead()validates the OLE signature +CHNKWKSmagic and returns false gracefully for anything else.IOFactory::load(, 'WPS')— no factory changes needed.Verification
tests/_files/documents/reader.wps— a generated, spec-conformant CFB container (3 known paragraphs). Round-trip verified with an independent parser before being committed.vendor/bin/phpunit --no-coverage --filter WPSTest: 3/3 green (canRead true/false + full load with exact text assertions).vendor/bin/phpstan analyse: clean.php-cs-fixer: 0 violations repo-wide.Happy to re-scope to the Writer if maintainers prefer that for this bounty — but a Reader seemed the missing piece given the linked references.