MediaWiki 1.43.1
TempFSFile.php
Go to the documentation of this file.
1<?php
2
26
28use RuntimeException;
29use WeakMap;
30use Wikimedia\AtEase\AtEase;
31
38class TempFSFile extends FSFile {
40 protected $canDelete = false;
41
43 protected static $pathsCollect = null;
44
51 private static $references;
52
58 public function __construct( $path ) {
59 parent::__construct( $path );
60
61 if ( self::$pathsCollect === null ) {
62 // @codeCoverageIgnoreStart
63 self::$pathsCollect = [];
64 register_shutdown_function( [ __CLASS__, 'purgeAllOnShutdown' ] );
65 // @codeCoverageIgnoreEnd
66 }
67 }
68
80 public static function factory( $prefix, $extension = '', $tmpDirectory = null ) {
81 return ( new TempFSFileFactory( $tmpDirectory ) )->newTempFSFile( $prefix, $extension );
82 }
83
91 public static function getUsableTempDirectory() {
92 $tmpDir = array_map( 'getenv', [ 'TMPDIR', 'TMP', 'TEMP' ] );
93 $tmpDir[] = sys_get_temp_dir();
94 $tmpDir[] = ini_get( 'upload_tmp_dir' );
95 foreach ( $tmpDir as $tmp ) {
96 if ( $tmp != '' && is_dir( $tmp ) && is_writable( $tmp ) ) {
97 return $tmp;
98 }
99 }
100
101 // PHP on Windows will detect C:\Windows\Temp as not writable even though PHP can write to
102 // it so create a directory within that called 'mwtmp' with a suffix of the user running
103 // the current process.
104 // The user is included as if various scripts are run by different users they will likely
105 // not be able to access each others temporary files.
106 if ( PHP_OS_FAMILY === 'Windows' ) {
107 $tmp = sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'mwtmp-' . get_current_user();
108 if ( !is_dir( $tmp ) ) {
109 mkdir( $tmp );
110 }
111 if ( is_dir( $tmp ) && is_writable( $tmp ) ) {
112 return $tmp;
113 }
114 }
115
116 throw new RuntimeException(
117 'No writable temporary directory could be found. ' .
118 'Please explicitly specify a writable directory in configuration.' );
119 }
120
126 public function purge() {
127 $this->canDelete = false; // done
128 AtEase::suppressWarnings();
129 $ok = unlink( $this->path );
130 AtEase::restoreWarnings();
131
132 unset( self::$pathsCollect[$this->path] );
133
134 return $ok;
135 }
136
143 public function bind( $object ) {
144 if ( is_object( $object ) ) {
145 // Use a WeakMap on PHP >= 8.0 to avoid dynamic property creation (T324894)
146 if ( PHP_VERSION_ID >= 80000 ) {
147 if ( self::$references === null ) {
148 self::$references = new WeakMap;
149 }
150 self::$references[$object] = $this;
151 } else {
152 // PHP 7.4
153 if ( !isset( $object->tempFSFileReferences ) ) {
154 // Init first since $object might use __get() and return only a copy variable
155 $object->tempFSFileReferences = [];
156 }
157 $object->tempFSFileReferences[] = $this;
158 }
159 }
160
161 return $this;
162 }
163
169 public function preserve() {
170 $this->canDelete = false;
171
172 unset( self::$pathsCollect[$this->path] );
173
174 return $this;
175 }
176
182 public function autocollect() {
183 $this->canDelete = true;
184
185 self::$pathsCollect[$this->path] = 1;
186
187 return $this;
188 }
189
197 public static function purgeAllOnShutdown() {
198 foreach ( self::$pathsCollect as $path => $unused ) {
199 AtEase::suppressWarnings();
200 unlink( $path );
201 AtEase::restoreWarnings();
202 }
203 }
204
208 public function __destruct() {
209 if ( $this->canDelete ) {
210 $this->purge();
211 }
212 }
213}
214
216class_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.