mambax7 /
gwiki
This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
| 1 | <?php |
||
| 2 | /** |
||
| 3 | * ajaxfileedit.php - backend upload attachments and update file info |
||
| 4 | * |
||
| 5 | * @copyright Copyright © 2013 geekwright, LLC. All rights reserved. |
||
| 6 | * @license gwiki/docs/license.txt GNU General Public License (GPL) |
||
| 7 | * @since 1.0 |
||
| 8 | * @author Richard Griffith <[email protected]> |
||
| 9 | * @package gwiki |
||
| 10 | */ |
||
| 11 | include __DIR__ . '/../../mainfile.php'; |
||
| 12 | $xoopsLogger->activated = false; |
||
| 13 | // provide error logging for our sanity in debugging ajax use (won't see xoops logger) |
||
| 14 | restore_error_handler(); |
||
| 15 | error_reporting(-1); |
||
| 16 | |||
| 17 | $dir = basename(__DIR__); |
||
| 18 | require_once XOOPS_ROOT_PATH . '/modules/' . $dir . '/class/GwikiPage.php'; |
||
| 19 | global $wikiPage; |
||
| 20 | $wikiPage = new GwikiPage; |
||
| 21 | |||
| 22 | $uploadpath = XOOPS_ROOT_PATH . "/uploads/{$dir}/"; |
||
| 23 | $uploadurl = XOOPS_URL . "/uploads/{$dir}/"; |
||
| 24 | |||
| 25 | $newfile = (isset($_SERVER['HTTP_GW_FILENAME']) ? $_SERVER['HTTP_GW_FILENAME'] : false); |
||
| 26 | $jsondata = (isset($_SERVER['HTTP_GW_JSONDATA']) ? $_SERVER['HTTP_GW_JSONDATA'] : false); |
||
| 27 | |||
| 28 | // initialize whitelist |
||
| 29 | $whitelist = array(); |
||
| 30 | $wlconfig = $xoopsModuleConfig['attach_ext_whitelist']; |
||
| 31 | //$wlconfig='txt,pdf,doc,docx,xls,rtf,zip'; |
||
| 32 | |||
| 33 | // populate whitelist |
||
| 34 | if (!empty($wlconfig)) { |
||
| 35 | $whitelist = explode(',', $wlconfig); |
||
| 36 | } |
||
| 37 | |||
| 38 | /** |
||
| 39 | * @param $filename |
||
| 40 | * |
||
| 41 | * @return array|bool |
||
| 42 | */ |
||
| 43 | function getExtensionInfo($filename) |
||
| 44 | { |
||
| 45 | global $whitelist; |
||
| 46 | |||
| 47 | $fi = array(); |
||
| 48 | |||
| 49 | // these choices are just from our icon set - nothing magic, just ext => filename - .png |
||
| 50 | $icons = array( |
||
| 51 | 'aac' => 'aac', |
||
| 52 | 'aiff' => 'aiff', |
||
| 53 | 'ai' => 'ai', |
||
| 54 | 'avi' => 'avi', |
||
| 55 | 'bmp' => 'bmp', |
||
| 56 | 'c' => 'c', |
||
| 57 | 'cpp' => 'cpp', |
||
| 58 | 'css' => 'css', |
||
| 59 | 'dat' => 'dat', |
||
| 60 | 'dmg' => 'dmg', |
||
| 61 | 'doc' => 'doc', |
||
| 62 | 'docx' => 'doc', |
||
| 63 | 'dot' => 'dotx', |
||
| 64 | 'dotx' => 'dotx', |
||
| 65 | 'dwg' => 'dwg', |
||
| 66 | 'dxf' => 'dxf', |
||
| 67 | 'eps' => 'eps', |
||
| 68 | 'exe' => 'exe', |
||
| 69 | 'flv' => 'flv', |
||
| 70 | 'gif' => 'gif', |
||
| 71 | 'h' => 'h', |
||
| 72 | 'hpp' => 'hpp', |
||
| 73 | 'htm' => 'html', |
||
| 74 | 'html' => 'html', |
||
| 75 | 'ics' => 'ics', |
||
| 76 | 'iso' => 'iso', |
||
| 77 | 'java' => 'java', |
||
| 78 | 'jpe' => 'jpg', |
||
| 79 | 'jpeg' => 'jpg', |
||
| 80 | 'jpg' => 'jpg', |
||
| 81 | 'key' => 'key', |
||
| 82 | 'mid' => 'mid', |
||
| 83 | 'mp3' => 'mp3', |
||
| 84 | 'mp4' => 'mp4', |
||
| 85 | 'mpg' => 'mpg', |
||
| 86 | 'odf' => 'odf', |
||
| 87 | 'ods' => 'ods', |
||
| 88 | 'odt' => 'odt', |
||
| 89 | 'otp' => 'otp', |
||
| 90 | 'ots' => 'ots', |
||
| 91 | 'ott' => 'ott', |
||
| 92 | 'pdf' => 'pdf', |
||
| 93 | 'php' => 'php', |
||
| 94 | 'png' => 'png', |
||
| 95 | 'ppt' => 'ppt', |
||
| 96 | 'psd' => 'psd', |
||
| 97 | 'py' => 'py', |
||
| 98 | 'qt' => 'qt', |
||
| 99 | 'rar' => 'rar', |
||
| 100 | 'rb' => 'rb', |
||
| 101 | 'rtf' => 'rtf', |
||
| 102 | 'sql' => 'sql', |
||
| 103 | 'tga' => 'tga', |
||
| 104 | 'tgz' => 'tgz', |
||
| 105 | 'tif' => 'tiff', |
||
| 106 | 'tiff' => 'tiff', |
||
| 107 | 'txt' => 'txt', |
||
| 108 | 'wav' => 'wav', |
||
| 109 | 'xls' => 'xls', |
||
| 110 | 'xlsx' => 'xlsx', |
||
| 111 | 'xml' => 'xml', |
||
| 112 | 'yml' => 'yml', |
||
| 113 | 'zip' => 'zip', |
||
| 114 | ); |
||
| 115 | // Also have files '_blank' '_page' |
||
| 116 | |||
| 117 | $path_parts = pathinfo($filename); |
||
| 118 | // =$path_parts['dirname'], "\n"; |
||
| 119 | $fi['file_name'] = $path_parts['basename']; |
||
| 120 | if (!isset($path_parts['extension'])) { |
||
| 121 | $ext = ''; |
||
| 122 | } else { |
||
| 123 | $ext = strtolower($path_parts['extension']); |
||
| 124 | } |
||
| 125 | //=$path_parts['filename']; |
||
| 126 | |||
| 127 | // if no name, or not on whitelist reject |
||
| 128 | if (empty($path_parts['filename']) || array_search($ext, $whitelist) === false) { |
||
| 129 | return false; |
||
| 130 | } |
||
| 131 | |||
| 132 | if (empty($ext)) { |
||
| 133 | $fi['file_icon'] = '_blank'; |
||
| 134 | } else { |
||
| 135 | if (empty($icons[$ext])) { |
||
| 136 | $fi['file_icon'] = '_blank'; |
||
| 137 | } else { |
||
| 138 | $fi['file_icon'] = $icons[$ext]; |
||
| 139 | } |
||
| 140 | } |
||
| 141 | |||
| 142 | return $fi; |
||
| 143 | } |
||
| 144 | |||
| 145 | /** |
||
| 146 | * @param $filename |
||
| 147 | * |
||
| 148 | * @return array |
||
| 149 | */ |
||
| 150 | function getFileInfo($filename) |
||
| 151 | { |
||
| 152 | $fi = array(); |
||
| 153 | |||
| 154 | if (function_exists('finfo_open')) { |
||
| 155 | $finfo = finfo_open(FILEINFO_MIME_TYPE); // return mime type ala mimetype extension |
||
| 156 | $fi['file_type'] = finfo_file($finfo, $filename); |
||
| 157 | finfo_close($finfo); |
||
| 158 | } else { |
||
| 159 | $fi['file_type'] = mime_content_type($filename); |
||
| 160 | } |
||
| 161 | $fi['file_size'] = filesize($filename); |
||
| 162 | |||
| 163 | return $fi; |
||
| 164 | } |
||
| 165 | |||
| 166 | /** |
||
| 167 | * @param $string |
||
| 168 | * |
||
| 169 | * @return string |
||
| 170 | */ |
||
| 171 | View Code Duplication | function cleaner($string) |
|
| 172 | { |
||
| 173 | $string = stripcslashes($string); |
||
| 174 | $string = html_entity_decode($string); |
||
| 175 | $string = strip_tags($string); // DANGER -- kills wiki text |
||
| 176 | $string = trim($string); |
||
| 177 | $string = stripslashes($string); |
||
| 178 | |||
| 179 | return $string; |
||
| 180 | } |
||
| 181 | |||
| 182 | /** |
||
| 183 | * @param $uid |
||
| 184 | * |
||
| 185 | * @return string |
||
| 186 | */ |
||
| 187 | function getUserName($uid) |
||
| 188 | { |
||
| 189 | global $xoopsConfig; |
||
| 190 | |||
| 191 | $uid = (int)$uid; |
||
| 192 | |||
| 193 | if ($uid > 0) { |
||
| 194 | $memberHandler = xoops_getHandler('member'); |
||
| 195 | $user = $memberHandler->getUser($uid); |
||
| 196 | if (is_object($user)) { |
||
| 197 | return "<a href=\"" . XOOPS_URL . "/userinfo.php?uid=$uid\">" . htmlspecialchars($user->getVar('uname'), ENT_QUOTES) . '</a>'; |
||
| 198 | } |
||
| 199 | } |
||
| 200 | |||
| 201 | return $xoopsConfig['anonymous']; |
||
| 202 | } |
||
| 203 | |||
| 204 | /** |
||
| 205 | * @param $input |
||
| 206 | * |
||
| 207 | * @return mixed |
||
| 208 | */ |
||
| 209 | View Code Duplication | function deleteData(&$input) |
|
| 210 | { |
||
| 211 | global $xoopsDB, $uploadpath, $wikiPage; |
||
| 212 | |||
| 213 | $q_file_id = (int)$input['file_id']; |
||
| 214 | // use keyword in delete so we know id and edit authority are connected |
||
| 215 | $q_keyword = $wikiPage->escapeForDB($input['page']); |
||
| 216 | |||
| 217 | // look up the name and delete the image file |
||
| 218 | $sql = 'SELECT file_path FROM ' . $xoopsDB->prefix('gwiki_page_files') . " where file_id='{$q_file_id}' AND keyword = '{$q_keyword}' "; |
||
| 219 | |||
| 220 | $result = $xoopsDB->query($sql); |
||
| 221 | if ($result) { |
||
| 222 | $rows = $xoopsDB->getRowsNum($result); |
||
| 223 | if ($rows) { |
||
| 224 | $myrow = $xoopsDB->fetchArray($result); |
||
| 225 | if (!empty($myrow['file_path'])) { |
||
| 226 | $oldfilename = $uploadpath . '/' . $myrow['file_path']; |
||
| 227 | unlink($oldfilename); |
||
| 228 | } |
||
| 229 | } |
||
| 230 | } |
||
| 231 | |||
| 232 | // delete the row |
||
| 233 | $sql = 'DELETE FROM ' . $xoopsDB->prefix('gwiki_page_files') . " where file_id='{$q_file_id}' AND keyword = '{$q_keyword}' "; |
||
| 234 | |||
| 235 | $result = $xoopsDB->queryF($sql); |
||
| 236 | $cnt = $xoopsDB->getAffectedRows(); |
||
| 237 | if ($cnt) { |
||
| 238 | $input['message'] = _MD_GWIKI_AJAX_FILEEDIT_DEL_OK; |
||
| 239 | } |
||
| 240 | |||
| 241 | return $result; |
||
| 242 | } |
||
| 243 | |||
| 244 | /** |
||
| 245 | * @param $input |
||
| 246 | * |
||
| 247 | * @return mixed |
||
| 248 | */ |
||
| 249 | function updateData(&$input) |
||
| 250 | { |
||
| 251 | global $xoopsDB, $xoopsUser, $wikiPage; |
||
| 252 | |||
| 253 | $q_file_id = (int)$input['file_id']; |
||
| 254 | $q_keyword = $wikiPage->escapeForDB($input['page']); |
||
| 255 | $q_file_name = $wikiPage->escapeForDB($input['file_name']); |
||
| 256 | $q_file_icon = $wikiPage->escapeForDB($input['file_icon']); |
||
| 257 | $q_file_type = $wikiPage->escapeForDB($input['file_type']); |
||
| 258 | $q_file_description = $wikiPage->escapeForDB($input['file_description']); |
||
| 259 | // file_path only changed by image upload |
||
| 260 | $q_file_size = (int)$input['file_size']; |
||
| 261 | $q_file_path = empty($input['file_path']) ? '' : $wikiPage->escapeForDB($input['file_path']); |
||
| 262 | $q_file_uid = $xoopsUser ? $xoopsUser->getVar('uid') : 0; |
||
| 263 | $input['file_uid'] = $q_file_uid; |
||
| 264 | if ((int)$input['file_upload_date'] === 0) { |
||
| 265 | $input['file_upload_date'] = time(); |
||
| 266 | } |
||
| 267 | $q_file_upload_date = $input['file_upload_date']; |
||
| 268 | |||
| 269 | $sql = 'UPDATE ' . $xoopsDB->prefix('gwiki_page_files') . ' SET '; |
||
| 270 | $sql .= " file_name = '{$q_file_name}', "; |
||
| 271 | $sql .= " file_icon = '{$q_file_icon}', "; |
||
| 272 | $sql .= " file_type = '{$q_file_type}', "; |
||
| 273 | $sql .= " file_size = '{$q_file_size}', "; |
||
| 274 | $sql .= " file_path = '{$q_file_path}', "; |
||
| 275 | $sql .= " file_uid = '{$q_file_uid}', "; |
||
| 276 | // $sql.= " file_uid = '{$q_file_upload_date}', "; |
||
| 277 | $sql .= " file_description = '{$q_file_description}' "; |
||
| 278 | $sql .= " where file_id = '{$q_file_id}' AND keyword = '{$q_keyword}' "; |
||
| 279 | |||
| 280 | $result = $xoopsDB->queryF($sql); |
||
| 281 | if (!$result) { |
||
| 282 | header('Status: 500 Internal Error - Database Error'); |
||
| 283 | $out['message'] === $xoopsDB->error(); |
||
| 284 | echo json_encode($out); |
||
| 285 | exit; |
||
| 286 | } |
||
| 287 | $cnt = $xoopsDB->getAffectedRows(); |
||
| 288 | if (!$cnt) { |
||
| 289 | $input['message'] = _MD_GWIKI_AJAX_FILEEDIT_NOT_DEFINED; |
||
| 290 | } else { |
||
| 291 | $input['message'] = _MD_GWIKI_AJAX_FILEEDIT_UPD_OK; |
||
| 292 | } |
||
| 293 | |||
| 294 | //file_id, keyword, file_name, file_path, file_type, file_icon, file_size, file_upload_date, file_description, file_uid |
||
| 295 | |||
| 296 | if ($result && !$cnt && !empty($q_file_path)) { // database is OK but nothing to update - require file_path |
||
| 297 | $sql = 'insert into ' . $xoopsDB->prefix('gwiki_page_files'); |
||
| 298 | $sql .= ' (keyword, file_name, file_path, file_type, file_icon, file_size, file_upload_date, file_description, file_uid) '; |
||
| 299 | $sql .= " values ('{$q_keyword}', '{$q_file_name}', '{$q_file_path}', '{$q_file_type}', '{$q_file_icon}', '{$q_file_size}', $q_file_upload_date, '{$q_file_description}', '{$q_file_uid}' )"; |
||
| 300 | $result = $xoopsDB->queryF($sql); |
||
| 301 | $input['file_id'] = $xoopsDB->getInsertId(); |
||
| 302 | $input['message'] = _MD_GWIKI_AJAX_FILEEDIT_ADD_OK; |
||
| 303 | } |
||
| 304 | |||
| 305 | return $input['file_id']; |
||
| 306 | } |
||
| 307 | |||
| 308 | /** |
||
| 309 | * @param $newfile |
||
| 310 | * @param $input |
||
| 311 | * |
||
| 312 | * @return mixed |
||
| 313 | */ |
||
| 314 | function updateFile($newfile, &$input) |
||
| 315 | { |
||
| 316 | global $uploadpath, $xoopsDB; |
||
| 317 | // For now, images are stored in individual directories for each page. |
||
| 318 | // We can change the directory distribution later, as the entire path |
||
| 319 | // relative to /uploads/gwiki/ ($relpath) is stored in the database. |
||
| 320 | |||
| 321 | // We get rid of any colons in the page name in case the filesystem has |
||
| 322 | // issues with them. (undescore is illegal in page name, so it stays unique.) |
||
| 323 | $relpath = 'pages/' . str_replace(':', '_', $input['page']) . '/file/'; |
||
| 324 | $ourpath = $uploadpath . $relpath; |
||
| 325 | $oldUmask = umask(0); |
||
| 326 | @mkdir($ourpath, 0755, true); |
||
|
0 ignored issues
–
show
|
|||
| 327 | umask($oldUmask); |
||
| 328 | $tempfn = tempnam($ourpath, 'WIKIFILE_'); |
||
| 329 | $image = file_get_contents('php://input'); |
||
| 330 | file_put_contents($tempfn, $image); |
||
| 331 | |||
| 332 | $filename = $ourpath . $newfile; |
||
| 333 | if (empty($input['file_name'])) { |
||
| 334 | $input['file_name'] = $justfn; |
||
| 335 | } |
||
| 336 | |||
| 337 | $fi = getFileInfo($tempfn); |
||
| 338 | foreach ($fi as $k => $v) { |
||
| 339 | $input[$k] = $v; |
||
| 340 | } |
||
| 341 | |||
| 342 | $input['file_name'] = $newfile; |
||
| 343 | $input['file_path'] = $relpath . $newfile; |
||
| 344 | |||
| 345 | rename($tempfn, $filename); |
||
| 346 | chmod($filename, 0644); |
||
| 347 | $q_file_id = (int)$input['file_id']; |
||
| 348 | $sql = 'SELECT file_path FROM ' . $xoopsDB->prefix('gwiki_page_files') . " where file_id='{$q_file_id}' "; |
||
| 349 | |||
| 350 | $result = $xoopsDB->query($sql); |
||
| 351 | if ($result) { |
||
| 352 | $rows = $xoopsDB->getRowsNum($result); |
||
| 353 | if ($rows) { |
||
| 354 | $myrow = $xoopsDB->fetchArray($result); |
||
| 355 | if (!empty($myrow['file_path'])) { |
||
| 356 | $oldfilename = $uploadpath . '/' . $myrow['file_path']; |
||
| 357 | unlink($oldfilename); |
||
| 358 | } |
||
| 359 | // update |
||
| 360 | } else { |
||
| 361 | // new row |
||
| 362 | } |
||
| 363 | } |
||
| 364 | $input['file_upload_date'] = time(); |
||
| 365 | |||
| 366 | return updateData($input); |
||
| 367 | } |
||
| 368 | |||
| 369 | if (!$jsondata) { |
||
| 370 | header('Status: 500 Internal Error - No Data Passed'); |
||
| 371 | exit; |
||
| 372 | } |
||
| 373 | $input = json_decode($jsondata, true); |
||
| 374 | //file_put_contents ( XOOPS_ROOT_PATH.'/uploads/debug.txt', print_r($input,true)); |
||
| 375 | |||
| 376 | if (!empty($input['file_id'])) { |
||
| 377 | $q_file_id = (int)$input['file_id']; |
||
| 378 | $sql = 'SELECT * FROM ' . $xoopsDB->prefix('gwiki_page_files') . " where file_id = '{$q_file_id}' "; |
||
| 379 | $result = $xoopsDB->query($sql); |
||
| 380 | if ($row = $xoopsDB->fetcharray($result)) { |
||
| 381 | $input['page'] = $row['keyword']; |
||
| 382 | foreach ($row as $k => $v) { |
||
| 383 | if (!isset($input[$k])) { |
||
| 384 | $input[$k] = $v; |
||
| 385 | } |
||
| 386 | } |
||
| 387 | } |
||
| 388 | } |
||
| 389 | |||
| 390 | if (empty($input['page'])) { |
||
| 391 | header('Status: 500 Internal Error - No Page'); |
||
| 392 | exit; |
||
| 393 | } |
||
| 394 | $input['page'] = strtolower($wikiPage->normalizeKeyword($input['page'])); |
||
| 395 | $pageX = $wikiPage->getPage($input['page']); |
||
| 396 | $mayEdit = $wikiPage->checkEdit(); |
||
| 397 | |||
| 398 | View Code Duplication | if (!$mayEdit) { |
|
| 399 | header('Status: 403 Forbidden - No Permission'); |
||
| 400 | if (!$mayEdit) { |
||
| 401 | $out['message'] = _MD_GWIKI_AJAX_FILEEDIT_NO_AUTH; |
||
| 402 | } |
||
| 403 | echo json_encode($out); |
||
| 404 | exit; |
||
| 405 | } |
||
| 406 | |||
| 407 | $q_newfile = $wikiPage->escapeForDB($newfile); |
||
| 408 | $q_keyword = $wikiPage->escapeForDB($input['page']); |
||
| 409 | |||
| 410 | $sql = 'SELECT file_id FROM ' . $xoopsDB->prefix('gwiki_page_files') . " where file_name = '{$q_newfile}' AND keyword='{$q_keyword}' "; |
||
| 411 | |||
| 412 | $result = $xoopsDB->query($sql); |
||
| 413 | if ($row = $xoopsDB->fetcharray($result)) { |
||
| 414 | if ($input['file_id'] !== $row['file_id']) { |
||
| 415 | header('Status: 500 Internal Error - Duplicate File Name'); |
||
| 416 | $out['message'] = _MD_GWIKI_AJAX_FILEEDIT_DUPLICATE; |
||
| 417 | echo json_encode($out); |
||
| 418 | exit; |
||
| 419 | } |
||
| 420 | } |
||
| 421 | |||
| 422 | /* |
||
| 423 | * This creates issues if page being edited has not been saved yet, so let's not be anal about it |
||
| 424 | if (!$pageX) { |
||
| 425 | header("Status: 403 Forbidden - No Page"); |
||
| 426 | if(!$pageX) $out['message']='Page does not exist'; |
||
| 427 | echo json_encode($out); |
||
| 428 | exit; |
||
| 429 | } |
||
| 430 | */ |
||
| 431 | |||
| 432 | if ($newfile) { |
||
| 433 | $fi = getExtensionInfo($newfile); |
||
| 434 | if ($fi === false) { |
||
| 435 | header('Status: 403 Forbidden - Bad File Type'); |
||
| 436 | $out['message'] = _MD_GWIKI_AJAX_FILEEDIT_BAD_TYPE; |
||
| 437 | echo json_encode($out); |
||
| 438 | exit; |
||
| 439 | } |
||
| 440 | foreach ($fi as $k => $v) { |
||
| 441 | $input[$k] = $v; |
||
| 442 | } |
||
| 443 | $input['file_id'] = updateFile($newfile, $input); |
||
| 444 | if ($input['file_id']) { |
||
| 445 | $input['message'] = 'Attachment Saved'; |
||
| 446 | $input['link'] = $uploadurl . $input['file_path']; |
||
| 447 | $input['iconlink'] = XOOPS_URL . '/modules/' . $dir . '/assets/icons/48px/' . $input['file_icon'] . '.png'; |
||
| 448 | $input['userlink'] = getUserName($input['file_uid']); |
||
| 449 | $input['size'] = number_format($input['file_size']); |
||
| 450 | $input['date'] = date($wikiPage->dateFormat, $input['file_upload_date']); |
||
| 451 | } |
||
| 452 | View Code Duplication | } else { |
|
| 453 | if (!empty($input['op']) && $input['op'] === 'delete') { |
||
| 454 | deleteData($input); |
||
| 455 | } else { |
||
| 456 | updateData($input); |
||
| 457 | } |
||
| 458 | } |
||
| 459 | echo json_encode($input); |
||
| 460 | exit; |
||
| 461 |
If you suppress an error, we recommend checking for the error condition explicitly: