Skip to content

Instantly share code, notes, and snippets.

@beregond
Created July 14, 2012 12:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save beregond/3110928 to your computer and use it in GitHub Desktop.
Save beregond/3110928 to your computer and use it in GitHub Desktop.
Classes to help handle temporary files (also creation of such, but also 'checking' files to be removed after scripts end).
<?php
/**
* File contains two classes to help maintaining temporary files (especially problem of
* cleaning up such files) - FileToRemove and TemporaryFile.
*
* Requires PHP >= 5.3.0 (tested with 5.3.10-1)
*/
namespace Vendorname;
/**
* Class to help maintaining temporary files.
*
* Very important part of this class is stack, that keeps reference of ALL
* temporary files. It also gives possibilities to manipulate the objects, but the main
* reason is to keep references to them. Otherwise PHPs garbage collector sometimes would
* delete objects the moment they are created (and we don't want this - we want file
* to be removed at the end of script execution).
*
* Usage:
* $filename = (...); //Path to file, that has to be removed.
* $file = new FileToRemove($filename);
* //Or you can forget about references, file won't disappear before the very end.
* new FileToRemove($filename2);
*
* Warning: There is no check if file is indeed deleteable.
*
* @class FileToRemove
*/
class FileToRemove
{
/**
* Path to attached file.
*
* @var string
*/
protected $filename;
/**
* Stack to keep references to objects.
*
* @var array
*/
protected static $stack = array();
/**
* Constructor.
*
* @param string|array $filename path (or array of paths) to file(s)
* @return null
*/
public function __construct($filename)
{
if (is_file($filename)) {
$this->filename = $filename;
self::addToStack($this);
}
}
/**
* Gets filename.
*
* @return string
*/
public function getFilename()
{
return $this->filename;
}
/**
* Cancels file removal.
*
* @return null
*/
public function cancel()
{
$this->filename = null;
self::removeFromStack($this);
}
/**
* Force call for removal.
*
* @return null
*/
public function remove()
{
$this->__destruct();
$this->cancel();
}
/**
* Destructor. File is removed.
*
* @return null
*/
public function __destruct()
{
if ($this->filename) {
@unlink($this->filename);
}
}
/**
* Adds file to stack.
*
* @param FileToRemove $file
* @return null
*/
protected static function addToStack(self $file)
{
static::$stack[] = $file;
}
/**
* Removes file from stack.
*
* @param FileToRemove $file
* @return null
*/
protected function removeFromStack(self $file)
{
$stack = &static::$stack;
foreach ($stack as $key => $item) {
if ($item === $file) {
unset($stack[$key]);
}
}
}
/**
* Returns array of assigned files.
*
* @return array
*/
public static function getFiles()
{
return static::$stack;
}
/**
* Allows to create many instances of a class in one call.
*
* @param string|array filename or array of filenames
* @return array
*/
public static function factory($tab)
{
if (!is_array($tab)) {
$tab = array($tab);
}
$result = array();
foreach ($tab as $item) {
if ($file = new self($item) and $file->getFilename()) {
$result[] = $file;
}
}
return $result;
}
}
/**
* Extension of FileToRemove. It beheves like FileToRemove, but also creates
* temporary file.
*
* File will be removed after script end.
*
* Usage:
* $file = new TemporaryFile();
* $h = fopen($file->getFilename());
* //(...)
* //More often reference isn't needed, so you can perform static call to get path only.
* $h = fopen(TemporaryFile::path()); //It creates new unique file and return its path.
*
* @class TemporaryFile
*/
class TemporaryFile extends FileToRemove
{
/**
* Prefix for new temporary files.
*
* @const string
*/
const TEMPNAME_PREFIX = 'tmp';
/**
* Stack to keep references to objects.
*
* This parameter MUST be redeclared, so 'late state binding' would affect,
* (so class has its own 'stack' to keep files references).
*
* @var array
*/
protected static $stack = array();
/**
* Constructor.
*
* Creates new temporary file, and all pass its name to parent constructor.
*
* @return null
*/
public function __construct()
{
$file = tempnam(realpath(sys_get_temp_dir()), self::TEMPNAME_PREFIX);
parent::__construct($file);
}
/**
* Returns array with given amount of temporary files.
*
* It's also implemented again because parent implementation
* is nonsense in this context.
*
* @param int $amount
* @return array
*/
public static function factory($amount)
{
$amount = (int) $amount;
$result = array();
for ($x = 0; $x < $amount; $x++) {
$result[] = new self();
}
return $result;
}
/**
* Creates new, unique temporary file and return its path.
*
* It shortcut, usually all you want is just path, you don't
* need to keep reference to object.
*
* @return string
*/
public static function path()
{
$file = new self();
return $file->getFilename();
}
}
?>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment