]>
Commit | Line | Data |
---|---|---|
d8c46ff7 GJ |
1 | <?php |
2 | /** | |
8fa0750d GJ |
3 | * Handles POST uploads, generates filenames, moves files around and commits |
4 | * uploaded metadata to database. | |
d8c46ff7 GJ |
5 | */ |
6 | require_once 'classes/Response.class.php'; | |
7 | require_once 'classes/UploadException.class.php'; | |
8 | require_once 'classes/UploadedFile.class.php'; | |
9 | require_once 'includes/database.inc.php'; | |
10 | ||
11 | /** | |
8fa0750d GJ |
12 | * Generates a random name for the file, retrying until we get an unused one. |
13 | * | |
14 | * @param UploadedFile $file | |
15 | * | |
16 | * @return string | |
d8c46ff7 GJ |
17 | */ |
18 | function generateName($file) | |
19 | { | |
20 | global $db; | |
21 | global $doubledots; | |
22 | ||
23 | // We start at N retries, and --N until we give up | |
b349c51a GJ |
24 | $tries = UGUU_FILES_RETRIES; |
25 | $length = UGUU_FILES_LENGTH; | |
d9744300 | 26 | |
d8c46ff7 GJ |
27 | //Get EXT |
28 | $ext = pathinfo($file->name, PATHINFO_EXTENSION); | |
d9744300 GJ |
29 | |
30 | //Get MIME | |
d8c46ff7 GJ |
31 | $finfo = finfo_open(FILEINFO_MIME_TYPE); |
32 | $type_mime = finfo_file($finfo, $file->tempfile); | |
33 | finfo_close($finfo); | |
34 | ||
35 | // Check if extension is a double-dot extension and, if true, override $ext | |
36 | $revname = strrev($file->name); | |
37 | foreach ($doubledots as $ddot) { | |
38 | if (stripos($revname, $ddot) === 0) { | |
39 | $ext = strrev($ddot); | |
40 | } | |
41 | } | |
42 | ||
43 | do { | |
44 | // Iterate until we reach the maximum number of retries | |
45 | if ($tries-- === 0) { | |
d9744300 GJ |
46 | http_response_code(500); |
47 | throw new Exception( | |
d8c46ff7 GJ |
48 | 'Gave up trying to find an unused name', |
49 | 500 | |
50 | ); // HTTP status code "500 Internal Server Error" | |
51 | } | |
52 | ||
53 | $chars = ID_CHARSET; | |
54 | $name = ''; | |
55 | for ($i = 0; $i < $length; ++$i) { | |
56 | $name .= $chars[mt_rand(0, strlen($chars))]; | |
57 | } | |
58 | ||
59 | // Add the extension to the file name | |
60 | if (isset($ext) && $ext !== '') { | |
61 | $name .= '.'.$ext; | |
62 | } | |
63 | ||
d9744300 GJ |
64 | //Check if MIME is blacklisted |
65 | if (in_array($type_mime, unserialize(CONFIG_BLOCKED_MIME))) { | |
66 | http_response_code(415); | |
67 | throw new UploadException(UPLOAD_ERR_EXTENSION); | |
d8c46ff7 | 68 | exit(0); |
d9744300 | 69 | } |
d8c46ff7 GJ |
70 | //Check if EXT is blacklisted |
71 | if (in_array($ext, unserialize(CONFIG_BLOCKED_EXTENSIONS))) { | |
d9744300 GJ |
72 | http_response_code(415); |
73 | throw new UploadException(UPLOAD_ERR_EXTENSION); | |
8fa0750d GJ |
74 | exit(0); |
75 | } | |
76 | ||
d8c46ff7 GJ |
77 | // Check if a file with the same name does already exist in the database |
78 | $q = $db->prepare('SELECT COUNT(filename) FROM files WHERE filename = (:name)'); | |
79 | $q->bindValue(':name', $name, PDO::PARAM_STR); | |
80 | $q->execute(); | |
81 | $result = $q->fetchColumn(); | |
82 | // If it does, generate a new name | |
d9744300 GJ |
83 | } while ($result > 0); |
84 | ||
85 | return $name; | |
86 | } | |
d8c46ff7 GJ |
87 | |
88 | /** | |
89 | * Handles the uploading and db entry for a file. | |
90 | * | |
91 | * @param UploadedFile $file | |
92 | * | |
93 | * @return array | |
94 | */ | |
95 | function uploadFile($file) | |
96 | { | |
97 | global $db; | |
98 | global $FILTER_MODE; | |
99 | global $FILTER_MIME; | |
100 | ||
101 | // Handle file errors | |
102 | if ($file->error) { | |
103 | throw new UploadException($file->error); | |
104 | } | |
105 | ||
d9744300 GJ |
106 | //fixes a bug |
107 | $lol = $file->getSha1(); | |
108 | ||
109 | // Check if a file with the same hash and size (a file which is the same) | |
110 | // does already exist in the database; if it does, return the proper link | |
111 | // and data. PHP deletes the temporary file just uploaded automatically. | |
112 | if(ANTI_DUPE == 'true'){ | |
113 | $q = $db->prepare('SELECT filename, COUNT(*) AS count FROM files WHERE hash = (:hash) AND size = (:size)'); | |
114 | $q->bindValue(':hash', $file->getSha1(), PDO::PARAM_STR); | |
115 | $q->bindValue(':size', $file->size, PDO::PARAM_INT); | |
116 | $q->execute(); | |
117 | $result = $q->fetch(); | |
118 | if ($result['count'] > 0) { | |
119 | return [ | |
120 | 'hash' => $file->getSha1(), | |
121 | 'name' => $file->name, | |
122 | 'url' => UGUU_URL.rawurlencode($result['filename']), | |
123 | 'size' => $file->size, | |
124 | ]; | |
125 | } | |
126 | } | |
d8c46ff7 | 127 | |
8fa0750d GJ |
128 | // Get IP |
129 | $ip = $_SERVER['REMOTE_ADDR']; | |
130 | ||
d9744300 GJ |
131 | // Generate a name for the file |
132 | $newname = generateName($file); | |
133 | ||
d8c46ff7 | 134 | // Store the file's full file path in memory |
d9744300 | 135 | $uploadFile = UGUU_FILES_ROOT.$newname; |
d8c46ff7 GJ |
136 | |
137 | // Attempt to move it to the static directory | |
138 | if (!move_uploaded_file($file->tempfile, $uploadFile)) { | |
d9744300 GJ |
139 | http_response_code(500); |
140 | throw new Exception( | |
d8c46ff7 GJ |
141 | 'Failed to move file to destination', |
142 | 500 | |
143 | ); // HTTP status code "500 Internal Server Error" | |
144 | } | |
145 | ||
146 | // Need to change permissions for the new file to make it world readable | |
147 | if (!chmod($uploadFile, 0644)) { | |
d9744300 GJ |
148 | http_response_code(500); |
149 | throw new Exception( | |
d8c46ff7 GJ |
150 | 'Failed to change file permissions', |
151 | 500 | |
152 | ); // HTTP status code "500 Internal Server Error" | |
153 | } | |
154 | ||
155 | // Add it to the database | |
d9744300 | 156 | if(LOG_IP == 'true'){ |
8fa0750d | 157 | $q = $db->prepare('INSERT INTO files (hash, originalname, filename, size, date, ip) VALUES (:hash, :orig, :name, :size, :date, :ip)'); |
d9744300 | 158 | } else { |
317f6899 GJ |
159 | $ip = '0'; |
160 | $q = $db->prepare('INSERT INTO files (hash, originalname, filename, size, date, ip) VALUES (:hash, :orig, :name, :size, :date, :ip)'); | |
d9744300 GJ |
161 | } |
162 | ||
d8c46ff7 GJ |
163 | // Common parameters binding |
164 | $q->bindValue(':hash', $file->getSha1(), PDO::PARAM_STR); | |
165 | $q->bindValue(':orig', strip_tags($file->name), PDO::PARAM_STR); | |
166 | $q->bindValue(':name', $newname, PDO::PARAM_STR); | |
167 | $q->bindValue(':size', $file->size, PDO::PARAM_INT); | |
d9744300 | 168 | $q->bindValue(':date', time(), PDO::PARAM_STR); |
8fa0750d | 169 | $q->bindValue(':ip', $ip, PDO::PARAM_STR); |
d8c46ff7 GJ |
170 | $q->execute(); |
171 | ||
d9744300 | 172 | return [ |
d8c46ff7 GJ |
173 | 'hash' => $file->getSha1(), |
174 | 'name' => $file->name, | |
b349c51a | 175 | 'url' => UGUU_URL.rawurlencode($newname), |
d8c46ff7 | 176 | 'size' => $file->size, |
d9744300 | 177 | ]; |
d8c46ff7 GJ |
178 | } |
179 | ||
180 | /** | |
181 | * Reorder files array by file. | |
182 | * | |
183 | * @return array | |
184 | */ | |
185 | function diverseArray($files) | |
186 | { | |
d9744300 | 187 | $result = []; |
d8c46ff7 GJ |
188 | |
189 | foreach ($files as $key1 => $value1) { | |
190 | foreach ($value1 as $key2 => $value2) { | |
191 | $result[$key2][$key1] = $value2; | |
192 | } | |
193 | } | |
194 | ||
195 | return $result; | |
196 | } | |
197 | ||
198 | /** | |
199 | * Reorganize the $_FILES array into something saner. | |
200 | * | |
201 | * @return array | |
202 | */ | |
203 | function refiles($files) | |
204 | { | |
d9744300 | 205 | $result = []; |
d8c46ff7 GJ |
206 | $files = diverseArray($files); |
207 | ||
208 | foreach ($files as $file) { | |
209 | $f = new UploadedFile(); | |
210 | $f->name = $file['name']; | |
211 | $f->mime = $file['type']; | |
212 | $f->size = $file['size']; | |
213 | $f->tempfile = $file['tmp_name']; | |
214 | $f->error = $file['error']; | |
215 | $result[] = $f; | |
216 | } | |
217 | ||
218 | return $result; | |
219 | } | |
220 | ||
221 | $type = isset($_GET['output']) ? $_GET['output'] : 'json'; | |
222 | $response = new Response($type); | |
223 | ||
224 | if (isset($_FILES['files'])) { | |
225 | $uploads = refiles($_FILES['files']); | |
226 | ||
227 | try { | |
228 | foreach ($uploads as $upload) { | |
229 | $res[] = uploadFile($upload); | |
230 | } | |
231 | $response->send($res); | |
232 | } catch (Exception $e) { | |
233 | $response->error($e->getCode(), $e->getMessage()); | |
234 | } | |
235 | } else { | |
236 | $response->error(400, 'No input file(s)'); | |
237 | } |