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