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