📄 server.php
字号:
echo " <D:prop>\n"; foreach ($file["noprops"] as $key => $prop) { if ($prop["ns"] == "DAV:") { echo " <D:$prop[name]/>\n"; } else if ($prop["ns"] == "") { echo " <$prop[name] xmlns=\"\"/>\n"; } else { echo " <" . $ns_hash[$prop["ns"]] . ":$prop[name]/>\n"; } } echo " </D:prop>\n"; echo " <D:status>HTTP/1.1 404 Not Found</D:status>\n"; echo " </D:propstat>\n"; } echo " </D:response>\n"; } echo "</D:multistatus>\n"; } // }}} // {{{ http_PROPPATCH() /** * PROPPATCH method handler * * @param void * @return void */ function http_PROPPATCH() { if ($this->_check_lock_status($this->path)) { $options = Array(); $options["path"] = $this->path; $propinfo = new _parse_proppatch("php://input"); if (!$propinfo->success) { $this->http_status("400 Error"); return; } $options['props'] = $propinfo->props; $responsedescr = $this->PROPPATCH($options); $this->http_status("207 Multi-Status"); header('Content-Type: text/xml; charset="utf-8"'); echo "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"; echo "<D:multistatus xmlns:D=\"DAV:\">\n"; echo " <D:response>\n"; echo " <D:href>".$this->_urlencode($this->_mergePathes($this->_SERVER["SCRIPT_NAME"], $this->path))."</D:href>\n"; foreach ($options["props"] as $prop) { echo " <D:propstat>\n"; echo " <D:prop><$prop[name] xmlns=\"$prop[ns]\"/></D:prop>\n"; echo " <D:status>HTTP/1.1 $prop[status]</D:status>\n"; echo " </D:propstat>\n"; } if ($responsedescr) { echo " <D:responsedescription>". $this->_prop_encode(htmlspecialchars($responsedescr)). "</D:responsedescription>\n"; } echo " </D:response>\n"; echo "</D:multistatus>\n"; } else { $this->http_status("423 Locked"); } } // }}} // {{{ http_MKCOL() /** * MKCOL method handler * * @param void * @return void */ function http_MKCOL() { $options = Array(); $options["path"] = $this->path; $stat = $this->MKCOL($options); $this->http_status($stat); } // }}} // {{{ http_GET() /** * GET method handler * * @param void * @returns void */ function http_GET() { // TODO check for invalid stream $options = Array(); $options["path"] = $this->path; $this->_get_ranges($options); if (true === ($status = $this->GET($options))) { if (!headers_sent()) { $status = "200 OK"; if (!isset($options['mimetype'])) { $options['mimetype'] = "application/octet-stream"; } header("Content-type: $options[mimetype]"); if (isset($options['mtime'])) { header("Last-modified:".gmdate("D, d M Y H:i:s ", $options['mtime'])."GMT"); } if (isset($options['stream'])) { // GET handler returned a stream if (!empty($options['ranges']) && (0===fseek($options['stream'], 0, SEEK_SET))) { // partial request and stream is seekable if (count($options['ranges']) === 1) { $range = $options['ranges'][0]; if (isset($range['start'])) { fseek($options['stream'], $range['start'], SEEK_SET); if (feof($options['stream'])) { $this->http_status("416 Requested range not satisfiable"); return; } if (isset($range['end'])) { $size = $range['end']-$range['start']+1; $this->http_status("206 partial"); header("Content-length: $size"); header("Content-range: $range[start]-$range[end]/" . (isset($options['size']) ? $options['size'] : "*")); while ($size && !feof($options['stream'])) { $buffer = fread($options['stream'], 4096); $size -= $this->bytes($buffer); echo $buffer; } } else { $this->http_status("206 partial"); if (isset($options['size'])) { header("Content-length: ".($options['size'] - $range['start'])); header("Content-range: ".$range['start']."-".$range['end']."/" . (isset($options['size']) ? $options['size'] : "*")); } fpassthru($options['stream']); } } else { header("Content-length: ".$range['last']); fseek($options['stream'], -$range['last'], SEEK_END); fpassthru($options['stream']); } } else { $this->_multipart_byterange_header(); // init multipart foreach ($options['ranges'] as $range) { // TODO what if size unknown? 500? if (isset($range['start'])) { $from = $range['start']; $to = !empty($range['end']) ? $range['end'] : $options['size']-1; } else { $from = $options['size'] - $range['last']-1; $to = $options['size'] -1; } $total = isset($options['size']) ? $options['size'] : "*"; $size = $to - $from + 1; $this->_multipart_byterange_header($options['mimetype'], $from, $to, $total); fseek($options['stream'], $from, SEEK_SET); while ($size && !feof($options['stream'])) { $buffer = fread($options['stream'], 4096); $size -= $this->bytes($buffer); echo $buffer; } } $this->_multipart_byterange_header(); // end multipart } } else { // normal request or stream isn't seekable, return full content if (isset($options['size'])) { header("Content-length: ".$options['size']); } fpassthru($options['stream']); return; // no more headers } } elseif (isset($options['data'])) { if (is_array($options['data'])) { // reply to partial request } else { header("Content-length: ".$this->bytes($options['data'])); echo $options['data']; } } } } if (!headers_sent()) { if (false === $status) { $this->http_status("404 not found"); } else { // TODO: check setting of headers in various code pathes above $this->http_status("$status"); } } } /** * parse HTTP Range: header * * @param array options array to store result in * @return void */ function _get_ranges(&$options) { // process Range: header if present if (isset($this->_SERVER['HTTP_RANGE'])) { // we only support standard "bytes" range specifications for now if (preg_match('/bytes\s*=\s*(.+)/', $this->_SERVER['HTTP_RANGE'], $matches)) { $options["ranges"] = array(); // ranges are comma separated foreach (explode(",", $matches[1]) as $range) { // ranges are either from-to pairs or just end positions list($start, $end) = explode("-", $range); $options["ranges"][] = ($start==="") ? array("last"=>$end) : array("start"=>$start, "end"=>$end); } } } } /** * generate separator headers for multipart response * * first and last call happen without parameters to generate * the initial header and closing sequence, all calls inbetween * require content mimetype, start and end byte position and * optionaly the total byte length of the requested resource * * @param string mimetype * @param int start byte position * @param int end byte position * @param int total resource byte size */ function _multipart_byterange_header($mimetype = false, $from = false, $to=false, $total=false) { if ($mimetype === false) { if (!isset($this->multipart_separator)) { // initial // a little naive, this sequence *might* be part of the content // but it's really not likely and rather expensive to check $this->multipart_separator = "SEPARATOR_".md5(microtime()); // generate HTTP header header("Content-type: multipart/byteranges; boundary=".$this->multipart_separator); } else { // final // generate closing multipart sequence echo "\n--{$this->multipart_separator}--"; } } else { // generate separator and header for next part echo "\n--{$this->multipart_separator}\n"; echo "Content-type: $mimetype\n"; echo "Content-range: $from-$to/". ($total === false ? "*" : $total); echo "\n\n"; } } // }}} // {{{ http_HEAD() /** * HEAD method handler * * @param void * @return void */ function http_HEAD() { $status = false; $options = Array(); $options["path"] = $this->path; if (method_exists($this, "HEAD")) { $status = $this->head($options); } else if (method_exists($this, "GET")) { ob_start(); $status = $this->GET($options); if (!isset($options['size'])) { $options['size'] = ob_get_length(); } ob_end_clean(); } if (!isset($options['mimetype'])) { $options['mimetype'] = "application/octet-stream"; } header("Content-type: $options[mimetype]"); if (isset($options['mtime'])) { header("Last-modified:".gmdate("D, d M Y H:i:s ", $options['mtime'])."GMT"); } if (isset($options['size'])) { header("Content-length: ".$options['size']); } if ($status === true) $status = "200 OK"; if ($status === false) $status = "404 Not found"; $this->http_status($status); } // }}} // {{{ http_PUT() /** * PUT method handler * * @param void * @return void */ function http_PUT() { if ($this->_check_lock_status($this->path)) { $options = Array(); $options["path"] = $this->path; $options["content_length"] = $this->_SERVER["CONTENT_LENGTH"]; // get the Content-type if (isset($this->_SERVER["CONTENT_TYPE"])) { // for now we do not support any sort of multipart requests if (!strncmp($this->_SERVER["CONTENT_TYPE"], "multipart/", 10)) { $this->http_status("501 not implemented"); echo "The service does not support mulipart PUT requests"; return; } $options["content_type"] = $this->_SERVER["CONTENT_TYPE"]; } else { // default content type if none given $options["content_type"] = "application/octet-stream"; } /* RFC 2616 2.6 says: "The recipient of the entity MUST NOT ignore any Content-* (e.g. Content-Range) headers that it does not understand or implement and MUST return a 501 (Not Implemented) response in such cases." */ foreach ($this->_SERVER as $key => $val) { if (strncmp($key, "HTTP_CONTENT", 11)) continue; switch ($key) { case 'HTTP_CONTENT_ENCODING': // RFC 2616 14.11 // TODO support this if ext/zlib filters are available $this->http_status("501 not implemented"); echo "The service does not support '$val' content encoding"; return; case 'HTTP_CONTENT_LANGUAGE': // RFC 2616 14.12 // we assume it is not critical if this one is ignored // in the actual PUT implementation ... $options["content_language"] = $val; break; case 'HTTP_CONTENT_LOCATION': // RFC 2616 14.14 /* The meaning of the Content-Location header in PUT or POST requests is undefined; servers are free to ignore it in those cases. */ break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -