|  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Request #61168 fwrite() should allow for buffering
Submitted: 2012-02-23 06:16 UTC Modified: 2016-07-01 21:14 UTC
Avg. Score:4.8 ± 0.4
Reproduced:4 of 4 (100.0%)
Same Version:1 (25.0%)
Same OS:4 (100.0%)
From: Assigned:
Status: Open Package: Streams related
PHP Version: 5.4.0RC8 OS: Linux
Private report: No CVE-ID: None
View Add Comment Developer Edit
Welcome! If you don't have a Git account, you can't do anything here.
You can add a comment by following this link or if you reported this bug, you can edit this bug over here.
Block user comment
Status: Assign to:
Bug Type:
New email:
PHP Version: OS:


 [2012-02-23 06:16 UTC]
The stream_set_write_buffer() manual entry indicates that fwrite() buffers its output. This is incorrect. For regular files, no buffering is ever done, each fwrite() call leads to a syscall. 

This is a performance issue, especially for extensions like the CDB handler in DBA. I have a real-world script that uses almost as much system CPU as user CPU, because each dba_insert() call leads to multiple syscalls.

Test script:
$f = fopen( '/tmp/blah', 'w' );
stream_set_write_buffer( $f, 8192 );
for ( $i = 0; $i < 10; $i++ ) {
	fwrite( $f, 'x' );
fclose( $f );

Expected result:
strace php write-tight-loop.php
write(3, "xxxxxxxxxx", 1)                        = 10

Actual result:
write(3, "x", 1)                        = 1
write(3, "x", 1)                        = 1
write(3, "x", 1)                        = 1
write(3, "x", 1)                        = 1
write(3, "x", 1)                        = 1
write(3, "x", 1)                        = 1
write(3, "x", 1)                        = 1
write(3, "x", 1)                        = 1
write(3, "x", 1)                        = 1
write(3, "x", 1)                        = 1


Add a Patch

Pull Requests

Add a Pull Request


AllCommentsChangesGit/SVN commitsRelated reports
 [2012-02-23 10:32 UTC]
You're not checking the return value of stream_set_write_buffer. If you were, you'd have noticed it returns -1 indicating failure.

PHP does not have buffering for writes as it does for reads. In fact, it has the opposite: it breaks the data to write in chunk_size bits (see the undocumented stream_set_chunk_size in PHP 5.4).

Therefore, streams that want to provide write buffering must do so themselves; PHP merely provides a way to configure the write buffering. In the case of plain files, write buffering is supported, but only for stdio files, not plain file descriptors. The stream by default doesn't use stdio (to avoid duplication of read buffers for instance).

Extensions can open a FILE* and pass it to php_stream_fopen_from_file(), but it seems that this won't suffice because PHP will still use low-level I/O on the file descriptor returned by fileno(), so you'd have to violate some abstractions and zero the fd field in the php_stdio_stream_data structure (stored in stream->abstract) to force stdio to be used. This should be revisited.

In any case, the documentation is wrong. I'm changing this to a documentation problem for the time being.
 [2012-02-23 10:32 UTC]
-Type: Bug +Type: Documentation Problem
 [2012-02-23 14:49 UTC]
Perhaps this change in plain_wrapper.c would be a good idea:

@@ -583,7 +583,13 @@
                case PHP_STREAM_OPTION_WRITE_BUFFER:

                        if (data->file == NULL) {
-                               return -1;
+                               char fixed_mode[5];
+                               php_stream_mode_sanitize_fdopen_fopencookie(stream, fixed_mode);
+                               data->file = fdopen(data->fd, fixed_mode);
+                               if (data->file == NULL) {
+                                       return -1;
+                               }
+                               data->fd = -1;

                        if (ptrparam)

I'll have to think a bit more about the implications.
 [2013-04-22 01:02 UTC]
Still not even a documentation change? It's been more than a year, and I can't imagine it being particularly complex to edit a single sentence in the manual.
 [2013-04-22 18:41 UTC]
You are right, it isn't. In fact you can easily do it. Go to 
and make the change and submit it.
 [2016-07-01 21:13 UTC]
Automatic comment from SVN on behalf of cmb
Log: Address #61168: fwrite() has no buffering

The info that fwrite() is normally buffered is obviously wrong, but the
rest of the paragraph also looks fishy, so we remove it altogether.
 [2016-07-01 21:14 UTC]
-Summary: fwrite() has no buffering +Summary: fwrite() should allow for buffering -Type: Documentation Problem +Type: Feature/Change Request
 [2016-07-01 21:14 UTC]
I've fixed the docs; changing to feature request as indicated by
PHP Copyright © 2001-2021 The PHP Group
All rights reserved.
Last updated: Wed Mar 03 06:01:23 2021 UTC