Перейти к содержимому
Поиск
Php Разработка

PHP: полный мануал с примерами, функциями и ООП

Практический мануал PHP: от переменных и читаемого кода до безопасных форм, интеграций, базы данных и ООП на примере магазина. Учебный маршрут, поиск функций, подробные примеры, разбор ошибок и исходники для скачивания.

Александр НекрасовИзменено:
Практический мануал PHP: от переменных и функций к объектной модели интернет-магазина
PHP 8.5.11149 глав4458 карточек справочника
Дерево руководства

Глава 78 · Сначала текст, затем импорт и протоколы

Многобайтовые строки: полный справочник mbstring

Длина и поиск Unicode, границы байтов, старые кодировки, японский текст, регулярные выражения, HTTP и почта — от понятной первой строки до точных контрактов функций.

Посчитать название товара, а не размер его байтов

Наглядная модель

Одна строка «Мир», два правильных результата

Кодировка UTF-8 объясняет, как байты объединяются в знаки. Выбираем измерение под правило формы или протокола.

  • strlen → 6 байтов

    Для размера файла и байтового бюджета считаются все шесть единиц хранения.

    • D0 9C

      Два байта для буквы М.

    • D0 B8

      Два байта для буквы и.

    • D1 80

      Два байта для буквы р.

  • mb_strlen UTF-8 → 3 кодовые точки

    Декодер видит три знака Unicode. Исходная строка не меняется.

    • М → U+041C

      Одна кодовая точка, индекс 0.

    • и → U+0438

      Одна кодовая точка, индекс 1.

    • р → U+0440

      Одна кодовая точка, индекс 2.

В этом слове каждая буква — одна кодовая точка. Составной emoji или буква с отдельным акцентом могут занимать несколько точек: для видимых знаков нужна графемная модель.

В каталоге разрешено короткое название. «Мир» состоит из трёх букв, но в UTF-8 занимает шесть байтов. Сначала получим полезный результат одной функцией. Затем научимся выбирать единицу длины и не портить данные при импорте.

Одна строка — два разных измерения
  1. Переменная $title хранит байты текста Мир
  2. UTF-8 задаёт, какие байты составляют одну кодовую точку
  3. mb_strlen($title, 'UTF-8') возвращает число 3
  4. echo печатает результат; исходный $title не меняется

$title — имя переменной; = сохраняет значение справа; кавычки ограничивают текст. Имя функции перед круглыми скобками указывает действие. В скобках через запятую передаются текст и название его кодировки. Функция возвращает число; echo выводит его. Точка с запятой завершает инструкцию.

Три буквы занимают шесть байтовСамостоятельный пример
<?php
declare(strict_types=1);

$title = 'Мир';
echo mb_strlen($title, 'UTF-8'), "\n";
echo strlen($title), "\n";
Ожидаемый результат
3
6

Сохраните файл в UTF-8 и выполните php example.php. mb_strlen — функция расширения mbstring; strlen работает с байтами. Обе полезны, но отвечают на разные вопросы. Если расширение не установлено, сначала откройте следующий раздел.

Предпосылки: переменная и присваивание, вызов и возвращаемое значение. Не начинайте с регулярных выражений: для длины готовая функция проще.

Байт, кодовая точка, графема и ширина — четыре шкалы

Байт состоит из восьми битов и имеет 256 возможных значений. Для всех языков этого недостаточно: многобайтовая кодировка использует несколько байтов на некоторые знаки. В диагностике 0xFF — шестнадцатеричная запись одного байта, U+20AC — номер знака евро в Unicode; это разные уровни описания.

Что считаемПример и задачаИнструмент
БайтыРазмер файла, протокольный лимит поля, бинарные данныеstrlen; mb_strcut режет байтовый бюджет по границам символов
Кодовые точки UnicodeВ UTF-8 А — одна, e + объединяющий акцент — двеmb_strlen, mb_substr, mb_str_split
Графемные кластерыОдин воспринимаемый знак может содержать несколько кодовых точекgrapheme_strlen / grapheme_substr из intl; отдельная зависимость
Условная восточноазиатская ширинаУзкие знаки 1, широкие 2; удобно для согласованного текстового отчётаmb_strwidth, mb_strimwidth; не измерение пикселей
Одинаковый вид не гарантирует одинаковое представлениеСамостоятельный пример
<?php
declare(strict_types=1);

$composed = "é";
$combined = "e\u{0301}";
echo strlen($composed), '/', mb_strlen($composed, 'UTF-8'), "\n";
echo strlen($combined), '/', mb_strlen($combined, 'UTF-8'), "\n";
echo mb_strwidth('A東', 'UTF-8'), "\n";
Ожидаемый результат
2/1
3/2
3

Запись \u{0301} в двойных кавычках добавляет объединяющий акцент. mbstring не нормализует эти строки в одну форму. Для Unicode-нормализации нужен Normalizer из intl; визуальная похожесть сама по себе не делает логины одинаковыми.

Составной emoji может содержать соединители, модификаторы и несколько картинок. Ни mb_strlen, ни mb_strwidth не обещает посчитать то, что человек увидит одним знаком. Правило поля нужно сформулировать явно: байты протокола, кодовые точки или графемы. Сначала проверяют корректность кодировки, затем применяют выбранное ограничение. SQL-коллация и JavaScript length могут использовать другие правила: согласуйте контракт формы и сервера.

Подключить расширение и проверить именно нужный PHP

mbstring — расширение PHP, а не Composer-пакет и не переключатель UTF-8 в редакторе. Оно не обязано входить в минимальную сборку. В консоли php --ini показывает конфигурацию CLI, php --ri mbstring — расширение. У сайта другой SAPI и иногда другая версия/INI; подтверждать загрузку нужно в обоих окружениях, не публикуя полный phpinfo с путями и секретами.

Проверить текстовые функции и отдельный движок regexСамостоятельный пример
<?php
declare(strict_types=1);

echo extension_loaded('mbstring') ? 'mbstring: yes' : 'mbstring: no';
echo "\n";
echo function_exists('mb_ereg') ? 'mbregex: yes' : 'mbregex: no';
Ожидаемый результат
mbstring: yes
mbregex: yes

В проверенной сборке обе возможности доступны. На другом компьютере no — причина установить/включить подходящий модуль, а не включать автоматическое преобразование HTTP.

В Windows используют расширение из совместимого комплекта PHP: архитектура, TS/NTS и версия должны совпадать; проверьте extension_dir и загрузку mbstring в фактически используемом php.ini. В Linux/macOS способ установки зависит от дистрибутива или менеджера пакетов. После изменения конфигурации веб-процессы перезапускают штатным способом; новая CLI-команда прочитает INI заново. Как найти действующую конфигурацию.

При сборке из исходников включают --enable-mbstring. libmbfl поставляется с PHP; возможность внешней библиотеки --with-libmbfl относилась к версиям до 7.3. Regex-часть можно исключить --disable-mbregex; с PHP 7.4 Oniguruma ищется через pkg-config, до этого библиотека поставлялась в исходниках и существовал --with-onig. Опция --disable-mbregex-backtrack отключает проверку обратного поиска и не является ускорением, которое стоит бездумно включать. Наличие mb_strlen ещё не доказывает наличие mb_ereg.

Как читать сигнатуры и не прятать ошибки

string — строка байтов; int — целое; bool — true/false; array — массив. ?string разрешает строку или null; string|false — два возможных результата. = null задаёт поведение при пропущенном аргументе. Амперсанд & у параметра означает изменение переданной переменной: для mb_parse_str и mb_convert_variables это принципиально. В примерах эти правила раскрываются на маленьких вызовах до массивов и callback.

В большинстве текстовых функций encoding = null означает текущую внутреннюю кодировку. mb_internal_encoding не преобразует уже существующие байты, не меняет кодировку исходного файла, базы или regex. Regex использует отдельное mb_regex_encoding. Для точного контракта передавайте известное UTF-8 явно; для старого файла сначала проверьте его заявленную кодировку и преобразуйте один раз на границе.

На современном PHP неизвестное имя кодировки обычно вызывает ValueError; неверный тип при strict_types=1 — TypeError; неверное число аргументов — ArgumentCountError. В слабом режиме скаляры иногда преобразуются; null для ненулевого встроенного параметра deprecated с 8.1. Не ловите всё ради пустой строки: неверная конфигурация не равна пустому полю. Ошибочная последовательность байтов не всегда вызывает исключение: проверка, подстановка и конкретная функция имеют разные контракты.

Настройки mb_* действуют в текущем запросе/процессе. В долгоживущем worker их может увидеть следующая задача; временное изменение оборачивают try/finally и восстанавливают. Это не передача настроек между отдельными HTTP-запросами. В книге примеры исполняются отдельно; отправка почты и реальные HTTP-заголовки отмечены как контекстные, не как подтверждённая доставка.

Какие настройки меняют смысл текста

Рабочая исходная договорённость для нового сайта: PHP-файлы и входной JSON в UTF-8, кодировка подключения БД задана явно, ответы помечены правильным Content-Type. Автоматическое перекодирование всего входа оставляют выключенным. Изменить название кодировки без преобразования байтов — всё равно что сменить подпись на коробке: содержимое останется прежним.

INI: значение по документацииГде меняетсяНазначение и граница
mbstring.language = neutralINI_ALLЯзыковой профиль, прежде всего для почты; не переводит текст и не задаёт локаль регистровых операций
mbstring.detect_order = NULLINI_ALLКандидаты определения; null использует профиль. Порядок не гарантирует выбор первого допустимого с PHP 8.1
mbstring.http_input = passINI_ALL; deprecatedУстаревшая настройка входной кодировки; для нового кода явный договорённый вход
mbstring.http_output = passINI_ALL; deprecatedУстаревшая настройка выхода; сама не равна установке callback буфера
mbstring.internal_encoding = NULLINI_ALL; deprecatedДля нового INI оставить пустой и использовать default_charset; отдельная функция mb_internal_encoding не объявлена устаревшей
mbstring.substitute_character = NULLINI_ALLПодстановка при недопустимых/непредставимых символах; смотреть mb_substitute_character
mbstring.func_overload = 0Исторически INI_SYSTEMDeprecated 7.2, удалена в 8.0; не включать в современную конфигурацию
mbstring.encoding_translation = 0INI_PERDIRПреобразование входных данных до выполнения PHP-кода; ini_set внутри обработчика уже не перепарсит запрос
mbstring.http_output_conv_mimetypes = ^(text/|application/xhtml\+xml)INI_ALLКакие Content-Type подходят для преобразования выходного буфера
mbstring.strict_detection = 0INI_ALLПоведение при отсутствии допустимого кандидата; явный true в mb_detect_encoding нагляднее зависимости от INI
mbstring.regex_stack_limit = 100000INI_ALL; с 7.3.5Предел стека regex; не заменяет безопасную структуру шаблона
mbstring.regex_retry_limit = 1000000INI_ALL; с 7.4Предел повторов regex; требует Oniguruma ≥ 6.8.0

INI_ALL допускает изменение во время исполнения там, где хостинг не ограничил настройку. INI_PERDIR требует конфигурации до запроса: способ зависит от SAPI (.user.ini для соответствующего CGI/FastCGI, php_value в .htaccess только при подходящем модуле Apache). INI_SYSTEM меняется на серверном уровне. Границы php.ini и SAPI. Старые примеры с EUC-JP/SJIS в php.ini описывают целиком согласованный legacy-сайт; переносить отдельные строчки в UTF-8-приложение опасно. Языковой профиль исторически влияет на выбор внутренних настроек, поэтому порядок старых INI-директив также имел значение.

Временная настройка возвращается после задачиСамостоятельный пример
<?php
declare(strict_types=1);

$previous = mb_internal_encoding();
try {
    mb_internal_encoding('UTF-8');
    echo mb_strlen('Заказ'), "\n";
} finally {
    mb_internal_encoding($previous);
}
echo mb_internal_encoding() === $previous ? 'restored' : 'changed';
Ожидаемый результат
5
restored

try выполняет работу, finally выполняется и при исключении. Для одной операции mb_strlen(..., UTF-8) ещё проще: не приходится менять общее состояние.

Кодировка задаёт соответствие байтов и знаков

Импорт известного Windows-1251 файла
  1. Файл пришёл вместе с договорённостью Windows-1251
  2. Сначала ограничить размер и проверить допустимые байты
  3. Преобразовать Windows-1251 → UTF-8 один раз
  4. Работать с UTF-8; хранить исходник отдельно, если нужен аудит импорта

Unicode присваивает знакам кодовые точки U+…; UTF-8, UTF-16 и UTF-32 — способы записать их байтами. Современные Unicode scalar values находятся до U+10FFFF, исключая диапазон суррогатов U+D800–U+DFFF. Историческое описание UCS-4 с 31-битным пространством не разрешает создавать такие «символы Unicode» в современном API. В UTF-16 знак за пределами BMP занимает пару кодовых единиц; UCS-2 такой пары не описывает. BE/LE — порядок байтов многобайтовой единицы.

СемействоКак трактовать
UTF-8Переменная длина; ASCII-совместим. Рекомендуемый договор для нового веб-приложения
UTF-16 / UTF-32; UCS-2 / UCS-4Формы без BE/LE могут учитывать начальный BOM при преобразовании; с BE/LE порядок указан явно. Не вычислять число Unicode-знаков простым делением размера UTF-16 на два
ASCII / ISO-8859-* / Windows-* / KOI8-* / CP866Одинаковые байты за пределами ASCII могут означать разные буквы. Допустимость байтов не доказывает выбор таблицы
EUC-JP, SJIS, ISO-2022-JP и их вариантыРазличаются и схема байтов, и таблицы соответствий; названия не взаимозаменяемы
UTF-7 / UTF7-IMAPСпециализированные исторические форматы; не выбирать вместо UTF-8 для нового HTML
Base64 / QPrint / UUencode / HTML-ENTITIESЭто представление байтов/сущностей, а не обычная кодировка текста; применение через mbstring deprecated с 8.2
Импортировать договорённый старый файлСамостоятельный пример
<?php
declare(strict_types=1);

$source = "\xCC\xE8\xF0";
if (!mb_check_encoding($source, 'Windows-1251')) {
    throw new RuntimeException('Неверный вход');
}
$title = mb_convert_encoding($source, 'UTF-8', 'Windows-1251');
echo $title, "\n", mb_strlen($title, 'UTF-8');
Ожидаемый результат
Мир
3

Байты записаны явно, поэтому пример не зависит от кодировки редактора. Проверка не доказывает, что файл действительно Windows-1251: это известно из договора с источником. Нельзя заменить такую договорённость бесконечным перебором кодировок.

BOM — маркер определённого формата, а не мусор в любом месте строки. Удалять известный UTF-8 BOM можно только в начале соответствующего файла; trim не предназначен для универсального исправления неизвестных байтов. UTF-8 допускает многие визуально похожие знаки: ни успешная проверка, ни перевод в нижний регистр не защищают от подмены идентификатора. Для входного JSON сначала проверяют размер и кодировку, затем структуру и прикладные поля.

Полный каталог имён: поддержка и назначение

Ниже сохранены семейства и варианты из официального списка; конкретная сборка сообщает свой каталог через mb_list_encodings, а синонимы — через mb_encoding_aliases. Псевдоним — второе имя той же таблицы, не доказательство совместимости разных таблиц. Возможности regex уже возможностей преобразования; например UTF-7/ISO-2022-JP не следует автоматически переносить в mb_regex_encoding.

ГруппаИмена и специальные варианты
Unicode и фиксированные единицыUCS-4, UCS-4BE, UCS-4LE; UCS-2, UCS-2BE, UCS-2LE; UTF-32, UTF-32BE, UTF-32LE; UTF-16, UTF-16BE, UTF-16LE; UTF-7, UTF7-IMAP, UTF-8; byte2be, byte2le, byte4be, byte4le
Японские таблицыEUC-JP, SJIS, eucJP-win, SJIS-win, ISO-2022-JP, ISO-2022-JP-MS, CP932, CP51932, SJIS-mac (MacJapanese), JIS, JIS-ms, CP50220, CP50220raw, CP50221, CP50222
Японские мобильные legacy-таблицыSJIS-Mobile#DOCOMO (SJIS-DOCOMO); SJIS-Mobile#KDDI (SJIS-KDDI); SJIS-Mobile#SOFTBANK (SJIS-SOFTBANK); UTF-8-Mobile#DOCOMO (UTF-8-DOCOMO); UTF-8-Mobile#KDDI-A; UTF-8-Mobile#KDDI-B (UTF-8-KDDI); UTF-8-Mobile#SOFTBANK (UTF-8-SOFTBANK); ISO-2022-JP-MOBILE#KDDI (ISO-2022-JP-KDDI)
ASCII и ISOASCII; ISO-8859-1, -2, -3, -4, -5, -6, -7, -8, -9, -10, -13, -14, -15, -16
Китайские / корейскиеEUC-CN, CP936, GB18030, HZ, EUC-TW, CP950, BIG-5; EUC-KR, UHC (CP949), ISO-2022-KR
Другие региональныеWindows-1251 (CP1251), Windows-1252 (CP1252), CP866 (IBM866), KOI8-R, KOI8-U, ArmSCII-8 (ArmSCII8)
Исторические нетекстовые именаBASE64, HTML-ENTITIES (HTML), 7bit, 8bit; runtime-каталог также может содержать UUENCODE и Quoted-Printable. Наличие имени не делает его современным рекомендуемым API

В официальном перечне для regex отмечены UCS-4/UCS-4LE; UTF-32 и его BE/LE, UTF-16 и его BE/LE; UTF-8, ASCII, EUC-JP, SJIS, eucJP-win, SJIS-win; перечисленные ISO-8859; EUC-CN, EUC-TW, BIG-5, EUC-KR, KOI8-R/KOI8-U. Это не обещание, что произвольный alias/новое имя примет каждая сборка: mb_regex_encoding проверяет свой поддерживаемый набор.

auto в списках кандидатов разворачивается в набор языкового профиля, например Japanese: ASCII, JIS, UTF-8, EUC-JP, SJIS. Это не универсальная кодировка, которую нужно передавать любому параметру encoding: mb_strlen(..., auto) не является способом распознать вход. pass в поддерживающих его настройках означает отсутствие преобразования; это не текстовая таблица. Кандидаты определяют допустимую область угадывания, а не происхождение данных.

Японский импорт: ширина, kana и таблица CP932

Zen-kaku обозначает широкие, han-kaku — узкие формы. Их вид зависит от шрифта; ширина на экране и количество байтов не совпадают. В японском legacy-обмене один знак мог занимать до нескольких байтов, а ISO-2022 использует переключающие escape-последовательности. Нельзя считать, что «японская буква всегда два байта» или что одна смена ширины исправит файл.

SJIS/Shift_JIS по стандартной таблице отличается от Windows CP932; для Windows-данных используется договорённый SJIS-win/CP932. Аналогично EUC-JP и eucJP-win различаются расширениями IBM/NEC. Сначала выясняют таблицу источника, затем меняют представление. Старые i-mode/EZweb и мобильные emoji имели собственные таблицы: поддержка нужна для миграции архива, а не как рекомендация строить новый сайт на Shift_JIS. Исторический совет ISO-2022-JP для SMTP отражает совместимость старых клиентов; современный формат письма согласуют с используемой библиотекой и транспортом.

Сначала разделить байтовый формат, потом преобразоватьСамостоятельный пример
<?php
declare(strict_types=1);

$record = "01" . mb_convert_encoding('東京', 'SJIS-win', 'UTF-8') . "07";
$cityBytes = substr($record, 2, 4);
$city = mb_convert_encoding($cityBytes, 'UTF-8', 'SJIS-win');
echo $city, "\n", substr($record, 6, 2), "\n";
echo strlen($cityBytes), ' -> ', strlen($city);
Ожидаемый результат
東京
07
4 -> 6

В учебной схеме город занимает строго четыре байта SJIS-win и поле заканчивается на границе знака. Смещение следующего поля 6 относится к исходному record. Если сначала преобразовать всю запись в UTF-8, старое смещение уже неверно. Для реального файла нужна его спецификация, а не подбор чисел по одному образцу.

Преобразование kana mb_convert_kana полезно для согласованного поиска адресов/наименований, но сохраните оригинальное отображаемое имя. Широкие цифры, латиница, пробел, хирагана, катакана и знак озвончения требуют разных флагов; функция не является общей транслитерацией японского текста.

Режимы Unicode: обычное преобразование и simple

КонстантыКонтракт
MB_CASE_UPPER / LOWER / TITLEВерхний, нижний и начальный регистр слов; полные отображения могут увеличить число кодовых точек
MB_CASE_FOLD (с 7.3)Сведение регистра для сравнения; это не красивый текст для вывода
MB_CASE_UPPER_SIMPLE / LOWER_SIMPLE / TITLE_SIMPLE / FOLD_SIMPLE (с 7.3)Простое отображение без расширения в несколько кодовых точек. Сохранение количества точек не равно сохранению числа UTF-8 байтов
MB_ONIGURUMA_VERSION (с 7.4)Строка версии regex-библиотеки, когда соответствующая возможность собрана
MB_OVERLOAD_MAIL / STRING / REGEXИсторические биты 1/2/4; удалены с PHP 8.0 вместе с перегрузкой
Изменение регистра может менять длинуСамостоятельный пример
<?php
declare(strict_types=1);

$word = 'Straße';
echo mb_convert_case($word, MB_CASE_UPPER, 'UTF-8'), "\n";
echo mb_convert_case($word, MB_CASE_UPPER_SIMPLE, 'UTF-8'), "\n";
echo mb_convert_case($word, MB_CASE_FOLD, 'UTF-8');
Ожидаемый результат
STRASSE
STRAßE
strasse

Полное uppercase расширяет ß в SS; simple сохраняет одну кодовую точку. Это правило Unicode, не ошибка UTF-8. Для конкретного печатного стандарта организации может потребоваться отдельное явно документированное правило, а не глобальная замена символов.

mbstring использует Unicode-данные версии 16.0 в PHP 8.4 и 17.0 в PHP 8.5. Изменения таблиц влияют на новые знаки и правила, поэтому сохранённые ключи поиска нельзя бездумно считать вечными между версиями. Смена регистра не является Unicode-нормализацией, языковой сортировкой или удалением диакритики.

HTTP: где именно происходит преобразование

Вход и выход не одно и то же
  1. Входные байты запроса → SAPI разбирает форму
  2. Если заранее включён входной фильтр, он преобразует значения до пользовательского кода
  3. PHP проверяет типы/значения массива; это отдельная защита формы
  4. На выходе установленный output handler может преобразовать буфер согласно кодировке и MIME-типу

mbstring.encoding_translation может преобразовывать значения GET/POST/cookie и имена загруженных файлов multipart; имена ключей запроса этим механизмом не преобразуются. PHP-файл уже не управляет тем, как была разобрана форма. В новом JSON API обычно читают ожидаемый UTF-8 явно; изменение INI-фильтра не исправляет повреждённый JSON и не заменяет проверку схемы.

Для выходного преобразования нужны согласованные internal encoding, mb_http_output и зарегистрированный ob_start('mb_output_handler') либо серверный output_handler. Одно mb_http_output не перехватывает echo. Фильтр учитывает Content-Type и mbstring.http_output_conv_mimetypes; бинарный файл не должен проходить текстовую конверсию. Заголовки отправляют до тела. Двойное преобразование вручную и в буфере портит данные.

Удобнее хранить и выводить UTF-8 без скрытой конверсии. Legacy-клиент, которому действительно требуется Windows-1251, — отдельный пограничный маршрут с явным контрактом. Тело, HTTP-заголовок charset и байтовая длина должны согласоваться. Безопасная форма также требует метода запроса, CSRF при cookie-аутентификации, проверки каждого поля и контекстного экранирования: полный приём формы.

Исходный PHP-файл и удалённая перегрузка функций

Кодировка исходника — ещё один слой. Для обычного PHP-файла используйте UTF-8 без BOM. Старое правило книги требует ASCII-совместимых управляющих диапазонов и отсутствия конфликтов многобайтовых хвостов с синтаксисом PHP; JIS/ISO-2022-JP, SJIS, BIG5 и некоторые региональные таблицы в исходнике создавали проблемы разбора. Поддержка этих кодировок как данных не означает, что в них следует сохранять PHP-код. mb_internal_encoding не перенастраивает лексер автоматически.

В старом PHP mbstring.func_overload мог незаметно заменить mail на mb_send_mail (бит 1), строковые функции (бит 2) и исторические regex (бит 4); 7 объединяло биты. Это deprecated с 7.2 и удалено с 8.0. Старые советы о перегрузке по каталогу были особенно ненадёжны. В PHP 8 strlen всегда имеет свой байтовый смысл: новое приложение вызывает нужную функцию явно.

Старые подменяемые функцииЯвная замена, если нужна именно такая семантика
strlen, substr, substr_countmb_strlen, mb_substr, mb_substr_count
strpos, strrpos, stripos, strriposmb_strpos, mb_strrpos, mb_stripos, mb_strripos
strstr, stristr, strrchrmb_strstr, mb_stristr, mb_strrchr
strtolower, strtoupper; mailmb_strtolower, mb_strtoupper; mb_send_mail

Не переписывайте весь проект механически: подпись запроса, длина бинарного пакета и лимит байтов должны остаться байтовыми. Для старой базы согласуйте кодировку соединения и хранимых данных; даже автоматическая конверсия драйвера не исправит ошибочную исходную метку. Универсальная «перекодировка до тех пор, пока выглядит нормально» теряет информацию.

Regex mbstring: шаблон, результат и общий курсор

Регулярное выражение описывает форму текста: [0-9]+ означает одну или несколько цифр, круглые скобки захватывают часть, ^ и $ ограничивают края по выбранному режиму. Здесь используется Oniguruma; у preg_* другой API и синтаксические настройки. Шаблон mb_ereg не обрамляют разделителями /…/u. Для обычной подстроки сначала рассмотрите mb_strpos, для фиксированного разделителя — explode.

Два способа поиска
  1. mb_ereg(pattern, text, matches) получает текст в каждом вызове
  2. mb_ereg_search_init(text, pattern) сохраняет один общий текст и курсор
  3. search/search_pos/search_regs ищут дальше и передвигают этот курсор
  4. getregs/getpos только читают результат/позицию; новый init заменит чужой поиск

У последовательного поиска позиции в байтах, у mb_strpos — в кодовых точках. Не передавайте их друг другу. Вложенная функция, которая вызовет mb_ereg_search_init, затрёт внешнее состояние: для независимых разборов удобнее явные аргументы или свой объект парсера. Предпочитайте шаблоны с непустым совпадением, ограничивайте вход и число извлечений; пустые совпадения и катастрофический backtracking требуют отдельной проверки, не бесконечного while.

Неверный шаблон обычно выдаёт E_WARNING и false; в заменах некорректные байты дают null. false нельзя всегда читать как «такого текста нет», если перед ним была ошибка компиляции/ресурсного предела. Ошибки callback не исчезают. Не подставляйте внешний текст как готовый шаблон и никогда не используйте исторический eval-флаг e: он удалён в PHP 8.0.

Найти нужную функцию и выбрать соседний инструмент

ФункцияКогда нужна
mb_check_encodingПоставщик обещает UTF-8, но в названии товара иногда приходит повреждённый байт. До поиска, записи и вывода нужно понять, соответствует ли строка этой договорённости. mb_check_encoding возвращает ответ да/нет; далее программа либо принимает данные, либо показывает причину отказа. Функция не восстанавливает испорченную букву.
mb_chrВ таблице интеграции символ указан числом Unicode, например 8364 для евро. mb_chr создаёт из такого числа настоящую строку в нужной кодировке. Её можно включить в подпись цены или диагностическое сообщение.
mb_convert_caseУ преобразования регистра несколько разных задач: вывести заголовок, подготовить этикетку или сравнить два написания без регистра. mb_convert_case позволяет явно выбрать правило. Для сравнения Straße и STRASSE нужен полный case folding, а не простое приведение к строчным буквам.
mb_convert_encodingСтарая складская программа выгружает названия в Windows-1251, а сайт работает в UTF-8. Слова должны остаться теми же, но последовательность байтов изменится. mb_convert_encoding получает исходные байты, кодировку назначения и известную кодировку источника. На выходе — новая строка или массив, с которыми уже можно работать в кодировке сайта.
mb_convert_kanaЯпонский поставщик прислал артикул широкими символами AB12, а каталог хранит AB12. mb_convert_kana умеет согласованно менять ширину выбранных знаков и формы kana. Это помогает сопоставить данные по заранее выбранному правилу, сохраняя исходное написание.
mb_convert_variablesСтарый модуль отдаёт несколько связанных полей в одной кодировке и ожидает, что они будут изменены на месте. mb_convert_variables перекодирует переданные переменные по ссылке. Возвращаемое значение сообщает исходную кодировку; сами новые строки надо читать из тех переменных, которые передали.
mb_decode_mimeheaderПри импорте письма тема выглядит как =?UTF-8?B?...?=. Человеку нужно название, а не транспортная упаковка. mb_decode_mimeheader раскрывает encoded-word и возвращает текст в mb_internal_encoding. Она не разбирает вложения и не декодирует автоматически тело MIME-письма.
mb_decode_numericentityПартнёр передал знак евро в виде числовой HTML-ссылки, а отчёту нужна обычная UTF-8-строка. mb_decode_numericentity раскрывает ссылки только в выбранных диапазонах. После декодирования строка остаётся внешними данными и требует правил своего назначения.
mb_detect_encodingФайл пришёл без метки кодировки. Детектор может предложить кандидата из заданного списка, но не знает, что автор файла имел в виду. Поэтому сначала ищут договорённость с источником; автоматическую гипотезу используют для предпросмотра и подтверждения импорта, а не как доказательство правильного текста.
mb_detect_orderСтарый компонент вызывает mb_detect_encoding без списка кандидатов. mb_detect_order позволяет задать, какие таблицы он будет рассматривать по умолчанию. Это настройка детектора, а не команда перекодирования и не доказательство происхождения файла.
mb_encode_mimeheaderВ почтовом списке человек должен увидеть «Кисть», хотя транспортный заголовок содержит специальную ASCII-запись. mb_encode_mimeheader кодирует значение заголовка по MIME. Она не создаёт целое письмо и не отправляет его. Сначала получим одну строку Subject, затем сохраним собственный order.eml.
mb_encode_numericentityИногда текстовый формат требует представить выбранные Unicode-знаки числовыми HTML-ссылками. Например, евро можно записать как € или €. Функция создаёт это представление по карте диапазонов; само по себе оно не является универсальным HTML-экранированием.
mb_encoding_aliasesВ настройке поставщика написано CP1251, а в вашем профиле — Windows-1251. Aliases помогают разобраться, являются ли это два имени одной таблицы. Это полезно при настройке интеграции; разные похожие кодировки нельзя объявлять одинаковыми только по названию.
mb_eregВ уведомлении поставщика есть номер заказа внутри текста: «Заказ 42 готов». mb_ereg ищет фрагмент по шаблону и возвращает захваченные части через отдельную переменную. Регистр букв по умолчанию важен; для варианта без регистра есть mb_eregi.
mb_ereg_matchПеред поиском товара нужно принять артикул определённого вида: две латинские буквы, дефис, две цифры. mb_ereg_match начинает проверку с начала строки, но конец следует указать явно. Иначе правильный префикс может скрыть лишний текст.
mb_ereg_replaceРедактору нужно привести подписи заказов к новому формату, сохранив номера. Замена по шаблону находит подпись и захватывает число, затем вставляет его в новый текст. mb_ereg_replace учитывает регистр, если явно не выбраны другие опции.
mb_ereg_replace_callbackТекст уведомления содержит метки {{товар}} и {{город}}, а значения уже получены из заказа. Callback получает каждое найденное совпадение и возвращает подходящую подстановку. Так обычная PHP-функция участвует в построении текста без eval и без ручного поиска каждого места.
mb_ereg_searchТекст и шаблон уже подготовлены через init. mb_ereg_search передвигается к следующему совпадению и сообщает, найдено ли оно. Сам найденный номер читают отдельной функцией getregs; когда больше номеров нет, цикл заканчивается.
mb_ereg_search_getposПарсер уже прочитал один номер. Чтобы временно заглянуть вперёд и затем вернуться, нужно сохранить текущую позицию. getpos возвращает байтовый курсор следующего поиска, не изменяя его и не извлекая новый номер.
mb_ereg_search_getregsНайденный номер нужен и для подписи, и для следующего шага обработки. getregs читает группы последнего совпадения повторно, не переходя к следующему. Этим он отличается от search_regs, который сразу выполняет новый поиск.
mb_ereg_search_initНужно последовательно извлечь номера из длинного уведомления, а не искать всё заново с начала. init сохраняет текст и шаблон для семейства mb_ereg_search_*. Это только подготовка: результат появится при следующем поисковом вызове.
mb_ereg_search_posКроме самого номера бывает нужно знать его место в исходном тексте: для разбора протокола, отметки проблемного участка или последующей замены. search_pos возвращает байтовое начало и длину следующего совпадения. Эти числа можно передать substr для той же неизменённой строки.
mb_ereg_search_regsУведомление содержит пары «заказ — состояние». search_regs за один вызов находит следующую пару и возвращает группы: номер отдельно, состояние отдельно. Так текст можно превратить в обычные записи массива, которые дальше удобно перебирать.
mb_ereg_search_setposПосле предварительного просмотра следующего номера нужно обработать его ещё раз. setpos возвращает курсор на сохранённую байтовую границу. Сам setter не ищет совпадение: результат появится только при следующем search-вызове.
mb_eregiВ уведомлении поставщика есть номер заказа внутри текста: «ЗАКАЗ 42 готов». mb_eregi ищет фрагмент по шаблону и возвращает захваченные части через отдельную переменную. Регистр подписи при этом не важен.
mb_eregi_replaceРедактору нужно привести подписи заказов к новому формату, сохранив номера. Замена по шаблону находит подпись и захватывает число, затем вставляет его в новый текст. mb_eregi_replace принимает разные регистры подписи.
mb_get_infoНа одном сервере письмо читается, на другом получается нечитаемая тема. Для диагностики нужны конкретные значения настройки mbstring: внутренняя кодировка, почтовый charset и способ упаковки. mb_get_info показывает их без огромной страницы phpinfo.
mb_http_inputНа страницу пришёл товар «Молоток». Нужно узнать, участвовал ли входной конвертер mbstring, и одновременно увидеть сами данные. mb_http_input читает состояние обработанного типа входа; она не возвращает содержимое формы и не определяет заново кодировку произвольной строки. Здесь согласован UTF-8, автоматическая конверсия выключена.
mb_http_outputЧитатель старой складской программы должен получить понятную строку «Молоток — 8 шт.». Задаёт желаемую выходную кодировку mbstring. Сам вызов не меняет уже существующие строки: нужен обработчик выходного буфера. Прежде чем подключать его к старому клиенту, сравним два настоящих ответа.
mb_internal_encodingУзнать или задать default для текстовых mb-функций.
mb_languageВыбрать языковой профиль кодирования почты, а не язык пользовательского интерфейса.
mb_lcfirstЕсть готовая подпись «Заказ готов», которую надо включить после слова «Статус:». mb_lcfirst делает строчной только первую кодовую точку: остальное написание остаётся как было. Это удобно для заранее подготовленных фраз, но не является редактором произвольного текста.
mb_list_encodingsФорма импорта предлагает UTF-8 и старый Windows-1251. Перед обработкой нужно убедиться, что установленная сборка PHP поддерживает выбранные таблицы. mb_list_encodings возвращает каталог имён; из него приложение выбирает только форматы, которые действительно обещает обработать.
mb_ltrimПосле копирования названия из документа вокруг слова остаются неразрывные пробелы. mb_ltrim убирает выбранные знаки слева, сохраняя содержимое поля. Сначала увидим границы строки в квадратных скобках, затем подготовим название для карточки товара. Это осмысленная обработка текстового поля; пароли и подписанные данные так менять нельзя.
mb_ordНазвание выглядит нормально, но сравнение не проходит: в начале может стоять не обычный пробел, а NBSP. mb_ord возвращает числовой код первого символа. Это позволяет объяснить различие, которое на экране почти незаметно.
mb_output_handlerЧитатель старой складской программы должен получить понятную строку «Молоток — 8 шт.». Преобразует вывод только как зарегистрированный обработчик буфера. Сначала увидим режим pass: PHP собирает текст и передаёт его без изменения кодировки. Затем включим конверсию для старого клиента.
mb_parse_strПартнёр передал поля как строку product=...&stock=... . Требуется получить название, остаток и список меток, а затем проверить данные. mb_parse_str разбирает URL-encoded запись по правилам PHP и настроенного входного профиля; это не разбор JSON и не подтверждение корректности товара.
mb_preferred_mime_nameПолучить имя charset для протокольной метки.
mb_regex_encodingВ старом приложении используются mb_ereg и другие функции Oniguruma. Чтобы русский шаблон находил русское название, движок должен одинаково читать шаблон и текст. mb_regex_encoding задаёт именно эту настройку; кодировка обычных mb-строк хранится отдельно.
mb_regex_set_optionsОдин и тот же шаблон должен либо учитывать регистр, либо принимать «заказ» и «ЗАКАЗ». Опции задают это поведение и выбранный синтаксис mbregex. Они не совпадают с привычными флагами preg_match; особенно различается смысл m.
mb_rtrimПосле копирования названия из документа вокруг слова остаются неразрывные пробелы. mb_rtrim убирает выбранные знаки справа, сохраняя содержимое поля. Сначала увидим границы строки в квадратных скобках, затем подготовим название для карточки товара. Это осмысленная обработка текстового поля; пароли и подписанные данные так менять нельзя.
mb_scrubВ диагностическом сообщении повреждён один байт, из-за чего дальнейшая Unicode-обработка ломается. mb_scrub заменяет недопустимые последовательности выбранным знаком. Так можно показать место повреждения в техническом отчёте; восстановить исходную букву эта функция не может.
mb_send_mailНужно подготовить уведомление «Заказ 42: Кисть» и убедиться, какие тему и тело получил почтовый транспорт. В этом опыте транспорт — свой Python-приёмник на 127.0.0.1; он только сохраняет файл и не пересылает письмо. mb_send_mail выполняет MIME-кодирование по mb_language, затем передаёт результат почтовой подсистеме PHP.
mb_splitВ простом списке категорий пользователь может поставить запятую или точку с запятой. mb_split разбивает текст по regex-разделителю и возвращает массив. Когда разделитель один и буквально известен, достаточно explode; CSV с кавычками требует отдельного парсера.
mb_str_padВ текстовом списке нужно дополнить русское название до восьми кодовых точек, чтобы после него поставить разделитель. Обычная str_pad считает байты; mb_str_pad работает с кодовыми точками и добавляет указанное заполнение слева, справа или с двух сторон.
mb_str_splitДля подсказки в учебной игре или диагностики текста нужно пройти по отдельным буквам русского слова. mb_str_split создаёт массив групп кодовых точек. Он не ищет разделитель, как explode: размер каждой группы задаётся числом.
mb_strcutСтарое устройство принимает подпись максимум в девять байтов, а название хранится в UTF-8. mb_substr ограничивает символы, поэтому здесь нужен mb_strcut: он соблюдает байтовую границу, не оставляя половину многобайтового знака. Обрезка допустима только если это разрешает задача.
mb_strimwidthКолонка простого отчёта допускает шесть условных единиц ширины. Длинную подпись нужно сократить и показать две точки. mb_strimwidth учитывает и ширину знаков, и место маркера внутри общего бюджета.
mb_striposВ текстовой заметке нужно найти первое упоминание метки и получить его позицию. mb_stripos считает кодовые точки, поэтому ответ можно передать в mb_substr. Регистр Unicode-букв при поиске не учитывается.
mb_stristrВ подписи категории или простой служебной заметке нужно сразу получить часть текста до либо от первого совпадения. mb_stristr возвращает сам фрагмент, поэтому отдельное вычисление позиции не требуется. Поиск не зависит от регистра Unicode-букв.
mb_strlenФорма разрешает название длиной до десяти символов. Для русского UTF-8-текста strlen посчитает байты, и короткое слово ошибочно покажется слишком длинным. mb_strlen считает кодовые точки: для обычного слова «Кисть» это пять букв. Составные видимые знаки требуют отдельного понятия графемы.
mb_strposВ текстовой заметке нужно найти первое упоминание метки и получить его позицию. mb_strpos считает кодовые точки, поэтому ответ можно передать в mb_substr. Регистр букв учитывается: Кисть и кисть различаются.
mb_strrchrВ подписи категории или простой служебной заметке нужно сразу получить часть текста до либо от последнего совпадения. mb_strrchr возвращает сам фрагмент, поэтому отдельное вычисление позиции не требуется. Поиск учитывает регистр букв.
mb_strrichrВ подписи категории или простой служебной заметке нужно сразу получить часть текста до либо от последнего совпадения. mb_strrichr возвращает сам фрагмент, поэтому отдельное вычисление позиции не требуется. Поиск не зависит от регистра Unicode-букв.
mb_strriposВ текстовой заметке нужно найти последнее упоминание метки и получить его позицию. mb_strripos считает кодовые точки, поэтому ответ можно передать в mb_substr. Регистр Unicode-букв при поиске не учитывается.
mb_strrposВ текстовой заметке нужно найти последнее упоминание метки и получить его позицию. mb_strrpos считает кодовые точки, поэтому ответ можно передать в mb_substr. Регистр букв учитывается: Кисть и кисть различаются.
mb_strstrВ подписи категории или простой служебной заметке нужно сразу получить часть текста до либо от первого совпадения. mb_strstr возвращает сам фрагмент, поэтому отдельное вычисление позиции не требуется. Поиск учитывает регистр букв.
mb_strtolowerВ поисковом поле покупатель написал «КИСТЬ», а товар называется «Кисть». Для простого русского поиска можно сравнить копии в нижнем регистре и вывести исходное название. mb_strtolower понимает Unicode-буквы; обычная strtolower для этой задачи с кириллицей не подходит.
mb_strtoupperНужно напечатать крупную подпись на складской этикетке: «Кисть» превращается в «КИСТЬ». При этом некоторые Unicode-буквы разворачиваются в несколько букв, поэтому размер готовой подписи проверяют после преобразования.
mb_strwidthВ простом текстовом отчёте есть латиница и японские названия. Две кодовые точки могут занимать разные условные ширины: AB считается как 2, 東京 — как 4. mb_strwidth помогает рассчитывать такую колонку, но не измеряет пиксели страницы.
mb_substitute_characterПри преобразовании строки встречается символ, которого нет в целевой кодировке. Настройка mb_substitute_character определяет, будет ли виден знак замены, код потерянного символа или вообще ничего. От этого зависит, заметит ли человек повреждение; исходную информацию подстановка не сохраняет.
mb_substrНужно получить короткое превью русского названия, не обрывая UTF-8-букву посередине. mb_substr выбирает часть по позициям кодовых точек. Сначала возьмём слово из известной строки, затем добавим многоточие только там, где название действительно сокращено.
mb_substr_countПеред сборкой уведомления нужно узнать, сколько раз шаблон использует метку номера заказа. mb_substr_count считает неперекрывающиеся вхождения буквальной подстроки. Это не число слов и не поиск по регулярному выражению.
mb_trimПосле копирования названия из документа вокруг слова остаются неразрывные пробелы. mb_trim убирает выбранные знаки с обоих краёв, сохраняя содержимое поля. Сначала увидим границы строки в квадратных скобках, затем подготовим название для карточки товара. Это осмысленная обработка текстового поля; пароли и подписанные данные так менять нельзя.
mb_ucfirstСоставленная подпись начинается со строчной буквы: «заказ готов». mb_ucfirst переводит первый знак в начальную форму регистра, сохраняя остальную строку. Для русской буквы это привычная заглавная; для некоторых Unicode-диграфов начальная и полностью верхняя формы различаются.

Упражнение: одно имя для двух потребителей. Из импорта пришла UTF-8 строка «Кружка». Форма принимает максимум 10 кодовых точек; старый протокол разрешает подпись не длиннее 8 байтов. Для этой учебной подписи обрезка разрешена. Сначала отвергните повреждённый UTF-8, затем проверьте правило формы и подготовьте отдельную подпись для протокола, сохранив исходное имя. До запуска предскажите, сколько букв останется. Измените требование: теперь приёмнику нужно полное имя — какая ветка программы должна поменяться?

Предложенное решение. Проверка mb_check_encoding с явным UTF-8 должна вернуть true; mb_strlen даст 6, поэтому правило формы выполнено. mb_strcut с аргументами 0, 8 и UTF-8 вернёт «Круж»: четыре кириллические буквы занимают восемь байтов. Полную строку храним отдельно; после подготовки подписи сверяем strlen с байтовым бюджетом. Если требуется полное имя, вместо обрезки сравниваем исходный байтовый размер 12 с лимитом 8 и возвращаем понятную ошибку. Повторите шаги с составным emoji: проверка кодовых точек не обещает число видимых знаков. Исполняемые варианты этих операций приведены в карточках выше; упражнение проверяет выбор контракта, а не запоминание названия функции.

Регулярные выражения preg_* относятся к PCRE, grapheme_* и Normalizer — к intl, iconv_* — к iconv. Их возможности не включаются установкой mbstring. Для обычного разделителя подходит explode; для точной замены корректной UTF-8 подстроки часто достаточно str_replace. Выбор определяется задачей, а не обязательным префиксом mb_.

Функции и методы этой темы

Откройте карточку, чтобы увидеть договор функции, примеры, ограничения и связанные инструменты.

mb_check_encodingПоставщик обещает UTF-8, но в названии товара иногда приходит повреждённый байт. До поиска, записи и вывода нужно понять, соответствует ли строка этой договорённости. mb_check_encoding возвращает ответ да/нет; далее программа либо принимает данные, либо показывает причину отказа. Функция не восстанавливает испорченную букву.

PHP 4.4.3 / 5.1.3+ · mbstring

mb_check_encoding(array|string|null $value = null, ?string $encoding = null): bool
Данные до и после вызова
  1. Правильное название Кисть проходит проверку UTF-8.
  2. Байт FF в Ки\xFFсть не является допустимым UTF-8.
  3. Повреждённую строку отклоняем, а не выдаём за исправленное название.
Аргумент / результатЧто передать и получить
valueСтрока либо массив; в массиве рекурсивно проверяются и строковые ключи, и значения. Числа/boolean не превращаются в пользовательский текст.
encoding = nullИмя кодировки исходных байтов. null или пропуск использует текущее mb_internal_encoding(); явное UTF-8 делает локальный пример независимым от чужих настроек. Это не преобразование входа.
returntrue — все проверенные строки допустимы; false — найдены недопустимые байты. Это не определение происхождения текста.
Проверить настоящее название и повреждённую копиюСамостоятельный пример
<?php
$title = 'Кисть';
var_dump(mb_check_encoding($title, 'UTF-8'));
var_dump(mb_check_encoding("Ки\xFFсть", 'UTF-8'));
Ожидаемый результат
bool(true)
bool(false)

var_dump показывает тип bool явно; echo для false вывел бы пустоту. \xFF в двойной строке создаёт один намеренно неправильный байт. Проверка не меняет $title и не сравнивает его с каталогом.

Принять строку импорта или назвать её номер в ошибкеСамостоятельный пример
<?php
$rows = ['Кисть', "Мо\xFFлоток", 'Валик'];
foreach ($rows as $index => $title) {
    if (!mb_check_encoding($title, 'UTF-8')) {
        echo 'Строка ', $index + 1, ": повреждён UTF-8, товар не принят\n";
        continue;
    }
    echo 'Принят товар: ', $title, "\n";
}
Ожидаемый результат
Принят товар: Кисть
Строка 2: повреждён UTF-8, товар не принят
Принят товар: Валик

Нумерация для человека начинается с единицы. continue пропускает обработку повреждённого значения и переходит к следующему. Это проверка локального массива до реальной записи в базу. Название всё ещё проверяют по длине и правилам каталога; корректный UTF-8 не означает безопасный HTML.

Проверить вложенные значения и ключи пакетаСамостоятельный пример
<?php
$order = ['customer' => ['name' => 'Анна'], 'quantity' => 2];
echo mb_check_encoding($order, 'UTF-8') ? "Пакет читается как UTF-8\n" : "Повреждён пакет\n";
$order['customer']["note\xFF"] = 'Позвонить';
echo mb_check_encoding($order, 'UTF-8') ? "Пакет читается как UTF-8\n" : "Повреждён ключ или значение\n";
Ожидаемый результат
Пакет читается как UTF-8
Повреждён ключ или значение

Массив проверяется рекурсивно, включая строковые ключи. Функция не сообщает путь к плохому элементу: для подробного отчёта нужен собственный обход. Размер и глубину внешнего пакета ограничивают до обработки. Число quantity остаётся числом; проверка кодировки не проверяет схему заказа.

Ошибки и границы. Массивы поддерживаются с 7.2; пропуск value или null deprecated с 8.1 (старое значение означало проверку входа запроса). Передавайте конкретные данные. encoding nullable с 8.0; неизвестная кодировка — ValueError. Состоящий из ASCII текст допустим во многих кодировках; true не выбирает одну из них.

Рядом: mb_detect_encoding, mb_scrub, mb_convert_encoding. Байты, кодовые точки и графемы; общие правила вызова.

mb_detect_encodingФайл пришёл без метки кодировки. Детектор может предложить кандидата из заданного списка, но не знает, что автор файла имел в виду. Поэтому сначала ищут договорённость с источником; автоматическую гипотезу используют для предпросмотра и подтверждения импорта, а не как доказательство правильного текста.

PHP 4.0.6+ · mbstring

mb_detect_encoding(string $string, array|string|null $encodings = null, bool $strict = false): string|false
Данные до и после вызова
  1. Байты сравниваются с разрешёнными таблицами.
  2. Несколько таблиц могут принять одну последовательность.
  3. Известная метка источника надёжнее удачной на вид гипотезы.
Аргумент / результатЧто передать и получить
stringИсследуемые байты; короткая строка даёт особенно мало информации.
encodingsМассив имён или список через запятую; null/пропуск использует mb_detect_order. auto разворачивает языковой набор.
stricttrue возвращает false, если ни один кандидат не допускает вход; false может выбрать ближайший даже для некорректной строки. Значение при пропуске также связано с mbstring.strict_detection.
returnКаноническое имя предполагаемой кодировки либо false; это не процент уверенности.
Проверить один разрешённый вариантСамостоятельный пример
<?php
$encoding = mb_detect_encoding('Кисть', ['UTF-8'], true);
echo 'Кандидат: ', $encoding, "\n";
$broken = mb_detect_encoding("\xFF", ['UTF-8'], true);
echo $broken === false ? "UTF-8 не подходит\n" : $broken;
Ожидаемый результат
Кандидат: UTF-8
UTF-8 не подходит

true включает строгую проверку допустимости байтов. При одном кандидате понятен смысл опыта: это не угадывание языка. Для простой проверки известного UTF-8 короче использовать mb_check_encoding.

Увидеть два разных чтения одних и тех же байтовСамостоятельный пример
<?php
$bytes = "\xC4\xA2";
foreach (['UTF-8', 'Windows-1252'] as $encoding) {
    if (mb_check_encoding($bytes, $encoding)) {
        echo $encoding, ': ', mb_convert_encoding($bytes, 'UTF-8', $encoding), "\n";
    }
}
$candidate = mb_detect_encoding($bytes, ['UTF-8', 'Windows-1252'], true);
echo $candidate === false ? "Нет кандидата\n" : "Есть гипотеза; источник ещё неизвестен\n";
Ожидаемый результат
UTF-8: Ģ
Windows-1252: Ģ
Есть гипотеза; источник ещё неизвестен

Оба чтения допустимы, а смысл различается. Какой кандидат выберет эвристика, не фиксируем как бизнес-правило. После PHP 8.1 порядок списка не гарантирует выбор первой допустимой таблицы. Сохраняйте исходные байты и профиль импорта; неверную догадку нельзя выдавать за исправление.

Ошибки и границы. С 8.1 эвристика не обязана выбирать первый допустимый кандидат. С 8.2 нетекстовые Base64/QPrint/UUencode/HTML entities/7bit/8bit не являются результатом детектора. Неизвестное имя и пустой список — ValueError. strict=true доказывает допустимость в кандидате, а не правильность языка/смысла.

Рядом: mb_check_encoding, mb_detect_order, mb_convert_encoding. Байты, кодовые точки и графемы; общие правила вызова.

mb_detect_orderСтарый компонент вызывает mb_detect_encoding без списка кандидатов. mb_detect_order позволяет задать, какие таблицы он будет рассматривать по умолчанию. Это настройка детектора, а не команда перекодирования и не доказательство происхождения файла.

PHP 4.0.6+ · mbstring

mb_detect_order(array|string|null $encoding = null): array|bool
Данные до и после вызова
  1. Сохраняем предыдущий список.
  2. На время компонента разрешаем ASCII и UTF-8.
  3. После обработки возвращаем прежнюю настройку; сама строка не изменилась.
Аргумент / результатЧто передать и получить
encodingМассив имён/строка через запятую устанавливает список; null/пропуск читает текущий. auto раскрывается по языковому профилю.
returnПри чтении — упорядоченный массив; при записи — true при успехе (контракт допускает false).
Записать список и прочитать его обратноСамостоятельный пример
<?php
$previous = mb_detect_order();
try {
    mb_detect_order(['ASCII', 'UTF-8']);
    echo 'Кандидаты: ', implode(', ', mb_detect_order()), "\n";
    echo 'Для Кисть получено: ', mb_detect_encoding('Кисть', null, true), "\n";
} finally {
    mb_detect_order($previous);
}
Ожидаемый результат
Кандидаты: ASCII, UTF-8
Для Кисть получено: UTF-8

null во втором аргументе детектора означает использовать default. Русские UTF-8-байты не допускаются ASCII, поэтому в этом ограниченном опыте выбор однозначен. В общем случае несколько таблиц принимают одинаковые байты, и порядок не гарантирует истинность результата.

Выбрать кандидатов для одного вызова без смены общего спискаСамостоятельный пример
<?php
$candidate = mb_detect_encoding('Кисть', ['UTF-8'], true);
if ($candidate === false) {
    echo "Файл не соответствует договорённому UTF-8\n";
} else {
    echo 'Для предпросмотра выбран ', $candidate, ': Кисть', "\n";
}
Ожидаемый результат
Для предпросмотра выбран UTF-8: Кисть

Если управляете самим вызовом, явный список проще общей настройки. mb_detect_order нужен для совместимости с компонентом, который список не передаёт. При известном контракте UTF-8 обычно достаточно mb_check_encoding вместо эвристики.

Ошибки и границы. В PHP 8 неверное имя — ValueError; null разрешён с 8.0. Старый текст страницы о «всегда неверном UTF-16/32» и гарантированном первом совпадении не описывает современный движок: на 8.5.11 UTF-16LE проверяется. Однобайтовые таблицы допускают множество любых последовательностей, поэтому широкий список не улучшает доказательность.

Рядом: mb_detect_encoding, mb_language, mb_internal_encoding. Байты, кодовые точки и графемы; общие правила вызова.

mb_list_encodingsФорма импорта предлагает UTF-8 и старый Windows-1251. Перед обработкой нужно убедиться, что установленная сборка PHP поддерживает выбранные таблицы. mb_list_encodings возвращает каталог имён; из него приложение выбирает только форматы, которые действительно обещает обработать.

PHP 5+ · mbstring

mb_list_encodings(): array
Данные до и после вызова
  1. Расширение возвращает массив поддерживаемых имён.
  2. Приложение пересекает его со своим небольшим списком форматов.
  3. Пользователь видит подходящие варианты импорта, а не все исторические кодировки подряд.
Аргумент / результатЧто передать и получить
ПараметрыНет; результат относится к текущему установленному расширению.
returnМассив строк с числовыми ключами. Набор и порядок не стоит фиксировать как контракт приложения.
Получить доступные форматы выбранного импортаСамостоятельный пример
<?php
$supported = mb_list_encodings();
$wanted = ['UTF-8', 'Windows-1251', 'ASCII'];
$available = array_intersect($wanted, $supported);
foreach ($available as $encoding) {
    echo 'Можно выбрать: ', $encoding, "\n";
}
Ожидаемый результат
Можно выбрать: UTF-8
Можно выбрать: Windows-1251
Можно выбрать: ASCII

$supported — полный массив. array_intersect оставляет только значения, присутствующие в обоих списках; порядок здесь берётся из $wanted. Перечисление ещё не преобразовало ни одного файла. Полный состав сборки можно просмотреть через foreach ($supported as $encoding).

Применить разрешённый профиль к конкретным байтамСамостоятельный пример
<?php
$allowed = ['UTF-8', 'Windows-1251'];
$selected = 'Windows-1251';
if (!in_array($selected, $allowed, true)
    || !in_array($selected, mb_list_encodings(), true)) {
    throw new InvalidArgumentException('Этот профиль импорта недоступен');
}
$bytes = "\xCA\xE8\xF1\xF2\xFC";
echo 'Импортировано название: ', mb_convert_encoding($bytes, 'UTF-8', $selected), "\n";
Ожидаемый результат
Импортировано название: Кисть

Два условия отвечают за разные вещи: разрешение формата вашим приложением и его поддержку PHP. true у in_array включает строгое сравнение. Название кодировки должно соответствовать договорённости с поставщиком; наличие таблицы не доказывает, что именно ею записан файл.

Ошибки и границы. Документация не указывает специальных ошибок корректного вызова без аргументов. Отсутствие самого расширения — Error при попытке вызвать функцию. Список конвертера не равен списку mbregex.

Рядом: mb_encoding_aliases, mb_preferred_mime_name, mb_get_info. Байты, кодовые точки и графемы; общие правила вызова.

mb_encoding_aliasesВ настройке поставщика написано CP1251, а в вашем профиле — Windows-1251. Aliases помогают разобраться, являются ли это два имени одной таблицы. Это полезно при настройке интеграции; разные похожие кодировки нельзя объявлять одинаковыми только по названию.

PHP 5.3+ · mbstring

mb_encoding_aliases(string $encoding): array
Данные до и после вызова
  1. Основное имя UTF-8 имеет известный псевдоним utf8.
  2. Каталог имён позволяет объяснить такое написание в конфигурации.
  3. Перекодирование выполняет другая функция; чтение aliases само текст не меняет.
Аргумент / результатЧто передать и получить
encodingИзвестное имя таблицы, например Windows-1251.
returnМассив alias-строк; может быть пустым. Основное имя не обязано входить в aliases.
Прочитать настоящий массив альтернативных имёнСамостоятельный пример
<?php
$aliases = mb_encoding_aliases('UTF-8');
foreach ($aliases as $alias) {
    echo 'Альтернативное имя: ', $alias, "\n";
}
Ожидаемый результат
Альтернативное имя: utf8

Функция возвращает массив, а не строку через запятую. Основное имя не обязано входить в aliases. Этот результат относится к проверенной сборке; код не должен зависеть от номера конкретного элемента.

Применить известное альтернативное имя из профиляСамостоятельный пример
<?php
$aliases = array_map('strtolower', mb_encoding_aliases('Windows-1251'));
if (in_array('cp1251', $aliases, true)) {
    $bytes = "\xCA\xE8\xF1\xF2\xFC";
    echo 'CP1251 читается как Windows-1251: ', mb_convert_encoding($bytes, 'UTF-8', 'CP1251'), "\n";
}
Ожидаемый результат
CP1251 читается как Windows-1251: Кисть

array_map меняет регистр только ASCII-имён для проверки, не байты файла. Сам список aliases не является разрешением принять любой профиль пользователя: приложение по-прежнему ограничивает доступные форматы.

Отказаться от выдуманного имени до чтения файлаСамостоятельный пример
<?php
try {
    mb_encoding_aliases('vendor-unknown-encoding');
} catch (ValueError $error) {
    echo "Уточните кодировку у поставщика: такой таблицы PHP не знает\n";
}
Ожидаемый результат
Уточните кодировку у поставщика: такой таблицы PHP не знает

Нельзя молча заменить неизвестную таблицу на UTF-8 и объявить импорт успешным. В PHP 8 возникает ValueError; старые версии сообщали warning/false. Широкий catch всех ошибок без объяснения скрыл бы ошибку настройки.

Ошибки и границы. С PHP 8 неизвестное имя вызывает ValueError; раньше были E_WARNING и false. Alias не делает Shift_JIS и CP932 идентичными.

Рядом: mb_list_encodings, mb_preferred_mime_name, mb_convert_encoding. Байты, кодовые точки и графемы; общие правила вызова.

mb_preferred_mime_nameПолучить имя charset для протокольной метки.

PHP 4.0.6+ · mbstring

mb_preferred_mime_name(string $encoding): string|false
Данные до и после вызова
  1. В программе используется alias
  2. Функция возвращает имя для charset
  3. Байты тела всё равно нужно получить в этой кодировке
Аргумент / результатЧто передать и получить
encodingИзвестное mbstring имя кодировки.
returnПредпочтительное MIME-имя; false, если предпочтительного имени нет. Это не уже готовый заголовок.
Преобразовать имя UTF8 в MIME-написаниеСамостоятельный пример
<?php
declare(strict_types=1);

echo mb_preferred_mime_name('utf8');
Ожидаемый результат
UTF-8

Возвращённая строка не меняет ни данные, ни заголовки HTTP.

Согласовать метаданные подготовленного экспортаСамостоятельный пример
<?php
declare(strict_types=1);

$encoding = 'Windows-1251';
$charset = mb_preferred_mime_name($encoding);
if ($charset === false) { throw new RuntimeException('Нет MIME-имени'); }
$body = mb_convert_encoding('Мир', $encoding, 'UTF-8');
echo 'charset=', $charset, "\nbytes=", strlen($body);
Ожидаемый результат
charset=Windows-1251
bytes=3

Это локальная подготовка тела и метки; реальную отправку header() пример не имитирует. Для HTML всё равно нужно контекстное экранирование.

Ошибки и границы. Неизвестное имя в PHP 8.5 вызывает ValueError. false с E_WARNING — другая ситуация, известная таблица без предпочтительного MIME-имени. Не подставляйте произвольную строку пользователя в заголовок.

Рядом: mb_encoding_aliases, mb_http_output, mb_encode_mimeheader. Байты, кодовые точки и графемы; общие правила вызова.

mb_internal_encodingУзнать или задать default для текстовых mb-функций.

PHP 4.0.6+ · mbstring

mb_internal_encoding(?string $encoding = null): string|bool
Данные до и после вызова
  1. Строковые байты уже существуют
  2. Меняется только default для будущих вызовов без encoding
  3. Явный encoding у вызова имеет свой смысл независимо от default
Аргумент / результатЧто передать и получить
encodingИмя устанавливает default; null/пропуск читает его.
returnПри чтении строка; при успешной записи true, контракт включает false.
Текущая настройка влияет на вызов без второго аргументаСамостоятельный пример
<?php
declare(strict_types=1);

$old = mb_internal_encoding();
try {
    mb_internal_encoding('UTF-8');
    echo mb_internal_encoding(), ': ', mb_strlen('Дом');
} finally { mb_internal_encoding($old); }
Ожидаемый результат
UTF-8: 3

Второй аргумент mb_strlen пропущен намеренно, чтобы увидеть default. Для библиотечного кода явная кодировка часто понятнее.

Настройка не преобразует байтыСамостоятельный пример
<?php
declare(strict_types=1);

$bytes = "\xCC\xE8\xF0";
$old = mb_internal_encoding();
try {
    mb_internal_encoding('UTF-8');
    echo bin2hex($bytes), "\n";
    echo mb_convert_encoding($bytes, 'UTF-8', 'Windows-1251');
} finally { mb_internal_encoding($old); }
Ожидаемый результат
cce8f0
Мир

bin2hex показывает исходные байты. Только второй вызов выполняет преобразование с известной исходной таблицей.

Ошибки и границы. Неизвестная кодировка — ValueError с 8.0 (раньше warning/false); null разрешён с 8.0. Эта функция не меняет отдельную regex-кодировку и не перенастраивает соединение БД. Устарела INI-директива mbstring.internal_encoding, а не сама функция.

Рядом: mb_convert_encoding, mb_regex_encoding, mb_get_info. Байты, кодовые точки и графемы; общие правила вызова.

mb_substitute_characterПри преобразовании строки встречается символ, которого нет в целевой кодировке. Настройка mb_substitute_character определяет, будет ли виден знак замены, код потерянного символа или вообще ничего. От этого зависит, заметит ли человек повреждение; исходную информацию подстановка не сохраняет.

PHP 4.0.6+ · mbstring

mb_substitute_character(string|int|null $substitute_character = null): string|int|bool
Данные до и после вызова
  1. Стоимость 5 € нужно выразить в ASCII.
  2. Евро не существует в ASCII.
  3. Выбранный режим даёт 5 ?, 5 U+20AC или 5 без знака валюты — это разные последствия потери.
Аргумент / результатЧто передать и получить
substitute_characterUnicode codepoint числом, например 0xFFFD; либо none (удаление), long (описание кода), entity (числовая сущность). null читает текущую настройку.
returnЧтение: int/строка; запись: true при успехе, контракт включает false.
Увидеть замену непредставимого знакаСамостоятельный пример
<?php
$old = mb_substitute_character();
try {
    mb_substitute_character(ord('?'));
    echo mb_convert_encoding('5 €', 'ASCII', 'UTF-8'), "\n";
} finally {
    mb_substitute_character($old);
}
Ожидаемый результат
5 ?

ord получает числовой код ASCII-знака ?. Настройка действует на последующие преобразования, а не меняет строку сама. После примера прежнее правило возвращается.

Сравнить явный след потери с молчаливым удалениемСамостоятельный пример
<?php
$old = mb_substitute_character();
try {
    foreach (['long', 'entity', 'none'] as $mode) {
        mb_substitute_character($mode);
        echo $mode, ': [', mb_convert_encoding('5 €', 'ASCII', 'UTF-8'), "]\n";
    }
} finally {
    mb_substitute_character($old);
}
Ожидаемый результат
long: [5 U+20AC]
entity: [5 &#x20AC;]
none: [5 ]

Квадратные скобки показывают оставшийся пробел. none удалил сам знак валюты, а entity записал техническую последовательность, которую обычный текстовый приёмник может показать буквально. Для цены правильнее согласовать UTF-8 или явное обозначение EUR, чем молча потерять валюту.

Ошибки и границы. Недопустимый codepoint/строка режима — ValueError. С 8.0 пустая строка не означает удаление: для этого есть none. Настройка влияет также на output handler и почту; не оставляйте её изменённой в worker.

Рядом: mb_scrub, mb_convert_encoding, mb_convert_variables. Байты, кодовые точки и графемы; общие правила вызова.

mb_scrubВ диагностическом сообщении повреждён один байт, из-за чего дальнейшая Unicode-обработка ломается. mb_scrub заменяет недопустимые последовательности выбранным знаком. Так можно показать место повреждения в техническом отчёте; восстановить исходную букву эта функция не может.

PHP 7.2+ · mbstring

mb_scrub(string $string, ?string $encoding = null): string
Данные до и после вызова
  1. Ки\xFFсть содержит байт, не читаемый как UTF-8.
  2. Настройка замены U+FFFD означает видимый знак �.
  3. Результат Ки�сть читается как UTF-8, но исходное название всё ещё потеряно.
Аргумент / результатЧто передать и получить
stringПовреждённые или корректные байты.
encoding = nullИмя кодировки исходных байтов. null или пропуск использует текущее mb_internal_encoding(); явное UTF-8 делает локальный пример независимым от чужих настроек. Это не преобразование входа.
returnНовая строка той же кодировки с подстановками согласно mb_substitute_character.
Показать повреждение вместо молчаливого удаленияСамостоятельный пример
<?php
$old = mb_substitute_character();
try {
    mb_substitute_character(0xFFFD);
    $clean = mb_scrub("Ки\xFFсть", 'UTF-8');
    echo $clean, "\n";
    echo mb_check_encoding($clean, 'UTF-8') ? "Результат имеет допустимые байты\n" : "Ошибка\n";
} finally {
    mb_substitute_character($old);
}
Ожидаемый результат
Ки�сть
Результат имеет допустимые байты

0xFFFD — код знака замены. try/finally здесь сохраняет общую настройку для остального приложения. Допустимость результата не доказывает правильность слова; очищенную копию нельзя считать исходными данными заказа.

Составить понятный отчёт об отклонённой строкеСамостоятельный пример
<?php
$old = mb_substitute_character();
try {
    mb_substitute_character(0xFFFD);
    $raw = "Ки\xFFсть";
    if (!mb_check_encoding($raw, 'UTF-8')) {
        echo 'Строка 7 отклонена. Диагностическая копия: ', mb_scrub($raw, 'UTF-8'), "\n";
        echo 'Исходные байты: ', bin2hex($raw), "\n";
    }
} finally {
    mb_substitute_character($old);
}
Ожидаемый результат
Строка 7 отклонена. Диагностическая копия: Ки�сть
Исходные байты: d09ad0b8ffd181d182d18c

Номер строки помогает попросить поставщика исправить конкретную запись. Пример использует учебное название без секретов. В реальном журнале ограничивают объём и доступ; scrub не скрывает личные данные и не заменяет htmlspecialchars при HTML-выводе.

Ошибки и границы. Неизвестная кодировка — ValueError; nullable encoding с 8.0. Для подписи, пароля, платёжного идентификатора исправление с потерями меняет смысл: такой вход обычно отклоняют.

Рядом: mb_check_encoding, mb_substitute_character, mb_convert_encoding. Байты, кодовые точки и графемы; общие правила вызова.

mb_get_infoНа одном сервере письмо читается, на другом получается нечитаемая тема. Для диагностики нужны конкретные значения настройки mbstring: внутренняя кодировка, почтовый charset и способ упаковки. mb_get_info показывает их без огромной страницы phpinfo.

PHP 4.2+ · mbstring

mb_get_info(string $type = "all"): array|string|int|false|null
Данные до и после вызова
  1. Настройка internal_encoding описывает чтение исходного текста.
  2. mail_charset и mail_header_encoding описывают подготовку заголовка письма.
  3. Снимок помогает сравнить окружения, но сам письмо не отправляет и не исправляет.
Аргумент / результатЧто передать и получить
typeall или пропуск возвращает набор. Отдельные ключи перечислены ниже; это не имя произвольной INI-директивы.
returnМассив при all; значение соответствующего типа при выбранном ключе; false для неизвестного ключа.

Доступны internal_encoding, http_input, http_output, http_output_conv_mimetypes, mail_charset, mail_header_encoding, mail_body_encoding, illegal_chars, encoding_translation, language, detect_order, substitute_character, strict_detection. illegal_chars — счётчик проблем преобразования в данном контексте, не карта повреждённых мест в конкретной строке. Regex-настройку получают отдельно через mb_regex_encoding.

Прочитать одно известное значениеСамостоятельный пример
<?php
$old = mb_internal_encoding();
try {
    mb_internal_encoding('UTF-8');
    echo 'Исходный текст: ', mb_get_info('internal_encoding'), "\n";
} finally {
    mb_internal_encoding($old);
}
Ожидаемый результат
Исходный текст: UTF-8

Строка internal_encoding выбирает конкретное поле. Это чтение информации, а не запись настройки. Настройку перед этим меняет отдельная функция mb_internal_encoding.

Вывести полезные поля диагностического отчётаСамостоятельный пример
<?php
$language = mb_language();
$encoding = mb_internal_encoding();
try {
    mb_language('neutral');
    mb_internal_encoding('UTF-8');
    $info = mb_get_info();
    foreach (['internal_encoding', 'mail_charset', 'mail_header_encoding', 'mail_body_encoding'] as $key) {
        echo $key, ': ', $info[$key], "\n";
    }
} finally {
    mb_language($language);
    mb_internal_encoding($encoding);
}
Ожидаемый результат
internal_encoding: UTF-8
mail_charset: UTF-8
mail_header_encoding: BASE64
mail_body_encoding: BASE64

Это конкретный профиль neutral. На чужом сервере значения могут отличаться, поэтому вывод читают, а не подменяют проверкой наличия ключей. Кодирование заголовка и тела — отдельные поля. Диагностику показывают администратору, а не каждому посетителю сайта.

Ошибки и границы. Неизвестный type возвращает false с E_WARNING. Не отдавайте диагностические настройки публичным endpoint без необходимости: для формы важнее понятная ошибка поля, чем детали сервера.

Рядом: mb_internal_encoding, mb_detect_order, mb_language. Байты, кодовые точки и графемы; общие правила вызова.

mb_languageВыбрать языковой профиль кодирования почты, а не язык пользовательского интерфейса.

PHP 4.0.6+ · mbstring

mb_language(?string $language = null): string|bool
Данные до и после вызова
  1. Почтовый legacy-профиль задаёт charset и переносимое представление
  2. mb_send_mail использует этот профиль
  3. Сам текст не переводится, регистр не становится локалезависимым
Аргумент / результатЧто передать и получить
languageПоддерживаемое имя/alias профиля; null/пропуск читает текущий.
returnСтрока при чтении, true при успешной записи; сигнатура включает false.
Профиль / aliasCharset; кодирование заголовка
German/de/DeutschISO-8859-15; Quoted-Printable
English/enISO-8859-1; Quoted-Printable
Armenian/hyArmSCII-8; Quoted-Printable
Japanese/jaISO-2022-JP; Base64
Korean/koISO-2022-KR; Base64
neutral; uni/universalUTF-8; Base64
Russian/ruKOI8-R; Quoted-Printable
Turkish/trISO-8859-9; Quoted-Printable
Ukrainian/uaKOI8-U; Quoted-Printable
Simplified Chinese/zh-cnHZ; Base64
Traditional Chinese/zh-twBIG-5; Base64

Кодирование заголовка и Content-Transfer-Encoding тела — отдельные настройки профиля. В PHP 8.5.11 Japanese использует Base64 для заголовка, но 7bit для тела; English/Russian — Quoted-Printable для заголовка, 8bit для тела; neutral/uni — Base64 для обоих. Смотрите mb_get_info('mail_header_encoding') и mb_get_info('mail_body_encoding'), а не переносите одну колонку таблицы на всё письмо.

Профиль neutral использует UTF-8Самостоятельный пример
<?php
declare(strict_types=1);

$old = mb_language();
try { mb_language('neutral'); echo mb_get_info('mail_charset'); }
finally { mb_language($old); }
Ожидаемый результат
UTF-8

Это чтение подготовки почты; письмо не отправляется.

Настройка профиля не переводит строкуСамостоятельный пример
<?php
declare(strict_types=1);

$old = mb_language();
try {
    mb_language('Japanese');
    echo 'Заказ готов', "\n", mb_get_info('mail_charset'), "\n";
    echo mb_get_info('mail_header_encoding'), '/', mb_get_info('mail_body_encoding');
} finally { mb_language($old); }
Ожидаемый результат
Заказ готов
ISO-2022-JP
BASE64/7bit

Выбор Japanese — совместимость с определённым почтовым получателем, а не автоматический перевод. В последних двух значениях видна разница упаковки заголовка и тела. Для нового многоязычного сервиса обычно удобнее согласованный UTF-8-профиль.

Ошибки и границы. В PHP 8.5 неизвестное имя языка вызывает ValueError, хотя историческое описание говорит о false. null разрешён с 8.0. Не меняет setlocale и не делает Unicode lowercase турецкой локализацией.

Рядом: mb_send_mail, mb_encode_mimeheader, mb_detect_order. Байты, кодовые точки и графемы; общие правила вызова.

mb_convert_encodingСтарая складская программа выгружает названия в Windows-1251, а сайт работает в UTF-8. Слова должны остаться теми же, но последовательность байтов изменится. mb_convert_encoding получает исходные байты, кодировку назначения и известную кодировку источника. На выходе — новая строка или массив, с которыми уже можно работать в кодировке сайта.

PHP 4.0.6+ · mbstring

mb_convert_encoding(array|string $string, string $to_encoding, array|string|null $from_encoding = null): array|string|false
Данные до и после вызова
  1. Кисть в Windows-1251: ca e8 f1 f2 fc — пять байтов.
  2. Декодируем источник по Windows-1251, записываем результат по UTF-8.
  3. Кисть в UTF-8 занимает десять байтов и нормально выводится на UTF-8-странице.
Аргумент / результатЧто передать и получить
stringСтрока или массив; строковые значения и строковые ключи преобразуются рекурсивно, числовые ключи сохраняются. Исходная переменная не переписывается.
to_encodingКодировка результата.
from_encodingИзвестная кодировка исходных байтов; null — internal/default_charset. Список кандидатов вызывает угадывание, а не последовательные конверсии.
returnПреобразованная строка/массив либо false при неудаче определения/преобразования. Потеря символа через подстановку не обязана дать false.
Превратить пять старых байтов в читаемое названиеСамостоятельный пример
<?php
$legacy = "\xCA\xE8\xF1\xF2\xFC";
$title = mb_convert_encoding($legacy, 'UTF-8', 'Windows-1251');
echo 'Название: ', $title, "\n";
echo 'Байтов до: ', strlen($legacy), '; после: ', strlen($title), "\n";
echo 'Исходные байты: ', bin2hex($legacy), "\n";
Ожидаемый результат
Название: Кисть
Байтов до: 5; после: 10
Исходные байты: cae8f1f2fc

Второй аргумент — куда, третий — откуда. Шестнадцатеричная запись нужна, чтобы UTF-8-файл примера действительно содержал старые байты в переменной. Это не транслитерация: слово осталось русским. Заголовок страницы с UTF-8 сам по себе не преобразует старую строку.

Прочитать конкретную строку складского CSVСамостоятельный пример
<?php
$legacyRow = "BR41;\xCA\xE8\xF1\xF2\xFC;12";
$utf8Row = mb_convert_encoding($legacyRow, 'UTF-8', 'Windows-1251');
$fields = str_getcsv($utf8Row, ';', '"', '');
echo 'Артикул: ', $fields[0], "\n";
echo 'Название: ', $fields[1], "\n";
echo 'Остаток из файла: ', $fields[2], "\n";
Ожидаемый результат
Артикул: BR41
Название: Кисть
Остаток из файла: 12

По контракту этой выгрузки разделитель — точка с запятой, исходная кодировка — Windows-1251. Сначала получаем нормальный текст, затем разбираем CSV. Для файла используют file_get_contents/fgetcsv или поток с согласованной перекодировкой; здесь показана одна строка. Перед записью проверяют число полей, тип и предел остатка: значение CSV пока строка.

Перекодировать ключ и вложенное названиеСамостоятельный пример
<?php
$legacy = ["\xEA\xEE\xE4" => ['title' => "\xCA\xE8\xF1\xF2\xFC", 'stock' => 12]];
$catalog = mb_convert_encoding($legacy, 'UTF-8', 'Windows-1251');
echo 'Имя ключа: ', array_key_first($catalog), "\n";
echo $catalog['код']['title'], ': ', $catalog['код']['stock'], " шт.\n";
Ожидаемый результат
Имя ключа: код
Кисть: 12 шт.

Массив преобразуется рекурсивно, в том числе строковые ключи. stock был числом и остался числом. Смешивать кодировки разных строк в одном таком вызове нельзя. Потери и совпадение преобразованных ключей способны изменить данные; для важного импорта сохраняют оригинал и проверяют схему.

Обнаружить, что ASCII не вмещает русское имяСамостоятельный пример
<?php
$old = mb_substitute_character();
try {
    mb_substitute_character(ord('?'));
    $name = 'Кисть';
    $export = mb_convert_encoding($name, 'ASCII', 'UTF-8');
    echo 'Экспорт: ', $export, "\n";
    $roundTrip = mb_convert_encoding($export, 'UTF-8', 'ASCII');
    if ($roundTrip !== $name) {
        echo "Название потеряет символы — нужен другой формат экспорта\n";
    }
} finally {
    mb_substitute_character($old);
}
Ожидаемый результат
Экспорт: ?????
Название потеряет символы — нужен другой формат экспорта

Возврат строки не означает отсутствие потерь. Здесь обратное преобразование обнаруживает потерю именно этого значения; вопросительные знаки уже не содержат исходных букв. Нельзя исправить неверно выбранную таблицу подстановками «похожих» букв. Источник кодировки выясняют у поставщика.

Ошибки и границы. Массивы поддерживаются с 7.2; неизвестные имена — ValueError с 8.0, from nullable с 8.0. Объекты/ресурсы внутри массива не поддерживаются, предупреждения могут сопровождаться пропуском элемента; рекурсивные ссылки также не являются обычным деревом данных. Перед повторной конверсией убедитесь, что строка ещё в исходной кодировке. Base64/QPrint/UUencode/HTML-ENTITIES deprecated с 8.2: используйте отдельные функции; в 8.5 это ещё не универсальное удаление конвертеров.

Рядом: mb_convert_variables, mb_check_encoding, mb_substitute_character. Байты, кодовые точки и графемы; общие правила вызова.

mb_convert_variablesСтарый модуль отдаёт несколько связанных полей в одной кодировке и ожидает, что они будут изменены на месте. mb_convert_variables перекодирует переданные переменные по ссылке. Возвращаемое значение сообщает исходную кодировку; сами новые строки надо читать из тех переменных, которые передали.

PHP 4.0.6+ · mbstring

mb_convert_variables(string $to_encoding, array|string $from_encoding, mixed &$var, mixed &...$vars): string|false
Данные до и после вызова
  1. $title и $note содержат байты Windows-1251.
  2. Вызов получает переменные по ссылке и записывает новые байты внутрь них.
  3. $source содержит имя Windows-1251; $title теперь читается как Кисть.
Аргумент / результатЧто передать и получить
to_encodingКодировка назначения.
from_encodingОбязательное имя/список кандидатов. Старое упоминание пропуска не соответствует современной сигнатуре: аргумент нужен.
var, ...varsОдна или несколько переменных по ссылке: строка, массив, объект. Вложенные строковые значения предполагаются одной исходной кодировки.
returnИмя определённой исходной кодировки, а не преобразованный текст; false при неудаче.
Различить возвращённое имя и изменённый текстСамостоятельный пример
<?php
$title = "\xCA\xE8\xF1\xF2\xFC";
$source = mb_convert_variables('UTF-8', 'Windows-1251', $title);
echo 'Источник: ', $source, "\n";
echo 'Название: ', $title, "\n";
Ожидаемый результат
Источник: Windows-1251
Название: Кисть

Амперсанд & стоит в объявленной сигнатуре функции, в вызове его не пишут. Строковый литерал вместо переменной передать по ссылке нельзя. Если требуется сохранить старый текст отдельной переменной, mb_convert_encoding обычно яснее.

Изменить связанные поля одной выгрузкиСамостоятельный пример
<?php
$product = ['title' => "\xCA\xE8\xF1\xF2\xFC", 'stock' => 12];
$note = "\xCC\xE8\xF0";
mb_convert_variables('UTF-8', 'Windows-1251', $product, $note);
echo $product['title'], ': ', $product['stock'], " шт.\n";
echo 'Примечание: ', $note, "\n";
Ожидаемый результат
Кисть: 12 шт.
Примечание: Мир

Все строковые значения этого пакета имеют одну известную кодировку. Вложенные значения изменены, число stock сохранилось. Функция поддерживает также объекты, но массовое изменение объекта с инвариантами, hooks или readonly-свойствами — другой уровень ответственности; начинайте с простого контейнера данных.

Ошибки и границы. Не смешивайте UTF-8 и Windows-1251 внутри одного пакета: общий детектор не выбирает отдельную таблицу каждой строке. Неизвестные имена — ValueError; выражение вместо переменной по ссылке — ошибка вызова. Следите за алиасами переменных: изменение видно другим ссылкам на те же данные.

Рядом: mb_convert_encoding, mb_detect_encoding, mb_substitute_character. Байты, кодовые точки и графемы; общие правила вызова.

mb_chrВ таблице интеграции символ указан числом Unicode, например 8364 для евро. mb_chr создаёт из такого числа настоящую строку в нужной кодировке. Её можно включить в подпись цены или диагностическое сообщение.

PHP 7.2+ · mbstring

mb_chr(int $codepoint, ?string $encoding = null): string|false
Данные до и после вызова
  1. 0x20AC и 8364 — две записи одного числа.
  2. mb_chr кодирует соответствующий знак как UTF-8.
  3. Полученная строка € включается в Цена: 25 €.
Аргумент / результатЧто передать и получить
codepointЦелое Unicode-значение, не номер байта и не строка U+…. Шестнадцатеричная запись 0x20AC — обычное целое.
encoding = nullИмя кодировки исходных байтов. null или пропуск использует текущее mb_internal_encoding(); явное UTF-8 делает локальный пример независимым от чужих настроек. Это не преобразование входа.
returnСтрока в выбранной кодировке; false, если значение/символ в ней непредставим.
Получить символ по его кодуСамостоятельный пример
<?php
$currency = mb_chr(0x20AC, 'UTF-8');
echo 'Цена: 25 ', $currency, "\n";
echo 'Байтов UTF-8: ', strlen($currency), "\n";
Ожидаемый результат
Цена: 25 €
Байтов UTF-8: 3

Вводится число без кавычек. Результат — строка, а не HTML-сущность. chr создаёт один байт и не является заменой mb_chr для произвольного Unicode.

Подготовить обозначение валюты для старого каналаСамостоятельный пример
<?php
$symbol = mb_chr(0x20AC, 'ISO-8859-1');
if ($symbol === false) {
    $symbol = 'EUR';
}
echo 'Цена: 25 ', $symbol, "\n";
echo mb_chr(0x110000, 'UTF-8') === false ? "Такой код лежит вне Unicode\n" : "Получен знак\n";
Ожидаемый результат
Цена: 25 EUR
Такой код лежит вне Unicode

В ISO-8859-1 нет евро, поэтому явно выбрано допустимое для задачи обозначение EUR. Нельзя так же произвольно менять имя человека. Один Unicode-код не всегда равен целому видимому emoji: составные последовательности состоят из нескольких кодов.

Ошибки и границы. Неизвестная или неподдерживаемая этой операцией кодировка (например UTF-7) — ValueError; nullable encoding с 8.0. Число кодовой точки не описывает многокомпонентный emoji целиком.

Рядом: mb_ord, mb_convert_encoding. Байты, кодовые точки и графемы; общие правила вызова.

mb_ordНазвание выглядит нормально, но сравнение не проходит: в начале может стоять не обычный пробел, а NBSP. mb_ord возвращает числовой код первого символа. Это позволяет объяснить различие, которое на экране почти незаметно.

PHP 7.2+ · mbstring

mb_ord(string $string, ?string $encoding = null): int|false
Данные до и после вызова
  1. Обычный пробел имеет код U+0020.
  2. Неразрывный пробел имеет код U+00A0.
  3. После диагностики выбирают конкретное правило mb_trim для текстового поля.
Аргумент / результатЧто передать и получить
stringНепустая строка; читается только первый знак, а не сумма/массив всех кодов.
encoding = nullИмя кодировки исходных байтов. null или пропуск использует текущее mb_internal_encoding(); явное UTF-8 делает локальный пример независимым от чужих настроек. Это не преобразование входа.
returnЦелое значение первой Unicode-кодовой точки; false при невозможности декодировать знак. Пустая строка в PHP 8.5 — ValueError.
Прочитать код целого знака, а не его первого байтаСамостоятельный пример
<?php
$symbol = '€';
echo 'Unicode: ', mb_ord($symbol, 'UTF-8'), "\n";
echo 'Первый байт: ', ord($symbol[0]), "\n";
Ожидаемый результат
Unicode: 8364
Первый байт: 226

Индекс [0] читает первый байт E2, а mb_ord декодирует целый UTF-8-символ. Поэтому числа различаются. Для нескольких символов нужен явный обход, функция не возвращает массив всех кодов.

Объяснить лишний знак в скопированном названииСамостоятельный пример
<?php
$title = "\u{00A0}Кисть";
printf("Первый знак: U+%04X\n", mb_ord($title, 'UTF-8'));
if (mb_ord($title, 'UTF-8') === 0x00A0) {
    echo 'Название после согласованной очистки: ', mb_trim($title, null, 'UTF-8'), "\n";
}
Ожидаемый результат
Первый знак: U+00A0
Название после согласованной очистки: Кисть

printf оформляет число в привычную Unicode-запись. Пример проверяет конкретный случай, а не удаляет все невидимые знаки из любых данных. mb_trim требует PHP 8.4+. В пустой строке нет первого знака: перед вызовом проверяют $title !== ""; в PHP 8.5 пустой вход вызывает ValueError.

Ошибки и границы. Пустая строка, неизвестная или неподдерживаемая этой операцией кодировка — ValueError; nullable encoding с 8.0. Например UTF-7 не является поддерживаемой кодировкой mb_ord. Не используйте результат как визуальную идентичность: один знак может быть последовательностью кодовых точек.

Рядом: mb_chr, mb_trim, mb_check_encoding. Байты, кодовые точки и графемы; общие правила вызова.

mb_strcutСтарое устройство принимает подпись максимум в девять байтов, а название хранится в UTF-8. mb_substr ограничивает символы, поэтому здесь нужен mb_strcut: он соблюдает байтовую границу, не оставляя половину многобайтового знака. Обрезка допустима только если это разрешает задача.

PHP 4.0.6+ · mbstring

mb_strcut(string $string, int $start, ?int $length = null, ?string $encoding = null): string
Данные до и после вызова
  1. Кисть занимает 10 байтов: по два на каждую букву.
  2. Бюджет 9 не вмещает последнюю ь целиком.
  3. mb_strcut возвращает Кист — 8 байтов корректного UTF-8.
Аргумент / результатЧто передать и получить
stringБайты текста известной кодировки.
startБайтовое смещение; отрицательное — от конца. Если попало внутрь знака, начало сдвигается к первому байту этого знака. Слишком отрицательное означает начало.
lengthБайтовый бюджет; null — оставшаяся строка, отрицательное исключает байты с конца. Конечная граница не разрезает знак; результат может быть короче бюджета.
encoding = nullИмя кодировки исходных байтов. null или пропуск использует текущее mb_internal_encoding(); явное UTF-8 делает локальный пример независимым от чужих настроек. Это не преобразование входа.
returnЧасть строки в исходной кодировке.
Уложить подпись в байтовое ограничениеСамостоятельный пример
<?php
$title = 'Кисть';
$wireLabel = mb_strcut($title, 0, 9, 'UTF-8');
echo 'Подпись для устройства: ', $wireLabel, "\n";
echo 'Байтов в подписи: ', strlen($wireLabel), "\n";
echo 'Исходное название: ', $title, "\n";
Ожидаемый результат
Подпись для устройства: Кист
Байтов в подписи: 8
Исходное название: Кисть

Возвращено меньше девяти байтов, поскольку девятый был бы половиной буквы. Если приёмнику нужно полное юридически значимое имя, его не сокращают: сравнивают strlen с пределом и возвращают ошибку. Кодировка протокола должна быть выбрана до применения лимита.

Увидеть сдвиг начала, попавшего внутрь буквыСамостоятельный пример
<?php
$text = 'АБВ';
echo 'С байта 0: ', mb_strcut($text, 0, 3, 'UTF-8'), "\n";
echo 'С байта 1: ', mb_strcut($text, 1, 3, 'UTF-8'), "\n";
echo 'С символа 1: ', mb_substr($text, 1, 1, 'UTF-8'), "\n";
Ожидаемый результат
С байта 0: А
С байта 1: А
С символа 1: Б

Байт 1 находится внутри А, поэтому mb_strcut отступает к началу этой буквы. В mb_substr позиция 1 означает уже вторую кодовую точку Б. Эти функции не взаимозаменяемы. Целая кодовая точка всё ещё не гарантирует целую графему с акцентом.

Ошибки и границы. Обработка ошибочных UTF-8/UTF-16 стала последовательнее с 8.4; это не повод принимать повреждённый вход. Неизвестная кодировка — ValueError; nullable encoding с 8.0. Статус «целый знак декодера» не гарантирует целую графему.

Рядом: mb_substr, mb_strimwidth, mb_convert_encoding. Байты, кодовые точки и графемы; общие правила вызова.

mb_strwidthВ простом текстовом отчёте есть латиница и японские названия. Две кодовые точки могут занимать разные условные ширины: AB считается как 2, 東京 — как 4. mb_strwidth помогает рассчитывать такую колонку, но не измеряет пиксели страницы.

PHP 4.0.6+ · mbstring

mb_strwidth(string $string, ?string $encoding = null): int
Данные до и после вызова
  1. AB и 東京 содержат по две кодовые точки.
  2. В модели восточноазиатской ширины латинские знаки дают по 1, эти иероглифы — по 2.
  3. До колонки шириной 6 добавляются соответственно 4 и 2 пробела.
Аргумент / результатЧто передать и получить
stringТекст для оценки.
encoding = nullИмя кодировки исходных байтов. null или пропуск использует текущее mb_internal_encoding(); явное UTF-8 делает локальный пример независимым от чужих настроек. Это не преобразование входа.
returnСумма условных единиц: узкие знаки считаются за 1, широкие за 2 по таблицам Unicode расширения.
Сравнить число знаков и условную ширинуСамостоятельный пример
<?php
foreach (['AB', '東京'] as $label) {
    echo $label, ': кодовых точек ', mb_strlen($label, 'UTF-8');
    echo ', условная ширина ', mb_strwidth($label, 'UTF-8'), "\n";
}
Ожидаемый результат
AB: кодовых точек 2, условная ширина 2
東京: кодовых точек 2, условная ширина 4

東京 — японское название Токио. Единицы ширины не равны байтам и не равны CSS-пикселям. На результат отображения влияют шрифт и терминал; emoji, управляющие последовательности и combining marks требуют более сложной модели.

Собрать две строки текстового отчётаСамостоятельный пример
<?php
$stock = ['AB' => 12, '東京' => 8];
foreach ($stock as $location => $quantity) {
    $padding = max(0, 6 - mb_strwidth($location, 'UTF-8'));
    echo $location, str_repeat(' ', $padding), '| ', $quantity, "\n";
}
Ожидаемый результат
AB    | 12
東京  | 8

max не позволяет передать отрицательное число в str_repeat, если название длиннее колонки. Длинную подпись здесь не обрезаем; для ограничения этой же моделью есть mb_strimwidth. На веб-странице для выравнивания колонок применяют CSS или таблицу.

Ошибки и границы. Неизвестная кодировка — ValueError; nullable encoding с 8.0. У функции нет понятия CSS-пикселей и фактически выбранного браузером шрифта; для веб-вёрстки применяют CSS.

Рядом: mb_strimwidth, mb_strlen, mb_str_pad. Байты, кодовые точки и графемы; общие правила вызова.

mb_strimwidthКолонка простого отчёта допускает шесть условных единиц ширины. Длинную подпись нужно сократить и показать две точки. mb_strimwidth учитывает и ширину знаков, и место маркера внутри общего бюджета.

PHP 4.0.6+ · mbstring

mb_strimwidth(string $string, int $start, int $width, string $trim_marker = "", ?string $encoding = null): string
Данные до и после вызова
  1. 東京ABCD имеет ширину 8: четыре единицы дают два иероглифа, ещё четыре — ABCD.
  2. Общий бюджет 6 включает маркер .. шириной 2.
  3. Остаётся 東京.. шириной 6; короткая 東京 остаётся без маркера.
Аргумент / результатЧто передать и получить
stringИсходный текст.
startНачальный индекс в символах (не в ширине и не в байтах); отрицательный — от конца.
widthОбщая допустимая условная ширина результата; отрицательная исторически отсчитывалась от конца, deprecated с 8.3.
trim_markerДобавляется только при обрезке, занимает часть width. Выбирайте маркер не шире бюджета.
encoding = nullИмя кодировки исходных байтов. null или пропуск использует текущее mb_internal_encoding(); явное UTF-8 делает локальный пример независимым от чужих настроек. Это не преобразование входа.
returnОставшаяся часть с маркером либо без него.
Увидеть, когда добавляется маркер сокращенияСамостоятельный пример
<?php
foreach (['東京ABCD', '東京'] as $label) {
    $short = mb_strimwidth($label, 0, 6, '..', 'UTF-8');
    echo $label, ' → ', $short, "\n";
}
Ожидаемый результат
東京ABCD → 東京..
東京 → 東京

start=0 — начало по кодовым точкам, width=6 — предел по условной ширине. Это разные единицы. Две точки появляются только при сокращении и занимают место внутри предела, а не после него.

Подготовить полную строку отчёта с разделителемСамостоятельный пример
<?php
foreach (['東京ABCD', 'AB'] as $label) {
    $short = mb_strimwidth($label, 0, 6, '..', 'UTF-8');
    $padding = 6 - mb_strwidth($short, 'UTF-8');
    echo $short, str_repeat(' ', $padding), "| готово\n";
}
Ожидаемый результат
東京..| готово
AB    | готово

Первая функция сокращает, вторая измеряет результат в той же модели, str_repeat дополняет пробелами. Для обычной русской карточки по числу кодовых точек чаще нужен mb_substr. Для реального CSS-блока — вёрстка, а не подсчёт условной ширины PHP.

Ошибки и границы. Отрицательные start/width поддержаны с 7.1, отрицательный width deprecated с 8.3. Недопустимый диапазон start/width и неизвестная кодировка — ValueError. Не смешивайте start в символах с width в условных единицах.

Рядом: mb_strwidth, mb_substr, mb_strcut. Байты, кодовые точки и графемы; общие правила вызова.

mb_str_padВ текстовом списке нужно дополнить русское название до восьми кодовых точек, чтобы после него поставить разделитель. Обычная str_pad считает байты; mb_str_pad работает с кодовыми точками и добавляет указанное заполнение слева, справа или с двух сторон.

PHP 8.3+ · mbstring

mb_str_pad(string $string, int $length, string $pad_string = " ", int $pad_type = STR_PAD_RIGHT, ?string $encoding = null): string
Данные до и после вызова
  1. Кисть содержит пять кодовых точек.
  2. До длины 8 не хватает трёх пробелов.
  3. Получается Кисть и три пробела; полное длинное название не сокращается.
Аргумент / результатЧто передать и получить
stringИсходный текст.
lengthЦелевая длина в Unicode-кодовых точках; не больше исходной или отрицательная — строка остаётся без дополнения.
pad_stringНепустая строка заполнения: повторяется и при необходимости обрезается по символам.
pad_typeSTR_PAD_RIGHT по умолчанию; STR_PAD_LEFT; STR_PAD_BOTH. При нечётном остатке BOTH добавляет лишний знак справа.
encoding = nullИмя кодировки исходных байтов. null или пропуск использует текущее mb_internal_encoding(); явное UTF-8 делает локальный пример независимым от чужих настроек. Это не преобразование входа.
returnНовая дополненная строка; не обрезает слишком длинную исходную.
Дополнить подписи до выбранной длиныСамостоятельный пример
<?php
echo '[', mb_str_pad('Кисть', 8, ' ', STR_PAD_RIGHT, 'UTF-8'), "]\n";
echo '[', mb_str_pad('Кисть широкая', 8, ' ', STR_PAD_RIGHT, 'UTF-8'), "]\n";
Ожидаемый результат
[Кисть   ]
[Кисть широкая]

Скобки показывают добавленные пробелы. length — минимальная общая длина, а не число добавляемых знаков. Длинная строка остаётся целиком. Функция доступна с PHP 8.3 и не заменяет измерение условной ширины или CSS-пикселей.

Выбрать сторону заполнения для текстовой меткиСамостоятельный пример
<?php
echo mb_str_pad('Мир', 8, '.', STR_PAD_LEFT, 'UTF-8'), "\n";
echo mb_str_pad('Мир', 8, '.', STR_PAD_RIGHT, 'UTF-8'), "\n";
echo mb_str_pad('Мир', 8, '.', STR_PAD_BOTH, 'UTF-8'), "\n";
Ожидаемый результат
.....Мир
Мир.....
..Мир...

Всего нужно пять точек. При BOTH нечётный лишний знак оказывается справа. Многосимвольное заполнение повторяется и при необходимости сокращается. Пустое заполнение недопустимо; это ошибка параметра, а не команда «ничего не добавлять».

Ошибки и границы. Пустой pad_string или неизвестный pad_type — ValueError; неверная кодировка — ValueError. Большой length создаёт большую строку: ограничивайте значения из внешней конфигурации.

Рядом: mb_strwidth, mb_strimwidth, mb_strlen. Байты, кодовые точки и графемы; общие правила вызова.

mb_str_splitДля подсказки в учебной игре или диагностики текста нужно пройти по отдельным буквам русского слова. mb_str_split создаёт массив групп кодовых точек. Он не ищет разделитель, как explode: размер каждой группы задаётся числом.

PHP 7.4+ · mbstring

mb_str_split(string $string, int $length = 1, ?string $encoding = null): array
Данные до и после вызова
  1. Кисть — одна строка.
  2. mb_str_split с length=1 создаёт элементы К, и, с, т, ь.
  3. foreach может показать каждую подсказку вместе с её номером.
Аргумент / результатЧто передать и получить
stringТекст для разбиения.
lengthПоложительное число символов в группе; последняя группа может быть короче.
encoding = nullИмя кодировки исходных байтов. null или пропуск использует текущее mb_internal_encoding(); явное UTF-8 делает локальный пример независимым от чужих настроек. Это не преобразование входа.
returnМассив строк; пустой вход даёт пустой массив в современном PHP.
Превратить слово в отдельные подсказкиСамостоятельный пример
<?php
$letters = mb_str_split('Кисть', 1, 'UTF-8');
echo 'Первая буква: ', $letters[0], "\n";
echo 'Все буквы: ', implode(' | ', $letters), "\n";
Ожидаемый результат
Первая буква: К
Все буквы: К | и | с | т | ь

Ключ первого элемента — 0. Вертикальные черты добавила implode, а не mb_str_split. Для большого файла массив на каждую кодовую точку потребует много памяти; не делите так весь импорт без необходимости.

Показать номер группы и неполный хвостСамостоятельный пример
<?php
$groups = mb_str_split('АБВГД', 2, 'UTF-8');
foreach ($groups as $index => $group) {
    echo 'Группа ', $index + 1, ': ', $group, "\n";
}
Ожидаемый результат
Группа 1: АБ
Группа 2: ВГ
Группа 3: Д

Каждая группа содержит не более двух кодовых точек. Последняя Д не теряется. Для соединённых emoji или буквы с отдельным акцентом такой разбор может разделить видимый знак; графемное разбиение относится к intl.

Ошибки и границы. length < 1 — ValueError; неверная кодировка — ValueError. С 8.0 функция больше не возвращает false при ошибке, encoding nullable. Массив на каждый знак расходует память: не делите так весь многогигабайтный файл.

Рядом: mb_substr, mb_ord, mb_strlen. Байты, кодовые точки и графемы; общие правила вызова.

mb_trimПосле копирования названия из документа вокруг слова остаются неразрывные пробелы. mb_trim убирает выбранные знаки с обоих краёв, сохраняя содержимое поля. Сначала увидим границы строки в квадратных скобках, затем подготовим название для карточки товара. Это осмысленная обработка текстового поля; пароли и подписанные данные так менять нельзя.

PHP 8.4+ · mbstring

mb_trim(string $string, ?string $characters = null, ?string $encoding = null): string
Данные до и после вызова
  1. Вход содержит NBSP, слово Кисть и ещё один NBSP.
  2. mb_trim идёт с обоих краёв, пока встречает разрешённые для удаления знаки.
  3. Возвращается новая строка; пробелы между словами не исчезают.
Аргумент / результатЧто передать и получить
stringИсходный текст.
charactersnull — стандартный набор; строка — буквальный набор отдельных удаляемых символов, а не regex и не диапазон a..z. Пустая строка ничего не удаляет.
encoding = nullИмя кодировки исходных байтов. null или пропуск использует текущее mb_internal_encoding(); явное UTF-8 делает локальный пример независимым от чужих настроек. Это не преобразование входа.
returnНовая строка с удалением с обоих краёв до первого знака вне набора.

По умолчанию удаляются U+0000, U+0009–U+000D, U+0020, U+0085, U+00A0, U+1680, U+180E, U+2000–U+200A, U+2028–U+2029, U+202F, U+205F, U+3000. Это точный набор PHP, а не любое «невидимое»: U+200B и BOM U+FEFF в него не входят.

Убрать невидимый лишний знак с обоих краёвСамостоятельный пример
<?php
$raw = "\u{00A0}Кисть\u{00A0}";
$title = mb_trim($raw, null, 'UTF-8');
echo '[', $title, "]\n";
echo 'Кодовых точек: ', mb_strlen($title, 'UTF-8'), "\n";
Ожидаемый результат
[Кисть]
Кодовых точек: 5

Запись \u{00A0} создаёт неразрывный пробел: он похож на обычный, но имеет другой код. null выбирает стандартный набор пробельных знаков. Квадратные скобки — наша подсказка для чтения вывода, они не часть результата функции. Полный набор знаков приведён перед примерами.

Подготовить название, сохранив пробел внутриСамостоятельный пример
<?php
$raw = "\u{00A0}Кисть широкая\u{00A0}";
$title = mb_trim($raw, null, 'UTF-8');
echo 'Название: [', $title, "]\n";
echo 'Оригинал сохранён: ', mb_strlen($raw, 'UTF-8'), " знаков\n";
Ожидаемый результат
Название: [Кисть широкая]
Оригинал сохранён: 15 знаков

Внутренний пробел нужен для названия из двух слов и остаётся на месте. Выбранная функция работает с обоих краёв. Если надо снять оба края, используйте mb_trim. В форме до такого вызова отдельно убеждаются, что значение — строка корректного UTF-8; массив вместо текста не обрабатывают как название.

Задать набор рамочных знаков и сравнить стороныСамостоятельный пример
<?php
echo '[', mb_trim('《Кисть》', '《》', 'UTF-8'), "]\n";
echo '[', mb_trim('  Кисть  ', null, 'UTF-8'), "]\n";
Ожидаемый результат
[Кисть]
[Кисть]

Второй аргумент — набор отдельных знаков, а не точная фраза и не регулярное выражение. Функция снимает сколько угодно крайних знаков из набора до первого другого символа. Для удаления ровно одного известного префикса сначала проверяют его и берут подстроку.

Ошибки и границы. Неизвестная кодировка — ValueError. Функция не удаляет пробелы внутри, не нормализует Unicode и не экранирует HTML. Сначала проверьте исходные байты; не применяйте очистку к бинарным данным.

Рядом: mb_ltrim, mb_rtrim, mb_check_encoding. Байты, кодовые точки и графемы; общие правила вызова.

mb_ltrimПосле копирования названия из документа вокруг слова остаются неразрывные пробелы. mb_ltrim убирает выбранные знаки слева, сохраняя содержимое поля. Сначала увидим границы строки в квадратных скобках, затем подготовим название для карточки товара. Это осмысленная обработка текстового поля; пароли и подписанные данные так менять нельзя.

PHP 8.4+ · mbstring

mb_ltrim(string $string, ?string $characters = null, ?string $encoding = null): string
Данные до и после вызова
  1. Вход содержит NBSP, слово Кисть и ещё один NBSP.
  2. mb_ltrim идёт слева, пока встречает разрешённые для удаления знаки.
  3. Возвращается новая строка; пробелы между словами не исчезают.
Аргумент / результатЧто передать и получить
stringИсходный текст.
charactersnull — стандартный набор; строка — буквальный набор отдельных удаляемых символов, а не regex и не диапазон a..z. Пустая строка ничего не удаляет.
encoding = nullИмя кодировки исходных байтов. null или пропуск использует текущее mb_internal_encoding(); явное UTF-8 делает локальный пример независимым от чужих настроек. Это не преобразование входа.
returnНовая строка с удалением только слева до первого знака вне набора.

По умолчанию удаляются U+0000, U+0009–U+000D, U+0020, U+0085, U+00A0, U+1680, U+180E, U+2000–U+200A, U+2028–U+2029, U+202F, U+205F, U+3000. Это точный набор PHP, а не любое «невидимое»: U+200B и BOM U+FEFF в него не входят.

Убрать невидимый лишний знак слеваСамостоятельный пример
<?php
$raw = "\u{00A0}Кисть\u{00A0}";
$title = mb_ltrim($raw, null, 'UTF-8');
echo '[', $title, "]\n";
echo 'Кодовых точек: ', mb_strlen($title, 'UTF-8'), "\n";
Ожидаемый результат
[Кисть ]
Кодовых точек: 6

Запись \u{00A0} создаёт неразрывный пробел: он похож на обычный, но имеет другой код. null выбирает стандартный набор пробельных знаков. Квадратные скобки — наша подсказка для чтения вывода, они не часть результата функции. Полный набор знаков приведён перед примерами.

Подготовить название, сохранив пробел внутриСамостоятельный пример
<?php
$raw = "\u{00A0}Кисть широкая\u{00A0}";
$title = mb_ltrim($raw, null, 'UTF-8');
echo 'Название: [', $title, "]\n";
echo 'Оригинал сохранён: ', mb_strlen($raw, 'UTF-8'), " знаков\n";
Ожидаемый результат
Название: [Кисть широкая ]
Оригинал сохранён: 15 знаков

Внутренний пробел нужен для названия из двух слов и остаётся на месте. Выбранная функция работает слева. Если надо снять оба края, используйте mb_trim. В форме до такого вызова отдельно убеждаются, что значение — строка корректного UTF-8; массив вместо текста не обрабатывают как название.

Задать набор рамочных знаков и сравнить стороныСамостоятельный пример
<?php
echo '[', mb_ltrim('《Кисть》', '《》', 'UTF-8'), "]\n";
echo '[', mb_ltrim('  Кисть  ', null, 'UTF-8'), "]\n";
Ожидаемый результат
[Кисть》]
[Кисть  ]

Второй аргумент — набор отдельных знаков, а не точная фраза и не регулярное выражение. Функция снимает сколько угодно крайних знаков из набора до первого другого символа. Для удаления ровно одного известного префикса сначала проверяют его и берут подстроку.

Ошибки и границы. Неизвестная кодировка — ValueError. Функция не удаляет пробелы внутри, не нормализует Unicode и не экранирует HTML. Сначала проверьте исходные байты; не применяйте очистку к бинарным данным.

Рядом: mb_trim, mb_rtrim, mb_check_encoding. Байты, кодовые точки и графемы; общие правила вызова.

mb_rtrimПосле копирования названия из документа вокруг слова остаются неразрывные пробелы. mb_rtrim убирает выбранные знаки справа, сохраняя содержимое поля. Сначала увидим границы строки в квадратных скобках, затем подготовим название для карточки товара. Это осмысленная обработка текстового поля; пароли и подписанные данные так менять нельзя.

PHP 8.4+ · mbstring

mb_rtrim(string $string, ?string $characters = null, ?string $encoding = null): string
Данные до и после вызова
  1. Вход содержит NBSP, слово Кисть и ещё один NBSP.
  2. mb_rtrim идёт справа, пока встречает разрешённые для удаления знаки.
  3. Возвращается новая строка; пробелы между словами не исчезают.
Аргумент / результатЧто передать и получить
stringИсходный текст.
charactersnull — стандартный набор; строка — буквальный набор отдельных удаляемых символов, а не regex и не диапазон a..z. Пустая строка ничего не удаляет.
encoding = nullИмя кодировки исходных байтов. null или пропуск использует текущее mb_internal_encoding(); явное UTF-8 делает локальный пример независимым от чужих настроек. Это не преобразование входа.
returnНовая строка с удалением только справа до первого знака вне набора.

По умолчанию удаляются U+0000, U+0009–U+000D, U+0020, U+0085, U+00A0, U+1680, U+180E, U+2000–U+200A, U+2028–U+2029, U+202F, U+205F, U+3000. Это точный набор PHP, а не любое «невидимое»: U+200B и BOM U+FEFF в него не входят.

Убрать невидимый лишний знак справаСамостоятельный пример
<?php
$raw = "\u{00A0}Кисть\u{00A0}";
$title = mb_rtrim($raw, null, 'UTF-8');
echo '[', $title, "]\n";
echo 'Кодовых точек: ', mb_strlen($title, 'UTF-8'), "\n";
Ожидаемый результат
[ Кисть]
Кодовых точек: 6

Запись \u{00A0} создаёт неразрывный пробел: он похож на обычный, но имеет другой код. null выбирает стандартный набор пробельных знаков. Квадратные скобки — наша подсказка для чтения вывода, они не часть результата функции. Полный набор знаков приведён перед примерами.

Подготовить название, сохранив пробел внутриСамостоятельный пример
<?php
$raw = "\u{00A0}Кисть широкая\u{00A0}";
$title = mb_rtrim($raw, null, 'UTF-8');
echo 'Название: [', $title, "]\n";
echo 'Оригинал сохранён: ', mb_strlen($raw, 'UTF-8'), " знаков\n";
Ожидаемый результат
Название: [ Кисть широкая]
Оригинал сохранён: 15 знаков

Внутренний пробел нужен для названия из двух слов и остаётся на месте. Выбранная функция работает справа. Если надо снять оба края, используйте mb_trim. В форме до такого вызова отдельно убеждаются, что значение — строка корректного UTF-8; массив вместо текста не обрабатывают как название.

Задать набор рамочных знаков и сравнить стороныСамостоятельный пример
<?php
echo '[', mb_rtrim('《Кисть》', '《》', 'UTF-8'), "]\n";
echo '[', mb_rtrim('  Кисть  ', null, 'UTF-8'), "]\n";
Ожидаемый результат
[《Кисть]
[  Кисть]

Второй аргумент — набор отдельных знаков, а не точная фраза и не регулярное выражение. Функция снимает сколько угодно крайних знаков из набора до первого другого символа. Для удаления ровно одного известного префикса сначала проверяют его и берут подстроку.

Ошибки и границы. Неизвестная кодировка — ValueError. Функция не удаляет пробелы внутри, не нормализует Unicode и не экранирует HTML. Сначала проверьте исходные байты; не применяйте очистку к бинарным данным.

Рядом: mb_trim, mb_ltrim, mb_check_encoding. Байты, кодовые точки и графемы; общие правила вызова.

mb_strtoupperНужно напечатать крупную подпись на складской этикетке: «Кисть» превращается в «КИСТЬ». При этом некоторые Unicode-буквы разворачиваются в несколько букв, поэтому размер готовой подписи проверяют после преобразования.

PHP 4.3+ · mbstring

mb_strtoupper(string $string, ?string $encoding = null): string
Данные до и после вызова
  1. Исходное имя Кисть хранится для обычной карточки.
  2. mb_strtoupper создаёт копию КИСТЬ для этикетки.
  3. Ограничение места применяется к полученной копии.
Аргумент / результатЧто передать и получить
stringТекст; преобразование — верхний регистр.
encoding = nullИмя кодировки исходных байтов. null или пропуск использует текущее mb_internal_encoding(); явное UTF-8 делает локальный пример независимым от чужих настроек. Это не преобразование входа.
returnНовая строка той же кодировки. Unicode-отображение может изменить число кодовых точек/байтов.
Сделать подпись этикеткиСамостоятельный пример
<?php
$title = 'Кисть';
$label = mb_strtoupper($title, 'UTF-8');
echo 'Этикетка: ', $label, "\n";
echo 'Каталог: ', $title, "\n";
Ожидаемый результат
Этикетка: КИСТЬ
Каталог: Кисть

Второй аргумент — кодировка, а не язык. Преобразование выполняет правила Unicode; оно не меняет исходное имя и не транслитерирует его в латиницу.

Поймать увеличение длины перед отправкой в принтерСамостоятельный пример
<?php
$name = 'Straße';
$label = mb_strtoupper($name, 'UTF-8');
echo $name, ' -> ', $label, "\n";
echo mb_strlen($name, 'UTF-8'), ' -> ', mb_strlen($label, 'UTF-8'), " знаков\n";
if (mb_strlen($label, 'UTF-8') > 6) {
    echo "Этикетка не помещается в поле из 6 знаков\n";
}
Ожидаемый результат
Straße -> STRASSE
6 -> 7 знаков
Этикетка не помещается в поле из 6 знаков

ß в полном верхнем регистре становится SS. Поэтому правило «вход помещался, значит выход тоже» неверно. Код показывает отказ до отправки; никакого реального принтера здесь нет. Для юридического имени или бренда сохраняют утверждённое написание.

Ошибки и границы. Неизвестная кодировка — ValueError. Преобразование основано на Unicode, не на setlocale; турецкие языковые правила и красивое написание имени человека не гарантируются.

Рядом: mb_convert_case, mb_strtolower, mb_lcfirst. Байты, кодовые точки и графемы; общие правила вызова.

mb_lcfirstЕсть готовая подпись «Заказ готов», которую надо включить после слова «Статус:». mb_lcfirst делает строчной только первую кодовую точку: остальное написание остаётся как было. Это удобно для заранее подготовленных фраз, но не является редактором произвольного текста.

PHP 8.4+ · mbstring

mb_lcfirst(string $string, ?string $encoding = null): string
Данные до и после вызова
  1. Заказ готов — отдельная подпись.
  2. Первая З → з, остальные знаки не меняются.
  3. В сообщении получается Статус: заказ готов.
Аргумент / результатЧто передать и получить
stringТекст; преобразование — нижний регистр первого знака.
encoding = nullИмя кодировки исходных байтов. null или пропуск использует текущее mb_internal_encoding(); явное UTF-8 делает локальный пример независимым от чужих настроек. Это не преобразование входа.
returnНовая строка той же кодировки. Unicode-отображение может изменить число кодовых точек/байтов.
Изменить только первую буквуСамостоятельный пример
<?php
echo mb_lcfirst('ЗаКАЗ', 'UTF-8'), "\n";
echo mb_strtolower('ЗаКАЗ', 'UTF-8'), "\n";
Ожидаемый результат
заКАЗ
заказ

Первый результат сохраняет КАЗ. Второй меняет все буквы. Выбирайте функцию по тому, какую часть подписи действительно нужно преобразовать.

Встроить подпись в составное уведомлениеСамостоятельный пример
<?php
$statusLabel = 'Заказ готов';
echo 'Статус: ', mb_lcfirst($statusLabel, 'UTF-8'), ".\n";
echo 'Заголовок: ', $statusLabel, "\n";
Ожидаемый результат
Статус: заказ готов.
Заголовок: Заказ готов

Такое правило подходит для контролируемого набора статусов. Не применяйте его автоматически к именам людей или брендам. mb_lcfirst появилась в PHP 8.4; на старой версии этот вызов отсутствует.

Ошибки и границы. Неизвестная кодировка — ValueError. Преобразование основано на Unicode, не на setlocale; турецкие языковые правила и красивое написание имени человека не гарантируются.

Рядом: mb_convert_case, mb_strtolower, mb_strtoupper. Байты, кодовые точки и графемы; общие правила вызова.

mb_ucfirstСоставленная подпись начинается со строчной буквы: «заказ готов». mb_ucfirst переводит первый знак в начальную форму регистра, сохраняя остальную строку. Для русской буквы это привычная заглавная; для некоторых Unicode-диграфов начальная и полностью верхняя формы различаются.

PHP 8.4+ · mbstring

mb_ucfirst(string $string, ?string $encoding = null): string
Данные до и после вызова
  1. заказ готов → Заказ готов.
  2. Изменяется первая кодовая точка, а не каждое слово.
  3. Готовую подпись можно использовать в заголовке уведомления.
Аргумент / результатЧто передать и получить
stringТекст; преобразование — title case первого знака.
encoding = nullИмя кодировки исходных байтов. null или пропуск использует текущее mb_internal_encoding(); явное UTF-8 делает локальный пример независимым от чужих настроек. Это не преобразование входа.
returnНовая строка той же кодировки. Unicode-отображение может изменить число кодовых точек/байтов.
Поставить заглавную в начале фразыСамостоятельный пример
<?php
$message = 'заказ готов';
echo mb_ucfirst($message, 'UTF-8'), "\n";
echo mb_ucfirst('заКАЗ готов', 'UTF-8'), "\n";
Ожидаемый результат
Заказ готов
ЗаКАЗ готов

Во втором случае остальной неправильный регистр не исправился. Функция не понимает грамматику и не ищет первое слово после ведущего пробела: первый знак должен быть тем, который требуется изменить.

Различить начальную и полностью верхнюю формыСамостоятельный пример
<?php
echo mb_ucfirst('dzabc', 'UTF-8'), "\n";
echo mb_strtoupper('dzabc', 'UTF-8'), "\n";
Ожидаемый результат
Dzabc
DZABC

У диграфа dz есть начальная форма Dz и верхняя DZ. Это демонстрация реального Unicode-правила, а не обещание автоматически красиво оформить любое имя. Для слов есть MB_CASE_TITLE; оно тоже требует редакционной проверки.

Ошибки и границы. Неизвестная кодировка — ValueError. Преобразование основано на Unicode, не на setlocale; турецкие языковые правила и красивое написание имени человека не гарантируются.

Рядом: mb_convert_case, mb_strtolower, mb_strtoupper. Байты, кодовые точки и графемы; общие правила вызова.

mb_convert_caseУ преобразования регистра несколько разных задач: вывести заголовок, подготовить этикетку или сравнить два написания без регистра. mb_convert_case позволяет явно выбрать правило. Для сравнения Straße и STRASSE нужен полный case folding, а не простое приведение к строчным буквам.

PHP 4.3+ · mbstring

mb_convert_case(string $string, int $mode, ?string $encoding = null): string
Данные до и после вызова
  1. Straße и STRASSE имеют разное исходное написание.
  2. MB_CASE_FOLD даёт strasse в обоих случаях.
  3. Сравниваем ключи; пользователю показываем сохранённое исходное название.
Аргумент / результатЧто передать и получить
stringИсходный текст.
modeОдна из восьми MB_CASE_* констант: UPPER, LOWER, TITLE, FOLD и их *_SIMPLE варианты. Это выбор одного режима, не битовая маска.
encoding = nullИмя кодировки исходных байтов. null или пропуск использует текущее mb_internal_encoding(); явное UTF-8 делает локальный пример независимым от чужих настроек. Это не преобразование входа.
returnСтрока в исходной кодировке после Unicode-преобразования.
Получить три оформления одной подписиСамостоятельный пример
<?php
$text = 'новый ЗАКАЗ';
echo mb_convert_case($text, MB_CASE_LOWER, 'UTF-8'), "\n";
echo mb_convert_case($text, MB_CASE_UPPER, 'UTF-8'), "\n";
echo mb_convert_case($text, MB_CASE_TITLE, 'UTF-8'), "\n";
Ожидаемый результат
новый заказ
НОВЫЙ ЗАКАЗ
Новый Заказ

Второй аргумент — одна константа выбора. MB_CASE_TITLE меняет форму слов; это не гарантия правильного написания аббревиатур и фамилий. Все восемь режимов описаны в параметрах выше.

Сопоставить название из двух системСамостоятельный пример
<?php
$stored = 'Straße';
$imported = 'STRASSE';
$left = mb_convert_case($stored, MB_CASE_FOLD, 'UTF-8');
$right = mb_convert_case($imported, MB_CASE_FOLD, 'UTF-8');
echo 'Ключи: ', $left, ' / ', $right, "\n";
if ($left === $right) {
    echo 'Найдено сохранённое название: ', $stored, "\n";
}
Ожидаемый результат
Ключи: strasse / strasse
Найдено сохранённое название: Straße

Здесь прикладное правило разрешает такое сопоставление; для уникальных идентификаторов его заранее согласуют. Case folding не включает каноническую нормализацию Unicode и не обязан совпадать с правилами базы данных.

Увидеть, что simple-режим меняет контрактСамостоятельный пример
<?php
echo mb_convert_case('Straße', MB_CASE_FOLD, 'UTF-8'), "\n";
echo mb_convert_case('Straße', MB_CASE_FOLD_SIMPLE, 'UTF-8'), "\n";
Ожидаемый результат
strasse
straße

SIMPLE не разворачивает ß в ss. Он нужен там, где выбран именно такой контракт, а не как более быстрая взаимозаменяемая версия. Пример показывает причину возможного несовпадения поиска.

Ошибки и границы. Неизвестный mode/encoding — ValueError. FOLD и SIMPLE добавлены в 7.3. С 8.3 условное правило греческого sigma действует для LOWER/TITLE, но не LOWER_SIMPLE/TITLE_SIMPLE. Регистр не зависит от locale; Unicode-таблицы меняются между версиями PHP.

Рядом: mb_strtolower, mb_strtoupper, mb_ucfirst. Байты, кодовые точки и графемы; общие правила вызова.

mb_convert_kanaЯпонский поставщик прислал артикул широкими символами AB12, а каталог хранит AB12. mb_convert_kana умеет согласованно менять ширину выбранных знаков и формы kana. Это помогает сопоставить данные по заранее выбранному правилу, сохраняя исходное написание.

PHP 4.0.6+ · mbstring

mb_convert_kana(string $string, string $mode = "KV", ?string $encoding = null): string
Данные до и после вызова
  1. В исходнике AB12 CD широкие латинские знаки, цифры и пробел.
  2. Флаги as выбирают узкие ASCII-формы и обычный пробел.
  3. Результат AB12 CD можно использовать в согласованном поисковом ключе.
Аргумент / результатЧто передать и получить
stringЯпонский текст, широкая латиница/цифры или пробелы, к которым применимы флаги.
modeКомбинация совместимых букв; по умолчанию KV. Каждая буква выбирает отдельное направление.
encoding = nullИмя кодировки исходных байтов. null или пропуск использует текущее mb_internal_encoding(); явное UTF-8 делает локальный пример независимым от чужих настроек. Это не преобразование входа.
returnПреобразованная строка. Число кодовых точек может измениться при объединении озвончения.
ФлагиНаправление
r / RШирокая → узкая / узкая → широкая латиница
n / NШирокие → узкие / узкие → широкие цифры
a / AШирокие → узкие / обратное для набора ASCII U+0021–U+007E, кроме кавычек U+0022/U+0027, обратной косой U+005C и тильды U+007E
s / SU+3000 → обычный пробел / обратное
k / KШирокая катакана → узкая / обратное
h / HШирокая хирагана → узкая катакана / узкая катакана → широкая хирагана
c / CШирокая катакана → хирагана / обратное
VОбъединить знак озвончения с предыдущим знаком; используют с K или H
Показать исходный и преобразованный артикулСамостоятельный пример
<?php
$raw = 'AB12 CD';
$code = mb_convert_kana($raw, 'as', 'UTF-8');
echo 'Источник: ', $raw, "\n";
echo 'Для сопоставления: ', $code, "\n";
Ожидаемый результат
Источник: AB12 CD
Для сопоставления: AB12 CD

Флаг a меняет поддерживаемые широкие ASCII-знаки, s — широкий пробел. Это не общая очистка строки и не транслитерация. Полный перечень флагов и исключения сохранены в таблице выше.

Найти товар по согласованной форме артикулаСамостоятельный пример
<?php
$catalog = ['AB12' => 'Кисть'];
$received = 'AB12';
$key = mb_convert_kana($received, 'a', 'UTF-8');
if (array_key_exists($key, $catalog)) {
    echo 'Получено ', $received, '; найден ', $key, ': ', $catalog[$key], "\n";
}
Ожидаемый результат
Получено AB12; найден AB12: Кисть

Такое сопоставление допустимо, только если правило поставщика считает эти формы одним артикулом. Два разных внешних идентификатора могут превратиться в один ключ — коллизии нужно обнаруживать. Исходное значение остаётся для отчёта.

Собрать раздельный знак озвончения kanaСамостоятельный пример
<?php
$half = 'ガク';
$full = mb_convert_kana($half, 'KV', 'UTF-8');
echo $half, ' -> ', $full, "\n";
echo 'Кодовых точек: ', mb_strlen($half, 'UTF-8'), ' -> ', mb_strlen($full, 'UTF-8'), "\n";
Ожидаемый результат
ガク -> ガク
Кодовых точек: 3 -> 2

K меняет узкую катакану на широкую, V объединяет озвончение с предыдущим знаком. Поэтому длина изменилась. Валидацию длины делают по форме, которая действительно отправится получателю; юридически значимое имя не переписывают без правила.

Ошибки и границы. С 8.2 конфликтующие флаги, например sS, дают ValueError; неизвестная кодировка также ValueError. Это не транслитерация в латиницу и не универсальная Unicode-нормализация.

Рядом: mb_convert_encoding, mb_strwidth, mb_convert_case. Байты, кодовые точки и графемы; общие правила вызова.

mb_encode_numericentityИногда текстовый формат требует представить выбранные Unicode-знаки числовыми HTML-ссылками. Например, евро можно записать как &#8364; или &#x20AC;. Функция создаёт это представление по карте диапазонов; само по себе оно не является универсальным HTML-экранированием.

PHP 4.0.6+ · mbstring

mb_encode_numericentity(string $string, array $map, ?string $encoding = null, bool $hex = false): string
Данные до и после вызова
  1. A€ содержит ASCII-букву и знак вне ASCII.
  2. Карта от U+0080 выбирает только евро.
  3. A&#8364; — буквальная строка результата; в HTML число обозначает тот же знак €.
Аргумент / результатЧто передать и получить
stringВходной текст с символами для кодирования.
mapПлоский массив групп по четыре: начало диапазона Unicode, конец включительно, смещение, битовая маска. При кодировании используется (codepoint + offset) & mask; для обычных ссылок offset=0, mask=0x10FFFF.
encoding = nullИмя кодировки исходных байтов. null или пропуск использует текущее mb_internal_encoding(); явное UTF-8 делает локальный пример независимым от чужих настроек. Это не преобразование входа.
hexfalse — десятичные ссылки; true — шестнадцатеричные.
returnПреобразованная строка; данные вне выбранных диапазонов остаются как были.
Получить десятичную и шестнадцатеричную записиСамостоятельный пример
<?php
$map = [0x80, 0x10FFFF, 0, 0x10FFFF];
echo mb_encode_numericentity('A€', $map, 'UTF-8'), "\n";
echo mb_encode_numericentity('A€', $map, 'UTF-8', true), "\n";
Ожидаемый результат
A&#8364;
A&#x20AC;

Четыре числа — одна группа: начало, конец, смещение, маска. Начало 0x80 оставляет ASCII без изменения; смещение 0 сохраняет номер Unicode. Последний аргумент true выбирает шестнадцатеричную запись. Это обычные строки, которые здесь показаны буквально.

Увидеть, почему числовые ссылки не экранируют HTML целикомСамостоятельный пример
<?php
$map = [0x80, 0x10FFFF, 0, 0x10FFFF];
$text = '<Кисть>';
echo 'Выбранные знаки: ', mb_encode_numericentity($text, $map, 'UTF-8'), "\n";
echo 'Текст для HTML: ', htmlspecialchars($text, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'), "\n";
Ожидаемый результат
Выбранные знаки: <&#1050;&#1080;&#1089;&#1090;&#1100;>
Текст для HTML: &lt;Кисть&gt;

У первого результата угловые скобки остались: они вне выбранного диапазона. Для показа пользовательского текста в HTML обычно нужен второй вариант. Для JavaScript, URL и SQL правила другие; не пытайтесь одной картой решить все контексты.

Ошибки и границы. Количество элементов map должно делиться на четыре, иначе ValueError. С 8.4 непереводимые в int значения карты вызывают ValueError; допустимы int и неявно преобразуемые float/bool/null/числовые строки, но для ясности используйте целые. Неверная кодировка — ValueError; nullable encoding с 8.0. Именованные сущности вроде &amp; не входят в задачу числового декодера; для их набора есть html_entity_decode.

Рядом: mb_decode_numericentity, mb_chr, mb_ord. Байты, кодовые точки и графемы; общие правила вызова.

mb_decode_numericentityПартнёр передал знак евро в виде числовой HTML-ссылки, а отчёту нужна обычная UTF-8-строка. mb_decode_numericentity раскрывает ссылки только в выбранных диапазонах. После декодирования строка остаётся внешними данными и требует правил своего назначения.

PHP 4.0.6+ · mbstring

mb_decode_numericentity(string $string, array $map, ?string $encoding = null): string
Данные до и после вызова
  1. В A&#8364; евро пока записан последовательностью ASCII-знаков.
  2. Карта разрешает числовой код евро.
  3. Результат A€ — обычный текст с настоящим знаком валюты.
Аргумент / результатЧто передать и получить
stringВходной текст с десятичными/шестнадцатеричными числовыми ссылками.
mapПлоский массив групп по четыре: начало диапазона Unicode, конец включительно, смещение, битовая маска. При кодировании используется (codepoint + offset) & mask; для обычных ссылок offset=0, mask=0x10FFFF.
encoding = nullИмя кодировки исходных байтов. null или пропуск использует текущее mb_internal_encoding(); явное UTF-8 делает локальный пример независимым от чужих настроек. Это не преобразование входа.
returnПреобразованная строка; данные вне выбранных диапазонов остаются как были.
Прочитать две записи одной валютыСамостоятельный пример
<?php
$map = [0x80, 0x10FFFF, 0, 0x10FFFF];
echo mb_decode_numericentity('Цена: 5 &#8364;', $map, 'UTF-8'), "\n";
echo mb_decode_numericentity('Цена: 5 &#x20AC;', $map, 'UTF-8'), "\n";
Ожидаемый результат
Цена: 5 €
Цена: 5 €

Десятичная и шестнадцатеричная записи дали один знак. Карта состоит из групп по четыре числа. Именованная &amp; — другая форма: для общего набора HTML-сущностей смотрят html_entity_decode.

Раскодировать внешний текст, затем подготовить его к HTMLСамостоятельный пример
<?php
$map = [0, 0x10FFFF, 0, 0x10FFFF];
$text = mb_decode_numericentity('&#60;b&#62;Кисть&#60;/b&#62;', $map, 'UTF-8');
echo 'Полученные данные: ', $text, "\n";
echo 'Безопасный HTML-текст: ', htmlspecialchars($text, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'), "\n";
Ожидаемый результат
Полученные данные: <b>Кисть</b>
Безопасный HTML-текст: &lt;b&gt;Кисть&lt;/b&gt;

В CLI первая строка просто текст; если без экранирования поместить её в HTML, браузер воспримет тег. Поэтому декодирование и вывод — отдельные действия. Кавычки, теги и произвольные атрибуты нельзя объявлять доверенными после успешного преобразования.

Ошибки и границы. Количество элементов map должно делиться на четыре, иначе ValueError. С 8.4 непереводимые в int значения карты вызывают ValueError; допустимы int и неявно преобразуемые float/bool/null/числовые строки, но для ясности используйте целые. Неверная кодировка — ValueError; nullable encoding с 8.0. Именованные сущности вроде &amp; не входят в задачу числового декодера; для их набора есть html_entity_decode.

Рядом: mb_encode_numericentity, mb_chr, mb_ord. Байты, кодовые точки и графемы; общие правила вызова.

mb_strposВ текстовой заметке нужно найти первое упоминание метки и получить его позицию. mb_strpos считает кодовые точки, поэтому ответ можно передать в mb_substr. Регистр букв учитывается: Кисть и кисть различаются.

PHP 4.0.6+ · mbstring

mb_strpos(string $haystack, string $needle, int $offset = 0, ?string $encoding = null): int|false
Данные до и после вызова
  1. Кисть / Кисть — исходная строка; второе слово начинается с позиции 8.
  2. mb_strpos выбирает первое совпадение и возвращает 0.
  3. false означает отсутствие; успешный нулевой индекс нельзя принять за ошибку.
Аргумент / результатЧто передать и получить
haystackТекст, в котором ищем.
needleПодстрока в той же кодировке, не regex.
offsetНачало поиска в кодовых точках с нуля; отрицательный отсчитывается от конца. Возвращаемая позиция остаётся относительно начала всей строки.
encoding = nullИмя кодировки исходных байтов. null или пропуск использует текущее mb_internal_encoding(); явное UTF-8 делает локальный пример независимым от чужих настроек. Это не преобразование входа.
returnИндекс кодовой точки с нуля; false, если совпадения нет. Число 0 — успешное совпадение в начале.
Увидеть позицию найденного словаСамостоятельный пример
<?php
$text = 'Кисть / Кисть';
$position = mb_strpos($text, 'Кисть', 0, 'UTF-8');
if ($position !== false) {
    echo 'Найдено с позиции ', $position, "
";
    echo 'Фрагмент от позиции: ', mb_substr($text, $position, null, 'UTF-8'), "
";
}
Ожидаемый результат
Найдено с позиции 0
Фрагмент от позиции: Кисть / Кисть

Нумерация начинается с нуля. Даже при совпадении в начале условие !== false остаётся истинным. mb_substr принимает позицию в тех же единицах. Обычный substr воспринял бы её как байтовый индекс и мог разрезать русскую букву.

Получить нужную отметку из заметки о заказеСамостоятельный пример
<?php
$comment = 'заказ: принят; заказ: выдан';
$position = mb_strpos($comment, 'заказ:', 0, 'UTF-8');
if ($position === false) {
    echo "В заметке нет отметки заказа
";
} else {
    $note = mb_substr($comment, $position, null, 'UTF-8');
    echo 'Выбранная отметка: ', $note, "
";
}
Ожидаемый результат
Выбранная отметка: заказ: принят; заказ: выдан

Первый поиск сохраняет текст от первой отметки, включая последующие записи. Если поставщик допускает произвольный регистр метки, нужен регистронезависимый вариант. Для настоящего структурированного журнала с датами и полями лучше разбирать его формат, а не считать эту подстроку доказательством статуса заказа.

Показать понятный отказ вместо потерянного falseСамостоятельный пример
<?php
$position = mb_strpos('Доставка завтра', 'заказ:', 0, 'UTF-8');
if ($position === false) {
    echo "Метка не найдена: уточните текст заметки
";
}
$emptyNeedle = '';
if ($emptyNeedle === '') {
    echo "Введите непустой запрос поиска
";
}
Ожидаемый результат
Метка не найдена: уточните текст заметки
Введите непустой запрос поиска

Пустую строку PHP 8 разрешает как искомую, но для интерфейса поиска это часто лишено смысла. Поэтому правило формы проверяется до вызова. Слишком большой offset является отдельной ошибкой параметра. Регистронезависимость не означает Unicode-нормализацию или языковую коллацию.

Ошибки и границы. С PHP 8 пустой needle разрешён: определите заранее, нужен ли такой поиск вашему полю. Offset за допустимыми границами и неизвестная кодировка — ValueError; nullable encoding с 8.0. Отрицательные offsets добавлены в 7.1. Длина/позиция в символах не является длиной в байтах или графемах.

Рядом: mb_stripos, mb_strrpos, mb_substr. Байты, кодовые точки и графемы; общие правила вызова.

mb_striposВ текстовой заметке нужно найти первое упоминание метки и получить его позицию. mb_stripos считает кодовые точки, поэтому ответ можно передать в mb_substr. Регистр Unicode-букв при поиске не учитывается.

PHP 5.2+ · mbstring

mb_stripos(string $haystack, string $needle, int $offset = 0, ?string $encoding = null): int|false
Данные до и после вызова
  1. КИСТЬ / кисть — исходная строка; второе слово начинается с позиции 8.
  2. mb_stripos выбирает первое совпадение и возвращает 0.
  3. false означает отсутствие; успешный нулевой индекс нельзя принять за ошибку.
Аргумент / результатЧто передать и получить
haystackТекст, в котором ищем.
needleПодстрока в той же кодировке, не regex.
offsetНачало поиска в кодовых точках с нуля; отрицательный отсчитывается от конца. Возвращаемая позиция остаётся относительно начала всей строки.
encoding = nullИмя кодировки исходных байтов. null или пропуск использует текущее mb_internal_encoding(); явное UTF-8 делает локальный пример независимым от чужих настроек. Это не преобразование входа.
returnИндекс кодовой точки с нуля; false, если совпадения нет. Число 0 — успешное совпадение в начале.
Увидеть позицию найденного словаСамостоятельный пример
<?php
$text = 'КИСТЬ / кисть';
$position = mb_stripos($text, 'кисть', 0, 'UTF-8');
if ($position !== false) {
    echo 'Найдено с позиции ', $position, "
";
    echo 'Фрагмент от позиции: ', mb_substr($text, $position, null, 'UTF-8'), "
";
}
Ожидаемый результат
Найдено с позиции 0
Фрагмент от позиции: КИСТЬ / кисть

Нумерация начинается с нуля. Даже при совпадении в начале условие !== false остаётся истинным. mb_substr принимает позицию в тех же единицах. Обычный substr воспринял бы её как байтовый индекс и мог разрезать русскую букву.

Получить нужную отметку из заметки о заказеСамостоятельный пример
<?php
$comment = 'ЗАКАЗ: принят; заказ: выдан';
$position = mb_stripos($comment, 'заказ:', 0, 'UTF-8');
if ($position === false) {
    echo "В заметке нет отметки заказа
";
} else {
    $note = mb_substr($comment, $position, null, 'UTF-8');
    echo 'Выбранная отметка: ', $note, "
";
}
Ожидаемый результат
Выбранная отметка: ЗАКАЗ: принят; заказ: выдан

Первый поиск сохраняет текст от первой отметки, включая последующие записи. Слово ЗАКАЗ находится по запросу заказ, а исходное написание результата сохраняется. Для настоящего структурированного журнала с датами и полями лучше разбирать его формат, а не считать эту подстроку доказательством статуса заказа.

Показать понятный отказ вместо потерянного falseСамостоятельный пример
<?php
$position = mb_stripos('Доставка завтра', 'заказ:', 0, 'UTF-8');
if ($position === false) {
    echo "Метка не найдена: уточните текст заметки
";
}
$emptyNeedle = '';
if ($emptyNeedle === '') {
    echo "Введите непустой запрос поиска
";
}
Ожидаемый результат
Метка не найдена: уточните текст заметки
Введите непустой запрос поиска

Пустую строку PHP 8 разрешает как искомую, но для интерфейса поиска это часто лишено смысла. Поэтому правило формы проверяется до вызова. Слишком большой offset является отдельной ошибкой параметра. Регистронезависимость не означает Unicode-нормализацию или языковую коллацию.

Ошибки и границы. С PHP 8 пустой needle разрешён: определите заранее, нужен ли такой поиск вашему полю. Offset за допустимыми границами и неизвестная кодировка — ValueError; nullable encoding с 8.0. Отрицательные offsets добавлены в 7.1. Регистронезависимость не равна языковой коллации/Unicode-нормализации; не рассчитывайте, что любые визуально одинаковые или расширяющиеся формы совпадут. Длина/позиция в символах не является длиной в байтах или графемах.

Рядом: mb_strpos, mb_strrpos, mb_substr. Байты, кодовые точки и графемы; общие правила вызова.

mb_strrposВ текстовой заметке нужно найти последнее упоминание метки и получить его позицию. mb_strrpos считает кодовые точки, поэтому ответ можно передать в mb_substr. Регистр букв учитывается: Кисть и кисть различаются.

PHP 4.0.6+ · mbstring

mb_strrpos(string $haystack, string $needle, int $offset = 0, ?string $encoding = null): int|false
Данные до и после вызова
  1. Кисть / Кисть — исходная строка; второе слово начинается с позиции 8.
  2. mb_strrpos выбирает последнее совпадение и возвращает 8.
  3. false означает отсутствие; успешный нулевой индекс нельзя принять за ошибку.
Аргумент / результатЧто передать и получить
haystackТекст, в котором ищем.
needleПодстрока в той же кодировке, не regex.
offsetПри offset ≥ 0 ищет последнее совпадение в части начиная с этой позиции; отрицательный ограничивает правую границу поиска относительно конца. Возвращённая позиция всё равно от начала всей строки.
encoding = nullИмя кодировки исходных байтов. null или пропуск использует текущее mb_internal_encoding(); явное UTF-8 делает локальный пример независимым от чужих настроек. Это не преобразование входа.
returnИндекс кодовой точки с нуля; false, если совпадения нет. Число 0 — успешное совпадение в начале.
Увидеть позицию найденного словаСамостоятельный пример
<?php
$text = 'Кисть / Кисть';
$position = mb_strrpos($text, 'Кисть', 0, 'UTF-8');
if ($position !== false) {
    echo 'Найдено с позиции ', $position, "
";
    echo 'Фрагмент от позиции: ', mb_substr($text, $position, null, 'UTF-8'), "
";
}
Ожидаемый результат
Найдено с позиции 8
Фрагмент от позиции: Кисть

Нумерация начинается с нуля. Даже при совпадении в начале условие !== false остаётся истинным. mb_substr принимает позицию в тех же единицах. Обычный substr воспринял бы её как байтовый индекс и мог разрезать русскую букву.

Получить нужную отметку из заметки о заказеСамостоятельный пример
<?php
$comment = 'заказ: принят; заказ: выдан';
$position = mb_strrpos($comment, 'заказ:', 0, 'UTF-8');
if ($position === false) {
    echo "В заметке нет отметки заказа
";
} else {
    $note = mb_substr($comment, $position, null, 'UTF-8');
    echo 'Выбранная отметка: ', $note, "
";
}
Ожидаемый результат
Выбранная отметка: заказ: выдан

Последний поиск позволяет получить последнюю отметку в этом простом текстовом формате. Если поставщик допускает произвольный регистр метки, нужен регистронезависимый вариант. Для настоящего структурированного журнала с датами и полями лучше разбирать его формат, а не считать эту подстроку доказательством статуса заказа.

Показать понятный отказ вместо потерянного falseСамостоятельный пример
<?php
$position = mb_strrpos('Доставка завтра', 'заказ:', 0, 'UTF-8');
if ($position === false) {
    echo "Метка не найдена: уточните текст заметки
";
}
$emptyNeedle = '';
if ($emptyNeedle === '') {
    echo "Введите непустой запрос поиска
";
}
Ожидаемый результат
Метка не найдена: уточните текст заметки
Введите непустой запрос поиска

Пустую строку PHP 8 разрешает как искомую, но для интерфейса поиска это часто лишено смысла. Поэтому правило формы проверяется до вызова. Слишком большой offset является отдельной ошибкой параметра. Регистронезависимость не означает Unicode-нормализацию или языковую коллацию.

Ошибки и границы. С PHP 8 пустой needle разрешён: определите заранее, нужен ли такой поиск вашему полю. Offset за допустимыми границами и неизвестная кодировка — ValueError; nullable encoding с 8.0. С 8.0 нельзя передать encoding третьим аргументом вместо offset. Длина/позиция в символах не является длиной в байтах или графемах.

Рядом: mb_strpos, mb_stripos, mb_substr. Байты, кодовые точки и графемы; общие правила вызова.

mb_strriposВ текстовой заметке нужно найти последнее упоминание метки и получить его позицию. mb_strripos считает кодовые точки, поэтому ответ можно передать в mb_substr. Регистр Unicode-букв при поиске не учитывается.

PHP 5.2+ · mbstring

mb_strripos(string $haystack, string $needle, int $offset = 0, ?string $encoding = null): int|false
Данные до и после вызова
  1. КИСТЬ / кисть — исходная строка; второе слово начинается с позиции 8.
  2. mb_strripos выбирает последнее совпадение и возвращает 8.
  3. false означает отсутствие; успешный нулевой индекс нельзя принять за ошибку.
Аргумент / результатЧто передать и получить
haystackТекст, в котором ищем.
needleПодстрока в той же кодировке, не regex.
offsetПри offset ≥ 0 ищет последнее совпадение в части начиная с этой позиции; отрицательный ограничивает правую границу поиска относительно конца. Возвращённая позиция всё равно от начала всей строки.
encoding = nullИмя кодировки исходных байтов. null или пропуск использует текущее mb_internal_encoding(); явное UTF-8 делает локальный пример независимым от чужих настроек. Это не преобразование входа.
returnИндекс кодовой точки с нуля; false, если совпадения нет. Число 0 — успешное совпадение в начале.
Увидеть позицию найденного словаСамостоятельный пример
<?php
$text = 'КИСТЬ / кисть';
$position = mb_strripos($text, 'кисть', 0, 'UTF-8');
if ($position !== false) {
    echo 'Найдено с позиции ', $position, "
";
    echo 'Фрагмент от позиции: ', mb_substr($text, $position, null, 'UTF-8'), "
";
}
Ожидаемый результат
Найдено с позиции 8
Фрагмент от позиции: кисть

Нумерация начинается с нуля. Даже при совпадении в начале условие !== false остаётся истинным. mb_substr принимает позицию в тех же единицах. Обычный substr воспринял бы её как байтовый индекс и мог разрезать русскую букву.

Получить нужную отметку из заметки о заказеСамостоятельный пример
<?php
$comment = 'ЗАКАЗ: принят; заказ: выдан';
$position = mb_strripos($comment, 'заказ:', 0, 'UTF-8');
if ($position === false) {
    echo "В заметке нет отметки заказа
";
} else {
    $note = mb_substr($comment, $position, null, 'UTF-8');
    echo 'Выбранная отметка: ', $note, "
";
}
Ожидаемый результат
Выбранная отметка: заказ: выдан

Последний поиск позволяет получить последнюю отметку в этом простом текстовом формате. Слово ЗАКАЗ находится по запросу заказ, а исходное написание результата сохраняется. Для настоящего структурированного журнала с датами и полями лучше разбирать его формат, а не считать эту подстроку доказательством статуса заказа.

Показать понятный отказ вместо потерянного falseСамостоятельный пример
<?php
$position = mb_strripos('Доставка завтра', 'заказ:', 0, 'UTF-8');
if ($position === false) {
    echo "Метка не найдена: уточните текст заметки
";
}
$emptyNeedle = '';
if ($emptyNeedle === '') {
    echo "Введите непустой запрос поиска
";
}
Ожидаемый результат
Метка не найдена: уточните текст заметки
Введите непустой запрос поиска

Пустую строку PHP 8 разрешает как искомую, но для интерфейса поиска это часто лишено смысла. Поэтому правило формы проверяется до вызова. Слишком большой offset является отдельной ошибкой параметра. Регистронезависимость не означает Unicode-нормализацию или языковую коллацию.

Ошибки и границы. С PHP 8 пустой needle разрешён: определите заранее, нужен ли такой поиск вашему полю. Offset за допустимыми границами и неизвестная кодировка — ValueError; nullable encoding с 8.0. Регистронезависимость не равна языковой коллации/Unicode-нормализации; не рассчитывайте, что любые визуально одинаковые или расширяющиеся формы совпадут. Длина/позиция в символах не является длиной в байтах или графемах.

Рядом: mb_strpos, mb_stripos, mb_substr. Байты, кодовые точки и графемы; общие правила вызова.

mb_strstrВ подписи категории или простой служебной заметке нужно сразу получить часть текста до либо от первого совпадения. mb_strstr возвращает сам фрагмент, поэтому отдельное вычисление позиции не требуется. Поиск учитывает регистр букв.

PHP 5.2+ · mbstring

mb_strstr(string $haystack, string $needle, bool $before_needle = false, ?string $encoding = null): string|false
Данные до и после вызова
  1. Дом/Склад/Офис — исходная подпись из трёх частей.
  2. Поиск первого / делит её на Дом и /Склад/Офис.
  3. before_needle=true выбирает левую часть без разделителя; false — правую вместе с ним.
Аргумент / результатЧто передать и получить
haystackИсходный текст.
needleИскомая подстрока в той же кодировке. Даже у mb_strrchr/mb_strrichr современный PHP ищет всю переданную подстроку; это не байтовый strrchr с первым знаком.
before_needlefalse — вернуть от найденного вхождения до конца, включая needle; true — от начала до вхождения, исключая needle.
encoding = nullИмя кодировки исходных байтов. null или пропуск использует текущее mb_internal_encoding(); явное UTF-8 делает локальный пример независимым от чужих настроек. Это не преобразование входа.
returnЧасть исходного текста или false. Успешная часть может быть пустой строкой, поэтому используйте === false для отсутствия.
Выбрать нужную сторону от разделителяСамостоятельный пример
<?php
$path = 'Дом/Склад/Офис';
echo 'До разделителя: ', mb_strstr($path, '/', true, 'UTF-8'), "
";
echo 'От разделителя: ', mb_strstr($path, '/', false, 'UTF-8'), "
";
Ожидаемый результат
До разделителя: Дом
От разделителя: /Склад/Офис

Третий аргумент задаёт сторону, а не чувствительность к регистру. / входит только в правую часть. Это удобно для собственного простого формата подписи, если / запрещён внутри названий. Функция не разбирает путь файловой системы и не проверяет доступ к каталогу.

Получить отметку целиком и обработать её отсутствиеСамостоятельный пример
<?php
$comment = 'Статус: принят; Статус: выдан';
$part = mb_strstr($comment, 'Статус:', false, 'UTF-8');
echo $part === false ? "Отметка отсутствует
" : 'Найдено: ' . $part . "
";
$missing = mb_strstr($comment, 'Ошибка:', false, 'UTF-8');
if ($missing === false) {
    echo "В этой заметке нет метки ошибки
";
}
Ожидаемый результат
Найдено: Статус: принят; Статус: выдан
В этой заметке нет метки ошибки

Результат сохраняет исходные буквы, даже когда поиск не учитывает регистр. false означает, что подстроки не было. Это поиск в известном тексте, а не проверка реального состояния заказа: для работы с API используют структурированные поля ответа.

Не перепутать пустую левую часть и отсутствие меткиСамостоятельный пример
<?php
$before = mb_strstr('Кисть широкая', 'Кисть', true, 'UTF-8');
if ($before === false) {
    echo "Слово не найдено
";
} else {
    echo 'Слово найдено. До него: [', $before, "]
";
}
Ожидаемый результат
Слово найдено. До него: []

Метка стоит в начале, поэтому перед ней ничего нет. Это успешный пустой результат, а не false. Проверка if (!$before) смешала бы два разных исхода. В mb_strrchr/mb_strrichr текущего PHP искомая строка используется целиком; поведение нельзя переносить с байтовой strrchr.

Ошибки и границы. Пустой needle разрешён с 8.0; для такой границы возможен пустой успешный результат. Неизвестная кодировка — ValueError, nullable encoding с 8.0. С 8.3.2 before_needle=true для повреждённых/SJIS-mac строк согласован с общими индексами. Не разрезает графемы по их визуальному смыслу и не выполняет HTML-экранирование.

Рядом: mb_stristr, mb_strrchr, mb_substr. Байты, кодовые точки и графемы; общие правила вызова.

mb_stristrВ подписи категории или простой служебной заметке нужно сразу получить часть текста до либо от первого совпадения. mb_stristr возвращает сам фрагмент, поэтому отдельное вычисление позиции не требуется. Поиск не зависит от регистра Unicode-букв.

PHP 5.2+ · mbstring

mb_stristr(string $haystack, string $needle, bool $before_needle = false, ?string $encoding = null): string|false
Данные до и после вызова
  1. Дом/Склад/Офис — исходная подпись из трёх частей.
  2. Поиск первого / делит её на Дом и /Склад/Офис.
  3. before_needle=true выбирает левую часть без разделителя; false — правую вместе с ним.
Аргумент / результатЧто передать и получить
haystackИсходный текст.
needleИскомая подстрока в той же кодировке. Даже у mb_strrchr/mb_strrichr современный PHP ищет всю переданную подстроку; это не байтовый strrchr с первым знаком.
before_needlefalse — вернуть от найденного вхождения до конца, включая needle; true — от начала до вхождения, исключая needle.
encoding = nullИмя кодировки исходных байтов. null или пропуск использует текущее mb_internal_encoding(); явное UTF-8 делает локальный пример независимым от чужих настроек. Это не преобразование входа.
returnЧасть исходного текста или false. Успешная часть может быть пустой строкой, поэтому используйте === false для отсутствия.
Выбрать нужную сторону от разделителяСамостоятельный пример
<?php
$path = 'Дом/Склад/Офис';
echo 'До разделителя: ', mb_stristr($path, '/', true, 'UTF-8'), "
";
echo 'От разделителя: ', mb_stristr($path, '/', false, 'UTF-8'), "
";
Ожидаемый результат
До разделителя: Дом
От разделителя: /Склад/Офис

Третий аргумент задаёт сторону, а не чувствительность к регистру. / входит только в правую часть. Это удобно для собственного простого формата подписи, если / запрещён внутри названий. Функция не разбирает путь файловой системы и не проверяет доступ к каталогу.

Получить отметку целиком и обработать её отсутствиеСамостоятельный пример
<?php
$comment = 'Статус: принят; СТАТУС: выдан';
$part = mb_stristr($comment, 'статус:', false, 'UTF-8');
echo $part === false ? "Отметка отсутствует
" : 'Найдено: ' . $part . "
";
$missing = mb_stristr($comment, 'Ошибка:', false, 'UTF-8');
if ($missing === false) {
    echo "В этой заметке нет метки ошибки
";
}
Ожидаемый результат
Найдено: Статус: принят; СТАТУС: выдан
В этой заметке нет метки ошибки

Результат сохраняет исходные буквы, даже когда поиск не учитывает регистр. false означает, что подстроки не было. Это поиск в известном тексте, а не проверка реального состояния заказа: для работы с API используют структурированные поля ответа.

Не перепутать пустую левую часть и отсутствие меткиСамостоятельный пример
<?php
$before = mb_stristr('Кисть широкая', 'Кисть', true, 'UTF-8');
if ($before === false) {
    echo "Слово не найдено
";
} else {
    echo 'Слово найдено. До него: [', $before, "]
";
}
Ожидаемый результат
Слово найдено. До него: []

Метка стоит в начале, поэтому перед ней ничего нет. Это успешный пустой результат, а не false. Проверка if (!$before) смешала бы два разных исхода. В mb_strrchr/mb_strrichr текущего PHP искомая строка используется целиком; поведение нельзя переносить с байтовой strrchr.

Ошибки и границы. Пустой needle разрешён с 8.0; для такой границы возможен пустой успешный результат. Неизвестная кодировка — ValueError, nullable encoding с 8.0. Не разрезает графемы по их визуальному смыслу и не выполняет HTML-экранирование.

Рядом: mb_strstr, mb_strrchr, mb_substr. Байты, кодовые точки и графемы; общие правила вызова.

mb_strrchrВ подписи категории или простой служебной заметке нужно сразу получить часть текста до либо от последнего совпадения. mb_strrchr возвращает сам фрагмент, поэтому отдельное вычисление позиции не требуется. Поиск учитывает регистр букв.

PHP 5.2+ · mbstring

mb_strrchr(string $haystack, string $needle, bool $before_needle = false, ?string $encoding = null): string|false
Данные до и после вызова
  1. Дом/Склад/Офис — исходная подпись из трёх частей.
  2. Поиск последнего / делит её на Дом/Склад и /Офис.
  3. before_needle=true выбирает левую часть без разделителя; false — правую вместе с ним.
Аргумент / результатЧто передать и получить
haystackИсходный текст.
needleИскомая подстрока в той же кодировке. Даже у mb_strrchr/mb_strrichr современный PHP ищет всю переданную подстроку; это не байтовый strrchr с первым знаком.
before_needlefalse — вернуть от найденного вхождения до конца, включая needle; true — от начала до вхождения, исключая needle.
encoding = nullИмя кодировки исходных байтов. null или пропуск использует текущее mb_internal_encoding(); явное UTF-8 делает локальный пример независимым от чужих настроек. Это не преобразование входа.
returnЧасть исходного текста или false. Успешная часть может быть пустой строкой, поэтому используйте === false для отсутствия.
Выбрать нужную сторону от разделителяСамостоятельный пример
<?php
$path = 'Дом/Склад/Офис';
echo 'До разделителя: ', mb_strrchr($path, '/', true, 'UTF-8'), "
";
echo 'От разделителя: ', mb_strrchr($path, '/', false, 'UTF-8'), "
";
Ожидаемый результат
До разделителя: Дом/Склад
От разделителя: /Офис

Третий аргумент задаёт сторону, а не чувствительность к регистру. / входит только в правую часть. Это удобно для собственного простого формата подписи, если / запрещён внутри названий. Функция не разбирает путь файловой системы и не проверяет доступ к каталогу.

Получить отметку целиком и обработать её отсутствиеСамостоятельный пример
<?php
$comment = 'Статус: принят; Статус: выдан';
$part = mb_strrchr($comment, 'Статус:', false, 'UTF-8');
echo $part === false ? "Отметка отсутствует
" : 'Найдено: ' . $part . "
";
$missing = mb_strrchr($comment, 'Ошибка:', false, 'UTF-8');
if ($missing === false) {
    echo "В этой заметке нет метки ошибки
";
}
Ожидаемый результат
Найдено: Статус: выдан
В этой заметке нет метки ошибки

Результат сохраняет исходные буквы, даже когда поиск не учитывает регистр. false означает, что подстроки не было. Это поиск в известном тексте, а не проверка реального состояния заказа: для работы с API используют структурированные поля ответа.

Не перепутать пустую левую часть и отсутствие меткиСамостоятельный пример
<?php
$before = mb_strrchr('Кисть широкая', 'Кисть', true, 'UTF-8');
if ($before === false) {
    echo "Слово не найдено
";
} else {
    echo 'Слово найдено. До него: [', $before, "]
";
}
Ожидаемый результат
Слово найдено. До него: []

Метка стоит в начале, поэтому перед ней ничего нет. Это успешный пустой результат, а не false. Проверка if (!$before) смешала бы два разных исхода. В mb_strrchr/mb_strrichr текущего PHP искомая строка используется целиком; поведение нельзя переносить с байтовой strrchr.

Ошибки и границы. Пустой needle разрешён с 8.0; для такой границы возможен пустой успешный результат. Неизвестная кодировка — ValueError, nullable encoding с 8.0. Не разрезает графемы по их визуальному смыслу и не выполняет HTML-экранирование.

Рядом: mb_strstr, mb_stristr, mb_substr. Байты, кодовые точки и графемы; общие правила вызова.

mb_strrichrВ подписи категории или простой служебной заметке нужно сразу получить часть текста до либо от последнего совпадения. mb_strrichr возвращает сам фрагмент, поэтому отдельное вычисление позиции не требуется. Поиск не зависит от регистра Unicode-букв.

PHP 5.2+ · mbstring

mb_strrichr(string $haystack, string $needle, bool $before_needle = false, ?string $encoding = null): string|false
Данные до и после вызова
  1. Дом/Склад/Офис — исходная подпись из трёх частей.
  2. Поиск последнего / делит её на Дом/Склад и /Офис.
  3. before_needle=true выбирает левую часть без разделителя; false — правую вместе с ним.
Аргумент / результатЧто передать и получить
haystackИсходный текст.
needleИскомая подстрока в той же кодировке. Даже у mb_strrchr/mb_strrichr современный PHP ищет всю переданную подстроку; это не байтовый strrchr с первым знаком.
before_needlefalse — вернуть от найденного вхождения до конца, включая needle; true — от начала до вхождения, исключая needle.
encoding = nullИмя кодировки исходных байтов. null или пропуск использует текущее mb_internal_encoding(); явное UTF-8 делает локальный пример независимым от чужих настроек. Это не преобразование входа.
returnЧасть исходного текста или false. Успешная часть может быть пустой строкой, поэтому используйте === false для отсутствия.
Выбрать нужную сторону от разделителяСамостоятельный пример
<?php
$path = 'Дом/Склад/Офис';
echo 'До разделителя: ', mb_strrichr($path, '/', true, 'UTF-8'), "
";
echo 'От разделителя: ', mb_strrichr($path, '/', false, 'UTF-8'), "
";
Ожидаемый результат
До разделителя: Дом/Склад
От разделителя: /Офис

Третий аргумент задаёт сторону, а не чувствительность к регистру. / входит только в правую часть. Это удобно для собственного простого формата подписи, если / запрещён внутри названий. Функция не разбирает путь файловой системы и не проверяет доступ к каталогу.

Получить отметку целиком и обработать её отсутствиеСамостоятельный пример
<?php
$comment = 'Статус: принят; СТАТУС: выдан';
$part = mb_strrichr($comment, 'статус:', false, 'UTF-8');
echo $part === false ? "Отметка отсутствует
" : 'Найдено: ' . $part . "
";
$missing = mb_strrichr($comment, 'Ошибка:', false, 'UTF-8');
if ($missing === false) {
    echo "В этой заметке нет метки ошибки
";
}
Ожидаемый результат
Найдено: СТАТУС: выдан
В этой заметке нет метки ошибки

Результат сохраняет исходные буквы, даже когда поиск не учитывает регистр. false означает, что подстроки не было. Это поиск в известном тексте, а не проверка реального состояния заказа: для работы с API используют структурированные поля ответа.

Не перепутать пустую левую часть и отсутствие меткиСамостоятельный пример
<?php
$before = mb_strrichr('Кисть широкая', 'Кисть', true, 'UTF-8');
if ($before === false) {
    echo "Слово не найдено
";
} else {
    echo 'Слово найдено. До него: [', $before, "]
";
}
Ожидаемый результат
Слово найдено. До него: []

Метка стоит в начале, поэтому перед ней ничего нет. Это успешный пустой результат, а не false. Проверка if (!$before) смешала бы два разных исхода. В mb_strrchr/mb_strrichr текущего PHP искомая строка используется целиком; поведение нельзя переносить с байтовой strrchr.

Ошибки и границы. Пустой needle разрешён с 8.0; для такой границы возможен пустой успешный результат. Неизвестная кодировка — ValueError, nullable encoding с 8.0. Не разрезает графемы по их визуальному смыслу и не выполняет HTML-экранирование.

Рядом: mb_strstr, mb_stristr, mb_substr. Байты, кодовые точки и графемы; общие правила вызова.

mb_substr_countПеред сборкой уведомления нужно узнать, сколько раз шаблон использует метку номера заказа. mb_substr_count считает неперекрывающиеся вхождения буквальной подстроки. Это не число слов и не поиск по регулярному выражению.

PHP 4.3+ · mbstring

mb_substr_count(string $haystack, string $needle, ?string $encoding = null): int
Данные до и после вызова
  1. Шаблон содержит {{номер}} в двух местах.
  2. mb_substr_count возвращает 2 для точной метки.
  3. Затем str_replace подставляет 42, и получается готовое уведомление.
Аргумент / результатЧто передать и получить
haystackТекст для подсчёта.
needleНепустая подстрока, регистр учитывается.
encoding = nullИмя кодировки исходных байтов. null или пропуск использует текущее mb_internal_encoding(); явное UTF-8 делает локальный пример независимым от чужих настроек. Это не преобразование входа.
returnЦелое число неперекрывающихся совпадений, 0 при отсутствии.
Посчитать точные метки шаблонаСамостоятельный пример
<?php
$template = 'Заказ {{номер}} готов. Назовите {{номер}} на выдаче.';
echo 'Метка встречается: ', mb_substr_count($template, '{{номер}}', 'UTF-8'), " раза\n";
echo str_replace('{{номер}}', '42', $template), "\n";
Ожидаемый результат
Метка встречается: 2 раза
Заказ 42 готов. Назовите 42 на выдаче.

Подсчёт сам ничего не заменил. str_replace подходит для точной замены целой UTF-8-подстроки без mb-префикса. Если значения могут содержать другие метки, сравните поведение последовательных замен и strtr с картой.

Различить вхождение, слово и перекрытиеСамостоятельный пример
<?php
echo 'Пара аа внутри ааа: ', mb_substr_count('ааа', 'аа', 'UTF-8'), "\n";
echo 'Подстрока заказ: ', mb_substr_count('заказ заказчик', 'заказ', 'UTF-8'), "\n";
echo 'Метка с другим регистром: ', mb_substr_count('Заказ', 'заказ', 'UTF-8'), "\n";
Ожидаемый результат
Пара аа внутри ааа: 1
Подстрока заказ: 2
Метка с другим регистром: 0

После первого аа поиск продолжается за занятым диапазоном, поэтому перекрывающаяся пара не считается. В слове заказчик подстрока заказ тоже присутствует. Для числа самостоятельных слов нужны границы слов, а для нечувствительности к регистру — явно выбранная нормализация. Пустая искомая строка вызывает ValueError.

Ошибки и границы. Пустой needle вызывает ValueError в PHP 8; неизвестная кодировка также ValueError. null encoding разрешён с 8.0. Подсчёт подстрок не является подсчётом слов: заказ встречается внутри заказчик.

Рядом: mb_strpos, mb_stripos, mb_substr. Байты, кодовые точки и графемы; общие правила вызова.

mb_regex_encodingВ старом приложении используются mb_ereg и другие функции Oniguruma. Чтобы русский шаблон находил русское название, движок должен одинаково читать шаблон и текст. mb_regex_encoding задаёт именно эту настройку; кодировка обычных mb-строк хранится отдельно.

PHP 4.2+ · mbstring

mb_regex_encoding(?string $encoding = null): string|bool
Данные до и после вызова
  1. Шаблон Кисть и строка Кисть: 12 сохранены в UTF-8.
  2. Движок mbregex явно получает настройку UTF-8.
  3. Из найденного фрагмента извлекаем количество 12.
Аргумент / результатЧто передать и получить
encodingПоддерживаемое mbregex имя; null/пропуск читает текущее значение. Не каждая кодировка mb_convert_encoding доступна regex.
returnСтрока при чтении; true при успешной записи, сигнатура включает false.
Настроить движок и извлечь остаток товараСамостоятельный пример
<?php
$previous = mb_regex_encoding();
try {
    mb_regex_encoding('UTF-8');
    echo 'Движок читает: ', mb_regex_encoding(), "\n";
    if (mb_ereg('Кисть: ([0-9]+)', 'Кисть: 12', $parts)) {
        echo 'Остаток: ', $parts[1], " шт.\n";
    }
} finally {
    mb_regex_encoding($previous);
}
Ожидаемый результат
Движок читает: UTF-8
Остаток: 12 шт.

[0-9]+ означает одну или несколько цифр, скобки сохраняют их в группе 1. Шаблон mbregex не окружают разделителями /.../u из PCRE. try/finally возвращает прежнюю настройку, чтобы не повлиять на следующий код.

Увидеть две независимые настройкиСамостоятельный пример
<?php
$internal = mb_internal_encoding();
$regex = mb_regex_encoding();
try {
    mb_internal_encoding('ASCII');
    mb_regex_encoding('UTF-8');
    echo 'Строковые функции по умолчанию: ', mb_internal_encoding(), "\n";
    echo 'Регулярные выражения: ', mb_regex_encoding(), "\n";
    mb_ereg('(Кисть)', 'Кисть: 12', $parts);
    echo 'Найдено: ', $parts[1], "\n";
} finally {
    mb_internal_encoding($internal);
    mb_regex_encoding($regex);
}
Ожидаемый результат
Строковые функции по умолчанию: ASCII
Регулярные выражения: UTF-8
Найдено: Кисть

ASCII выбрана только для демонстрации независимости настроек; она не подходит как общий default русскоязычного сайта. mb_regex_encoding не перекодирует ни строку, ни шаблон. Если вход не UTF-8, сначала согласуют или преобразуют его кодировку.

Ошибки и границы. Неизвестная/неподдерживаемая regex-кодировка вызывает ValueError в PHP 8.5; null разрешён с 8.0. Глобальный default не позволяет независимо чередовать два stateful поиска без согласования.

Рядом: mb_internal_encoding, mb_regex_set_options, mb_ereg. Байты, кодовые точки и графемы; общие правила вызова.

mb_regex_set_optionsОдин и тот же шаблон должен либо учитывать регистр, либо принимать «заказ» и «ЗАКАЗ». Опции задают это поведение и выбранный синтаксис mbregex. Они не совпадают с привычными флагами preg_match; особенно различается смысл m.

PHP 4.3+ · mbstring

mb_regex_set_options(?string $options = null): string
Данные до и после вызова
  1. Без i шаблон заказ не находит ЗАКАЗ.
  2. С i находятся оба написания.
  3. Локальные options отдельной функции предпочтительнее изменения общего default для всего приложения.
Аргумент / результатЧто передать и получить
optionsСтрока флагов; один символ режима синтаксиса ставят последним. null/пропуск только читает.
returnВ PHP 8 запись возвращает предыдущие опции; чтение возвращает текущие. До PHP 8 запись возвращала новые.
ФлагСмысл
iРегистронезависимый поиск (ambiguity match)
xРасширенная запись шаблона с пробелами/комментариями по синтаксису движка
mТочка захватывает также перевод строки; не переносите сюда смысл PCRE m
s^/$ получают смысл \A/\Z
pВместе m и s
lПредпочитать длиннейшее совпадение
nИгнорировать пустые совпадения
eИсторическое выполнение замены как PHP; deprecated 7.1, удалено 8.0 — ValueError
РежимСинтаксис
jJava
uGNU regex
ggrep
cEmacs
rRuby
zPerl
bPOSIX Basic
dPOSIX Extended
Получить номер независимо от регистра подписиСамостоятельный пример
<?php
mb_regex_encoding('UTF-8');
$previous = mb_regex_set_options('ir');
try {
    if (mb_ereg('заказ ([0-9]+)', 'ЗАКАЗ 42', $parts)) {
        echo 'Номер: ', $parts[1], "\n";
    }
} finally {
    mb_regex_set_options($previous);
}
Ожидаемый результат
Номер: 42

i включает сопоставление без регистра, r выбирает Ruby-синтаксис. В PHP 8 setter возвращает предыдущую строку опций; её сохраняем для finally. Старые версии возвращали новые опции, поэтому старый пример восстановления надо читать с учётом версии.

Найти текст через перевод строки только при нужном флагеСамостоятельный пример
<?php
mb_regex_encoding('UTF-8');
$text = "Начало\nКонец";
foreach (['r', 'mr'] as $options) {
    $found = mb_ereg_match('Начало.Конец', $text, $options);
    echo $options, ': ', $found ? 'весь фрагмент найден' : 'точка не прошла перевод строки', "\n";
}
Ожидаемый результат
r: точка не прошла перевод строки
mr: весь фрагмент найден

В Oniguruma-флаге m точка захватывает перевод строки. Не переносите сюда значение PCRE m. Опции переданы непосредственно конкретному вызову: общий default не изменился. Для буквального поиска одной строки регулярное выражение вообще не требуется.

Ошибки и границы. Флаг e в PHP 8 — ValueError; старые инструкции с eval нельзя переносить. Синтаксический режим один, флагов несколько. Применимость/ошибки шаблона зависят от выбранного синтаксиса; произвольный набор букв не является безопасной пользовательской настройкой.

Рядом: mb_ereg_match, mb_ereg_replace, mb_regex_encoding. Байты, кодовые точки и графемы; общие правила вызова.

mb_eregВ уведомлении поставщика есть номер заказа внутри текста: «Заказ 42 готов». mb_ereg ищет фрагмент по шаблону и возвращает захваченные части через отдельную переменную. Регистр букв по умолчанию важен; для варианта без регистра есть mb_eregi.

PHP 4.2+ · mbstring

mb_ereg(string $pattern, string $string, array &$matches = null): bool
Данные до и после вызова
  1. Заказ 42 готов → шаблон Заказ ([0-9]+).
  2. Группа 0 содержит весь найденный фрагмент, группа 1 — только 42.
  3. Номер можно показать оператору или проверить по каталогу заказов.
Аргумент / результатЧто передать и получить
patternШаблон Oniguruma без разделителей /.../.
stringТекст в текущей mb_regex_encoding.
matchesНеобязательная выходная переменная: [0] — всё совпадение, [1] и далее — группы скобок; при отсутствии совпадения пустой массив.
returnВ PHP 8 true при найденном совпадении, false при отсутствии/ошибке. Это больше не длина совпадения.
Извлечь номер и увидеть состав массива совпаденияСамостоятельный пример
<?php
mb_regex_encoding('UTF-8');
$found = mb_ereg('Заказ ([0-9]+)', 'Заказ 42 готов', $parts);
if ($found) {
    echo 'Полный фрагмент: ', $parts[0], "\n";
    echo 'Номер: ', $parts[1], "\n";
}
Ожидаемый результат
Полный фрагмент: Заказ 42
Номер: 42

Скобки в шаблоне создают группу, [0-9] выбирает цифру, + разрешает несколько цифр подряд. $parts передаётся как выходная переменная; знак & уже указан в сигнатуре функции. Успешный ответ PHP 8 — bool, сам номер находится в $parts[1].

Разобрать полезную строку и сообщить о неподходящейСамостоятельный пример
<?php
mb_regex_encoding('UTF-8');
$messages = ['Заказ 42 готов', 'Поставка отложена'];
foreach ($messages as $message) {
    if (mb_ereg('Заказ ([0-9]+)', $message, $parts)) {
        echo 'Проверить заказ №', $parts[1], "\n";
    } else {
        echo 'В сообщении нет номера: ', $message, "\n";
    }
}
Ожидаемый результат
Проверить заказ №42
В сообщении нет номера: Поставка отложена

После неудачного поиска не читаем старые группы: в современных версиях массив очищается. Шаблон заранее известен и корректен; произвольная ошибка шаблона также может вернуть false с предупреждением, и её не следует называть обычным отсутствием номера. Извлечение цифр ещё не подтверждает существование заказа или право доступа к нему.

Ошибки и границы. Неверный шаблон вызывает E_WARNING и false; исчерпание ресурсов regex также нельзя приравнивать к нормальному отсутствию совпадения. Выбирайте короткий проверенный шаблон, ограниченный вход и не передавайте произвольный regex пользователя. Кодировка задаётся отдельно через mb_regex_encoding; regex-часть может отсутствовать в сборке. До 8.0 успешный результат мог быть длиной в байтах или 1; современный код должен ожидать bool.

Рядом: mb_ereg_match, mb_eregi, mb_ereg_search_regs. Байты, кодовые точки и графемы; общие правила вызова.

mb_eregiВ уведомлении поставщика есть номер заказа внутри текста: «ЗАКАЗ 42 готов». mb_eregi ищет фрагмент по шаблону и возвращает захваченные части через отдельную переменную. Регистр подписи при этом не важен.

PHP 4.2+ · mbstring

mb_eregi(string $pattern, string $string, array &$matches = null): bool
Данные до и после вызова
  1. ЗАКАЗ 42 готов → шаблон заказ ([0-9]+).
  2. Группа 0 содержит весь найденный фрагмент, группа 1 — только 42.
  3. Номер можно показать оператору или проверить по каталогу заказов.
Аргумент / результатЧто передать и получить
patternШаблон Oniguruma без разделителей /.../.
stringТекст в текущей mb_regex_encoding.
matchesНеобязательная выходная переменная: [0] — всё совпадение, [1] и далее — группы скобок; при отсутствии совпадения пустой массив.
returnВ PHP 8 true при найденном совпадении, false при отсутствии/ошибке. Это больше не длина совпадения.
Извлечь номер и увидеть состав массива совпаденияСамостоятельный пример
<?php
mb_regex_encoding('UTF-8');
$found = mb_eregi('заказ ([0-9]+)', 'ЗАКАЗ 42 готов', $parts);
if ($found) {
    echo 'Полный фрагмент: ', $parts[0], "\n";
    echo 'Номер: ', $parts[1], "\n";
}
Ожидаемый результат
Полный фрагмент: ЗАКАЗ 42
Номер: 42

Скобки в шаблоне создают группу, [0-9] выбирает цифру, + разрешает несколько цифр подряд. $parts передаётся как выходная переменная; знак & уже указан в сигнатуре функции. Успешный ответ PHP 8 — bool, сам номер находится в $parts[1].

Разобрать полезную строку и сообщить о неподходящейСамостоятельный пример
<?php
mb_regex_encoding('UTF-8');
$messages = ['ЗАКАЗ 42 готов', 'Поставка отложена'];
foreach ($messages as $message) {
    if (mb_eregi('заказ ([0-9]+)', $message, $parts)) {
        echo 'Проверить заказ №', $parts[1], "\n";
    } else {
        echo 'В сообщении нет номера: ', $message, "\n";
    }
}
Ожидаемый результат
Проверить заказ №42
В сообщении нет номера: Поставка отложена

После неудачного поиска не читаем старые группы: в современных версиях массив очищается. Шаблон заранее известен и корректен; произвольная ошибка шаблона также может вернуть false с предупреждением, и её не следует называть обычным отсутствием номера. Извлечение цифр ещё не подтверждает существование заказа или право доступа к нему.

Ошибки и границы. Неверный шаблон вызывает E_WARNING и false; исчерпание ресурсов regex также нельзя приравнивать к нормальному отсутствию совпадения. Выбирайте короткий проверенный шаблон, ограниченный вход и не передавайте произвольный regex пользователя. Кодировка задаётся отдельно через mb_regex_encoding; regex-часть может отсутствовать в сборке. До 8.0 успешный результат мог быть длиной в байтах или 1; современный код должен ожидать bool.

Рядом: mb_ereg_match, mb_ereg, mb_ereg_search_regs. Байты, кодовые точки и графемы; общие правила вызова.

mb_ereg_matchПеред поиском товара нужно принять артикул определённого вида: две латинские буквы, дефис, две цифры. mb_ereg_match начинает проверку с начала строки, но конец следует указать явно. Иначе правильный префикс может скрыть лишний текст.

PHP 4.2+ · mbstring

mb_ereg_match(string $pattern, string $string, ?string $options = null): bool
Данные до и после вызова
  1. AB-42 соответствует правилу целиком.
  2. AB-42! содержит подходящее начало, но лишний конец.
  3. Якорь \z требует конец строки и отклоняет лишний знак.
Аргумент / результатЧто передать и получить
patternШаблон, который автоматически сопоставляется с началом; для полного поля нужен якорь конца \z.
stringПроверяемый текст.
options = nullЛокальные флаги/один режим синтаксиса; null/пропуск использует текущие mb_regex_set_options. Флаги mbregex не равны флагам preg_*.
returntrue/false; captures не возвращаются.
Понять отличие подходящего начала от целого поляСамостоятельный пример
<?php
mb_regex_encoding('UTF-8');
echo mb_ereg_match('[0-9]+', '42x', 'r') ? "Префикс 42 подошёл\n" : "Не подошёл\n";
echo mb_ereg_match('[0-9]+\z', '42x', 'r') ? "Поле подошло\n" : "Поле целиком не число\n";
Ожидаемый результат
Префикс 42 подошёл
Поле целиком не число

Первый шаблон остановился после цифр и не потребовал конец. Второй использует \z. Это проверка формата, а не числового диапазона и не преобразование строки в int.

Показать причину допуска артикула к поискуСамостоятельный пример
<?php
mb_regex_encoding('UTF-8');
foreach (['AB-42', 'xx AB-42', 'AB-42!'] as $code) {
    $valid = mb_ereg_match('[A-Z]{2}-[0-9]{2}\z', $code, 'r');
    echo $code, ': ', $valid ? 'можно искать в каталоге' : 'нужен формат AB-42', "\n";
}
Ожидаемый результат
AB-42: можно искать в каталоге
xx AB-42: нужен формат AB-42
AB-42!: нужен формат AB-42

{2} требует ровно два знака; дефис здесь обычный литерал. Начало добавляет сама функция. Для ASCII-артикула preg_match тоже подходит; mbregex не обязателен. Успешный формат не означает, что товар существует.

Ошибки и границы. Неверный шаблон вызывает E_WARNING и false; исчерпание ресурсов regex также нельзя приравнивать к нормальному отсутствию совпадения. Выбирайте короткий проверенный шаблон, ограниченный вход и не передавайте произвольный regex пользователя. Кодировка задаётся отдельно через mb_regex_encoding; regex-часть может отсутствовать в сборке. options nullable с 8.0.

Рядом: mb_ereg, mb_regex_set_options, mb_check_encoding. Байты, кодовые точки и графемы; общие правила вызова.

mb_ereg_replaceРедактору нужно привести подписи заказов к новому формату, сохранив номера. Замена по шаблону находит подпись и захватывает число, затем вставляет его в новый текст. mb_ereg_replace учитывает регистр, если явно не выбраны другие опции.

PHP 4.2+ · mbstring

mb_ereg_replace(string $pattern, string $replacement, string $string, ?string $options = null): string|false|null
Данные до и после вызова
  1. Заказ 42; Заказ 43 содержит две подписи.
  2. ([0-9]+) сохраняет каждый номер отдельно.
  3. В результате появляются заявки №42 и №43, а оригинальная строка остаётся в своей переменной.
Аргумент / результатЧто передать и получить
patternШаблон Oniguruma.
replacementТекст замены; \1, \2… могут ссылаться на захваченные группы. В PHP-строке обратную косую нужно сохранить корректным quoting.
stringТекст для обработки.
options = nullЛокальные флаги/один режим синтаксиса; null/пропуск использует текущие mb_regex_set_options. Флаги mbregex не равны флагам preg_*.
returnНовая строка; false при regex-ошибке; null для недопустимых байтов текущей кодировки. Отсутствие совпадений оставляет строку.
Переименовать буквальную меткуСамостоятельный пример
<?php
mb_regex_encoding('UTF-8');
$text = 'Заказ 42; Заказ 43';
$result = mb_ereg_replace('Заказ', 'Заявка', $text);
echo $result, "\n";
echo 'Оригинал: ', $text, "\n";
Ожидаемый результат
Заявка 42; Заявка 43
Оригинал: Заказ 42; Заказ 43

Это простейший шаг без групп. Если нужна только буквальная замена с учётом регистра, str_replace проще. mbregex имеет смысл, когда правило действительно содержит шаблон, как в следующем примере.

Перенести найденные номера в новую подписьСамостоятельный пример
<?php
mb_regex_encoding('UTF-8');
$text = 'Заказ 42; Заказ 43';
$result = mb_ereg_replace('Заказ ([0-9]+)', 'Заявка №\\1', $text);
if ($result === false || $result === null) {
    throw new RuntimeException('Не удалось преобразовать подписи');
}
echo $result, "\n";
Ожидаемый результат
Заявка №42; Заявка №43

В одинарной PHP-строке две обратные косые дают одну для механизма замены; \1 означает первую захваченную группу. false и null проверяют строго: это ошибки, а не готовая пустая строка. Для вычисляемой замены используют callback, не выполнение сгенерированного PHP-кода.

Ошибки и границы. Неверный шаблон вызывает E_WARNING и false; исчерпание ресурсов regex также нельзя приравнивать к нормальному отсутствию совпадения. Выбирайте короткий проверенный шаблон, ограниченный вход и не передавайте произвольный regex пользователя. Кодировка задаётся отдельно через mb_regex_encoding; regex-часть может отсутствовать в сборке. Проверка корректности входа с результатом null введена в 7.1; options nullable с 8.0. Старый eval-флаг e deprecated с 7.1 и удалён в 8.0: применяется callback, не eval.

Рядом: mb_ereg_replace_callback, mb_eregi_replace, mb_regex_set_options. Байты, кодовые точки и графемы; общие правила вызова.

mb_eregi_replaceРедактору нужно привести подписи заказов к новому формату, сохранив номера. Замена по шаблону находит подпись и захватывает число, затем вставляет его в новый текст. mb_eregi_replace принимает разные регистры подписи.

PHP 4.2+ · mbstring

mb_eregi_replace(string $pattern, string $replacement, string $string, ?string $options = null): string|false|null
Данные до и после вызова
  1. ЗАКАЗ 42; Заказ 43 содержит две подписи.
  2. ([0-9]+) сохраняет каждый номер отдельно.
  3. В результате появляются заявки №42 и №43, а оригинальная строка остаётся в своей переменной.
Аргумент / результатЧто передать и получить
patternШаблон Oniguruma.
replacementТекст замены; \1, \2… могут ссылаться на захваченные группы. В PHP-строке обратную косую нужно сохранить корректным quoting.
stringТекст для обработки.
options = nullЛокальные флаги/один режим синтаксиса; null/пропуск использует текущие mb_regex_set_options. Флаги mbregex не равны флагам preg_*.
returnНовая строка; false при regex-ошибке; null для недопустимых байтов текущей кодировки. Отсутствие совпадений оставляет строку.
Переименовать буквальную меткуСамостоятельный пример
<?php
mb_regex_encoding('UTF-8');
$text = 'ЗАКАЗ 42; Заказ 43';
$result = mb_eregi_replace('заказ', 'Заявка', $text);
echo $result, "\n";
echo 'Оригинал: ', $text, "\n";
Ожидаемый результат
Заявка 42; Заявка 43
Оригинал: ЗАКАЗ 42; Заказ 43

Это простейший шаг без групп. Если нужна только буквальная замена с учётом регистра, str_replace проще. mbregex имеет смысл, когда правило действительно содержит шаблон, как в следующем примере.

Перенести найденные номера в новую подписьСамостоятельный пример
<?php
mb_regex_encoding('UTF-8');
$text = 'ЗАКАЗ 42; Заказ 43';
$result = mb_eregi_replace('заказ ([0-9]+)', 'Заявка №\\1', $text);
if ($result === false || $result === null) {
    throw new RuntimeException('Не удалось преобразовать подписи');
}
echo $result, "\n";
Ожидаемый результат
Заявка №42; Заявка №43

В одинарной PHP-строке две обратные косые дают одну для механизма замены; \1 означает первую захваченную группу. false и null проверяют строго: это ошибки, а не готовая пустая строка. Для вычисляемой замены используют callback, не выполнение сгенерированного PHP-кода.

Ошибки и границы. Неверный шаблон вызывает E_WARNING и false; исчерпание ресурсов regex также нельзя приравнивать к нормальному отсутствию совпадения. Выбирайте короткий проверенный шаблон, ограниченный вход и не передавайте произвольный regex пользователя. Кодировка задаётся отдельно через mb_regex_encoding; regex-часть может отсутствовать в сборке. Проверка корректности входа с результатом null введена в 7.1; options nullable с 8.0. Старый eval-флаг e deprecated с 7.1 и удалён в 8.0: применяется callback, не eval.

Рядом: mb_ereg_replace_callback, mb_ereg_replace, mb_regex_set_options. Байты, кодовые точки и графемы; общие правила вызова.

mb_ereg_replace_callbackТекст уведомления содержит метки {{товар}} и {{город}}, а значения уже получены из заказа. Callback получает каждое найденное совпадение и возвращает подходящую подстановку. Так обычная PHP-функция участвует в построении текста без eval и без ручного поиска каждого места.

PHP 5.4.1+ · mbstring

mb_ereg_replace_callback(string $pattern, callable $callback, string $string, ?string $options = null): string|false|null
Данные до и после вызова
  1. Движок находит {{товар}}.
  2. Callback получает массив: [0]={{товар}}, [1]=товар.
  3. return отдаёт Кисть, и она занимает место метки в готовом уведомлении.
Аргумент / результатЧто передать и получить
patternШаблон поиска.
callbackВызываемая функция получает массив captures и должна вернуть строку замены. matches[0] — всё, [1] и далее — группы.
stringТекст для обработки.
options = nullЛокальные флаги/один режим синтаксиса; null/пропуск использует текущие mb_regex_set_options. Флаги mbregex не равны флагам preg_*.
returnНовая строка; false при regex-ошибке; null при неверной кодировке входа. Исключение callback проходит наружу.
Проследить один вызов и возвращённую заменуСамостоятельный пример
<?php
mb_regex_encoding('UTF-8');
function nextPlace($parts) {
    return 'место ' . ((int) $parts[1] + 1);
}
$text = mb_ereg_replace_callback('место ([0-9]+)', 'nextPlace', 'место 4; место 8');
echo $text, "\n";
Ожидаемый результат
место 5; место 9

Функцию nextPlace вызывает движок дважды. В первый раз группа 1 содержит строку 4, приведение int и +1 дают число 5; return отдаёт строку «место 5». Во второй раз аналогично получается 9. echo внутри callback здесь не нужен: текст возвращается в замену.

Заполнить метки конкретного уведомленияСамостоятельный пример
<?php
mb_regex_encoding('UTF-8');
$values = ['товар' => 'Кисть', 'город' => 'Тула'];
$template = '{{товар}} ждёт вас: {{город}}. Цена: {{цена}}.';
$result = mb_ereg_replace_callback('\{\{([а-я]+)\}\}', function ($parts) use ($values) {
    return $values[$parts[1]] ?? $parts[0];
}, $template);
if ($result === false || $result === null) {
    throw new RuntimeException('Не удалось собрать уведомление');
}
echo $result, "\n";
Ожидаемый результат
Кисть ждёт вас: Тула. Цена: {{цена}}.

use передаёт готовую карту замыканию. Неизвестная метка осталась заметной — отправку такого сообщения можно отклонить на следующем шаге. Шаблон допускает только заданный набор русских букв; это намеренно маленький текстовый формат. HTML-шаблону потребуются контекстные правила экранирования. Данные лучше получить до callback, а не выполнять запрос на каждую метку.

Ошибки и границы. Неверный шаблон вызывает E_WARNING и false; исчерпание ресурсов regex также нельзя приравнивать к нормальному отсутствию совпадения. Выбирайте короткий проверенный шаблон, ограниченный вход и не передавайте произвольный regex пользователя. Кодировка задаётся отдельно через mb_regex_encoding; regex-часть может отсутствовать в сборке. Невызываемый callback — TypeError. Неверная строка даёт null с 7.1, options nullable с 8.0. Не выполняйте сетевой запрос внутри callback для каждого слова: сначала получите данные и передайте готовую карту.

Рядом: mb_ereg_replace, mb_ereg, mb_regex_set_options. Байты, кодовые точки и графемы; общие правила вызова.

mb_splitВ простом списке категорий пользователь может поставить запятую или точку с запятой. mb_split разбивает текст по regex-разделителю и возвращает массив. Когда разделитель один и буквально известен, достаточно explode; CSV с кавычками требует отдельного парсера.

PHP 4.2+ · mbstring

mb_split(string $pattern, string $string, int $limit = -1): array|false
Данные до и после вызова
  1. Кисти,Валики;Перчатки — одна строка.
  2. [,;] выбирает каждый из двух разделителей.
  3. Получается массив из трёх названий для дальнейшей проверки.
Аргумент / результатЧто передать и получить
patternRegex-разделитель, не буквальная строка.
stringТекст в mb_regex_encoding.
limitПоложительный максимум частей; последняя содержит остаток. Отрицательный — без ограничения. В 8.5 значение 0 ведёт себя как 1; используйте -1 или явное положительное.
returnМассив частей; false при ошибке. Пустые части на границах могут сохраняться.
Получить и вывести все названияСамостоятельный пример
<?php
mb_regex_encoding('UTF-8');
$categories = mb_split('[,;]', 'Кисти,Валики;Перчатки');
foreach ($categories as $number => $category) {
    echo $number + 1, '. ', $category, "\n";
}
Ожидаемый результат
1. Кисти
2. Валики
3. Перчатки

Квадратные скобки внутри шаблона означают один символ из набора. foreach проходит полученный массив. Для внешнего поля результат сначала проверяют на false и ограничивают размер; здесь шаблон и вход фиксированы.

Оставить описание целым после первой меткиСамостоятельный пример
<?php
mb_regex_encoding('UTF-8');
$parts = mb_split(':', 'товар:Кисть:широкая', 2);
echo 'Тип записи: ', $parts[0], "\n";
echo 'Описание: ', $parts[1], "\n";
Ожидаемый результат
Тип записи: товар
Описание: Кисть:широкая

Лимит 2 разрешает не более двух частей, поэтому остаток содержит второе двоеточие. До обращения к элементу 1 у произвольного ввода проверяют число частей. Для строго буквального двоеточия explode с тем же лимитом проще.

Увидеть пустые категории на границахСамостоятельный пример
<?php
mb_regex_encoding('UTF-8');
$parts = mb_split('[,;]', ';Кисти,,Валики;');
foreach ($parts as $index => $part) {
    echo $index, ': [', $part, "]\n";
}
Ожидаемый результат
0: []
1: [Кисти]
2: []
3: [Валики]
4: []

Разделитель не означает автоматическую валидацию списка. Пустые элементы можно явно отклонить или удалить по правилам формы. Не применяйте этот способ к CSV, где запятая может находиться внутри кавычек.

Ошибки и границы. Неверный шаблон вызывает E_WARNING и false; исчерпание ресурсов regex также нельзя приравнивать к нормальному отсутствию совпадения. Выбирайте короткий проверенный шаблон, ограниченный вход и не передавайте произвольный regex пользователя. Кодировка задаётся отдельно через mb_regex_encoding; regex-часть может отсутствовать в сборке. Большой вход без limit создаёт большой массив. Не путайте mb_str_split (фиксированные группы символов) и mb_split (regex-разделитель).

Рядом: mb_ereg, mb_str_split, mb_regex_encoding. Байты, кодовые точки и графемы; общие правила вызова.

mb_ereg_search_initНужно последовательно извлечь номера из длинного уведомления, а не искать всё заново с начала. init сохраняет текст и шаблон для семейства mb_ereg_search_*. Это только подготовка: результат появится при следующем поисковом вызове.

PHP 4.2+ · mbstring

mb_ereg_search_init(string $string, ?string $pattern = null, ?string $options = null): bool
Данные до и после вызова
  1. Текст №42; №43 сохраняется вместе с шаблоном цифр.
  2. Курсор устанавливается на байт 0.
  3. Первый search_regs найдёт 42, второй — 43.
Аргумент / результатЧто передать и получить
stringНовый текст; курсор начинается с нуля.
pattern = nullНовый шаблон или null для последнего установленного через init/поиск. Не означает любой текст.
options = nullЛокальные флаги/один режим синтаксиса; null/пропуск использует текущие mb_regex_set_options. Флаги mbregex не равны флагам preg_*.
returntrue при успешной подготовке; false при ошибке. Само совпадение ещё не извлекается.

Перед поиском вызовите mb_ereg_search_init с собственным текстом и непустым шаблоном. Состояние одно на текущий контекст; вложенный init его заменит. Примеры используют UTF-8 и шаблоны, которые не совпадают с пустой строкой. Позиции этого семейства — байты, а не индексы mb_substr.

Отделить подготовку от извлечения номераСамостоятельный пример
<?php
mb_regex_encoding('UTF-8');
mb_ereg_search_init('№42; №43', '[0-9]+');
echo 'Курсор после подготовки: ', mb_ereg_search_getpos(), "\n";
$parts = mb_ereg_search_regs();
echo 'Первый номер: ', $parts[0], "\n";
$parts = mb_ereg_search_regs();
echo 'Второй номер: ', $parts[0], "\n";
Ожидаемый результат
Курсор после подготовки: 0
Первый номер: 42
Второй номер: 43

Два вызова regs продолжают один поиск, а не повторяют первый. [0-9]+ не может совпасть с пустой строкой, поэтому курсор продвигается. В произвольном вводе каждый результат проверяют на false до чтения [0].

Обработать два уведомления, заново подготовив каждоеСамостоятельный пример
<?php
mb_regex_encoding('UTF-8');
$messages = ['Сегодня №42; №43', 'Завтра №50'];
foreach ($messages as $message) {
    mb_ereg_search_init($message, '[0-9]+');
    echo 'Уведомление: ', $message, "\n";
    while (($parts = mb_ereg_search_regs()) !== false) {
        echo '  Проверить заказ ', $parts[0], "\n";
    }
}
Ожидаемый результат
Уведомление: Сегодня №42; №43
  Проверить заказ 42
  Проверить заказ 43
Уведомление: Завтра №50
  Проверить заказ 50

Новый init заменяет предыдущий текст и состояние. Поэтому его нельзя неожиданно вызывать внутри callback другого активного поиска. Этот учебный формат содержит только номера заказов; для произвольных уведомлений уточняют шаблон, чтобы не спутать заказ с датой или суммой.

Ошибки и границы. Неверный шаблон вызывает E_WARNING и false; исчерпание ресурсов regex также нельзя приравнивать к нормальному отсутствию совпадения. Выбирайте короткий проверенный шаблон, ограниченный вход и не передавайте произвольный regex пользователя. Кодировка задаётся отдельно через mb_regex_encoding; regex-часть может отсутствовать в сборке. pattern/options nullable с 8.0. Устанавливайте pattern явно для независимого разбора, вместо надежды на оставшийся от предыдущей операции.

Рядом: mb_ereg_search_regs, mb_ereg_search_getpos, mb_regex_encoding. Байты, кодовые точки и графемы; общие правила вызова.

mb_ereg_search_posКроме самого номера бывает нужно знать его место в исходном тексте: для разбора протокола, отметки проблемного участка или последующей замены. search_pos возвращает байтовое начало и длину следующего совпадения. Эти числа можно передать substr для той же неизменённой строки.

PHP 4.2+ · mbstring

mb_ereg_search_pos(?string $pattern = null, ?string $options = null): array|false
Данные до и после вызова
  1. В №42 знак № занимает три байта UTF-8.
  2. Цифры 42 начинаются с байта 3 и занимают 2 байта.
  3. substr($text, 3, 2) возвращает именно 42.
Аргумент / результатЧто передать и получить
pattern = nullНовый шаблон или null для последнего установленного через init/поиск. Не означает любой текст.
options = nullЛокальные флаги/один режим синтаксиса; null/пропуск использует текущие mb_regex_set_options. Флаги mbregex не равны флагам preg_*.
return[offset, length] в байтах от начала исходного текста; false при отсутствии/ошибке. Вызов передвигает курсор.

Перед поиском вызовите mb_ereg_search_init с собственным текстом и непустым шаблоном. Состояние одно на текущий контекст; вложенный init его заменит. Примеры используют UTF-8 и шаблоны, которые не совпадают с пустой строкой. Позиции этого семейства — байты, а не индексы mb_substr.

Применить найденные координаты к исходной строкеСамостоятельный пример
<?php
mb_regex_encoding('UTF-8');
$text = '№42; №43';
mb_ereg_search_init($text, '[0-9]+');
$range = mb_ereg_search_pos();
echo 'Начало: ', $range[0], '; длина: ', $range[1], " байта\n";
echo 'Фрагмент: ', substr($text, $range[0], $range[1]), "\n";
Ожидаемый результат
Начало: 3; длина: 2 байта
Фрагмент: 42

Массив содержит координаты, а не группы. mb_substr здесь был бы ошибкой: у него индексы символов, а у полученных координат единицы — байты. Текст нельзя перекодировать или изменить до использования диапазона.

Показать положение каждого найденного номераСамостоятельный пример
<?php
mb_regex_encoding('UTF-8');
$text = '№42; №43';
mb_ereg_search_init($text, '[0-9]+');
while (($range = mb_ereg_search_pos()) !== false) {
    echo 'Байт ', $range[0], ': заказ ', substr($text, $range[0], $range[1]), "\n";
}
Ожидаемый результат
Байт 3: заказ 42
Байт 10: заказ 43

Второй диапазон начинается на байте 10, хотя по видимым знакам кажется ближе. В браузере индексы JavaScript имеют ещё другую единицу — UTF-16; байтовые координаты нельзя напрямую использовать для выделения текста в DOM. Для захваченных полей удобнее search_regs.

Ошибки и границы. Неверный шаблон вызывает E_WARNING и false; исчерпание ресурсов regex также нельзя приравнивать к нормальному отсутствию совпадения. Выбирайте короткий проверенный шаблон, ограниченный вход и не передавайте произвольный regex пользователя. Кодировка задаётся отдельно через mb_regex_encoding; regex-часть может отсутствовать в сборке. Требуется init; pattern/options nullable с 8.0. Не смешивайте единицы измерения при подсветке в браузере, где индекс JavaScript строки обычно в UTF-16 кодовых единицах.

Рядом: mb_ereg_search_regs, mb_ereg_search_getpos, mb_strpos. Байты, кодовые точки и графемы; общие правила вызова.

mb_ereg_search_regsУведомление содержит пары «заказ — состояние». search_regs за один вызов находит следующую пару и возвращает группы: номер отдельно, состояние отдельно. Так текст можно превратить в обычные записи массива, которые дальше удобно перебирать.

PHP 4.2+ · mbstring

mb_ereg_search_regs(?string $pattern = null, ?string $options = null): array|false
Данные до и после вызова
  1. Заказ 42: готов → группа 1 равна 42, группа 2 равна готов.
  2. Следующий вызов даёт Заказ 43: отложен.
  3. После исчерпания текста возвращается false, цикл завершается.
Аргумент / результатЧто передать и получить
pattern = nullНовый шаблон или null для последнего установленного через init/поиск. Не означает любой текст.
options = nullЛокальные флаги/один режим синтаксиса; null/пропуск использует текущие mb_regex_set_options. Флаги mbregex не равны флагам preg_*.
returnМассив: [0] полный фрагмент, [1] первая группа и далее; false при отсутствии/ошибке. Это новый поиск, не чтение старого результата.

Перед поиском вызовите mb_ereg_search_init с собственным текстом и непустым шаблоном. Состояние одно на текущий контекст; вложенный init его заменит. Примеры используют UTF-8 и шаблоны, которые не совпадают с пустой строкой. Позиции этого семейства — байты, а не индексы mb_substr.

Увидеть полное совпадение и две его частиСамостоятельный пример
<?php
mb_regex_encoding('UTF-8');
mb_ereg_search_init('Заказ 42: готов', 'Заказ ([0-9]+): ([а-я]+)');
$parts = mb_ereg_search_regs();
echo 'Фрагмент: ', $parts[0], "\n";
echo 'Номер: ', $parts[1], "\n";
echo 'Состояние: ', $parts[2], "\n";
Ожидаемый результат
Фрагмент: Заказ 42: готов
Номер: 42
Состояние: готов

Каждая пара круглых скобок создаёт свою группу. [а-я]+ — учебное ограничение состояний, не полноценное правило для всех русских слов: например, ё вне этого диапазона. Для реального протокола лучше перечислить допустимые состояния.

Собрать записи и вывести человекуСамостоятельный пример
<?php
mb_regex_encoding('UTF-8');
$text = 'Заказ 42: готов; Заказ 43: отложен';
mb_ereg_search_init($text, 'Заказ ([0-9]+): (готов|отложен)');
$orders = [];
while (($parts = mb_ereg_search_regs()) !== false) {
    $orders[] = ['id' => (int) $parts[1], 'status' => $parts[2]];
}
foreach ($orders as $order) {
    echo 'Заказ №', $order['id'], ' — ', $order['status'], "\n";
}
Ожидаемый результат
Заказ №42 — готов
Заказ №43 — отложен

Вертикальная черта выбирает готов или отложен. После разбора уже не надо искать строковые фрагменты: в массиве есть id и status. Это извлечение из учебного формата; строгий импорт дополнительно выявляет пропущенные или лишние участки, дубликаты и слишком большие номера.

Ошибки и границы. Неверный шаблон вызывает E_WARNING и false; исчерпание ресурсов regex также нельзя приравнивать к нормальному отсутствию совпадения. Выбирайте короткий проверенный шаблон, ограниченный вход и не передавайте произвольный regex пользователя. Кодировка задаётся отдельно через mb_regex_encoding; regex-часть может отсутствовать в сборке. init обязателен; pattern/options nullable с 8.0. Не вызывайте regs только ради чтения найденного ранее: он уже перейдёт к следующему.

Рядом: mb_ereg_search_init, mb_ereg_search_getregs, mb_ereg_search_pos. Байты, кодовые точки и графемы; общие правила вызова.

mb_ereg_search_getposПарсер уже прочитал один номер. Чтобы временно заглянуть вперёд и затем вернуться, нужно сохранить текущую позицию. getpos возвращает байтовый курсор следующего поиска, не изменяя его и не извлекая новый номер.

PHP 4.2+ · mbstring

mb_ereg_search_getpos(): int
Данные до и после вызова
  1. После номера 42 курсор находится на байте 5.
  2. Закладка 5 сохраняется в собственной переменной.
  3. Следующее извлечение даёт 43; закладка пригодится для повторного чтения.
Аргумент / результатЧто передать и получить
ПараметрыНет. Работает с общим stateful поиском.
returnБайтовое смещение от начала текста. После совпадения обычно указывает сразу за ним; до первого поиска после init — 0.

Перед поиском вызовите mb_ereg_search_init с собственным текстом и непустым шаблоном. Состояние одно на текущий контекст; вложенный init его заменит. Примеры используют UTF-8 и шаблоны, которые не совпадают с пустой строкой. Позиции этого семейства — байты, а не индексы mb_substr.

Посмотреть курсор до и после поискаСамостоятельный пример
<?php
mb_regex_encoding('UTF-8');
mb_ereg_search_init('№42; №43', '[0-9]+');
echo 'До поиска: ', mb_ereg_search_getpos(), "\n";
$parts = mb_ereg_search_regs();
echo 'Прочитан номер: ', $parts[0], "\n";
echo 'После поиска: ', mb_ereg_search_getpos(), "\n";
Ожидаемый результат
До поиска: 0
Прочитан номер: 42
После поиска: 5

Три байта № и два байта цифр дают курсор 5. Он не означает пять символов или пять найденных заказов. getpos показывает позицию продолжения; search_pos отдельно возвращает начало и длину самого совпадения.

Сохранить место перед предварительным чтениемСамостоятельный пример
<?php
mb_regex_encoding('UTF-8');
mb_ereg_search_init('№42; №43', '[0-9]+');
mb_ereg_search_regs();
$bookmark = mb_ereg_search_getpos();
$preview = mb_ereg_search_regs();
echo 'Предварительно увидели: ', $preview[0], "\n";
mb_ereg_search_setpos($bookmark);
$accepted = mb_ereg_search_regs();
echo 'Прочитали при обработке: ', $accepted[0], "\n";
Ожидаемый результат
Предварительно увидели: 43
Прочитали при обработке: 43

Такое чтение вперёд бывает нужно небольшому парсеру. Закладка относится только к той же строке и состоянию; после другого init её нельзя переносить. Для независимых вложенных парсеров лучше собственный объект с курсором.

Ошибки и границы. Вызов не принимает аргументов и не начинает поиск. Порядок вызовов должен быть явным: не используйте случайное состояние от чужого кода как закладку.

Рядом: mb_ereg_search_setpos, mb_ereg_search_pos, mb_ereg_search_init. Байты, кодовые точки и графемы; общие правила вызова.

mb_ereg_search_setposПосле предварительного просмотра следующего номера нужно обработать его ещё раз. setpos возвращает курсор на сохранённую байтовую границу. Сам setter не ищет совпадение: результат появится только при следующем search-вызове.

PHP 4.2+ · mbstring

mb_ereg_search_setpos(int $offset): bool
Данные до и после вызова
  1. Сохранили курсор после заказа 42.
  2. Предварительно прочитали 43.
  3. Вернули сохранённую позицию и получили 43 снова.
Аргумент / результатЧто передать и получить
offsetБайтовая позиция; отрицательная — от конца строки (с 7.1). Выбирайте границу символа, полученную из самого поиска или проверенного формата.
returntrue при успешной установке; сигнатура включает false. Не извлекает совпадение.

Перед поиском вызовите mb_ereg_search_init с собственным текстом и непустым шаблоном. Состояние одно на текущий контекст; вложенный init его заменит. Примеры используют UTF-8 и шаблоны, которые не совпадают с пустой строкой. Позиции этого семейства — байты, а не индексы mb_substr.

Повторить чтение с началаСамостоятельный пример
<?php
mb_regex_encoding('UTF-8');
mb_ereg_search_init('№42; №43', '[0-9]+');
echo 'Первый раз: ', mb_ereg_search_regs()[0], "\n";
mb_ereg_search_setpos(0);
echo 'После возврата: ', mb_ereg_search_regs()[0], "\n";
Ожидаемый результат
Первый раз: 42
После возврата: 42

Ноль — безопасная байтовая граница начала строки. В реальном входе перед чтением [0] проверяют false. Если внутри цикла безусловно возвращаться на ноль, цикл никогда не закончит обработку.

Вернуть позицию только после конкретного предварительного просмотраСамостоятельный пример
<?php
mb_regex_encoding('UTF-8');
mb_ereg_search_init('№42; №43', '[0-9]+');
mb_ereg_search_regs();
$bookmark = mb_ereg_search_getpos();
$next = mb_ereg_search_regs();
echo 'Номер для предпросмотра: ', $next[0], "\n";
mb_ereg_search_setpos($bookmark);
echo 'Номер для основной обработки: ', mb_ereg_search_regs()[0], "\n";
Ожидаемый результат
Номер для предпросмотра: 43
Номер для основной обработки: 43

Не вычисляем позицию по количеству букв, а берём её у движка. Произвольное число может попасть внутрь UTF-8-буквы; формально допустимый байтовый offset ещё не означает осмысленную границу текста. Выход за диапазон в PHP 8.5 вызывает ValueError.

Ошибки и границы. После инициализации offset за допустимыми границами вызывает ValueError в PHP 8.5. Число внутри UTF-8 последовательности не является корректной пользовательской границей, даже если setter принял его. Не используйте без init.

Рядом: mb_ereg_search_getpos, mb_ereg_search_regs, mb_ereg_search_init. Байты, кодовые точки и графемы; общие правила вызова.

mb_ereg_search_getregsНайденный номер нужен и для подписи, и для следующего шага обработки. getregs читает группы последнего совпадения повторно, не переходя к следующему. Этим он отличается от search_regs, который сразу выполняет новый поиск.

PHP 4.2+ · mbstring

mb_ereg_search_getregs(): array|false
Данные до и после вызова
  1. search уже нашёл 42.
  2. Два getregs читают один и тот же номер 42.
  3. Только следующий search_regs продвинется к 43.
Аргумент / результатЧто передать и получить
ПараметрыНет.
return[0] последний полный фрагмент, [1] и далее группы; false, когда доступного совпадения нет. Не обещает хранить старое совпадение после неуспешного следующего поиска.

Перед поиском вызовите mb_ereg_search_init с собственным текстом и непустым шаблоном. Состояние одно на текущий контекст; вложенный init его заменит. Примеры используют UTF-8 и шаблоны, которые не совпадают с пустой строкой. Позиции этого семейства — байты, а не индексы mb_substr.

Прочитать результат дважды и затем перейти дальшеСамостоятельный пример
<?php
mb_regex_encoding('UTF-8');
mb_ereg_search_init('№42; №43', '[0-9]+');
mb_ereg_search();
echo 'Подпись: заказ ', mb_ereg_search_getregs()[0], "\n";
echo 'Действие для заказа: ', mb_ereg_search_getregs()[0], "\n";
echo 'Следующий номер: ', mb_ereg_search_regs()[0], "\n";
Ожидаемый результат
Подпись: заказ 42
Действие для заказа: 42
Следующий номер: 43

Одинаковый результат первых двух чтений — ожидаемое поведение. Эти вызовы лишь показывают данные, они не обращаются к внешней системе. Не заменяйте getregs на search_regs в середине обработки одного заказа.

Сохранить данные до неуспешного следующего поискаСамостоятельный пример
<?php
mb_regex_encoding('UTF-8');
mb_ereg_search_init('Заказ 42: готов', 'Заказ ([0-9]+): (готов)');
mb_ereg_search();
$saved = mb_ereg_search_getregs();
mb_ereg_search();
echo mb_ereg_search_getregs() === false ? "Следующего совпадения нет\n" : "Есть результат\n";
echo 'Сохранённый заказ: ', $saved[1], ' — ', $saved[2], "\n";
Ожидаемый результат
Следующего совпадения нет
Сохранённый заказ: 42 — готов

Общее состояние поиска не является архивом: после неудачи доступных групп может не быть. Своя переменная сохраняет нужные данные. Для внешнего текста сначала проверяют успех начального поиска и только потом читают группы.

Ошибки и границы. Нет аргументов; зависит от явно подготовленного состояния. false проверяется до обращения [0], иначе возникнет предупреждение доступа к не-массиву.

Рядом: mb_ereg_search, mb_ereg_search_regs, mb_ereg_search_getpos. Байты, кодовые точки и графемы; общие правила вызова.

mb_http_inputНа страницу пришёл товар «Молоток». Нужно узнать, участвовал ли входной конвертер mbstring, и одновременно увидеть сами данные. mb_http_input читает состояние обработанного типа входа; она не возвращает содержимое формы и не определяет заново кодировку произвольной строки. Здесь согласован UTF-8, автоматическая конверсия выключена.

PHP 4.0.6+ · mbstring

mb_http_input(?string $type = null): array|string|false
Данные до и после вызова
  1. probe_http.py посылает URL-encoded product=Молоток и stock=8.
  2. PHP заполняет $_GET либо $_POST; код сначала проверяет типы и UTF-8.
  3. mb_http_input(G/P) может вернуть false при реально пришедших данных: конвертер их не обрабатывал.
Аргумент / результатЧто передать и получить
typeG — GET, P — POST, C — cookie, S — разобранная строка; null/пропуск — последний обработанный вход. I — массив настроенных входных кодировок, L — тот же список строкой.
returnИмя для обработанного типа, false если соответствующего результата нет; I возвращает массив. Это не содержимое $_POST.

Как увидеть результат. Здесь example.php выполняет роль сервера. Сначала запустите локальную команду php -S из README архива, затем во втором терминале python probe_http.py. Python в этом уроке — готовый небольшой HTTP-клиент, который возвращает реальные заголовки и читает тело по полученному charset. Он также сохраняет сырые байты response.bin. PHP-код не нужно запускать как обычную CLI-программу: тогда HTTP-заголовков не будет. Имя Content-Type задаёт формат, charset — кодировку, echo создаёт тело ответа.

Увидеть реальный GET и состояние его конвертераПример для указанного окружения
<?php
declare(strict_types=1);

header('Content-Type: text/plain; charset=UTF-8');
$product = $_GET['product'] ?? null;
$stock = $_GET['stock'] ?? null;
if (!is_string($product) || !mb_check_encoding($product, 'UTF-8') || !is_string($stock) || !ctype_digit($stock)) {
    http_response_code(400);
    echo "Проверьте название и остаток\n";
    exit;
}
echo $product, ' — ', $stock, " шт.\n";
$encoding = mb_http_input('G');
echo $encoding === false ? "Входной конвертер mbstring не обрабатывал эти данные\n" : 'Конвертер использовал: '.$encoding."\n";
Ожидаемый результат
HTTP 200
Content-Type: text/plain
Кодировка: utf-8
Молоток — 8 шт.
Входной конвертер mbstring не обрабатывал эти данные

Полный локальный клиент и команды лежат в архиве. product из запроса становится ключом _GET[product], stock — ключом stock; оба значения формы — строки. is_string защищает от поддельного массива; mb_check_encoding проверяет договор UTF-8; ctype_digit проверяет цифры. Конфигурация запуска намеренно задаёт mbstring.encoding_translation=0. Поэтому false здесь говорит о конвертере, а не об отсутствии товара. Селекторы G/P/C/S и I/L сохранены в контракте; они не являются именами произвольных HTTP-методов.

Увидеть реальный POST и состояние его конвертераПример для указанного окружения
<?php
declare(strict_types=1);

header('Content-Type: text/plain; charset=UTF-8');
$product = $_POST['product'] ?? null;
$stock = $_POST['stock'] ?? null;
if (!is_string($product) || !mb_check_encoding($product, 'UTF-8') || !is_string($stock) || !ctype_digit($stock)) {
    http_response_code(400);
    echo "Проверьте название и остаток\n";
    exit;
}
echo $product, ' — ', $stock, " шт.\n";
$encoding = mb_http_input('P');
echo $encoding === false ? "Входной конвертер mbstring не обрабатывал эти данные\n" : 'Конвертер использовал: '.$encoding."\n";
Ожидаемый результат
HTTP 200
Content-Type: text/plain
Кодировка: utf-8
Молоток — 8 шт.
Входной конвертер mbstring не обрабатывал эти данные

Полный локальный клиент и команды лежат в архиве. product из запроса становится ключом _POST[product], stock — ключом stock; оба значения формы — строки. is_string защищает от поддельного массива; mb_check_encoding проверяет договор UTF-8; ctype_digit проверяет цифры. Конфигурация запуска намеренно задаёт mbstring.encoding_translation=0. Поэтому false здесь говорит о конвертере, а не об отсутствии товара. Селекторы G/P/C/S и I/L сохранены в контракте; они не являются именами произвольных HTTP-методов.

Ошибки и границы. С PHP 8 неверный type — ValueError; null разрешён с 8.0. Изменение mb_internal_encoding в обработчике не выполняет заново разбор GET/POST. Настройка входного фильтра должна существовать до запроса.

Рядом: mb_parse_str, mb_check_encoding, mb_get_info. Байты, кодовые точки и графемы; общие правила вызова.

mb_http_outputЧитатель старой складской программы должен получить понятную строку «Молоток — 8 шт.». Задаёт желаемую выходную кодировку mbstring. Сам вызов не меняет уже существующие строки: нужен обработчик выходного буфера. Прежде чем подключать его к старому клиенту, сравним два настоящих ответа.

PHP 4.0.6+ · mbstring

mb_http_output(?string $encoding = null): string|bool
Данные до и после вызова
  1. Файл example.php сохранён в UTF-8; строка внутри PHP содержит UTF-8 байты.
  2. HTTP-заголовок описывает байты; имя кодировки само по себе их не преобразует.
  3. probe_http.py сохраняет response.bin и читает текст по charset полученного ответа.
Аргумент / результатЧто передать и получить
encodingИмя кодировки назначения либо pass для отсутствия конверсии; null/пропуск читает текущее.
returnСтрока при чтении, true при успешной записи (контракт включает false).

Как увидеть результат. Здесь example.php выполняет роль сервера. Сначала запустите локальную команду php -S из README архива, затем во втором терминале python probe_http.py. Python в этом уроке — готовый небольшой HTTP-клиент, который возвращает реальные заголовки и читает тело по полученному charset. Он также сохраняет сырые байты response.bin. PHP-код не нужно запускать как обычную CLI-программу: тогда HTTP-заголовков не будет. Имя Content-Type задаёт формат, charset — кодировку, echo создаёт тело ответа.

Получить фактический HTTP-ответ без перекодировкиПример для указанного окружения
<?php
declare(strict_types=1);

mb_internal_encoding('UTF-8');
mb_http_output('Windows-1251');
header('Content-Type: text/plain; charset=UTF-8');
echo "Молоток — 8 шт.\n";
Ожидаемый результат
HTTP 200
Content-Type: text/plain
Кодировка: utf-8
Молоток — 8 шт.

Это HTTP endpoint, не CLI-вывод. Сначала запустите php -d mbstring.encoding_translation=0 -S 127.0.0.1:8793 example.php; во втором терминале python probe_http.py. Полные команды в README архива. Клиент показывает настоящие заголовки и декодированное тело; response.bin содержит исходные UTF-8 байты. Настройка Windows-1251 без конвертера их не меняет; режим pass явно выключает конверсию.

Передать тому же клиенту настоящие байты Windows-1251Пример для указанного окружения
<?php
declare(strict_types=1);

mb_internal_encoding('UTF-8');
mb_http_output('Windows-1251');
header('Content-Type: text/plain; charset=Windows-1251');
ob_start('mb_output_handler');
echo "Молоток — 8 шт.\n";
ob_end_flush();
Ожидаемый результат
HTTP 200
Content-Type: text/plain
Кодировка: windows-1251
Молоток — 8 шт.

ob_start регистрирует имя функции: PHP вызовет её при сбросе буфера. echo пока пишет внутрь буфера; ob_end_flush завершает его и отправляет преобразованное тело. Обработчик берёт исходную кодировку из mb_internal_encoding, назначение — из mb_http_output. Клиент действительно читает Windows-1251 по HTTP charset: сообщение человеку то же, байты response.bin другие. Не конвертируйте строку вручную перед этим обработчиком. Для обычного UTF-8 сайта этот слой не нужен; бинарные данные и неподходящие MIME-типы нельзя преобразовывать таким способом.

Ошибки и границы. Неизвестная кодировка вызывает ValueError в PHP 8.5. С 8.4 нулевой байт в имени также ValueError; encoding nullable с 8.0. deprecated INI mbstring.http_output не означает deprecated самой функции.

Рядом: mb_output_handler, mb_internal_encoding, mb_preferred_mime_name. Байты, кодовые точки и графемы; общие правила вызова.

mb_output_handlerЧитатель старой складской программы должен получить понятную строку «Молоток — 8 шт.». Преобразует вывод только как зарегистрированный обработчик буфера. Сначала увидим режим pass: PHP собирает текст и передаёт его без изменения кодировки. Затем включим конверсию для старого клиента.

PHP 4.0.6+ · mbstring

mb_output_handler(string $string, int $status): string
Данные до и после вызова
  1. Файл example.php сохранён в UTF-8; строка внутри PHP содержит UTF-8 байты.
  2. HTTP-заголовок описывает байты; имя кодировки само по себе их не преобразует.
  3. probe_http.py сохраняет response.bin и читает текст по charset полученного ответа.
Аргумент / результатЧто передать и получить
stringЧасть содержимого буфера, которую передаёт система output buffering.
statusБитовые флаги жизненного цикла PHP_OUTPUT_HANDLER_*; их передаёт PHP. Приложение обычно регистрирует имя callback, не вызывает его вручную.
returnСтрока результата, преобразованная при подходящем MIME/настройках либо переданная как есть.

Content-Type должен быть выставлен до вывода, а MIME-тип должен соответствовать данным. text/* обычно преобразуется; image/png или application/octet-stream не должны попадать под текстовое правило. Обработка зависит от mbstring.http_output_conv_mimetypes и SAPI. Если вручную уже перевели текст в Windows-1251, повторный handler из UTF-8 испортит его. Для обычного UTF-8 сайта проще обходиться без конвертера.

Как увидеть результат. Здесь example.php выполняет роль сервера. Сначала запустите локальную команду php -S из README архива, затем во втором терминале python probe_http.py. Python в этом уроке — готовый небольшой HTTP-клиент, который возвращает реальные заголовки и читает тело по полученному charset. Он также сохраняет сырые байты response.bin. PHP-код не нужно запускать как обычную CLI-программу: тогда HTTP-заголовков не будет. Имя Content-Type задаёт формат, charset — кодировку, echo создаёт тело ответа.

Получить фактический HTTP-ответ без перекодировкиПример для указанного окружения
<?php
declare(strict_types=1);

mb_internal_encoding('UTF-8');
mb_http_output('pass');
header('Content-Type: text/plain; charset=UTF-8');
ob_start('mb_output_handler');
echo "Молоток — 8 шт.\n";
ob_end_flush();
Ожидаемый результат
HTTP 200
Content-Type: text/plain
Кодировка: utf-8
Молоток — 8 шт.

Это HTTP endpoint, не CLI-вывод. Сначала запустите php -d mbstring.encoding_translation=0 -S 127.0.0.1:8793 example.php; во втором терминале python probe_http.py. Полные команды в README архива. Клиент показывает настоящие заголовки и декодированное тело; response.bin содержит исходные UTF-8 байты. Настройка Windows-1251 без конвертера их не меняет; режим pass явно выключает конверсию.

Передать тому же клиенту настоящие байты Windows-1251Пример для указанного окружения
<?php
declare(strict_types=1);

mb_internal_encoding('UTF-8');
mb_http_output('Windows-1251');
header('Content-Type: text/plain; charset=Windows-1251');
ob_start('mb_output_handler');
echo "Молоток — 8 шт.\n";
ob_end_flush();
Ожидаемый результат
HTTP 200
Content-Type: text/plain
Кодировка: windows-1251
Молоток — 8 шт.

ob_start регистрирует имя функции: PHP вызовет её при сбросе буфера. echo пока пишет внутрь буфера; ob_end_flush завершает его и отправляет преобразованное тело. Обработчик берёт исходную кодировку из mb_internal_encoding, назначение — из mb_http_output. Клиент действительно читает Windows-1251 по HTTP charset: сообщение человеку то же, байты response.bin другие. Не конвертируйте строку вручную перед этим обработчиком. Для обычного UTF-8 сайта этот слой не нужен; бинарные данные и неподходящие MIME-типы нельзя преобразовывать таким способом.

Ошибки и границы. Callback имеет состояние между фрагментами буфера; для разовой строки используйте mb_convert_encoding, не ручную имитацию status. Header already sent, неверное назначение/конфликт буферов — ошибки конфигурации, а не нормальный текстовый результат. Отправка и Content-Length должны учитывать итоговые байты.

Рядом: mb_http_output, mb_internal_encoding, mb_substitute_character. Байты, кодовые точки и графемы; общие правила вызова.

mb_parse_strПартнёр передал поля как строку product=...&stock=... . Требуется получить название, остаток и список меток, а затем проверить данные. mb_parse_str разбирает URL-encoded запись по правилам PHP и настроенного входного профиля; это не разбор JSON и не подтверждение корректности товара.

PHP 4.0.6+ · mbstring

mb_parse_str(string $string, array &$result): bool
Данные до и после вызова
  1. %XX раскрывает байты, + обозначает пробел.
  2. Имя stock даёт строку; tag[] создаёт список.
  3. Успех разбора ещё не означает, что stock имеет нужный тип и диапазон.
Аргумент / результатЧто передать и получить
stringСтрока вида name=value&tag[]=a; это не JSON и не multipart. Разделители зависят от arg_separator.input.
resultОбязательная выходная переменная-массив, передаётся по ссылке. Данные записываются сюда, не в произвольные глобальные переменные.
returntrue при успешной обработке, false при неудаче; true не означает валидность бизнес-полей.

Современная реализация берёт кандидатов из входной конфигурации http_input, а назначение из текущего internal encoding; одно mb_detect_order не является универсальной настройкой этого парсера. Для нового UTF-8 URL-encoded входа обычно понятнее parse_str с проверкой mb_check_encoding результата. Прямой выбор исходной таблицы в аргументах mb_parse_str отсутствует. Применяются ограничения парсинга PHP, включая max_input_vars/max_input_nesting_level; результат может оказаться неполным после предупреждения. Не считать return true доказательством полноты внешнего документа.

Из строки полей получить карточку товараСамостоятельный пример
<?php
declare(strict_types=1);

mb_internal_encoding('UTF-8');
$input = 'product=%D0%9A%D0%B8%D1%81%D1%82%D1%8C&stock=0&tag[]=tools&tag[]=sale';
if (!mb_parse_str($input, $fields)) { throw new RuntimeException('Поля не разобраны'); }
echo $fields['product'], ' — ', $fields['stock'], " шт.\n";
echo 'Метки: ', implode(', ', $fields['tag']), "\n";
Ожидаемый результат
Кисть — 0 шт.
Метки: tools, sale

Исходная строка полностью задана в коде и содержит UTF-8. Второй аргумент — выходная переменная; писать & при вызове не нужно. Квадратные скобки tag[] создают массив, implode соединяет его строки для человека. Значение "0" не следует отвергать через empty: нулевой остаток реален. Приёмник должен иметь согласованный входной профиль; разбор не угадывает происхождение любого файла.

Принять нулевой остаток и отказать массиву вместо числаСамостоятельный пример
<?php
declare(strict_types=1);

mb_internal_encoding('UTF-8');
foreach (['product=Кисть&stock=0', 'product=Кисть&stock[]=8'] as $input) {
    if (!mb_parse_str($input, $fields)) { throw new RuntimeException('Поля не разобраны'); }
    $name = $fields['product'] ?? null;
    $stock = $fields['stock'] ?? null;
    if (!is_string($name) || !mb_check_encoding($name, 'UTF-8')
        || !is_string($stock) || !ctype_digit($stock) || strlen($stock) > 4) {
        echo "Импорт отклонён: название и остаток должны быть строковыми полями\n";
        continue;
    }
    echo 'Принято: ', $name, ' — ', (int)$stock, " шт.\n";
}
Ожидаемый результат
Принято: Кисть — 0 шт.
Импорт отклонён: название и остаток должны быть строковыми полями

foreach проверяет два самостоятельных входа. ?? даёт null при отсутствующем ключе, условия не допускают массив stock[]. Только после проверки цифр и длины (int) создаёт число. continue пропускает сохранение ошибочного входа. Точки/пробелы в именах и дублирующиеся ключи PHP нормализует: для подписываемого протокола согласуйте эти правила или выберите формат без неоднозначности.

Ошибки и границы. Второй аргумент обязателен с PHP 8; пропуск deprecated с 7.2. Старый заголовок страницы про global и недоступность raw POST исторический: php://input существует, но формат тела и доступность зависят от SAPI/content type. Функция не проверяет CSRF, права, HTML или SQL.

Рядом: mb_http_input, mb_internal_encoding, mb_check_encoding. Байты, кодовые точки и графемы; общие правила вызова.

mb_encode_mimeheaderВ почтовом списке человек должен увидеть «Кисть», хотя транспортный заголовок содержит специальную ASCII-запись. mb_encode_mimeheader кодирует значение заголовка по MIME. Она не создаёт целое письмо и не отправляет его. Сначала получим одну строку Subject, затем сохраним собственный order.eml.

PHP 4.0.6+ · mbstring

mb_encode_mimeheader(string $string, ?string $charset = null, ?string $transfer_encoding = null, string $newline = "\r\n", int $indent = 0): string
Данные до и после вызова
  1. UTF-8 строка Кисть → mb_encode_mimeheader.
  2. Маркер =?UTF-8?B?...?= сообщает charset и Base64-представление.
  3. Почтовый клиент декодирует поле обратно в читаемое название.
Аргумент / результатЧто передать и получить
stringТекст в текущей mb_internal_encoding. Это отдельное условие от выходного charset.
charsetКодировка encoded-word результата; при пропуске/ null зависит от языкового профиля. Для ясного контракта задайте UTF-8.
transfer_encodingB — Base64, Q — вариант quoted-printable для encoded-word. Укажите явно; default определяется вызовом/профилем.
newlineМаркер переноса длинного заголовка, обычно CRLF.
indentЧисло знаков до текста на первой строке: для Subject: — 9. Это не количество отступов каждого переноса.
returnASCII-строка с encoded-word; без названия заголовка Subject:. Длинный текст складывается в несколько частей.
Получить точную строку почтовой темыСамостоятельный пример
<?php
declare(strict_types=1);

mb_internal_encoding('UTF-8');
$subject = mb_encode_mimeheader('Кисть', 'UTF-8', 'B');
echo 'Subject: ', $subject, "\n";
Ожидаемый результат
Subject: =?UTF-8?B?0JrQuNGB0YLRjA==?=

Первый аргумент — обычный текст во внутренней кодировке, второй — charset результата, B — Base64; Q обозначает другой MIME-способ. Строка Subject содержит имя поля отдельно от закодированного значения. Это не base64_encode целого письма и не HTML-экранирование.

Создать читаемое письмо в локальном файлеСамостоятельный пример
<?php
declare(strict_types=1);

mb_internal_encoding('UTF-8');
$subject = mb_encode_mimeheader('Заказ 42: Кисть', 'UTF-8', 'B', "\r\n", 9);
$headers = ['From: shop@phpmanual.test', 'To: student@phpmanual.test',
    'Subject: '.$subject, 'MIME-Version: 1.0',
    'Content-Type: text/plain; charset=UTF-8', 'Content-Transfer-Encoding: 8bit'];
$mail = implode("\r\n", $headers)."\r\n\r\nКисть — 2 шт.\r\n";
if (file_put_contents(__DIR__ . '/order.eml', $mail) !== strlen($mail)) {
    throw new RuntimeException('Письмо не записано полностью');
}
if (file_get_contents(__DIR__ . '/order.eml') !== file_get_contents(__DIR__ . '/EXPECTED-ORDER.eml')) {
    throw new RuntimeException('Содержимое письма отличается от заданного образца');
}
echo 'Сохранён order.eml; тема: ', mb_decode_mimeheader($subject), "\n";
echo "Тело: Кисть — 2 шт.\n";
Ожидаемый результат
Сохранён order.eml; тема: Заказ 42: Кисть
Тело: Кисть — 2 шт.

order.eml появляется рядом с example.php; код сравнивает все его байты с приложенным EXPECTED-ORDER.eml, где видно точное содержимое. Заголовки разделяются CRLF, пустая строка отделяет тело. indent=9 учитывает длину префикса Subject: ; функция сама переносит длинное значение. В этом коротком письме тема помещается в одну строку. From/To заданы нами, пользовательский CR/LF в заголовки не вставляется. mb_send_mail кодирует свою тему самостоятельно: туда передают исходную тему, а не результат этой функции.

Ошибки и границы. Неизвестный/неподходящий MIME charset — ValueError. В PHP 8 параметры charset/transfer_encoding допускают null; с 8.3 NUL в Q-кодировании сохраняется как =00, а не теряется. Функция не является валидатором адреса или защитой от header injection: исходные CR/LF и другие недопустимые управляющие знаки в пользовательской теме отклоняют до сборки письма. Адрес целиком не превращают в encoded-word.

Рядом: mb_decode_mimeheader, mb_language, mb_send_mail. Байты, кодовые точки и графемы; общие правила вызова.

mb_decode_mimeheaderПри импорте письма тема выглядит как =?UTF-8?B?...?=. Человеку нужно название, а не транспортная упаковка. mb_decode_mimeheader раскрывает encoded-word и возвращает текст в mb_internal_encoding. Она не разбирает вложения и не декодирует автоматически тело MIME-письма.

PHP 4.0.6+ · mbstring

mb_decode_mimeheader(string $string): string
Данные до и после вызова
  1. Файл order.eml содержит отдельное поле Subject.
  2. Декодер превращает его значение в UTF-8 текст.
  3. Импорт показывает тему и отдельно прочитанное текстовое тело.
Аргумент / результатЧто передать и получить
stringЗначение поля MIME-заголовка, которое может содержать encoded-word.
returnРаскодированный текст в текущей mb_internal_encoding. Это не массив всех заголовков и не тело письма.
Прочитать закодированное названиеСамостоятельный пример
<?php
declare(strict_types=1);

mb_internal_encoding('UTF-8');
echo mb_decode_mimeheader('=?UTF-8?B?0JrQuNGB0YLRjA==?='), "\n";
Ожидаемый результат
Кисть

Закодированная строка целиком дана в примере. Внутренняя кодировка результата явно UTF-8, поэтому кириллица не теряется при конверсии в неподходящий однобайтовый профиль.

Импортировать тему из полностью заданного письмаСамостоятельный пример
<?php
declare(strict_types=1);

mb_internal_encoding('UTF-8');
$raw = file_get_contents(__DIR__ . '/order.eml');
if ($raw === false) { throw new RuntimeException('Письмо не прочитано'); }
[$headers, $body] = explode("\r\n\r\n", $raw, 2);
foreach (explode("\r\n", $headers) as $line) {
    if (str_starts_with($line, 'Subject: ')) {
        echo 'Тема: ', mb_decode_mimeheader(substr($line, 9)), "\n";
    }
}
echo 'Тело: ', str_replace("\r\n", "\n", $body);
Ожидаемый результат
Тема: Заказ 42: Кисть
Тело: Кисть — 2 шт.

Архив содержит order.eml, не предполагаемый внешний ящик. explode отделяет заголовки от тела по пустой строке; foreach ищет известный короткий Subject, substr убирает префикс. Это разбор конкретного приложенного письма с одной строкой темы и телом 8bit UTF-8. Общая почта требует MIME-парсера: folded fields, multipart, другие transfer encodings и вложения этим циклом не разобраны. Для HTML-показа декодированный текст дополнительно экранируют.

Ошибки и границы. Функция не обещает строгую проверку корректности всего RFC-письма. Не используйте результат как готовый безопасный HTML, имя файла или команду; валидируйте контекст назначения. Нужна функция/библиотека разбора MIME для вложений и структуры письма.

Рядом: mb_encode_mimeheader, mb_internal_encoding, mb_check_encoding. Байты, кодовые точки и графемы; общие правила вызова.

mb_send_mailНужно подготовить уведомление «Заказ 42: Кисть» и убедиться, какие тему и тело получил почтовый транспорт. В этом опыте транспорт — свой Python-приёмник на 127.0.0.1; он только сохраняет файл и не пересылает письмо. mb_send_mail выполняет MIME-кодирование по mb_language, затем передаёт результат почтовой подсистеме PHP.

PHP 4.0.6+ · mbstring

mb_send_mail(string $to, string $subject, string $message, array|string $additional_headers = [], ?string $additional_params = null): bool
Данные до и после вызова
  1. Обычные UTF-8 тема и тело → профиль uni.
  2. Windows PHP соединяется только с 127.0.0.1:8794.
  3. smtp_sink.py сохраняет captured.eml; probe_mail.py декодирует настоящий файл.
  4. Принятие локальным SMTP не доказывает доставку в чей-либо ящик.
Аргумент / результатЧто передать и получить
toОдин адрес или список через запятую; автоматически MIME-кодироваться не будет. Политика получателей/валидация — ответственность приложения.
subjectИсходная тема в согласованной internal encoding; обёртка выполняет своё кодирование, поэтому не применяйте mb_encode_mimeheader повторно заранее.
messageТекст тела; кодирование зависит от языкового профиля. Это не автоматическая поддержка любых вложений/HTML-шаблонов.
additional_headersМассив name → value (с 7.2) либо строка заголовков, разделённых CRLF. Нужен From здесь или в серверной конфигурации.
additional_paramsДополнительные параметры MTA, например статически доверенный envelope sender для sendmail. Это не SMTP-пароль. Не принимать их из HTTP.
returntrue означает принятие к отправке транспортом, не доставку получателю; false — неудачу передачи. Возможны предупреждения/ошибки конфигурации.

additional_params проходит escapeshellcmd, но это не запрещает добавление новых параметров MTA. Используйте только доверенную фиксированную серверную настройку либо null; произвольное пользовательское значение запрещено контрактом вашего приложения. При sendmail envelope -f может потребовать настройки доверенного системного пользователя, иначе появится X-Warning. В Windows From влияет также на Return-Path. Отсутствующий From вызывает предупреждение конфигурации. Исторический обход qmail с LF вместо CRLF применялся только под конкретный MTA и не является общим стандартным рецептом.

Для очереди уведомлений обычно удобнее почтовая библиотека с явной SMTP-конфигурацией и обработкой ошибок. Многократный вызов mail-обёртки не создаёт автоматически безопасную массовую рассылку. При неопределённом результате нельзя бесконечно повторять отправку: иначе пользователю придут дубликаты. Локальный приёмник проверяет только подготовку и принятие сообщения в указанной лаборатории; внешняя доставка и DNS этим не проверяются.

Прежде чем запускать. Вызов ниже передаёт четыре значения: получатель, обычная тема, обычное тело и массив заголовков. Элемент From содержит наш фиксированный адрес; своего Subject в массиве нет. ini_set меняет настройку текущего PHP-процесса. getenv читает необязательный порт из окружения, ?: выбирает учебный порт 8794, если переменная пуста. ctype_digit и проверка диапазона подтверждают, что задан допустимый номер учебного порта. Проверка PHP_OS_FAMILY останавливает опыт вне Windows, чтобы код не попал в системный Unix MTA. Никаких адресов SMTP из формы не принимается.

Прочитать настоящее письмо из локального SMTP-приёмникаПример для указанного окружения
<?php
declare(strict_types=1);

if (PHP_OS_FAMILY !== 'Windows') {
    throw new RuntimeException('Этот SMTP-опыт требует Windows; системный MTA не вызывается');
}
$port = getenv('PHP_MANUAL_SMTP_PORT') ?: '8794';
if (!ctype_digit($port) || (int)$port < 1024 || (int)$port > 65535) {
    throw new RuntimeException('Нужен локальный учебный порт');
}
ini_set('SMTP', '127.0.0.1');
ini_set('smtp_port', $port);
ini_set('sendmail_from', 'shop@phpmanual.test');
mb_internal_encoding('UTF-8');
mb_language('uni');
$accepted = mb_send_mail('student@phpmanual.test', 'Заказ 42: Кисть',
    "Кисть — 2 шт.\nК выдаче: 160 руб.\n", ['From'=>'shop@phpmanual.test']);
if (!$accepted) { throw new RuntimeException('Локальный SMTP не принял письмо'); }
echo "Локальный приёмник принял сообщение\n";
Ожидаемый результат
Локальный приёмник принял сообщение
Кому: student@phpmanual.test
Тема: Заказ 42: Кисть
Формат: text/plain
Кодировка: utf-8
Тело:
Кисть — 2 шт.
К выдаче: 160 руб.

Нужны Windows PHP с mbstring и Python 3. В первом терминале python smtp_sink.py; во втором php example.php; затем python probe_mail.py. Результат ниже — вывод двух последних команд. Все файлы и команды входят в архив. ini_set изменяет только этот процесс; uni задаёт профиль UTF-8/MIME, но не адрес SMTP. Тема передаётся обычным текстом ровно один раз, дополнительный Subject не дублируется. captured.eml содержит реальные транспортные заголовки и тело, smtp-transcript.txt — ответы SMTP. На Unix этот файл останавливается до вызова почтовой подсистемы; там нужен отдельный контролируемый sendmail_path.

Обработать настоящий отказ SMTP до сохранения письмаПример для указанного окружения
<?php
declare(strict_types=1);

if (PHP_OS_FAMILY !== 'Windows') {
    throw new RuntimeException('Этот SMTP-опыт требует Windows; системный MTA не вызывается');
}
$port = getenv('PHP_MANUAL_SMTP_PORT') ?: '8794';
if (!ctype_digit($port) || (int)$port < 1024 || (int)$port > 65535) {
    throw new RuntimeException('Нужен локальный учебный порт');
}
ini_set('SMTP', '127.0.0.1');
ini_set('smtp_port', $port);
ini_set('sendmail_from', 'shop@phpmanual.test');
mb_internal_encoding('UTF-8');
mb_language('uni');
$warning = null;
set_error_handler(function (int $level, string $message) use (&$warning): bool {
    if ($level !== E_WARNING) { return false; }
    $warning = $message;
    return true;
});
try {
    $accepted = mb_send_mail('student@phpmanual.test', 'Заказ 42: Кисть',
        'Кисть — 2 шт.', ['From'=>'shop@phpmanual.test']);
} finally { restore_error_handler(); }
if ($accepted) { throw new RuntimeException('Ожидался отказ учебного SMTP'); }
file_put_contents(__DIR__ . '/transport-warning.txt', $warning ?? 'Нет предупреждения');
echo "Письмо не принято: проверьте адрес и настройки транспорта\n";
Ожидаемый результат
Письмо не принято: проверьте адрес и настройки транспорта
Письмо не сохранено: SMTP отклонил получателя

Новая пустая папка из этого архива; в первом терминале python smtp_sink.py --reject. Приёмник отвечает 550 на RCPT, файл письма не создаётся. Обработчик E_WARNING установлен только вокруг одного mb_send_mail и обязательно снят в finally. Подробное предупреждение сохраняется для оператора; человек видит понятный отказ. Этот опыт отличается от неизвестного результата после обрыва связи: повтор отправки без идемпотентного события может дать дубликат.

Ошибки и границы. additional_headers принимает массив с 7.2, additional_params nullable с 8.0. PHP проверяет часть недопустимых заголовков/нулевых байтов, но это не замена вашей валидации. Ошибка локального транспорта может дать warning/false; исключения/ошибки вызова также не являются доставкой. Подробности системного mail относятся к отдельной почтовой категории.

Рядом: mb_language, mb_encode_mimeheader, mb_internal_encoding. Байты, кодовые точки и графемы; общие правила вызова.

Источники и обсуждения

Код и руководство с собой

Скачайте самостоятельные примеры с исходными данными, инструкциями и ожидаемыми результатами. Примеры HTTP и фрагменты для проекта помечены отдельно: им нужно указанное окружение.

Код не исполняется на сайте. Скачайте нужный пример и запускайте его в своём локальном окружении.

Материалы сверены 2026-10-12. Примеры и объяснения написаны для этого руководства; источники и обсуждения доступны в каждой главе.