fopen is duplicating the same line - php

I have a file that looks like this:
1||Allan||34||male||USA||||55.789.980
2||Georg||32||male||USA||||55.756.180
3||Rocky||21||male||USA||[100][200]||55.183.567
I made a function that when executed adds a given number or removes it if already present, which is $added and equals 100 for this example. This is my code:
$added = $_GET['added']; //100 for this example
$f = fopen($file, "w");
$list = file($file);
foreach ($list as $line) {
$details = explode("||", $line);
if (preg_match("~\b$details[0]\b~", 3)) {
foreach ($details as $key => $value) {
if ($key == 5) {
$newline .= str_replace("[" . $added . "]", "", $value);
} else {
$newline .= $value . "||";
}
}
$line = $newline . "\n";
}
fputs($f, $line);
}
fclose($f);
}
this code is supposed to remove the [100] from the Rocky line since its already present which it kinda does. However, upon further execution instead of adding it back it duplicates the Rocky line and messes it up so the file looks like this:
1||Allan||34||male||USA||||55.789.980
2||Georg||32||male||USA||||55.756.180
3||Rocky||21||male||USA||[100][200]55.183.567
3||Rocky||21||male||USA||[100][200]55.183.567
||
||
why is it doing this? I cant make any sense out of it...
Thank you.

First, you should read the file before you open it for output, because opening with the w mode truncates the file.
Second, you don't need to loop over the fields in $details if you just want to change one of them. Just access and assign it by index.
Then you can put the line back together with implode().
$list = file($file);
$f = fopen($file, "w");
foreach ($list as $line) {
$details = explode("||", $line);
if (preg_match("~\b$details[0]\b~", 3)) {
if (strpos("[$added]", $details[5]) === false) {
$details[5] = "[$added]" . $details[5];
} else {
$details[5] = str_replace("[$added]", "", $details[5]);
}
$line = implode('||', $details)
}
fputs($f, $line);
}
fclose($f);

Related

PHP - Incrementing multiple values in a text file with explode

I'm trying to increment a counter inside a text file, that counts HTTP responses from some APIs. This part is handled correctly at the moment. The issue I'm having is that when my text file has more than two values that need to be incremented, only one of the fields is updated and I'm not sure what the structure of the explode should be to update the other value.
The structure of the text file is:
api:one
success:1
fail:1
and no matter what response is received, only the fail is updated.
The code section I have at the moment is:
if ($status == "6" OR $status == "2") {
$filename = '/home/path/to/file/'.basename(__DIR__).'-responses.txt';
$lines = file($filename);
if(!is_file($filename)){
$default = 'api:one' . "\n" . 'success:1' . "\n" . 'fail:1';
file_put_contents($filename, $default);
} else {
foreach ($lines as $k=>$v) {
$exploded = explode(":", $v);
if ($exploded[0] == "fail") {
$exploded[1]++;
$lines[$k] = implode(":", $exploded);
}
}
file_put_contents($filename, $lines);
}
} else {
$filename = '/home/path/to/file/'.basename(__DIR__).'-responses.txt';
$lines = file($filename);
if(!is_file($filename)){
$default = 'api:one' . "\n" . 'success:1' . "\n" . 'fail:1';
file_put_contents($filename, $default);
} else {
foreach ($lines as $k=>$v) {
$exploded = explode(":", $v);
if ($exploded[0] == "success") {
$exploded[1]++;
$lines[$k] = implode(":", $exploded);
}
}
file_put_contents($filename, $lines);
}
}
The problem is that you're not removing the newlines from the lines before you try to increment the numbers. The success line has a newline at the end, and when you try to increment "1\n" it doesn't do anything, since that's not a number.
Use the FILE_IGNORE_NEW_LINES option to remove the newlines when creating the array, then add them back when writing back to the file.
if ($status == "6" OR $status == "2") {
$filename = '/home/path/to/file/'.basename(__DIR__).'-responses.txt';
if(!is_file($filename)){
$default = 'api:one' . "\n" . 'success:1' . "\n" . 'fail:1';
file_put_contents($filename, $default);
} else {
$lines = file($filename, FILE_IGNORE_NEW_LINES);
foreach ($lines as $k=>$v) {
$exploded = explode(":", $v);
if ($exploded[0] == "fail") {
$exploded[1]++;
$lines[$k] = implode(":", $exploded);
}
}
file_put_contents($filename, implode("\n", $lines));
}
} else {
$filename = '/home/path/to/file/'.basename(__DIR__).'-responses.txt';
if(!is_file($filename)){
$default = 'api:one' . "\n" . 'success:1' . "\n" . 'fail:1';
file_put_contents($filename, $default);
} else {
$lines = file($filename, FILE_IGNORE_NEW_LINES);
foreach ($lines as $k=>$v) {
$exploded = explode(":", $v);
if ($exploded[0] == "success") {
$exploded[1]++;
$lines[$k] = implode(":", $exploded);
}
}
file_put_contents($filename, implode("\n", $lines));
}
}
Also, you should do the check for whether the file exists before you try to read the file.

(PHP, AJAX) Simple counter. Figured the problem, no solution

Apologies for having to ask.
In short I'm making a simple imageboard with a "like" button for each image. The number of clicks (likes) stores in 'counter.txt' file in the following format:
click-001||15
click-002||7
click-003||10
Clicking the buttons initiates a small php code via AJAX. counter.php:
<?php
$file = 'counter.txt'; // path to text file that stores counts
$fh = fopen($file, 'r+');
$id = $_REQUEST['id']; // posted from page
$lines = '';
while(!feof($fh)){
$line = explode('||', fgets($fh));
$item = trim($line[0]);
$num = trim($line[1]);
if(!empty($item)){
if($item == $id){
$num++; // increment count by 1
echo $num;
}
$lines .= "$item||$num\r\n";
}
}
file_put_contents($file, $lines);
fclose($fh);
?>
So when I run the website and testclick my buttons I get the following message:
Notice: Undefined offset: 1 in C:\wamp64\www\wogue\counter.php on line
18
I figured that the script 'counter.php' creates a whitespace on a new string in 'counter.txt' and so it fails to 'explode' and thus make a [1] index. The way I figured that is by backspacing the last empty line in .txt file and saving it. It ran without errors until I clicked a button a few times then the same error appeared.
The piece of code in index looks like this:
<?php
$clickcount = explode("\n", file_get_contents('counter.txt'));
foreach($clickcount as $line){
$tmp = explode('||', $line);
$count[trim($tmp[0])] = trim($tmp[1]);
}
?>
Any ideas?..
Trim $line and if it is not empty - do what you need:
$line = trim(fgets($fh));
if ($line) {
$line = explode('||', $line);
$item = trim($line[0]);
$num = trim($line[1]);
if(!empty($item)){
if($item == $id){
$num++; // increment count by 1
echo $num;
}
$lines .= "$item||$num\r\n";
}
}
Or check with empty this way:
$line = explode('||', fgets($fh));
if(!empty(line[0]) && !empty($line[1])){
if(line[0] == $id){
$line[1]++; // increment count by 1
echo $line[1];
}
$lines .= "{$line[0]}||{$line[1]}\r\n";
}
}
You are writing using \r\n as a line separator in counter.php and reading the same file exploding only for \n. You should be consistent.
Just removing the \n should be enough to avoid the extra "space" you're seeing.
<?php
$file = 'counter.txt'; // path to text file that stores counts
$fh = fopen($file, 'r+');
$id = $_REQUEST['id']; // posted from page
$lines = '';
while(!feof($fh)){
$line = explode('||', fgets($fh));
$item = trim($line[0]);
$num = trim($line[1]);
if(!empty($item)){
if($item == $id){
$num++; // increment count by 1
echo $num;
}
$lines .= "$item||$num\n"; //removing the \r here
}
}
file_put_contents($file, $lines);
fclose($fh);
?>

How to update files in PHP

I have some PHP function that requires the line number of a CSV file used as database. Once it has line, it navigates to the specific value that needs to be changed, changes it and rewrites the whole files. Here is my code:
<?php
function update($file, $id, $field, $value)
{
//$id is the line number
$contents = explode("\n", file_get_contents($file));
$fh = fopen($file, "w");
$lines = array();
foreach($contents as $line)
{
if($line == "")
continue;
$fields = explode("|", $line);
if($fields[0] == $id)
{
$line = null;
for($i = 0; $i<count($fields); $i++)
{
if($i == $field)
$fields[$i] = $value;
if($i != count($fields)-1)
$line .= $fields[$i]."|";
else
$line .= $fields[$i];
}
}
$line .= "\n";
fwrite($fh, $line);
}
fclose($fh);
$contents = null;
return true;
}
$id = $_SESSION['id'];
$uid = $_GET['p'];
$myfile = "myfile.txt";
if(update($myfile, 12, 14, "somevalue"))
echo "updated!";
?>
I am unable to find the problem because whenever I run the code, it outputs "updated!" just as it should but when check the file, I find it has not been updated. I do not know why, but it always remains the same! Thanks.
Check that fwrite() is not failing.
Do something like this:
...
$writeSuccess = (fwrite($fh, $line) !== false);
}
fclose($fh);
$contents = null;
return $writeSuccess;
}
...
If it is failing, check that your filesystem permissions are correctly set. The Apache user needs to have write access to whatever file/folder you are writing the file to.
I found out what the problem was.
$id = $_SESSION['id'];
$uid = $_GET['p'];
$myfile = "myfile.txt";
if(update($myfile, 12, 14, "somevalue"))
The line number pointed to the previous line, which made it impossible to update the first line of the file. So all I had to do was
$line ++;

take special lines from txt database PHP

I have text database
0,Apple,Green
1,Banana,Yellow
2,Cherry,Red
and when I call getdata.php?row=2 I need get data which is 2,cherry,red
I am a bachelor in PHP and I have only one example ,
please help me for this problem.
thanks
$file_handle = fopen("./news.txt", "rb");
while (!feof($file_handle) ) {
$line_of_text = fgets($file_handle);
$parts = explode(',', $line_of_text);
print $parts[0] . $parts[1] . $parts[2];
}
fclose($file_handle);
This would work and would also stop reading as soon as it found the right line (unlike the other answers who read the whole no file matter what)
if (isset($_GET['row']))
{
$file_handle = fopen("./news.txt", "rb");
$i = 0;
while (!feof($file_handle))
{
if ($i == $_GET['row'])
{
$line_of_text = fgets($file_handle);
$parts = explode(',', $line_of_text);
print $parts[0] . $parts[1] . $parts[2];
break;
}
$i++;
}
fclose($file_handle);
}
You first have to explode by rule with explode("/n", $txt) than you've an array of each rule. After you stored this explode in to a variable than you should explode a specific value again by ,.
A straightforward way to do this: if record number 2 is always on line number 3.
if (!isset($_GET['row']) || !is_int($_GET['row'])) {
echo "please supply a row number";
die;
}
$lines = file('news.txt');
// assumes record number 2 is on line 3
$row = $_GET['row'] + 1;
$parts = explode(',', $lines[$row]);
print $parts[0] . $parts[1] . $parts[2];
If record number 2 is not guaranteed to be on line 3
$row = $_GET['row'];
foreach ($lines as $line) {
if (strpos($line, $row) === 0) {
$parts = explode(',', $lines[$row]);
print $parts[0] . $parts[1] . $parts[2];
break;
}
}
If the file is extremely large you will want to read line by line from a buffer.
$row = $_GET['row'];
if ($fp = fopen('news.txt', 'r')) {
while ($line = fgets($fp)) {
if (strpos($line, $row) === 0) {
$parts = explode(',', $line);
print $parts[0] . $parts[1] . $parts[2];
break;
}
}
fclose($fp);
}

How to get a recuring parts from a file in php

I have a file file.txt. This file has portions and parts that recur throughout the file. I
am trying to read the parts between the last and the first key words.
I have managed to get the first and the last key words but I can't read the lines between the key words.
Here is my script
$file=file('file.txt');
$begin = 'first_line';
$end='last_line';
foreach ($file as $lineNumber => $line) {
$lineNumber++;
if (strpos($line,$begin))
{
echo $lineNumber.$line."<br/>";
}
elseif (strpos($line,$end))
{
echo $value."<br/>";
}
echo $lineNumber. $line."<br/>";
}
Please some one assist me.
Here you go:
$lines=file('data.txt');
$begin = 'first_line';
$end='last_line';
$switch = false;
$content = "";
foreach ($lines as $line_num => $line) {
if(strpos($line, $begin) !== false) {$switch = true;continue;}
if(strpos($line, $end) !== false) $switch = false;
if(!$switch) continue;
$content .= "Line #<b>{$line_num}</b> : " . htmlspecialchars($line) . "<br />\n";
}
echo $content;
This will do it:
$file = file('file.txt');
$begin = 'first_line';
$end = 'last_line';
$isInside = false;
foreach ($file as $lineNumber => $line)
{
$lineNumber++;
if (!(strpos($line,$begin)===false))
$isInside = true;
if ($isInside)
echo $lineNumber." : ".$line."<br/>";
if (!(strpos($line,$end)===false))
$isInside = false;
}
Some points:
You were displaying everything regardless, my script only shows lines between $begin and $end.
Your comparison is case-sensitive
You had a major bug using strpos and assuming it returns true if it matches. It could also return 0 if the string matches at the beginning,hence using === to catch this. See the disclaimer on the strpos page.
$file=fopen("welcome.txt","r");
while(!feof($file))
{
$open=fgets($file);
print $open;
}
fclose($file);

Categories