Writing large string to text file - php

A trivial use of PHP and frwite() to create/write to a text file.
However, is there a way to write a very large text string to a file using fwrite?()? I assume there is, and that it involves some form of buffer management. The PHP docs don't seem to have this covered.
Sample code:
$p = "Some really large string ~ 100-250K in size"
$myFile = "testp.txt";
$fh = fopen($myFile, 'w') or die("can't open file");
set_file_buffer($fh, 1000000);
fwrite($fh, $p);
fclose($fh);
Believe it or not, this simply gets a file with the name of the file inside the file.
Using a much smaller text string, it works as expected. Pointers to what I should do would be useful.
UPDATE:
Some of you are missing that I did try the above with a string of ~100K, and it didn't work. All I got in the output file was the name of the file!!!
thanks
::: 2ND UPDATE....
never mind.. the whole thing was user error... god i need a drink... or sleep!
thanks
php/fwrite works as i thought it would/should.. nothing to see here..!

There is no limit on how much data can be written to a stream (a file handle) in PHP and you do not need to fiddle with any buffers. Just write the data to the stream, done.

Related

How can i save all the variable results from a echo into a txt file using php?

I wrote a php script that generates random tokens, and I want to output these tokens into a .txt file.
Below is the code:
do {
$token = bin2hex(random_bytes(2));
echo("token: $token");
$myfile = fopen("output.txt", "w+") or die("Unable to open file!");
fwrite($myfile, $token);
fclose($myfile);
} while ($token != "e3b0");
It echos multiple tokens, until the echo = e3b0, but when I try to write the result on a txt file, it only writes "e3b0", is that a way to write all the results of the "echo" into a txt file?
As I see it the most efficient way to do this would be to do everything just enough times.
Meaning we have to loop and generate the codes, but we only need to write to the file once,same thing with the echo.
$code = "start value";
while ($code != "e3b0"){
$arr[] = $code = bin2hex(random_bytes(2));
}
echo $str = implode("\n", $arr);
file_put_contents("output.txt", $str);
This is do everything just enough times, and a more optimized code.
But if you run this in a browser then it will not output them on separate lines on screen, only in the txt file. But if you open the source it will be on separate lines.
That is because I did not use the br tag in the implode.
EDIT: Efficiency was never asked in original OP question. This post is being edited to include efficiency, namely no need to reopen and close a file.
Your use of w+ will always place the file pointer at the beginning of the file and truncate the file in the process. So as a result, you always end up with the last value written.
From php.net on fopen w+:
Open for reading and writing; place the file pointer at the beginning of the file
and truncate the file to zero length. If the file does not exist, attempt to create it.
Using your existing code, a solution then would be as follows:
$myfile = fopen("output.txt", "a+") or die("Unable to open file!");
do {
$token = bin2hex(random_bytes(2));
echo("token: $token");
fwrite($myfile, $token);
} while ($token != "e3b0");
fclose($myfile);
Where a+ in the same docs says:
Open for reading and writing; place the file pointer at the end of the file.
If the file does not exist, attempt to create it. In this mode, fseek()
only affects the reading position, writes are always appended.
Source:
https://www.php.net/manual/en/function.fopen.php
Amendments:
As #andreas mentions, opening and closing the file repeatedly inside the loop is not necessary (nor efficient). Since you are appending, you can open it once with a+ before the loop begins; and close it after the loop ends.
In terms of having a separator char between tokens written to the file, a carriage return (line break) is a good choice. In this way you can reduce the amount of parsing you would have to program when programmatically reading the file. For this, your writes could be written as follows:
fwrite($myfile, $token . "\n");

Script reading from STDIN

I have a php script that reads text files. I use fgetc() to get every character one by one. I open file to read from with fopen(),and then I use file descriptor returned from fopen() as a first argument to fgetc(). I tried to do the same thing with reading from STDIN. I wanted to run the script in a terminal, give it the whole text (that was in a text file before) and press enter. I thought that the script would read it and will run as if it read from a text file, but it doesn't work. It only works when a type every single character alone and press enter after it. Why is that? Is there a possibility to make the script behave the way I wanted? That I can give it the whole text to the terminal at once? Should I use different functions or something?
$inputFile = fopen($path, "w");
while(($char = fgetc($inputFile)) !== false){
dosomething();
}
What I'm trying to do is to replace $inputFile in fgetc()with STDIN.
See http://php.net/manual/en/features.commandline.io-streams.php, second comment
Note, without the stream_set_blocking() call, fgetcsv() hangs on STDIN, awaiting input from the user, which isn't useful as we're looking for a piped file. If it isn't here already, it isn't going to be.
<?php
stream_set_blocking(STDIN, 0);
$csv_ar = fgetcsv(STDIN);
I think it's the same for fgetc. After all it
string fgetc ( resource $handle ) Gets a character from the given file pointer.
Emphasis mine.
See http://php.net/manual/en/function.fgetc.php
...

Can't get fopen to open file

I can't tell you how stupid I feel having to ask this question, but I've been working on the most simple of commands (for two days) and can't find the problem. I 'borrowed' some code for a non repeating hit counter. I have tried to get it to work and I finally determined I'm not getting access to the simple txt files that store the hits or the one that stores the ip addresses. I've read the problems here, looked at the command in a 'Dummies' book and even watched YouTube videos and I'm blind to the problem. I've tried using a string for the file name and using the filename directly. I had the files in a sub folder on the server and thought that might be the issue so I moved them to the root with the same error. If someone can see why this isn't working I'd be eternally grateful.
This is only part of the whole code but it's where I determined that it fails.
$filename = 'countfix.txt';
$handle = fopen('$filename', 'r');
fread($handle, $current_inc)
or die ("Can't open file");
echo $current_inc;
fclose($handle);
Thanks.
This is wrong:
$handle = fopen('$filename', 'r'); // tries to open a file named $filename
It should be written this way:
$handle = fopen($filename, 'r'); // no quotes, opens countfix.txt
You might have meant to write this instead:
$handle = fopen("$filename", 'r');
wherein the double quotes will cause the real value of $filename to be substituted into the string (thus making the code work), but there is no point in doing that. Lose the quotes.
Additionally, this code doesn't do what it says:
fread($handle, $current_inc) or die ("Can't open file");
Here the error message is printed if you cannot read from the file, not when you fail to open it. You should check the return value of fopen instead or modify the message to be more accurate.
This is the right way to do it:
$handle = fopen("$filename", 'r');
You must enclose variables with doubble quotes, or not enclose them at all! This is how PHP is.
You might want to read this: what is the difference between single quoted and double quoted strings in php

Add a line to top of csv file (first line) with PHP

Need to process large csv files with php.
Working with fgetcsv and performance seems pretty good. For even better/ faster processing I would like the csv files to have column names on the first row, which are missing right now.
Now I would like to add a top row with columns names to the csv file with PHP before processing the files with fgetcsv.
Is there a way to add a line top the top of the file with php easily? Or would this mean I have to take a approach like below?
List item
List item
create a temp file
add the column names to this temp file
read original csv file contents
put original csv contents into the temp file
delete original file
rename the temp file
Any feedback on how to do this in the most effective way is highly appreciated. Thanks for your time :)
Please try this .. much simpler and straight to the point.
$file = 'addline.csv';
$header = "Name, IP, Host, RAM, Task, NS \r\n";
$data = file_get_contents($file);
file_put_contents($file, $header.$data);
You are done. Hope this helps...
Read the CSV file using fgetcsv.
Close the file.
Open the file using "w" (write) mode.
Write the headers.
Close the file.
Open the file using "a" (append) mode.
Write the CSV file using fputcsv.
Voila!
Just do it the way you provided. there is no easy way to extend a file on the beginning instead of the end. it's like writing on paper. it's easy to add new lines below your text but you can't write above you text.
Don't use fopen($file, "r+") or fopen($file, "c") as this will remove existing lines at the beginning or even all lines of your file.
Why not to define header in your code manually, especially if every file has the same header?
If you really need to insert header into CSV files before you process them maybe you should consider using sed like this: sed -i 1i'"header 1","header 2"' file.csv

fgetcsv doesn't validate whether or not this is a csv file

This question has been asked several times, but as it turns out all of the answers I have come across have been wrong.
I'm having a problem validating whether a file is a CSV or not. Users upload a file, and the application checks to see if fgetcsv works in order to make sure it's a CSV and not an Excel file or something else. That has been the traditional answer I'm finding via Google.
e.g.:
if ($form->file->receive()) {
$fileName = $form->file->getFileName();
$handle = fopen($fileName, 'r'); // or 'w', 'a'
if (fgetcsv($handle)) {
die('sos yer face');
}
if ($PHPExcelReader->canRead($fileName)) {
die('that\'s what she said');
}
}
What happens with the above is 'sos yer face' because fgetcsv validates as true no matter what you give it if your handle comes from fopen($fileName, 'r') as long as there is a file to read; and fgetcsv always false when using fopen($fileName, 'w') or 'a' because the pointer will be initiated at the EOF. This is according to the php.net documentation.
Maybe what I'm saying is ridiculous and I just don't realize it. Can anyone please fix my brain.
The problem with validating whether or not a file is a CSV file is that CSV is not a well-defined format. In fact, by most definitions of CSV, just about any file would be a valid CSV, treating each line as a row with a single column.
You'll need to come up with your own validation routine specific to the domain you are using it in.

Categories