1<?php 2 3/** 4 * Simple wrapper to create a temporary file and guarantee it will be deleted on 5 * object destruction. Used like a string to path: 6 * 7 * $temp = new TempFile(); 8 * Filesystem::writeFile($temp, 'Hello World'); 9 * echo "Wrote data to path: ".$temp; 10 * 11 * Throws Filesystem exceptions for errors. 12 * 13 * @task create Creating a Temporary File 14 * @task config Configuration 15 * @task internal Internals 16 */ 17final class TempFile extends Phobject { 18 19 private $dir; 20 private $file; 21 private $preserve; 22 private $destroyed = false; 23 24/* -( Creating a Temporary File )------------------------------------------ */ 25 26 27 /** 28 * Create a new temporary file. 29 * 30 * @param string? Filename hint. This is useful if you intend to edit the 31 * file with an interactive editor, so the user's editor shows 32 * "commit-message" instead of "p3810hf-1z9b89bas". 33 * @param string? Root directory to hold the file. If omitted, the system 34 * temporary directory (often "/tmp") will be used by default. 35 * @task create 36 */ 37 public function __construct($filename = null, $root_directory = null) { 38 $this->dir = Filesystem::createTemporaryDirectory( 39 '', 40 0700, 41 $root_directory); 42 if ($filename === null) { 43 $this->file = tempnam($this->dir, getmypid().'-'); 44 } else { 45 $this->file = $this->dir.'/'.$filename; 46 } 47 48 // If we fatal (e.g., call a method on NULL), destructors are not called. 49 // Make sure our destructor is invoked. 50 register_shutdown_function(array($this, '__destruct')); 51 52 Filesystem::writeFile($this, ''); 53 } 54 55 56/* -( Configuration )------------------------------------------------------ */ 57 58 59 /** 60 * Normally, the file is deleted when this object passes out of scope. You 61 * can set it to be preserved instead. 62 * 63 * @param bool True to preserve the file after object destruction. 64 * @return this 65 * @task config 66 */ 67 public function setPreserveFile($preserve) { 68 $this->preserve = $preserve; 69 return $this; 70 } 71 72 73/* -( Internals )---------------------------------------------------------- */ 74 75 76 /** 77 * Get the path to the temporary file. Normally you can just use the object 78 * in a string context. 79 * 80 * @return string Absolute path to the temporary file. 81 * @task internal 82 */ 83 public function __toString() { 84 return $this->file; 85 } 86 87 88 /** 89 * When the object is destroyed, it destroys the temporary file. You can 90 * change this behavior with @{method:setPreserveFile}. 91 * 92 * @task internal 93 */ 94 public function __destruct() { 95 if ($this->destroyed) { 96 return; 97 } 98 99 if ($this->preserve) { 100 return; 101 } 102 103 Filesystem::remove($this->dir); 104 105 // NOTE: tempnam() doesn't guarantee it will return a file inside the 106 // directory you passed to the function, so we make sure to nuke the file 107 // explicitly. 108 109 Filesystem::remove($this->file); 110 111 $this->file = null; 112 $this->dir = null; 113 $this->destroyed = true; 114 } 115 116} 117