3

I'd think there was a question on this already, but I can't find one. Maybe the solution is too easy... Anyway, I have a flat-file and want to let the user change the values based on a name. I've already sorted out creating new name+value-pairs using the fopen('a') mode, using jQuery to send the AJAX call with newValue and newName. But say the content looks like this:

host|http:www.stackoverflow.com
folder|/questions/
folder2|/users/

And now I want to change the folder value. So I'll send in folder as oldName and /tags/ as newValue. What's the best way to overwrite the value? The order in the list doesn't matter, and the name will always be on the left, followed by a |(pipe), the value and then a new-line.

My first thought was to read the list, store it in an array, search all the [0]'s for oldName, then change the [1] that belongs to it, and then write it back to a file. But I feel there is a better way around this? Any ideas? Maybe regex?

peirix
  • 36,512
  • 23
  • 96
  • 126
  • 1
    Don't forget some kind of locking mechanism. There's bound to be trouble if 2 scripts edit the file at the same time. – extraneon May 31 '10 at 14:23
  • 1
    CSV is an acronym for "comma separated values", and your separator is a pipe and not a comma. Though many CSV importers let you set the separator character to something that isn't a comma, I'd still say it's better to call this a "flat file". http://en.wikipedia.org/wiki/Flat_file_database – HostileFork says dont trust SE May 31 '10 at 14:32
  • @extraneon Yeah, this is for administrators only. And there will be one file per administrator. But I'll have a look into locking mechanisms just to be on the safe side (: thanks for reminding me. @Hostile Fork, Yeah, I know, but there really isn't any practical difference between the two, is there? – peirix May 31 '10 at 14:35
  • 1
    "When I use a word," Humpty Dumpty said in rather a scornful tone. "It means just what I choose it to mean, neither more or less." -- "The question is," said Alice, "whether you can make words mean so many different things." :) Choosing to be precise with our terminology avoids confusion and assists in relevant tagging. – HostileFork says dont trust SE May 31 '10 at 14:42
  • 1
    @Hostile Fork (: Nothing like quoting Lewis Carroll to get a point about semantics across. Point taken. – peirix May 31 '10 at 14:49
  • I'm not a PHP programmer (by choice) but searches on "PHP flat file" turn up a couple things which may or may not be useful if you're looking for database-oriented APIs instead of a more expedient hack...! – HostileFork says dont trust SE May 31 '10 at 15:01

2 Answers2

9

A very easy way would it be to use str_replace() on the whole file:

// read the file
$file = file_get_contents('filename.csv');
// replace the data
$file = str_replace('folder|oldValue', 'folder|newValue', $file);
// write the file
file_put_contents('filename.csv', $file);

That should work as only one user the file at a time. But a database is always a better idea. If you need CSV, it's better to have an additional DB to CSV script than only a CSV file.

2ndkauboy
  • 9,302
  • 3
  • 31
  • 65
5

You can keep the list in memory using a PHP feature like APC and write it out every so often to disk. That way you're only reading it in when it doesn't exist in memory.

If you want to be performance orientated storing this info in a CSV is likely not the best to begin with. If you don't want to use a true RDMS (MySQL) then I'd suggest using SQLite. It provides all the features you're looking for (UPDATE) in this case and it acts exactly the same as a CSV in the sense that it's just a file on your harddrive and doesn't have concurrency.

If that's not an option the other way is to use shell level commands like sed & awk to do inline regular expression changes. Lastly, reading the whole file into a string, performing a nasty regex adjustment on it (s///) and then writing it out again would work

Matt S
  • 1,767
  • 8
  • 9
  • Performance is not an issue, really. At most the file will have maybe 5 lines, that's why I'm not going to bother with MySQL. But there will be one file per client/user. I'll have a look into SQLite, though. Thanks. – peirix May 31 '10 at 14:31