Hello there so I just setup this basic poll, I inspired myself from something I found out there, and it's just a basic ajax poll that waves the results in a text file.
Although I was wondering, since I do not want the user to simply mass-click to advantage / disadvantage the results, i thought about adding a new text file that could simply save the IP, one on each line, and then checks if it's already logged, if yes, display the results, if not, show the poll.
My lines of code to save the result are:
<?php
$vote = $_REQUEST['vote'];
$filename = "votes.txt";
$content = file($filename);
$array = explode("-", $content[0]);
$yes = $array[0];
$no = $array[1];
if ($vote == 0)
{
$yes = $yes + 1;
}
if ($vote == 1)
{
$no = $no + 1;
}
$insert = $yes."-".$no;
$fp = fopen($filename,"w");
fputs($fp,$insert);
fclose($fp);
?>
So I'd like to know how I could check out the IPs, in the same way it does basically.
And I'm not interested in database, even for security measures, I'm alright with what Ive got.
Thanks to any help!
To stop multiple votes, I'd set a cookie once a user has voted. If the user reloads the page with the voting form on it and has a cookie, you could show just the results, or a "You have already voted." message. Note that this will not stop craftier people from double-voting - all they would have to do is remove the saved cookie, and they could re-vote.
Keep in mind though that IPs can be shared so your idea of storing IPs might backfire - people on a shared external-facing IP won't be able to vote, as your system will have registered a previous vote from someone at the same IP address.
easiest way is to write data to file is
file_put_contents($filename, $data)
and to read data from file
file_get_contents($filename);
To get IP Address of the user
$_SERVER['REMOTE_ADDR']
See php manual for file_put_contents for more information and file_get_contents
Here is sample code
<?php
// File path
$file = 'votedips.txt';
// Get User's IP Address
$ip = $_SERVER['REMOTE_ADDR'];
// Get data from file (if it exists) or initialize to empty string
$votedIps = file_exists($file) ? file_get_contents($file) : '';
//
$ips = explode("\n", $votedIps);
if (array_search($ip, $ips)) {
// USER VOTED
} else {
$ips[] = $ip;
}
// Write data to file
$data = implode("\n", $ips);
file_put_contents($file, $data);
?>
You can use file_get_contents to save the file's content into a variable and then use the strpos function to check if the IP exists in that variable.
For example:
$ipfile=file_get_contents('ip.txt');
if (strpos($ipfile, $_SERVER['REMOTE_ADDR'])!==FALSE) // show the results
else // show the poll
Be careful with storing IPs in a text file, and then using file_get_contents() and similar functions for loading the data/parseing. As an absolute worst case, assuming that every possible IP address used your system to vote, you'd end up with a text file in the many many gigabytes in size, and you'd exceed PHP's memory_limit very quickly.
Related
It works fine but later sometime the count just goes down to random
number. My guess is my code cannot process multiple visits at a time.
Where increment heppens
Where it displays the count
<?php
$args_loveteam = array('child_of' => 474);
$loveteam_children = get_categories($args_loveteam);
if(in_category('loveteams', $post->ID)){
foreach ($loveteam_children as $loveteam_child) {
$post_slug = $loveteam_child->slug;
echo "<script>console.log('".$post_slug."');</script>";
if(in_category($loveteam_child->name)){
/* counter */
// opens file to read saved hit number
if($loveteam_child->slug == "loveteam-mayward"){
$datei = fopen($_SERVER['DOCUMENT_ROOT']."/wp-content/themes/inside-showbiz-Vfeb13.ph-updated/countlog-".$post_slug."-2.txt","r");
}else{
$datei = fopen($_SERVER['DOCUMENT_ROOT']."/wp-content/themes/inside-showbiz-Vfeb13.ph-updated/countlog-".$post_slug.".txt","r");
}
$count = fgets($datei,1000);
fclose($datei);
$count=$count + 1 ;
// opens file to change new hit number
if($loveteam_child->slug == "loveteam-mayward"){
$datei = fopen($_SERVER['DOCUMENT_ROOT']."/wp-content/themes/inside-showbiz-Vfeb13.ph-updated/countlog-".$post_slug."-2.txt","w");
}else{
$datei = fopen($_SERVER['DOCUMENT_ROOT']."/wp-content/themes/inside-showbiz-Vfeb13.ph-updated/countlog-".$post_slug.".txt","w");
}
fwrite($datei, $count);
fclose($datei);
}
}
}
?>
I would at least change your code to this
foreach ($loveteam_children as $loveteam_child) {
$post_slug = $loveteam_child->slug;
echo "<script>console.log('".$post_slug."');</script>";
if($loveteam_child->slug == "loveteam-mayward"){
$filename = "{$_SERVER['DOCUMENT_ROOT']}/wp-content/themes/inside-showbiz-Vfeb13.ph-updated/countlog-{$post_slug}.txt";
}else{
$filename = "{$_SERVER['DOCUMENT_ROOT']}/wp-content/themes/inside-showbiz-Vfeb13.ph-updated/countlog-{$post_slug}-2.txt";
}
$count = file_get_contents($filename);
file_get_contents($filename, ++$count, LOCK_EX);
}
You could also try flock on the file to get a lock before modifying it. That way if another process comes along it has to wait on the first one. But file_put_contents works great for things like logging where you may have many processes competing for the same file.
Database should be ok, but even that may not be fast enough. It shouldn't mess up your data though.
Anyway hope it helps. This is kind of an odd question, concurrency can be a real pain if you have a high chance of process collisions and race conditions etc etc.
However as I mentioned (in the comments) using the filesystem is probably not going to provide the consistency you need. Probably the best for this may be some kind of in memory storage such as Redis. But that is hard to say without full knowing what you use it for. For example if it should persist on server reboot.
Hope it helps, good luck.
After almost 3 days of troubleshooting I gotta ask for advice.
A have a small imageboard with 4 images and 4 'like' buttons. Earlier I made it so the number of clicks with each button stores in a .txt file. Now I basically need to make it so a person can press a certain button only once.
This is ip.txt. The number to the left is button ID, to the right is IP of the person that clicked that button.
click-001||127.0.0.1
click-002||
This is very simple. I need to make sure it stores ip when I click on my PC, then stores another IP when I click on my pad - and stops whatever I do next. Now for the last few days it's been doing anything except that!
My current code with isset. That sees the first IP but doesn't add the second:
$file2 = 'ip.txt'; // path to text file that stores counts
$fh2 = fopen($file2, 'r+');
$ip_addr = $_SERVER['REMOTE_ADDR'];
$lines2 = '';
while(!feof($fh2)) {
$line2 = trim(fgets($fh2));
if ($line2) {
$line2 = explode('||', $line2);
if(isset($line2[0], $line2[1])) {
$item2 = trim($line2[0]);
if(!empty($item2)) {
if($item2 == $id) {
if(empty($line2[1])) {
$lines2 .= "$item2||$ip_addr\r\n";
file_put_contents($file2, $lines2);
} else {
// this is where it always fails
if (!isset($ip_addr)) { $ip_all = $line2[1] . " " . $ip_addr;
$lines2 .= "$item2||$ip_all\r\n";
file_put_contents($file2, $lines2);
} else {
echo "lul";
}
}
}
}
}
}
}
fclose($fh2);
I also tried this with in_array function:
$ip_all = array($line2[1]);
if (!in_array($ip_addr, $ip_all)) {
array_push($ip_all, ',' , $ip_addr);
$ip_fin = implode($ip_all);
$lines2 .= "$item2||$ip_fin\r\n";
file_put_contents($file2, $lines2);
^ This one also sees the first IP and adds the second, but then fails to find whether the IP is already there and just keeps adding copies when I click.
This is brutal. What am I doing wrong and is there an easier way?
Use MySQL database to accomplish this.
Using a text file is super inefficient and can cause conflicts when multiple users liked at the same time!
Insert the IP to database everytime a user clicked the 'Like' button and then use a select query to determine if this IP has liked the picture before.
I do not recommend using just IP tho as some ISP gives dynamic IP that changes the IP (Public IP) address every few seconds.
Use cookies to store a unique cookie for a user (if they are not logged in) or just ask the user to login first before voting!
Information about MySQL Insert and Select are everywhere on Google.
Here's one : https://www.w3schools.com/sql/
best method: use a database or use XML (XML have very useful library)
text file method:
get file and edit...
$id = "...";
$ip="...";
$file2 = file('ip.txt');
$file2 = array_map(
function($current_line) use ($id,$ip) {
$current_line = explode('||', $current_line);
if($current_line[0] == $id){
$current_line[]=$ip;
}
return join("||",$current_line);
},$file2
);
file_put_contents('ip.txt', implode('\n', $file2));
Basically to keep it short I have an assignment for college where I have to make a few scripts.
In one of these I have to make a scripts that records when data is entered wrong in a log in form. So it will take the users IP address and place it into a text file followed by the time, date, error name (e.g. wrong username and password, wrong name, w.e.), error page and attempts made.
I have figured out:
how to get the users ip
how to get the time and date
how to record the attempts
Now, what I want to do: I want the script to search for the users IP address and if this IP address has already been recorded for a failed attempt, instead of making a new record I want it to just add 1 to the attempts made to that IP address, update the time and date. Only in the case that this IP address has not been recorded a new record should be created.
if IP ALREADY EXISTS{
FIND AMOUNT OF ATTEMPTS
attempts++;
}
else{
ADD IP;
ADD TIME;
ADD DATE;
ADD REASON;
attempt=1;
}
this is what i have so far:
<?php
$time = date("h:i:sa");
$date = date("d/m/y");
$error = "Incorrect Data Entered";
$attempts = 0;
if (!empty($_SERVER['HTTP_CLIENT_IP'])) {
$ip = $_SERVER['HTTP_CLIENT_IP'];
} elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
$ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
} else {
$ip = $_SERVER['REMOTE_ADDR'];
}
$myFile = "errorLog.txt";
$file = fopen($myFile, 'a') or die("can't open file");
$searchfor = "$ip";
// the following line prevents the browser from parsing this as HTML.
header('Content-Type: text/plain');
// get the file contents, assuming the file to be readable (and exist)
$contents = file_get_contents($myFile);
// escape special characters in the query
$pattern = preg_quote($searchfor, '$ip');
// finalise the regular expression, matching the whole line
$pattern = "/^.*$pattern.*\$/m";
// search, and store all matching occurences in $matches
if(preg_match_all($pattern, $contents, $matches)){
echo "Found matches:\n";
echo implode("\n", $matches[0]);
}
else{
$attempts = 1;
$stringData = "$ip, $time, $date, $error, $attempts\n";
fwrite($file, $stringData);
fclose($file);
}
?>
If you simply append to the same text file over and over then if you really want to add up the number of attempts by each individual user, then your going to need to rewrite the full txt file as far as I'm aware.
If you want to make it easier for yourself then you can write your txt file in such a way that you can easily obtain the values you need out of it, such as the ip address.
You could write each line like:
IPADDRESS,ERROR CODE,ATTEMPTS /n
Then when you want to change that line you'll need to keep a record of which line it is. A loop will be required to parse your txt file.
So the way I would attempt it would be:
Store text from file into a variable.
Use the explode() function to create an array of records. ( Like a row in a database ). I would use it like $rows = explode("/n" , $txt);
Loop through the rows. I would probably use foreach( $rows as $row) for this.
Keep track of the row number. So create a variable for it and iterate it.
Use the explode() function again to create a list($ip, $err, $attempts) by doing: list($ip, $err, $attempts) = explode("," , $row);
Now use normal php if() function to check to see if the two ips match, if the error codes are the same.
If they do, you can do $attempts++. Now the tricky/essential part.
You will need to create a string up to but NOT including that row and place it into a variable call it something like $firstpart.
You will also need to do the same for the rows after the affect row. eg $lastpart
Now create a new string for your affected row. Easily done: $str = $ip . "," . $err . "," . $attempts;
Finally, write your txt file using the variables, in the order: $firstpart, $str, $lastpart.
Not sure if this will work, not sure how practical this is, but at the very least I hope it helps you to get some sort of brainwave for how to approach your problem.
I've setup a PHP IP Blacklist system and it works really well.
I now want it to be able to take a reason from the txt file.
ip_blacklist.txt
1.2.4.5 , No Spamming Allowed
1.2.4.5 , No Spamming Allowed
1.2.4.5 , No Spamming Allowed
Now in PHP it get's the IP to compare it to the users IP being used, that's perfect.
But if the IP matches the IP in the txt it will redirect you to a blacklist page.
I want it to display the reason for their blacklisting.
How do I get the reason matching the IP in the txt file using PHP and then linking it to
$reason?
Like the answers above, I agree that the best way to solve this would be store the user's IP in a database, but if you still need to read a file for it, this code should do the job:
<?php
//The file you will read
$file = fopen("ip_blacklist.txt", "r") or exit("Unable to open file!");
//Where we will store each ip as we read it
$ip = "";
$parts;
while(!feof($file))
{
//Split the line and save the parts
$parts = explode(" , ", fgets($file));
$ip = $parts[0];
$reason = $parts[1];
//And here you can compare it to the client's ip
//The first one is the ip read from the file
echo $ip."<br>";
//And this is how you would get the client's ip
echo $_SERVER['REMOTE_ADDR']."<br>";
}
//Close the file
fclose($file);
?>
Note that the way to get the client's IP I used is not the best by any means (since it can be spoofed really easily). For more information about that, read here How to get Client IP address in PHP?
-Edit-
And I just noticed you simply wanted to check the IP, compare it and get the reason. In that case, change the while to:
while(!feof($file))
{
//Split the line and save the parts
$parts = explode(" , ", fgets($file));
$ip = $parts[0];
if($_SERVER['REMOTE_ADDR'] == $ip)
echo $parts[1];
}
Or you could use explode:
$myTextFileLine = "1.2.4.5 , No Spamming Allowed";
$cutted = explode(",", $myTextFileLine);
echo "Ip blacklisted: ".$cutted[0].", reason: ".$cutted[1];
Edit: Edited to include preg_match method of getting result from file instead of db. This method would do the check if the user is in the blacklist as well as get the users reason.
You could simply store the users IP in your database along with a reason. Then when the check is run, if the user is in the blacklist, query the database for their ip, and return and display the reason.
$ip = $_SERVER['REMOTE_ADDR'];
$sql = 'SELECT reason FROM blacklist WHERE ip = "' . $ip . '"';
Then run that sql against your database. Ofcourse that is a rough idea and has no protection against sql injection, so I would advise in using some form of excaping and validating that $ip is in the correct format for an ip address before running the query.
The overall process would be:
Check if user is in blacklist by comparing ip to file.
User is in blacklist.
Get reason from database by the users ip.
Display reason.
If you are just looking to do it all by file, then it would be a better of getting the file contents, finding the ip and reason and displaying the reason.
This could be done using preg_match.
$file = file_get_contents('path/to/blacklist/file');
$ip = $_SERVER['REMOTE_ADDR'];
$pattern = '#' . $ip . '\s,\s.*#';
if(preg_match($pattern, $file_contents, $matches)) {
$match = $matches[0];
$explode = explode(',', $match);
$reason = $explode[1];
echo $reason;
}
Note this is untested, but I think it would work.
I tried to write a counter for visits of my page, which only counts each IP once per day.
I transcribed a found code to understand how it works and to implement some other features later.
Unfortunately my new code doesn't work.
Code I made from it:
<?php
$timeReset = 86400; //24h
$ipPath = "ipsafe.txt";
$countPath = "counts.txt";
$timePath = "time.txt";
$ip = $REMOTE_ADDR;
$time = time();
$resetTime = $time+$timeReset;
$timeFile = fopen($timePath, "r+");
$timeData = fread($timeFile, filesize($timePath));
//if resetTime is passed -> Reset
if($time >= $timeData) {
//clear ipSafe
$ipFile1 = fopen($ipPath, "w+");
fclose($ipFile);
//set new resetTime
rewind($timeData);
fwrite ($timeData, $resetTime);
}
fclose($timeFile);
//creat IP-List
$ipData = file($ipPath);
while (list ($line_num, $line) = each ($ipData)) {
$digits = explode(",",$line);
}
//if IP was not saved in last timeframe
if(!in_array($ip, $digits))
{
//write new IP
$ipFile2=fopen($ipPath, "a+");
#flock($ipFile1,2);
fwrite($ipFile2, "$ip".",");
#flock($ipFile1,3);
fclose($ipFile2);
//increment counter
$countFile = fopen($countPath,"r+");
$countData = fread($countFile, filesize($countPath);
rewind($countFile);
$countData++;
fwrite($countFile, $countData);
fclose($countFile);
}
?>
with the following questions:
what's wrong with my code?
flock is used to manage the access to the files, but why shall I use different names for the same file?
Thanks for your suggestions.
EDIT:
Sorry for being so unspecific in explaining the problem. After integrating a debugger, I changed "REMOTE_ADDR" to "$_SERVER['REMOTE_ADDR']" so I fixed 1 error. Now i got the following problems:
Warning: fopen(time.txt): failed to open stream: No such file or directory in .../counter.php on line 15
But the file is in the same directory as counter.php - of course the fread and filesize failed too
Warning: fopen(ipsafe.txt): failed to open stream: Permission denied in .../counter.php on line 20
The file doesn't exist yet, but I thought "fopen($ipPath, "w+");" creats it if it doesn't exist.
Fatal error: Call to undefined function fb() in .../counter.php on line 26
Doesn't "fb($timeFile);" send the value to firePHP?
Not doing a full code review (which would result in an almost full rewrite of your code), here are the things I would recommend changing to fix your listed issues:
The following line uses $REMOTE_ADDR, which is undefined.
$ip = $REMOTE_ADDR;
You most likely meant to use $_SERVER['REMOTE_ADDR'] (which you confirmed with your edit), so the line should read:
$ip = $_SERVER['REMOTE_ADDR'];
You state you're receiving an error attempting to open the time.txt file: "No such file or directory". You also say that the file exists in the same directory as counter.php - and yet you're still receiving this error. This can mean one of two things; the first, the file doesn't exist and you're mistaken; the second, your counter.php file is in a different directory than whatever script is executing it - this would mean that the time.txt file would need to be in the directory of the executing script. I would recommend two things for this.
The first, if the file actually exists, use an absolute path for it:
$timePath = '/path/to/your/files/time.txt';
The second, verify if the file exists (in code) and if not, create it. fopen() with r/r+ flags does not create a file if it doesn't exist, so this needs to be manual. Try changing the code to the following:
if (!file_exists($timePath)) touch($timePath);
$timeFile = fopen($timePath, 'r+');
if ($timeFile) {
// the rest of your code
}
You say you're receiving an error when opening the ipsafe.txt file: "Permission denied". This is a fun one; Though the line numbers don't match with your sample code, I believe these are the lines in question:
//clear ipSafe
$ipFile1 = fopen($ipPath, "w+");
fclose($ipFile);
The first issue is that you never use $ipFile1 in your code (except erroneously locking/unlocking it; see below for that info). The second is that you call fclose($ipFile);. There is no handle named $ipFile! You can remove these lines of code!
You attempt to rewind the file pointer in your time.txt file to write the new time, however, you're using the value you read-in from the file $timeData - not the file itself $timeFile. Update the lines to the following:
rewind($timeFile);
fwrite($timeFile, $resetTime);
You read in the file ipsafe.txt, again, to look through the full list of IP addresses - if the current user's IP isn't in it, you add it. This may be a logic issue, but you're only checking the IP addresses of the last line of the file - but you still iterate through every line of the item. Per the comment in the code: //if IP was not saved in last timeframe, I'm going to assume that this is what you're intending to do - but just in case - I would recommend moving the full if-statement block that appears below the loop to inside the loop.
Here's the fun block:
//write new IP
$ipFile2=fopen($ipPath, "a+");
#flock($ipFile1,2);
fwrite($ipFile2, "$ip".",");
#flock($ipFile1,3);
fclose($ipFile2);
You open the file into $ipFile2 (2), then you lock a completely different file $ipFile1 (1), write to 2, unlock 1, and then close 2. I think that you're intentions were to lock/unlock 2, which would make perfect sense here, so I'd recommend changing $ipFile1 to $ipFile2 in those lines.
That should about do it (potentially). After everything, the code should resemble something similar to:
<?php
$timeReset = 86400; //24h
$ipPath = "ipsafe.txt";
$countPath = "counts.txt";
$timePath = "time.txt";
$ip = $_SERVER['REMOTE_ADDR'];
$time = time();
$resetTime = $time+$timeReset;
if (!file_exists($timePath)) touch($timePath);
$timeFile = fopen($timePath, "r+");
if ($timeFile) {
$timeData = fread($timeFile, filesize($timePath));
//if resetTime is passed -> Reset
if($time >= $timeData) {
//set new resetTime
rewind($timeFile);
fwrite ($timeFile, $resetTime);
}
fclose($timeFile);
//creat IP-List
$ipData = file($ipPath);
while (list ($line_num, $line) = each ($ipData)) {
$digits = explode(",",$line);
}
//if IP was not saved in last timeframe
if(!in_array($ip, $digits)) {
//write new IP
$ipFile2=fopen($ipPath, "a+");
#flock($ipFile2, LOCK_EX);
fwrite($ipFile2, "$ip".",");
#flock($ipFile2, LOCK_UN);
fclose($ipFile2);
//increment counter
if (!file_exists($countPath)) touch($countPath);
$countFile = fopen($countPath,"r+");
if ($countFile) {
$countData = fread($countFile, filesize($countPath);
if (empty($countData)) $countData = 0; // initialize the counter to '0' if it hasn't been set
rewind($countFile);
$countData++;
fwrite($countFile, $countData);
fclose($countFile);
}
}
}
?>
Now, I also have one additional logic issue regarding your $resetTime variable. Ideally, incrementing by a single day is to add 24 hours to a given timestamp (24 hours = 86400 seconds). However, daylight savings time will break this. Instead of doing the following:
$resetTime = time() + 86400;
Try going a different route (if you're worried about this, that is):
$resetTime = strtotime('+1 day');