server.php
来自「PHP 知识管理系统(基于树结构的知识管理系统), 英文原版的PHP源码。」· PHP 代码 · 共 1,998 行 · 第 1/5 页
PHP
1,998 行
{
// 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 (@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");
header("X-WebDAV-Status: $status", true);
}
/**
* private minimalistic version of PHP urlencode()
*
* only blanks and XML special chars must be encoded here
* full urlencode() encoding confuses some clients ...
*
* @param string URL to encode
* @return string encoded URL
*/
function _urlencode($url)
{
return strtr($url, array(" "=>"%20",
"&"=>"%26",
"<"=>"%3C",
">"=>"%3E",
));
}
/**
* private version of PHP urldecode
*
* not really needed but added for completenes
*
* @param string URL to decode
* @return string decoded URL
*/
function _urldecode($path)
{
return urldecode($path);
}
/**
* UTF-8 encode property values if not already done so
*
* @param string text to encode
* @return string utf-8 encoded text
*/
function _prop_encode($text)
{
switch (strtolower($this->_prop_encoding)) {
case "utf-8":
return $text;
case "iso-8859-1":
case "iso-8859-15":
case "latin-1":
default:
return utf8_encode($text);
}
}
/**
* Slashify - make sure path ends in a slash
*
* @param string
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?