├── src ├── Exceptions │ ├── PathAlreadyExists.php │ └── InvalidDirectoryName.php └── TemporaryDirectory.php ├── LICENSE.md ├── composer.json └── README.md /src/Exceptions/PathAlreadyExists.php: -------------------------------------------------------------------------------- 1 | 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "spatie/temporary-directory", 3 | "description": "Easily create, use and destroy temporary directories", 4 | "license": "MIT", 5 | "keywords": [ 6 | "spatie", 7 | "php", 8 | "temporary-directory" 9 | ], 10 | "authors": [ 11 | { 12 | "name": "Alex Vanderbist", 13 | "email": "alex@spatie.be", 14 | "homepage": "https://spatie.be", 15 | "role": "Developer" 16 | } 17 | ], 18 | "homepage": "https://github.com/spatie/temporary-directory", 19 | "require": { 20 | "php": "^8.0" 21 | }, 22 | "require-dev": { 23 | "phpunit/phpunit": "^9.5" 24 | }, 25 | "minimum-stability": "dev", 26 | "prefer-stable": true, 27 | "autoload": { 28 | "psr-4": { 29 | "Spatie\\TemporaryDirectory\\": "src" 30 | } 31 | }, 32 | "autoload-dev": { 33 | "psr-4": { 34 | "Spatie\\TemporaryDirectory\\Test\\": "tests" 35 | } 36 | }, 37 | "config": { 38 | "sort-packages": true 39 | }, 40 | "scripts": { 41 | "test": "vendor/bin/phpunit", 42 | "test-coverage": "vendor/bin/phpunit --coverage-html coverage" 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/TemporaryDirectory.php: -------------------------------------------------------------------------------- 1 | location = $this->sanitizePath($location); 23 | } 24 | 25 | public static function make(string $location = ''): self 26 | { 27 | return (new self($location))->create(); 28 | } 29 | 30 | public function create(): self 31 | { 32 | if (empty($this->location)) { 33 | $this->location = $this->getSystemTemporaryDirectory(); 34 | } 35 | 36 | if (empty($this->name)) { 37 | $this->name = mt_rand().'-'.str_replace([' ', '.'], '', microtime()); 38 | } 39 | 40 | if ($this->forceCreate && file_exists($this->getFullPath())) { 41 | $this->deleteDirectory($this->getFullPath()); 42 | } 43 | 44 | if ($this->exists()) { 45 | throw PathAlreadyExists::create($this->getFullPath()); 46 | } 47 | 48 | mkdir($this->getFullPath(), 0777, true); 49 | 50 | return $this; 51 | } 52 | 53 | public function force(): self 54 | { 55 | $this->forceCreate = true; 56 | 57 | return $this; 58 | } 59 | 60 | public function name(string $name): self 61 | { 62 | $this->name = $this->sanitizeName($name); 63 | 64 | return $this; 65 | } 66 | 67 | public function location(string $location): self 68 | { 69 | $this->location = $this->sanitizePath($location); 70 | 71 | return $this; 72 | } 73 | 74 | public function path(string $pathOrFilename = ''): string 75 | { 76 | if (empty($pathOrFilename)) { 77 | return $this->getFullPath(); 78 | } 79 | 80 | $path = $this->getFullPath().DIRECTORY_SEPARATOR.trim($pathOrFilename, '/'); 81 | 82 | $directoryPath = $this->removeFilenameFromPath($path); 83 | 84 | if (! file_exists($directoryPath)) { 85 | mkdir($directoryPath, 0777, true); 86 | } 87 | 88 | return $path; 89 | } 90 | 91 | public function empty(): self 92 | { 93 | $this->deleteDirectory($this->getFullPath()); 94 | 95 | mkdir($this->getFullPath(), 0777, true); 96 | 97 | return $this; 98 | } 99 | 100 | public function delete(): bool 101 | { 102 | return $this->deleteDirectory($this->getFullPath()); 103 | } 104 | 105 | public function exists(): bool 106 | { 107 | return file_exists($this->getFullPath()); 108 | } 109 | 110 | public function getName(): string 111 | { 112 | return $this->name; 113 | } 114 | 115 | protected function getFullPath(): string 116 | { 117 | return $this->location.(! empty($this->name) ? DIRECTORY_SEPARATOR.$this->name : ''); 118 | } 119 | 120 | protected function isValidDirectoryName(string $directoryName): bool 121 | { 122 | return strpbrk($directoryName, '\\/?%*:|"<>') === false; 123 | } 124 | 125 | protected function getSystemTemporaryDirectory(): string 126 | { 127 | return rtrim(sys_get_temp_dir(), DIRECTORY_SEPARATOR); 128 | } 129 | 130 | protected function sanitizePath(string $path): string 131 | { 132 | $path = rtrim($path); 133 | 134 | return rtrim($path, DIRECTORY_SEPARATOR); 135 | } 136 | 137 | protected function sanitizeName(string $name): string 138 | { 139 | if (! $this->isValidDirectoryName($name)) { 140 | throw InvalidDirectoryName::create($name); 141 | } 142 | 143 | return trim($name); 144 | } 145 | 146 | protected function removeFilenameFromPath(string $path): string 147 | { 148 | if (! $this->isFilePath($path)) { 149 | return $path; 150 | } 151 | 152 | return substr($path, 0, strrpos($path, DIRECTORY_SEPARATOR)); 153 | } 154 | 155 | protected function isFilePath(string $path): bool 156 | { 157 | return str_contains($path, '.'); 158 | } 159 | 160 | protected function deleteDirectory(string $path): bool 161 | { 162 | try { 163 | if (is_link($path)) { 164 | return unlink($path); 165 | } 166 | 167 | if (! file_exists($path)) { 168 | return true; 169 | } 170 | 171 | if (! is_dir($path)) { 172 | return unlink($path); 173 | } 174 | 175 | foreach (new FilesystemIterator($path) as $item) { 176 | if (! $this->deleteDirectory((string) $item)) { 177 | return false; 178 | } 179 | } 180 | 181 | /* 182 | * By forcing a php garbage collection cycle using gc_collect_cycles() we can ensure 183 | * that the rmdir does not fail due to files still being reserved in memory. 184 | */ 185 | gc_collect_cycles(); 186 | 187 | return rmdir($path); 188 | } catch (Throwable) { 189 | return false; 190 | } 191 | } 192 | 193 | public function deleteWhenDestroyed(bool $deleteWhenDestroyed = true): self 194 | { 195 | $this->deleteWhenDestroyed = $deleteWhenDestroyed; 196 | 197 | return $this; 198 | } 199 | 200 | public function __destruct() 201 | { 202 | if ($this->deleteWhenDestroyed) { 203 | $this->delete(); 204 | } 205 | } 206 | } 207 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Quickly create, use and delete temporary directories 2 | 3 | [![Latest Version on Packagist](https://img.shields.io/packagist/v/spatie/temporary-directory.svg?style=flat-square)](https://packagist.org/packages/spatie/temporary-directory) 4 | ![Tests](https://github.com/spatie/temporary-directory/workflows/run-tests/badge.svg?label=tests) 5 | [![Software License](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square)](LICENSE.md) 6 | [![Total Downloads](https://img.shields.io/packagist/dt/spatie/temporary-directory.svg?style=flat-square)](https://packagist.org/packages/spatie/temporary-directory) 7 | 8 | This package allows you to quickly create, use and delete a temporary directory in the system's temporary directory. 9 | 10 | Here's a quick example on how to create a temporary directory and delete it: 11 | 12 | ```php 13 | use Spatie\TemporaryDirectory\TemporaryDirectory; 14 | 15 | $temporaryDirectory = (new TemporaryDirectory())->create(); 16 | 17 | // Get a path inside the temporary directory 18 | $temporaryDirectory->path('temporaryfile.txt'); 19 | 20 | // Delete the temporary directory and all the files inside it 21 | $temporaryDirectory->delete(); 22 | ``` 23 | 24 | ## Support us 25 | 26 | [](https://spatie.be/github-ad-click/temporary-directory) 27 | 28 | We invest a lot of resources into creating [best in class open source packages](https://spatie.be/open-source). You can support us by [buying one of our paid products](https://spatie.be/open-source/support-us). 29 | 30 | We highly appreciate you sending us a postcard from your hometown, mentioning which of our package(s) you are using. You'll find our address on [our contact page](https://spatie.be/about-us). We publish all received postcards on [our virtual postcard wall](https://spatie.be/open-source/postcards). 31 | 32 | ## Installation 33 | 34 | You can install the package via composer: 35 | 36 | ```bash 37 | composer require spatie/temporary-directory 38 | ``` 39 | 40 | ## Usage 41 | 42 | ### Creating a temporary directory 43 | 44 | To create a temporary directory simply call the `create` method on a `TemporaryDirectory` object. 45 | 46 | ```php 47 | (new TemporaryDirectory())->create(); 48 | ``` 49 | 50 | Alternatively, use the static `make` method on a `TemporaryDirectory` object. 51 | 52 | ```php 53 | TemporaryDirectory::make(); 54 | ``` 55 | 56 | By default, the temporary directory will be created in a timestamped directory in your system's temporary directory (usually `/tmp`). 57 | 58 | ### Naming your temporary directory 59 | 60 | If you want to use a custom name for your temporary directory instead of the timestamp call the `name` method with a string `$name` argument before the `create` method. 61 | 62 | ```php 63 | (new TemporaryDirectory()) 64 | ->name($name) 65 | ->create(); 66 | ``` 67 | 68 | By default an exception will be thrown if a directory already exists with the given argument. You can override this behaviour by calling the `force` method in combination with the `name` method. 69 | 70 | ```php 71 | (new TemporaryDirectory()) 72 | ->name($name) 73 | ->force() 74 | ->create(); 75 | ``` 76 | 77 | ### Setting a custom location for a temporary directory 78 | 79 | You can set a custom location in which your temporary directory will be created by passing a string `$location` argument to the `TemporaryDirectory` constructor. 80 | 81 | ```php 82 | (new TemporaryDirectory($location)) 83 | ->create(); 84 | ``` 85 | 86 | The `make` method also accepts a `$location` argument. 87 | 88 | ```php 89 | TemporaryDirectory::make($location); 90 | ``` 91 | 92 | Finally, you can call the `location` method with a `$location` argument. 93 | 94 | ```php 95 | (new TemporaryDirectory()) 96 | ->location($location) 97 | ->create(); 98 | ``` 99 | 100 | ### Determining paths within the temporary directory 101 | 102 | You can use the `path` method to determine the full path to a file or directory in the temporary directory: 103 | 104 | ```php 105 | $temporaryDirectory = (new TemporaryDirectory())->create(); 106 | $temporaryDirectory->path('dumps/datadump.dat'); // return /tmp/1485941876276/dumps/datadump.dat 107 | ``` 108 | 109 | ### Emptying a temporary directory 110 | 111 | Use the `empty` method to delete all the files inside the temporary directory. 112 | 113 | ```php 114 | $temporaryDirectory->empty(); 115 | ``` 116 | 117 | ### Deleting a temporary directory 118 | 119 | Once you're done processing your temporary data you can delete the entire temporary directory using the `delete` method. All files inside of it will be deleted. 120 | 121 | ```php 122 | $temporaryDirectory->delete(); 123 | ``` 124 | 125 | ### Deleting a temporary directory when the object is destroyed 126 | 127 | If you want to automatically have the filesystem directory deleted when the object instance has no more references in 128 | its defined scope, you can enable `deleteWhenDestroyed()` on the TemporaryDirectory object. 129 | 130 | ```php 131 | function handleTemporaryFiles() 132 | { 133 | $temporaryDirectory = (new TemporaryDirectory()) 134 | ->deleteWhenDestroyed() 135 | ->create(); 136 | 137 | // ... use the temporary directory 138 | 139 | return; // no need to manually call $temporaryDirectory->delete()! 140 | } 141 | 142 | handleTemporaryFiles(); 143 | ``` 144 | 145 | You can also call `unset()` on an object instance. 146 | 147 | ## Testing 148 | 149 | ```bash 150 | composer test 151 | ``` 152 | 153 | ## Changelog 154 | 155 | Please see [CHANGELOG](CHANGELOG.md) for more information on what has changed recently. 156 | 157 | ## Contributing 158 | 159 | Please see [CONTRIBUTING](https://github.com/spatie/.github/blob/main/CONTRIBUTING.md) for details. 160 | 161 | ## Security Vulnerabilities 162 | 163 | Please review [our security policy](../../security/policy) on how to report security vulnerabilities. 164 | 165 | ## Postcardware 166 | 167 | You're free to use this package, but if it makes it to your production environment we highly appreciate you sending us a postcard from your hometown, mentioning which of our package(s) you are using. 168 | 169 | Our address is: Spatie, Kruikstraat 22, 2018 Antwerp, Belgium. 170 | 171 | We publish all received postcards [on our company website](https://spatie.be/en/opensource/postcards). 172 | 173 | ## Credits 174 | 175 | - [Alex Vanderbist](https://github.com/AlexVanderbist) 176 | - [All Contributors](../../contributors) 177 | 178 | ## License 179 | 180 | The MIT License (MIT). Please see [License File](LICENSE.md) for more information. 181 | --------------------------------------------------------------------------------