1<?php
2
3namespace Sabre\DAV\FSExt;
4
5use Sabre\DAV;
6use Sabre\DAV\FS\Node;
7
8/**
9 * Directory class
10 *
11 * @copyright Copyright (C) fruux GmbH (https://fruux.com/)
12 * @author Evert Pot (http://evertpot.com/)
13 * @license http://sabre.io/license/ Modified BSD License
14 */
15class Directory extends Node implements DAV\ICollection, DAV\IQuota, DAV\IMoveTarget {
16
17    /**
18     * Creates a new file in the directory
19     *
20     * Data will either be supplied as a stream resource, or in certain cases
21     * as a string. Keep in mind that you may have to support either.
22     *
23     * After successful creation of the file, you may choose to return the ETag
24     * of the new file here.
25     *
26     * The returned ETag must be surrounded by double-quotes (The quotes should
27     * be part of the actual string).
28     *
29     * If you cannot accurately determine the ETag, you should not return it.
30     * If you don't store the file exactly as-is (you're transforming it
31     * somehow) you should also not return an ETag.
32     *
33     * This means that if a subsequent GET to this new file does not exactly
34     * return the same contents of what was submitted here, you are strongly
35     * recommended to omit the ETag.
36     *
37     * @param string $name Name of the file
38     * @param resource|string $data Initial payload
39     * @return null|string
40     */
41    function createFile($name, $data = null) {
42
43        // We're not allowing dots
44        if ($name == '.' || $name == '..') throw new DAV\Exception\Forbidden('Permission denied to . and ..');
45        $newPath = $this->path . '/' . $name;
46        file_put_contents($newPath, $data);
47        clearstatcache(true, $newPath);
48
49        return '"' . sha1(
50            fileinode($newPath) .
51            filesize($newPath) .
52            filemtime($newPath)
53        ) . '"';
54
55    }
56
57    /**
58     * Creates a new subdirectory
59     *
60     * @param string $name
61     * @return void
62     */
63    function createDirectory($name) {
64
65        // We're not allowing dots
66        if ($name == '.' || $name == '..') throw new DAV\Exception\Forbidden('Permission denied to . and ..');
67        $newPath = $this->path . '/' . $name;
68        mkdir($newPath);
69        clearstatcache(true, $newPath);
70
71    }
72
73    /**
74     * Returns a specific child node, referenced by its name
75     *
76     * This method must throw Sabre\DAV\Exception\NotFound if the node does not
77     * exist.
78     *
79     * @param string $name
80     * @throws DAV\Exception\NotFound
81     * @return DAV\INode
82     */
83    function getChild($name) {
84
85        $path = $this->path . '/' . $name;
86
87        if (!file_exists($path)) throw new DAV\Exception\NotFound('File could not be located');
88        if ($name == '.' || $name == '..') throw new DAV\Exception\Forbidden('Permission denied to . and ..');
89
90        if (is_dir($path)) {
91
92            return new self($path);
93
94        } else {
95
96            return new File($path);
97
98        }
99
100    }
101
102    /**
103     * Checks if a child exists.
104     *
105     * @param string $name
106     * @return bool
107     */
108    function childExists($name) {
109
110        if ($name == '.' || $name == '..')
111            throw new DAV\Exception\Forbidden('Permission denied to . and ..');
112
113        $path = $this->path . '/' . $name;
114        return file_exists($path);
115
116    }
117
118    /**
119     * Returns an array with all the child nodes
120     *
121     * @return DAV\INode[]
122     */
123    function getChildren() {
124
125        $nodes = [];
126        $iterator = new \FilesystemIterator(
127            $this->path,
128            \FilesystemIterator::CURRENT_AS_SELF
129          | \FilesystemIterator::SKIP_DOTS
130        );
131
132        foreach ($iterator as $entry) {
133
134            $nodes[] = $this->getChild($entry->getFilename());
135
136        }
137        return $nodes;
138
139    }
140
141    /**
142     * Deletes all files in this directory, and then itself
143     *
144     * @return bool
145     */
146    function delete() {
147
148        // Deleting all children
149        foreach ($this->getChildren() as $child) $child->delete();
150
151        // Removing the directory itself
152        rmdir($this->path);
153
154        return true;
155
156    }
157
158    /**
159     * Returns available diskspace information
160     *
161     * @return array
162     */
163    function getQuotaInfo() {
164
165        $total = disk_total_space(realpath($this->path));
166        $free = disk_free_space(realpath($this->path));
167
168        return [
169            $total - $free,
170            $free
171        ];
172    }
173
174    /**
175     * Moves a node into this collection.
176     *
177     * It is up to the implementors to:
178     *   1. Create the new resource.
179     *   2. Remove the old resource.
180     *   3. Transfer any properties or other data.
181     *
182     * Generally you should make very sure that your collection can easily move
183     * the move.
184     *
185     * If you don't, just return false, which will trigger sabre/dav to handle
186     * the move itself. If you return true from this function, the assumption
187     * is that the move was successful.
188     *
189     * @param string $targetName New local file/collection name.
190     * @param string $sourcePath Full path to source node
191     * @param DAV\INode $sourceNode Source node itself
192     * @return bool
193     */
194    function moveInto($targetName, $sourcePath, DAV\INode $sourceNode) {
195
196        // We only support FSExt\Directory or FSExt\File objects, so
197        // anything else we want to quickly reject.
198        if (!$sourceNode instanceof self && !$sourceNode instanceof File) {
199            return false;
200        }
201
202        // PHP allows us to access protected properties from other objects, as
203        // long as they are defined in a class that has a shared inheritence
204        // with the current class.
205        rename($sourceNode->path, $this->path . '/' . $targetName);
206
207        return true;
208
209    }
210
211}
212