1: <?php
2: /**
3: * This file is part of the Autarky package.
4: *
5: * (c) Andreas Lutro <anlutro@gmail.com>
6: *
7: * For the full copyright and license information, please view the LICENSE
8: * file that was distributed with this source code.
9: */
10:
11: namespace Autarky\Files;
12:
13: /**
14: * Class that performs a locking file read/write operation.
15: *
16: * The object will add a file lock before writing and release it right after the
17: * contents have been written. This can be used to prevent corruption of data
18: * when multiple requests try to write to the same file at the same time.
19: */
20: class LockingFilesystem
21: {
22: /**
23: * Read from a file.
24: *
25: * @param string $path Path to the file.
26: * @param bool $blocking Wait for other locks to expire rather than
27: * throwing an error when a lock cannot be aquired.
28: *
29: * @return string
30: *
31: * @throws IOException
32: */
33: public function read($path, $blocking = false)
34: {
35: $size = filesize($path);
36:
37: if ($size === 0) {
38: return '';
39: }
40:
41: $flockFlags = $blocking ? LOCK_SH : LOCK_SH | LOCK_NB;
42:
43: $file = fopen($path, 'r');
44:
45: if (!flock($file, $flockFlags)) {
46: fclose($file);
47: throw new IOException("Could not aquire file lock for file: $path");
48: }
49:
50: $contents = fread($file, $size);
51: flock($file, LOCK_UN | LOCK_NB);
52: fclose($file);
53:
54: return $contents;
55: }
56:
57: /**
58: * Write to the file.
59: *
60: * @param string $path Path to the file.
61: * @param string $contents Contents to write to the file.
62: * @param bool $blocking Wait for other locks to expire rather than
63: * throwing an error when a lock cannot be aquired.
64: *
65: * @return void
66: *
67: * @throws IOException
68: */
69: public function write($path, $contents, $blocking = false)
70: {
71: $flockFlags = $blocking ? LOCK_EX : LOCK_EX | LOCK_NB;
72:
73: $file = fopen($path, 'c');
74:
75: if (!flock($file, $flockFlags)) {
76: fclose($file);
77: throw new IOException("Could not aquire file lock for file: $path");
78: }
79:
80: ftruncate($file, 0);
81: fwrite($file, $contents);
82: fflush($file);
83: flock($file, LOCK_UN | LOCK_NB);
84: fclose($file);
85: }
86: }
87: