1
\$\begingroup\$

So, I made a tiny (~2 KB, <100 lines) library for simple flat-file data storage.

How it works is, you define a file to be used, and then you can add/read/modify/delete objects as "keys" to/from the file.

All the code is on github, but I'll put it here too:

varDx.php:

<?php
namespace varDX;

class cDX {
    private $dataFile;  

    public function def($filename){
        $this->dataFile = $filename;
    }

    public function write($varName, $varVal){
        if(file_exists($this->dataFile)){
            $foundLine = $this->check($varName);
        } else {
            $foundLine = false;
        }

        if(!$foundLine){
            $writeData = $varName.'__=__'.urlencode(serialize($varVal)).PHP_EOL;
            file_put_contents($this->dataFile, $writeData, FILE_APPEND);    
        } else {
            return "ERR_DX_KEY_ALREADY_EXISTS";
        }
    }

    public function read($varName){
        if(file_exists($this->dataFile)){
            foreach(file($this->dataFile) as $line) {
                if(strpos($line, $varName) !== false) {
                    list(, $new_str) = explode("__=__", $line);
                    $foundLine = true;
                }
            }
            if($foundLine){
                $val = rtrim($new_str); 
                return unserialize(urldecode($val));
            } else {
                return "ERR_DX_KEY_NOT_FOUND";
            }
        } else {
            return "ERR_DX_FILE_DOES_NOT_EXIST";
        }
    }


    public function del($varName){
        if(file_exists($this->dataFile)){
            $f = $this->dataFile;
            $term = $varName.'__=__';
            $arr = file($f);
            foreach ($arr as $key=> $line) {
                if(stristr($line,$term)!== false){unset($arr[$key]);break;}
            }
            //reindexing array
            $arr = array_values($arr);
            //writing to file
            file_put_contents($f, implode($arr));
        } else {
            return "ERR_DX_FILE_DOES_NOT_EXIST";
        }
    }

    public function modify($varName, $varVal){
        if(file_exists($this->dataFile)){   
            if($this->check($varName)){
                $this->del($varName);
            } 
        }
        $writeData = $varName.'__=__'.urlencode(serialize($varVal)).PHP_EOL;
        file_put_contents($this->dataFile, $writeData, FILE_APPEND);    

    }

    public function check($varName){
        if(file_exists($this->dataFile)){
            foreach(file($this->dataFile) as $line) {
                if(stripos($line, $varName.'__=__') === 0){
                    return true;
                } 
            }
            return false;
        } else {
            return "ERR_DX_FILE_DOES_NOT_EXIST";
        }
    }
}

Usage:

<?php
require 'varDx.php';
$dx = new \varDx\cDX; //create object
$dx->def('file1.txt'); //define data file

$a = "this is a string";
$dx->write('val1', $a); //write key to file

$dx->modify('val1', "this is another string"); //modify value of key
echo $dx->read('val1'); //read value of key

if($dx->check('val1')){ //check if key exists
    del('val1'); //delete key
}

File storage:

All keys are stored in this format:

keyname__=__urlencode(serialize(value_of_key))

There's more info on the functions in the README on the github page. I'm wondering if I can make this more efficient when dealing with files, and if there's anything else that I'm doing wrong?

\$\endgroup\$
2
  • 3
    \$\begingroup\$ Can you please explain the purpose of this storage? \$\endgroup\$ Dec 30, 2018 at 18:34
  • \$\begingroup\$ Your library does not adhere to PSR; it can not be installed by composer. \$\endgroup\$
    – Kyslik
    Dec 30, 2018 at 18:58

1 Answer 1

1
\$\begingroup\$

Assuming this code is solely for learning purpose, there are several main issues

  • to be honest, a function that returns ERR_DX_FILE_DOES_NOT_EXIST when I request an object looks a bit weird. I don't even know how to use it. Should I wrap every call to a function in a condition that checks the returned value? Or what else I am supposed to do with this string? Consider using errors/exceptions in case of error.
  • a race condition issue. you can have this file malformed if two parallel processes would try to write at the same time. Consider use file locks
  • an obvious memory issue - the bigger the file is, the more RAM does it take to process. PHP can let you to read a file line by line without memory overhead
  • such a clumsy format as keyname__=__urlencode(serialize(value_of_key)) doesn't seem to be very reliable. For such a toy storage I would rather use json format, to ease the search/key access.
\$\endgroup\$
3
  • \$\begingroup\$ The reason I used that weird long return value is because I can't return something like false or 0 because those could totally be valid values for the keys being accessed \$\endgroup\$
    – undo
    Dec 31, 2018 at 6:56
  • \$\begingroup\$ I understand that. it desn't make sense to use such weird return value either. there are errors/exceptions to handle this situation \$\endgroup\$ Dec 31, 2018 at 7:11
  • \$\begingroup\$ Cheers! Still new to this stuff, I'll figure something out. \$\endgroup\$
    – undo
    Dec 31, 2018 at 7:22

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.