omaressaouaf/text-morph

A lightweight PHP package for reversible text transformations using simple morphing algorithms and a composable pipeline

Maintainers

Package info

github.com/omaressaouaf/text-morph

pkg:composer/omaressaouaf/text-morph

Statistics

Installs: 2

Dependents: 0

Suggesters: 0

Stars: 1

Open Issues: 0

v1.0.0 2026-06-26 17:47 UTC

This package is not auto-updated.

Last update: 2026-06-26 17:50:14 UTC


README

Latest Stable Version License Tests

A lightweight PHP package for reversible text transformations using simple morphing algorithms and a composable pipeline.

Features

  • Rotational morphing: shift letters across a 52-character alphabet with wrap-around
  • Substitution morphing: bidirectional character-pair swaps with case preservation
  • Transposition morphing: rail-fence (zigzag) character reordering
  • Composite pipeline: chain multiple morphers and reverse them in one call
  • Every morpher supports morph() and unmorph()
  • Framework-agnostic, zero runtime dependencies

TextMorph is a text transformation package. It is not intended for encryption, password hashing, or security-sensitive data. It currently operates on ASCII strings. Multibyte/Unicode-aware transformations are not currently supported.

Installation

Install via Composer:

composer require omaressaouaf/text-morph

Usage

Every morpher implements the TextMorpher contract:

use Omaressaouaf\TextMorph\Contracts\TextMorpher;

interface TextMorpher
{
    public function morph(string $text): string;

    public function unmorph(string $text): string;
}

Rotational Morphing

Shift each letter forward across a-zA-Z, wrapping from Z back to a. Non-alphabetic characters are left unchanged.

use Omaressaouaf\TextMorph\Morphers\RotationalTextMorpher;

$morpher = new RotationalTextMorpher(3);

$morphed = $morpher->morph('Meet at 9pm!');
// Phhw dw 9sp!

$original = $morpher->unmorph($morphed);
// Meet at 9pm!

More examples:

$morpher = new RotationalTextMorpher(1);

$morpher->morph('a'); // b
$morpher->morph('z'); // B
$morpher->morph('Z'); // a

Substitution Morphing

Swap character pairs bidirectionally. Each pair defines a two-way substitution that preserves letter case.

use Omaressaouaf\TextMorph\Morphers\SubstitutionTextMorpher;

$morpher = new SubstitutionTextMorpher(['ab', 'cd']);

$morpher->morph('aabbcc'); // bbaacc
$morpher->morph('adam');   // bcbm

Because pairs are swaps, unmorph() applies the same transform as morph():

$morpher->unmorph('bbaacc'); // aabbcc

Transposition Morphing

Reorder characters using a rail-fence (zigzag) cipher. Letters are written in a zigzag across the configured number of rails, then read row by row.

use Omaressaouaf\TextMorph\Morphers\TranspositionTextMorpher;

$morpher = new TranspositionTextMorpher(3);

$morpher->morph('HELLO');       // HOELL
$morpher->morph('Meet at 9pm!'); // M 9eta p!etm

unmorph() splits the text back into rails and reads the zigzag to restore the original order.

Composite Pipeline

Chain multiple morphers together. morph() applies them in registration order; unmorph() reverses them.

use Omaressaouaf\TextMorph\Morphers\CompositeTextMorpher;
use Omaressaouaf\TextMorph\Morphers\RotationalTextMorpher;
use Omaressaouaf\TextMorph\Morphers\SubstitutionTextMorpher;
use Omaressaouaf\TextMorph\Morphers\TranspositionTextMorpher;

$pipeline = new CompositeTextMorpher();

$pipeline->add(new SubstitutionTextMorpher(['ae', 'io']));
$pipeline->add(new RotationalTextMorpher(5));
$pipeline->add(new TranspositionTextMorpher(3));

$original = 'Meet at 9pm!';

$morphed = $pipeline->morph($original);
$restored = $pipeline->unmorph($morphed);

// $restored === $original

Custom Morphers

The package is fully extensible. You can create your own morphers by implementing the TextMorpher contract.

Example

namespace App\Morphers;

use Omaressaouaf\TextMorph\Contracts\TextMorpher;

class ReverseTextMorpher implements TextMorpher
{
    public function morph(string $text): string
    {
        return strrev($text);
    }

    public function unmorph(string $text): string
    {
        return strrev($text);
    }
}

Then use it on its own or inside a composite pipeline:

use App\Morphers\ReverseTextMorpher;
use Omaressaouaf\TextMorph\Morphers\CompositeTextMorpher;
use Omaressaouaf\TextMorph\Morphers\RotationalTextMorpher;

$pipeline = new CompositeTextMorpher();
$pipeline->add(new ReverseTextMorpher());
$pipeline->add(new RotationalTextMorpher(13));

$morphed = $pipeline->morph('Hello');
$original = $pipeline->unmorph($morphed);

This approach allows you to implement completely custom transformations while preserving the same architecture and developer experience as the package's built-in morphers.

Testing

Run unit tests:

composer test

License

This package is licensed under the MIT License.