PHP Multiple Users Problem
01-01-2011, 02:20 PM
|
PHP Multiple Users Problem
|
Posts: 45
Location: Canada
|
Hey all,
I'm a little new to PHP and have run into a little problem with my code. I'm still testing it but I uploaded a sample here:
http://hwhelper.ca/test/archive/ask.php
- You ask a question here
http://hwhelper.ca/test/archive/math1.php
- The question gets displayed here. As more questions are asked, the older questions are moved down in queue and eventually to the next page and so on.
The code works fine when I test it alone but when me and some other user ask questions simultaneously, weird stuff happens. Sometime the page just disappears or pages don't switch with each other.
I'm not sure if it's very helpful but here's the code:
Thank you.
PHP Code:
<?php
$title= $_POST["title"]; $ques= $_POST["questions"];
$pages=4;
$line_counter=1; $url_count=1;
$file = fopen("math" . $url_count . ".php","r");
while (!feof($file)) {
$buffer = fgets($file); $line_counter++;
// Which file to write in if 1 full then 2 then 3 ...
if (trim($buffer) == '<p id="new_page">' && $line_counter>76) { $url_count++; $file = fopen("math" . $url_count . ".php","r"); $line_counter=1; } }
$file = fopen("math" . $url_count . ".php","r"); $line_counter=1;
$file_copy = fopen("math_copy.php","w");
$content= $title . " <br /> \n"; $content= $content . substr($ques, 0, 100) . " ... <br /><br /> \n";
while (!feof($file)) //math.php is being read and copied {
$buffer = fgets($file); // Read a line.
if (trim($buffer) <> '<p id="change">') { fwrite($file_copy, $buffer); $line_counter++; }
if (trim($buffer) == '<p id="change">') { fwrite($file_copy, $buffer); fwrite($file_copy, $content); $line_counter++; }
}
fclose($file);
$file = fopen("math" . $url_count . ".php","w"); $file_copy = fopen("math_copy.php","r");
while (!feof($file_copy)) { $buffer = fgets($file_copy);
fwrite($file, $buffer); }
// Switching Files Script i.e. page 1 =page 3 etc. // Problem: pages kept switching too many times: counter and switch
$switch=1; // Problem in actual switches. Don't switch again. $counter= $_REQUEST['counter']; // To count # of clicks on main.php $next=1; //Priting two nexts
echo $_POST["id"];
$counter++;
if($counter==6) { $counter=0; }
//As soon as the 2nd, 3rd... pages get written on them, move content to // the first page and so forth.
for($i=$pages; $i>=2; $i--) {
$file = fopen("math" . $i . ".php","r"); $line_counter=1;
while (!feof($file)) { $buffer = fgets($file); $line_counter++;
if(trim($buffer) == '<p id="new_page">' && $line_counter>66) {
// Change the value of counter in ask.php!!
$file_ask = fopen("ask.php","r"); $file_askc = fopen("ask_copy.php","w");
while (!feof($file_ask)) { $buffer2 = fgets($file_ask);
if(strncasecmp(trim($buffer2), '$counter;', 7) <> 0) { fwrite($file_askc, $buffer2); }
if(strncasecmp(trim($buffer2), '$counter;', 7)==0) { fwrite($file_askc, '$counter=' . $counter . ";\n"); } }
$ask_copy = file_get_contents ("ask_copy.php","r"); $file_ask = fopen("ask.php","w"); fwrite($file_ask, $ask_copy);
// The actual switches are here if($counter==1 && $switch==1) {
$j=1;
while($j<$i) {
$copy_string = file_get_contents ("math" . $i . ".php","r"); //Get contents of page 2 $file_cs = fopen("math_cs.php","w"); fwrite($file_cs, $copy_string);
$long_string = file_get_contents ("math" . $j . ".php","r"); $file3 = fopen("math" . $i . ".php","w"); fwrite($file3, $long_string); //Write Page 1 to Page 2
$file_cs = fopen("math_cs.php","r"); $file1 = fopen("math" . $j . ".php","w");
while (!feof($file_cs)) { $buffer3 = fgets($file_cs);
//Quite Tricky! Both if-else and or conditions
if (strncasecmp(trim($buffer3), "<!--Next-->", 7) == 0 || strncasecmp(trim($buffer3), "<a href=math", 11) == 0 || strncasecmp(trim($buffer3), "<!--Back-->", 7) == 0) { if (strncasecmp(trim($buffer3), "<!--Back-->", 7) == 0 || strncasecmp(trim($buffer3), "<a href=math", 11) == 0 && $next==1) { $k= $j-1; fwrite($file1, "<a href=math" . $k . ".php> back </a>\n"); $next*=-1; } else if (strncasecmp(trim($buffer3), "<!--Next-->", 7) == 0 || strncasecmp(trim($buffer3), "<a href=math", 11) == 0) { $k= $j+1; fwrite($file1, "<a href=math" . $k . ".php> next </a>\n"); $next*=-1; }}
else if (strncasecmp(trim($buffer3), "<!--Next-->", 7) <> 0 && strncasecmp(trim($buffer3), "<!--Back-->", 7) <> 0) { fwrite($file1, $buffer3); }
}
++$j; } // end of while($j<$i) $switch=0; }
}
//Completely different 2nd case ... if(trim($buffer) == '<p id="new_page">' && $line_counter<=66) {
}
}}
//Fix the problem with backs indivisually
$filea = fopen("math1.php","r"); $fileb = fopen("math1_cp.php","w");
while (!feof($filea)) { $buffers = fgets($filea); if(strncasecmp(trim($buffers), "<a href=math0.php", 15) == 0) { fwrite($fileb, "<!--Back-->\n"); } else fwrite($fileb, $buffers); } $filea = fopen("math1_cp.php","r"); $fileb = fopen("math1.php","w"); while (!feof($filea)) { $buffers = fgets($filea); fwrite($fileb, $buffers); }
header('Location: ask.php') ; exit;
?>
Last edited by chrishirst; 01-01-2011 at 05:33 PM..
|
|
|
|
01-01-2011, 03:29 PM
|
Re: PHP Multiple Users Problem
|
Posts: 1,618
Location: UK
|
Ok,
1) - dont store data in files, use a database.
2) - CLEAN! all incoming data, Your server is WIDE open for hacks ( see your page ) - I can run php code from your form.
3) The problem is most likely due to a page lock and while writing data to a page it fails on the other.
USE a mysql database, Check http://www.tizag.com/mysqlTutorial/ for an easy to follow guide.
While I havent taken advantage of your security hole, Someone else might.. Sanitize all user input, Strip html tags, strip php code etc..
Last edited by lynxus; 01-01-2011 at 03:33 PM..
|
|
|
|
01-01-2011, 04:11 PM
|
Re: PHP Multiple Users Problem
|
Posts: 45
Location: Canada
|
Hey,
Thanks a lot! It's funny how easily my script got pawned!
I think point 2 is taken care of.
As for point 3, is it possible to tell php to not write to a file when it's already writing. I can see it being inefficient compared to databases, but I just really want the code to work and get the job done. But I will look into MySQL.
Regards.
|
|
|
|
01-01-2011, 04:19 PM
|
Re: PHP Multiple Users Problem
|
Posts: 1,618
Location: UK
|
Quote:
Originally Posted by Jaspworld
Hey,
Thanks a lot! It's funny how easily my script got pawned!
I think point 2 is taken care of.
As for point 3, is it possible to tell php to not write to a file when it's already writing. I can see it being inefficient compared to databases, but I just really want the code to work and get the job done. But I will look into MySQL.
Regards.
|
Im not sure if php can check if its open or not ( im sure there is a way somewhere )
However If i ever use flat files to write to, I get PHP to create a basic lock file with some text in it saying 1 or 0 ( ie: lock.txt )
Basically when the script starts, It will check for that value inside lock.txt, If its 0 it will edit the file change it to 1 then start playing with other files.
When its finished it will change the lock file back to 0
When the script runs, If it finds a lock file with a value of 1 you could either tell it to wait / loop until its 0 and then continue ( locking the file while it does it ) OR give a user a message to try again ( with all the data pre-filled in for them so they only have to hit submit again .)
Thats how i would do it.
Bit of a nasty hack, but works.
Last edited by lynxus; 01-01-2011 at 04:21 PM..
|
|
|
|
01-01-2011, 04:40 PM
|
Re: PHP Multiple Users Problem
|
Posts: 2,815
Name: Matt
Location: Irvine, CA
|
I haven't tested this but it should cause the script to wait until it can acquire a lock on the file:
PHP Code:
$file = 'somefile.txt';
if(file_exists($file) && is_writeable($file))
{
$fh = fopen($file);
while(!flock($fh, LOCK_EX)) {} //while a lock cannot be acquired
//write to file here
flock($fh, LOCK_UN); //release the lock
}
Edit
It may be a good idea to call usleep inside the body of that while loop. I'm honestly not sure if anything bad can happen as a result of calling flock numerous times (performance issues maybe?).
Quote:
Basically when the script starts, It will check for that value inside lock.txt, If its 0 it will edit the file change it to 1 then start playing with other files.
When its finished it will change the lock file back to 0
|
By the way, what you're describing is similar to a mutex. There are a few cases where this approach can fail:
1. Two processes attempt to write to the mutex file at the same time (basically the same problem you are trying to prevent)
2. Process 1 reads the mutex file and sees it is set to 0. Before process 1 can set the mutex to 1 process 2 reads it and sees 0. Process 1 sets it to 1 and process 2 does the same immediately afterward. Both processes now think they have a lock on the file.
3. If for whatever reason a process fails to reset the mutex file to 0 after acquiring a lock, then all other processes are locked out.
It's best to rely on the OS for file locking since these types of problems have already been solved.
Last edited by NullPointer; 01-01-2011 at 04:51 PM..
|
|
|
|
01-01-2011, 06:20 PM
|
Re: PHP Multiple Users Problem
|
Posts: 1,618
Location: UK
|
Quote:
Originally Posted by NullPointer
I haven't tested this but it should cause the script to wait until it can acquire a lock on the file:
PHP Code:
$file = 'somefile.txt';
if(file_exists($file) && is_writeable($file)) { $fh = fopen($file); while(!flock($fh, LOCK_EX)) {} //while a lock cannot be acquired
//write to file here
flock($fh, LOCK_UN); //release the lock }
Edit
It may be a good idea to call usleep inside the body of that while loop. I'm honestly not sure if anything bad can happen as a result of calling flock numerous times (performance issues maybe?).
By the way, what you're describing is similar to a mutex. There are a few cases where this approach can fail:
1. Two processes attempt to write to the mutex file at the same time (basically the same problem you are trying to prevent)
2. Process 1 reads the mutex file and sees it is set to 0. Before process 1 can set the mutex to 1 process 2 reads it and sees 0. Process 1 sets it to 1 and process 2 does the same immediately afterward. Both processes now think they have a lock on the file.
3. If for whatever reason a process fails to reset the mutex file to 0 after acquiring a lock, then all other processes are locked out.
It's best to rely on the OS for file locking since these types of problems have already been solved.
|
Completely agree.
Your way is far nicer  Yet another thread bookmarked encase I need it 
|
|
|
|
01-02-2011, 05:54 PM
|
Problem Solved
|
Posts: 45
Location: Canada
|
Hey,
OK. The problem is solved thanks to both of you. I took both of your suggestions and combined them.
So now my code locks the entire script using the mutex file and I lock the mutex file using flock(). I believe this takes care of all the cases under which the mutex method may fail.
I think I could have just "flocked()" all the the files I'm writing to in the script but for some reason I went with the method I chose.
Regards.
|
|
|
|
01-03-2011, 04:23 PM
|
Re: PHP Multiple Users Problem
|
Posts: 879
Name: Paul W
|
Beware flock if using NFS - there can be serious issues.
|
|
|
|
|
« Reply to PHP Multiple Users Problem
|
|
|
| Thread Tools |
Search this Thread |
|
|
|
Posting Rules
|
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts
HTML code is Off
|
|
|
|