php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #23406 \r\n not functioning the same from 4.3.1 and prior
Submitted: 2003-04-29 08:03 UTC Modified: 2003-06-06 03:30 UTC
Votes:1
Avg. Score:4.0 ± 0.0
Reproduced:1 of 1 (100.0%)
Same Version:1 (100.0%)
Same OS:1 (100.0%)
From: gfraley5 at earthlink dot net Assigned: wez (profile)
Status: Closed Package: Filesystem function related
PHP Version: 4.3.2RC2 OS: Win98SE,WinXP,Win2K
Private report: No CVE-ID: None
 [2003-04-29 08:03 UTC] gfraley5 at earthlink dot net
This code snippet demonstrates the problem.  Under 4.3.1 and prior, it functions correctly.  Under 4.3.2 (all versions) it does not function the same and is actually wrong.

<? 
$myArray[] = 'msgid'."\r\n"; 
$myArray[] = '1049987091'."\r\n"; 
$myArray[] = '1050930128'."\r\n"; 

$fp = fopen("problemFile.php",'w') or die("Unable to open file"); 
for ($i=0;$i<count($myArray);$i++) { 
	if ($i==0) $prefx = "<? Header(\"HTTP/1.0 403 Forbidden\");exit;?>\r\n"; 
else $prefx = ""; 
fwrite($fp,$prefx.$myArray[$i]); 
} 
fclose($fp); 
echo nl2br(readfile("problemFile.php"));
?>


Under 4.3.1 and prior, here is the output of problemFile.php:
<? Header("HTTP/1.0 403 Forbidden");exit;?>
msgid
1049987091
1050930128


Under 4.3.2, here is the output of problemFile.php.  Notice the difference in the behaviour of the \r\n:
<? Header("HTTP/1.0 403 Forbidden");exit;?>
msgid
1049987091

1050930128


Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2003-04-29 09:12 UTC] wez@php.net
fopen("problemFile.php",'wb')
Does that help?

Also, check the line endings in the actual file (not in the output generated by php), and your auto_detect_line_endings ini setting.

 [2003-04-29 09:27 UTC] gfraley5 at earthlink dot net
Adding the 'wb' corrects the problem.  But, and here is the most important issue, the behavior HAS changed from 4.3.1 and prior to 4.3.2 and it definitely breaks and renders useless the file that it writes out, based on how the input routines then read that file in 4.3.1 and prior.  If you use \n instead of \r\n you have the same issue except the you don't get the line feed extra line.  I did check the actual line endings and they are different and the byte count is different also.  My ini settings have not changed.

Can you explain why this change in behaviour has been made?

Thanks.
 [2003-04-29 09:34 UTC] wez@php.net
The curious thing is that PHP doesn't treat the line endings specially itself.

Can you try this with 4.2.3 (NOT 4.3.2!)?

It's more likely that this was a bug in 4.3.0/4.3.1 that has been fixed; I do want to get to the bottom of it though.

In general, it is always a good idea to use the 'b' flag in your fopen calls if you are planning to write canonical line endings, as windows does strange things with line endings on text-mode file handles.

 [2003-04-29 14:24 UTC] gfraley5 at earthlink dot net
Where can I get the older version?
 [2003-04-29 16:02 UTC] michael dot mauch at gmx dot de
<http://www.php.net/downloads.php> (scroll down to where it says "PHP 4.2.3").
 [2003-04-29 16:34 UTC] gfraley5 at earthlink dot net
It works _perfectly_ under 4.2.3 WITHOUT using 'wb', just like 4.3.1!  That's the problem :(.  I always upgrade before the finals are released and it has always worked as just 'w'.  Not only that, and hold on here, but the windows version has NEVER required \r\n.  It always works with \n but that's a whole 'nother issue :)
 [2003-04-30 05:57 UTC] sniper@php.net
Wez: You broke it, fix it before 4.3.2 goes gold.
(some streams stuff :)

 [2003-04-30 06:24 UTC] wez@php.net
I can't reproduce this here (tried 4.2.1 and 4.3.2 under XP).

NOTE: readfile() returns the number of bytes it wrote, NOT the contents of the file.
Use file_get_contents() for that.

Please try this script on 4.3.2 and your 4.2.3 and report back (paste the output from each into this report):

<?php
$myArray[] = 'msgid'."\r\n"; 
$myArray[] = '1049987091'."\r\n"; 
$myArray[] = '1050930128'."\r\n"; 

$l = 0;

$fp = fopen("problemFile.php",'w') or die("Unable to open file"); 
for ($i=0;$i<count($myArray);$i++) { 
	if ($i==0) {
		$prefx = "<? Header(\"HTTP/1.0 403 Forbidden\");exit;?>\r\n";
	} else {
		$prefx = ""; 
	}
	$l += fwrite($fp, $prefx.$myArray[$i]); 
} 
fclose($fp); 
echo "Wrote: $l bytes; filesize is now " . filesize("problemFile.php") . "\n";

echo "==== using readfile =====\n";
$x = readfile("problemFile.php");
echo "==== readfile read $x bytes ====\n";
echo "==== using fopen 'r' ===\n";
$fp = fopen("problemFile.php", "r");
while (!feof($fp)) {
	echo fgets($fp);
}
fclose($fp);
echo "==== using fopen 'rb' ===\n";
$fp = fopen("problemFile.php", "rb");
while (!feof($fp)) {
	echo fgets($fp);
}
fclose($fp);
echo "==== done ===\n";
?>
 [2003-04-30 12:06 UTC] gfraley5 at earthlink dot net
From 4.2.3
Wrote: 76 bytes; filesize is now 80 ==== using readfile ===== msgid 1049987091 1050930128 ==== readfile read 80 bytes ==== ==== using fopen 'r' === msgid 1049987091 1050930128 ==== using fopen 'rb' === msgid 1049987091 1050930128 ==== done === 

From 4.3.2
Wrote: 76 bytes; filesize is now 77 ==== using readfile ===== msgid 1049987091 1050930128 ==== readfile read 77 bytes ==== ==== using fopen 'r' === msgid 1049987091 1050930128 ==== using fopen 'rb' === msgid 1049987091 1050930128 ==== done ===
 [2003-04-30 13:18 UTC] wez@php.net
Which SAPI are you using?
CGI/FastCGI, Apache or IIS?
 [2003-04-30 13:58 UTC] gfraley5 at earthlink dot net
Apache
 [2003-05-01 09:11 UTC] wez@php.net
The Apache SAPI leaves the _fmode variable as-is, whereas the CLI, CGI and Embed SAPIs all force it to binary mode.
What this means is that for the latter three,
fopen($file, "r") is forced to fopen($file, "rb") internally by the MS libc.

Technically speaking this behaviour is a bit naughty, as it prevents opening files in text-mode when using CLI and CGI, and Embed interferes with the hosting application's binary settings (this is the main reason we don't set it in Apache).

I can't find any logical reason for the apparent change in behaviour under Apache, except for the fact that we are now using the lower level file descriptors returned by _open() rather than calling the slightly higher level fopen() to get at the files.  Why this makes a difference, I can't tell (it just doesn't make sense).

However, all of this aside, the behaviour you are currently experiencing under Apache is the technically correct behaviour that you should expect when opening a file in text mode.

The correct fix for your problem is to open the file in binary mode, as is suggested in the PHP manual for the fopen() function, and in numerous places throughout the manual when talking about binary safety.

I'm tempted to mark this report as bogus (because it is the expected behaviour), but want to discuss the implications of this with some of the other developers first, because of potential backwards compatibility issues.
 [2003-05-01 09:18 UTC] gfraley5 at earthlink dot net
Thanks!  I have submitted this in the past and it was rebuffed and marked as bogus.  I don't think it should be marked as bogus because it is a definite backward compatability issue that will render files useless (as it does with hundreds of my users that use legacy 'w' instead of 'wb') if written to without the 'B' attribute.  If anything, it could/should be marked as an 'enhancement' or something as you have changed the behavior whether intentionally or not.  Was there a specific reason why you wnet to the lower level call open()?  If nothing in particular, then maybe you leave 4.3.2 as is and prepare the public and developers for the change in a future release.  Just a thought.
 [2003-05-01 09:24 UTC] wez@php.net
The reason for the change was primarily to avoid crippling limitations for the number of opened files under Solaris, but has other benefits for the streams API.

My opinion of the backwards compatibility issue here is that it should be a non-issue; the fopen() docs have warned about binary mode for a very long time.  However, I think we will wait and see if we get any more feedback on this issue before making a firm decision.

 [2003-05-15 13:22 UTC] sniper@php.net
For me this looks like bogus.

 [2003-05-17 19:22 UTC] gfraley5 at earthlink dot net
I would disagree.  Since it was never manadatory to use the 'wb' then making a change that forces it, needs to be announced, imo.  Otherwise, files will be ruined if the circumstances mentioned here are used.
 [2003-06-06 03:15 UTC] braden_marr at yahoo dot ca
I believe I may have run into this exact same problem after upgrading to 4.3.2 ("gold" by now) (Apache SAPI) from 4.3.1 (Apache SAPI) on WinXP/Apache 1.3.27. I am running Gallery (on sourceforge) on my web site and found that users submitting photos broke the database; Gallery uses serialize and deserialize to store it's often large objects as files, and the \r\n vs \n used in objects that get serialized as files, breaks the object's file. Since this "bug" seems to be still out in the open and appears to be on the fence for Bogus, I am thinking the Gallery dev should know about this new and special Win32/PHP4.3.2 problem and bend accordingly... unless of course, I am barking up the wrong tree.
 [2003-06-06 03:30 UTC] wez@php.net
PHP will force binary mode starting from 4.3.2.
If you need text mode, you now need to explicitly open with a 't' in your mode string.
No doubt others will complain about this.
We didn't really change the default behaviour in the RC's; its actually some strange inconsistency between ANSI and "posix" functions on the MS libc.
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Thu Dec 26 17:01:31 2024 UTC