ILIAS  release_5-1 Revision 5.0.0-5477-g43f3e3fab5f
HTTP_WebDAV_Server Class Reference
+ Inheritance diagram for HTTP_WebDAV_Server:
+ Collaboration diagram for HTTP_WebDAV_Server:

Public Member Functions

 HTTP_WebDAV_Server ()
 Constructor. More...
 
 serveRequest ()
 Serve WebDAV HTTP request. More...
 
 http_OPTIONS ()
 GET implementation. More...
 
 http_PROPFIND ()
 PROPFIND method handler. More...
 
 http_PROPPATCH ()
 PROPPATCH method handler. More...
 
 http_MKCOL ()
 MKCOL method handler. More...
 
 http_GET ()
 GET method handler. More...
 
 _get_ranges (&$options)
 parse HTTP Range: header More...
 
 _multipart_byterange_header ($mimetype=false, $from=false, $to=false, $total=false)
 generate separator headers for multipart response More...
 
 http_HEAD ()
 HEAD method handler. More...
 
 http_PUT ()
 PUT method handler. More...
 
 http_DELETE ()
 DELETE method handler. More...
 
 http_COPY ()
 COPY method handler. More...
 
 http_MOVE ()
 MOVE method handler. More...
 
 http_LOCK ()
 LOCK method handler. More...
 
 http_UNLOCK ()
 UNLOCK method handler. More...
 
 _copymove ($what)
 
 _allow ()
 check for implemented HTTP methods More...
 
 mkprop ()
 helper for property element creation More...
 
 _check_auth ()
 check authentication if check is implemented More...
 
 _new_uuid ()
 generate Unique Universal IDentifier for lock token More...
 
 _new_locktoken ()
 create a new opaque lock token as defined in RFC2518 More...
 
 _if_header_lexer ($string, &$pos)
 
 _if_header_parser ($str)
 parse If: header More...
 
 _check_if_header_conditions ()
 check if conditions from "If:" headers are meat More...
 
 _check_uri_condition ($uri, $condition)
 Check a single URI condition parsed from an if-header. More...
 
 _check_lock_status ($path, $exclusive_only=false)
 
 lockdiscovery ($path)
 Generate lockdiscovery reply from checklock() result. More...
 
 http_status ($status)
 set HTTP return status and mirror it in a private header More...
 
 _urlencode ($url)
 private minimalistic version of PHP urlencode() More...
 
 _urldecode ($path)
 private version of PHP urldecode More...
 
 _prop_encode ($text)
 UTF-8 encode property values if not already done so. More...
 
 _slashify ($path)
 Slashify - make sure path ends in a slash. More...
 

Data Fields

 $uri
 
 $base_uri
 
 $path
 
 $http_auth_realm = "PHP WebDAV"
 
 $dav_powered_by = ""
 
 $_if_header_uris = array()
 
 $_http_status = "200 OK"
 
 $_prop_encoding = "utf-8"
 

Private Member Functions

 writelog ($message)
 Writes a message to the logfile.,. More...
 

Detailed Description

Definition at line 37 of file Server.php.

Member Function Documentation

◆ _allow()

HTTP_WebDAV_Server::_allow ( )

check for implemented HTTP methods

Parameters
void
Returns
array something

Definition at line 1511 of file Server.php.

1512 {
1513 // OPTIONS is always there
1514 $allow = array("OPTIONS" =>"OPTIONS");
1515
1516 // all other METHODS need both a http_method() wrapper
1517 // and a method() implementation
1518 // the base class supplies wrappers only
1519 foreach(get_class_methods($this) as $method) {
1520 if (!strncmp("http_", $method, 5)) {
1521 $method = strtoupper(substr($method, 5));
1522 if (method_exists($this, $method)) {
1523 $allow[$method] = $method;
1524 }
1525 }
1526 }
1527
1528 // we can emulate a missing HEAD implemetation using GET
1529 if (isset($allow["GET"]))
1530 $allow["HEAD"] = "HEAD";
1531
1532 // no LOCK without checklok()
1533 if (!method_exists($this, "checklock")) {
1534 unset($allow["LOCK"]);
1535 unset($allow["UNLOCK"]);
1536 }
1537
1538 return $allow;
1539 }

Referenced by http_OPTIONS(), and serveRequest().

+ Here is the caller graph for this function:

◆ _check_auth()

HTTP_WebDAV_Server::_check_auth ( )

check authentication if check is implemented

Parameters
void
Returns
bool true if authentication succeded or not necessary

Definition at line 1573 of file Server.php.

1574 {
1575 if (method_exists($this, "checkAuth")) {
1576 // PEAR style method name
1577 return $this->checkAuth(@$_SERVER["AUTH_TYPE"],
1578 @$_SERVER["PHP_AUTH_USER"],
1579 @$_SERVER["PHP_AUTH_PW"]);
1580 } else if (method_exists($this, "check_auth")) {
1581 // old (pre 1.0) method name
1582 return $this->check_auth(@$_SERVER["AUTH_TYPE"],
1583 @$_SERVER["PHP_AUTH_USER"],
1584 @$_SERVER["PHP_AUTH_PW"]);
1585 } else {
1586 // no method found -> no authentication required
1587 return true;
1588 }
1589 }
if((!isset($_SERVER['DOCUMENT_ROOT'])) OR(empty($_SERVER['DOCUMENT_ROOT']))) $_SERVER['DOCUMENT_ROOT']

References $_SERVER.

Referenced by serveRequest().

+ Here is the caller graph for this function:

◆ _check_if_header_conditions()

HTTP_WebDAV_Server::_check_if_header_conditions ( )

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

Parameters
void
Returns
void

Definition at line 1786 of file Server.php.

1787 {
1788 if (isset($_SERVER["HTTP_IF"])) {
1789 $this->_if_header_uris =
1790 $this->_if_header_parser($_SERVER["HTTP_IF"]);
1791
1792 foreach($this->_if_header_uris as $uri => $conditions) {
1793 if ($uri == "") {
1794 $uri = $this->uri;
1795 }
1796 // all must match
1797 $state = true;
1798 foreach($conditions as $condition) {
1799 // lock tokens may be free form (RFC2518 6.3)
1800 // but if opaquelocktokens are used (RFC2518 6.4)
1801 // we have to check the format (litmus tests this)
1802 if (!strncmp($condition, "<opaquelocktoken:", strlen("<opaquelocktoken"))) {
1803 if (!ereg("^<opaquelocktoken:[[:xdigit:]]{8}-[[:xdigit:]]{4}-[[:xdigit:]]{4}-[[:xdigit:]]{4}-[[:xdigit:]]{12}>$", $condition)) {
1804 return false;
1805 }
1806 }
1807 if (!$this->_check_uri_condition($uri, $condition)) {
1808 $state = false;
1809 break;
1810 }
1811 }
1812
1813 // any match is ok
1814 if ($state == true) {
1815 return true;
1816 }
1817 }
1818 return false;
1819 }
1820 return true;
1821 }
_check_uri_condition($uri, $condition)
Check a single URI condition parsed from an if-header.
Definition: Server.php:1833
_if_header_parser($str)
parse If: header
Definition: Server.php:1701

References $_SERVER, $uri, _check_uri_condition(), and _if_header_parser().

Referenced by serveRequest().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ _check_lock_status()

HTTP_WebDAV_Server::_check_lock_status (   $path,
  $exclusive_only = false 
)
Parameters
stringpath of resource to check
boolexclusive lock?

Definition at line 1847 of file Server.php.

1848 {
1849 // FIXME depth -> ignored for now
1850 if (method_exists($this, "checkLock")) {
1851 // is locked?
1852 $lock = $this->checkLock($path);
1853
1854 // ... and lock is not owned?
1855 if (is_array($lock) && count($lock)) {
1856 // FIXME doesn't check uri restrictions yet
1857 if (!strstr($_SERVER["HTTP_IF"], $lock["token"])) {
1858 if (!$exclusive_only || ($lock["scope"] !== "shared"))
1859 return false;
1860 }
1861 }
1862 }
1863 return true;
1864 }

References $_SERVER, and $path.

Referenced by _copymove(), http_DELETE(), http_LOCK(), http_MOVE(), http_PROPPATCH(), and http_PUT().

+ Here is the caller graph for this function:

◆ _check_uri_condition()

HTTP_WebDAV_Server::_check_uri_condition (   $uri,
  $condition 
)

Check a single URI condition parsed from an if-header.

Check a single URI condition parsed from an if-header

@abstract

Parameters
string$uriURI to check
string$conditionCondition to check for this URI
Returns
bool Condition check result

Definition at line 1833 of file Server.php.

1834 {
1835 // not really implemented here,
1836 // implementations must override
1837 return true;
1838 }

Referenced by _check_if_header_conditions().

+ Here is the caller graph for this function:

◆ _copymove()

HTTP_WebDAV_Server::_copymove (   $what)

Definition at line 1448 of file Server.php.

1449 {
1450 //$this->writelog('_copymove('.$what.')');
1451 $options = Array();
1452 $options["path"] = $this->path;
1453
1454 if (isset($_SERVER["HTTP_DEPTH"])) {
1455 $options["depth"] = $_SERVER["HTTP_DEPTH"];
1456 } else {
1457 $options["depth"] = "infinity";
1458 }
1459//$this->writelog('_copymove dest='.$_SERVER["HTTP_DESTINATION"]);
1460 extract(parse_url($_SERVER["HTTP_DESTINATION"]));
1461 // BEGIN WebDAV: decode path (bereits in PEAR CVS gefixt)
1462 // We must decode the target path too.
1463 $path = $this->_urldecode($path);
1464 // END Patch WebDAV: decode path
1465 $http_host = $host;
1466 if (isset($port) && $port != 80)
1467 $http_host.= ":$port";
1468
1469 list($http_header_host,$http_header_port) = explode(":",$_SERVER["HTTP_HOST"]);
1470 if (isset($http_header_port) && $http_header_port != 80) {
1471 $http_header_host .= ":".$http_header_port;
1472 }
1473
1474 if ($http_host == $http_header_host &&
1475 !strncmp($_SERVER["SCRIPT_NAME"], $path,
1476 strlen($_SERVER["SCRIPT_NAME"]))) {
1477 $options["dest"] = substr($path, strlen($_SERVER["SCRIPT_NAME"]));
1478 //$this->writelog('_copymove() dest='.$options['dest']);
1479 if (!$this->_check_lock_status($options["dest"])) {
1480 //$this->writelog('_copymove():423 Locked');
1481 $this->http_status("423 Locked");
1482 return;
1483 }
1484 //$this->writelog('_copymove() ...');
1485
1486 } else {
1487 $options["dest_url"] = $_SERVER["HTTP_DESTINATION"];
1488 }
1489
1490 // see RFC 2518 Sections 9.6, 8.8.4 and 8.9.3
1491 if (isset($_SERVER["HTTP_OVERWRITE"])) {
1492 $options["overwrite"] = $_SERVER["HTTP_OVERWRITE"] == "T";
1493 } else {
1494 $options["overwrite"] = true;
1495 }
1496
1497 $stat = $this->$what($options);
1498 $this->http_status($stat);
1499 }
_check_lock_status($path, $exclusive_only=false)
Definition: Server.php:1847
_urldecode($path)
private version of PHP urldecode
Definition: Server.php:1966
http_status($status)
set HTTP return status and mirror it in a private header
Definition: Server.php:1924
if(!is_array($argv)) $options

References $_SERVER, $options, $path, _check_lock_status(), _urldecode(), and http_status().

Referenced by http_COPY(), and http_MOVE().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ _get_ranges()

HTTP_WebDAV_Server::_get_ranges ( $options)

parse HTTP Range: header

Parameters
arrayoptions array to store result in
Returns
void

Definition at line 986 of file Server.php.

987 {
988 // process Range: header if present
989 if (isset($_SERVER['HTTP_RANGE'])) {
990
991 // we only support standard "bytes" range specifications for now
992 if (ereg("bytes[[:space:]]*=[[:space:]]*(.+)", $_SERVER['HTTP_RANGE'], $matches)) {
993 $options["ranges"] = array();
994
995 // ranges are comma separated
996 foreach (explode(",", $matches[1]) as $range) {
997 // ranges are either from-to pairs or just end positions
998 list($start, $end) = explode("-", $range);
999 $options["ranges"][] = ($start==="")
1000 ? array("last"=>$end)
1001 : array("start"=>$start, "end"=>$end);
1002 }
1003 }
1004 }
1005 }

References $_SERVER, and $options.

Referenced by http_GET().

+ Here is the caller graph for this function:

◆ _if_header_lexer()

HTTP_WebDAV_Server::_if_header_lexer (   $string,
$pos 
)
Parameters
stringheader string to parse
intcurrent parsing position
Returns
array next token (type and value)

Definition at line 1647 of file Server.php.

1648 {
1649 // skip whitespace
1650 while (ctype_space($string{$pos})) {
1651 ++$pos;
1652 }
1653
1654 // already at end of string?
1655 if (strlen($string) <= $pos) {
1656 return false;
1657 }
1658
1659 // get next character
1660 $c = $string{$pos++};
1661
1662 // now it depends on what we found
1663 switch ($c) {
1664 case "<":
1665 // URIs are enclosed in <...>
1666 $pos2 = strpos($string, ">", $pos);
1667 $uri = substr($string, $pos, $pos2 - $pos);
1668 $pos = $pos2 + 1;
1669 return array("URI", $uri);
1670
1671 case "[":
1672 //Etags are enclosed in [...]
1673 if ($string{$pos} == "W") {
1674 $type = "ETAG_WEAK";
1675 $pos += 2;
1676 } else {
1677 $type = "ETAG_STRONG";
1678 }
1679 $pos2 = strpos($string, "]", $pos);
1680 $etag = substr($string, $pos + 1, $pos2 - $pos - 2);
1681 $pos = $pos2 + 1;
1682 return array($type, $etag);
1683
1684 case "N":
1685 // "N" indicates negation
1686 $pos += 2;
1687 return array("NOT", "Not");
1688
1689 default:
1690 // anything else is passed verbatim char by char
1691 return array("CHAR", $c);
1692 }
1693 }

References $uri.

Referenced by _if_header_parser().

+ Here is the caller graph for this function:

◆ _if_header_parser()

HTTP_WebDAV_Server::_if_header_parser (   $str)

parse If: header

Parameters
stringheader string
Returns
array URIs and their conditions

Definition at line 1701 of file Server.php.

1702 {
1703 $pos = 0;
1704 $len = strlen($str);
1705
1706 $uris = array();
1707
1708 // parser loop
1709 while ($pos < $len) {
1710 // get next token
1711 $token = $this->_if_header_lexer($str, $pos);
1712
1713 // check for URI
1714 if ($token[0] == "URI") {
1715 $uri = $token[1]; // remember URI
1716 $token = $this->_if_header_lexer($str, $pos); // get next token
1717 } else {
1718 $uri = "";
1719 }
1720
1721 // sanity check
1722 if ($token[0] != "CHAR" || $token[1] != "(") {
1723 return false;
1724 }
1725
1726 $list = array();
1727 $level = 1;
1728 $not = "";
1729 while ($level) {
1730 $token = $this->_if_header_lexer($str, $pos);
1731 if ($token[0] == "NOT") {
1732 $not = "!";
1733 continue;
1734 }
1735 switch ($token[0]) {
1736 case "CHAR":
1737 switch ($token[1]) {
1738 case "(":
1739 $level++;
1740 break;
1741 case ")":
1742 $level--;
1743 break;
1744 default:
1745 return false;
1746 }
1747 break;
1748
1749 case "URI":
1750 $list[] = $not."<$token[1]>";
1751 break;
1752
1753 case "ETAG_WEAK":
1754 $list[] = $not."[W/'$token[1]']>";
1755 break;
1756
1757 case "ETAG_STRONG":
1758 $list[] = $not."['$token[1]']>";
1759 break;
1760
1761 default:
1762 return false;
1763 }
1764 $not = "";
1765 }
1766
1767 if (@is_array($uris[$uri])) {
1768 $uris[$uri] = array_merge($uris[$uri],$list);
1769 } else {
1770 $uris[$uri] = $list;
1771 }
1772 }
1773
1774 return $uris;
1775 }
_if_header_lexer($string, &$pos)
Definition: Server.php:1647

References $uri, and _if_header_lexer().

Referenced by _check_if_header_conditions().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ _multipart_byterange_header()

HTTP_WebDAV_Server::_multipart_byterange_header (   $mimetype = false,
  $from = false,
  $to = false,
  $total = false 
)

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

Parameters
stringmimetype
intstart byte position
intend byte position
inttotal resource byte size

Definition at line 1020 of file Server.php.

1021 {
1022 if ($mimetype === false) {
1023 if (!isset($this->multipart_separator)) {
1024 // initial
1025
1026 // a little naive, this sequence *might* be part of the content
1027 // but it's really not likely and rather expensive to check
1028 $this->multipart_separator = "SEPARATOR_".md5(microtime());
1029
1030 // generate HTTP header
1031 header("Content-type: multipart/byteranges; boundary=".$this->multipart_separator);
1032 } else {
1033 // final
1034
1035 // generate closing multipart sequence
1036 echo "\n--{$this->multipart_separator}--";
1037 }
1038 } else {
1039 // generate separator and header for next part
1040 echo "\n--{$this->multipart_separator}\n";
1041 echo "Content-type: $mimetype\n";
1042 echo "Content-range: $from-$to/". ($total === false ? "*" : $total);
1043 echo "\n\n";
1044 }
1045 }

References $total.

Referenced by http_GET().

+ Here is the caller graph for this function:

◆ _new_locktoken()

HTTP_WebDAV_Server::_new_locktoken ( )

create a new opaque lock token as defined in RFC2518

Parameters
void
Returns
string new RFC2518 opaque lock token

Definition at line 1631 of file Server.php.

1632 {
1633 return "opaquelocktoken:".$this->_new_uuid();
1634 }

Referenced by http_LOCK().

+ Here is the caller graph for this function:

◆ _new_uuid()

HTTP_WebDAV_Server::_new_uuid ( )

generate Unique Universal IDentifier for lock token

Parameters
void
Returns
string a new UUID

Definition at line 1601 of file Server.php.

1602 {
1603 // use uuid extension from PECL if available
1604 if (function_exists("uuid_create")) {
1605 return uuid_create();
1606 }
1607
1608 // fallback
1609 $uuid = md5(microtime().getmypid()); // this should be random enough for now
1610
1611 // set variant and version fields for 'true' random uuid
1612 $uuid{12} = "4";
1613 $n = 8 + (ord($uuid{16}) & 3);
1614 $hex = "0123456789abcdef";
1615 $uuid{16} = $hex{$n};
1616
1617 // return formated uuid
1618 return substr($uuid, 0, 8)."-"
1619 . substr($uuid, 8, 4)."-"
1620 . substr($uuid, 12, 4)."-"
1621 . substr($uuid, 16, 4)."-"
1622 . substr($uuid, 20);
1623 }
$n
Definition: RandomTest.php:80

References $n.

◆ _prop_encode()

HTTP_WebDAV_Server::_prop_encode (   $text)

UTF-8 encode property values if not already done so.

Parameters
stringtext to encode
Returns
string utf-8 encoded text

Definition at line 1984 of file Server.php.

1985 {
1986 switch (strtolower($this->_prop_encoding)) {
1987 case "utf-8":
1988 return $text;
1989 case "iso-8859-1":
1990 case "iso-8859-15":
1991 case "latin-1":
1992 default:
1993 return utf8_encode($text);
1994 }
1995 }
$text

References $text.

Referenced by http_PROPFIND(), and http_PROPPATCH().

+ Here is the caller graph for this function:

◆ _slashify()

HTTP_WebDAV_Server::_slashify (   $path)

Slashify - make sure path ends in a slash.

Parameters
stringdirectory path
Returns
string directory path wiht trailing slash

Definition at line 2003 of file Server.php.

2003 {
2004 if ($path[strlen($path)-1] != '/') {
2005 $path = $path."/";
2006 }
2007 return $path;
2008 }

References $path.

◆ _urldecode()

HTTP_WebDAV_Server::_urldecode (   $path)

private version of PHP urldecode

not really needed but added for completenes

Parameters
stringURL to decode
Returns
string decoded URL

Definition at line 1966 of file Server.php.

1967 {
1968 // BEGIN WebDAV
1969 // urldecode wrongly replaces '+' characters by ' ' characters.
1970 // We replace '+' into '%2b' before passing the path through urldecode.
1971 //return urldecode($path);
1972 $result =& urldecode(str_replace('+','%2b',$path));
1973 //$this->writelog('_urldecode('.$path.'):'.$result);
1974 return $result;
1975 // END PATCH WebDAV
1976 }
$result

References $path, and $result.

Referenced by _copymove(), and serveRequest().

+ Here is the caller graph for this function:

◆ _urlencode()

HTTP_WebDAV_Server::_urlencode (   $url)

private minimalistic version of PHP urlencode()

only blanks and XML special chars must be encoded here full urlencode() encoding confuses some clients ...

Parameters
stringURL to encode
Returns
string encoded URL

Definition at line 1949 of file Server.php.

1950 {
1951 return strtr($url, array(" "=>"%20",
1952 "&"=>"%26",
1953 "<"=>"%3C",
1954 ">"=>"%3E",
1955 ));
1956 }
$url
Definition: shib_logout.php:72

References $url.

◆ http_COPY()

HTTP_WebDAV_Server::http_COPY ( )

COPY method handler.

Parameters
void
Returns
void

Definition at line 1267 of file Server.php.

1268 {
1269 // no need to check source lock status here
1270 // destination lock status is always checked by the helper method
1271 $this->_copymove("copy");
1272 }

References _copymove().

+ Here is the call graph for this function:

◆ http_DELETE()

HTTP_WebDAV_Server::http_DELETE ( )

DELETE method handler.

Parameters
void
Returns
void

Definition at line 1232 of file Server.php.

1233 {
1234 // check RFC 2518 Section 9.2, last paragraph
1235 if (isset($_SERVER["HTTP_DEPTH"])) {
1236 if ($_SERVER["HTTP_DEPTH"] != "infinity") {
1237 $this->http_status("400 Bad Request");
1238 return;
1239 }
1240 }
1241
1242 // check lock status
1243 if ($this->_check_lock_status($this->path)) {
1244 // ok, proceed
1245 $options = Array();
1246 $options["path"] = $this->path;
1247
1248 $stat = $this->delete($options);
1249
1250 $this->http_status($stat);
1251 } else {
1252 // sorry, its locked
1253 $this->http_status("423 Locked");
1254 }
1255 }

References $_SERVER, $options, $path, _check_lock_status(), and http_status().

+ Here is the call graph for this function:

◆ http_GET()

HTTP_WebDAV_Server::http_GET ( )

GET method handler.

Parameters
void
Returns
void

Definition at line 851 of file Server.php.

852 {
853 // TODO check for invalid stream
854 $options = Array();
855 $options["path"] = $this->path;
856
857 $this->_get_ranges($options);
858
859 if (true === ($status = $this->get($options))) {
860 if (!headers_sent()) {
861 $status = "200 OK";
862
863 if (!isset($options['mimetype'])) {
864 $options['mimetype'] = "application/octet-stream";
865 }
866 header("Content-type: $options[mimetype]");
867
868 if (isset($options['mtime'])) {
869 header("Last-modified:".gmdate("D, d M Y H:i:s ", $options['mtime'])."GMT");
870 }
871
872 if (isset($options['stream'])) {
873 // GET handler returned a stream
874 if (!empty($options['ranges']) && (0===fseek($options['stream'], 0, SEEK_SET))) {
875 // partial request and stream is seekable
876
877 if (count($options['ranges']) === 1) {
878 $range = $options['ranges'][0];
879
880 if (isset($range['start'])) {
881 fseek($options['stream'], $range['start'], SEEK_SET);
882 if (feof($options['stream'])) {
883 $this->http_status("416 Requested range not satisfiable");
884 exit;
885 }
886
887 if (isset($range['end'])) {
888 $size = $range['end']-$range['start']+1;
889 $this->http_status("206 partial");
890 header("Content-length: $size");
891 header("Content-range: $range[start]-$range[end]/"
892 . (isset($options['size']) ? $options['size'] : "*"));
893 while ($size && !feof($options['stream'])) {
894 $buffer = fread($options['stream'], 4096);
895 $size -= strlen($buffer);
896 echo $buffer;
897 }
898 } else {
899 $this->http_status("206 partial");
900 if (isset($options['size'])) {
901 header("Content-length: ".($options['size'] - $range['start']));
902 header("Content-range: $start-$end/"
903 . (isset($options['size']) ? $options['size'] : "*"));
904 }
905 fpassthru($options['stream']);
906 }
907 } else {
908 header("Content-length: ".$range['last']);
909 fseek($options['stream'], -$range['last'], SEEK_END);
910 fpassthru($options['stream']);
911 }
912 } else {
913 $this->_multipart_byterange_header(); // init multipart
914 foreach ($options['ranges'] as $range) {
915 // TODO what if size unknown? 500?
916 if (isset($range['start'])) {
917 $from = $range['start'];
918 $to = !empty($range['end']) ? $range['end'] : $options['size']-1;
919 } else {
920 $from = $options['size'] - $range['last']-1;
921 $to = $options['size'] -1;
922 }
923 $total = isset($options['size']) ? $options['size'] : "*";
924 $size = $to - $from + 1;
925 $this->_multipart_byterange_header($options['mimetype'], $from, $to, $total);
926
927
928 fseek($options['stream'], $start, SEEK_SET);
929 while ($size && !feof($options['stream'])) {
930 $buffer = fread($options['stream'], 4096);
931 $size -= strlen($buffer);
932 echo $buffer;
933 }
934 }
935 $this->_multipart_byterange_header(); // end multipart
936 }
937 } else {
938 // normal request or stream isn't seekable, return full content
939 if (isset($options['size'])) {
940 header("Content-length: ".$options['size']);
941 }
942
943 // BEGIN WebDAV W. Randelshofer
944 // fpassthru apparently only delivers up to 2 million bytes.
945 // use fread instead
946 //fpassthru($options['stream']);
947 while (! feof($options['stream'])) {
948 $buffer = fread($options['stream'], 4096);
949 echo $buffer;
950 }
951 // END PATCH WebDAV W. Randelshofer
952
953 return; // no more headers
954 }
955 } elseif (isset($options['data'])) {
956 if (is_array($options['data'])) {
957 // reply to partial request
958 } else {
959 header("Content-length: ".strlen($options['data']));
960 echo $options['data'];
961 }
962 }
963 }
964 }
965
966 if (false === $status) {
967 // BEGIN WebDAV Randelshofer
968 $status = '404 Not Found';
969 //$this->http_status("404 not found");
970 // END PATCH WebDAV Randelshofer
971 }
972
973 if (!headers_sent()) {
974 // TODO: check setting of headers in various code pathes above
975 $this->http_status("$status");
976 }
977 }
$size
Definition: RandomTest.php:79
_multipart_byterange_header($mimetype=false, $from=false, $to=false, $total=false)
generate separator headers for multipart response
Definition: Server.php:1020
_get_ranges(&$options)
parse HTTP Range: header
Definition: Server.php:986
exit
Definition: login.php:54

References $options, $path, $size, $total, _get_ranges(), _multipart_byterange_header(), exit, and http_status().

+ Here is the call graph for this function:

◆ http_HEAD()

HTTP_WebDAV_Server::http_HEAD ( )

HEAD method handler.

Parameters
void
Returns
void

Definition at line 1059 of file Server.php.

1060 {
1061 $status = false;
1062 $options = Array();
1063 $options["path"] = $this->path;
1064
1065 if (method_exists($this, "HEAD")) {
1066 $status = $this->head($options);
1067 } else if (method_exists($this, "GET")) {
1068 ob_start();
1069 $status = $this->GET($options);
1070 ob_end_clean();
1071 }
1072
1073 if($status===true) $status = "200 OK";
1074 if($status===false) $status = "404 Not found";
1075
1076 $this->http_status($status);
1077 }

References $options, $path, and http_status().

+ Here is the call graph for this function:

◆ http_LOCK()

HTTP_WebDAV_Server::http_LOCK ( )

LOCK method handler.

Parameters
void
Returns
void

Definition at line 1307 of file Server.php.

1308 {
1309 $options = Array();
1310 $options["path"] = $this->path;
1311
1312 if (isset($_SERVER['HTTP_DEPTH'])) {
1313 $options["depth"] = $_SERVER["HTTP_DEPTH"];
1314 } else {
1315 $options["depth"] = "infinity";
1316 }
1317
1318 if (isset($_SERVER["HTTP_TIMEOUT"])) {
1319 $options["timeout"] = explode(",", $_SERVER["HTTP_TIMEOUT"]);
1320 }
1321
1322 if(empty($_SERVER['CONTENT_LENGTH']) && !empty($_SERVER['HTTP_IF'])) {
1323 // check if locking is possible
1324 if(!$this->_check_lock_status($this->path)) {
1325 $this->http_status("423 Locked");
1326 return;
1327 }
1328
1329 // refresh lock
1330 $options["update"] = substr($_SERVER['HTTP_IF'], 2, -2);
1331 $stat = $this->lock($options);
1332 } else {
1333 // extract lock request information from request XML payload
1334 $lockinfo = new _parse_lockinfo("php://input");
1335 if (!$lockinfo->success) {
1336 $this->http_status("400 bad request");
1337 }
1338
1339 // check if locking is possible
1340 if(!$this->_check_lock_status($this->path, $lockinfo->lockscope === "shared")) {
1341 $this->http_status("423 Locked");
1342 return;
1343 }
1344
1345 // new lock
1346 $options["scope"] = $lockinfo->lockscope;
1347 $options["type"] = $lockinfo->locktype;
1348 $options["owner"] = $lockinfo->owner;
1349
1350 $options["locktoken"] = $this->_new_locktoken();
1351
1352 $stat = $this->lock($options);
1353 }
1354
1355 if(is_bool($stat)) {
1356 $http_stat = $stat ? "200 OK" : "423 Locked";
1357 } else {
1358 $http_stat = $stat;
1359 }
1360
1361 $this->http_status($http_stat);
1362
1363 if ($http_stat{0} == 2) { // 2xx states are ok
1364 if($options["timeout"]) {
1365 // more than a million is considered an absolute timestamp
1366 // less is more likely a relative value
1367 if($options["timeout"]>1000000) {
1368 $timeout = "Second-".($options['timeout']-time());
1369 } else {
1370 $timeout = "Second-$options[timeout]";
1371 }
1372 } else {
1373 $timeout = "Infinite";
1374 }
1375 /*
1376 $this->writelog(
1377 'Content-Type: text/xml; charset="utf-8"'
1378 ."Lock-Token: <$options[locktoken]>"
1379 . "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
1380 . "<D:prop xmlns:D=\"DAV:\">\n"
1381 . " <D:lockdiscovery>\n"
1382 . " <D:activelock>\n"
1383 . " <D:lockscope><D:$options[scope]/></D:lockscope>\n"
1384 . " <D:locktype><D:$options[type]/></D:locktype>\n"
1385 . " <D:depth>$options[depth]</D:depth>\n"
1386 . " <D:owner>$options[owner]</D:owner>\n"
1387 . " <D:timeout>$timeout</D:timeout>\n"
1388 . " <D:locktoken><D:href>$options[locktoken]</D:href></D:locktoken>\n"
1389 . " </D:activelock>\n"
1390 . " </D:lockdiscovery>\n"
1391 . "</D:prop>\n\n"
1392 );*/
1393 header('Content-Type: text/xml; charset="utf-8"');
1394 header("Lock-Token: <$options[locktoken]>");
1395 echo "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n";
1396 echo "<D:prop xmlns:D=\"DAV:\">\n";
1397 echo " <D:lockdiscovery>\n";
1398 echo " <D:activelock>\n";
1399 echo " <D:lockscope><D:$options[scope]/></D:lockscope>\n";
1400 echo " <D:locktype><D:$options[type]/></D:locktype>\n";
1401 echo " <D:depth>$options[depth]</D:depth>\n";
1402 echo " <D:owner>$options[owner]</D:owner>\n";
1403 echo " <D:timeout>$timeout</D:timeout>\n";
1404 echo " <D:locktoken><D:href>$options[locktoken]</D:href></D:locktoken>\n";
1405 echo " </D:activelock>\n";
1406 echo " </D:lockdiscovery>\n";
1407 echo "</D:prop>\n\n";
1408 }
1409 }
_new_locktoken()
create a new opaque lock token as defined in RFC2518
Definition: Server.php:1631

References $_SERVER, $options, $path, _check_lock_status(), _new_locktoken(), and http_status().

+ Here is the call graph for this function:

◆ http_MKCOL()

HTTP_WebDAV_Server::http_MKCOL ( )

MKCOL method handler.

Parameters
void
Returns
void

Definition at line 830 of file Server.php.

831 {
832 $options = Array();
833 $options["path"] = $this->path;
834
835 $stat = $this->mkcol($options);
836
837 $this->http_status($stat);
838 }

References $options, $path, and http_status().

+ Here is the call graph for this function:

◆ http_MOVE()

HTTP_WebDAV_Server::http_MOVE ( )

MOVE method handler.

Parameters
void
Returns
void

Definition at line 1284 of file Server.php.

1285 {
1286 //$this->writelog('MOVE()');
1287 if ($this->_check_lock_status($this->path)) {
1288 // destination lock status is always checked by the helper method
1289 $this->_copymove("move");
1290 } else {
1291 //$this->writelog('MOVE():423 Locked');
1292 $this->http_status("423 Locked");
1293 }
1294 }

References _check_lock_status(), _copymove(), and http_status().

+ Here is the call graph for this function:

◆ http_OPTIONS()

HTTP_WebDAV_Server::http_OPTIONS ( )

GET implementation.

overload this method to retrieve resources from your server

@abstract

Parameters
array&$paramsArray of input and output parameters
input
  • path -

output
  • size -
Returns
int HTTP-Statuscode PUT implementation

PUT implementation

@abstract

Parameters
array&$params
Returns
int HTTP-Statuscode COPY implementation

COPY implementation

@abstract

Parameters
array&$params
Returns
int HTTP-Statuscode MOVE implementation

MOVE implementation

@abstract

Parameters
array&$params
Returns
int HTTP-Statuscode DELETE implementation

DELETE implementation

@abstract

Parameters
array&$params
Returns
int HTTP-Statuscode PROPFIND implementation

PROPFIND implementation

@abstract

Parameters
array&$params
Returns
int HTTP-Statuscode PROPPATCH implementation

PROPPATCH implementation

@abstract

Parameters
array&$params
Returns
int HTTP-Statuscode LOCK implementation

LOCK implementation

@abstract

Parameters
array&$params
Returns
int HTTP-Statuscode UNLOCK implementation

UNLOCK implementation

@abstract

Parameters
array&$params
Returns
int HTTP-Statuscode check authentication

overload this method to retrieve and confirm authentication information

@abstract

Parameters
stringtype Authentication type, e.g. "basic" or "digest"
stringusername Transmitted username
stringpasswort Transmitted password
Returns
bool Authentication status check lock status for a resource

overload this method to return shared and exclusive locks active for this resource

@abstract

Parameters
stringresource Resource path to check
Returns
array An array of lock entries each consisting of 'type' ('shared'/'exclusive'), 'token' and 'timeout' OPTIONS method handler

The OPTIONS method handler creates a valid OPTIONS reply including Dav: and Allowed: headers based on the implemented methods found in the actual instance

Parameters
void
Returns
void

Definition at line 478 of file Server.php.

479 {
480 // Microsoft clients default to the Frontpage protocol
481 // unless we tell them to use WebDAV
482 header("MS-Author-Via: DAV");
483
484 // get allowed methods
485 $allow = $this->_allow();
486
487 // dav header
488 $dav = array(1); // assume we are always dav class 1 compliant
489 if (isset($allow['LOCK'])) {
490 $dav[] = 2; // dav class 2 requires that locking is supported
491 }
492
493 // tell clients what we found
494 $this->http_status("200 OK");
495 header("DAV: " .join("," , $dav));
496 header("Allow: ".join(", ", $allow));
497 $this->writelog(__METHOD__.': dav='.var_export($dav,true).' allow='.var_export($allow,true));
498 header("Content-length: 0");
499 }
writelog($message)
Writes a message to the logfile.,.
Definition: Server.php:2016
_allow()
check for implemented HTTP methods
Definition: Server.php:1511

References _allow(), http_status(), and writelog().

+ Here is the call graph for this function:

◆ http_PROPFIND()

HTTP_WebDAV_Server::http_PROPFIND ( )

PROPFIND method handler.

Parameters
void
Returns
void

Definition at line 512 of file Server.php.

513 {
514 $options = Array();
515 $options["path"] = $this->path;
516
517 // search depth from header (default is "infinity)
518 if (isset($_SERVER['HTTP_DEPTH'])) {
519 $options["depth"] = $_SERVER["HTTP_DEPTH"];
520 } else {
521 $options["depth"] = "infinity";
522 }
523
524 // analyze request payload
525 $propinfo = new _parse_propfind("php://input");
526 if (!$propinfo->success) {
527 $this->http_status("400 Error");
528 return;
529 }
530 $options['props'] = $propinfo->props;
531
532 // call user handler
533 $files = array();
534 if (!$this->propfind($options, $files)) {
535 $this->http_status("404 Not Found");
536 return;
537 }
538
539 // collect namespaces here
540 $ns_hash = array();
541
542 // Microsoft Clients need this special namespace for date and time values
543 $ns_defs = "xmlns:ns0=\"urn:uuid:c2f41010-65b3-11d1-a29f-00aa00c14882/\"";
544
545 // now we loop over all returned file entries
546 foreach($files["files"] as $filekey => $file) {
547
548 // nothing to do if no properties were returend for a file
549 if (!isset($file["props"]) || !is_array($file["props"])) {
550 continue;
551 }
552
553 // now loop over all returned properties
554 foreach($file["props"] as $key => $prop) {
555 // as a convenience feature we do not require that user handlers
556 // restrict returned properties to the requested ones
557 // here we strip all unrequested entries out of the response
558
559 switch($options['props']) {
560 case "all":
561 // nothing to remove
562 break;
563
564 case "names":
565 // only the names of all existing properties were requested
566 // so we remove all values
567 unset($files["files"][$filekey]["props"][$key]["val"]);
568 break;
569
570 default:
571 $found = false;
572
573 // search property name in requested properties
574 foreach((array)$options["props"] as $reqprop) {
575 if ( $reqprop["name"] == $prop["name"]
576 && $reqprop["xmlns"] == $prop["ns"]) {
577 $found = true;
578 break;
579 }
580 }
581
582 // unset property and continue with next one if not found/requested
583 if (!$found) {
584 $files["files"][$filekey]["props"][$key]="";
585 continue(2);
586 }
587 break;
588 }
589
590 // namespace handling
591 if (empty($prop["ns"])) continue; // no namespace
592 $ns = $prop["ns"];
593 if ($ns == "DAV:") continue; // default namespace
594 if (isset($ns_hash[$ns])) continue; // already known
595
596 // register namespace
597 $ns_name = "ns".(count($ns_hash) + 1);
598 $ns_hash[$ns] = $ns_name;
599 $ns_defs .= " xmlns:$ns_name=\"$ns\"";
600 }
601
602 // we also need to add empty entries for properties that were requested
603 // but for which no values where returned by the user handler
604 if (is_array($options['props'])) {
605 foreach($options["props"] as $reqprop) {
606 if($reqprop['name']=="") continue; // skip empty entries
607
608 $found = false;
609
610 // check if property exists in result
611 foreach($file["props"] as $prop) {
612 if ( $reqprop["name"] == $prop["name"]
613 && $reqprop["xmlns"] == $prop["ns"]) {
614 $found = true;
615 break;
616 }
617 }
618
619 if (!$found) {
620 if($reqprop["xmlns"]==="DAV:" && $reqprop["name"]==="lockdiscovery") {
621 // lockdiscovery is handled by the base class
622 $files["files"][$filekey]["props"][]
623 = $this->mkprop("DAV:",
624 "lockdiscovery" ,
625 $this->lockdiscovery($files["files"][$filekey]['path']));
626 } else {
627 // add empty value for this property
628 $files["files"][$filekey]["noprops"][] =
629 $this->mkprop($reqprop["xmlns"], $reqprop["name"], "");
630
631 // register property namespace if not known yet
632 if ($reqprop["xmlns"] != "DAV:" && !isset($ns_hash[$reqprop["xmlns"]])) {
633 $ns_name = "ns".(count($ns_hash) + 1);
634 $ns_hash[$reqprop["xmlns"]] = $ns_name;
635 $ns_defs .= " xmlns:$ns_name=\"$reqprop[xmlns]\"";
636 }
637 }
638 }
639 }
640 }
641 }
642
643 // now we generate the reply header ...
644 $this->http_status("207 Multi-Status");
645 header('Content-Type: text/xml; charset="utf-8"');
646
647 // ... and payload
648 echo "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n";
649 echo "<D:multistatus xmlns:D=\"DAV:\">\n";
650
651 foreach($files["files"] as $file) {
652 // ignore empty or incomplete entries
653 if(!is_array($file) || empty($file) || !isset($file["path"])) continue;
654 $path = $file['path'];
655 if(!is_string($path) || $path==="") continue;
656
657 echo " <D:response $ns_defs>\n";
658
659 // BEGIN WebDAV W. Randelshofer Don't slashify path because it confuses Mac OS X
660 //$href = $this->_slashify($_SERVER['SCRIPT_NAME'] . $path);
661 $href = $_SERVER['SCRIPT_NAME'] . $path;
662 //END PATCH WebDAV W. Randelshofer
663
664 echo " <D:href>$href</D:href>\n";
665
666 // report all found properties and their values (if any)
667 if (isset($file["props"]) && is_array($file["props"])) {
668 echo " <D:propstat>\n";
669 echo " <D:prop>\n";
670
671 foreach($file["props"] as $key => $prop) {
672
673 if (!is_array($prop)) continue;
674 if (!isset($prop["name"])) continue;
675 if (!isset($prop["val"]) || $prop["val"] === "" || $prop["val"] === false) {
676 // empty properties (cannot use empty() for check as "0" is a legal value here)
677 if($prop["ns"]=="DAV:") {
678 echo " <D:$prop[name]/>\n";
679 } else if(!empty($prop["ns"])) {
680 echo " <".$ns_hash[$prop["ns"]].":$prop[name]/>\n";
681 } else {
682 echo " <$prop[name] xmlns=\"\"/>";
683 }
684 } else if ($prop["ns"] == "DAV:") {
685 // some WebDAV properties need special treatment
686 switch ($prop["name"]) {
687 case "creationdate":
688 echo " <D:creationdate ns0:dt=\"dateTime.tz\">"
689 // BEGIN WebDAV W. Randelshofer
690 . gmdate("Y-m-d\\TH:i:s\\Z",$prop['val'])
691 // . gmdate("D, d M Y H:i:s ", $prop['val'])
692 // END PATCH WebDAV W. Randelshofer
693 . "</D:creationdate>\n";
694 break;
695 case "getlastmodified":
696 echo " <D:getlastmodified ns0:dt=\"dateTime.rfc1123\">"
697 . gmdate("D, d M Y H:i:s ", $prop['val'])
698 . "GMT</D:getlastmodified>\n";
699 break;
700 case "resourcetype":
701 echo " <D:resourcetype><D:$prop[val]/></D:resourcetype>\n";
702 break;
703 case "supportedlock":
704 echo " <D:supportedlock>$prop[val]</D:supportedlock>\n";
705 break;
706 case "lockdiscovery":
707 echo " <D:lockdiscovery>\n";
708 echo $prop["val"];
709 echo " </D:lockdiscovery>\n";
710 break;
711 default:
712 echo " <D:$prop[name]>"
713 . $this->_prop_encode(htmlspecialchars($prop['val']))
714 . "</D:$prop[name]>\n";
715 break;
716 }
717 } else {
718 // properties from namespaces != "DAV:" or without any namespace
719 if ($prop["ns"]) {
720 echo " <" . $ns_hash[$prop["ns"]] . ":$prop[name]>"
721 . $this->_prop_encode(htmlspecialchars($prop['val']))
722 . "</" . $ns_hash[$prop["ns"]] . ":$prop[name]>\n";
723 } else {
724 echo " <$prop[name] xmlns=\"\">"
725 . $this->_prop_encode(htmlspecialchars($prop['val']))
726 . "</$prop[name]>\n";
727 }
728 }
729 }
730
731 echo " </D:prop>\n";
732 echo " <D:status>HTTP/1.1 200 OK</D:status>\n";
733 echo " </D:propstat>\n";
734 }
735
736 // now report all properties requested but not found
737 if (isset($file["noprops"])) {
738 echo " <D:propstat>\n";
739 echo " <D:prop>\n";
740
741 foreach($file["noprops"] as $key => $prop) {
742 if ($prop["ns"] == "DAV:") {
743 echo " <D:$prop[name]/>\n";
744 } else if ($prop["ns"] == "") {
745 echo " <$prop[name] xmlns=\"\"/>\n";
746 } else {
747 echo " <" . $ns_hash[$prop["ns"]] . ":$prop[name]/>\n";
748 }
749 }
750
751 echo " </D:prop>\n";
752 echo " <D:status>HTTP/1.1 404 Not Found</D:status>\n";
753 echo " </D:propstat>\n";
754 }
755
756 echo " </D:response>\n";
757 }
758
759 echo "</D:multistatus>\n";
760 }
print $file
_prop_encode($text)
UTF-8 encode property values if not already done so.
Definition: Server.php:1984
lockdiscovery($path)
Generate lockdiscovery reply from checklock() result.
Definition: Server.php:1876
mkprop()
helper for property element creation
Definition: Server.php:1551

References $_SERVER, $file, $options, $path, _prop_encode(), http_status(), lockdiscovery(), and mkprop().

+ Here is the call graph for this function:

◆ http_PROPPATCH()

HTTP_WebDAV_Server::http_PROPPATCH ( )

PROPPATCH method handler.

Parameters
void
Returns
void

Definition at line 773 of file Server.php.

774 {
775 if($this->_check_lock_status($this->path)) {
776 $options = Array();
777 $options["path"] = $this->path;
778
779 $propinfo = new _parse_proppatch("php://input");
780
781 if (!$propinfo->success) {
782 $this->http_status("400 Error");
783 return;
784 }
785
786 $options['props'] = $propinfo->props;
787
788 $responsedescr = $this->proppatch($options);
789
790 $this->http_status("207 Multi-Status");
791 header('Content-Type: text/xml; charset="utf-8"');
792
793 echo "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n";
794
795 echo "<D:multistatus xmlns:D=\"DAV:\">\n";
796 echo " <D:response>\n";
797 echo " <D:href>".$this->_urlencode($_SERVER["SCRIPT_NAME"].$this->path)."</D:href>\n";
798
799 foreach($options["props"] as $prop) {
800 echo " <D:propstat>\n";
801 echo " <D:prop><$prop[name] xmlns=\"$prop[ns]\"/></D:prop>\n";
802 echo " <D:status>HTTP/1.1 $prop[status]</D:status>\n";
803 echo " </D:propstat>\n";
804 }
805
806 if ($responsedescr) {
807 echo " <D:responsedescription>".
808 $this->_prop_encode(htmlspecialchars($responsedescr)).
809 "</D:responsedescription>\n";
810 }
811
812 echo " </D:response>\n";
813 echo "</D:multistatus>\n";
814 } else {
815 $this->http_status("423 Locked");
816 }
817 }

References $_SERVER, $options, $path, _check_lock_status(), _prop_encode(), and http_status().

+ Here is the call graph for this function:

◆ http_PUT()

HTTP_WebDAV_Server::http_PUT ( )

PUT method handler.

Parameters
void
Returns
void

Definition at line 1089 of file Server.php.

1090 {
1091 if ($this->_check_lock_status($this->path)) {
1092 $options = Array();
1093 $options["path"] = $this->path;
1094 $options["content_length"] = $_SERVER["CONTENT_LENGTH"];
1095
1096 // get the Content-type
1097 if (isset($_SERVER["CONTENT_TYPE"])) {
1098 // for now we do not support any sort of multipart requests
1099 if (!strncmp($_SERVER["CONTENT_TYPE"], "multipart/", 10)) {
1100 $this->http_status("501 not implemented");
1101 echo "The service does not support mulipart PUT requests";
1102 return;
1103 }
1104 $options["content_type"] = $_SERVER["CONTENT_TYPE"];
1105 } else {
1106 // default content type if none given
1107 $options["content_type"] = "application/octet-stream";
1108 }
1109
1110 /* RFC 2616 2.6 says: "The recipient of the entity MUST NOT
1111 ignore any Content-* (e.g. Content-Range) headers that it
1112 does not understand or implement and MUST return a 501
1113 (Not Implemented) response in such cases."
1114 */
1115 foreach ($_SERVER as $key => $val) {
1116 if (strncmp($key, "HTTP_CONTENT", 11)) continue;
1117 switch ($key) {
1118 case 'HTTP_CONTENT_ENCODING': // RFC 2616 14.11
1119 // TODO support this if ext/zlib filters are available
1120 $this->http_status("501 not implemented");
1121 echo "The service does not support '$val' content encoding";
1122 return;
1123
1124 case 'HTTP_CONTENT_LANGUAGE': // RFC 2616 14.12
1125 // we assume it is not critical if this one is ignored
1126 // in the actual PUT implementation ...
1127 $options["content_language"] = $value;
1128 break;
1129
1130 case 'HTTP_CONTENT_LOCATION': // RFC 2616 14.14
1131 /* The meaning of the Content-Location header in PUT
1132 or POST requests is undefined; servers are free
1133 to ignore it in those cases. */
1134 break;
1135
1136 case 'HTTP_CONTENT_RANGE': // RFC 2616 14.16
1137 // single byte range requests are supported
1138 // the header format is also specified in RFC 2616 14.16
1139 // TODO we have to ensure that implementations support this or send 501 instead
1140 if (!preg_match('@bytes\s+(\d+)-(\d+)/((\d+)|\*)@', $value, $matches)) {
1141 $this->http_status("400 bad request");
1142 echo "The service does only support single byte ranges";
1143 return;
1144 }
1145
1146 $range = array("start"=>$matches[1], "end"=>$matches[2]);
1147 if (is_numeric($matches[3])) {
1148 $range["total_length"] = $matches[3];
1149 }
1150 $option["ranges"][] = $range;
1151
1152 // TODO make sure the implementation supports partial PUT
1153 // this has to be done in advance to avoid data being overwritten
1154 // on implementations that do not support this ...
1155 break;
1156
1157 case 'HTTP_CONTENT_MD5': // RFC 2616 14.15
1158 // TODO: maybe we can just pretend here?
1159 $this->http_status("501 not implemented");
1160 echo "The service does not support content MD5 checksum verification";
1161 return;
1162
1163 case 'HTTP_CONTENT_LENGTH':
1164 // defined on IIS and has the same value as CONTENT_LENGTH
1165 break;
1166
1167 default:
1168 // any other unknown Content-* headers
1169 $this->http_status("501 not implemented");
1170 echo "The service does not support '$key'";
1171 return;
1172 }
1173 }
1174
1175 $options["stream"] = fopen("php://input", "r");
1176
1177 $stat = $this->PUT($options);
1178
1179 if ($stat == false) {
1180 $stat = "403 Forbidden";
1181 } else if (is_resource($stat) && get_resource_type($stat) == "stream") {
1182 $stream = $stat;
1183
1184 $stat = $options["new"] ? "201 Created" : "204 No Content";
1185
1186 if (!empty($options["ranges"])) {
1187 // TODO multipart support is missing (see also above)
1188 if (0 == fseek($stream, $range[0]["start"], SEEK_SET)) {
1189 $length = $range[0]["end"]-$range[0]["start"]+1;
1190 if (!fwrite($stream, fread($options["stream"], $length))) {
1191 $stat = "403 Forbidden";
1192 }
1193 } else {
1194 $stat = "403 Forbidden";
1195 }
1196 } else {
1197 while (!feof($options["stream"])) {
1198 // BEGIN WebDAV W. Randelshofer explicitly compare with false.
1199 if (false === ($written = fwrite($stream, fread($options["stream"], 4096)))) {
1200 // END WebDAV W. Randelshofer explicitly compare with false.
1201 $stat = "403 Forbidden";
1202 break;
1203 }
1204 $count += $written;
1205 }
1206 }
1207
1208 fclose($stream);
1209 //$this->writelog('PUT wrote '.$written.' bytes');
1210 // BEGIN WebDAV W. Randelshofer finish the put-operation
1211 $this->PUTfinished($options);
1212 // END WebDAV W. Randelshofer finish the put-operation
1213 }
1214
1215 $this->http_status($stat);
1216 } else {
1217 $this->http_status("423 Locked");
1218 }
1219 }

References $_SERVER, $options, $path, _check_lock_status(), and http_status().

+ Here is the call graph for this function:

◆ http_status()

HTTP_WebDAV_Server::http_status (   $status)

set HTTP return status and mirror it in a private header

Parameters
stringstatus code and message
Returns
void

Definition at line 1924 of file Server.php.

1925 {
1926 // simplified success case
1927 if($status === true) {
1928 $status = "200 OK";
1929 }
1930 //$this->writelog('http_status('.$status.')');
1931
1932 // remember status
1933 $this->_http_status = $status;
1934
1935 // generate HTTP status response
1936 header("HTTP/1.1 $status");
1937 header("X-WebDAV-Status: $status", true);
1938 }

Referenced by _copymove(), http_DELETE(), http_GET(), http_HEAD(), http_LOCK(), http_MKCOL(), http_MOVE(), http_OPTIONS(), http_PROPFIND(), http_PROPPATCH(), http_PUT(), http_UNLOCK(), ilDAVServer\serveRequest(), and serveRequest().

+ Here is the caller graph for this function:

◆ http_UNLOCK()

HTTP_WebDAV_Server::http_UNLOCK ( )

UNLOCK method handler.

Parameters
void
Returns
void

Definition at line 1422 of file Server.php.

1423 {
1424 $options = Array();
1425 $options["path"] = $this->path;
1426
1427 if (isset($_SERVER['HTTP_DEPTH'])) {
1428 $options["depth"] = $_SERVER["HTTP_DEPTH"];
1429 } else {
1430 $options["depth"] = "infinity";
1431 }
1432
1433 // strip surrounding <>
1434 $options["token"] = substr(trim($_SERVER["HTTP_LOCK_TOKEN"]), 1, -1);
1435//$this->writelog('http_UNLOCK HTTP_LOCK_TOKEN='.$_SERVER["HTTP_LOCK_TOKEN"]);
1436 // call user method
1437 $stat = $this->unlock($options);
1438
1439 $this->http_status($stat);
1440 }

References $_SERVER, $options, $path, and http_status().

+ Here is the call graph for this function:

◆ HTTP_WebDAV_Server()

HTTP_WebDAV_Server::HTTP_WebDAV_Server ( )

Constructor.

Parameters
void

Definition at line 108 of file Server.php.

109 {
110 // PHP messages destroy XML output -> switch them off
111 //ini_set("display_errors", 0);
112 }

Referenced by ilDAVServer\ilDAVServer().

+ Here is the caller graph for this function:

◆ lockdiscovery()

HTTP_WebDAV_Server::lockdiscovery (   $path)

Generate lockdiscovery reply from checklock() result.

Parameters
stringresource path to check
Returns
string lockdiscovery response

Definition at line 1876 of file Server.php.

1877 {
1878 // no lock support without checklock() method
1879 if (!method_exists($this, "checklock")) {
1880 return "";
1881 }
1882
1883 // collect response here
1884 $activelocks = "";
1885
1886 // get checklock() reply
1887 $lock = $this->checklock($path);
1888
1889 // generate <activelock> block for returned data
1890 if (is_array($lock) && count($lock)) {
1891 // check for 'timeout' or 'expires'
1892 if (!empty($lock["expires"])) {
1893 $timeout = "Second-".($lock["expires"] - time());
1894 } else if (!empty($lock["timeout"])) {
1895 $timeout = "Second-$lock[timeout]";
1896 } else {
1897 $timeout = "Infinite";
1898 }
1899
1900 // genreate response block
1901 $activelocks.= "
1902 <D:activelock>
1903 <D:lockscope><D:$lock[scope]/></D:lockscope>
1904 <D:locktype><D:$lock[type]/></D:locktype>
1905 <D:depth>$lock[depth]</D:depth>
1906 <D:owner>$lock[owner]</D:owner>
1907 <D:timeout>$timeout</D:timeout>
1908 <D:locktoken><D:href>$lock[token]</D:href></D:locktoken>
1909 </D:activelock>
1910 ";
1911 }
1912 //$this->writelog('lockdiscovery('.$path.'):'.$activeclocks);
1913
1914 // return generated response
1915 return $activelocks;
1916 }

References $path.

Referenced by http_PROPFIND().

+ Here is the caller graph for this function:

◆ mkprop()

HTTP_WebDAV_Server::mkprop ( )

helper for property element creation

Parameters
stringXML namespace (optional)
stringproperty name
stringproperty value
Returns
array property array

Definition at line 1551 of file Server.php.

1552 {
1553 $args = func_get_args();
1554 if (count($args) == 3) {
1555 return array("ns" => $args[0],
1556 "name" => $args[1],
1557 "val" => $args[2]);
1558 } else {
1559 return array("ns" => "DAV:",
1560 "name" => $args[0],
1561 "val" => $args[1]);
1562 }
1563 }

Referenced by ilDAVServer\fileinfo(), and http_PROPFIND().

+ Here is the caller graph for this function:

◆ serveRequest()

HTTP_WebDAV_Server::serveRequest ( )

Serve WebDAV HTTP request.

dispatch WebDAV HTTP request to the apropriate method handler

Parameters
void
Returns
void

Reimplemented in ilDAVServer.

Definition at line 125 of file Server.php.

126 {
127 // default uri is the complete request uri
128 // FIXME: use ilHTTPS::isDetected
129 $uri = (@$_SERVER["HTTPS"] === "on" ? "https:" : "http:");
130 $uri.= "//$_SERVER[HTTP_HOST]$_SERVER[SCRIPT_NAME]";
131
132 $this->base_uri = $uri;
133 $this->uri = $uri . $_SERVER[PATH_INFO];
134
135 // identify ourselves
136 if (empty($this->dav_powered_by)) {
137 header("X-Dav-Powered-By: PHP class: ".get_class($this));
138 } else {
139 header("X-Dav-Powered-By: ".$this->dav_powered_by );
140 }
141
142 $this->writelog(__METHOD__.': Using uri: '.$this->uri);
143
144 // check authentication
145 if (!$this->_check_auth()) {
146 // RFC2518 says we must use Digest instead of Basic
147 // but Microsoft Clients do not support Digest
148 // and we don't support NTLM and Kerberos
149 // so we are stuck with Basic here
150 header('WWW-Authenticate: Basic realm="'.($this->http_auth_realm).'"');
151
152 // Windows seems to require this being the last header sent
153 // (changed according to PECL bug #3138)
154 $this->http_status('401 Unauthorized');
155 $this->writelog('Check auth failed');
156
157 return;
158 }
159
160 // check
161 if(! $this->_check_if_header_conditions()) {
162 $this->writelog(__METHOD__.': Precondition failed.');
163 $this->http_status("412 Precondition failed");
164 return;
165 }
166
167 // set path
168 $this->path = $this->_urldecode($_SERVER["PATH_INFO"]);
169 if (!strlen($this->path)) {
170 header("Location: ".$this->base_uri."/");
171 $this->writelog('HTTP_WebDAV_Server.ServeRequest() missing path info');
172 $this->path = '/';
173 //exit;
174 }
175 // BEGIN WebDAV: Don't strip backslashes. Backslashes are a valid part of a unix filename!
176 /*
177 if(ini_get("magic_quotes_gpc")) {
178 $this->path = stripslashes($this->path);
179 }*/
180 // END PATCH WebDAV: Don't strip backslashes. Backslashes are a valid part of a unix filename!
181
182
183 // detect requested method names
184 $method = strtolower($_SERVER["REQUEST_METHOD"]);
185 $wrapper = "http_".$method;
186
187 $this->writelog(__METHOD__.': Using request method: '.$method);
188
189 // activate HEAD emulation by GET if no HEAD method found
190 if ($method == "head" && !method_exists($this, "head"))
191 {
192 $method = "get";
193 $this->writelog(__METHOD__.': Using head emulation by get.');
194 }
195
196 if (method_exists($this, $wrapper) && ($method == "options" || method_exists($this, $method)))
197 {
198 $this->writelog(__METHOD__.': Calling wrapper: '.$wrapper);
199 $this->$wrapper(); // call method by name
200 }
201 else
202 { // method not found/implemented
203 if ($_SERVER["REQUEST_METHOD"] == "LOCK")
204 {
205 $this->writelog(__METHOD__.': Method not found/implemented. Sending 412');
206 $this->http_status("412 Precondition failed");
207 }
208 else
209 {
210 $this->writelog(__METHOD__.': Method not found/implemented. Sending allowd methods');
211 $this->http_status("405 Method not allowed");
212 header("Allow: ".join(", ", $this->_allow())); // tell client what's allowed
213 }
214 }
215 }
_check_if_header_conditions()
check if conditions from "If:" headers are meat
Definition: Server.php:1786
_check_auth()
check authentication if check is implemented
Definition: Server.php:1573

References $_SERVER, $uri, _allow(), _check_auth(), _check_if_header_conditions(), _urldecode(), http_status(), and writelog().

+ Here is the call graph for this function:

◆ writelog()

HTTP_WebDAV_Server::writelog (   $message)
private

Writes a message to the logfile.,.

Parameters
messageString.
Returns
void.

Reimplemented in ilDAVServer.

Definition at line 2016 of file Server.php.

2017 {
2018 global $log, $ilUser;
2019
2020 $log->write(
2021 $ilUser->getLogin()
2022 .' DAV Server.'.str_replace("\n",";",$message)
2023 );
2024 /*
2025 if ($this->logFile)
2026 {
2027 $fh = fopen($this->logFile, 'a');
2028 fwrite($fh, date('Y-m-d h:i:s '));
2029 fwrite($fh, str_replace("\n",";",$message));
2030 fwrite($fh, "\n\n");
2031 fclose($fh);
2032 }*/
2033 }
global $ilUser
Definition: imgupload.php:15

References $ilUser, and $log.

Referenced by http_OPTIONS(), and serveRequest().

+ Here is the caller graph for this function:

Field Documentation

◆ $_http_status

HTTP_WebDAV_Server::$_http_status = "200 OK"

Definition at line 90 of file Server.php.

◆ $_if_header_uris

HTTP_WebDAV_Server::$_if_header_uris = array()

Definition at line 83 of file Server.php.

◆ $_prop_encoding

HTTP_WebDAV_Server::$_prop_encoding = "utf-8"

Definition at line 97 of file Server.php.

◆ $base_uri

HTTP_WebDAV_Server::$base_uri

Definition at line 54 of file Server.php.

◆ $dav_powered_by

HTTP_WebDAV_Server::$dav_powered_by = ""

Definition at line 76 of file Server.php.

◆ $http_auth_realm

HTTP_WebDAV_Server::$http_auth_realm = "PHP WebDAV"

Definition at line 69 of file Server.php.

◆ $path

◆ $uri


The documentation for this class was generated from the following file: