]>
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 | //Check if EXT is blacklisted |
71 | if (in_array($ext, unserialize(CONFIG_BLOCKED_EXTENSIONS))) { | |
8fa0750d GJ |
72 | http_response_code(415); |
73 | throw new Exception ('Extension type not allowed.'); | |
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 | |
8fa0750d GJ |
83 | } while ($result > 0); |
84 | return $name; | |
85 | } | |
d8c46ff7 GJ |
86 | |
87 | /** | |
88 | * Handles the uploading and db entry for a file. | |
89 | * | |
90 | * @param UploadedFile $file | |
91 | * | |
92 | * @return array | |
93 | */ | |
94 | function uploadFile($file) | |
95 | { | |
96 | global $db; | |
97 | global $FILTER_MODE; | |
98 | global $FILTER_MIME; | |
99 | ||
100 | // Handle file errors | |
101 | if ($file->error) { | |
102 | throw new UploadException($file->error); | |
103 | } | |
104 | ||
105 | // Generate a name for the file | |
106 | $newname = generateName($file); | |
107 | ||
8fa0750d GJ |
108 | // Get IP |
109 | $ip = $_SERVER['REMOTE_ADDR']; | |
110 | ||
d8c46ff7 | 111 | // Store the file's full file path in memory |
b349c51a | 112 | $uploadFile = UGUU_FILES_ROOT . $newname; |
d8c46ff7 GJ |
113 | |
114 | // Attempt to move it to the static directory | |
115 | if (!move_uploaded_file($file->tempfile, $uploadFile)) { | |
8fa0750d GJ |
116 | http_response_code(500); |
117 | throw new Exception( | |
d8c46ff7 GJ |
118 | 'Failed to move file to destination', |
119 | 500 | |
120 | ); // HTTP status code "500 Internal Server Error" | |
121 | } | |
122 | ||
123 | // Need to change permissions for the new file to make it world readable | |
124 | if (!chmod($uploadFile, 0644)) { | |
8fa0750d GJ |
125 | http_response_code(500); |
126 | throw new Exception( | |
d8c46ff7 GJ |
127 | 'Failed to change file permissions', |
128 | 500 | |
129 | ); // HTTP status code "500 Internal Server Error" | |
130 | } | |
131 | ||
132 | // Add it to the database | |
8fa0750d GJ |
133 | if(LOG_IP == 'yes'){ |
134 | $q = $db->prepare('INSERT INTO files (hash, originalname, filename, size, date, ip) VALUES (:hash, :orig, :name, :size, :date, :ip)'); | |
135 | }else{ | |
317f6899 GJ |
136 | $ip = '0'; |
137 | $q = $db->prepare('INSERT INTO files (hash, originalname, filename, size, date, ip) VALUES (:hash, :orig, :name, :size, :date, :ip)'); | |
8fa0750d | 138 | } |
d8c46ff7 GJ |
139 | // Common parameters binding |
140 | $q->bindValue(':hash', $file->getSha1(), PDO::PARAM_STR); | |
141 | $q->bindValue(':orig', strip_tags($file->name), PDO::PARAM_STR); | |
142 | $q->bindValue(':name', $newname, PDO::PARAM_STR); | |
143 | $q->bindValue(':size', $file->size, PDO::PARAM_INT); | |
144 | $q->bindValue(':date', time(), PDO::PARAM_INT); | |
8fa0750d | 145 | $q->bindValue(':ip', $ip, PDO::PARAM_STR); |
d8c46ff7 GJ |
146 | $q->execute(); |
147 | ||
8fa0750d | 148 | return array( |
d8c46ff7 GJ |
149 | 'hash' => $file->getSha1(), |
150 | 'name' => $file->name, | |
b349c51a | 151 | 'url' => UGUU_URL.rawurlencode($newname), |
d8c46ff7 | 152 | 'size' => $file->size, |
8fa0750d | 153 | ); |
d8c46ff7 GJ |
154 | } |
155 | ||
156 | /** | |
157 | * Reorder files array by file. | |
158 | * | |
8fa0750d GJ |
159 | * @param $_FILES |
160 | * | |
d8c46ff7 GJ |
161 | * @return array |
162 | */ | |
163 | function diverseArray($files) | |
164 | { | |
8fa0750d | 165 | $result = array(); |
d8c46ff7 GJ |
166 | |
167 | foreach ($files as $key1 => $value1) { | |
168 | foreach ($value1 as $key2 => $value2) { | |
169 | $result[$key2][$key1] = $value2; | |
170 | } | |
171 | } | |
172 | ||
173 | return $result; | |
174 | } | |
175 | ||
176 | /** | |
177 | * Reorganize the $_FILES array into something saner. | |
178 | * | |
8fa0750d GJ |
179 | * @param $_FILES |
180 | * | |
d8c46ff7 GJ |
181 | * @return array |
182 | */ | |
183 | function refiles($files) | |
184 | { | |
8fa0750d | 185 | $result = array(); |
d8c46ff7 GJ |
186 | $files = diverseArray($files); |
187 | ||
188 | foreach ($files as $file) { | |
189 | $f = new UploadedFile(); | |
190 | $f->name = $file['name']; | |
191 | $f->mime = $file['type']; | |
192 | $f->size = $file['size']; | |
193 | $f->tempfile = $file['tmp_name']; | |
194 | $f->error = $file['error']; | |
195 | $result[] = $f; | |
196 | } | |
197 | ||
198 | return $result; | |
199 | } | |
200 | ||
201 | $type = isset($_GET['output']) ? $_GET['output'] : 'json'; | |
202 | $response = new Response($type); | |
203 | ||
204 | if (isset($_FILES['files'])) { | |
205 | $uploads = refiles($_FILES['files']); | |
206 | ||
207 | try { | |
208 | foreach ($uploads as $upload) { | |
209 | $res[] = uploadFile($upload); | |
210 | } | |
211 | $response->send($res); | |
212 | } catch (Exception $e) { | |
213 | $response->error($e->getCode(), $e->getMessage()); | |
214 | } | |
215 | } else { | |
216 | $response->error(400, 'No input file(s)'); | |
217 | } |