Macrame provides several methods to read user text input, either as lines or single keystrokes.

Quickref

$macrame = new Macrame();

// string. Read one line of user input with prompt
$line = $macrame->input()->readline('Enter a line: ');

// string. Read user input and validate it.
$line = $macrame->input()
                ->isLengthMin(4, 'Must be 4 more than characters')
                ->readline();


// string. Read a line of user input with a validator and echo '*' 
$password = $macrame->input()
                    ->isLengthMin(8, 'Must be at least eight characters.')
                    ->readPassword("Password: ");

// string. Read content piped in as a string
$pipedContent = $macrame->input()->readPipe();

// iterator. Read content piped in one line at a time
foreach($macrame->input()->readPipeByLine() as $line){
    print $line.PHP_EOL;
}

// string. Read a single keystroke
$key = $macrame->input()->readKey('Hit one key: ');

Reading a line of user input

User text input is read using the method readline() from the class MacrameInput.

$userInput = $macrame->input()->readline();

The readline() method waits for one line of user input, finished with the <RETURN> key, and returns it as a string.

An optional prompt can be passed to readline()

$userEmail = $macrame->input()->readline('enter email: ');

Validating readline input

An arbitrary number of validators can be applied to readline() input. When validators are applied, the user will be prompted for input until that input meets all the validation criteria.

Validators are added to the MacrameInput object. For example, to validate that the text entered by the user is a valid email address, the isEmail() validator can be applied:

$userEmail = $macrame->input()
             ->isEmail()
             ->readline('enter email: ');

In this example, the user will be prompted to enter text until the input is a valid email.

An optional error message can be added to all validators:

$userEmail = $macrame->input()
             ->isEmail('Must be a valid email address')
             ->readline('enter email: ');

If the input does not pass validation, the error message will be displayed and the user will be prompted to enter input again.

An arbitrary number of validators can be applied to input. All validators must pass for the input to be considered valid. In this example, the user input must be between five and nine characters long.

$userString = $macrame->input()
              ->isLengthMin(5, 'Must be at least 5 characters')
              ->isLengthMax(9, 'Cannot be longer than 9 characters')
              ->readline('enter a string: ');

Validator list

Validator Description
isLengthMin(int $min, ?string $errorMessage) Minimum string length
isLengthMax(int $min, ?string $errorMessage) Maximum string length
isPregMatch(string $expression, ?string $errorMessage) Matches preg_match() expression
isEqualTo(string $value, ?string $errorMessage) Equal to $value
isOneOf(array $values, ?string $errorMessage) Equal to one of $values
isEntropyMin(float $min, ?string $errorMessage) Has entropy of $min or more
doesContain(string $substring, ?string $errorMessage) Contains substring $substring
doesNotContain(string $substring, ?string $errorMessage) Does not contain substring $substring
isInt(?string $errorMessage) Is an integer
isNumber(?string $errorMessage) Is any number
isEmail(?string $errorMessage) Is a valid email
isUrl(?string $errorMessage) Is a valid url
isIpAddress(?string $errorMessage) Is a valid ipv4 or ipv6 address
isDate(?string $errorMessage) Is a valid date of any format

Adding custom validators

Custom validators can be written and added to the input object using the addValidator() method.

Custom validators are functions that accept the user input as an argument and return a boolean value. The body of the function tests if the user input meets the validation criteria and returns true if it passes, false otherwise.

This example shows a custom validator that tests if the user input text is all uppercase.

// the custom validator as an arrow function
$validator = fn($input) => strtoupper($input) == $input;

// or as a long-form function. either notation is fine.
$validator = function(String $input):bool {
    return strtoupper($input) == $input;
};

$userString = $macrame->input()
                      ->addValidator($validator)
                      ->readline();

The addValidator() method accepts an optional error message as the second argument.

$userString = $macrame->input()
                      ->addValidator($validator, 'Invalid input')
                      ->readline();

Custom validators can be chained with the pre-existing, provided validators. There can be an arbitrary number of them.

Reading password input

User password input, or other input that should not be echoed to the screen during entry, can be read using readPassword().

The readPassword() method behaves like readline(), but echoes asterisks to the console rather than the characters typed.

$userSecret = $macrame->input()->readPassword();

Like readline(), validators can be used to validate the input to readPassword().

$password = $macrame->input()
                    ->isLengthMin(8, 'Must be at least eight characters.')
                    ->doesNotContain(explode('@', $email)[0], 'Must not contain your name')
                    ->isPregMatch('/[0-9]+/', 'Must contain at least one number')
                    ->isPregMatch('/[A-Z]+/', 'Must contain at least one uppercase letter')
                    ->isPregMatch('/[a-z]+/', 'Must contain at least one lowercase letter')
                    ->isPregMatch('/[^\w]/', 'Must contain at least one special character')
                    ->isEntropyMin(3.0, 'Password not complex enough')
                    ->readPassword("Password: ");

Reading piped input

Sometimes, it is desired to read user input that is supplied to the script by the shell’s pipe operator. ie.

echo "some content" | php ./my_script.php

Reading input that has been piped in can be done with the readPipe() method.

$content = $macrame->input()->readPipe();

The readPipe() method returns a string that contains all the piped input. If no input is piped into the script, null is returned.

Piped content can also be iterated over at read time, line-by-line, using readPipeByLine().

foreach($macrame->input()->readPipeByLine() as $line){
    print $line.PHP_EOL;
}