I have this text-file:
STATIONS_ID;MESS_DATUM; QN;PP_10;TT_10;TM5_10;RF_10;TD_10;eor
5371;201912250000; 2; 903.5; 2.3; 2.2; 100.0; 2.3;eor
[...]
5371;201912251820; 2; 913.3; 0.4; 0.3; 100.0; 0.4;eor
And I want to get ONLY the last line with timestamp 25-12-2019 18:20 (201912251820).
Thats my php code (finally I want to save the data in my MySQL database):
$row = 1;
if(($handle = fopen("produkt_zehn_now_tu_20191225_20191226_05371.txt", "r")) !== FALSE)
{
while(($data = fgetcsv($handle, 1000, ",")) !== FALSE)
{
echo "<p> 1 fields in line $row: <br /></p>\n";
$row++;
for($c=0; $c < 1; $c++)
{
echo $data[$c] . "<br />\n";
$daten = $data[$c];
$carray = explode(";", $daten);
list($station,$zeit,$quali,$luftdruck,$temp2m,$temp5cm,$feuchte,$taupunkt) = $carray;
echo "<b>temp2m:".$temp2m."</b>";
/*
$res_wetterdaten_dwd = $sql_datenbank -> query("INSERT INTO wetterdaten_dwd
(daten_zeit, daten_luftdruck, daten_temp2m, daten_temp5cm, daten_feuchte, daten_taupunkt, daten_station)
VALUES ('".$zeit."', ".$luftdruck.", ".$temp2m.", ".$temp5cm.", ".$feuchte.", ".$taupunkt.", ".$station.")");
*/
}
}
fclose($handle);
}
<?php
function getDateFromFile($file = 'text.txt')
{
$f = fopen($file, 'r');
$cursor = -1;
$line = '';
fseek($f, $cursor, SEEK_END);
$char = fgetc($f);
/**
* Trim trailing newline chars of the file
*/
while ($char === "\n" || $char === "\r") {
fseek($f, $cursor--, SEEK_END);
$char = fgetc($f);
}
/**
* Read until the start of file or first newline char
*/
while ($char !== false && $char !== "\n" && $char !== "\r") {
/**
* Prepend the new char
*/
$line = $char . $line;
fseek($f, $cursor--, SEEK_END);
$char = fgetc($f);
}
$value = explode(";", $line);
$year = substr($value[1], 0, 4);
$month = substr($value[1], 4, 2);
$day = substr($value[1], 6, 2);
$hour = substr($value[1], 8, 2);
$min = substr($value[1], 10, 2);
$date = new DateTime("$year-$month-$day $hour:$min");`
return $date;
}
print_r(getDateFromFile("produkt_zehn_now_tu_20191225_20191226_05371.txt"));
Related
I am trying to parse a large log file and store data to array.
The above test code works fine on localhost, but on server it returns "The connection was reset" error on firefox and "ERR_EMPTY_RESPONSE" on Chrome.
Is there a way to optimize this script in order to run on server too?
<?php
ini_set('max_execution_time', 990);
ini_set("memory_limit","1024M");
ini_set('max_input_vars', 3000);
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
set_time_limit(200);
function startsWith ($string, $startString){
$len = strlen($startString);
return (substr($string, 0, $len) === $startString);
}
function append_string ($str1, $str2){
$str1 .=$str2;
return $str1;
}
function readTheFile($file) {
$i = 0;
$handle = fopen($file, "rb") or die("Unable to open file!");
while(!feof($handle)) {
$line = fgets($handle);
if(!startsWith($line,"::1") && !startsWith($line,"127.0.0.1") || $line != ''){
$line = str_replace('"', '', explode (' ', $line));
$line = str_replace('[', '', $line);
$line = str_replace(']', '', $line);
if(array_key_exists("5",$line) && array_key_exists("8",$line)){
if($line[5] == "GET" || $line[5] == "POST" || $line[5] == "PUT" || $line[5] == "HEAD" || $line[5] == "DELETE" || $line[5] == "PATCH" || $line[5] == "OPTIONS"){
if(is_numeric($line[8])){
$dt = explode(":", $line[3], 2);
$date = $dt[0];
$time = substr($dt[1], 0, strrpos( $dt[1], ':'));
$time = substr($time, 0, strrpos($time, ':'));
$time = append_string($time, ':00');
$recs[$i]['Date'] = $date;
$recs[$i]['Time'] = $time;
$recs[$i]['Method'] = $line[5];
$recs[$i]['StatusCode'] = $line[8];
unset($dt);
unset($date);
unset($time);
$i++;
}
}
}
}
unset($line);
}
fclose($handle);
return $recs;
}
$records = [];
$records = readTheFile('access.log');
echo json_encode($records);
?>
I'm trying to get using only fopen() and fseek() to get specific lines of code (not only one lines, i need to get line above and below of current seek line).
To improve performance, I know how to get specific line to seek and then exit. If I need line 5 then should be get seekable into 4 and 6.
Here is a code to get bytes of each lines then put into array as lines as key and value as bytes to EOF.
$fh = fopen($source, 'r');
$meta = stream_get_meta_data($fh);
if (!$meta['seekable']) {
throw new Exception(sprintf("A source is not seekable: %s", print_r($source, true)));
}
$line = fgets($fh, 4096);
$pos = -1;
$i = 0;
$result = null;
$linenum = 10;
var_dump('Line num:'.$linenum);
$total_lines = null;
// Get seek byte end of each line
while (!feof($fh)) {
$char = fgetc($fh);
if ($char != "\n" && $char != "\r") {
$total_lines[$i] = $pos;
$pos++;
} else {
$i++;
}
//var_dump(fgets($fh).' _ '.$pos);
}
// Now get specific lines (line 5, line 6 and line 7)
$seekssearch = array($total_lines[5], $total_lines[6], $total_lines[7]);
$result = null;
$posr = 0;
foreach ($seekssearch as $sk) {
while (!feof($fh)) {
if ($char != "\n" && $char != "\r") {
fseek($fh, $sk, SEEK_SET);
$posr++;
} else {
$ir++;
}
}
// Merge result of line 5,6 and 7
$result .= fgets($fh);
}
echo $result;
exit;
while (!feof($fh) && $i<($linenum)) {
$char = fgetc($fh);
if ($char != "\n" && $char != "\r") {
fseek($fh, $pos, SEEK_SET);
$pos++;
}
else {
$i++;
}
}
$line = trim(fgets($fh));
var_dump($line);
exit;
exit;
while (!feof($fh) && $i<($linenum-1)) {
$char = fgetc($fh);
if ($char != "\n" && $char != "\r") {
//fseek($fh, $pos);
fseek($fh, $pos);
$pos++;
}
else {
if ($pos == 3) {
$line = fgets($fh);
}
$i++;
}
}
//$line = fgets($fh);
var_dump($line); exit;
How to merge this lines?
Note: I don't want using splFileInfo or any tricks like arrays. Just want to seek then exit.
I've created a function that read a file and count lines and store into arrays each lines bytes to seek. If maximum specified by linenum is set, it will break from while to keep performance than in a new loop function to seek a position in bytes to get a content of file.
I believe that can this function improve.
function readFileSeek($source, $linenum = 0, $range = 0)
{
$fh = fopen($source, 'r');
$meta = stream_get_meta_data($fh);
if (!$meta['seekable']) {
throw new Exception(sprintf("A source is not seekable: %s", print_r($source, true)));
}
$pos = 2;
$result = null;
if ($linenum) {
$minline = $linenum - $range - 1;
$maxline = $minline+$range+$range;
}
$totalLines = 0;
while (!feof($fh)) {
$char = fgetc($fh);
if ($char == "\n" || $char == "\r") {
++$totalLines;
} else {
$result[$totalLines] = $pos;
}
$pos++;
if ($maxline+1 == $totalLines) {
// break from while to not read entire file
break;
}
}
$buffer = '';
for ($nr=$minline; $nr<=$maxline; $nr++) {
if (isset($result[$nr])) {
fseek($fh, $result[$nr], SEEK_SET);
while (!feof($fh)) {
$char = fgetc($fh);
if ($char == "\n" || $char == "\r") {
$buffer .= $char;
break;
} else {
$buffer .= $char;
}
}
}
}
return $buffer;
}
Test results (1.3 GB file, 100000000 lines of codes, seek to 300000 line a code):
string(55) "299998_abc
299999_abc
300000_abc
300001_abc
300002_abc
"
Time: 612 ms, Memory: 20.00Mb
$ ll -h /tmp/testReadSourceLines_27151460344/41340913936
-rw-rw-r-- 1 1,3G /tmp/testReadSourceLines_27151460344/41340913936
I have text file
name,name1
willhaveishere1
name,name2
willhaveishere2
name,name3
willhaveishere3
i want read it and return like that
$nn = name1
$ss = willhaveishere1
with my code i get only name1
my code is
$file1 = "file.txt";
$file = file($file1);
$count = count($file);
if($count > 0) {
$i = 1;
foreach($file as $row) {
$n = strstr($row, 'name,');
$cc = array("name,");
$dd = array("");
$nn = str_replace($cc, $dd, $n);
echo $nn;
$i++; } }
This is probably what you need
if($count > 0) {
foreach($file as $row) {
$pos = strpos($row, ',');
if($pos !== false){
echo substr($row, $pos + 1);
$nn[] = substr($row, $pos + 1);
} else {
echo $row;
$ss[] = $row;
}
}
}
EDIT
Yes, just loop through, but make sure both $nn and $ss has same count, which is depending on your file.
Also Note: mysql_* functions has been deprecated, so please use mysqli or PDO instead
$count = count($nn);
for($i=0; $i < $count; $i++){
$sql = "INSERT INTO users(name, line) VALUES('$nn[$i]', '$ss[$i]')"; mysql_query($sql);
}
EDIT 2
try this example:
$file = array(
0 => 'name,name1',
1 => 'willhaveishere1',
2 => 'name,name2',
3 => 'willhaveishere2',
4 => 'name,name3',
5 => 'willhaveishere3'
);
$count = count($file);
if($count > 0) {
foreach($file as $row) {
$pos = strpos($row, ',');
if($pos !== false){
$nn[] = substr($row, $pos + 1);
} else {
$ss[] = $row;
}
}
}
echo '<pre>';
$count = count($nn);
for($i=0; $i < $count; $i++){
$sql = "INSERT INTO users(name, line) VALUES('$nn[$i]', '$ss[$i]');";
echo $sql.PHP_EOL;
}
You can try this straightforward method:
if($fh = fopen("file.txt","r")){
$nameBefore = false;
//loop through every line of your file
while (!feof($fh)){
$line = fgets($fh);
//check if the name was detected in previous line
if ($nameBefore !== false)
{
//you have the set of name and line, do what you want
echo $nameBefore . ': ' . $line . '<br />';
$nameBefore = false;
}
else
{
//see if the line is made of two coma separated segments and the first one is 'name'
//Remember the name for the next line
$parts = explode(',', $line);
if (count($parts) == 2 && $parts[0] == 'name')
$nameBefore = $parts[1];
}
}
fclose($fh);
}
One option is to use strpos to find the first occurrence of the character in the line, and if found remove everything from the line before that position. This way you are left with only the part of the line you are interested in.
Code:
$character = ',';
$fileHandle = fopen('file.txt', 'r');
while (!feof($fileHandle)) {
// Retrieve the line from the file
$line = fgets($fileHandle);
// If the line contains the character
// Remove everything before the character
$charPos = strpos($line, $character);
if ($charPos !== false) {
$line = substr($line, $charPos + 1);
}
// Do something with the remainder of the line
echo $line . PHP_EOL;
}
fclose($fileHandle);
Output:
name1
willhaveishere1
name2
willhaveishere2
name3
willhaveishere3
If you wish to retrieve the following line, simply do another retrieve line call in your loop:
while (!feof($fileHandle)) {
// Retrieve two lines in one loop iteration
$lineOne = fgets($fileHandle);
$lineTwo = fgets($fileHandle);
}
Making sure to only apply the comma replace part on the first line. This can lead to problems though if your data is... inconsistent.
Hope this helps.
How to read and echo the N rows before the last row in TEXT file using PHP?
Example in file.txt
test1
test2
test3
test4
test5
test6
test7
I want to get the last row value and 3 row before last row.
So the result will be :
test4
test7
Here is my code so far (just show last row)
$line = '';
$f = fopen('\\\\192.168.183.28\\wk$\\sbin\\file.txt', 'r');
$cursor = -1;
fseek($f, $cursor, SEEK_END);
$char = fgetc($f);
while ($char === "\n" || $char === "\r") {
fseek($f, $cursor--, SEEK_END);
$char = fgetc($f);
}
while ($char !== false && $char !== "\n" && $char !== "\r")
{
$line = $char . $line;
fseek($f, $cursor--, SEEK_END);
$char = fgetc($f);
}
$future_sn = substr($line, 28, 36);
Any advice?
try
$array = explode("\n", file_get_contents('file.txt'));
// counting array and get key for prev
$prev_third = count($array)-4;
echo end($array); // test7
echo $array[$prev_third]; //test4
You can use fgets() to read file and keep a counter to keep track of last row. You can get 3 row ahead from last by mod(%) the counter.
$handle = fopen("input.txt", "r");
$lastRow = "";
$last3Ahead = "";
$counter = 0;
$a = "";
$b = "";
$c = "";
if ($handle) {
while (($line = fgets($handle)) !== false) {
if($counter == 0) $a = $line;
if($counter == 1) $b = $line;
if($counter == 2) $c = $line;
$lastRow = $line ;
if($counter >= 3) {
$last3Ahead = $a;
$a = $b;
$b = $c;
$c = $line
}
$counter++;
} else {
// error opening the file.
}
fclose($handle);
echo $lastRow. "<br>" ; //last row
echo $last3Ahead . "<br>"; //3 row before last;
I'm guessing it's fgets, but I can't find the specific syntax. I'm trying to read out (in a string I'm thinking is easier) the last line added to a log file.
The simplest naive solution is simply:
$file = "/path/to/file";
$data = file($file);
$line = $data[count($data)-1];
Though, this WILL load the whole file into memory. Possibly a problem (or not). A better solution is this:
$file = escapeshellarg($file); // for the security concious (should be everyone!)
$line = `tail -n 1 $file`;
This looks like it is what you are looking for:
tekkie.flashbit.net: Tail functionality in PHP
It implements a function that uses fseek() with a negative index to roll up the file from the end. You can define how many lines you want to be returned.
The code also is available as a Gist on GitHub:
// full path to text file
define("TEXT_FILE", "/home/www/default-error.log");
// number of lines to read from the end of file
define("LINES_COUNT", 10);
function read_file($file, $lines) {
//global $fsize;
$handle = fopen($file, "r");
$linecounter = $lines;
$pos = -2;
$beginning = false;
$text = array();
while ($linecounter > 0) {
$t = " ";
while ($t != "\n") {
if(fseek($handle, $pos, SEEK_END) == -1) {
$beginning = true;
break;
}
$t = fgetc($handle);
$pos --;
}
$linecounter --;
if ($beginning) {
rewind($handle);
}
$text[$lines-$linecounter-1] = fgets($handle);
if ($beginning) break;
}
fclose ($handle);
return array_reverse($text);
}
$fsize = round(filesize(TEXT_FILE)/1024/1024,2);
echo "<strong>".TEXT_FILE."</strong>\n\n";
echo "File size is {$fsize} megabytes\n\n";
echo "Last ".LINES_COUNT." lines of the file:\n\n";
$lines = read_file(TEXT_FILE, LINES_COUNT);
foreach ($lines as $line) {
echo $line;
}
define('YOUR_EOL', "\n");
$fp = fopen('yourfile.txt', 'r');
$pos = -1; $line = ''; $c = '';
do {
$line = $c . $line;
fseek($fp, $pos--, SEEK_END);
$c = fgetc($fp);
} while ($c != YOUR_EOL);
echo $line;
fclose($fp);
This is better, since it does not load the complete file into memory...
Set YOUR_EOL to your correct line endings, if you use the same line endings as the default line endings of the OS where your script resides, you could use the constant PHP_EOL.
function seekLastLine($f) {
$pos = -2;
do {
fseek($f, $pos--, SEEK_END);
$ch = fgetc($f);
} while ($ch != "\n");
}
-2 because last char can be \n
You either have to read the file in line by line and save the last read line to get it.
Or if on unix/linux you might consider using the shell command tail
tail -n 1 filename
This one wont break for a 1 or 0 line file.
function readlastline($fileName)
{
$fp = #fopen($fileName, "r");
$begining = fseek($fp, 0);
$pos = -1;
$t = " ";
while ($t != "\n") {
fseek($fp, $pos, SEEK_END);
if(ftell($fp) == $begining){
break;
}
$t = fgetc($fp);
$pos = $pos - 1;
}
$t = fgets($fp);
fclose($fp);
return $t;
}
If you want to read a file line by line the file function reads the contents of a file, line by line and returns each line as an element of an array.
So you could do something simple like:
$lines = file('log.txt');
$lastLine = array_pop($lines);
...Why just read the last line?
function readLines($fp, $num) {
$line_count = 0; $line = ''; $pos = -1; $lines = array(); $c = '';
while($line_count < $num) {
$line = $c . $line;
fseek($fp, $pos--, SEEK_END);
$c = fgetc($fp);
if($c == "\n") { $line_count++; $lines[] = $line; $line = ''; $c = ''; }
}
return $lines;
}
$filename = "content.txt";
$fp = #fopen($filename, "r");
print_r(readLines($fp, 2));
fclose($fp);
#unique_stephen, your answer is flawed. PHP fseek returns 0 for success and -1 for failure. Storing the result in $begining (sic) and then later using it in a filter for ftell() isn't correct. If my reputation were higher I would have voted you down and left a comment. Here is a modified version of unique_stephen's function.
function readlastline($fileName)
{
$fp = #fopen($fileName, "r");
if (fseek($fp, 0) == -1)
exit('Cannot seek to beginning of the file');
$pos = -1;
$t = " ";
while ($t != "\n") {
if (fseek($fp, $pos, SEEK_END) == -1)
exit('Cannot seek to the end of the file');
if (ftell($fp) == 0) {
break;
}
$t = fgetc($fp);
$pos = $pos - 1;
}
$t = fgets($fp);
fclose($fp);
return $t;
}
NOTE: PHP's fseek cannot manage to seek to the end of files larger than PHP_MAX_INT which is 32bit signed even on 64bit binaries.
function readlastline($fileName)
{
$fp = #fopen($fileName, "r");
$begining = fseek($fp, 0);
$pos = -1;
$t = " ";
while ($t != "\n") {
fseek($fp, $pos, SEEK_END);
if(ftell($fp) == $begining){
break;
}
$t = fgetc($fp);
$pos = $pos - 1;
}
$t = fgets($fp);
fclose($fp);
return $t;
}