Глава 148 · С нуля → справочник
Проверка символов: полный справочник Ctype
Одиннадцать функций: цифры, буквы, регистр, пробелы, управляющие и HEX-символы. От одной строки до правил импорта и полей формы, с разбором Unicode и нестрокового входа.
Проверить текст кода, а не превратить его в число
Код 0041 проходит проверку, сохраняя ведущие нули
Задача первой программы — проверить состав кода посылки. Внутри остаётся строка, арифметического преобразования нет.
- $code = "0041"
Четыре текстовых символа: 0, 0, 4, 1.
- ctype_digit($code)
Каждая позиция — цифра, поэтому функция возвращает true.
- var_dump(...)
Показывает bool(true), ответ проверки.
- echo $code
Выводит исходные 0041. Нули остались на своих местах.
При "00A1" проверка даст false. Это модель последовательной проверки условия, а не изображение расположения байтов в памяти. Существование посылки в базе проверяется отдельно.
На наклейке посылки написано 0041. Это код из четырёх цифр: ведущие нули должны сохраниться. Прежде чем искать посылку, сайт проверяет, что посетитель ввёл только цифры. Семейство ctype отвечает именно на вопросы о составе строки. Оно не превращает код в число, не исправляет его и не ищет посылку в базе.
- В переменную $code помещена строка "0041".
- ctype_digit($code): 0 — цифра; 0 — цифра; 4 — цифра; 1 — цифра.
- Все позиции подходят → результат true.
- var_dump показывает ответ проверки. echo отдельно показывает неизменившийся код 0041.
<?php
$code = "0041";
var_dump(ctype_digit($code));
echo $code;
Ожидаемый результат
bool(true)
0041$ обозначает переменную; = сохраняет строку; кавычки сохраняют нули как часть текста. Скобки после имени функции передают значение на проверку. true означает «да». var_dump выводит тип bool и результат; echo печатает сам код. Точка с запятой завершает инструкцию. Циклы и регулярные выражения для этого вызова не нужны.
Теперь измените один символ на букву: "00A1" даст false. Даже три правильные цифры не компенсируют одну неподходящую букву. Перед продолжением полезно понимать переменную и вызов функции и её результат.
Один договор у всех одиннадцати функций
Передаём строку, получаем true или false. Проверяется каждый её байт: все должны относиться к выбранной группе. ctype_alpha("Ab") разрешает смесь регистров; ctype_lower("Ab") — нет. Ни одна функция семейства не считает пустую строку подходящей. Ответ false не сообщает позицию ошибки — при необходимости её находят отдельным проходом.
- Вход "": нет символов → digit=false и space=false.
- Вход " ": один пробел → space=true.
- Проверка обязательности поля отдельно объединяет нужные случаи.
<?php
var_dump(ctype_digit(""));
var_dump(ctype_space(""));
var_dump(ctype_space(" "));
Ожидаемый результат
bool(false)
bool(false)
bool(true)
В первых двух строках нет символов для проверки: результат false. В третьей строке есть один пробел, поэтому ctype_space возвращает true. Проверка обязательного поля должна отдельно решить, что делать с пустой строкой.
LC_CTYPE — настройка локали для классификации символов. В локали C буквами являются A–Z и a–z. В других однобайтовых локалях группы могут отличаться. UTF-8 хранит многие буквы несколькими байтами; ctype не собирает их в символ Unicode. Для русских имён, диакритики и разных письменностей выберите Unicode-правило, а не случайно подходящую серверную локаль.
В PHP 8.1+ любой нестроковый аргумент устарел. Особенность старого режима: int от −128 до 255 трактуется как код одного байта; к отрицательному прибавляется 256. Другие int проверяются как десятичная строка. Поэтому ctype_digit(48) исторически проверяет символ "0", а не текст "48". Не полагайтесь на эту неоднозначность. Если по договору нужен текст числа, явно создайте (string) $number; если символ по коду — chr($number). Для данных формы сначала is_string, а не безусловное приведение массива в строку.
<?php
$number = 65;
var_dump(ctype_alpha((string) $number));
var_dump(ctype_alpha(chr($number)));
Ожидаемый результат
bool(false)
bool(true)
(string) 65 создаёт "65": это цифры, не буквы. chr(65) создаёт ASCII-букву A. Оба аргумента уже строки, предупреждения об устаревшем нестроковом входе нет. Это объяснение старого поведения, а не совет преобразовывать любые входные данные без проверки.
Требования, установка и проверка окружения
Ctype использует стандартную библиотеку C и не требует сторонней библиотеки для классификации. В обычной сборке расширение включено по умолчанию; при сборке PHP его можно отключить флагом --disable-ctype. В стандартной Windows-сборке поддержка встроена: добавлять строку extension=ctype ради неё не требуется. Состав пакета дистрибутива или контейнера всё равно проверяют в том PHP, который обслуживает приложение.
- Запущенный PHP имеет свой список расширений.
- extension_loaded("ctype") ищет расширение.
- function_exists("ctype_digit") ищет доступную функцию.
- true и true в примере подтверждают возможность перейти к проверкам символов.
<?php
var_dump(extension_loaded("ctype"));
var_dump(function_exists("ctype_digit"));
Ожидаемый результат
bool(true)
bool(true)
Ожидаемый результат указан для окружения примеров с ctype. Если получается false, сначала уточните сборку, пакет и конфигурацию; CLI и сервер сайта могут запускать разные PHP. Composer-библиотека не включает отсутствующее нативное расширение сама.
Как сравнить CLI и веб-сервер, разобрано в настройке PHP. Здесь нет собственной группы директив ctype: поведение классификации зависит от локали. Не ставьте LC_ALL ради одной проверки — этим можно затронуть формат чисел и другие категории локали.
ASCII, Unicode и границы проверки
Следующий опыт меняет настройку, поэтому сначала разберём его каркас. if проверяет, удалось ли прочитать и установить локаль. === false сравнивает именно с признаком неудачи, а || означает «хотя бы одна проверка неуспешна». throw останавливает обычный путь, передавая ошибку вызывающему коду. В try находится сам опыт; finally возвращает прежнюю локаль при обычном завершении блока или передаче исключения. Эти конструкции подробно объясняются в условиях и границах выполнения и обработке ошибок. Здесь они нужны, чтобы демонстрация не оставила после себя изменённую настройку.
- Сохранить прежнюю локаль → установить LC_CTYPE=C.
- Анна как UTF-8-байты → ctype_alpha=false.
- Анна как Unicode-буквы в PCRE → совпадение, true.
- U+00A0 не ASCII-пробел → ctype_space=false; finally восстанавливает настройку.
<?php
$previous = setlocale(LC_CTYPE, 0);
if ($previous === false || setlocale(LC_CTYPE, "C") === false) {
throw new RuntimeException("Не удалось настроить локаль примера");
}
try {
var_dump(ctype_alpha("Анна"));
var_dump(preg_match('/\A\p{L}+\z/u', "Анна") === 1);
var_dump(ctype_space("\u{00A0}"));
} finally {
setlocale(LC_CTYPE, $previous);
}
Ожидаемый результат
bool(false)
bool(true)
bool(false)
Это следующий, более сложный опыт: setlocale с 0 читает настройку, C задаёт известный режим; finally восстанавливает прежний. preg_match проверяет Unicode-буквы: \A и \z ограничивают всю строку, \p{L} обозначает буквы, + требует одну или больше, u включает UTF-8. Неразрывный пробел U+00A0 не совпал с байтовой ctype_space. Сложные имена могут включать составные знаки, дефисы и пробелы; правило «только буквы» — не готовая проверка ФИО.
Локаль — состояние окружения, а не параметр конкретного вызова ctype. В многопоточном окружении setlocale может затронуть соседние потоки; начиная с PHP 7.0.5 на Windows информация локали поддерживается на уровне потока. Восстановление через finally полезно, но не устраняет гонку в окружении с общей локалью. В библиотеке предпочтительнее явно заданный ASCII/Unicode-шаблон без смены локали.
Разбор шаблонов и трёх исходов preg_match (1, 0, false) — регулярные выражения. Для отдельной кодовой точки Unicode есть методы IntlChar; обычная многобайтовая строка и одна кодовая точка — разные входы.
Выбрать проверку по задаче
| Нужно проверить | Подходит | Нужно дополнительно |
|---|---|---|
| Код посылки содержит только цифры | ctype_digit | Длина, допустимость нулей, существование кода и права на просмотр. |
| Артикул из букв и цифр | ctype_alnum | Локаль, длина; дефис и подчёркивание сюда не входят. |
| Однобайтовая буквенная команда | ctype_alpha | Список разрешённых команд; буквы не означают право выполнить действие. |
| HEX-цвет без # | ctype_xdigit | Разрешённая длина 3/4/6/8 по своему контракту. |
| Пустой по смыслу ASCII-текст | ctype_space | Отдельно пустая строка; Unicode-пробелы требуют другого правила. |
| Весь текст состоит из управляющих байтов | ctype_cntrl | Для поиска хотя бы одного управляющего байта нужен отдельный проход. |
| Все символы печатные, пробел допустим | ctype_print | Это не HTML-экранирование и не универсальная проверка Unicode. |
| Печатный текст без пробелов | ctype_graph | Это не проверка URL, имени файла или токена авторизации. |
Каждая ctype-проверка в худшем случае просматривает всю строку: работа растёт с её длиной. Сначала ограничьте длину входа, затем выполняйте проверки. Не разбивайте весь файл в массив символов ради одной проверки. Обещание «всегда быстрее регулярного выражения» некорректно: сравнивать нужно одинаковые правила и реальные данные.
Проверить свой выбор на реальных требованиях
- Поле quantity="0007": ctype_digit вернёт true, но разрешение ведущих нулей и диапазон количества — отдельное правило. Не используйте такой ответ как автоматическое разрешение заказа.
- Поле name="Анна-Мария": ctype_alpha не подходит для такого Unicode-имени. Сначала определите допустимую модель имени, затем выберите проверку.
- Пустая строка в списке через |: используйте $item !== "" и !ctype_space($item), чтобы не отбрасывать полезный текст "0".
- Поле code[]=123: это массив, а не строка. is_string должен остановить проверку до ctype.
- Строка id="12e3": is_numeric допускает числовую экспоненту, ctype_digit — нет. Выберите формат по договору API.
Серверная функция проверяет уже пришедший запрос. Она не блокирует клавиши в браузере. HTML-атрибуты помогают вводу, но серверная проверка остаётся обязательной: поле формы → POST → проверка.
Все функции Ctype
Функции и методы этой темы
Откройте карточку, чтобы увидеть договор функции, примеры, ограничения и связанные инструменты.
ctype_alnumПроверить, что короткий технический код состоит из букв и цифр.
ctype_alnum(mixed $text): bool| Часть вызова | Правило |
|---|---|
| text | Строка для проверки. Хотя историческая сигнатура содержит mixed, в новом коде передавайте string. Нестроковый вход deprecated с PHP 8.1. |
| Результат bool | true, если каждый символ — буква либо цифра. Пустая строка всегда даёт false. Исходная строка не меняется. |
| Окружение | Расширение ctype; байтовая классификация с учётом LC_CTYPE. Это не проверка букв Unicode. Здесь ASCII-примеры для локали C. |
- "SKU42" → S,K,U — буквы; 4,2 — цифры → true.
- "SKU_42" → _ не буква и не цифра → false.
<?php
var_dump(ctype_alnum("SKU42"));
var_dump(ctype_alnum("SKU_42"));
var_dump(ctype_alnum(""));
Ожидаемый результат
bool(true)
bool(false)
bool(false)
alnum объединяет alphabetic и numeric. Наличие букв не обязательно: "42" тоже подходит. Проверяется состав, а не формат артикула.
<?php
$codes = ["BR41", "BR-41", ["BR41"], "123456789"];
foreach ($codes as $code) {
if (!is_string($code) || strlen($code) > 8 || !ctype_alnum($code)) {
echo "Отклонён\n";
continue;
}
echo "Код: ", $code, "\n";
}
Ожидаемый результат
Код: BR41
Отклонён
Отклонён
Отклонён
Массив моделирует строки импорта. foreach берёт следующий элемент. || прекращает вычисление после истинного условия, поэтому массив не попадёт в strlen/ctype. continue пропускает неподходящий элемент. Длина проверена до посимвольного прохода.
Не применяйте этот договор к произвольным именам людей. Для ASCII-артикулов с дефисом понадобится явный набор разрешённых символов; не удаляйте дефисы молча, иначе разные артикулы могут стать одинаковыми.
Рядом: ctype_alpha, ctype_digit, ctype_graph. Общие правила: тип входа, локаль и Unicode.
ctype_alphaПроверить буквенное поле технического протокола.
ctype_alpha(mixed $text): bool| Часть вызова | Правило |
|---|---|
| text | Строка для проверки. Хотя историческая сигнатура содержит mixed, в новом коде передавайте string. Нестроковый вход deprecated с PHP 8.1. |
| Результат bool | true, если все символы — буквы текущей локали. Пустая строка всегда даёт false. Исходная строка не меняется. |
| Окружение | Расширение ctype; байтовая классификация с учётом LC_CTYPE. Это не проверка букв Unicode. Здесь ASCII-примеры для локали C. |
- "Ready" → R,e,a,d,y подходят, регистр может различаться.
- "Ready2" → последняя позиция 2 не буква → false.
<?php
var_dump(ctype_alpha("Ready"));
var_dump(ctype_alpha("Ready now"));
var_dump(ctype_alpha("Ready2"));
Ожидаемый результат
bool(true)
bool(false)
bool(false)
Ready содержит только буквы. Второй ответ отрицательный из-за пробела, третий — из-за цифры. Проверка не меняет регистр.
<?php
foreach (["ping", "delete", "ping2"] as $command) {
if (strlen($command) > 12 || !ctype_alpha($command)) {
echo "Неверная форма команды\n";
} elseif (!in_array($command, ["ping", "status"], true)) {
echo "Команда не разрешена\n";
} else {
echo "Разрешена: ", $command, "\n";
}
}
Ожидаемый результат
Разрешена: ping
Команда не разрешена
Неверная форма команды
Сначала проверен состав короткой строки, затем белый список. Третий аргумент true у in_array включает строгое сравнение. Здесь ничего не отправляется и не выполняется: это модель выбора разрешённой команды.
Для всей строки ctype_alpha не равно ctype_upper(...) || ctype_lower(...): смешанный регистр допустим только первому. Для одного символа в C такое объединение совпадает. В Unicode встречаются буквы без верхнего/нижнего регистра; не расширяйте однобайтовую модель на них.
Рядом: ctype_alnum, ctype_lower, ctype_upper. Общие правила: тип входа, локаль и Unicode.
ctype_cntrlИсследовать управляющие байты в строке протокола или импорта.
ctype_cntrl(mixed $text): bool| Часть вызова | Правило |
|---|---|
| text | Строка для проверки. Хотя историческая сигнатура содержит mixed, в новом коде передавайте string. Нестроковый вход deprecated с PHP 8.1. |
| Результат bool | true, если вся строка состоит из управляющих символов. Пустая строка всегда даёт false. Исходная строка не меняется. |
| Окружение | Расширение ctype; байтовая классификация с учётом LC_CTYPE. Это не проверка букв Unicode. Здесь ASCII-примеры для локали C. |
- "ORD\n41" → проверка целой строки даёт false.
- Проверки отдельных позиций: O нет, R нет, D нет, перевод строки да.
- Вернуть позицию 3, не печатая скрытый управляющий байт.
<?php
var_dump(ctype_cntrl("\r\n\t"));
var_dump(ctype_cntrl("Order\n41"));
var_dump(ctype_cntrl(" "));
Ожидаемый результат
bool(true)
bool(false)
bool(false)
В двойных кавычках \r, \n, \t обозначают возврат каретки, перевод строки и табуляцию. Обычный пробел не управляющий символ. false во втором случае не означает отсутствия управляющего байта: не все байты управляющие.
<?php
function firstControlByte(string $text): ?int
{
$length = strlen($text);
for ($position = 0; $position < $length; $position++) {
if (ctype_cntrl($text[$position])) {
return $position;
}
}
return null;
}
var_dump(firstControlByte("ORD\n41"));
var_dump(firstControlByte("ORD41"));
Ожидаемый результат
int(3)
NULL
Функция возвращает позицию первого управляющего байта либо null. Индексы строки начинаются с 0: O=0, R=1, D=2, перевод=3. for проверяет по одному байту, поэтому здесь вопрос «есть хотя бы один». Результат 0 был бы допустимой позицией; проверяйте !== null, а не if($position).
<?php
$identifiers = ["ORD41", "ORD\n42"];
foreach ($identifiers as $identifier) {
$badPosition = null;
for ($position = 0; $position < strlen($identifier); $position++) {
if (ctype_cntrl($identifier[$position])) {
$badPosition = $position;
break;
}
}
if ($badPosition !== null) {
echo "Строка импорта отклонена: управляющий байт на позиции ", $badPosition, "\n";
continue;
}
echo "Можно искать заказ: ", $identifier, "\n";
}
Ожидаемый результат
Можно искать заказ: ORD41
Строка импорта отклонена: управляющий байт на позиции 3
Партнёр выгрузил ID заказов; в один попал невидимый перевод строки. Если незаметно убрать его, значение изменится и может совпасть с чужим ID. Поэтому импорт отклоняет строку и сообщает позицию. break завершает внутренний поиск после первого сбоя, continue переходит к следующему ID. !== null сохраняет правильную обработку ошибки на позиции 0. Вывод здесь консольный: в HTML сообщения экранируют. Остальные правила ID и наличие заказа проверяются следующим шагом.
В C это байты 0–31 и 127. Проверка не находит все Unicode-управляющие знаки или форматирующие символы. Не считайте удаление этих байтов универсальной очисткой: иногда перевод строки допустим, иногда вход нужно отклонить и сообщить об ошибке, а не менять ID.
Рядом: ctype_print, ctype_graph, ctype_space. Общие правила: тип входа, локаль и Unicode.
ctype_digitПроверить код из десятичных цифр без знака, точки и пробелов.
ctype_digit(mixed $text): bool| Часть вызова | Правило |
|---|---|
| text | Строка для проверки. Хотя историческая сигнатура содержит mixed, в новом коде передавайте string. Нестроковый вход deprecated с PHP 8.1. |
| Результат bool | true, если каждый символ — десятичная цифра. Пустая строка всегда даёт false. Исходная строка не меняется. |
| Окружение | Расширение ctype; байтовая классификация с учётом LC_CTYPE. Это не проверка букв Unicode. Здесь ASCII-примеры для локали C. |
- "0041" → четыре цифры → true.
- strlen("0041") → 4; оба требования формата выполнены.
- Код остаётся "0041", приведение к int не производится.
<?php
var_dump(ctype_digit("007"));
var_dump(ctype_digit("-7"));
var_dump(ctype_digit("7.0"));
var_dump(ctype_digit("7e2"));
var_dump(ctype_digit("0"));
Ожидаемый результат
bool(true)
bool(false)
bool(false)
bool(false)
bool(true)
Знак, точка и буква e не цифры. Ноль и ведущие нули допустимы для проверки символов. Большая строка цифр тоже может пройти, хотя её число не помещается в int.
<?php
function hasFourDigits(mixed $value): bool
{
return is_string($value) && strlen($value) === 4 && ctype_digit($value);
}
foreach (["0041", "41", "4e01", ["0041"], 41] as $value) {
if (!hasFourDigits($value)) {
echo "Введите код из четырёх цифр\n";
continue;
}
$parcels = ["0041" => "Передана курьеру"];
echo "Посылка ", $value, ": ", $parcels[$value] ?? "не найдена", "\n";
}
Ожидаемый результат
Посылка 0041: Передана курьеру
Введите код из четырёх цифр
Введите код из четырёх цифр
Введите код из четырёх цифр
Введите код из четырёх цифр
mixed разрешает функции принять любой PHP-тип и самой вернуть отказ. && означает «все условия верны» и останавливается при первом false. Сначала функция отвечает на маленький вопрос о формате. Вызывающий код использует ответ: при ошибке выводит подсказку, при успехе ищет посылку в учебном массиве. Код 0041 остаётся строкой с нулями. Добавьте в список 9999: формат правильный, но посылка не найдена. Нативный int 41 сознательно не принимаем: по договору поле должно быть текстом. Это не проверка подлинности секретного PIN: срок действия, доступ и ограничение попыток потребовали бы отдельной логики.
Для формы с quantity сначала проверяют строку и длину, затем допустимый диапазон перед приведением к int. Если требуется математическое число со знаком/дробью/экспонентой, посмотрите is_numeric. Если требуется сам тип int — is_int. Преобразование intval не является проверкой корректности исходной строки.
Не применяйте empty к результату ввода до этой проверки, если "0" допустим. Для телефона цифры — только часть формата: код страны, длина, международный знак + и подтверждение владения требуют отдельного договора.
Рядом: ctype_alnum, ctype_xdigit, ctype_space. Общие правила: тип входа, локаль и Unicode.
ctype_graphПроверить печатное поле без пробельных символов.
ctype_graph(mixed $text): bool| Часть вызова | Правило |
|---|---|
| text | Строка для проверки. Хотя историческая сигнатура содержит mixed, в новом коде передавайте string. Нестроковый вход deprecated с PHP 8.1. |
| Результат bool | true, если все байты печатные и не пробельные. Пустая строка всегда даёт false. Исходная строка не меняется. |
| Окружение | Расширение ctype; байтовая классификация с учётом LC_CTYPE. Это не проверка букв Unicode. Здесь ASCII-примеры для локали C. |
- "ORD-41" → буквы, дефис, цифры → true.
- "ORD 41" → позиция с пробелом нарушает условие → false.
<?php
var_dump(ctype_graph("ORD-41"));
var_dump(ctype_graph("ORD 41"));
var_dump(ctype_graph("ORD\t41"));
Ожидаемый результат
bool(true)
bool(false)
bool(false)
Дефис разрешён как печатный символ; обычный пробел и табуляция не проходят. graph — не сокращение от графика: речь о видимых печатных символах.
<?php
$parts = explode(" ", "SEND ORD-41");
foreach ($parts as $part) {
if (ctype_graph($part)) {
echo $part, "\n";
}
}
Ожидаемый результат
SEND
ORD-41
explode разделяет по каждому обычному пробелу. Два пробела создают пустую часть: ctype_graph её отклоняет. Такой разбор подходит только простому договору без кавычек и вложенных значений; полноценному языку нужен его парсер.
Знаки /, <, > и кавычки тоже могут пройти. Поэтому результат не делает текст безопасным путём файла, HTML или SQL. Для вывода по-прежнему нужен соответствующий контексту способ защиты.
Рядом: ctype_print, ctype_alnum, ctype_punct. Общие правила: тип входа, локаль и Unicode.
ctype_lowerПроверить буквенное слово в нижнем регистре.
ctype_lower(mixed $text): bool| Часть вызова | Правило |
|---|---|
| text | Строка для проверки. Хотя историческая сигнатура содержит mixed, в новом коде передавайте string. Нестроковый вход deprecated с PHP 8.1. |
| Результат bool | true, если каждый символ — строчная буква текущей локали. Пустая строка всегда даёт false. Исходная строка не меняется. |
| Окружение | Расширение ctype; байтовая классификация с учётом LC_CTYPE. Это не проверка букв Unicode. Здесь ASCII-примеры для локали C. |
- "draft" → пять строчных букв → true.
- "draft2" → 2 не строчная буква → false.
<?php
var_dump(ctype_lower("draft"));
var_dump(ctype_lower("draft2"));
var_dump(ctype_lower("Draft"));
Ожидаемый результат
bool(true)
bool(false)
bool(false)
Цифра 2 не является строчной буквой, хотя не имеет верхнего регистра. Поэтому ctype_lower и «нет заглавных букв» — разные условия.
<?php
function isSectionWord(string $name): bool
{
return strlen($name) <= 20 && ctype_lower($name);
}
foreach (["catalog", "my-catalog", "Catalog", ""] as $name) {
if (!isSectionWord($name)) {
echo "Имя раздела не подходит\n";
continue;
}
$pages = ["catalog" => "Каталог товаров", "contacts" => "Контакты"];
echo $pages[$name] ?? "Раздел не найден", "\n";
}
Ожидаемый результат
Каталог товаров
Имя раздела не подходит
Имя раздела не подходит
Имя раздела не подходит
Этот договор разрешает только короткое слово из строчных букв. После проверки вызывающий код выбирает заголовок из известного списка; catalog открывает каталог. Добавьте news: строка допустима, но раздел не найден. PHP-файлы по пользовательскому пути здесь не подключаются. Если проекту нужны дефисы или цифры, меняют правило осознанно; слепое удаление знаков может столкнуть разные имена. Для UTF-8-названий ctype_lower не подходит.
Функция не приводит текст к нижнему регистру. Сравнение strtolower($text) === $text имеет другой смысл: например, цифры не изменяются и тоже пройдут сравнение. Для UTF-8 нужен подходящий Unicode-инструмент, а для допустимого идентификатора — полный договор его символов.
Рядом: ctype_upper, ctype_alpha, ctype_alnum. Общие правила: тип входа, локаль и Unicode.
ctype_printПроверить однострочное печатное поле, в котором допустим пробел.
ctype_print(mixed $text): bool| Часть вызова | Правило |
|---|---|
| text | Строка для проверки. Хотя историческая сигнатура содержит mixed, в новом коде передавайте string. Нестроковый вход deprecated с PHP 8.1. |
| Результат bool | true, если каждый байт печатный, включая обычный пробел. Пустая строка всегда даёт false. Исходная строка не меняется. |
| Окружение | Расширение ctype; байтовая классификация с учётом LC_CTYPE. Это не проверка букв Unicode. Здесь ASCII-примеры для локали C. |
- "Order 41" → пробел допустим → true.
- "Order\n41" → управляющий перевод строки → false.
- " " → print=true, space=true; прикладное правило может отклонить.
<?php
var_dump(ctype_print("Order 41"));
var_dump(ctype_print("Order\n41"));
var_dump(ctype_print(" "));
Ожидаемый результат
bool(true)
bool(false)
bool(true)
print в названии означает группу печатных байтов: сама функция ничего не печатает. Печатает var_dump. Обычный пробел допустим, управляющий перевод строки нет.
<?php
$labels = ["Order 41", " ", "Order\n41"];
foreach ($labels as $label) {
$valid = strlen($label) <= 24 && ctype_print($label) && !ctype_space($label);
echo $valid ? "Можно передать\n" : "Исправьте подпись\n";
}
Ожидаемый результат
Можно передать
Исправьте подпись
Исправьте подпись
Условие моделирует устройство, которое принимает до 24 печатных ASCII-байтов в одной строке. Дополнительный !ctype_space отвергает подпись только из пробелов. Реального сетевого вызова нет. Перед поддержкой русского текста нужно изменить контракт устройства и кодировки, а не просто убрать проверку.
ctype_print не означает «текст хорошо отобразится в браузере». Управляющие последовательности, кодировка и HTML-контекст — разные вопросы. Проверка также не гарантирует, что в строке есть содержательное слово или что она подходит принтеру конкретной модели.
Рядом: ctype_graph, ctype_space, ctype_cntrl. Общие правила: тип входа, локаль и Unicode.
ctype_punctПроверить группу печатных небуквенных и нецифровых знаков.
ctype_punct(mixed $text): bool| Часть вызова | Правило |
|---|---|
| text | Строка для проверки. Хотя историческая сигнатура содержит mixed, в новом коде передавайте string. Нестроковый вход deprecated с PHP 8.1. |
| Результат bool | true, если каждый символ печатный и не относится к буквам, цифрам или пробелам. Пустая строка всегда даёт false. Исходная строка не меняется. |
| Окружение | Расширение ctype; байтовая классификация с учётом LC_CTYPE. Это не проверка букв Unicode. Здесь ASCII-примеры для локали C. |
<?php
var_dump(ctype_punct("-_"));
var_dump(ctype_punct("!?"));
var_dump(ctype_punct("A!"));
var_dump(ctype_punct("! "));
Ожидаемый результат
bool(true)
bool(true)
bool(false)
bool(false)
В C сюда входят печатные знаки, которые не являются буквами, цифрами или пробелами. Подчёркивание — один из них. В A! одна буква, поэтому вся строка не состоит из пунктуации.
<?php
function validReportSeparator(string $separator): bool
{
return strlen($separator) === 1
&& ctype_punct($separator)
&& in_array($separator, [";", "|", ","], true);
}
foreach ([";", "||", "<", " "] as $separator) {
if (!validReportSeparator($separator)) {
echo "Этот разделитель не поддерживается\n";
continue;
}
$output = fopen('php://output', 'w');
fputcsv($output, ['Артикул', 'Цена'], $separator, '"', '');
fputcsv($output, ['BR41', '250'], $separator, '"', '');
fclose($output);
}
Ожидаемый результат
Артикул;Цена
BR41;250
Этот разделитель не поддерживается
Этот разделитель не поддерживается
Этот разделитель не поддерживается
Получили настоящий текст отчёта с выбранным разделителем. php://output направляет запись в вывод программы; для файла передают путь к файлу. fputcsv учитывает кавычки и разделители внутри полей, пятый аргумент отключает нестандартное экранирование обратной косой чертой. Длина оставляет один байт, ctype_punct проверяет его класс, белый список сужает возможности. В таком коротком списке ctype-проверка избыточна: в рабочем коде достаточно списка. Она оставлена здесь, чтобы различить класс символа и разрешённые настройки отчёта.
Это не способ обнаружить «любой спецсимвол» во всём тексте или проверить надёжность пароля. HTML-знаки тоже пунктуация; они не становятся безопасными для вставки в HTML. Unicode-категории пунктуации шире байтового Ctype.
Рядом: ctype_alnum, ctype_graph, ctype_print. Общие правила: тип входа, локаль и Unicode.
ctype_spaceУзнать, состоит ли всё значение из пробельных символов.
ctype_space(mixed $text): bool| Часть вызова | Правило |
|---|---|
| text | Строка для проверки. Хотя историческая сигнатура содержит mixed, в новом коде передавайте string. Нестроковый вход deprecated с PHP 8.1. |
| Результат bool | true, если все символы относятся к пробельной группе. Пустая строка всегда даёт false. Исходная строка не меняется. |
| Окружение | Расширение ctype; байтовая классификация с учётом LC_CTYPE. Это не проверка букв Unicode. Здесь ASCII-примеры для локали C. |
- Разделение по | → "Поставка", " ", "0", "", "Монтаж".
- " " → space=true; "" → проверка длины; оба пропускаем.
- "0" → space=false; сохраняем полезное значение.
<?php
var_dump(ctype_space(" \t\r\n"));
var_dump(ctype_space("A B"));
var_dump(ctype_space(""));
var_dump(ctype_space("0"));
Ожидаемый результат
bool(true)
bool(false)
bool(false)
bool(false)
Кроме обычного пробела группа включает горизонтальную/вертикальную табуляцию, перевод строки, возврат каретки и перевод страницы. Пустая строка не пробельная строка. "0" — содержательный текст, его нельзя отбрасывать как пустой только из-за приведения к bool.
<?php
$items = explode("|", "Поставка| |0||Монтаж");
foreach ($items as $item) {
if ($item === "" || ctype_space($item)) {
continue;
}
echo $item, "\n";
}
Ожидаемый результат
Поставка
0
Монтаж
Отдельно исключили нулевую длину и строку только из ASCII-пробелов. В остальных элементах ничего не меняем. Кириллица в непустом пункте просто не пробельная; это не попытка классифицировать её буквы. Для скопированных Unicode-пробелов нужен другой явный договор.
trim($text) === "" и ctype_space($text) не полностью взаимозаменяемы: отличаются пустая строка и наборы байтов (например NUL). trim может ещё и изменить значение, если результат присвоить. Неразрывный пробел UTF-8 не становится обычным ASCII-пробелом от внешнего сходства.
Рядом: ctype_cntrl, ctype_print, ctype_graph. Общие правила: тип входа, локаль и Unicode.
ctype_upperПроверить буквенный технический код в верхнем регистре.
ctype_upper(mixed $text): bool| Часть вызова | Правило |
|---|---|
| text | Строка для проверки. Хотя историческая сигнатура содержит mixed, в новом коде передавайте string. Нестроковый вход deprecated с PHP 8.1. |
| Результат bool | true, если каждый символ — заглавная буква текущей локали. Пустая строка всегда даёт false. Исходная строка не меняется. |
| Окружение | Расширение ctype; байтовая классификация с учётом LC_CTYPE. Это не проверка букв Unicode. Здесь ASCII-примеры для локали C. |
- "USD" → три заглавные буквы → true.
- "ZZZ" тоже проходит класс символов; список магазина отклоняет.
- "US2" → цифра не заглавная буква → false.
<?php
var_dump(ctype_upper("USD"));
var_dump(ctype_upper("US2"));
var_dump(ctype_upper("Usd"));
Ожидаемый результат
bool(true)
bool(false)
bool(false)
U, S, D — заглавные буквы. Цифра и строчная d не удовлетворяют требованию. Это проверка, не преобразование регистра.
<?php
foreach (["USD", "ZZZ", "US2"] as $currency) {
if (strlen($currency) !== 3 || !ctype_upper($currency)) {
echo "Неверный формат\n";
} elseif (!in_array($currency, ["RUB", "USD", "EUR"], true)) {
echo "Валюта не поддерживается магазином\n";
} else {
echo "Поддерживается: ", $currency, "\n";
}
}
Ожидаемый результат
Поддерживается: USD
Валюта не поддерживается магазином
Неверный формат
Три заглавные буквы — проверка формы. Поддерживаемые валюты — настройка нашего учебного магазина, а не полный международный каталог и не гарантия работы платёжного провайдера. В коде нет платежей.
Не равнозначно strtoupper($text) === $text: знаки и цифры не изменяются при таком преобразовании. Для кода валюты/страны проверка регистра не заменяет справочник действительных кодов.
Рядом: ctype_lower, ctype_alpha, ctype_alnum. Общие правила: тип входа, локаль и Unicode.
ctype_xdigitПроверить HEX-строку перед цветовым значением или разбором байтов.
ctype_xdigit(mixed $text): bool| Часть вызова | Правило |
|---|---|
| text | Строка для проверки. Хотя историческая сигнатура содержит mixed, в новом коде передавайте string. Нестроковый вход deprecated с PHP 8.1. |
| Результат bool | true, если все символы принадлежат 0–9, A–F, a–f. Пустая строка всегда даёт false. Исходная строка не меняется. |
| Окружение | Расширение ctype; байтовая классификация с учётом LC_CTYPE. Это не проверка букв Unicode. Здесь ASCII-примеры для локали C. |
- "A2B3C4" → шесть разрешённых символов → true.
- Правило RGB требует длину 6 → добавить # и получить #a2b3c4.
- Для "abc" ctype=true, но RGB-правило длины и правило пар байтов дают отказ.
<?php
var_dump(ctype_xdigit("1aF0"));
var_dump(ctype_xdigit("0x1a"));
var_dump(ctype_xdigit("1g"));
var_dump(ctype_xdigit("abc"));
Ожидаемый результат
bool(true)
bool(false)
bool(false)
bool(true)
Шестнадцатеричная запись использует 0–9 и A–F в обоих регистрах. Префикс 0x не проходит из-за x. Нечётное количество символов допустимо для ctype_xdigit, но может не подходить следующей операции.
<?php
function readRgbColor(mixed $raw): ?string
{
if (!is_string($raw) || strlen($raw) !== 6 || !ctype_xdigit($raw)) {
return null;
}
return "#" . strtolower($raw);
}
foreach (["A2B3C4", "abc", "#a2b3c4", "zzzzzz", ["A2B3C4"]] as $raw) {
echo readRgbColor($raw) ?? "Нужны 6 HEX-символов", "\n";
}
Ожидаемый результат
#a2b3c4
Нужны 6 HEX-символов
Нужны 6 HEX-символов
Нужны 6 HEX-символов
Нужны 6 HEX-символов
Наше поле принимает ровно шесть HEX-символов без #. Это сознательно более узкое правило, чем все CSS-цвета. После проверки добавили # и унифицировали регистр. null обозначает отказ; ?? выбирает сообщение. Если цвет передают в query string с #, символ кодируют как %23: неэкранированный фрагмент URL серверу не отправляется. $_GET уже декодирован PHP; повторный urldecode не нужен.
<?php
$rawColor = "A2B3C4";
if (strlen($rawColor) === 6 && ctype_xdigit($rawColor)) {
$cssColor = '#' . strtolower($rawColor);
echo '<p>Цвет товара: <span style="display:inline-block;width:3em;height:1em;border:1px solid #333;background:',
$cssColor, '"></span> ', $cssColor, '</p>';
} else {
echo '<p>Нужно ровно 6 HEX-символов, например A2B3C4.</p>';
}
Ожидаемый результат
<p>Цвет товара: <span style="display:inline-block;width:3em;height:1em;border:1px solid #333;background:#a2b3c4"></span> #a2b3c4</p>Сохраните как example.php и откройте через локальный PHP-сервер: появится цветной прямоугольник с подписью. В консоли вы увидите тот же HTML как текст. Функция сама ничего не рисует: она разрешает только шесть HEX-символов; PHP добавляет # и выдаёт HTML, браузер окрашивает span. Замените значение на FF8800 — образец станет оранжевым; zz8800 даст сообщение. Строгий список допустимых символов не позволяет вставить произвольный CSS в этот конкретный атрибут. Если значение приходит из формы, перед strlen отдельно проверьте is_string, как в предыдущем примере.
Цвет товара: #a2b3c4
<?php
foreach (["4142", "abc", "41ZZ"] as $hex) {
if (strlen($hex) > 64 || strlen($hex) % 2 !== 0 || !ctype_xdigit($hex)) {
echo "Неверный HEX-пакет\n";
continue;
}
$bytes = hex2bin($hex);
if ($bytes === false) {
throw new RuntimeException("Не удалось декодировать HEX");
}
echo bin2hex($bytes), "\n";
}
Ожидаемый результат
4142
Неверный HEX-пакет
Неверный HEX-пакет
% 2 вычисляет остаток деления длины: 0 означает пары символов. 41 и 42 — два байта; bin2hex показывает их безопасным текстом вместо произвольного двоичного вывода. Максимум 64 символа — правило нашего маленького пакета, не лимит PHP. Проверка не обещает, что пакет соответствует протоколу или подписи.
ctype_xdigit не преобразует строку в int и не проверяет подлинность хеша/токена. Для двоичного декодирования длина должна быть чётной. Пустой HEX может иметь смысл в вашем протоколе, но ctype_xdigit("") возвращает false: разрешение пустого значения задавайте отдельно.
Рядом: ctype_digit, ctype_alnum, ctype_graph. Общие правила: тип входа, локаль и Unicode.