-
Notifications
You must be signed in to change notification settings - Fork 16
/
Copy pathFile.php
210 lines (188 loc) · 6.48 KB
/
File.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
<?php
namespace mikehaertl\tmp;
/**
* File
*
* A convenience class for temporary files.
*
* @author Michael Härtl <haertl.mike@gmail.com>
* @license http://www.opensource.org/licenses/MIT
*/
class File
{
const DEFAULT_CONTENT_TYPE = 'application/octet-stream';
/**
* @var bool whether to delete the tmp file when it's no longer referenced
* or when the request ends. Default is `true`.
*/
public $delete = true;
/**
* @var bool whether to ignore if a user closed the connection so that the
* temporary file can still be cleaned up in that case. Default is `true`.
* @see https://www.php.net/manual/en/function.ignore-user-abort.php
*/
public $ignoreUserAbort = true;
/**
* @var array the list of static default headers to send when `send()` is
* called as key/value pairs.
*/
public static $defaultHeaders = array(
'Pragma' => 'public',
'Expires' => 0,
'Cache-Control' => 'must-revalidate, post-check=0, pre-check=0',
'Content-Transfer-Encoding' => 'binary',
);
/**
* @var string the name of this file
*/
protected $_fileName;
/**
* Constructor
*
* @param string $content the tmp file content
* @param string|null $suffix the optional suffix for the tmp file
* @param string|null $prefix the optional prefix for the tmp file. If null
* 'php_tmpfile_' is used.
* @param string|null $directory directory where the file should be
* created. Autodetected if not provided.
*/
public function __construct($content, $suffix = null, $prefix = null, $directory = null)
{
if ($directory === null) {
$directory = self::getTempDir();
}
if ($prefix === null) {
$prefix = 'php_tmpfile_';
}
$this->_fileName = tempnam($directory,$prefix);
if ($suffix !== null) {
$newName = $this->_fileName . $suffix;
rename($this->_fileName, $newName);
$this->_fileName = $newName;
}
file_put_contents($this->_fileName, $content);
}
/**
* Delete tmp file on shutdown if `$delete` is `true`
*/
public function __destruct()
{
if ($this->delete && file_exists($this->_fileName)) {
unlink($this->_fileName);
}
}
/**
* Send tmp file to client, either inline or as download
*
* @param string|null $filename the filename to send. If empty, the file is
* streamed inline.
* @param string|null $contentType the Content-Type header to send. If
* `null` the type is auto-detected and if that fails
* 'application/octet-stream' is used.
* @param bool $inline whether to force inline display of the file, even if
* filename is present.
* @param array $headers a list of additional HTTP headers to send in the
* response as an array. The array keys are the header names like
* 'Cache-Control' and the array values the header value strings to send.
* Each array value can also be another array of strings if the same header
* should be sent multiple times. This can also be used to override
* automatically created headers like 'Expires' or 'Content-Length'. To suppress
* automatically created headers, `false` can also be used as header value.
*/
public function send($filename = null, $contentType = null, $inline = false, $headers = array())
{
$headers = array_merge(self::$defaultHeaders, $headers);
if ($contentType !== null) {
$headers['Content-Type'] = $contentType;
} elseif (!isset($headers['Content-Type'])) {
$contentType = @mime_content_type($this->_filename);
if ($contentType === false) {
$contentType = self::DEFAULT_CONTENT_TYPE;
}
$headers['Content-Type'] = $contentType;
}
if (!isset($headers['Content-Length'])) {
// #11 Undefined index: HTTP_USER_AGENT
$userAgent = isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : '';
// #84: Content-Length leads to "network connection was lost" on iOS
$isIOS = preg_match('/i(phone|pad|pod)/i', $userAgent);
if (!$isIOS) {
$headers['Content-Length'] = filesize($this->_fileName);
}
}
if (($filename !== null || $inline) && !isset($headers['Content-Disposition'])) {
$disposition = $inline ? 'inline' : 'attachment';
$encodedFilename = rawurlencode($filename);
$headers['Content-Disposition'] = "$disposition; " .
"filename=\"$filename\"; " .
"filename*=UTF-8''$encodedFilename";
}
$this->sendHeaders($headers);
// #28: File not cleaned up if user aborts connection during download
if ($this->ignoreUserAbort) {
ignore_user_abort(true);
}
readfile($this->_fileName);
}
/**
* @param string $name the name to save the file as
* @return bool whether the file could be saved
*/
public function saveAs($name)
{
return copy($this->_fileName, $name);
}
/**
* @return string the full file name
*/
public function getFileName()
{
return $this->_fileName;
}
/**
* @return string the path to the temp directory
*/
public static function getTempDir()
{
if (function_exists('sys_get_temp_dir')) {
return sys_get_temp_dir();
} elseif (
($tmp = getenv('TMP')) ||
($tmp = getenv('TEMP')) ||
($tmp = getenv('TMPDIR'))
) {
return realpath($tmp);
} else {
return '/tmp';
}
}
/**
* @return string the full file name
*/
public function __toString()
{
return $this->_fileName;
}
/**
* Send the given list of headers
*
* @param array $headers the list of headers to send as key/value pairs.
* Value can either be a string or an array of strings to send the same
* header multiple times.
*/
protected function sendHeaders($headers)
{
foreach ($headers as $name => $value) {
if ($value === false) {
continue;
}
if (is_array($value)) {
foreach ($value as $v) {
header("$name: $v");
}
} else {
header("$name: $value");
}
}
}
}