Character checks7 min readExamples run on PHP 8.5.10

ctype_upper()

Learn how ctype_upper() tests whether every character in a string is an uppercase letter, with examples, edge cases, locale notes and common mistakes.

Signature

ctype_upper(mixed $text): bool
Available since PHP 4.0.47.48.08.18.28.38.48.5All versions →

Purpose

ctype_upper() answers one narrow question: is every character in a string an uppercase letter? It is a quick validation helper for short, strict inputs such as region codes, grade labels or tokens that must be all capitals. It does not convert case and it does not look inside the string for a pattern. It only reports true or false.

Signature

The function belongs to the ctype extension, which provides small character-class checks that work byte by byte.

Parameters and defaults

$text is the value to test. There are no other parameters and no defaults. You should pass a string.

The manual documents a legacy behaviour for integers. An int from -128 to 255 is treated as the ASCII code of a single character, and any other int is treated as a string of its decimal digits. Since PHP 8.1 passing a non-string argument is deprecated, and the manual says the argument will be read as a string in the future. If you have a number, cast it with (string) when you mean digits, or use chr() when you mean a character code. Being explicit keeps your code stable and avoids deprecation notices.

Return value and failure cases

The function returns true only when every character is an uppercase letter in the current locale. Otherwise it returns false. It does not throw for ordinary strings, and an empty string always gives false, which is different from what some "all items match" checks would suggest.

Because the check is per character, one bad character is enough to fail. Digits, spaces, punctuation, underscores and line breaks all make the result false.

Example 1: basic strings

The first example runs several ASCII strings through the function and prints the results as JSON.

Example
<?php
$inputs = ['LMNSDO', 'AKLWC139', 'akwSKWsm', 'HELLO WORLD'];
$results = [];
foreach ($inputs as $input) {
    $results[$input] = ctype_upper($input);
}
echo json_encode($results), "\n";
Output
{"LMNSDO":true,"AKLWC139":false,"akwSKWsm":false,"HELLO WORLD":false}

Only LMNSDO passes. AKLWC139 contains digits, akwSKWsm mixes cases, and HELLO WORLD contains a space.

Example 2: validating a fixed-length code

ctype_upper() checks the character class but not the length, so combine it with strlen() when the format has a fixed size.

Example
<?php
function isRegionCode(string $value): bool
{
    return strlen($value) === 2 && ctype_upper($value);
}

$values = ['US', 'us', 'U1', 'USA', ''];
echo json_encode(array_map('isRegionCode', $values)), "\n";
Output
[true,false,false,false,false]

Only US is accepted. Lowercase, a digit, a third letter and an empty string are all rejected.

Example 3: edge cases and explicit conversions

This example shows the empty string, trailing whitespace and the two explicit ways to handle numbers.

Example
<?php
$raw = "ABC\n";
$checks = [
    'empty' => ctype_upper(''),
    'newline' => ctype_upper($raw),
    'trimmed' => ctype_upper(trim($raw)),
    'digits string' => ctype_upper((string) 65),
    'chr' => ctype_upper(chr(65)),
];
echo json_encode($checks), "\n";
Output
{"empty":false,"newline":false,"trimmed":true,"digits string":false,"chr":true}

The newline at the end of $raw is a character that is not an uppercase letter, so the first check fails until the value is trimmed. Casting 65 to a string produces the digits 6 and 5, which are not letters. chr(65) produces A, which is.

Edge cases

  • Empty string: always false. If empty input should be allowed, test for it separately.
  • Whitespace: spaces, tabs and newlines are not uppercase letters. Trim user input first if surrounding whitespace is acceptable.
  • Locale: the definition of an uppercase letter depends on the current locale. With the default setup, stick to ASCII A to Z for predictable results. Changing it with setlocale() can alter how bytes above 127 are classified, so such code is harder to reproduce across servers.
  • Multibyte text: the check is byte-oriented. Do not rely on it for UTF-8 text with accents or non-Latin scripts. For code point properties, the manual points to IntlChar::isupper() when the intl extension is available.
  • Non-string input: integers keep their legacy ASCII-code interpretation but are deprecated as of PHP 8.1. Convert them explicitly.

Common mistakes

  1. Expecting an empty string to pass. It returns false.
  2. Forgetting digits and separators. A code like AB-12 is not all uppercase letters. If digits are allowed, use a different check or a regular expression.
  3. Passing integers on purpose. ctype_upper(65) relies on deprecated behaviour. Use chr(65) or a string instead.
  4. Using it as a case-conversion test for all languages. It is not a Unicode-aware validator.
  5. Skipping the length check. ctype_upper('A') is true, so enforce size separately when a format requires it.
  6. Not trimming input. A trailing newline from a pasted value causes a surprising false.
  • ctype_alpha() checks for letters of either case.
  • ctype_lower() checks for lowercase letters.
  • setlocale() changes locale information that can affect ctype checks.
  • IntlChar::isupper() checks the Unicode general category "Lu" for a code point.

Recap

ctype_upper(mixed $text): bool returns true only for a non-empty string whose characters are all uppercase letters in the current locale. Pass real strings, trim input when whitespace is not meaningful, add your own length rule when needed, and remember that digits, spaces and the empty string all produce false.

Tested examples

Basic uppercase checks on ASCII strings
<?php
$inputs = ['LMNSDO', 'AKLWC139', 'akwSKWsm', 'HELLO WORLD'];
$results = [];
foreach ($inputs as $input) {
    $results[$input] = ctype_upper($input);
}
echo json_encode($results), "\n";
Output
{"LMNSDO":true,"AKLWC139":false,"akwSKWsm":false,"HELLO WORLD":false}
Validating a two-letter region code
<?php
function isRegionCode(string $value): bool
{
    return strlen($value) === 2 && ctype_upper($value);
}

$values = ['US', 'us', 'U1', 'USA', ''];
echo json_encode(array_map('isRegionCode', $values)), "\n";
Output
[true,false,false,false,false]
Edge cases: empty string, whitespace and explicit conversions
<?php
$raw = "ABC\n";
$checks = [
    'empty' => ctype_upper(''),
    'newline' => ctype_upper($raw),
    'trimmed' => ctype_upper(trim($raw)),
    'digits string' => ctype_upper((string) 65),
    'chr' => ctype_upper(chr(65)),
];
echo json_encode($checks), "\n";
Output
{"empty":false,"newline":false,"trimmed":true,"digits string":false,"chr":true}