MediaWiki master
TempFSFile.php
Go to the documentation of this file.
1<?php
2
26
27use RuntimeException;
28use WeakMap;
29use Wikimedia\AtEase\AtEase;
30
37class TempFSFile extends FSFile {
39 protected $canDelete = false;
40
42 protected static $pathsCollect = null;
43
50 private static $references;
51
57 public function __construct( $path ) {
58 parent::__construct( $path );
59
60 if ( self::$pathsCollect === null ) {
61 // @codeCoverageIgnoreStart
62 self::$pathsCollect = [];
63 register_shutdown_function( [ __CLASS__, 'purgeAllOnShutdown' ] );
64 // @codeCoverageIgnoreEnd
65 }
66 }
67
79 public static function factory( $prefix, $extension = '', $tmpDirectory = null ) {
80 return ( new TempFSFileFactory( $tmpDirectory ) )->newTempFSFile( $prefix, $extension );
81 }
82
90 public static function getUsableTempDirectory() {
91 $tmpDir = array_map( 'getenv', [ 'TMPDIR', 'TMP', 'TEMP' ] );
92 $tmpDir[] = sys_get_temp_dir();
93 $tmpDir[] = ini_get( 'upload_tmp_dir' );
94 foreach ( $tmpDir as $tmp ) {
95 if ( $tmp != '' && is_dir( $tmp ) && is_writable( $tmp ) ) {
96 return $tmp;
97 }
98 }
99
100 // PHP on Windows will detect C:\Windows\Temp as not writable even though PHP can write to
101 // it so create a directory within that called 'mwtmp' with a suffix of the user running
102 // the current process.
103 // The user is included as if various scripts are run by different users they will likely
104 // not be able to access each others temporary files.
105 if ( PHP_OS_FAMILY === 'Windows' ) {
106 $tmp = sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'mwtmp-' . get_current_user();
107 if ( !is_dir( $tmp ) ) {
108 mkdir( $tmp );
109 }
110 if ( is_dir( $tmp ) && is_writable( $tmp ) ) {
111 return $tmp;
112 }
113 }
114
115 throw new RuntimeException(
116 'No writable temporary directory could be found. ' .
117 'Please explicitly specify a writable directory in configuration.' );
118 }
119
125 public function purge() {
126 $this->canDelete = false; // done
127 AtEase::suppressWarnings();
128 $ok = unlink( $this->path );
129 AtEase::restoreWarnings();
130
131 unset( self::$pathsCollect[$this->path] );
132
133 return $ok;
134 }
135
142 public function bind( $object ) {
143 if ( is_object( $object ) ) {
144 // Use a WeakMap on PHP >= 8.0 to avoid dynamic property creation (T324894)
145 if ( PHP_VERSION_ID >= 80000 ) {
146 if ( self::$references === null ) {
147 self::$references = new WeakMap;
148 }
149 self::$references[$object] = $this;
150 } else {
151 // PHP 7.4
152 if ( !isset( $object->tempFSFileReferences ) ) {
153 // Init first since $object might use __get() and return only a copy variable
154 $object->tempFSFileReferences = [];
155 }
156 $object->tempFSFileReferences[] = $this;
157 }
158 }
159
160 return $this;
161 }
162
168 public function preserve() {
169 $this->canDelete = false;
170
171 unset( self::$pathsCollect[$this->path] );
172
173 return $this;
174 }
175
181 public function autocollect() {
182 $this->canDelete = true;
183
184 self::$pathsCollect[$this->path] = 1;
185
186 return $this;
187 }
188
196 public static function purgeAllOnShutdown() {
197 foreach ( self::$pathsCollect as $path => $unused ) {
198 AtEase::suppressWarnings();
199 unlink( $path );
200 AtEase::restoreWarnings();
201 }
202 }
203
207 public function __destruct() {
208 if ( $this->canDelete ) {
209 $this->purge();
210 }
211 }
212}
213
215class_alias( TempFSFile::class, 'TempFSFile' );
Class representing a non-directory file on the file system.
Definition FSFile.php:34
string $path
Path to file.
Definition FSFile.php:36
This class is used to hold the location and do limited manipulation of files stored temporarily (this...
purge()
Purge this file off the file system.
bool $canDelete
Garbage collect the temp file.
__construct( $path)
Do not call directly.
autocollect()
Set flag clean up after the temporary file.
__destruct()
Cleans up after the temporary file by deleting it.
static factory( $prefix, $extension='', $tmpDirectory=null)
Make a new temporary file on the file system.
static purgeAllOnShutdown()
Try to make sure that all files are purged on error.
static array $pathsCollect
Map of (path => 1) for paths to delete on shutdown.
bind( $object)
Clean up the temporary file only after an object goes out of scope.
preserve()
Set flag to not clean up after the temporary file.