← All docs

iconv

Character-set conversion and character-oriented string functions: the 10 PHP iconv functions.

elephc implements all 10 procedural iconv functions and the extension’s four constants, on the native compilation path and inside dynamic eval(). The conversions themselves are performed by the platform’s iconv implementation — glibc on Linux, GNU libiconv on macOS — so the charsets your system supports are exactly the charsets your program supports, the same relationship PHP has.

The implementation lives in the elephc_iconv bridge crate. It is linked automatically the first time a program calls one of these functions, and never linked otherwise; --with-iconv force-links it when detection cannot see the call. See Linking & Conditional Compilation.

Converting between charsets

FunctionSignatureNotes
iconv()iconv(string $from_encoding, string $to_encoding, string $string): string|falseConverts a byte string from one charset to another

$to_encoding accepts the two suffixes the platform iconv defines:

  • //TRANSLIT approximates characters the target charset cannot represent.
  • //IGNORE drops them instead.

The approximation //TRANSLIT chooses belongs to the platform’s iconv, not to PHP, so it differs between targets: glibc renders é as e, while GNU libiconv renders it as 'e. PHP behaves the same way, reporting whatever its own provider produces. Only //IGNORE reads identically everywhere, because dropping a character has one spelling.

$utf8   = "Prüfung café";
$latin1 = iconv("UTF-8", "ISO-8859-1", $utf8);

echo bin2hex($latin1);                        // 5072fc66756e6720636166e9
echo iconv("ISO-8859-1", "UTF-8", $latin1);   // Prüfung café
echo iconv("UTF-8", "ASCII//TRANSLIT", $utf8); // Prufung cafe   (glibc)
echo iconv("UTF-8", "ASCII//IGNORE", $utf8);   // Prfung caf

A charset pair the platform cannot open raises a warning and returns false; a byte sequence the source charset rejects raises a notice and returns false.

Character-oriented strings

strlen() and friends count bytes. These four functions count characters in the selected charset, so multibyte text measures and slices the way a reader expects.

FunctionSignatureNotes
iconv_strlen()iconv_strlen(string $string, ?string $encoding = null): int|falseCharacter count
iconv_substr()iconv_substr(string $string, int $offset, ?int $length = null, ?string $encoding = null): string|falseCharacter-indexed slice, with substr()’s negative-value conventions
iconv_strpos()iconv_strpos(string $haystack, string $needle, int $offset = 0, ?string $encoding = null): int|falseFirst character position
iconv_strrpos()iconv_strrpos(string $haystack, string $needle, ?string $encoding = null): int|falseLast character position
$text = "Prüfung café";

echo strlen($text);                  // 14 bytes
echo iconv_strlen($text);            // 12 characters
echo iconv_substr($text, 0, 7);      // Prüfung
echo iconv_strpos($text, "café");    // 8
echo iconv_strrpos($text, "f");      // 10

An omitted or null $encoding uses the internal encoding (see below); an explicitly empty string uses PHP’s default_charset, which is UTF-8. An empty $needle never matches. An $offset outside $haystack throws a catchable \ValueError, matching PHP 8.

elephc converts the whole subject to UCS-4LE before iconv_strlen() and iconv_substr() operate. This preserves shift state for stateful encodings such as ISO-2022-JP: 日本語 counts as three characters and every one-character slice converts back correctly. PHP with GNU libiconv 1.11 loses shift state between slices, counts this input as four characters, and can return undecodable fragments. elephc intentionally keeps the correct whole-subject behavior.

MIME header fields

RFC 2047 encoded-words carry non-ASCII text through mail headers that only allow ASCII.

FunctionSignatureNotes
iconv_mime_encode()iconv_mime_encode(string $field_name, string $field_value, array $options = []): string|falseEncodes one field, folding it across lines
iconv_mime_decode()iconv_mime_decode(string $string, int $mode = 0, ?string $encoding = null): string|falseDecodes one header field
iconv_mime_decode_headers()iconv_mime_decode_headers(string $headers, int $mode = 0, ?string $encoding = null): array|falseDecodes a whole header block

$options accepts these keys:

KeyDefaultMeaning
schemeBB for base64 encoded-words, Q for quoted-printable
input-charsetinternal encodingCharset $field_value is currently in
output-charsetinput-charsetCharset the header is encoded into
line-length76Maximum length of one output line
line-break-chars"\r\n"Bytes written between folded lines

For ["line-length" => -1], elephc returns false. PHP 8.5 instead terminates with an integer-overflow fatal while calculating the allocation size; elephc intentionally avoids that crash.

$subject = iconv_mime_encode("Subject", "Prüfung");
echo $subject;                        // Subject: =?UTF-8?B?UHLDvGZ1bmc=?=
echo iconv_mime_decode($subject);     // Subject: Prüfung

echo iconv_mime_encode("Subject", "Prüfung", ["scheme" => "Q"]);
// Subject: =?UTF-8?Q?Pr=C3=BCfung?=

iconv_mime_decode() decodes exactly one field: a line break that no linear whitespace follows ends it. iconv_mime_decode_headers() walks the whole block and returns an associative array; a field name that appears more than once collects its values into a list.

$headers = iconv_mime_decode_headers(
    "Subject: =?ISO-8859-1?Q?Pr=FCfung?=\r\n" .
    "To: alice@example.com\r\n" .
    "To: bob@example.com\r\n\r\nbody"
);

echo $headers["Subject"];              // Prüfung
echo implode(", ", $headers["To"]);    // alice@example.com, bob@example.com

$mode accepts the extension’s two flags, which may be combined:

ConstantValueEffect
ICONV_MIME_DECODE_STRICT1Only accept encoded-words RFC 2047 allows at that position; anything else stays literal text
ICONV_MIME_DECODE_CONTINUE_ON_ERROR2Keep undecodable text verbatim instead of failing the whole call

When ICONV_MIME_DECODE_CONTINUE_ON_ERROR preserves a malformed encoded-word, elephc also preserves the surrounding header boundaries. PHP 8.5 can leak the carriage return into a value with CRLF input, or absorb the next header into that value with LF-only input. elephc intentionally returns separate, clean header fields in both cases.

Default encodings

The extension keeps three process-wide charset settings. All three start at UTF-8, and the character-oriented functions fall back to internal_encoding when their $encoding argument is omitted. The compiler accepts --ini default_charset=..., but that directive is not wired into the iconv bridge yet; an explicitly empty $encoding therefore still uses UTF-8.

FunctionSignatureNotes
iconv_get_encoding()iconv_get_encoding(string $type = "all"): array|string|falseall reports the trio as an array; a single name reports one charset
iconv_set_encoding()iconv_set_encoding(string $type, string $encoding): boolSets one of input_encoding, output_encoding, internal_encoding
$encodings = iconv_get_encoding();
echo $encodings["internal_encoding"];        // UTF-8

iconv_set_encoding("internal_encoding", "ISO-8859-1");
echo iconv_strlen("Prüfung café");           // 14 — the bytes are now read as Latin-1

Like PHP, iconv_set_encoding() stores the charset without validating it, so only an unrecognized $type reports false. $type is matched case-insensitively. PHP 8.5 emits a deprecation diagnostic for all three iconv_set_encoding() slots. elephc provides the function but has no runtime deprecation channel, so it does not emit that diagnostic.

Constants

ConstantValue
ICONV_MIME_DECODE_STRICT1
ICONV_MIME_DECODE_CONTINUE_ON_ERROR2
ICONV_IMPL"glibc" on Linux targets, "libiconv" on macOS targets
ICONV_VERSION"unknown"

PHP bakes ICONV_IMPL and ICONV_VERSION when the interpreter is built. elephc compiles ahead of time for a target whose libc build is not knowable, so ICONV_IMPL is derived from the target platform and ICONV_VERSION reports the portable fallback "unknown". A normal PHP build reports the provider version detected while PHP itself was built instead.

Stream filters

The convert.iconv.<from>/<to> stream filter transcodes data as it flows through a stream, in either direction. It is part of the stream layer rather than this extension; see Streams.

$stream = fopen("php://memory", "r+");
stream_filter_append($stream, "convert.iconv.UTF-8/ISO-8859-1", STREAM_FILTER_WRITE);
fwrite($stream, "café");

Functions {#functions}

Generated from the shared symbol catalog by scripts/docs/gen_module_sections.py; do not edit this section by hand. Each function links to its reference page.

FunctionSignatureReturnsAOTeval()
iconv()(string $from_encoding, string $to_encoding, string $string): mixedmixed
iconv_get_encoding()(string $type = 'all'): mixedmixed
iconv_mime_decode()(string $string, int $mode = 0, ?string $encoding = null): mixedmixed
iconv_mime_decode_headers()(string $headers, int $mode = 0, ?string $encoding = null): mixedmixed
iconv_mime_encode()(string $field_name, string $field_value, mixed $options = []): mixedmixed
iconv_set_encoding()(string $type, string $encoding): boolbool
iconv_strlen()(string $string, ?string $encoding = null): mixedmixed
iconv_strpos()(string $haystack, string $needle, int $offset = 0, ?string $encoding = null): mixedmixed
iconv_strrpos()(string $haystack, string $needle, ?string $encoding = null): mixedmixed
iconv_substr()(string $string, int $offset, ?int $length = null, ?string $encoding = null): mixedmixed

Constants: ICONV_IMPL, ICONV_MIME_DECODE_CONTINUE_ON_ERROR, ICONV_MIME_DECODE_STRICT, ICONV_VERSION.