xref: /plugin/davcal/vendor/sabre/dav/lib/DAV/Locks/Backend/File.php (revision a1a3b6794e0e143a4a8b51d3185ce2d339be61ab)
1*a1a3b679SAndreas Boehler<?php
2*a1a3b679SAndreas Boehler
3*a1a3b679SAndreas Boehlernamespace Sabre\DAV\Locks\Backend;
4*a1a3b679SAndreas Boehler
5*a1a3b679SAndreas Boehleruse Sabre\DAV\Locks\LockInfo;
6*a1a3b679SAndreas Boehler
7*a1a3b679SAndreas Boehler/**
8*a1a3b679SAndreas Boehler * This Locks backend stores all locking information in a single file.
9*a1a3b679SAndreas Boehler *
10*a1a3b679SAndreas Boehler * Note that this is not nearly as robust as a database. If you are considering
11*a1a3b679SAndreas Boehler * using this backend, keep in mind that the PDO backend can work with SqLite,
12*a1a3b679SAndreas Boehler * which is designed to be a good file-based database.
13*a1a3b679SAndreas Boehler *
14*a1a3b679SAndreas Boehler * It literally solves the problem this class solves as well, but much better.
15*a1a3b679SAndreas Boehler *
16*a1a3b679SAndreas Boehler * @copyright Copyright (C) 2007-2015 fruux GmbH (https://fruux.com/).
17*a1a3b679SAndreas Boehler * @author Evert Pot (http://evertpot.com/)
18*a1a3b679SAndreas Boehler * @license http://sabre.io/license/ Modified BSD License
19*a1a3b679SAndreas Boehler */
20*a1a3b679SAndreas Boehlerclass File extends AbstractBackend {
21*a1a3b679SAndreas Boehler
22*a1a3b679SAndreas Boehler    /**
23*a1a3b679SAndreas Boehler     * The storage file
24*a1a3b679SAndreas Boehler     *
25*a1a3b679SAndreas Boehler     * @var string
26*a1a3b679SAndreas Boehler     */
27*a1a3b679SAndreas Boehler    private $locksFile;
28*a1a3b679SAndreas Boehler
29*a1a3b679SAndreas Boehler    /**
30*a1a3b679SAndreas Boehler     * Constructor
31*a1a3b679SAndreas Boehler     *
32*a1a3b679SAndreas Boehler     * @param string $locksFile path to file
33*a1a3b679SAndreas Boehler     */
34*a1a3b679SAndreas Boehler    function __construct($locksFile) {
35*a1a3b679SAndreas Boehler
36*a1a3b679SAndreas Boehler        $this->locksFile = $locksFile;
37*a1a3b679SAndreas Boehler
38*a1a3b679SAndreas Boehler    }
39*a1a3b679SAndreas Boehler
40*a1a3b679SAndreas Boehler    /**
41*a1a3b679SAndreas Boehler     * Returns a list of Sabre\DAV\Locks\LockInfo objects
42*a1a3b679SAndreas Boehler     *
43*a1a3b679SAndreas Boehler     * This method should return all the locks for a particular uri, including
44*a1a3b679SAndreas Boehler     * locks that might be set on a parent uri.
45*a1a3b679SAndreas Boehler     *
46*a1a3b679SAndreas Boehler     * If returnChildLocks is set to true, this method should also look for
47*a1a3b679SAndreas Boehler     * any locks in the subtree of the uri for locks.
48*a1a3b679SAndreas Boehler     *
49*a1a3b679SAndreas Boehler     * @param string $uri
50*a1a3b679SAndreas Boehler     * @param bool $returnChildLocks
51*a1a3b679SAndreas Boehler     * @return array
52*a1a3b679SAndreas Boehler     */
53*a1a3b679SAndreas Boehler    function getLocks($uri, $returnChildLocks) {
54*a1a3b679SAndreas Boehler
55*a1a3b679SAndreas Boehler        $newLocks = [];
56*a1a3b679SAndreas Boehler
57*a1a3b679SAndreas Boehler        $locks = $this->getData();
58*a1a3b679SAndreas Boehler
59*a1a3b679SAndreas Boehler        foreach ($locks as $lock) {
60*a1a3b679SAndreas Boehler
61*a1a3b679SAndreas Boehler            if ($lock->uri === $uri ||
62*a1a3b679SAndreas Boehler                //deep locks on parents
63*a1a3b679SAndreas Boehler                ($lock->depth != 0 && strpos($uri, $lock->uri . '/') === 0) ||
64*a1a3b679SAndreas Boehler
65*a1a3b679SAndreas Boehler                // locks on children
66*a1a3b679SAndreas Boehler                ($returnChildLocks && (strpos($lock->uri, $uri . '/') === 0))) {
67*a1a3b679SAndreas Boehler
68*a1a3b679SAndreas Boehler                $newLocks[] = $lock;
69*a1a3b679SAndreas Boehler
70*a1a3b679SAndreas Boehler            }
71*a1a3b679SAndreas Boehler
72*a1a3b679SAndreas Boehler        }
73*a1a3b679SAndreas Boehler
74*a1a3b679SAndreas Boehler        // Checking if we can remove any of these locks
75*a1a3b679SAndreas Boehler        foreach ($newLocks as $k => $lock) {
76*a1a3b679SAndreas Boehler            if (time() > $lock->timeout + $lock->created) unset($newLocks[$k]);
77*a1a3b679SAndreas Boehler        }
78*a1a3b679SAndreas Boehler        return $newLocks;
79*a1a3b679SAndreas Boehler
80*a1a3b679SAndreas Boehler    }
81*a1a3b679SAndreas Boehler
82*a1a3b679SAndreas Boehler    /**
83*a1a3b679SAndreas Boehler     * Locks a uri
84*a1a3b679SAndreas Boehler     *
85*a1a3b679SAndreas Boehler     * @param string $uri
86*a1a3b679SAndreas Boehler     * @param LockInfo $lockInfo
87*a1a3b679SAndreas Boehler     * @return bool
88*a1a3b679SAndreas Boehler     */
89*a1a3b679SAndreas Boehler    function lock($uri, LockInfo $lockInfo) {
90*a1a3b679SAndreas Boehler
91*a1a3b679SAndreas Boehler        // We're making the lock timeout 30 minutes
92*a1a3b679SAndreas Boehler        $lockInfo->timeout = 1800;
93*a1a3b679SAndreas Boehler        $lockInfo->created = time();
94*a1a3b679SAndreas Boehler        $lockInfo->uri = $uri;
95*a1a3b679SAndreas Boehler
96*a1a3b679SAndreas Boehler        $locks = $this->getData();
97*a1a3b679SAndreas Boehler
98*a1a3b679SAndreas Boehler        foreach ($locks as $k => $lock) {
99*a1a3b679SAndreas Boehler            if (
100*a1a3b679SAndreas Boehler                ($lock->token == $lockInfo->token) ||
101*a1a3b679SAndreas Boehler                (time() > $lock->timeout + $lock->created)
102*a1a3b679SAndreas Boehler            ) {
103*a1a3b679SAndreas Boehler                unset($locks[$k]);
104*a1a3b679SAndreas Boehler            }
105*a1a3b679SAndreas Boehler        }
106*a1a3b679SAndreas Boehler        $locks[] = $lockInfo;
107*a1a3b679SAndreas Boehler        $this->putData($locks);
108*a1a3b679SAndreas Boehler        return true;
109*a1a3b679SAndreas Boehler
110*a1a3b679SAndreas Boehler    }
111*a1a3b679SAndreas Boehler
112*a1a3b679SAndreas Boehler    /**
113*a1a3b679SAndreas Boehler     * Removes a lock from a uri
114*a1a3b679SAndreas Boehler     *
115*a1a3b679SAndreas Boehler     * @param string $uri
116*a1a3b679SAndreas Boehler     * @param LockInfo $lockInfo
117*a1a3b679SAndreas Boehler     * @return bool
118*a1a3b679SAndreas Boehler     */
119*a1a3b679SAndreas Boehler    function unlock($uri, LockInfo $lockInfo) {
120*a1a3b679SAndreas Boehler
121*a1a3b679SAndreas Boehler        $locks = $this->getData();
122*a1a3b679SAndreas Boehler        foreach ($locks as $k => $lock) {
123*a1a3b679SAndreas Boehler
124*a1a3b679SAndreas Boehler            if ($lock->token == $lockInfo->token) {
125*a1a3b679SAndreas Boehler
126*a1a3b679SAndreas Boehler                unset($locks[$k]);
127*a1a3b679SAndreas Boehler                $this->putData($locks);
128*a1a3b679SAndreas Boehler                return true;
129*a1a3b679SAndreas Boehler
130*a1a3b679SAndreas Boehler            }
131*a1a3b679SAndreas Boehler        }
132*a1a3b679SAndreas Boehler        return false;
133*a1a3b679SAndreas Boehler
134*a1a3b679SAndreas Boehler    }
135*a1a3b679SAndreas Boehler
136*a1a3b679SAndreas Boehler    /**
137*a1a3b679SAndreas Boehler     * Loads the lockdata from the filesystem.
138*a1a3b679SAndreas Boehler     *
139*a1a3b679SAndreas Boehler     * @return array
140*a1a3b679SAndreas Boehler     */
141*a1a3b679SAndreas Boehler    protected function getData() {
142*a1a3b679SAndreas Boehler
143*a1a3b679SAndreas Boehler        if (!file_exists($this->locksFile)) return [];
144*a1a3b679SAndreas Boehler
145*a1a3b679SAndreas Boehler        // opening up the file, and creating a shared lock
146*a1a3b679SAndreas Boehler        $handle = fopen($this->locksFile, 'r');
147*a1a3b679SAndreas Boehler        flock($handle, LOCK_SH);
148*a1a3b679SAndreas Boehler
149*a1a3b679SAndreas Boehler        // Reading data until the eof
150*a1a3b679SAndreas Boehler        $data = stream_get_contents($handle);
151*a1a3b679SAndreas Boehler
152*a1a3b679SAndreas Boehler        // We're all good
153*a1a3b679SAndreas Boehler        flock($handle, LOCK_UN);
154*a1a3b679SAndreas Boehler        fclose($handle);
155*a1a3b679SAndreas Boehler
156*a1a3b679SAndreas Boehler        // Unserializing and checking if the resource file contains data for this file
157*a1a3b679SAndreas Boehler        $data = unserialize($data);
158*a1a3b679SAndreas Boehler        if (!$data) return [];
159*a1a3b679SAndreas Boehler        return $data;
160*a1a3b679SAndreas Boehler
161*a1a3b679SAndreas Boehler    }
162*a1a3b679SAndreas Boehler
163*a1a3b679SAndreas Boehler    /**
164*a1a3b679SAndreas Boehler     * Saves the lockdata
165*a1a3b679SAndreas Boehler     *
166*a1a3b679SAndreas Boehler     * @param array $newData
167*a1a3b679SAndreas Boehler     * @return void
168*a1a3b679SAndreas Boehler     */
169*a1a3b679SAndreas Boehler    protected function putData(array $newData) {
170*a1a3b679SAndreas Boehler
171*a1a3b679SAndreas Boehler        // opening up the file, and creating an exclusive lock
172*a1a3b679SAndreas Boehler        $handle = fopen($this->locksFile, 'a+');
173*a1a3b679SAndreas Boehler        flock($handle, LOCK_EX);
174*a1a3b679SAndreas Boehler
175*a1a3b679SAndreas Boehler        // We can only truncate and rewind once the lock is acquired.
176*a1a3b679SAndreas Boehler        ftruncate($handle, 0);
177*a1a3b679SAndreas Boehler        rewind($handle);
178*a1a3b679SAndreas Boehler
179*a1a3b679SAndreas Boehler        fwrite($handle, serialize($newData));
180*a1a3b679SAndreas Boehler        flock($handle, LOCK_UN);
181*a1a3b679SAndreas Boehler        fclose($handle);
182*a1a3b679SAndreas Boehler
183*a1a3b679SAndreas Boehler    }
184*a1a3b679SAndreas Boehler
185*a1a3b679SAndreas Boehler}
186