Simple (but robust!) PHP key-value flat-file data storage library
Current library version: 4.1
| 2022-02-22
Current DB file version: 3.1
License: AGPLv3
StorX is an easy and robust way to write data (objects) to flat files as "keys", which you can read and modify later.
It was initially developed primarily to facilitate sharing of objects between independent PHP scripts and sessions, but can be used in any context where you want to easily write/read data to/from files, but don't want to deal with the complexities of relational databases.
It is basically serialize()
+ file handling (fopen(), fread(), fwrite()
) on steroids. Objects are stored as "keys" in "DB files". These files can be read from and written to concurrently with (almost) no risk of data corruption, which is impossible with regular PHP file handling.
It is technically an abstraction layer on top of SQLite3, and the DB files are essentially just SQLite3 database files, so you get the robustness of SQLite, but don't have to actually manually create DBs or formulate complicated queries just to be able to store and retrieve information. This also means that it's easy to export the data to other DBs.
You can also interface with StorX DB files stored on a different machine over the network/internet. Take a look at StorX-API and StorX-Remote.
See a simple real-world usage example in the form of a website hit counter here!
The easiest way to understand what this library does is to see it in action:
//StorX example
<?php
//include the StorX library
require 'StorX.php';
//create Sx 'handle' object to work with the DB file
$sx = new \StorX\Sx;
//create a DB file
$sx->createFile('testDB.dat');
//open the file for writing
$sx->openFile('testDB.dat', 1);
//write stuff to the DB file
$sx->writeKey('username', 'Aavi'); //username is now 'Aavi'
//we can modify keys too!
$sx->modifyKey('username', 'Amit'); //username is now 'Amit'
//here's how we read a key
$sx->readKey('username', $username);
//the value of key 'username' ('Amit') has now been stored in $username
//now we can do whatever we want with it
echo "User: $username"; //prints 'User: Amit'
echo "<br>";
//there's also a function to directly return the value of a key:
echo "User: " . $sx->returnKey('username'); //prints 'User: Amit'
echo "<br>";
//here's how we check if a key exists in the DB file
if($sx->checkKey('username')){
echo "'username' key exists in DB file!";
echo "<br>";
}
//deleting a key
$sx->deleteKey('password');
//commit changes to DB file and close it
$sx->closeFile();
- Key names can technically be any strings, but for compatibility stick with the same naming pattern as with PHP variables:
A valid variable name starts with a letter or underscore, followed by any number of letters, numbers, or underscores.
- Changes you make using
writeKey()
,modifyKey()
,modifyMultipleKeys()
ordeleteKey()
are immediately reflected in subsequentreadKey()
,readAllKeys()
orreturnKey()
function calls, but are not saved to disk until you call eithercloseFile()
orcommitFile()
. - Exceptions are enabled by default, this behaviour can be changed by calling
\StorX\Sx::throwExceptions()
or by changing the value of the constantTHROW_EXCEPTIONS
at the beginning ofStorX.php
. - By default, StorX has a busy timeout of 1.5 seconds, this can be changed by calling
\StorX\Sx::setTimeout()
or by changing the value of the constantBUSY_TIMEOUT
at the beginning ofStorX.php
. - Because keyValues are serialized before storage, they can be objects of any class (or text/variables/NULL/arrays/etc).
StorXInfo
is the only reserved key name. Don't use it!
- Save
StorX.php
on your server. You can rename it. - Include the file:
require 'StorX.php';
.
To work with a StorX DB file, we use a file handle object (sorta similar to how fopen() works).
We create one like this:
$sx = new \StorX\Sx;
We then interface with this object using the following functions.
Conditions where e
is marked with *
will throw an exception if exceptions are enabled.
If an error is encountered, StorX will throw an exception if set to true
.
The default value for this can be changed by modifying the THROW_EXCEPTIONS
constant in StorX.php
.
$sx = new \StorX\Sx;
$sx->throwExceptions(true); //enable exceptions
Returns true
if exceptions are enabled, false
if they're not.
Tells SQLite how long to try for in case the DB file is locked. Learn more here.
The default value for this can be changed by modifying the BUSY_TIMEOUT
constant in StorX.php
.
$sx = new \StorX\Sx;
$sx->setTimeout(2500); //set timeout of 2.5 seconds
Returns the current set timeout value.
Create a StorX DB file.
$sx = new \StorX\Sx;
if($sx->createFile('testDB.dat') === 1){
echo 'testDB.dat created!';
} else {
echo 'error creating testDB.dat';
}
returned value | e | meaning |
---|---|---|
0 |
* | unable to create file |
1 |
file successfully created |
Delete everything in a StorX DB file, then delete the file itself. Will work on all StorX DB files, regardless of DB file version.
$sx = new \StorX\Sx;
if($sx->deleteFile('testDB.dat') === 1){
echo 'testDB.dat deleted!';
} else {
echo 'error deleting testDB.dat';
}
returned value | e | meaning |
---|---|---|
0 |
* | unable to delete data |
0 |
* | not a StorX DB file |
1 |
file does not exist | |
1 |
file successfully deleted |
Check if a StorX DB file exists.
$sx = new \StorX\Sx;
if($sx->checkFile('testDB.dat') === 1){
echo 'testDB.dat exists as a StorX DB file!';
} else {
echo 'testDB.dat doesn't exist as a StorX DB file!';
}
returned value | e | meaning |
---|---|---|
0 |
the file doesn't exist | |
1 |
a StorX file of the correct version (3.1) exists | |
2 |
a StorX DB file exists, but of a different version | |
3 |
an SQLite3 file exists but it's not a StorX DB | |
4 |
an SQLite3 file exists but it's locked | |
5 |
a file exists but it's not an SQLite3 file |
Opens a StorX DB file for reading (and optionally) writing.
- If
mode
is1
, file is opened for reading and writing. - If mode is
0
or empty, file is opened for reading only.
$sx = new \StorX\Sx;
if($sx->openFile('testDB.dat', 1)){
echo 'opened testDB.dat successfully';
} else {
echo 'error opening testDB.dat';
}
returned value | e | meaning |
---|---|---|
0 |
* | file doesn't exist |
0 |
* | unable to open file |
1 |
successfully opened file |
Closes a StorX DB file. If file was opened for writing then changes are saved before it's closed.
if($sx->closeFile('testDB.dat', 1)){
echo 'closed testDB.dat successfully';
} else {
echo 'error closing testDB.dat';
}
returned value | e | meaning |
---|---|---|
0 |
* | unable to save changes and close file |
1 |
changes have been saved and the file has been closed | |
1 |
no file open |
Saves changes made to an open StorX DB file, but keeps it open.
if($sx->commitFile('testDB.dat', 1)){
echo 'saved changes made to testDB.dat successfully';
} else {
echo 'error saving changes to testDB.dat';
}
returned value | e | meaning |
---|---|---|
0 |
* | unable to save changes to file |
0 |
* | no file open |
1 |
changes have been saved |
Reads a key and saves the value in store
.
$name = ''; //this statement is for readability, not strictly required
$sx->readKey('username', $name);
//value of 'username' key is now in $name
echo $name; //echo value of 'username' key
returned value | e | meaning |
---|---|---|
0 |
* | no file open |
0 |
* | key not found in DB file |
1 |
key read successfully, and value stored in store . |
Reads a key and returns the value.
Use of this function is discouraged, because if exceptions are disabled and the key read fails, then detecting the failure is messy.
Use readKey()
instead whenever possible!
echo $sx->returnKey('username'); //echo value of 'username' key
returned value | e | meaning |
---|---|---|
"STORX_ERROR " |
* | no file open |
"STORX_ERROR " |
* | key not found in DB file |
Reads all keys and saves them as an associative array in store
.
The array is structured as:
array(
key1 => val1,
key2 => val2,
key3 => val3
...
)
Usage:
$sx->readAllKeys($keyArray);
//all keys are now in $keyArray
echo $keyArray['username']; //echo value of 'username' key
returned value | e | meaning |
---|---|---|
0 |
* | no file open |
0 |
* | unable to read keys from DB file |
1 |
keys read successfully, and stored in store . |
Writes the key along with the value to the open DB file. The value can be text, a variable, an array, NULL, or an object of any class. Will fail if a key with the same keyName already exists.
$sx->writeKey('username', 'aavi001');
$array = array("foo", "bar", "hello", "world"); //array
$sx->writeKey('words', $array);
$rt = new RT(); //object of a class
$sx->writeKey('RTobj', $rt);
returned value | e | meaning |
---|---|---|
0 |
* | no file open |
0 |
* | file not locked (not opened for writing) |
0 |
* | another key with the same keyName already exists |
0 |
* | unable to write key |
1 |
key written successfully |
Modifies a key's value in the open DB file. If the key does not exist in the file then it is created.
Like with writeKey()
, the value can be text, a variable, an array, NULL, or an object of any class.
$sx->modifyKey('username', 'amit009');
returned value | e | meaning |
---|---|---|
0 |
* | no file open |
0 |
* | file not locked (not opened for writing) |
0 |
* | unable to modify key |
0 |
* | unable to write key |
1 |
key value modified successfully |
Reads multiple keys from an array and modifies them in the open DB file.
keyArray
should be an associative array like such:
array(
key1 => val1,
key2 => val2,
key3 => val3
...
)
If a key does not exist in the file then it is created.
As with modifyKey()
and writeKey()
, the value can be text, a variable, an array, NULL, or an object of any class.
$array1 = array("v1" => 100, "v2" => 200, "v3" => "300");
$sx->modifyMultipleKeys($array1);
returned value | e | meaning |
---|---|---|
0 |
* | no file open |
0 |
* | file not locked (not opened for writing) |
0 |
* | unable to modify key |
0 |
* | unable to write key |
1 |
key values modified successfully |
Checks if a key exists in the open DB file.
if($sx->checkKey('username')){
echo 'username key exists in file!';
} else {
echo 'username key doesn't exist in file!';
}
returned value | e | meaning |
---|---|---|
0 |
* | no file open |
0 |
key doesn't exist in DB file | |
1 |
key exists in DB file |
Deletes a key from the open DB file.
if($sx->deleteKey('username')){
echo 'username key deleted from file!';
} else {
echo 'username key can't be deleted from file!';
}
returned value | e | meaning |
---|---|---|
0 |
* | no file open |
0 |
* | file not locked (not opened for writing) |
0 |
* | unable to delete key |
1 |
key deleted successfully |
If exceptions are enabled, the thrown exceptions can have these exception codes:
Code | Meaning |
---|---|
101 | File does not exist |
102 | No file open |
103 | File is not locked for writing (but should be) |
104 | File is locked (but shouldn't be) |
105 | File not of matching StorX version |
106 | Unable to create file |
107 | Unable to delete file |
108 | Unable to open file |
109 | Unable to commit changes to file |
- | - |
201 | Key doesn't exist |
202 | Key already exists |
203 | Unable to read key(s) |
204 | Unable to write/modify key(s) |
205 | Unable to delete key |
- | - |
300 | SQLite3 error |
- Supported versions of PHP. At the time of writing, that's PHP
7.4+
. StorX will almost certainly work on older versions, but we don't test it on those, so be careful, do your own testing. - PHP's
sqlite3
extension. Almost always enabled by default.
Keys are serialized and then stored in an SQLite3 database file.
Because these are just regular SQLite3 DB files, you can access them using any software or library that supports the format.
As of StorX DB file version 3.1, the DB file contains a single table, main
:
+------------------------+
| keyName | keyValue |
+-------------|----------+
| StorXInfo | v3.1 |
| | |
| key1 | val1 |
| key2 | val2 |
| key3 | val3 |
| ... | ... |
| | |
+-------------|----------+
Key names are stored in the column keyName
as base64-encoded strings, and the corresponding data is stored in the column keyValue
as strings in the PHP serialized format: base64_encode(serialize(<data>))
.
Documentation updated 2022-04-13