Like others have said, there's a bug with \SplTempFileObject
where even if you do pass 0
into the constructor, you still have a file that's in memory and therefore doesn't have a filepath/realpath.
I've built a tiny, simple PHP7+ class for this:
interface TemporaryFile {
public function handle(\Closure $closure) : void;
public function write(string $contents): void;
public function getContents() : string;
public function chmod(int $mode): void;
public function getUri() : string; // aka realpath
public function close() : void;
}
class IO
{
/**
* @return TemporaryFile
*/
public static function getTemporaryFile() : TemporaryFile {
return new class implements TemporaryFile {
private $handle;
public function __construct()
{
$this->handle = tmpfile();
}
public function handle(\Closure $closure) : void {
$closure($this->handle);
}
public function getContents() : string {
// according to PHP docs file_get_contents has much better performance
// http://php.net/manual/en/function.fread.php
return file_get_contents($this->getUri());
}
public function getUri() : string {
return stream_get_meta_data($this->handle)['uri'];
}
public function close() : void {
if (is_resource($this->handle))
fclose($this->handle);
}
public function write(string $contents): void
{
fwrite($this->handle, $contents);
}
public function chmod(int $mode): void
{
chmod($this->getUri(), $mode);
}
public function __destruct() {
$this->close();
}
};
}
}
To use it, just do this:
$file = IO::getTemporaryFile();
$file->write('foo');
var_dump($file->getContents()); // string(3) "foo"
You can see the aforementioned example in a working state here: https://3v4l.org/LYfan#output
And then you have a temporary file that's gonna self the destruct after the process is finished or the class is dereferenced.