4
\$\begingroup\$

I'm using some simple files for caching and some basic user data. I was first just using file_put_contens and file_get_contents, but realized this could quickly go wrong when traffic starts increasing.

I've been trying to figure out how to do it properly with flock, correct file modes, etc, and come up with the following functions. Have I understood things correctly? Will this be safe in most normal use-cases, with small to medium web site usage?

class File
{

    public static function read($path, $default = NULL)
    {
        $fp = @fopen($path, 'r');
        if( ! $fp)
            return $default;

        flock($fp, LOCK_SH);
        $data = fread($fp, filesize($path));
        flock($fp, LOCK_UN);
        fclose($fp);

        return $data;
    }


    public static function write($path, $data)
    {
        self::check(dirname($path));

        $fp = fopen($path, 'c');
        flock($fp, LOCK_EX);
        ftruncate($fp, 0);
        fwrite($fp, $data);
        fflush($fp);
        flock($fp, LOCK_UN);
        fclose($fp);

        return $data;
    }



    public static function check($dir)
    {
        if( ! is_dir($dir))
        {
            // https://en.wikipedia.org/wiki/Chmod#System_call
            @mkdir($dir, 06750, true);
            @chmod($dir, 06750);
        }
        return $dir;
    }
}

Some particular things:

  • Should using LOCK_SH in read allow for multiple simultaneous reads?
    (which will be the bulk of what's happening since writes will happen quite seldom)
  • Will using LOCK_EX in write make sure nobody else is reading or writing while the file is changed?
  • Will using the directory permission mask 06750 makes sure that
    1. any files created in that directory will get the same permissions as the directory, and
    2. the directory/file will only be writable by the web server user and readable by its group?
\$\endgroup\$
  • \$\begingroup\$ I've already encountered with this situation where records of two more users gets merged. So, not sure this will help you out. \$\endgroup\$ – Haridarshan Feb 10 '16 at 13:31
  • \$\begingroup\$ @Haridarshan what do you mean? users gets merged? \$\endgroup\$ – Svish Feb 10 '16 at 16:05
  • \$\begingroup\$ If two users visit the site/portal at same timestamp and the visitor log of one user is getting written at the same visitor log of second user also gets written in the same. Because of which these two records of both users get merged. We're not using any kind of locking because that will delay the service we are provided. So, to handle such kind of problem we are using stomp to write the visitor logs. On an average we gets around 1M visitors. \$\endgroup\$ – Haridarshan Feb 11 '16 at 4:35
  • \$\begingroup\$ So performance aside, the locking would've fixed the merging problem? \$\endgroup\$ – Svish Feb 11 '16 at 6:01
  • \$\begingroup\$ We've tried the locking also but that delays the portal loading and we lose traffic. So, we're using stomp to write the log data in messaging queue i.e activemq and one fuse api to write the data into table/file. \$\endgroup\$ – Haridarshan Feb 11 '16 at 6:17
-1
\$\begingroup\$

Suppressing errors

Edit

Error suppression should be avoided if possible as it doesn't just suppress the error that you are trying to stop, but will also suppress errors that you didn't predict would ever occur. This will make debugging a nightmare.

Other then that, looks nice.

\$\endgroup\$
  • \$\begingroup\$ Good points. Although in my case, for read, if it fails, I just want to return the $default, and don't really care why it failed. This is why I chose to just suppress any errors and check if $fp is falsy right afterwards. As for in the write function, I'm not sure why it would ever fail, and if it did, not sure I could do anything sensible about it anyways. \$\endgroup\$ – Svish Feb 11 '16 at 6:07
  • \$\begingroup\$ You start by saying you should not just suppress the errors. You go on by saying you should suppress the errors. I think you meant something else there. \$\endgroup\$ – Mast May 21 '16 at 20:12
  • \$\begingroup\$ No, i'm saying surpress the errors & handle them when they occur. The error handler gets still called when surpressing errors with @ (With an error level of 0) \$\endgroup\$ – JazzCat May 21 '16 at 22:12
  • \$\begingroup\$ But i get the confusion, changed my answer. \$\endgroup\$ – JazzCat May 21 '16 at 22:18

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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