Using txt files as a log for quiz answers (php) - 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!

Related

php read from text file and combine duplicate entries [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 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.

fwrite to front of file for my chatroom with php and ajax

I have a simple chatroom I've built. I actually want it to scroll up instead of down, meaning new messages are added to the top of the chat. This means I have to fwrite to the top of the file. I have done a lot of trial and error, as well as googling and overflowing, but haven't had success. Also, I understand that I need to use r+ likely, and not a, but I wanted to give the currently functional code, not the under construction code.
The two commented out lines are two ideas I tried. r+ continuously replaced the first line, and left text. If I typed 1 character, it left >r>>, if I typed 2 characters, it left >r>, if I typed 3 characters, it left r>, if I typed 4, it left >, and if I typed 5 or more, it left nothing.
I can't find much relevant information to this. Perhaps I'm using the wrong keywords. Please help me understand.
if(isset($_SESSION['name'])){
$text = $_POST['text'];
$fp = fopen("log.html", 'a');
//$fp = fopen("log.html", 'r+');
//fseek("log.html", 0)
fwrite($fp, "<center><div class='msgln'><b>".$_SESSION['name'].":</b> ".stripslashes(htmlspecialchars($text))."<br></div><br></center>");
fclose($fp);
}
A - Use a database. This is a poor implementation.
B - If you insist on using this implementation, Writing the beginning of a file resets the pointer and overwrites the file. Instead, grab data from current file, add it to new data, and rewrite the file.
C - There will be collision issues. Don't actually do this. But it will work.
Try:
if(isset($_SESSION['name'], $_POST['text'])){
$text = $_POST['text'];
$current_content = file_get_contents("log.html");
$new_content = "<center><div class='msgln'><b>".$_SESSION['name'].":</b> ".stripslashes(htmlspecialchars($text))."<br></div><br></center>".$current_content;
file_put_contents("log.html", $new_content);
}

Getting the file name from a text file after string matching - PHP

I have a log file (log.txt) in the form:
=========================================
March 01 2050 13:05:00 log v.2.6
General Option: [default] log_options.xml
=========================================
Loaded options from xml file: '/the/path/of/log_options.xml'
printPDF started
PDF export
PDF file created:'/path/of/file.1.pdf'
postProcessingDocument started
INDD file removed:'/path/of/file.1.indd'
Error opening document: '/path/of/some/filesomething.indd':Error: file doesnt exist or no permissions
=========================================
March 01 2050 14:15:00 log v.2.6
General Option: [default] log_options.xml
=========================================
Loaded options from xml file: '/the/path/of/log_options.xml'
extendedprintPDF started
extendedprintPDF: Error: Unsaved documents have no full name: line xyz
Note: Each file name is of the format: 3lettersdatesomename_LO.pdf/indd. Example: MNM011112ThisFile_LO.pdf. Also, on a given day and time, the entry could either have just errors, just the message about the file created or both, like I have shown here.
The file continues this way. And, I have a db in the form:
id itemName status
1 file NULL
And so on...
Now, I am expected to go through the log file and for each file that is created or if there in an error, I am supposed to update the last column of DB with appropriate message: File created or Error. I thought of searching the string "PDF file created/Error" and then grabbing the file name.
I have tried various things like pathinfo() and strpos. But, I can't seem to understand how I am going to get it done.
Can someone please provide me some inputs on how I can solve this? The txt file and db are pretty huge.
NOTE: I provided the 2nd entry of the log file to be clear that the format in which errors appear IS NOT consistent. I would like to know if I can still achieve what I am supposed to with an inconsistent format for errors.
Can somebody please help after reading the whole question again? There have been plenty of changes from the first time I posted this.
You can use the explode method of php to break your file into pieces of words.
In case the fields in your text file are tab separated then you can explode on explode(String,'\t'); or else in case of space separated, explode on space.
Then a simple substr(word,start_index,length) on each word can give you the name of file (here start_index should be 0).
Using mysql_connect will help you connect to mysql database, or a much efficient way would be to use PDO (PHP Data Objects) to make your code much more reliable and flexible.
Another way out would be to use the preg_match method and specify a regular expression matching your error msg and parse for the file name.
You can refer to php.net manual for help any time.
Are all of the files PDFs? If so you can do a regex search on files with the .pdf extension. However, if the filename is also contained in the error string, you will need to exclude that somehow.
// Assume filenames contain only upper/lowercase letters, 0-9, underscores, periods, dashes, and forward slashes
preg_match_all('/([a-zA-Z0-9_\.-/]+\.pdf)/', $log_file_contents, $matches);
// $matches should be an array containing each filename.
// You can do array_unique() to exclude duplicates.
Edit: Keep in mind, $matches will be a multi-dimensional array as described http://php.net/manual/en/function.preg-match-all.php and http://php.net/manual/en/function.preg-match.php
To test a regex expression, you can use http://regexpal.com/
Okay, so the main issue here is that you either don't have a consistent delimiter for "entries"..or else you are not providing enough info. So based on what you have provided, here is my suggestion. The main caveat here is that without a solid delimiter for "entries," there's no way to know for sure if the error matches up with the file name. The only way to fix this is to format your file better. Also you have to fill in some blanks, like your db info and how you actually perform the query.
$handle = fopen("log.txt", "rb");
while (!feof($handle)) {
// get the current row
$row = fread($handle, 8192);
// get file names
preg_match('~^PDF file created:(.*?)$~',$row,$match);
if ( isset($match[1]) ) {
$files[] = $match[1];
}
// get errors
preg_match('~^Error:(.*?)$~',$row,$match);
if ( isset($match[1]) ) {
$errors[] = $match[1];
}
}
fclose($handle);
// connect to db
foreach ($files as $k => $file) {
// assumes your table just has basename of file
$file = basename($file);
$error = ( isset($errors[$k]) ) ? $errors[$k] : null;
$sql = "update tablename set status='$error' where itemName='$file'";
// execute query
}
EDIT: Actually going back to your post, it looks like you want to update a table not insert, so you will want to change the query to be an update. And you may need to further work with $file in that foreach for your where clause, depending on how you store your filenames in your db (for example, if you just store the basename, you will likely want to do $file = basename($file); in the foreach). Code updated to reflect this.
So hopefully this will point you in the right direction.

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.

Writing large string to text file

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.

Categories