My code:
$i = 0;
$file = fopen('ids.txt', 'w');
foreach ($gemList as $gem)
{
fwrite($file, $gem->getAttribute('id') . '\n');
$gemIDs[$i] = $gem->getAttribute('id');
$i++;
}
fclose($file);
For some reason, it's writing \n as a string, so the file looks like this:
40119\n40122\n40120\n42155\n36925\n45881\n42145\n45880
From Google'ing it tells me to use \r\n, but \r is a carriage return which doesn't seem to be what I want to do. I just want the file to look like this:
40119
40122
40120
42155
36925
45881
42145
45880
Thanks.
Replace '\n' with "\n". The escape sequence is not recognized when you use '.
See the manual.
For the question of how to write line endings, see the note here. Basically, different operating systems have different conventions for line endings. Windows uses "\r\n", unix based operating systems use "\n". You should stick to one convention (I'd chose "\n") and open your file in binary mode (fopen should get "wb", not "w").
PHP_EOL is a predefined constant in PHP since PHP 4.3.10 and PHP 5.0.2. See the manual posting:
Using this will save you extra coding on cross platform developments.
IE.
$data = 'some data'.PHP_EOL;
$fp = fopen('somefile', 'a');
fwrite($fp, $data);
If you looped through this twice you would see in 'somefile':
some data
some data
Use PHP_EOL which outputs \r\n or \n depending on the OS.
You can also use file_put_contents():
file_put_contents('ids.txt', implode("\n", $gemList) . "\n", FILE_APPEND);
Related
It's strange PHP Reading my Excel generated CSV file into a single line. Code is:
if ($file) {
while (($line = fgets($file)) !== false) {
print '<div>'.$line.'</div>'."<br/>";
}
} else {
// error opening the file.
}
fclose($file);
CSV
Name, City
Jon,Paris
Doe,Madrid
Add this code before reading the file.
ini_set("auto_detect_line_endings", true);
When turned on, PHP will examine the data read by fgets() and file() to see if it is using Unix, MS-Dos or Macintosh line-ending conventions.
This enables PHP to interoperate with Macintosh systems, but defaults to Off, as there is a very small performance penalty when detecting the EOL conventions for the first line, and also because people using carriage-returns as item separators under Unix systems would experience non-backwards-compatible behaviour.
Most likely, PHP is not correctly detecting the line endings in your file. The fgets documentation points this out.
You will probably want to write code like this:
$oldLineEndings = ini_set('auto_detect_line_endings', true);
//your while loop here
ini_set('auto_detect_line_endings', $oldLineEndings);
If you need to actually parse the csv, you may also want to look at fgetcsv.
I create a CSV file for download by our client using
$output = fopen('php://output', 'w');
and using fputcsv() to write data to a CSV file which is downloaded by the client.
I am running PHP on Linux and consequently the line endings are not interpreted by many Windows applications.
I could write the CSV file to a directory on the server, read it back in and perform a str_replace() from \n to \r\n, but this seems a rather clunky way of solving the problem. Is there a way to perform the conversion without creating a physical file?
You could use stream filters to accomplish this. This example writes to a physical file, but it should work fine for php://output as well.
// filter class that applies CRLF line endings
class crlf_filter extends php_user_filter
{
function filter($in, $out, &$consumed, $closing)
{
while ($bucket = stream_bucket_make_writeable($in)) {
// make sure the line endings aren't already CRLF
$bucket->data = preg_replace("/(?<!\r)\n/", "\r\n", $bucket->data);
$consumed += $bucket->datalen;
stream_bucket_append($out, $bucket);
}
return PSFS_PASS_ON;
}
}
// register the filter
stream_filter_register('crlf', 'crlf_filter');
$f = fopen('test.csv', 'wt');
// attach filter to output file
stream_filter_append($f, 'crlf');
// start writing
fputcsv($f, array('1 1', '2 2'));
fclose($f);
Not sure if you can do this with PHP itself. There may be a way to change PHP's EOL for file writing, but it's probably system dependent. You don't have a windows system you could ping, do you? ;)
As for a real solution, instead of str_replace line-by-line, you could use the Linux program unix2dos (inverse of dos2unix) assuming you have it installed:
fputcsv($fh ...)
exec("unix2dos " . escapeshellarg($filename));
Create the file with \n line endings on a Linux machine
FTP the file as ASCII from the Linux machine to a Windows machine
Hey presto! All line endings are now \r\n in the file on the Windows machine
Rather than writing the file, a better solution is to use output buffering
function output($buffer) {
return str_replace("\n", "\r\n", $buffer);
}
ob_start('output');
fputcsv(....);
Since PHP 8.1 fputcsv accepts a new $eol parameter to do this. By default is "\n" but can change it to "\r\n".
fputcsv($stream, $fields, eol: "\r\n");
If PHP is not properly recognizing the line endings when reading files either on or created by a Macintosh computer, enabling the auto_detect_line_endings run-time configuration option may help resolve the problem.
ini_set("auto_detect_line_endings", true);
Hi I am trying to create some code that first reads the existing contents of the file in and then adds the new line of code on a new line but the code i am using just adds it on the new text on to the already existing line instead of the new line...
Here is the code i am using:
<?php
$id = $_GET['id'];
$userfile = "user1.txt";
$fo = fopen($userfile, 'r') or die("can't open favourites file");
$currentdata = fread($fo, filesize($userfile));
fclose($fo);
$fw = fopen($userfile, 'w') or die("can't open favourites file");
$currentprocessed = "$currentdata\n";
fwrite($fw, $currentprocessed);
fwrite($fw, $id);
fclose($fw);
?>
I have tried a whole range of different ideas but nothing has worked, any help would be appreciated.
Line endings per OS
Unix / Linux
\n
DOS / Windows
\r\n
Invalid
\r and \n\r
The value of PHP_EOL constant depends on the platform php is running on.
It doesn't detect the line-endings in the current file or anything magic.
Instead of appending \n, concatenate the constant PHP_EOL which is always the correct newline character for the current platform.
It might also be an issue with the program you're using to open the text file with. For instance, Notepad on Windows is incapable of understanding unix style newlines.
I ran into this same issue. What application are you using to read the file? I found that for some reason Notepad (my default for .txt files) didn't recognize the "\n\r" escape characters. I opened my .txt file that I was writing to using Notepad++, Atom (my text editor of choice), or in a browser and they all showed the line breaks just fine.
When I try to open a .log file created by a game in PHP I get a bunch of this.
ÿþ*�*�*�*�*�*�*�*�*�*�*�*�*�*�*�*�*�*�*�*�*�*�*�*�*�*�*�*�*�*�*�*�*�*�*�*�*�*�*�*�*�*�*�*�*�*�*�*�*�*�*�*�*�*�*�*�*�*�*�*� �
K�2� �E�n�g�i�n�e� �s�t�a�r�t� �u�p�.�.�.� �
[�2�0�0�9�/�2�2�/�0�9�]� �
[�1�6�:�0�7�:�3�3�]� �
[�0�.�1�.�4�6�.�0�]� �
[�0�]� �
I have no idea as to why? My code is
$file = trim($_GET['id']);
$handle = #fopen($file, "a+");
if ($handle) {
print "<table>";
while (!feof($handle)) {
$buffer = stream_get_line($handle, 10000, "\n");
echo "<tr><td width=10>" . __LINE__ . "</td><td>" . $buffer . "</td></tr>";
}
print "</table>";
fclose($handle);
I'm using stream_get_line because it is apparently better for large files?
PHP doesn't really know much about encodings. In particular, it knows nothing about the encoding of your file.
The data looks like UTF-16LE. so you'll need to convert that into something you can handle - or, since you're just printing, you can convert the entire script to output its HTML as UTF-16LE as well.
I would probably prefer converting to UTF-8 and using that as the page encoding, so you're sure no characters are lost. Take a look at iconv, assuming it's available (a PHP extension is required on Windows, I believe).
Note that regardless of what you do, you should strip the first two characters of the first line, assuming the encoding is always the same. In the data you're showing, these characters are the byte order mark, which tells us the file's encoding (UTF-16LE, like I mentioned earlier).
However, seeing as how it appears to be plain text, and all you're doing is printing the data, consider just opening it in a plain old text editor (that supports Unicode). Not knowing your operating system, I'm hesitant to suggest a specific one, but if you're on Windows and the file is relatively small, Notepad can do it.
As a side note, __LINE__ will not give you the line number of the file you're reading, it will print the line number of the currently executing script line.
You might be running into a UTF-8 Byte Order Mark: http://en.wikipedia.org/wiki/Byte-order_mark
Try reading it like so:
<?php
// Reads past the UTF-8 bom if it is there.
function fopen_utf8 ($filename, $mode) {
$file = #fopen($filename, $mode);
$bom = fread($file, 3);
if ($bom != b"\xEF\xBB\xBF")
rewind($file, 0);
else
echo "bom found!\n";
return $file;
}
?>
From: http://us3.php.net/manual/en/function.fopen.php#78308
I have a form that allows the user to either upload a text file or copy/paste the contents of the file into a textarea. I can easily differentiate between the two and put whichever one they entered into a string variable, but where do I go from there?
I need to iterate over each line of the string (preferably not worrying about newlines on different machines), make sure that it has exactly one token (no spaces, tabs, commas, etc.), sanitize the data, then generate an SQL query based off of all of the lines.
I'm a fairly good programmer, so I know the general idea about how to do it, but it's been so long since I worked with PHP that I feel I am searching for the wrong things and thus coming up with useless information. The key problem I'm having is that I want to read the contents of the string line-by-line. If it were a file, it would be easy.
I'm mostly looking for useful PHP functions, not an algorithm for how to do it. Any suggestions?
preg_split the variable containing the text, and iterate over the returned array:
foreach(preg_split("/((\r?\n)|(\r\n?))/", $subject) as $line){
// do stuff with $line
}
I would like to propose a significantly faster (and memory efficient) alternative: strtok rather than preg_split.
$separator = "\r\n";
$line = strtok($subject, $separator);
while ($line !== false) {
# do something with $line
$line = strtok( $separator );
}
Testing the performance, I iterated 100 times over a test file with 17 thousand lines: preg_split took 27.7 seconds, whereas strtok took 1.4 seconds.
Note that though the $separator is defined as "\r\n", strtok will separate on either character - and as of PHP4.1.0, skip empty lines/tokens.
See the strtok manual entry:
http://php.net/strtok
If you need to handle newlines in diferent systems you can simply use the PHP predefined constant PHP_EOL (http://php.net/manual/en/reserved.constants.php) and simply use explode to avoid the overhead of the regular expression engine.
$lines = explode(PHP_EOL, $subject);
It's overly-complicated and ugly but in my opinion this is the way to go:
$fp = fopen("php://memory", 'r+');
fputs($fp, $data);
rewind($fp);
while($line = fgets($fp)){
// deal with $line
}
fclose($fp);
Potential memory issues with strtok:
Since one of the suggested solutions uses strtok, unfortunately it doesn't point out a potential memory issue (though it claims to be memory efficient). When using strtok according to the manual, the:
Note that only the first call to strtok uses the string argument.
Every subsequent call to strtok only needs the token to use, as it
keeps track of where it is in the current string.
It does this by loading the file into memory. If you're using large files, you need to flush them if you're done looping through the file.
<?php
function process($str) {
$line = strtok($str, PHP_EOL);
/*do something with the first line here...*/
while ($line !== FALSE) {
// get the next line
$line = strtok(PHP_EOL);
/*do something with the rest of the lines here...*/
}
//the bit that frees up memory
strtok('', '');
}
If you're only concerned with physical files (eg. datamining):
According to the manual, for the file upload part you can use the file command:
//Create the array
$lines = file( $some_file );
foreach ( $lines as $line ) {
//do something here.
}
foreach(preg_split('~[\r\n]+~', $text) as $line){
if(empty($line) or ctype_space($line)) continue; // skip only spaces
// if(!strlen($line = trim($line))) continue; // or trim by force and skip empty
// $line is trimmed and nice here so use it
}
^ this is how you break lines properly, cross-platform compatible with Regexp :)
Kyril's answer is best considering you need to be able to handle newlines on different machines.
"I'm mostly looking for useful PHP functions, not an algorithm for how
to do it. Any suggestions?"
I use these a lot:
explode() can be used to split a string into an array, given a
single delimiter.
implode() is explode's counterpart, to go from array back to string.
Similar as #pguardiario, but using a more "modern" (OOP) interface:
$fileObject = new \SplFileObject('php://memory', 'r+');
$fileObject->fwrite($content);
$fileObject->rewind();
while ($fileObject->valid()) {
$line = $fileObject->current();
$fileObject->next();
}
SplFileObject doc: https://www.php.net/manual/en/class.splfileobject.php
PHP IO streams: https://www.php.net/manual/en/wrappers.php.php