TemporaryDirectory::location()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 6
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 1
1
<?php
2
3
namespace Spatie\TemporaryDirectory;
4
5
use Exception;
6
use FilesystemIterator;
7
use InvalidArgumentException;
8
9
class TemporaryDirectory
10
{
11
    /** @var string */
12
    protected $location;
13
14
    /** @var string */
15
    protected $name;
16
17
    /** @var bool */
18
    protected $forceCreate = false;
19
20
    public function __construct(string $location = '')
21
    {
22
        $this->location = $this->sanitizePath($location);
23
    }
24
25
    public function create(): self
26
    {
27
        if (empty($this->location)) {
28
            $this->location = $this->getSystemTemporaryDirectory();
29
        }
30
31
        if (empty($this->name)) {
32
            $this->name = mt_rand().'-'.str_replace([' ', '.'], '', microtime());
33
        }
34
35
        if ($this->forceCreate && file_exists($this->getFullPath())) {
36
            $this->deleteDirectory($this->getFullPath());
37
        }
38
39
        if (file_exists($this->getFullPath())) {
40
            throw new InvalidArgumentException("Path `{$this->getFullPath()}` already exists.");
41
        }
42
43
        mkdir($this->getFullPath(), 0777, true);
44
45
        return $this;
46
    }
47
48
    public function force(): self
49
    {
50
        $this->forceCreate = true;
51
52
        return $this;
53
    }
54
55
    public function name(string $name): self
56
    {
57
        $this->name = $this->sanitizeName($name);
58
59
        return $this;
60
    }
61
62
    public function location(string $location): self
63
    {
64
        $this->location = $this->sanitizePath($location);
65
66
        return $this;
67
    }
68
69
    public function path(string $pathOrFilename = ''): string
70
    {
71
        if (empty($pathOrFilename)) {
72
            return $this->getFullPath();
73
        }
74
75
        $path = $this->getFullPath().DIRECTORY_SEPARATOR.trim($pathOrFilename, '/');
76
77
        $directoryPath = $this->removeFilenameFromPath($path);
78
79
        if (! file_exists($directoryPath)) {
80
            mkdir($directoryPath, 0777, true);
81
        }
82
83
        return $path;
84
    }
85
86
    public function empty(): self
87
    {
88
        $this->deleteDirectory($this->getFullPath());
89
        mkdir($this->getFullPath(), 0777, true);
90
91
        return $this;
92
    }
93
94
    public function delete(): bool
95
    {
96
        return $this->deleteDirectory($this->getFullPath());
97
    }
98
99
    protected function getFullPath(): string
100
    {
101
        return $this->location.($this->name ? DIRECTORY_SEPARATOR.$this->name : '');
102
    }
103
104
    protected function isValidDirectoryName(string $directoryName): bool
105
    {
106
        return strpbrk($directoryName, '\\/?%*:|"<>') === false;
107
    }
108
109
    protected function getSystemTemporaryDirectory(): string
110
    {
111
        return rtrim(sys_get_temp_dir(), DIRECTORY_SEPARATOR);
112
    }
113
114
    protected function sanitizePath(string $path): string
115
    {
116
        $path = rtrim($path);
117
118
        return rtrim($path, DIRECTORY_SEPARATOR);
119
    }
120
121
    protected function sanitizeName(string $name): string
122
    {
123
        if (! $this->isValidDirectoryName($name)) {
124
            throw new Exception("The directory name `$name` contains invalid characters.");
125
        }
126
127
        return trim($name);
128
    }
129
130
    protected function removeFilenameFromPath(string $path): string
131
    {
132
        if (! $this->isFilePath($path)) {
133
            return $path;
134
        }
135
136
        return substr($path, 0, strrpos($path, DIRECTORY_SEPARATOR));
137
    }
138
139
    protected function isFilePath(string $path): bool
140
    {
141
        return strpos($path, '.') !== false;
142
    }
143
144
    protected function deleteDirectory(string $path): bool
145
    {
146
        if (is_link($path)) {
147
            return unlink($path);
148
        }
149
150
        if (! file_exists($path)) {
151
            return true;
152
        }
153
154
        if (! is_dir($path)) {
155
            return unlink($path);
156
        }
157
158
        foreach (new FilesystemIterator($path) as $item) {
159
            if (! $this->deleteDirectory($item)) {
160
                return false;
161
            }
162
        }
163
164
        /*
165
         * By forcing a php garbage collection cycle using gc_collect_cycles() we can ensure
166
         * that the rmdir does not fail due to files still being reserved in memory.
167
         */
168
        gc_collect_cycles();
169
170
        return rmdir($path);
171
    }
172
}
173