ctype_cntrl

Checks whether every character in a string is a control character such as tab, newline or escape.

Signature
ctype_cntrl(mixed $text): bool
  • Added in PHP 4.0.4

Parameters

ParameterTypeDescription
$textmixedThe string to test. Every byte must be a control character for the result to be true. An int between -128 and 255 is interpreted as an ASCII codepoint, which is why non-string arguments are deprecated as of PHP 8.1.

Return value

booltrue if every character in text is a control character in the current locale, false otherwise. An empty string always returns false.

Errors

Never throws. A non-string argument raises an E_DEPRECATED notice as of PHP 8.1; values that are neither string nor int return false.

Changelog

  • PHP 8.1Passing a non-string argument is deprecated. Ints between -128 and 255 are still read as ASCII codepoints, so cast to string or use chr() explicitly.

ctype_cntrl() tests whether a string is made up entirely of control characters — ASCII 0 to 31 plus DEL (127). That covers the null byte, bell, backspace, tab, line feed, carriage return and escape. It is the exact complement of ctype_print() over the ASCII range.

When to reach for it

The whole-string form is rarely what you want, because real data is almost never only control characters. In practice you call it per character while scanning input that arrived from a file upload, a terminal, a scanner or a legacy feed, to find bytes that will corrupt a log line, break a CSV or slip an ANSI escape sequence into terminal output.

What trips people up

Tab, newline and carriage return are control characters, so a perfectly ordinary multi-line string will contain them. If you are hunting for unexpected control characters, whitelist \t, \n and \r before testing.

Note also that the check is per byte. A multi-byte UTF-8 character is never flagged, but an invalid byte sequence containing a stray \x00 is.

Example

Try it yourself
Loading editor…
Press Run to execute the code.

When to use it

  • Scanning uploaded CSV fields for null bytes or bell characters before importing
  • Stripping ANSI escape sequences and other invisible bytes out of log lines
  • Rejecting HTTP header values that contain CR or LF to prevent header injection

Frequently asked questions

Is a newline a control character in PHP?

Yes. Line feed, carriage return and tab are all ASCII control characters, so ctype_cntrl("\n") returns true. Exclude them explicitly if you only care about unusual control bytes.

How do I remove all control characters from a string?

Use preg_replace('/[\x00-\x1F\x7F]/', '', $text) for a one-liner, or loop with ctype_cntrl when you want to keep some characters such as newline and tab.

What is the difference between ctype_cntrl and ctype_print?

They are opposites over the ASCII range: ctype_print is true for characters that produce output including the space, and ctype_cntrl is true for the non-printing control codes 0-31 and 127.

More examples

Locating control bytes in a field

Prints "Control chars at: offset 5 (0x00), offset 8 (0x09)". bin2hex() is used because the characters themselves are invisible, so printing them directly would show nothing.

Example · php
<?php
$input = "order\x00id\t42";
$found = [];

foreach (str_split($input) as $offset => $ch) {
    if (ctype_cntrl($ch)) {
        $found[] = "offset $offset (0x" . bin2hex($ch) . ')';
    }
}

echo $found ? 'Control chars at: ' . implode(', ', $found) . "\n" : "Clean\n";

Allowing tab and newline but nothing else

Prints string(16) "line one\nlinetwo" with the bell character (0x07) removed while the newline survives — nothing is put in the bell's place, so "line" and "two" end up joined. This whitelist pattern is what most sanitising code actually needs.

Example · php
<?php
$text = "line one\nline\x07two";
$clean = '';

foreach (str_split($text) as $ch) {
    if (!ctype_cntrl($ch) || $ch === "\n" || $ch === "\t") {
        $clean .= $ch;
    }
}

var_dump($clean);

Discussion

  • Be the first to comment on this lesson.