ILIAS  release_5-3 Revision v5.3.23-19-g915713cf615
HTTP_WebDAV_Server Class Reference
+ Inheritance diagram for HTTP_WebDAV_Server:
+ Collaboration diagram for HTTP_WebDAV_Server:

Public Member Functions

 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

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

Detailed Description

Definition at line 37 of file Server.php.

Constructor & Destructor Documentation

◆ __construct()

HTTP_WebDAV_Server::__construct ( )
private

Constructor.

Parameters
void

Reimplemented in ilDAVServer.

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 }

Member Function Documentation

◆ _allow()

HTTP_WebDAV_Server::_allow ( )

check for implemented HTTP methods

Parameters
void
Returns
array something

Definition at line 1530 of file Server.php.

1531 {
1532 // OPTIONS is always there
1533 $allow = array("OPTIONS" =>"OPTIONS");
1534
1535 // all other METHODS need both a http_method() wrapper
1536 // and a method() implementation
1537 // the base class supplies wrappers only
1538 foreach (get_class_methods($this) as $method) {
1539 if (!strncmp("http_", $method, 5)) {
1540 $method = strtoupper(substr($method, 5));
1541 if (method_exists($this, $method)) {
1542 $allow[$method] = $method;
1543 }
1544 }
1545 }
1546
1547 // we can emulate a missing HEAD implemetation using GET
1548 if (isset($allow["GET"])) {
1549 $allow["HEAD"] = "HEAD";
1550 }
1551
1552 // no LOCK without checklok()
1553 if (!method_exists($this, "checklock")) {
1554 unset($allow["LOCK"]);
1555 unset($allow["UNLOCK"]);
1556 }
1557
1558 return $allow;
1559 }

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 1593 of file Server.php.

1594 {
1595 if (method_exists($this, "checkAuth")) {
1596 // PEAR style method name
1597 return $this->checkAuth(
1598 @$_SERVER["AUTH_TYPE"],
1599 @$_SERVER["PHP_AUTH_USER"],
1600 @$_SERVER["PHP_AUTH_PW"]
1601 );
1602 } elseif (method_exists($this, "check_auth")) {
1603 // old (pre 1.0) method name
1604 return $this->check_auth(
1605 @$_SERVER["AUTH_TYPE"],
1606 @$_SERVER["PHP_AUTH_USER"],
1607 @$_SERVER["PHP_AUTH_PW"]
1608 );
1609 } else {
1610 // no method found -> no authentication required
1611 return true;
1612 }
1613 }
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 1810 of file Server.php.

1811 {
1812 if (isset($_SERVER["HTTP_IF"])) {
1813 $this->_if_header_uris =
1814 $this->_if_header_parser($_SERVER["HTTP_IF"]);
1815
1816 foreach ($this->_if_header_uris as $uri => $conditions) {
1817 if ($uri == "") {
1818 $uri = $this->uri;
1819 }
1820 // all must match
1821 $state = true;
1822 foreach ($conditions as $condition) {
1823 // lock tokens may be free form (RFC2518 6.3)
1824 // but if opaquelocktokens are used (RFC2518 6.4)
1825 // we have to check the format (litmus tests this)
1826 if (!strncmp($condition, "<opaquelocktoken:", strlen("<opaquelocktoken"))) {
1827 if (!preg_match("/^<opaquelocktoken:[[:xdigit:]]{8}-[[:xdigit:]]{4}-[[:xdigit:]]{4}-[[:xdigit:]]{4}-[[:xdigit:]]{12}>$/", $condition)) {
1828 return false;
1829 }
1830 }
1831 if (!$this->_check_uri_condition($uri, $condition)) {
1832 $state = false;
1833 break;
1834 }
1835 }
1836
1837 // any match is ok
1838 if ($state == true) {
1839 return true;
1840 }
1841 }
1842 return false;
1843 }
1844 return true;
1845 }
if(!array_key_exists('stateid', $_REQUEST)) $state
Handle linkback() response from LinkedIn.
Definition: linkback.php:10
_check_uri_condition($uri, $condition)
Check a single URI condition parsed from an if-header.
Definition: Server.php:1857
_if_header_parser($str)
parse If: header
Definition: Server.php:1725

References $_SERVER, $state, $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 1871 of file Server.php.

1872 {
1873 // FIXME depth -> ignored for now
1874 if (method_exists($this, "checkLock")) {
1875 // is locked?
1876 $lock = $this->checkLock($path);
1877
1878 // ... and lock is not owned?
1879 if (is_array($lock) && count($lock)) {
1880 // FIXME doesn't check uri restrictions yet
1881 if (!strstr($_SERVER["HTTP_IF"], $lock["token"])) {
1882 if (!$exclusive_only || ($lock["scope"] !== "shared")) {
1883 return false;
1884 }
1885 }
1886 }
1887 }
1888 return true;
1889 }

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 1857 of file Server.php.

1858 {
1859 // not really implemented here,
1860 // implementations must override
1861 return true;
1862 }

Referenced by _check_if_header_conditions().

+ Here is the caller graph for this function:

◆ _copymove()

HTTP_WebDAV_Server::_copymove (   $what)

Definition at line 1464 of file Server.php.

1465 {
1466 //$this->writelog('_copymove('.$what.')');
1467 $options = array();
1468 $options["path"] = $this->path;
1469
1470 if (isset($_SERVER["HTTP_DEPTH"])) {
1471 $options["depth"] = $_SERVER["HTTP_DEPTH"];
1472 } else {
1473 $options["depth"] = "infinity";
1474 }
1475 //$this->writelog('_copymove dest='.$_SERVER["HTTP_DESTINATION"]);
1476 extract(parse_url($_SERVER["HTTP_DESTINATION"]));
1477 // BEGIN WebDAV: decode path (bereits in PEAR CVS gefixt)
1478 // We must decode the target path too.
1479 $path = $this->_urldecode($path);
1480 // END Patch WebDAV: decode path
1481 $http_host = $host;
1482 if (isset($port) && $port != 80) {
1483 $http_host.= ":$port";
1484 }
1485
1486 list($http_header_host, $http_header_port) = explode(":", $_SERVER["HTTP_HOST"]);
1487 if (isset($http_header_port) && $http_header_port != 80) {
1488 $http_header_host .= ":" . $http_header_port;
1489 }
1490
1491 if ($http_host == $http_header_host &&
1492 !strncmp(
1493 $_SERVER["SCRIPT_NAME"],
1494 $path,
1495 strlen($_SERVER["SCRIPT_NAME"])
1496 )) {
1497 $options["dest"] = substr($path, strlen($_SERVER["SCRIPT_NAME"]));
1498 //$this->writelog('_copymove() dest='.$options['dest']);
1499 if (!$this->_check_lock_status($options["dest"])) {
1500 //$this->writelog('_copymove():423 Locked');
1501 $this->http_status("423 Locked");
1502 return;
1503 }
1504 //$this->writelog('_copymove() ...');
1505 } else {
1506 $options["dest_url"] = $_SERVER["HTTP_DESTINATION"];
1507 }
1508
1509 // see RFC 2518 Sections 9.6, 8.8.4 and 8.9.3
1510 if (isset($_SERVER["HTTP_OVERWRITE"])) {
1511 $options["overwrite"] = $_SERVER["HTTP_OVERWRITE"] == "T";
1512 } else {
1513 $options["overwrite"] = true;
1514 }
1515
1516 $stat = $this->$what($options);
1517 $this->http_status($stat);
1518 }
if(!isset( $_REQUEST[ 'ReturnTo'])) if(!isset($_REQUEST['AuthId'])) $options
Definition: as_login.php:20
_check_lock_status($path, $exclusive_only=false)
Definition: Server.php:1871
_urldecode($path)
private version of PHP urldecode
Definition: Server.php:1991
http_status($status)
set HTTP return status and mirror it in a private header
Definition: Server.php:1949

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 996 of file Server.php.

997 {
998 // process Range: header if present
999 if (isset($_SERVER['HTTP_RANGE'])) {
1000
1001 // we only support standard "bytes" range specifications for now
1002 if (preg_match("/bytes[[:space:]]*=[[:space:]]*(.+)/", $_SERVER['HTTP_RANGE'], $matches)) {
1003 $options["ranges"] = array();
1004
1005 // ranges are comma separated
1006 foreach (explode(",", $matches[1]) as $range) {
1007 // ranges are either from-to pairs or just end positions
1008 list($start, $end) = explode("-", $range);
1009 $options["ranges"][] = ($start==="")
1010 ? array("last"=>$end)
1011 : array("start"=>$start, "end"=>$end);
1012 }
1013 }
1014 }
1015 }
$end
Definition: saml1-acs.php:18

References $_SERVER, $end, 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 1671 of file Server.php.

1672 {
1673 // skip whitespace
1674 while (ctype_space($string{$pos})) {
1675 ++$pos;
1676 }
1677
1678 // already at end of string?
1679 if (strlen($string) <= $pos) {
1680 return false;
1681 }
1682
1683 // get next character
1684 $c = $string{$pos++};
1685
1686 // now it depends on what we found
1687 switch ($c) {
1688 case "<":
1689 // URIs are enclosed in <...>
1690 $pos2 = strpos($string, ">", $pos);
1691 $uri = substr($string, $pos, $pos2 - $pos);
1692 $pos = $pos2 + 1;
1693 return array("URI", $uri);
1694
1695 case "[":
1696 //Etags are enclosed in [...]
1697 if ($string{$pos} == "W") {
1698 $type = "ETAG_WEAK";
1699 $pos += 2;
1700 } else {
1701 $type = "ETAG_STRONG";
1702 }
1703 $pos2 = strpos($string, "]", $pos);
1704 $etag = substr($string, $pos + 1, $pos2 - $pos - 2);
1705 $pos = $pos2 + 1;
1706 return array($type, $etag);
1707
1708 case "N":
1709 // "N" indicates negation
1710 $pos += 2;
1711 return array("NOT", "Not");
1712
1713 default:
1714 // anything else is passed verbatim char by char
1715 return array("CHAR", $c);
1716 }
1717 }
$type

References $type, and $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 1725 of file Server.php.

1726 {
1727 $pos = 0;
1728 $len = strlen($str);
1729
1730 $uris = array();
1731
1732 // parser loop
1733 while ($pos < $len) {
1734 // get next token
1735 $token = $this->_if_header_lexer($str, $pos);
1736
1737 // check for URI
1738 if ($token[0] == "URI") {
1739 $uri = $token[1]; // remember URI
1740 $token = $this->_if_header_lexer($str, $pos); // get next token
1741 } else {
1742 $uri = "";
1743 }
1744
1745 // sanity check
1746 if ($token[0] != "CHAR" || $token[1] != "(") {
1747 return false;
1748 }
1749
1750 $list = array();
1751 $level = 1;
1752 $not = "";
1753 while ($level) {
1754 $token = $this->_if_header_lexer($str, $pos);
1755 if ($token[0] == "NOT") {
1756 $not = "!";
1757 continue;
1758 }
1759 switch ($token[0]) {
1760 case "CHAR":
1761 switch ($token[1]) {
1762 case "(":
1763 $level++;
1764 break;
1765 case ")":
1766 $level--;
1767 break;
1768 default:
1769 return false;
1770 }
1771 break;
1772
1773 case "URI":
1774 $list[] = $not . "<$token[1]>";
1775 break;
1776
1777 case "ETAG_WEAK":
1778 $list[] = $not . "[W/'$token[1]']>";
1779 break;
1780
1781 case "ETAG_STRONG":
1782 $list[] = $not . "['$token[1]']>";
1783 break;
1784
1785 default:
1786 return false;
1787 }
1788 $not = "";
1789 }
1790
1791 if (@is_array($uris[$uri])) {
1792 $uris[$uri] = array_merge($uris[$uri], $list);
1793 } else {
1794 $uris[$uri] = $list;
1795 }
1796 }
1797
1798 return $uris;
1799 }
_if_header_lexer($string, &$pos)
Definition: Server.php:1671
if(isset($_REQUEST['delete'])) $list
Definition: registry.php:41

References $list, $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 1030 of file Server.php.

1031 {
1032 if ($mimetype === false) {
1033 if (!isset($this->multipart_separator)) {
1034 // initial
1035
1036 // a little naive, this sequence *might* be part of the content
1037 // but it's really not likely and rather expensive to check
1038 $this->multipart_separator = "SEPARATOR_" . md5(microtime());
1039
1040 // generate HTTP header
1041 header("Content-type: multipart/byteranges; boundary=" . $this->multipart_separator);
1042 } else {
1043 // final
1044
1045 // generate closing multipart sequence
1046 echo "\n--{$this->multipart_separator}--";
1047 }
1048 } else {
1049 // generate separator and header for next part
1050 echo "\n--{$this->multipart_separator}\n";
1051 echo "Content-type: $mimetype\n";
1052 echo "Content-range: $from-$to/" . ($total === false ? "*" : $total);
1053 echo "\n\n";
1054 }
1055 }
$total
Definition: Utf8Test.php:87

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 1655 of file Server.php.

1656 {
1657 return "opaquelocktoken:" . $this->_new_uuid();
1658 }
_new_uuid()
generate Unique Universal IDentifier for lock token
Definition: Server.php:1625

References _new_uuid().

Referenced by http_LOCK().

+ Here is the call graph for this function:
+ 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 1625 of file Server.php.

1626 {
1627 // use uuid extension from PECL if available
1628 if (function_exists("uuid_create")) {
1629 return uuid_create();
1630 }
1631
1632 // fallback
1633 $uuid = md5(microtime() . getmypid()); // this should be random enough for now
1634
1635 // set variant and version fields for 'true' random uuid
1636 $uuid{12} = "4";
1637 $n = 8 + (ord($uuid{16}) & 3);
1638 $hex = "0123456789abcdef";
1639 $uuid{16} = $hex{$n};
1640
1641 // return formated uuid
1642 return substr($uuid, 0, 8) . "-"
1643 . substr($uuid, 8, 4) . "-"
1644 . substr($uuid, 12, 4) . "-"
1645 . substr($uuid, 16, 4) . "-"
1646 . substr($uuid, 20);
1647 }
$n
Definition: RandomTest.php:85

References $n.

Referenced by _new_locktoken().

+ Here is the caller graph for this function:

◆ _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 2009 of file Server.php.

2010 {
2011 switch (strtolower($this->_prop_encoding)) {
2012 case "utf-8":
2013 return $text;
2014 case "iso-8859-1":
2015 case "iso-8859-15":
2016 case "latin-1":
2017 default:
2018 return utf8_encode($text);
2019 }
2020 }
$text
Definition: errorreport.php:18

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 2028 of file Server.php.

2029 {
2030 if ($path[strlen($path)-1] != '/') {
2031 $path = $path . "/";
2032 }
2033 return $path;
2034 }

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 1991 of file Server.php.

1992 {
1993 // BEGIN WebDAV
1994 // urldecode wrongly replaces '+' characters by ' ' characters.
1995 // We replace '+' into '%2b' before passing the path through urldecode.
1996 //return urldecode($path);
1997 $result =&urldecode(str_replace('+', '%2b', $path));
1998 //$this->writelog('_urldecode('.$path.'):'.$result);
1999 return $result;
2000 // END PATCH WebDAV
2001 }
$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 1974 of file Server.php.

1975 {
1976 return strtr($url, array(" "=>"%20",
1977 "&"=>"%26",
1978 "<"=>"%3C",
1979 ">"=>"%3E",
1980 ));
1981 }
$url

References $url.

Referenced by http_PROPPATCH().

+ Here is the caller graph for this function:

◆ http_COPY()

HTTP_WebDAV_Server::http_COPY ( )

COPY method handler.

Parameters
void
Returns
void

Definition at line 1283 of file Server.php.

1284 {
1285 // no need to check source lock status here
1286 // destination lock status is always checked by the helper method
1287 $this->_copymove("copy");
1288 }

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 1248 of file Server.php.

1249 {
1250 // check RFC 2518 Section 9.2, last paragraph
1251 if (isset($_SERVER["HTTP_DEPTH"])) {
1252 if ($_SERVER["HTTP_DEPTH"] != "infinity") {
1253 $this->http_status("400 Bad Request");
1254 return;
1255 }
1256 }
1257
1258 // check lock status
1259 if ($this->_check_lock_status($this->path)) {
1260 // ok, proceed
1261 $options = array();
1262 $options["path"] = $this->path;
1263
1264 $stat = $this->delete($options);
1265
1266 $this->http_status($stat);
1267 } else {
1268 // sorry, its locked
1269 $this->http_status("423 Locked");
1270 }
1271 }

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 861 of file Server.php.

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

References $from, $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 1069 of file Server.php.

1070 {
1071 $status = false;
1072 $options = array();
1073 $options["path"] = $this->path;
1074
1075 if (method_exists($this, "HEAD")) {
1076 $status = $this->head($options);
1077 } elseif (method_exists($this, "GET")) {
1078 ob_start();
1079 $status = $this->GET($options);
1080 ob_end_clean();
1081 }
1082
1083 if ($status===true) {
1084 $status = "200 OK";
1085 }
1086 if ($status===false) {
1087 $status = "404 Not found";
1088 }
1089
1090 $this->http_status($status);
1091 }

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 1323 of file Server.php.

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

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 840 of file Server.php.

841 {
842 $options = array();
843 $options["path"] = $this->path;
844
845 $stat = $this->mkcol($options);
846
847 $this->http_status($stat);
848 }

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 1300 of file Server.php.

1301 {
1302 //$this->writelog('MOVE()');
1303 if ($this->_check_lock_status($this->path)) {
1304 // destination lock status is always checked by the helper method
1305 $this->_copymove("move");
1306 } else {
1307 //$this->writelog('MOVE():423 Locked');
1308 $this->http_status("423 Locked");
1309 }
1310 }

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 471 of file Server.php.

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

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 505 of file Server.php.

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

References $_SERVER, $file, $files, $key, $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 783 of file Server.php.

784 {
785 if ($this->_check_lock_status($this->path)) {
786 $options = array();
787 $options["path"] = $this->path;
788
789 $propinfo = new _parse_proppatch("php://input");
790
791 if (!$propinfo->success) {
792 $this->http_status("400 Error");
793 return;
794 }
795
796 $options['props'] = $propinfo->props;
797
798 $responsedescr = $this->proppatch($options);
799
800 $this->http_status("207 Multi-Status");
801 header('Content-Type: text/xml; charset="utf-8"');
802
803 echo "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n";
804
805 echo "<D:multistatus xmlns:D=\"DAV:\">\n";
806 echo " <D:response>\n";
807 echo " <D:href>" . $this->_urlencode($_SERVER["SCRIPT_NAME"] . $this->path) . "</D:href>\n";
808
809 foreach ($options["props"] as $prop) {
810 echo " <D:propstat>\n";
811 echo " <D:prop><$prop[name] xmlns=\"$prop[ns]\"/></D:prop>\n";
812 echo " <D:status>HTTP/1.1 $prop[status]</D:status>\n";
813 echo " </D:propstat>\n";
814 }
815
816 if ($responsedescr) {
817 echo " <D:responsedescription>" .
818 $this->_prop_encode(htmlspecialchars($responsedescr)) .
819 "</D:responsedescription>\n";
820 }
821
822 echo " </D:response>\n";
823 echo "</D:multistatus>\n";
824 } else {
825 $this->http_status("423 Locked");
826 }
827 }
_urlencode($url)
private minimalistic version of PHP urlencode()
Definition: Server.php:1974

References $_SERVER, $options, $path, _check_lock_status(), _prop_encode(), _urlencode(), 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 1103 of file Server.php.

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

References $_SERVER, $key, $options, $path, GuzzleHttp\Psr7\$stream, _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 1949 of file Server.php.

1950 {
1951 // simplified success case
1952 if ($status === true) {
1953 $status = "200 OK";
1954 }
1955 //$this->writelog('http_status('.$status.')');
1956
1957 // remember status
1958 $this->_http_status = $status;
1959
1960 // generate HTTP status response
1961 header("HTTP/1.1 $status");
1962 header("X-WebDAV-Status: $status", true);
1963 }

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 1438 of file Server.php.

1439 {
1440 $options = array();
1441 $options["path"] = $this->path;
1442
1443 if (isset($_SERVER['HTTP_DEPTH'])) {
1444 $options["depth"] = $_SERVER["HTTP_DEPTH"];
1445 } else {
1446 $options["depth"] = "infinity";
1447 }
1448
1449 // strip surrounding <>
1450 $options["token"] = substr(trim($_SERVER["HTTP_LOCK_TOKEN"]), 1, -1);
1451 //$this->writelog('http_UNLOCK HTTP_LOCK_TOKEN='.$_SERVER["HTTP_LOCK_TOKEN"]);
1452 // call user method
1453 $stat = $this->unlock($options);
1454
1455 $this->http_status($stat);
1456 }

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

+ Here is the call 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 1901 of file Server.php.

1902 {
1903 // no lock support without checklock() method
1904 if (!method_exists($this, "checklock")) {
1905 return "";
1906 }
1907
1908 // collect response here
1909 $activelocks = "";
1910
1911 // get checklock() reply
1912 $lock = $this->checklock($path);
1913
1914 // generate <activelock> block for returned data
1915 if (is_array($lock) && count($lock)) {
1916 // check for 'timeout' or 'expires'
1917 if (!empty($lock["expires"])) {
1918 $timeout = "Second-" . ($lock["expires"] - time());
1919 } elseif (!empty($lock["timeout"])) {
1920 $timeout = "Second-$lock[timeout]";
1921 } else {
1922 $timeout = "Infinite";
1923 }
1924
1925 // genreate response block
1926 $activelocks.= "
1927 <D:activelock>
1928 <D:lockscope><D:$lock[scope]/></D:lockscope>
1929 <D:locktype><D:$lock[type]/></D:locktype>
1930 <D:depth>$lock[depth]</D:depth>
1931 <D:owner>$lock[owner]</D:owner>
1932 <D:timeout>$timeout</D:timeout>
1933 <D:locktoken><D:href>$lock[token]</D:href></D:locktoken>
1934 </D:activelock>
1935 ";
1936 }
1937 //$this->writelog('lockdiscovery('.$path.'):'.$activeclocks);
1938
1939 // return generated response
1940 return $activelocks;
1941 }

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 1571 of file Server.php.

1572 {
1573 $args = func_get_args();
1574 if (count($args) == 3) {
1575 return array("ns" => $args[0],
1576 "name" => $args[1],
1577 "val" => $args[2]);
1578 } else {
1579 return array("ns" => "DAV:",
1580 "name" => $args[0],
1581 "val" => $args[1]);
1582 }
1583 }

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 $method = "get";
192 $this->writelog(__METHOD__ . ': Using head emulation by get.');
193 }
194
195 if (method_exists($this, $wrapper) && ($method == "options" || method_exists($this, $method))) {
196 $this->writelog(__METHOD__ . ': Calling wrapper: ' . $wrapper);
197 $this->$wrapper(); // call method by name
198 } else { // method not found/implemented
199 if ($_SERVER["REQUEST_METHOD"] == "LOCK") {
200 $this->writelog(__METHOD__ . ': Method not found/implemented. Sending 412');
201 $this->http_status("412 Precondition failed");
202 } else {
203 $this->writelog(__METHOD__ . ': Method not found/implemented. Sending allowd methods');
204 $this->http_status("405 Method not allowed");
205 header("Allow: " . join(", ", $this->_allow())); // tell client what's allowed
206 }
207 }
208 }
_check_if_header_conditions()
check if conditions from "If:" headers are meat
Definition: Server.php:1810
_check_auth()
check authentication if check is implemented
Definition: Server.php:1593

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 2042 of file Server.php.

2043 {
2044 global $DIC;
2045 $log = $DIC['log'];
2046 $ilUser = $DIC['ilUser'];
2047
2048 $log->write(
2049 $ilUser->getLogin()
2050 . ' DAV Server.' . str_replace("\n", ";", $message)
2051 );
2052 }
catch(Exception $e) $message
global $DIC
Definition: saml.php:7
$ilUser
Definition: imgupload.php:18

References $DIC, $ilUser, $log, and $message.

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: