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

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.

References array.

Referenced by http_OPTIONS(), and serveRequest().

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  }
Create styles array
The data for the language used.
+ 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.

References $_SERVER.

Referenced by serveRequest().

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']
+ 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.

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

Referenced by serveRequest().

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((!isset($_SERVER['DOCUMENT_ROOT'])) OR(empty($_SERVER['DOCUMENT_ROOT']))) $_SERVER['DOCUMENT_ROOT']
_if_header_parser($str)
parse If: header
Definition: Server.php:1725
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
+ 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.

References $_SERVER, and $path.

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

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  }
if((!isset($_SERVER['DOCUMENT_ROOT'])) OR(empty($_SERVER['DOCUMENT_ROOT']))) $_SERVER['DOCUMENT_ROOT']
+ 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

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.

Referenced by _check_if_header_conditions().

1858  {
1859  // not really implemented here,
1860  // implementations must override
1861  return true;
1862  }
+ Here is the caller graph for this function:

◆ _copymove()

HTTP_WebDAV_Server::_copymove (   $what)

Definition at line 1464 of file Server.php.

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

Referenced by http_COPY(), and http_MOVE().

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($_SERVER['DOCUMENT_ROOT'])) OR(empty($_SERVER['DOCUMENT_ROOT']))) $_SERVER['DOCUMENT_ROOT']
_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
_check_lock_status($path, $exclusive_only=false)
Definition: Server.php:1871
Create styles array
The data for the language used.
if(!isset($_REQUEST['ReturnTo'])) if(!isset($_REQUEST['AuthId'])) $options
Definition: as_login.php:20
+ 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.

References $_SERVER, $end, $options, and array.

Referenced by http_GET().

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  }
if((!isset($_SERVER['DOCUMENT_ROOT'])) OR(empty($_SERVER['DOCUMENT_ROOT']))) $_SERVER['DOCUMENT_ROOT']
$end
Definition: saml1-acs.php:18
Create styles array
The data for the language used.
if(!isset($_REQUEST['ReturnTo'])) if(!isset($_REQUEST['AuthId'])) $options
Definition: as_login.php:20
+ 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.

References $type, $uri, and array.

Referenced by _if_header_parser().

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
Create styles array
The data for the language used.
+ 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.

References $list, $uri, _if_header_lexer(), and array.

Referenced by _check_if_header_conditions().

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(isset($_REQUEST['delete'])) $list
Definition: registry.php:41
_if_header_lexer($string, &$pos)
Definition: Server.php:1671
Create styles array
The data for the language used.
+ 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.

References $total, and header.

Referenced by http_GET().

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
Add a drawing to the header
Definition: 04printing.php:69
+ 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.

References _new_uuid().

Referenced by http_LOCK().

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

References $n.

Referenced by _new_locktoken().

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
+ 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.

References $text.

Referenced by http_PROPFIND(), and http_PROPPATCH().

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
+ 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.

References $path.

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

◆ _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.

References $path, and $result.

Referenced by _copymove(), and serveRequest().

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
+ 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.

References $url, and array.

Referenced by http_PROPPATCH().

1975  {
1976  return strtr($url, array(" "=>"%20",
1977  "&"=>"%26",
1978  "<"=>"%3C",
1979  ">"=>"%3E",
1980  ));
1981  }
Create styles array
The data for the language used.
$url
+ 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.

References _copymove().

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  }
+ 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.

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

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  }
if((!isset($_SERVER['DOCUMENT_ROOT'])) OR(empty($_SERVER['DOCUMENT_ROOT']))) $_SERVER['DOCUMENT_ROOT']
http_status($status)
set HTTP return status and mirror it in a private header
Definition: Server.php:1949
_check_lock_status($path, $exclusive_only=false)
Definition: Server.php:1871
Create styles array
The data for the language used.
if(!isset($_REQUEST['ReturnTo'])) if(!isset($_REQUEST['AuthId'])) $options
Definition: as_login.php:20
+ 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.

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

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  }
_get_ranges(&$options)
parse HTTP Range: header
Definition: Server.php:996
$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
$from
$total
Definition: Utf8Test.php:87
http_status($status)
set HTTP return status and mirror it in a private header
Definition: Server.php:1949
Add a drawing to the header
Definition: 04printing.php:69
Create styles array
The data for the language used.
if(!isset($_REQUEST['ReturnTo'])) if(!isset($_REQUEST['AuthId'])) $options
Definition: as_login.php:20
+ 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.

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

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  }
http_status($status)
set HTTP return status and mirror it in a private header
Definition: Server.php:1949
Create styles array
The data for the language used.
if(!isset($_REQUEST['ReturnTo'])) if(!isset($_REQUEST['AuthId'])) $options
Definition: as_login.php:20
+ 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.

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

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  }
if((!isset($_SERVER['DOCUMENT_ROOT'])) OR(empty($_SERVER['DOCUMENT_ROOT']))) $_SERVER['DOCUMENT_ROOT']
http_status($status)
set HTTP return status and mirror it in a private header
Definition: Server.php:1949
_new_locktoken()
create a new opaque lock token as defined in RFC2518
Definition: Server.php:1655
_check_lock_status($path, $exclusive_only=false)
Definition: Server.php:1871
Add a drawing to the header
Definition: 04printing.php:69
Create styles array
The data for the language used.
Add data(end) time
Method that wraps PHPs time in order to allow simulations with the workflow.
if(!isset($_REQUEST['ReturnTo'])) if(!isset($_REQUEST['AuthId'])) $options
Definition: as_login.php:20
+ 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.

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

841  {
842  $options = array();
843  $options["path"] = $this->path;
844 
845  $stat = $this->mkcol($options);
846 
847  $this->http_status($stat);
848  }
http_status($status)
set HTTP return status and mirror it in a private header
Definition: Server.php:1949
Create styles array
The data for the language used.
if(!isset($_REQUEST['ReturnTo'])) if(!isset($_REQUEST['AuthId'])) $options
Definition: as_login.php:20
+ 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.

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

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  }
http_status($status)
set HTTP return status and mirror it in a private header
Definition: Server.php:1949
_check_lock_status($path, $exclusive_only=false)
Definition: Server.php:1871
+ 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

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

output
  • size -
Returns
int HTTP-Statuscode PUT implementation

PUT implementation

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

COPY implementation

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

MOVE implementation

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

DELETE implementation

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

PROPFIND implementation

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

PROPPATCH implementation

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

LOCK implementation

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

UNLOCK implementation

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

overload this method to retrieve and confirm authentication information

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

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.

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

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  }
_allow()
check for implemented HTTP methods
Definition: Server.php:1530
http_status($status)
set HTTP return status and mirror it in a private header
Definition: Server.php:1949
Add a drawing to the header
Definition: 04printing.php:69
Create styles array
The data for the language used.
writelog($message)
Writes a message to the logfile.,.
Definition: Server.php:2042
+ 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.

References $_SERVER, $file, $files, $key, $options, $path, _prop_encode(), array, header, http_status(), lockdiscovery(), and mkprop().

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
if((!isset($_SERVER['DOCUMENT_ROOT'])) OR(empty($_SERVER['DOCUMENT_ROOT']))) $_SERVER['DOCUMENT_ROOT']
http_status($status)
set HTTP return status and mirror it in a private header
Definition: Server.php:1949
mkprop()
helper for property element creation
Definition: Server.php:1571
Add a drawing to the header
Definition: 04printing.php:69
Create styles array
The data for the language used.
lockdiscovery($path)
Generate lockdiscovery reply from checklock() result.
Definition: Server.php:1901
if(!file_exists("$old.txt")) if($old===$new) if(file_exists("$new.txt")) $file
_prop_encode($text)
UTF-8 encode property values if not already done so.
Definition: Server.php:2009
$key
Definition: croninfo.php:18
if(!isset($_REQUEST['ReturnTo'])) if(!isset($_REQUEST['AuthId'])) $options
Definition: as_login.php:20
+ 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.

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

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  }
if((!isset($_SERVER['DOCUMENT_ROOT'])) OR(empty($_SERVER['DOCUMENT_ROOT']))) $_SERVER['DOCUMENT_ROOT']
_urlencode($url)
private minimalistic version of PHP urlencode()
Definition: Server.php:1974
http_status($status)
set HTTP return status and mirror it in a private header
Definition: Server.php:1949
_check_lock_status($path, $exclusive_only=false)
Definition: Server.php:1871
Add a drawing to the header
Definition: 04printing.php:69
Create styles array
The data for the language used.
_prop_encode($text)
UTF-8 encode property values if not already done so.
Definition: Server.php:2009
if(!isset($_REQUEST['ReturnTo'])) if(!isset($_REQUEST['AuthId'])) $options
Definition: as_login.php:20
+ 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.

References $_SERVER, $key, $options, $path, GuzzleHttp\Psr7\$stream, _check_lock_status(), array, and http_status().

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  }
if((!isset($_SERVER['DOCUMENT_ROOT'])) OR(empty($_SERVER['DOCUMENT_ROOT']))) $_SERVER['DOCUMENT_ROOT']
$stream
PHP stream implementation.
http_status($status)
set HTTP return status and mirror it in a private header
Definition: Server.php:1949
_check_lock_status($path, $exclusive_only=false)
Definition: Server.php:1871
Create styles array
The data for the language used.
$key
Definition: croninfo.php:18
if(!isset($_REQUEST['ReturnTo'])) if(!isset($_REQUEST['AuthId'])) $options
Definition: as_login.php:20
+ 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.

References header.

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(), serveRequest(), and ilDAVServer\serveRequest().

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  }
Add a drawing to the header
Definition: 04printing.php:69
+ 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.

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

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  }
if((!isset($_SERVER['DOCUMENT_ROOT'])) OR(empty($_SERVER['DOCUMENT_ROOT']))) $_SERVER['DOCUMENT_ROOT']
http_status($status)
set HTTP return status and mirror it in a private header
Definition: Server.php:1949
Create styles array
The data for the language used.
if(!isset($_REQUEST['ReturnTo'])) if(!isset($_REQUEST['AuthId'])) $options
Definition: as_login.php:20
+ 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.

References $path, and time.

Referenced by http_PROPFIND().

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  }
Add data(end) time
Method that wraps PHPs time in order to allow simulations with the workflow.
+ 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.

References array.

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

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  }
Create styles array
The data for the language used.
+ 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

Definition at line 125 of file Server.php.

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

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  }
if((!isset($_SERVER['DOCUMENT_ROOT'])) OR(empty($_SERVER['DOCUMENT_ROOT']))) $_SERVER['DOCUMENT_ROOT']
_allow()
check for implemented HTTP methods
Definition: Server.php:1530
_check_if_header_conditions()
check if conditions from "If:" headers are meat
Definition: Server.php:1810
_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
Add a drawing to the header
Definition: 04printing.php:69
_check_auth()
check authentication if check is implemented
Definition: Server.php:1593
writelog($message)
Writes a message to the logfile.,.
Definition: Server.php:2042
+ 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.

Definition at line 2042 of file Server.php.

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

Referenced by http_OPTIONS(), and serveRequest().

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  }
global $DIC
Definition: saml.php:7
catch(Exception $e) $message
$ilUser
Definition: imgupload.php:18
+ 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: