Working with flat-file databases
I would like to learn how to use a flat-file database (because my computer can't support MySQL) I googled for tutorials but didn't have much lick with it. Could anyone direct me to one or two good ones? Or explain how to make one?
Mark Hensler posted this at 07:14 — 24th August 2003.
He has: 4,048 posts
Joined: Aug 2000
The way I've done it in the past is use rows as records and a delimeter for fields. Similar to the passwd file on a linux box.
First 3 lines of my /etc/passed file...
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/bin/sh
daemon:x:2:2:daemon:/sbin:/bin/sh
How do you read it? Basically...
Suck the entire file into memory. If possible, make each line in the file a seperate element in an array.
If not, then suck the file into a string, then explode on the newline character (\n) to create an array with each element being one of the lines in the file.
Array
(
[1] => root:x:0:0:root:/root:/bin/bash
[2] => bin:x:1:1:bin:/bin:/bin/sh
[3] => daemon:x:2:2:daemon:/sbin:/bin/sh
)
Then iterate (loop) through the first array, and explode on the colorn ( to create a second array of the fields for the current element in the first array.
Array
(
[1] => root
[2] => x
[3] => 0
[4] => 0
[5] => root
[6] => /root
[7] => /bin/bash
)
Now its important for you to know the format of your file. Meaning, the order of your fields within each line. In this case, the fields are as follows:
1 - user
2 - password
3 - user id
4 - group id
5 - name, notes, or short description
6 - home directory
7 - shell
Now, you will want to identify the record (first array) you wish to read/modify by examing the fields (second array). So, lets say you want to edit the 'bin' user. Within the loop, you would test the first element (or field) in the second array against the string 'bin'. If you have a match, then this is record you wish to modify. If not, you continue with the iteration until you find a match or you reach the end of the array.
Mark Hensler
If there is no answer on Google, then there is no question.
Renegade posted this at 11:07 — 24th August 2003.
He has: 3,022 posts
Joined: Oct 2002
So, when people say something is using a flat file database they really mean an array thats in an external file?
They arrays, they start with a 1? I thought they started with a 0?
Mark Hensler posted this at 16:14 — 25th August 2003.
He has: 4,048 posts
Joined: Aug 2000
No. I just decided to use arrays to examine the file.
A flat file could use fixed length fields. In which case, you'd be using substr(). (do you want to see an example of that?)
They do. Sorry about that.
Mark Hensler
If there is no answer on Google, then there is no question.
Renegade posted this at 01:46 — 26th August 2003.
He has: 3,022 posts
Joined: Oct 2002
Yes please
Mark Hensler posted this at 03:35 — 26th August 2003.
He has: 4,048 posts
Joined: Aug 2000
root x 0 0 root /root /bin/bash
bin x 1 1 bin /bin /bin/sh
daemon x 2 2 daemon /sbin /bin/sh
This time, the fields are fixed length...
field 1 - 10 characters
field 2 - 10 characters
field 3 - 5 characters
field 4 - 5 characters
field 5 - 20 characters
field 6 - 20 characters
field 7 - 15 characters
(record - 85 characters + 1 newline character)
To read this file, you do not need to suck the whole file into memory. You may simply read 86 bytes at a time.
You don't really need to suck the other format discussed into memory. You could simply read the file one character at a time until you read a newline character (\n). But that can get tedious. I've never seen anyone handle a delimited file without sucking the file into memory first.
<?php
$fptr = fopen(file, \"r\");
if ($fptr) {
do {
$data = fread($fptr, 86);
if (strlen($data) == 0) break;
$username = substr($data, 0, 10);
$password = substr($data, 10, 10);
$userid = substr($data, 20, 5);
$groupid = substr($data, 25, 5);
$notes = substr($data, 30, 20);
$home = substr($data, 50, 20);
$shell = substr($data, 70, 15);
if ($username != $the_record_to_edit) continue;
// this is the record i'm interested in
} while(true);
fclose ($handle);
}
?>
I just checked the PHP manual, and there is an fgets() funciton which reads up to X bytes of data or until EOL (end of line) or EOF (end of file) is reached. This would be usefull for reading delimited files one record at a time.
Mark Hensler
If there is no answer on Google, then there is no question.
Renegade posted this at 05:46 — 26th August 2003.
He has: 3,022 posts
Joined: Oct 2002
To me, the first one with arrays look a bit better.
If you wanted to change bin:x:1:1:bin:/bin:/bin/sh to something like bin:x:2:1:bin:/bin:/bin/sh how would yo go about doing it? or if you wanted to delete it.
Mark Hensler posted this at 16:41 — 26th August 2003.
He has: 4,048 posts
Joined: Aug 2000
I've only worked flat files from Perl...
# suck the flat file into an array
open (INFILE, "</path/to/flatfile") or die "Cannot open file for input: $!";
@database = <INFILE>;
close INFILE or die "Cannot close filename: $!";
open (OUTFILE, ">/path/to/flatfile") or die "Cannot open file for output: $!";
# loop through records
foreach $record (@database) {
@fields = split(/:/, $record);
if ($field{0} eq "bin") {
# this is the record we want to modify/delete
# if you want to delete this record,
# simply do not print it to the OUTFILE
$field{2} = 2;
$record = join(':', @field);
}
print OUTFILE $record;
}
close OUTFILE or die "Cannot close filename: $!";
Mark Hensler
If there is no answer on Google, then there is no question.
m3rajk posted this at 16:42 — 26th August 2003.
They have: 461 posts
Joined: Jul 2003
<?php
foreach ($array as $value){
if($value = 'bin:x:1:1:bin:/bin:/bin/sh'){
$value = 'bin:x:2:1:bin:/bin:/bin/sh';
}
}
?>
<?php
function remove_path($array, $string){
$newarray=array();
foreach ($array as $value){
if($value != '$string'){
$newarray[]=$value;
}
}
return $newarray;
}
$paths=remove_path($paths, 'bin:x:1:1:bin:/bin:/bin/sh');
?>
POSIX. because a stable os that doesn't have memory leaks and isn't buggy is always good.
Mark Hensler posted this at 16:50 — 26th August 2003.
He has: 4,048 posts
Joined: Aug 2000
That's too restrictive. You have to know what the whole record looks like. Not just which "primary field" you wish to work on.
Perl code converted to PHP...
<?php
// suck the flat file into an array
$database = file(\"/path/to/flatfile\", \"r+\");
$fp = fopen(\"/path/to/flatfile\", \"w\");
if ($fp) {
// loop through records
foreach ($database as $record) {
$fields = explode(\":\", $record);
if ($field[0] == \"bin\") {
// this is the record we want to modify/delete
// if you want to delete this record,
// simply do not print it to the OUTFILE
$field[2] = 2;
$record = implode(':', $field);
}
fwrite($fp, $record);
}
fclose($fp);
}
?>
Mark Hensler
If there is no answer on Google, then there is no question.
Renegade posted this at 21:08 — 26th August 2003.
He has: 3,022 posts
Joined: Oct 2002
Cool, thanks Mark
Want to join the discussion? Create an account or log in if you already have one. Joining is fast, free and painless! We’ll even whisk you back here when you’ve finished.