Strings7 min readExamples run on PHP 8.5.10

fprintf()

Learn how fprintf() formats values with printf-style directives and writes the result to a stream, including its return value, errors and common pitfalls.

Signature

fprintf(resource $stream, string $format, mixed ...$values): int

Purpose

fprintf() builds a string from a format template and a list of values, then writes that string to a stream you supply. It is the stream-oriented sibling of printf() (which writes to output) and sprintf() (which returns the string). Use it when formatted text must go to a particular resource: a log handle, a socket, a temporary buffer or an in-memory stream.

Signature

Parameters

  • $stream: a writable stream resource, usually from fopen(). There is no default; it is required.
  • $format: the template. Ordinary characters are copied unchanged, and each conversion specification such as %d or %s consumes a value. The general shape is %[argnum$][flags][width][.precision]specifier.
  • ...$values: zero or more values used by the conversion specifications. There is no default list.

Useful pieces of the format language:

  • Specifiers: d for signed integers, s for strings, f and F for floats (f respects the locale, F does not), x and X for hexadecimal, b for binary, o for octal, e for scientific notation, and %% for a literal percent sign.
  • Flags: - left-justifies, + forces a sign on positive numbers, 0 pads with zeros, and 'c pads with the character c.
  • Width sets a minimum field size. Precision, written as .n, sets decimals for floats or a maximum length for strings.
  • argnum$ such as %2$s selects a value by position, so the same value can be reused or the order changed.

Return value and failure cases

The function returns an int: the length of the string that was written, counted in bytes. Since PHP 8.0 it no longer returns false on failure. Problems with the format itself are reported by exceptions:

  • ArgumentCountError when fewer values are supplied than the format needs.
  • ValueError when the width or precision is negative or larger than PHP_INT_MAX, or when the argument count is zero.

Example 1: zero-padded integers

The examples use php://memory, so nothing touches the disk. After writing, rewind() moves the pointer back so the contents can be read.

Example
<?php
$stream = fopen('php://memory', 'w+');
$length = fprintf($stream, '%04d-%02d-%02d', 2005, 5, 6);
rewind($stream);
echo json_encode([$length, stream_get_contents($stream)], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
fclose($stream);
Output
[10,"2005-05-06"]

The date is ten bytes long, and the return value confirms it.

Example 2: money, padding and flags

Example
<?php
$stream = fopen('php://memory', 'w+');
$total = 68.75 + 54.35;
$a = fprintf($stream, "%01.2f\n", $total);
$b = fprintf($stream, "%'*10s|%-8s|%+d\n", 'abc', 'left', 5);
rewind($stream);
echo stream_get_contents($stream);
echo $a, ' ', $b, "\n";
fclose($stream);
Output
123.10
*******abc|left    |+5
7 23

The %01.2f directive always shows two decimals, so a sum that PHP would echo as 123.1 is written as 123.10. The second call shows a custom padding character, left justification and an explicit plus sign. Each return value includes the trailing newline.

Example 3: positional arguments

Example
<?php
$stream = fopen('php://memory', 'w+');
$length = fprintf($stream, '%2$s has %1$d items (%3$05.1f%%)', 3, 'Cart', 42.456);
rewind($stream);
echo json_encode([$length, stream_get_contents($stream)], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
fclose($stream);
Output
[25,"Cart has 3 items (042.5%)"]

Values are passed as 3, 'Cart', 42.456, but the template picks them out of order with %2$s, %1$d and %3$05.1f. The final %% writes a literal percent sign.

Edge cases

  • The return value counts bytes. A string such as é in UTF-8 occupies two bytes, so the count can exceed the number of visible characters.
  • Width and precision on s also operate on bytes, so padding or truncating multibyte text may split a character.
  • The c specifier ignores width and padding.
  • Values are coerced to suit the specifier, so %d applied to a numeric string converts it to an integer, and %d applied to a float drops the fractional part.
  • Once you use positional argnum$ forms, keep the numbering consistent so the template remains readable.
  • Using * for width or precision consumes an extra integer value before the formatted one.

Common mistakes

  1. Forgetting rewind() when reading back. After writing to a w+ memory stream the pointer is at the end, so reading immediately returns an empty string.
  2. Passing too few values. The format needs one value per non-positional directive; a shortfall throws ArgumentCountError.
  3. Writing a bare percent sign. A literal % must be written as %%, otherwise the next characters are read as a directive.
  4. Assuming the return value is a success flag. It is the written length, not a boolean.
  5. Expecting locale-independent floats from %f. Use %F when the decimal separator must never change with the locale.
  6. Using an unsuitable stream. The resource must be open and writable, so pick an appropriate mode with fopen().
  • printf() writes a formatted string to output.
  • sprintf() returns the formatted string instead of writing it.
  • vfprintf() accepts the values as an array.
  • vprintf() and vsprintf() are the array-based output and string versions.
  • number_format() groups thousands and is handy for display amounts.
  • fscanf() and sscanf() parse input according to a format.

Recap

fprintf() formats like sprintf() but sends the text to a stream and returns the byte length. Learn the directive pattern %[argnum$][flags][width][.precision]specifier, remember %% for a literal percent sign, and expect ArgumentCountError or ValueError for malformed calls.

Tested examples

Zero-padded integers written to a memory stream
<?php
$stream = fopen('php://memory', 'w+');
$length = fprintf($stream, '%04d-%02d-%02d', 2005, 5, 6);
rewind($stream);
echo json_encode([$length, stream_get_contents($stream)], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
fclose($stream);
Output
[10,"2005-05-06"]
Money formatting, padding characters and flags
<?php
$stream = fopen('php://memory', 'w+');
$total = 68.75 + 54.35;
$a = fprintf($stream, "%01.2f\n", $total);
$b = fprintf($stream, "%'*10s|%-8s|%+d\n", 'abc', 'left', 5);
rewind($stream);
echo stream_get_contents($stream);
echo $a, ' ', $b, "\n";
fclose($stream);
Output
123.10
*******abc|left    |+5
7 23
Positional arguments and a literal percent sign
<?php
$stream = fopen('php://memory', 'w+');
$length = fprintf($stream, '%2$s has %1$d items (%3$05.1f%%)', 3, 'Cart', 42.456);
rewind($stream);
echo json_encode([$length, stream_get_contents($stream)], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
fclose($stream);
Output
[25,"Cart has 3 items (042.5%)"]