function attach_doupload(&$file, $page, $pass = NULL, $temp = '', $copyright = FALSE, $notouch = FALSE) { global $_attach_messages; global $notify, $notify_subject, $notify_exclude, $spam; $type = get_mimeinfo($file['tmp_name']); $must_compress = attach_is_compress($type, PLUGIN_ATTACH_UNKNOWN_COMPRESS); if ($must_compress) { // if attach spam, filtering attach file. $vars['uploadname'] = $file['name']; $vars['uploadtext'] = attach_gettext($file['tmp_name']); if ($vars['uploadtext'] === '' || $vars['uploadtext'] === FALSE) { return FALSE; } //global $spam; if ($spam !== 0) { if (isset($spam['method']['attach'])) { $_method =& $spam['method']['attach']; } else { if (isset($spam['method']['_default'])) { $_method =& $spam['method']['_default']; } else { $_method = array(); } } $exitmode = isset($spam['exitmode']) ? $spam['exitmode'] : ''; pkwk_spamfilter('File Attach', $page, $vars, $_method, $exitmode); } } if ($must_compress && is_uploaded_file($file['tmp_name'])) { if (PLUGIN_ATTACH_COMPRESS_TYPE == 'TGZ' && exist_plugin('dump')) { $obj =& new AttachFile($page, $file['name'] . '.tgz'); if ($obj->exist) { return array('result' => FALSE, 'msg' => $_attach_messages['err_exists']); } $tar = new tarlib(); $tar->create(CACHE_DIR, 'tgz') or die_message(_("It failed in the generation of a temporary file.")); $tar->add_file($file['tmp_name'], $file['name']); $tar->close(); @rename($tar->filename, $obj->filename); chmod($obj->filename, PLUGIN_ATTACH_FILE_MODE); @unlink($tar->filename); } else { if (PLUGIN_ATTACH_COMPRESS_TYPE == 'GZ' && extension_loaded('zlib')) { $obj =& new AttachFile($page, $file['name'] . '.gz'); if ($obj->exist) { return array('result' => FALSE, 'msg' => $_attach_messages['err_exists']); } $tp = fopen($file['tmp_name'], 'rb') or die_message(_("The uploaded file cannot be read.")); // アップロードされたファイルが読めません。 $zp = gzopen($obj->filename, 'wb') or die_message(_("The compression file cannot be written.")); // 圧縮ファイルが書けません。 while (!feof($tp)) { gzwrite($zp, fread($tp, 8192)); } gzclose($zp); fclose($tp); chmod($obj->filename, PLUGIN_ATTACH_FILE_MODE); @unlink($file['tmp_name']); } else { if (PLUGIN_ATTACH_COMPRESS_TYPE == 'ZIP' && class_exists('ZipArchive')) { $obj =& new AttachFile($page, $file['name'] . '.zip'); if ($obj->exist) { return array('result' => FALSE, 'msg' => $_attach_messages['err_exists']); } $zip = new ZipArchive(); $zip->addFile($file['tmp_name'], $file['name']); // if ($zip->status !== ZIPARCHIVE::ER_OK) if ($zip->status !== 0) { die_message(_('The error occurred') . '(' . $zip->status . ').'); } $zip->close(); chmod($obj->filename, PLUGIN_ATTACH_FILE_MODE); @unlink($file['tmp_name']); } } } } else { //miko $obj =& new AttachFile($page, $file['name']); if ($obj->exist) { return array('result' => FALSE, 'msg' => $_attach_messages['err_exists']); } if (move_uploaded_file($file['tmp_name'], $obj->filename)) { chmod($obj->filename, PLUGIN_ATTACH_FILE_MODE); } } if (is_page($page)) { touch(get_filename($page)); } $obj->getstatus(); $obj->status['pass'] = $pass !== TRUE && $pass !== NULL ? md5($pass) : ''; $obj->putstatus(); if ($notify) { $notify_exec = TRUE; foreach ($notify_exclude as $exclude) { $exclude = preg_quote($exclude); if (substr($exclude, -1) == '.') { $exclude = $exclude . '*'; } if (preg_match('/^' . $exclude . '/', $_SERVER['REMOTE_ADDR'])) { $notify_exec = FALSE; break; } } } else { $notify_exec = FALSE; } if ($notify_exec !== FALSE) { $footer['ACTION'] = 'File attached'; $footer['FILENAME'] =& $file['name']; $footer['FILESIZE'] =& $file['size']; $footer['PAGE'] =& $page; $footer['URI'] = get_script_absuri() . '?plugin=attach' . '&refer=' . rawurlencode($page) . '&file=' . rawurlencode($file['name']) . '&pcmd=info'; $footer['USER_AGENT'] = TRUE; $footer['REMOTE_ADDR'] = TRUE; pkwk_mail_notify($notify_subject, "\n", $footer); } return array('result' => TRUE, 'msg' => $_attach_messages['msg_uploaded']); }
function plugin_dav_action() { global $scriptname, $log_ua, $attach_link; if (!exist_plugin('attach')) { dav_error_exit(500, 'attach plugin not found.'); } $scriptname = SCRIPT_NAME; header('Expires: Sat, 1 Jan 2000 00:00:00 GMT'); header('Cache-Control: no-store, no-cache, must-revalidate'); header('Cache-Control: post-check=0, pre-check=0', false); header('Pragma: no-cache'); //$_SERVER['REQUEST_METHOD'] = 'PROPFIND'; $req_headers = apache_request_headers(); $path_info = isset($_SERVER['PATH_INFO']) ? $_SERVER['PATH_INFO'] : ''; switch ($_SERVER['REQUEST_METHOD']) { case 'OPTIONS': header('DAV: 1'); // OPTIONS,PROPFIND,GET,HEAD,PUT,DELETE,MOVE,COPY // header('Allow: OPTIONS,PROPFIND,GET,PUT,MOVE,COPY'); header('Allow: OPTIONS,PROPFIND,GET,PUT,MOVE,COPY,LOCK,UNLOCK'); header('MS-Author-Via: DAV'); exit; case 'PROPFIND': // 添付する際にパスワードまたは、管理者のみの場合は、認証を要求 if (!$attach_link || Auth::is_protect() || PLUGIN_ATTACH_PASSWORD_REQUIRE || PLUGIN_ATTACH_UPLOAD_ADMIN_ONLY) { $is_admin = PLUGIN_ATTACH_UPLOAD_ADMIN_ONLY ? true : false; // 管理者パスワードを許容するか $login = Auth::check_auth_pw(); // 認証済かどうか if (empty($login)) { dav_error_exit(401, $is_admin); } // 未認証の場合、認証要求 // 認証判定 if (dav_login($is_admin) === false || Auth::is_protect()) { dav_error_exit(403); } } if (empty($path_info)) { dav_error_exit(301, NULL, dav_myurl1() . '/'); } $depth = isset($req_headers['Depth']) ? $req_headers['Depth'] : 0; list($dir, $file) = dav_get_folder_info($path_info, $depth); if (!isset($dir)) { dav_error_exit(404); } $ret = dav_makemultistat($dir, $file, $_SERVER['REQUEST_URI'], $depth); if (!isset($ret)) { dav_error_exit(301, NULL, dav_myurl() . '/'); } header('HTTP/1.1 207 Multi-Status'); header('Content-Type: text/xml'); echo $ret->saveXML(); exit; case 'GET': case 'HEAD': // 通常のファイル参照時は、このメソッドでアクセスされる $obj = dav_getfileobj($path_info, true); if (isset($obj) && $obj->exists) { $obj->open(); } else { if ($_SERVER['REQUEST_METHOD'] == 'GET' && empty($path_info) && strpos($log_ua, 'MSIE') > 0) { dav_officious_message(); exit; } else { dav_error_exit(404); } } exit; case 'PUT': if (Auth::check_role('readonly')) { dav_error_exit(403, 'PKWK_READONLY prohibits editing'); } // 添付する際にパスワードまたは、管理者のみの場合は、認証を要求 if (PLUGIN_ATTACH_UPLOAD_ADMIN_ONLY) { if (!Auth::check_role('role_contents_admin') && !Auth::is_temp_admin()) { dav_error_exit(403); } } $size = isset($req_headers['Content-Length']) ? intval($req_headers['Content-Length']) : 0; // Windows 7のクライアントは、まず0バイト書いて、 // それをLOCKしてから、上書きしにくる。 // しかし、Pukiwikiは基本上書き禁止。 // そこで0バイトの時は無視する。 if ($size == 0) { exit; } if ($size > PLUGIN_ATTACH_MAX_FILESIZE) { dav_error_exit(403, 'file size error'); } // get file $tmpfilename = tempnam('/tmp', 'dav'); $fp = fopen($tmpfilename, 'wb'); $size = 0; $putdata = fopen('php://input', 'rb'); while ($data = fread($putdata, 1024)) { $size += strlen($data); fwrite($fp, $data); } @fclose($putdata); @fclose($fp); list($_page, $_filename) = dav_get_filename($path_info); // FIXME - 勝手にファイル名を変更するため、クライアントの挙動がおかしくなる if (PLUGIN_DAV_MUST_COMPRESS) { $type = Utility::getMimeInfo($tmpfilename); $must_compress = attach_is_compress($type, PLUGIN_ATTACH_UNKNOWN_COMPRESS); } else { $must_compress = false; } $obj = dav_getfileobj($path_info, false, $must_compress); if (!is_object($obj)) { dav_error_exit(403, 'no page'); } if ($obj->exist) { @unlink($tmpfilename); dav_error_exit(403, 'already exist.'); } $ext = $must_compress ? dav_attach_get_ext() : ''; switch ($ext) { case '.tgz': $tar = new tarlib(); $tar->create(CACHE_DIR, 'tgz') or dav_error_exit(500); $tar->add_file($tmpfilename, $_filename); $tar->close(); @rename($tar->filename, $obj->filename); chmod($obj->filename, PLUGIN_ATTACH_FILE_MODE); @unlink($tar->filename); break; case '.gz': $tp = fopen($tmpfilename, 'rb') or dav_error_exit(500); // アップロードされたファイルが読めません $zp = gzopen($obj->filename, 'wb') or dav_error_exit(500); // 圧縮ファイルが書けません while (!feof($tp)) { gzwrite($zp, fread($tp, 8192)); } gzclose($zp); fclose($tp); chmod($obj->filename, PLUGIN_ATTACH_FILE_MODE); @unlink($tmpfilename); break; case '.bz2': $tp = fopen($tmpfilename, 'rb') or dav_error_exit(500); // アップロードされたファイルが読めません $zp = bzopen($obj->filename, 'wb') or dav_error_exit(500); // 圧縮ファイルが書けません while (!feof($tp)) { bzwrite($zp, fread($tp, 8192)); } bzclose($zp); fclose($tp); chmod($obj->filename, PLUGIN_ATTACH_FILE_MODE); @unlink($tmpfilename); break; case '.zip': $zip = new ZipArchive(); $zip->addFile($tmpfilename, $_filename); if ($zip->status !== 0) { dav_error_exit(500); } // $zip->status $zip->close(); chmod($obj->filename, PLUGIN_ATTACH_FILE_MODE); @unlink($tmpfilename); break; default: if (copy($tmpfilename, $obj->filename)) { chmod($obj->filename, PLUGIN_ATTACH_FILE_MODE); } @unlink($tmpfilename); } if (is_page($obj->page)) { touch(get_filename($obj->page)); } cache_timestamp_touch('attach'); $pass = dav_get_pass(); $obj->getstatus(); $obj->status['pass'] = $pass !== TRUE && $pass !== NULL ? md5($pass) : ''; $obj->putstatus(); // FIXME // $must_compress 時のファイル名変更に追随できない exit; case 'DELETE': if (Auth::check_role('readonly')) { dav_error_exit(403, 'PKWK_READONLY prohibits editing'); } // WinXP,Win7 では // フォルダーは消せないくせに、消せたように処理してしまう。 // レスポンスコードを確認しないで消すので無意味。 // また、フォルダーの削除は、ページを意味するので除外する if (substr($path_info, -1) === '/') { dav_error_exit(501); } // 添付する際にパスワードまたは、管理者のみの場合は、認証を要求 if (PLUGIN_ATTACH_DELETE_ADMIN_ONLY) { if (!Auth::check_role('role_contents_admin') && !Auth::is_temp_admin()) { dav_error_exit(403); } } $obj =& dav_getfileobj($path_info, false); if (!is_object($obj)) { dav_error_exit(403); } if ($obj->getstatus() == FALSE) { dav_error_exit(404); } $pass = dav_get_pass(); $obj->delete($pass); if (file_exists($obj->filename)) { dav_error_exit(406, "can't delete this file"); } cache_timestamp_touch('attach'); exit; case 'MOVE': case 'COPY': // 添付ファイルのコピーと移動のみ // 同じページ内での添付ファイルの移動もわざわざ消して書いている // ページのコピーや移動は未実装 if (Auth::check_role('readonly')) { dav_error_exit(403, 'PKWK_READONLY prohibits editing'); } // 添付する際にパスワードまたは、管理者のみの場合は、認証を要求 if (PLUGIN_ATTACH_UPLOAD_ADMIN_ONLY || PLUGIN_ATTACH_DELETE_ADMIN_ONLY) { if (!Auth::check_role('role_contents_admin') && !Auth::is_temp_admin()) { dav_error_exit(403); } } // GET TO (Destination) $destname = isset($req_headers['Destination']) ? $req_headers['Destination'] : ''; if (strpos($destname, dav_myurl0()) === 0) { $destname = substr($destname, strlen(dav_myurl0())); } if (strpos($destname, $scriptname) === 0) { $destname = urldecode(substr($destname, strlen($scriptname))); } else { dav_error_exit(403, 'not dav directory.'); } // if ($path_info === $destname) dav_error_exit(403); // Forbidden // ページ名変更 if (PLUGIN_DAV_CREATE_PAGE && $_SERVER['REQUEST_METHOD'] == 'MOVE') { // FIXME // 実在ページ && 添付ファイルなし なら許容 // 下位ページがあっても、無視して実行、関連ファイルもリネームしていない $from = dav_strip_slash($path_info); if (is_page($from)) { $pages = dav_get_existpages_cache(); if (isset($pages[$from]['file']) && count($pages[$from]['file']) == 0) { $to = dav_strip_slash($destname); if (isset($pages[$to])) { dav_error_exit(409); } // Conflict rename(get_filename($from), get_filename($to)); cache_timestamp_touch(); } else { dav_error_exit(501); // Method not Implemented } exit; } } // FROM (PATH_INFO) if ($_SERVER['REQUEST_METHOD'] == 'MOVE') { $obj1 =& dav_getfileobj($path_info, false); } else { $obj1 =& dav_getfileobj($path_info, true); // readonly } if (!is_object($obj1)) { dav_error_exit(403, 'no src page.'); } if ($obj1->getstatus() == FALSE) { dav_error_exit(404); } // TO (Destination) $obj2 =& dav_getfileobj($destname, false); if (!is_object($obj2)) { dav_error_exit(403, 'no dst page.'); } if ($obj2->exist) { dav_error_exit(409); } // Conflict - 'already exist' if (copy($obj1->filename, $obj2->filename)) { chmod($obj2->filename, PLUGIN_ATTACH_FILE_MODE); } else { dav_error_exit(406, "can't copy it"); } // COPY $pass = dav_get_pass(); if (is_page($obj2->page)) { touch(get_filename($obj2->page)); } $obj2->getstatus(); $obj2->status['pass'] = $pass !== TRUE && $pass !== NULL ? md5($pass) : ''; $obj2->putstatus(); // MOVE(DELETE) if ($_SERVER['REQUEST_METHOD'] == 'MOVE') { $obj1->delete($pass); if (file_exists($obj1->filename)) { dav_error_exit(406, "can't delete this file"); } } cache_timestamp_touch('attach'); exit; case 'MKCOL': // Microsoft-WebDAV-MiniRedir などは、[新しいフォルダー] をまず作成しようとするので無意味 if (!PLUGIN_DAV_CREATE_PAGE) { dav_error_exit(403); } if (Auth::check_role('readonly')) { dav_error_exit(403, 'PKWK_READONLY prohibits editing'); } if (Auth::is_check_role(PKWK_CREATE_PAGE)) { dav_error_exit(403, 'PKWK_CREATE_PAGE prohibits editing'); } // 添付する際にパスワードまたは、管理者のみの場合は、認証を要求 if (PLUGIN_ATTACH_UPLOAD_ADMIN_ONLY || PLUGIN_ATTACH_DELETE_ADMIN_ONLY) { if (!Auth::check_role('role_contents_admin') && !Auth::is_temp_admin()) { dav_error_exit(403); } } // windows の場合、スラッシュで終わらない場合がある if (substr($path_info, -1) !== '/') { $path_info .= '/'; } if (!isset($path_info)) { dav_error_exit(403); } if (preg_match('/^\\/(.+)\\/$/', $path_info, $matches) != 1) { dav_error_exit(403); } $page = dav_strip_slash($path_info); $wiki = Factory::Wiki($page); if (!$wiki->isValied()) { dav_error_exit(403); } $wiki->set(PLUGIN_DAV_FOLODER_PAGE_BODY); // write initial string to the page. cache_timestamp_touch(); // PROPFIND の挙動 (作成したフォルダーを表示させるため) $depth = '1'; list($dir, $file) = dav_get_folder_info($path_info, $depth); if (!isset($dir)) { dav_error_exit(404); } $ret = dav_makemultistat($dir, $file, $_SERVER['REQUEST_URI'], $depth); if (!isset($ret)) { dav_error_exit(301, NULL, dav_myurl() . '/'); } header('HTTP/1.1 200 OK'); header('Content-Type: text/xml'); echo $ret->saveXML(); exit; case 'PROPPATCH': // PROPPATCH が失敗するとファイルを消すため必要。 header('HTTP/1.1 207 Multi-Status'); header('Content-Type: text/xml'); $ret = dav_proppatch_dummy_response($_SERVER['REQUEST_URI']); echo $ret->saveXML(); exit; case 'LOCK': case 'UNLOCK': case 'POST': dav_error_exit(501); // Method not Implemented exit; default: dav_error_exit(405); // Method not Allowed } exit; }