1<?php
2
3namespace Sabre\DAV\FSExt;
4
5use Sabre\DAV;
6
7/**
8 * Base node-class
9 *
10 * The node class implements the method used by both the File and the Directory classes
11 *
12 * @copyright Copyright (C) 2007-2015 fruux GmbH (https://fruux.com/).
13 * @author Evert Pot (http://evertpot.com/)
14 * @license http://sabre.io/license/ Modified BSD License
15 */
16abstract class Node extends DAV\FS\Node implements DAV\IProperties {
17
18    /**
19     * Updates properties on this node,
20     *
21     * @param array $properties
22     * @see Sabre\DAV\IProperties::updateProperties
23     * @return bool|array
24     */
25    public function updateProperties($properties) {
26
27        $resourceData = $this->getResourceData();
28
29        foreach($properties as $propertyName=>$propertyValue) {
30
31            // If it was null, we need to delete the property
32            if (is_null($propertyValue)) {
33                if (isset($resourceData['properties'][$propertyName])) {
34                    unset($resourceData['properties'][$propertyName]);
35                }
36            } else {
37                $resourceData['properties'][$propertyName] = $propertyValue;
38            }
39
40        }
41
42        $this->putResourceData($resourceData);
43        return true;
44    }
45
46    /**
47     * Returns a list of properties for this nodes.;
48     *
49     * The properties list is a list of propertynames the client requested, encoded as xmlnamespace#tagName, for example: http://www.example.org/namespace#author
50     * If the array is empty, all properties should be returned
51     *
52     * @param array $properties
53     * @return array
54     */
55    function getProperties($properties) {
56
57        $resourceData = $this->getResourceData();
58
59        // if the array was empty, we need to return everything
60        if (!$properties) return $resourceData['properties'];
61
62        $props = array();
63        foreach($properties as $property) {
64            if (isset($resourceData['properties'][$property])) $props[$property] = $resourceData['properties'][$property];
65        }
66
67        return $props;
68
69    }
70
71    /**
72     * Returns the path to the resource file
73     *
74     * @return string
75     */
76    protected function getResourceInfoPath() {
77
78        list($parentDir) = DAV\URLUtil::splitPath($this->path);
79        return $parentDir . '/.sabredav';
80
81    }
82
83    /**
84     * Returns all the stored resource information
85     *
86     * @return array
87     */
88    protected function getResourceData() {
89
90        $path = $this->getResourceInfoPath();
91        if (!file_exists($path)) return array('properties' => array());
92
93        // opening up the file, and creating a shared lock
94        $handle = fopen($path,'r');
95        flock($handle,LOCK_SH);
96        $data = '';
97
98        // Reading data until the eof
99        while(!feof($handle)) {
100            $data.=fread($handle,8192);
101        }
102
103        // We're all good
104        fclose($handle);
105
106        // Unserializing and checking if the resource file contains data for this file
107        $data = unserialize($data);
108        if (!isset($data[$this->getName()])) {
109            return array('properties' => array());
110        }
111
112        $data = $data[$this->getName()];
113        if (!isset($data['properties'])) $data['properties'] = array();
114        return $data;
115
116    }
117
118    /**
119     * Updates the resource information
120     *
121     * @param array $newData
122     * @return void
123     */
124    protected function putResourceData(array $newData) {
125
126        $path = $this->getResourceInfoPath();
127
128        // opening up the file, and creating a shared lock
129        $handle = fopen($path,'a+');
130        flock($handle,LOCK_EX);
131        $data = '';
132
133        rewind($handle);
134
135        // Reading data until the eof
136        while(!feof($handle)) {
137            $data.=fread($handle,8192);
138        }
139
140        // Unserializing and checking if the resource file contains data for this file
141        $data = unserialize($data);
142        $data[$this->getName()] = $newData;
143        ftruncate($handle,0);
144        rewind($handle);
145
146        fwrite($handle,serialize($data));
147        fclose($handle);
148
149    }
150
151    /**
152     * Renames the node
153     *
154     * @param string $name The new name
155     * @return void
156     */
157    public function setName($name) {
158
159        list($parentPath, ) = DAV\URLUtil::splitPath($this->path);
160        list(, $newName) = DAV\URLUtil::splitPath($name);
161        $newPath = $parentPath . '/' . $newName;
162
163        // We're deleting the existing resourcedata, and recreating it
164        // for the new path.
165        $resourceData = $this->getResourceData();
166        $this->deleteResourceData();
167
168        rename($this->path,$newPath);
169        $this->path = $newPath;
170        $this->putResourceData($resourceData);
171
172
173    }
174
175    /**
176     * @return bool
177     */
178    public function deleteResourceData() {
179
180        // When we're deleting this node, we also need to delete any resource information
181        $path = $this->getResourceInfoPath();
182        if (!file_exists($path)) return true;
183
184        // opening up the file, and creating a shared lock
185        $handle = fopen($path,'a+');
186        flock($handle,LOCK_EX);
187        $data = '';
188
189        rewind($handle);
190
191        // Reading data until the eof
192        while(!feof($handle)) {
193            $data.=fread($handle,8192);
194        }
195
196        // Unserializing and checking if the resource file contains data for this file
197        $data = unserialize($data);
198        if (isset($data[$this->getName()])) unset($data[$this->getName()]);
199        ftruncate($handle,0);
200        rewind($handle);
201        fwrite($handle,serialize($data));
202        fclose($handle);
203
204        return true;
205    }
206
207    public function delete() {
208
209        return $this->deleteResourceData();
210
211    }
212
213}
214
215