1) for paths to delete on shutdown */ protected static $pathsCollect = null; public function __construct( $path ) { parent::__construct( $path ); if ( self::$pathsCollect === null ) { self::$pathsCollect = array(); register_shutdown_function( array( __CLASS__, 'purgeAllOnShutdown' ) ); } } /** * Make a new temporary file on the file system. * Temporary files may be purged when the file object falls out of scope. * * @param string $prefix * @param string $extension * @return TempFSFile|null */ public static function factory( $prefix, $extension = '' ) { $base = wfTempDir() . '/' . $prefix . wfRandomString( 12 ); $ext = ( $extension != '' ) ? ".{$extension}" : ""; for ( $attempt = 1; true; $attempt++ ) { $path = "{$base}-{$attempt}{$ext}"; MediaWiki\suppressWarnings(); $newFileHandle = fopen( $path, 'x' ); MediaWiki\restoreWarnings(); if ( $newFileHandle ) { fclose( $newFileHandle ); break; // got it } if ( $attempt >= 5 ) { return null; // give up } } $tmpFile = new self( $path ); $tmpFile->autocollect(); // safely instantiated return $tmpFile; } /** * Purge this file off the file system * * @return bool Success */ public function purge() { $this->canDelete = false; // done MediaWiki\suppressWarnings(); $ok = unlink( $this->path ); MediaWiki\restoreWarnings(); unset( self::$pathsCollect[$this->path] ); return $ok; } /** * Clean up the temporary file only after an object goes out of scope * * @param object $object * @return TempFSFile This object */ public function bind( $object ) { if ( is_object( $object ) ) { if ( !isset( $object->tempFSFileReferences ) ) { // Init first since $object might use __get() and return only a copy variable $object->tempFSFileReferences = array(); } $object->tempFSFileReferences[] = $this; } return $this; } /** * Set flag to not clean up after the temporary file * * @return TempFSFile This object */ public function preserve() { $this->canDelete = false; unset( self::$pathsCollect[$this->path] ); return $this; } /** * Set flag clean up after the temporary file * * @return TempFSFile This object */ public function autocollect() { $this->canDelete = true; self::$pathsCollect[$this->path] = 1; return $this; } /** * Try to make sure that all files are purged on error * * This method should only be called internally */ public static function purgeAllOnShutdown() { foreach ( self::$pathsCollect as $path ) { MediaWiki\suppressWarnings(); unlink( $path ); MediaWiki\restoreWarnings(); } } /** * Cleans up after the temporary file by deleting it */ function __destruct() { if ( $this->canDelete ) { $this->purge(); } } }