DoorsRent Posted March 3, 2009 Share Posted March 3, 2009 I have a .txt file I want to let users change through my various php functions (user interface is an html page). I got it all working, but now I'm starting to think about what may happen if two users try to access the file at the same time. For explanation's sake, the file is simply a list of names. The user will enter a name into a text box and click either "Add" or "Remove". The .txt file isn't actually opened until the button is clicked, so it is opened, change is made then closed all in whatever time it takes for the php commands to execute. I know it's unlikely, but it is possible that two people will click their buttons at almost the same time. How can I deal with this issue? I just started looking into mysql. Is that the way I should go here? Thank you very much. Quote Link to comment Share on other sites More sharing options...
genericnumber1 Posted March 3, 2009 Share Posted March 3, 2009 The main problem is if one person opens the file, a second person opens a file, the first person saves his changes to the file, then the second person saves his changes to the file, the changes done by person one are overridden. The simplest way is to lock people out while another person is editing the file, but this can be annoying. All major version control systems have ways of dealing with version conflicts, you may want to look into how successful version control systems like SVN handle conflicts. Quote Link to comment Share on other sites More sharing options...
WolfRage Posted March 3, 2009 Share Posted March 3, 2009 You can use flock() to prevent over writing of data. and for your fopen, just tell it, if it fails to try again, and maybe even a third time. But php is fast enough that just one retry should be enough to get the file after the other data has been written. By the way fclose also closes the lock. Quote Link to comment Share on other sites More sharing options...
DoorsRent Posted March 3, 2009 Author Share Posted March 3, 2009 flock() looks like exactly what I need. Thanks a lot. Quote Link to comment Share on other sites More sharing options...
DoorsRent Posted March 4, 2009 Author Share Posted March 4, 2009 I've hit a snag with implementing this technique. I've opened the file, locked it then read all the lines into an array. The problem is I need to write the array back to the txt file. Before I used fopen() I was simply using the file() function then file_put_contents() to put the data back into the text file. The only way I can think of doing this is to close the file then reopen with "w+". But that will negate the advantages of using fopen() and flock(). Any ideas? Quote Link to comment Share on other sites More sharing options...
corbin Posted March 4, 2009 Share Posted March 4, 2009 Try r+ as the option. Quote Link to comment Share on other sites More sharing options...
DoorsRent Posted March 4, 2009 Author Share Posted March 4, 2009 Try r+ as the option. Then how do you actually delete the lines in the file. What I have is an array that is 1 line shorter than the file. I need to write the array to the file overwriting everything and then delete what will be the last line in the file since it will be extra. Or, just completely clear the file before I write it. Quote Link to comment Share on other sites More sharing options...
WolfRage Posted March 4, 2009 Share Posted March 4, 2009 OK, just before creating a new file delete it using unlink(). But this could still allow simultaneous file access, because no lock can be attained, if the file does not exist. I think though at this point it would be better if you clearly stated your objectives for this project then maybe we can give you a complete solution. Quote Link to comment Share on other sites More sharing options...
DoorsRent Posted March 4, 2009 Author Share Posted March 4, 2009 OK, just before creating a new file delete it using unlink(). But this could still allow simultaneous file access, because no lock can be attained, if the file does not exist. I think though at this point it would be better if you clearly stated your objectives for this project then maybe we can give you a complete solution. Objectives: o Have html page with text box and submit button. User enters name into text box and clicks submit to remove the name from a .txt file on server. o Multiple users will be using page and if one clicks "submit" right after another (but before the first one's process is finished) there could be problems. Here's my code where I'm trying to use the flock() function but can't figure out how to write the data back to the file: <?php remove_name("bob"); function remove_name($name) { $file = fopen("names.txt", "r+"); //open file stream with read/write permission while(!flock($file, LOCK_EX)); //wait until we can lock file exclusively, then lock it $data=fgetcsv($file); //fill names into array print "Original array: "; print_r($data); print "<br>"; for ( $counter = 0; $counter <= count($data); $counter++) { if ($data[$counter] == $name) unset($data[$counter]); //remove name from array } print "Modified array: "; print_r($data); print "<br>"; //write new array back to file while overwriting every other line //note - array now has fewer elements than lines in file flock($file, LOCK_UN); // release the lock fclose($file); } ?> And my simple text file: bill,bob,pam,tim,donald,scott One possible solution I've thought of us to create a dummy file that the program must exclusively lock before it can modify the names file (without a lock). Then I could just use the standard file() function and file_put_contents() function. Kind of a workaround, but I think that will do the job. Quote Link to comment Share on other sites More sharing options...
WolfRage Posted March 5, 2009 Share Posted March 5, 2009 I can not think of a better way honestly unless you go to using a database. Which over all is probably a better solution, although it certianly is not as simple of a solution. Let me know of the dumby lock method works. Quote Link to comment Share on other sites More sharing options...
DoorsRent Posted March 6, 2009 Author Share Posted March 6, 2009 Well, I got the dummy lock method working. At least I think so. I haven't thought of a good way to test that two users (i.e. php processes) aren't accessing the file at the same time. But, the .txt file is getting updated properly. Code: <?php remove_name("bob"); function remove_name($name) { $permissions = fopen("permissions.txt", "r+"); //open the permissions file while(!flock($permissions, LOCK_EX)); //wait until we can lock file exclusively, then lock it $file = fopen("names.txt", "r+"); //open file stream with read/write permission $data=fgetcsv($file); //fill names into array print "Original array: "; print_r($data); print "<br>"; for ( $counter = 0; $counter <= count($data); $counter++) { if ($data[$counter] == $name) unset($data[$counter]); //remove name from array } print "Modified array: "; print_r($data); print "<br>"; fclose($file); unlink("names.txt"); $file = fopen("names.txt","w"); fputcsv($file, $data); //write the array back to the file flock($permissions, LOCK_UN); // release the lock fclose($permissions); fclose($file); } ?> I've been trying to wrap my head around mysql the past couple days. I think I'll take a shot at using that. It's by far a more functional system, but way overkill right now. It will make it easier for upgrades to the system in the future though. Thanks a lot for the help WolfRage. Quote Link to comment Share on other sites More sharing options...
WolfRage Posted March 7, 2009 Share Posted March 7, 2009 No Problem, I am sure you will return the favor in the future. Quote Link to comment Share on other sites More sharing options...
Psycho Posted March 7, 2009 Share Posted March 7, 2009 Although you seem to have a solution, I think there may be a better one. Simply create a while loop that will continue indefinitely (with an exit trigger) as long as the script is unable to change the name of the text file. So, the first script in will change the name and the second script in will wait until the name is changed back. Here is some mock code (not tested). At the very least you need to first put a sleep() call within your while loop as the server will put as much CPU cycles as it can to run that loop. If there was ever a problem with the file that it simply got fubar'd and couldn't be opened you could crash the server. Which is why you should also implement a flag to exit the loop after n iterations to prevent an indefinite loop. $loops = 0; $file_ready = true; //Flag to determine if file is available while (!rename('/path/names.txt', '/path/temp_names.txt')) { //After 5 attempts exit the loop if ($loops==5) { $file_ready = false; break; } //Wait one second before trying again sleep (1); } if ($file_ready) { echo "Unable to access file"; } else { //Read and write contents to file then rename back to original name rename('/path/temp_names.txt', '/path/names.txt'); } Quote Link to comment Share on other sites More sharing options...
alphanumetrix Posted March 7, 2009 Share Posted March 7, 2009 flock would be a good idea. instead of a txt file though, why don't you just use a database? Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.