📄 server.php
字号:
{ $args = func_get_args(); if (count($args) == 3) { return array("ns" => $args[0], "name" => $args[1], "val" => $args[2]); } else { return array("ns" => "DAV:", "name" => $args[0], "val" => $args[1]); } } // {{{ _check_auth /** * check authentication if check is implemented * * @param void * @return bool true if authentication succeded or not necessary */ function _check_auth() { $auth_type = isset($this->_SERVER["AUTH_TYPE"]) ? $this->_SERVER["AUTH_TYPE"] : null; $auth_user = isset($this->_SERVER["PHP_AUTH_USER"]) ? $this->_SERVER["PHP_AUTH_USER"] : null; $auth_pw = isset($this->_SERVER["PHP_AUTH_PW"]) ? $this->_SERVER["PHP_AUTH_PW"] : null; if (method_exists($this, "checkAuth")) { // PEAR style method name return $this->checkAuth($auth_type, $auth_user, $auth_pw); } else if (method_exists($this, "check_auth")) { // old (pre 1.0) method name return $this->check_auth($auth_type, $auth_user, $auth_pw); } else { // no method found -> no authentication required return true; } } // }}} // {{{ UUID stuff /** * generate Unique Universal IDentifier for lock token * * @param void * @return string a new UUID */ function _new_uuid() { // use uuid extension from PECL if available if (function_exists("uuid_create")) { return uuid_create(); } // fallback $uuid = md5(microtime().getmypid()); // this should be random enough for now // set variant and version fields for 'true' random uuid $uuid{12} = "4"; $n = 8 + (ord($uuid{16}) & 3); $hex = "0123456789abcdef"; $uuid{16} = $hex{$n}; // return formated uuid return substr($uuid, 0, 8)."-" . substr($uuid, 8, 4)."-" . substr($uuid, 12, 4)."-" . substr($uuid, 16, 4)."-" . substr($uuid, 20); } /** * create a new opaque lock token as defined in RFC2518 * * @param void * @return string new RFC2518 opaque lock token */ function _new_locktoken() { return "opaquelocktoken:".$this->_new_uuid(); } // }}} // {{{ WebDAV If: header parsing /** * * * @param string header string to parse * @param int current parsing position * @return array next token (type and value) */ function _if_header_lexer($string, &$pos) { // skip whitespace while (ctype_space($string{$pos})) { ++$pos; } // already at end of string? if (strlen($string) <= $pos) { return false; } // get next character $c = $string{$pos++}; // now it depends on what we found switch ($c) { case "<": // URIs are enclosed in <...> $pos2 = strpos($string, ">", $pos); $uri = substr($string, $pos, $pos2 - $pos); $pos = $pos2 + 1; return array("URI", $uri); case "[": //Etags are enclosed in [...] if ($string{$pos} == "W") { $type = "ETAG_WEAK"; $pos += 2; } else { $type = "ETAG_STRONG"; } $pos2 = strpos($string, "]", $pos); $etag = substr($string, $pos + 1, $pos2 - $pos - 2); $pos = $pos2 + 1; return array($type, $etag); case "N": // "N" indicates negation $pos += 2; return array("NOT", "Not"); default: // anything else is passed verbatim char by char return array("CHAR", $c); } } /** * parse If: header * * @param string header string * @return array URIs and their conditions */ function _if_header_parser($str) { $pos = 0; $len = strlen($str); $uris = array(); // parser loop while ($pos < $len) { // get next token $token = $this->_if_header_lexer($str, $pos); // check for URI if ($token[0] == "URI") { $uri = $token[1]; // remember URI $token = $this->_if_header_lexer($str, $pos); // get next token } else { $uri = ""; } // sanity check if ($token[0] != "CHAR" || $token[1] != "(") { return false; } $list = array(); $level = 1; $not = ""; while ($level) { $token = $this->_if_header_lexer($str, $pos); if ($token[0] == "NOT") { $not = "!"; continue; } switch ($token[0]) { case "CHAR": switch ($token[1]) { case "(": $level++; break; case ")": $level--; break; default: return false; } break; case "URI": $list[] = $not."<$token[1]>"; break; case "ETAG_WEAK": $list[] = $not."[W/'$token[1]']>"; break; case "ETAG_STRONG": $list[] = $not."['$token[1]']>"; break; default: return false; } $not = ""; } if (isset($uris[$uri]) && is_array($uris[$uri])) { $uris[$uri] = array_merge($uris[$uri], $list); } else { $uris[$uri] = $list; } } return $uris; } /** * check if conditions from "If:" headers are meat * * the "If:" header is an extension to HTTP/1.1 * defined in RFC 2518 section 9.4 * * @param void * @return void */ function _check_if_header_conditions() { if (isset($this->_SERVER["HTTP_IF"])) { $this->_if_header_uris = $this->_if_header_parser($this->_SERVER["HTTP_IF"]); foreach ($this->_if_header_uris as $uri => $conditions) { if ($uri == "") { $uri = $this->uri; } // all must match $state = true; foreach ($conditions as $condition) { // lock tokens may be free form (RFC2518 6.3) // but if opaquelocktokens are used (RFC2518 6.4) // we have to check the format (litmus tests this) if (!strncmp($condition, "<opaquelocktoken:", strlen("<opaquelocktoken"))) { if (!preg_match('/^<opaquelocktoken:[[:xdigit:]]{8}-[[:xdigit:]]{4}-[[:xdigit:]]{4}-[[:xdigit:]]{4}-[[:xdigit:]]{12}>$/', $condition)) { $this->http_status("423 Locked"); return false; } } if (!$this->_check_uri_condition($uri, $condition)) { $this->http_status("412 Precondition failed"); $state = false; break; } } // any match is ok if ($state == true) { return true; } } return false; } return true; } /** * Check a single URI condition parsed from an if-header * * Check a single URI condition parsed from an if-header * * @abstract * @param string $uri URI to check * @param string $condition Condition to check for this URI * @returns bool Condition check result */ function _check_uri_condition($uri, $condition) { // not really implemented here, // implementations must override // a lock token can never be from the DAV: scheme // litmus uses DAV:no-lock in some tests if (!strncmp("<DAV:", $condition, 5)) { return false; } return true; } /** * * * @param string path of resource to check * @param bool exclusive lock? */ function _check_lock_status($path, $exclusive_only = false) { // FIXME depth -> ignored for now if (method_exists($this, "checkLock")) { // is locked? $lock = $this->checkLock($path); // ... and lock is not owned? if (is_array($lock) && count($lock)) { // FIXME doesn't check uri restrictions yet if (!isset($this->_SERVER["HTTP_IF"]) || !strstr($this->_SERVER["HTTP_IF"], $lock["token"])) { if (!$exclusive_only || ($lock["scope"] !== "shared")) return false; } } } return true; } // }}} /** * Generate lockdiscovery reply from checklock() result * * @param string resource path to check * @return string lockdiscovery response */ function lockdiscovery($path) { // no lock support without checklock() method if (!method_exists($this, "checklock")) { return ""; } // collect response here $activelocks = ""; // get checklock() reply $lock = $this->checklock($path); // generate <activelock> block for returned data if (is_array($lock) && count($lock)) { // check for 'timeout' or 'expires' if (!empty($lock["expires"])) { $timeout = "Second-".($lock["expires"] - time()); } else if (!empty($lock["timeout"])) { $timeout = "Second-$lock[timeout]"; } else { $timeout = "Infinite"; } // genreate response block $activelocks.= " <D:activelock> <D:lockscope><D:$lock[scope]/></D:lockscope> <D:locktype><D:$lock[type]/></D:locktype> <D:depth>$lock[depth]</D:depth> <D:owner>$lock[owner]</D:owner> <D:timeout>$timeout</D:timeout> <D:locktoken><D:href>$lock[token]</D:href></D:locktoken> </D:activelock> "; } // return generated response return $activelocks; } /** * set HTTP return status and mirror it in a private header * * @param string status code and message * @return void */ function http_status($status) { // simplified success case if ($status === true) { $status = "200 OK"; } // remember status $this->_http_status = $status; // generate HTTP status response header("HTTP/1.1 $status");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -