php read from text file and combine duplicate entries [closed] - php

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 7 years ago.
Improve this question
I have this little piece of code I'm just testing out that basically redirects a user if their IP doesn't match the predefined IP and if it doesn't match write that IP into a text file.
$file = fopen("ips.txt", "w");
if ($ip == "iphere") {
echo "Welcome";
fclose($file);
} else {
header('Location: http://www.google.com');
fwrite($file, "\n" . $ip);
if ($file) {
$array = explode("\n", fread($file, filesize("ips.txt")));
}
$result = print_r($array, TRUE);
fclose($file);
}
What I want to do is take the IPs that I'm writing to the text file, put them all into an array to find the duplicates, make note of the duplicates, filter them out, then write them back into that file or another txt file, but I'm stuck and not sure where to go from here.

I could suggest you use serialize or json_encode to store the ip's in a file , that way you could add more info (how many times an IP has visited, last visit, etc.).
I'll show you a simple example.
1: Create some dummy ips for test.
$IPs = array(
'192.168.0.1' => array(
'visits' => 23,
'last' => '2015-07-20'
),
'192.168.0.2' => array(
'visits' => 32,
'last' => '2015-06-23'
)
);
So here we created an associative array with 2 IP addreses, that also contain visit count and last visit.
Save the file using php serialize function or json_encode (i prefer json format, because it can be used by other languages).
$for_save = json_encode($IPs); // OR serialize($IPs)
file_put_contents("FILE_NAME",$for_save); //Save the file with the IP's
Now its time to read the file
$file = fopen("FILE_NAME", "w");
$file = json_decode($file) // or unserialize($file);
and now we have the array to use as we wish and we can search for ip's using php array functions, and offcourse modify information about ips :
if(array_key_exists("YOUR_IP_HERE",$file)){
//What to do if we have found the ip in the file, for example :
$file['YOUR_IP']['visits']++; //we add +1 visit for that ip
}
And now we can save the file again
$file = json_encode($file);
file_put_contents("IP_FILE_NAME",$file);

There are a couple issues with this approach, around threading and performance. What happens if two people hit the webpage and write to the same file at the same time? Also, this file can grow to an unbounded size? This will be slow. You don't need to manually check all ip's, only that one exists.
It might be better to use a database table for this. Otherwise, you'll need to handle filelocking as well.
psuedo code for function check_ips:
Select * from ips where ip =?. Check the user id
if no result, insert the ip. it's unknown. (also if needed you can add constraint to the table to prevent duplicate ip's)
otherwise, the ip is known
You can log counts, dates, last access, or other stats in the table as a calculated summary.

You can do easly reading the file with the ip in an array and the get the unique value from the array like this
$ipList = file(ips.txt);
$ipUnique = array_unique($ipList);
then yo can save or parse the $ipUnique for your porpose.

Related

Parsing CSV files in PHP [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 7 years ago.
Improve this question
I am playing a video game that exports statistics into a CSV file.
http://pastebin.com/FPzJ3Qz7
Row 5 are my headers/tables.
I have a PHP/MySQL database that stores the data...
My issue is, every time I need to delete the first 4 lines, and all the ones after line 498. Because I am only interested in the data in between.
The line numbers can change every time.
I can use Regex to match the part I need, but when I use file_get_contents, it removes the new lines, and makes one big string.
Ultimately my goal is, upload CSV to web server, run cron to load PHP script, parse out the CSV, then run SQL statements to read CSV and update/insert into the database.
Any suggestions?
If you use file() instead of file_get_contents(), you'll get an array with a value per each line of your code. From there onward, you could use array_search() to find where your delimiters are located, and then use array_splice() to land with the relevant portion of the data.
However, since you're already preg_match()ing the bulk and extracting the relevant portion, this is real easy. $entries = explode("\n", $bulk); will give you an array with a line of data on each.
Then you can iterate over your array and e.g. use explode(',', $entryline) to parse each data-string to an array. There's also str_getcsv(), but in your case you'll have to tick off the default enclosure, since your data is unenclosed. Then plug that into matching fields in your database.
MySQL can also directly import CSV data with something like: LOAD DATA INFILE '/scores.csv' INTO TABLE tbl_name FIELDS TERMINATED BY ',' LINES TERMINATED BY '\r\n' IGNORE 4 LINES; -- though you'd have to somehow get rid of the chunk in the end, this is for uniform CSV data.
[If you have working code where you're trying to solve this, add it to your question for more help.]
Instead of loading all the file (that uses memory for nothing), you can read the file line by line (as a stream) and build a generator function that returns the records you are interested by one by one. In this way you don't need to delete, you only need to use conditions and to select what you want. Example:
function getLineFromFileHandler($fh, $headers = false) {
// initializations
$sectionSeparator = str_repeat('-', 62);
$newline = "\r\n";
$sectionSeparatorNL = $sectionSeparator . $newline;
$rowSeparatorNL = ',' . $newline;
// skip title/subtitle (feel free to add a param to yield them)
$title = stream_get_line($fh, 4096, $sectionSeparatorNL);
$subtitle = stream_get_line($fh, 4096, $sectionSeparatorNL);
// get the field names
$fieldNamesLine = stream_get_line($fh, 4096, $rowSeparatorNL);
// return the records
if ($headers) {
$fieldNames = array_map('trim', explode(',', $fieldNamesLine));
while (($line = stream_get_line($fh, 4096, $rowSeparatorNL)) !== false &&
strpos($line, $sectionSeparator) === false)
yield array_combine($fieldNames, explode(',', $line));
} else {
while (($line = stream_get_line($fh, 4096, $rowSeparatorNL)) !== false &&
strpos($line, $sectionSeparator) === false)
yield explode(',', $line);
}
}
$fh = fopen('csv.txt', 'r');
foreach(getLineFromFileHandler($fh, true) as $record)
print_r($record);
fclose($fh);
This example displays each record as an associative array with the field name as key. As you can see you can remove the second parameter of the generator function to obtain an indexed array. Feel free to choose the most convenient way to insert records into your database (one by one, by blocks, or all in one shot).
Try the PHP function file(), which gets a file as an array -- each line is an element in the array. Then you can loop through the lines starting and ending wherever you need to.

PHP select and save text template [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 8 years ago.
Improve this question
im new to php/html and i don't even know if PHP has ability like that.
What i want to do is to select some text from input and save it to txt file.
I have a for which takes all text from it and saves to .txt file. But there is alot of not necessary text and it makes .txt file big and hardly readable.
This is what text i usually paste
# userid name uniqueid connected ping loss state
# 122 "bryerzavala" [U:1:167845174] 03:25 152 0 active
# 118 "zhabka" [U:1:12080791] 05:41 109 0 active
and the part i need is only [U:1:167845174] so it would be great is there is an way to make a non needed text trown away and the file save only [U:X:XXXXXXXXX] part.
There are some options to do what you want, it all depends on how the input text is formatted:
If the input text is always formatted the same way for every line, meaning uniqueid is going to be located in the same position you could use substr http://php.net/manual/en/function.substr.php
If the position of uniqueid varies on every line you could use a regular expression to extract the part of the text line you are looking for, in this case you could use preg_match http://php.net/manual/en/function.preg-match.php
here is a simple approach. may be you will like it
i'll use the example of file.txt you have provided to simulate the input data.
old.txt
# userid name uniqueid connected ping loss state
# 122 "bryerzavala" [U:1:167845174] 03:25 152 0 active
# 118 "zhabka" [U:1:12080791] 05:41 109 0 active
process.php
<?php
$file = file_get_contents('./test.txt', true);
// var_dump($file);//for debug
preg_match_all('/\[U:\d:\d+\]/',
$file,
$out, PREG_PATTERN_ORDER);
var_dump($out); //for debug
//save data in your file
$fp = fopen("incomming.txt", "w");
foreach ($out[0] as $key => $data) {
fwrite($fp, $data.PHP_EOL);
}
//close file
fclose($fp);
echo '<hr/>';
$lines = file('incomming.txt');
var_dump($lines);

PHP string of IP addresses in a .txt file?

I'm writing a feature for an admin panel that blocks ip addresses on the apache level. The file is called blacklist.txt and looks like 10.0.0.1,10.0.0.2,10.0.0.3, ... All a single line, with each ip address separated by a comma. After reading What is the best way to write a large file to disk in PHP?, I am still unsure of the best practices on the matter.
Here's what I want to do: IF an administrator presses the 'ban hammer', the file is read looking for strpos($file, $ip), if it's not found, append to the end of the file and the .htaccess file blocks accordingly.
Question: is a .txt file suitable for this potentially large amount of data? I do not want to execute a query to check if someone is banned every time a page is requested
EDIT:
The purpose is to block single ip addresses that have 10 failed login attempts in the past 12 hours. I would think that the 'recover my password' would prevent a normal client from doing this.
Question: is a .txt file suitable for this potentially large amount of
data?
No, it is not. A database with proper indexing is.
First for reading your File in CSV format
you can use many ways. example:
$rows = array_map('str_getcsv', file('myfile.csv'));
$header = array_shift($rows);
$csv = array();
foreach ($rows as $row) {
$csv[] = array_combine($header, $row);
}
src: http://steindom.com/articles/shortest-php-code-convert-csv-associative-array
for checking that on each page load and to minimize the Reading of that file
you can use a memory cache , something like memCache, then search the array for the incoming ip. note: memory cache is faster then Database query.
PHP shared memory ref: http://www.php.net/manual/en/book.shmop.php
memCache php.net/memcache
Array Search php.net/in_array
also to return the key if value found php.net/array_search
note: in 1 mb file you can store ~65K IP considering an ip is the following format: "255.255.255.255,"
it's even better if you put the key of the array the ip, then instead of searching the array for that ip you can Check if the Key exist with this: php.net/array_key_exists‎

Modify a line with "KEY - AMOUNT" of a file in PHP

this has been bugging me for ages now but i can't figure it out..
Basically i'm using a hit counter which stores unique IP address in a file. But what i'm trying to do is get it to count how many hits each IP address has made.
So instead of the file reading:
222.111.111.111
222.111.111.112
222.111.111.113
I want it to read:
222.111.111.111 - 5
222.111.111.112 - 9
222.111.111.113 - 41
This is the code i'm using:
$file = "stats.php";
$ip_list = file($file);
$visitors = count($ip_list);
if (!in_array($_SERVER['REMOTE_ADDR'] . "\n", $ip_list))
{
$fp = fopen($file,"a");
fwrite($fp, $_SERVER['REMOTE_ADDR'] . "\n");
fclose($fp);
$visitors++;
}
What i was trying to do is change it to:
if (!in_array($_SERVER['REMOTE_ADDR'] . " - [ANY NUMBER] \n", $ip_list))
{
$fp = fopen($file,"a");
fwrite($fp, $_SERVER['REMOTE_ADDR'] . " - 1 \n");
fclose($fp);
$visitors++;
}
else if (in_array($_SERVER['REMOTE_ADDR'] . " - [ANY NUMBER] \n", $ip_list))
{
CHANGE [ANY NUMBER] TO [ANY NUMBER]+1
}
I think i can figure out the last adding part, but how do i represent the [ANY NUMBER] part so that it finds the IP whatever the following number is?
I realise i'm probably going about this all wrong but if someone could give me a clue i'd really appreciate it.
Thanks.
This is bad idea, don't do it this way.
Its normal to store website statics in the file-system but not with pre-aggregation applied to it.
If you going to use the file-system then do post-aggregation on the data otherwise use a database.
What you are doing is a very bad idea
But lets first answer the actual question you are asking.
To be able to do that you will have to actually process the file first in some kind of data structure that allows for that to be done. I'd presonally recommend an array in the form of IP => AMOUNT.
For example (untested code):
$fd = file($file);
$ip_list = array();
for ($fd as $line) {
list($ip, $amount) = explode("-", $line);
$ip_list[$ip] = $amount;
}
Note that the code is not perfect as it would leave a space at the end of $ip and another in front of $amount due to the nature of your original data. But it works good enough just to point you in the right direction. A more "accurate" solution would involve regular expressions or modifying the original data source to a more convenient format.
Now the real answer to your actual problem
Your process will quickly become a performance bottleneck as you would have to open up that file, process it and write it all back again afterwards (not sure if you can do in-line editing of an open file) for every request.
As you are trying to do some kind of per-IP hit count, there are a lot of better solutions to your problem:
Use an existing solution for it (like piwik)
Use an actual database for your data
Keep your file simple with just a list of IPs and post-process it off-line periodically to make it be the format you want
You can avoid writing that file altogether if you have access to your webserver's logs (and they are setup to log every request with the originating IP) and you can post-process that file instead
in_array() simply does a basic a string match. it will NOT look for substrings. Ignoring how bad an idea it is to use a flat file for data storage, what you want is preg_grep, which allows you to use regexes
$ip_list = file('ips.txt');
$matches = preg_replace('/^\d+\.\d+\.\d+\.\d+ - \d+$/', $ip_list);
of course, this is a very basic and very broken IP address match, and will not help you actually CHANGE the value in $ip_list, because you don't get the actual index(es) of the matched lines.

Using txt files as a log for quiz answers (php)

I have a php file that writes to a txt file:
<?php
$answers = "answers.txt";
$fh = fopen($answers, 'a+') or die("can't open file");
$stringData = $_POST["username"];
$timestamp = date("g:i A, m/j/Y");
fwrite($fh, $stringData);
fwrite($fh, " started the quiz at ");
fwrite($fh, $timestamp);
fwrite($fh, "\n");
fclose($fh);
?>
Assuming I replace this code to enter a number (e.g. 10) followed by the user's answer (a string) so it submits the question number followed by the answer, how can I search through the txt file for the username then add that line to an array? Also, could I check the file when each question loads to see which questions the user has answered and then either choose another random quiz or continue loading (if they have not)?
Basically:
Search the text file for a string and output any lines that contain it
Search the text file for a string and then search for a number encased in commas or some other identifier (e.g. ,23,) on the same line as the string.
If I should be doing this using MySQL, a few links or other resources would be nice, because I have heard of MySQL but never used it.
Thanks a bunch in advance!
NOTE: I believe I need to search for a string using strpos and then get the line number and take the whole line and put it in the string. Then, I need to use explode "," to get the question numbers and have a php script on each page check to see if it's number has already been answered. If so, then select another random number. If not, recieve input then write it back to the text file. Or, perhaps I could use sessions to store the questions answered. However, I have no idea how to implement all this together.
I would say MySQL would be the better route to take.
Get Started Here: http://www.w3schools.com
Also check out other posts here:
MySql database design for a quiz
Am doing online Quiz type of script in PHP. It is better to use cookies or sessions
EDIT:
Don't forget about security!

Categories