Many answers here in Stack Overflow use fopen($file, "rw+")
, but the manual doesn't list the "rw+"
mode, there's only the "r+"
mode (or "w+"
mode).
So I was wondering, what does the "rw+"
mode do? What's the difference between fopen($file,
"rw+"
or "r+"
? I'm asking this because there is no documentation on the "rw+"
mode.
One approach is to consider that the modes are additive, but I couldn't find any mention of combining modes in the fopen
manual page (besides, what's the sense of combining "r"
with "w+"
, if "w+"
already makes it readable?). But most importantly, w+
mode truncates the file, while rw+
does not truncate it (therefore, they cannot be additive). Probably there is no rw+
mode, despite its use by Stack Overflow users. Maybe it works because the parser ignores the "w" letter, as the rw+
mode appears to be === r+
?
To clarify my question: what is the "rw+"
mode, that is, how does it differ from other modes? I only received two answers in the comments: either that I should check the documentation (I already checked and rechecked) and a wrong answer, which said it is equal to "w+"
(it isn't). "w+"
truncates the file, while "rw+"
doesn't.
Here's a script for testing (it proves that w+
truncates the file, but rw+
doesn't):
<?php $file = "somefile"; $fileOpened = fopen($file, "w"); fwrite($fileOpened, "0000000000000000000"); fclose($fileOpened); $fileOpened = fopen($file, "rw+"); fwrite($fileOpened, "data"); fclose($fileOpened); $fileOpened = fopen($file, "r"); $output = fgets($fileOpened); echo "First, with 'rw+' mode:<br>".$output; $fileOpened = fopen($file, "w+"); fwrite($fileOpened, "data"); fclose($fileOpened); $fileOpened = fopen($file, "r"); $output = fgets($fileOpened); echo "<br><br><br>Now with only 'w+' mode:<br>".$output; ?>
The w creates a new file or truncates an existing file , then opens it for writing ; the file pointer position at the beginning of the file. The w+ creates a new file or truncates an existing file , then opens it for reading and writing ; the file pointer position at the beginning of the file.
DESCRIPTION. The fopen() function opens the file whose pathname is the string pointed to by filename, and associates a stream with it. The argument mode points to a string beginning with one of the following sequences: r or rb. Open file for reading.
a: Opens a file for appending new information to it. The pointer is placed at the end of the file. A new file is created if one with the same name doesn't exist. w+: Opens a file for writing and reading.
I think you have pretty much figured this out. Although I guess, you want authoritative answer.
It is true that the documentation does not mention "rw+"
. Yet, there is something better: PHP source code!
I had a hard time trying to navigate the source code until I found the article series PHP's Source Code For PHP Developers (Part 1, Part 2, Part 3, Part 4). I know the links jump between two sites, that series is hip like that. By the way, I didn't find the announced Part 5.
Note: Those articles are old, they are talking about PHP 5.4.
Let us see what fopen
actually does... let us fall into the rabbit hole...
First we look at the function definition (which I found following the advice of the linked part 2 above). I notice it uses php_stream_open_wrapper_ex
, which I found elsewhere, it just uses _php_stream_open_wrapper_ex
which we find in stream.c.
What does _php_stream_open_wrapper_ex
do with mode
? It passes it to stream_opener
.
Looking for the definition of stream_opener
took me to the type php_stream_wrapper_ops
in php_streams.h.
Searching for uses of the type php_stream_wrapper_ops
leaded me to plain_wrapper.c.
There are actually a lot of initializations of php_stream_wrapper_ops
that allow to open different things. We are looking at php_fopen_wrapper.c because it has an initialization of php_stream_wrapper_ops
where stream_opener
is php_plain_files_stream_opener
.
We are getting there...
php_plain_files_stream_opener
is further down in the same file. It delegates to php_stream_fopen_rel
.
php_streams.h
defines php_stream_fopen_rel
by using _php_stream_fopen
. Which is back on plain_wrapper.c.
Finally, _php_stream_fopen
calls php_stream_parse_fopen_modes
. Which will take the string and output some flags, Yay!
Let us have a look at php_stream_parse_fopen_modes
:
PHPAPI int php_stream_parse_fopen_modes(const char *mode, int *open_flags) { int flags; switch (mode[0]) { case 'r': flags = 0; break; case 'w': flags = O_TRUNC|O_CREAT; break; case 'a': flags = O_CREAT|O_APPEND; break; case 'x': flags = O_CREAT|O_EXCL; break; case 'c': flags = O_CREAT; break; default: /* unknown mode */ return FAILURE; } if (strchr(mode, '+')) { flags |= O_RDWR; } else if (flags) { flags |= O_WRONLY; } else { flags |= O_RDONLY; } #if defined(O_CLOEXEC) if (strchr(mode, 'e')) { flags |= O_CLOEXEC; } #endif #if defined(O_NONBLOCK) if (strchr(mode, 'n')) { flags |= O_NONBLOCK; } #endif #if defined(_O_TEXT) && defined(O_BINARY) if (strchr(mode, 't')) { flags |= _O_TEXT; } else { flags |= O_BINARY; } #endif *open_flags = flags; return SUCCESS; }
For abstract, this is what it does (ignoring the details):
It takes the first character of mode
and checks if it is r
, w
, a
, x
, c
. If it recognizes any of those, it sets the appropriate flag. Otherwise we have a FAILURE
.
It looks for +
somewhere in the string and sets the appropriate flags.
It looks for e
, n
and t
(depending on Preprocessor Directives) somewhere in the string and sets the appropriate flags.
Return SUCCESS
.
You asked:
What is the difference between fopen modes “r+” and “rw+” in PHP?
Nothing. PHP only cares that the string starts with "r"
and has a "+"
. The "w"
is ignored.
Final note: While it is tempting to play with it and write stuff like "read+"
, be careful with that, because those letter could someday have some meaning. It would not be forward compatible. In fact, in some context, "e"
already has a meaning. Instead, I suggest, sticking to the documentation.
Thanks for the excuse to give a look at the PHP source code.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With