Signature
ctype_alnum(mixed $text): boolPurpose
ctype_alnum() answers one narrow question: is every character in a string either a letter or a digit? It is a quick check for identifiers such as product codes, simple usernames or tokens that must not contain spaces, punctuation or symbols. It belongs to the ctype extension, which tests characters by class rather than by pattern, so no regular expression is needed.
Signature
Parameters and defaults
$text is the only parameter and has no default. It is meant to be a string. The function examines each character in turn and returns true only if all of them are alphanumeric.
The manual describes a legacy behavior for integers. An int from -128 to 255 is treated as the ASCII value of one character, with negative values having 256 added. Any other integer is treated as a string of its decimal digits. As of PHP 8.1.0, passing a non-string argument is deprecated, and the manual says the argument will be interpreted as a string in the future. In new code, pass strings only. Cast with (string) if you want the digits, or use chr() if you really want a character code.
Return value and failure cases
The function returns a bool:
truewhen every character is a letter or a digit.falsewhen at least one character is something else, such as a space, punctuation mark or newline.falsefor an empty string. This is the case people forget most often.
There is no exception for ordinary string input. A failed check is simply false. Which characters count as letters depends on the current locale. In the default locale this means the ASCII letters A to Z and a to z plus the digits 0 to 9. If you need a predictable, locale-independent rule, state it explicitly, for example by also checking the length or by using a pattern that spells out the allowed characters.
Example 1: Checking several strings
This example runs the function over a mix of inputs and prints the results as JSON. Notice that the empty string and the string containing a space both return false.
$inputs = ['AbCd1zyZ9', 'foo!#$bar', '', 'abc 123', 'user42'];
$result = [];
foreach ($inputs as $value) {
$result[$value] = ctype_alnum($value);
}
echo json_encode($result, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";{"AbCd1zyZ9":true,"foo!#$bar":false,"":false,"abc 123":false,"user42":true}
Example 2: A small username rule
ctype_alnum() only checks the character class, not the length. Combine it with strlen() to build a complete rule. This validator accepts names of 3 to 12 letters and digits. A trailing newline makes the last input fail, because a newline is not alphanumeric.
function isValidUsername(string $name): bool
{
$length = strlen($name);
return $length >= 3 && $length <= 12 && ctype_alnum($name);
}
$names = ['bob', 'ab', 'robert99', 'robert_99', "abc\n"];
$results = [];
foreach ($names as $name) {
$results[] = isValidUsername($name);
}
echo json_encode($results), "\n";[true,false,true,false,false]
Example 3: Integers must be converted deliberately
Because of the legacy integer behavior, a bare number can mean either a character code or a digit string. Make your intent explicit instead. Casting to string checks the decimal digits, and chr() checks a single character with that code.
$results = [
ctype_alnum((string) 12345),
ctype_alnum((string) -5),
ctype_alnum(chr(65)),
ctype_alnum(chr(33)),
];
echo json_encode($results), "\n";[true,false,true,false]
The string "-5" fails because the minus sign is not a letter or digit. chr(65) is "A", which passes, while chr(33) is "!", which does not.
Edge cases
- Empty string: always
false. If an empty value is acceptable in your application, test for it separately before calling the function. - Whitespace: spaces, tabs and newlines are not alphanumeric, so untrimmed input from a form or file often fails unexpectedly.
- Locale: letter classification follows the locale. Do not assume accented or non-Latin letters pass or fail without checking your runtime configuration. For true Unicode handling, ctype is the wrong tool and a Unicode-aware approach such as
IntlChar::isalnum()(listed in the manual) is a better fit. - Numeric strings: a string like
"12.5"fails because of the dot, even thoughis_numeric()accepts it.
Common mistakes
- Passing integers directly.
ctype_alnum(300)is read as the digits"300", butctype_alnum(65)is read as the letterA. This is confusing and deprecated since PHP 8.1. Always cast or convert first. - Forgetting the empty string. A blank field returns
false, which may be reported as an invalid character problem instead of a missing value. - Treating it as a length check. A 500-character string of letters passes. Add
strlen()limits where size matters. - Expecting Unicode letters to pass. The check is byte and locale based, not a general Unicode letter test.
- Skipping trimming. Run
trim()on user input when surrounding whitespace should be ignored, but only if that matches your rules.
Related functions
ctype_alpha()checks for letters only.ctype_digit()checks for digits only.setlocale()changes the locale that influences character classes.IntlChar::isalnum()checks a single code point for alphanumeric status.
Recap
ctype_alnum(mixed $text): bool returns true only when a non-empty string consists entirely of letters and digits. Pass strings, never bare integers. Remember that the empty string returns false, that whitespace and punctuation fail, and that length limits and Unicode support are your responsibility.
Tested examples
$inputs = ['AbCd1zyZ9', 'foo!#$bar', '', 'abc 123', 'user42'];
$result = [];
foreach ($inputs as $value) {
$result[$value] = ctype_alnum($value);
}
echo json_encode($result, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";{"AbCd1zyZ9":true,"foo!#$bar":false,"":false,"abc 123":false,"user42":true}
function isValidUsername(string $name): bool
{
$length = strlen($name);
return $length >= 3 && $length <= 12 && ctype_alnum($name);
}
$names = ['bob', 'ab', 'robert99', 'robert_99', "abc\n"];
$results = [];
foreach ($names as $name) {
$results[] = isValidUsername($name);
}
echo json_encode($results), "\n";[true,false,true,false,false]
$results = [
ctype_alnum((string) 12345),
ctype_alnum((string) -5),
ctype_alnum(chr(65)),
ctype_alnum(chr(33)),
];
echo json_encode($results), "\n";[true,false,true,false]