Signature
ctype_lower(mixed $text): boolPurpose
ctype_lower() answers a narrow question: does every character in a string count as a lowercase letter? It is a quick, byte-oriented check from the ctype extension. It suits small validation jobs such as accepting a lowercase code, a token made of a to z, or a name that must not contain capitals, digits or punctuation.
The function does not convert anything and does not tell you which character failed. It only returns true or false for the whole string.
Signature
Parameters and defaults
$text is the value to test. It has no default, so you must supply it. The parameter is typed mixed for historical reasons, but you should pass a string.
The manual describes an older behaviour for integers. An integer from -128 to 255 is treated as the ASCII code of one character, and any other integer is treated as the string of its decimal digits. Since PHP 8.1, passing a non-string argument is deprecated. If you start with an integer or another type, cast it with (string) or call chr() when you really mean a character code. This article avoids non-string calls so its examples stay free of deprecation notices.
Return value and failure cases
The function returns true only when every character of the string is a lowercase letter in the current locale. Otherwise it returns false. Several results can surprise you:
- An empty string always returns
false, nottrue. - Digits, spaces, hyphens, underscores and newlines are not lowercase letters, so one of them makes the result
false. - A single uppercase letter anywhere makes the result
false.
The function does not throw on a normal string. Its only special failure mode is the deprecation for non-string arguments described above.
Example 1: checking several inputs
This example runs a handful of plain ASCII strings through the function and prints the results as JSON.
$inputs = ['username', 'User', 'abc123', '', 'with space'];
$results = [];
foreach ($inputs as $input) {
$results[$input] = ctype_lower($input);
}
echo json_encode($results, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);{"username":true,"User":false,"abc123":false,"":false,"with space":false}Only username passes. User has a capital, abc123 has digits, the empty string always fails, and the space in with space is not a letter.
Example 2: allowing separators deliberately
Because hyphens fail the check, a slug validator has to remove the characters it wants to allow before calling ctype_lower(). The helper below strips hyphens and then tests what remains.
function isLowerSlug(string $slug): bool
{
return ctype_lower(str_replace('-', '', $slug));
}
$tests = ['hello-world', 'Hello-world', '--', 'php8'];
$results = [];
foreach ($tests as $test) {
$results[$test] = isLowerSlug($test);
}
echo json_encode($results, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);{"hello-world":true,"Hello-world":false,"--":false,"php8":false}The string -- becomes empty after the hyphens are removed, so the helper returns false. That is usually what you want, because a slug made only of separators is not meaningful.
Example 3: comparing related checks
The ctype functions look alike but test different things. ctype_alpha() accepts letters of either case, while ctype_lower() and ctype_upper() each accept one case.
$report = [
'lower' => ctype_lower('php'),
'upper' => ctype_upper('PHP'),
'alpha' => ctype_alpha('Php'),
'mixedLower' => ctype_lower('Php'),
];
echo json_encode($report, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);{"lower":true,"upper":true,"alpha":true,"mixedLower":false}The mixed-case string Php is alphabetic but is not entirely lowercase.
Edge cases
Locale. The check uses the current locale, so the set of lowercase letters can in principle change with setlocale(). For plain ASCII input, only a to z count. If your data can contain accented or other multibyte text, do not rely on this function. A byte-based check is the wrong tool for UTF-8 text, and a multibyte-aware approach such as IntlChar::islower() for individual code points is more suitable.
Whitespace. Leading or trailing spaces and newlines make the result false. If the value comes from user input, call trim() first when surrounding whitespace should be ignored.
Numeric input. Form fields and array values may arrive as integers or other non-strings. Convert them to a string explicitly so the intent is clear and the deprecation does not appear.
Common mistakes
- Expecting an empty string to pass. It returns
false, so check for emptiness separately if you need a different message. - Using it to test whether a string is "not uppercase". A string like
abc1is neither all-lowercase nor all-uppercase. - Passing an integer and assuming it is tested as digits. Small integers can be read as ASCII codes, which is exactly why the behaviour is deprecated.
- Treating it as a Unicode-aware validator. It works on bytes under the current locale.
- Using it to normalise text. It only reports a result. Use
strtolower()when you need to convert ASCII text.
Related functions
ctype_alpha()checks for letters of any case.ctype_upper()checks for uppercase letters.setlocale()changes locale information used by ctype checks.IntlChar::islower()tests a single code point when the intl extension is available.
Recap
ctype_lower() takes one value, ideally a string, and returns true only when every character is a lowercase letter. Empty strings, digits, spaces and punctuation all give false. Cast non-string input explicitly, avoid it for multibyte text, and strip any allowed separators before the check.
Tested examples
$inputs = ['username', 'User', 'abc123', '', 'with space'];
$results = [];
foreach ($inputs as $input) {
$results[$input] = ctype_lower($input);
}
echo json_encode($results, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);{"username":true,"User":false,"abc123":false,"":false,"with space":false}
function isLowerSlug(string $slug): bool
{
return ctype_lower(str_replace('-', '', $slug));
}
$tests = ['hello-world', 'Hello-world', '--', 'php8'];
$results = [];
foreach ($tests as $test) {
$results[$test] = isLowerSlug($test);
}
echo json_encode($results, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);{"hello-world":true,"Hello-world":false,"--":false,"php8":false}
$report = [
'lower' => ctype_lower('php'),
'upper' => ctype_upper('PHP'),
'alpha' => ctype_alpha('Php'),
'mixedLower' => ctype_lower('Php'),
];
echo json_encode($report, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);{"lower":true,"upper":true,"alpha":true,"mixedLower":false}