ILIAS  release_4-4 Revision
All Data Structures Namespaces Files Functions Variables Modules Pages
HTTP_WebDAV_Server Class Reference
+ Inheritance diagram for HTTP_WebDAV_Server:
+ Collaboration diagram for HTTP_WebDAV_Server:

Public Member Functions

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

Data Fields

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

Private Member Functions

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

Detailed Description

Definition at line 37 of file Server.php.

Member Function Documentation

◆ _allow()

HTTP_WebDAV_Server::_allow ( )

check for implemented HTTP methods

Parameters
void
Returns
array something

Definition at line 1507 of file Server.php.

Referenced by http_OPTIONS(), and serveRequest().

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

Referenced by serveRequest().

1570  {
1571  if (method_exists($this, "checkAuth")) {
1572  // PEAR style method name
1573  return $this->checkAuth(@$_SERVER["AUTH_TYPE"],
1574  @$_SERVER["PHP_AUTH_USER"],
1575  @$_SERVER["PHP_AUTH_PW"]);
1576  } else if (method_exists($this, "check_auth")) {
1577  // old (pre 1.0) method name
1578  return $this->check_auth(@$_SERVER["AUTH_TYPE"],
1579  @$_SERVER["PHP_AUTH_USER"],
1580  @$_SERVER["PHP_AUTH_PW"]);
1581  } else {
1582  // no method found -> no authentication required
1583  return true;
1584  }
1585  }
+ 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 1782 of file Server.php.

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

Referenced by serveRequest().

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

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

1844  {
1845  // FIXME depth -> ignored for now
1846  if (method_exists($this, "checkLock")) {
1847  // is locked?
1848  $lock = $this->checkLock($path);
1849 
1850  // ... and lock is not owned?
1851  if (is_array($lock) && count($lock)) {
1852  // FIXME doesn't check uri restrictions yet
1853  if (!strstr($_SERVER["HTTP_IF"], $lock["token"])) {
1854  if (!$exclusive_only || ($lock["scope"] !== "shared"))
1855  return false;
1856  }
1857  }
1858  }
1859  return true;
1860  }
+ 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 1829 of file Server.php.

Referenced by _check_if_header_conditions().

1830  {
1831  // not really implemented here,
1832  // implementations must override
1833  return true;
1834  }
+ Here is the caller graph for this function:

◆ _copymove()

HTTP_WebDAV_Server::_copymove (   $what)

Definition at line 1444 of file Server.php.

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

Referenced by http_COPY(), and http_MOVE().

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

◆ _get_ranges()

HTTP_WebDAV_Server::_get_ranges ( $options)

parse HTTP Range: header

Parameters
arrayoptions array to store result in
Returns
void

Definition at line 986 of file Server.php.

References $options.

Referenced by http_GET().

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

Referenced by _if_header_parser().

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

References $uri, and _if_header_lexer().

Referenced by _check_if_header_conditions().

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

◆ _multipart_byterange_header()

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

generate separator headers for multipart response

first and last call happen without parameters to generate the initial header and closing sequence, all calls inbetween require content mimetype, start and end byte position and optionaly the total byte length of the requested resource

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

Definition at line 1020 of file Server.php.

References $total.

Referenced by http_GET().

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

Referenced by http_LOCK().

1628  {
1629  return "opaquelocktoken:".$this->_new_uuid();
1630  }
+ 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 1597 of file Server.php.

References $n.

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

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

Referenced by http_PROPFIND(), and http_PROPPATCH().

1981  {
1982  switch (strtolower($this->_prop_encoding)) {
1983  case "utf-8":
1984  return $text;
1985  case "iso-8859-1":
1986  case "iso-8859-15":
1987  case "latin-1":
1988  default:
1989  return utf8_encode($text);
1990  }
1991  }
+ 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 1999 of file Server.php.

References $path.

1999  {
2000  if ($path[strlen($path)-1] != '/') {
2001  $path = $path."/";
2002  }
2003  return $path;
2004  }

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

References $result.

Referenced by _copymove(), and serveRequest().

1963  {
1964  // BEGIN WebDAV
1965  // urldecode wrongly replaces '+' characters by ' ' characters.
1966  // We replace '+' into '%2b' before passing the path through urldecode.
1967  //return urldecode($path);
1968  $result =& urldecode(str_replace('+','%2b',$path));
1969  //$this->writelog('_urldecode('.$path.'):'.$result);
1970  return $result;
1971  // END PATCH WebDAV
1972  }
$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 1945 of file Server.php.

1946  {
1947  return strtr($url, array(" "=>"%20",
1948  "&"=>"%26",
1949  "<"=>"%3C",
1950  ">"=>"%3E",
1951  ));
1952  }

◆ http_COPY()

HTTP_WebDAV_Server::http_COPY ( )

COPY method handler.

Parameters
void
Returns
void

Definition at line 1263 of file Server.php.

References _copymove().

1264  {
1265  // no need to check source lock status here
1266  // destination lock status is always checked by the helper method
1267  $this->_copymove("copy");
1268  }
+ 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 1228 of file Server.php.

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

1229  {
1230  // check RFC 2518 Section 9.2, last paragraph
1231  if (isset($_SERVER["HTTP_DEPTH"])) {
1232  if ($_SERVER["HTTP_DEPTH"] != "infinity") {
1233  $this->http_status("400 Bad Request");
1234  return;
1235  }
1236  }
1237 
1238  // check lock status
1239  if ($this->_check_lock_status($this->path)) {
1240  // ok, proceed
1241  $options = Array();
1242  $options["path"] = $this->path;
1243 
1244  $stat = $this->delete($options);
1245 
1246  $this->http_status($stat);
1247  } else {
1248  // sorry, its locked
1249  $this->http_status("423 Locked");
1250  }
1251  }
http_status($status)
set HTTP return status and mirror it in a private header
Definition: Server.php:1920
_check_lock_status($path, $exclusive_only=false)
Definition: Server.php:1843
if(!is_array($argv)) $options
+ Here is the call graph for this function:

◆ http_GET()

HTTP_WebDAV_Server::http_GET ( )

GET method handler.

Parameters
void
Returns
void

Definition at line 851 of file Server.php.

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

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

◆ http_HEAD()

HTTP_WebDAV_Server::http_HEAD ( )

HEAD method handler.

Parameters
void
Returns
void

Definition at line 1059 of file Server.php.

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

1060  {
1061  $status = false;
1062  $options = Array();
1063  $options["path"] = $this->path;
1064 
1065  if (method_exists($this, "HEAD")) {
1066  $status = $this->head($options);
1067  } else if (method_exists($this, "GET")) {
1068  ob_start();
1069  $status = $this->GET($options);
1070  ob_end_clean();
1071  }
1072 
1073  if($status===true) $status = "200 OK";
1074  if($status===false) $status = "404 Not found";
1075 
1076  $this->http_status($status);
1077  }
http_status($status)
set HTTP return status and mirror it in a private header
Definition: Server.php:1920
if(!is_array($argv)) $options
+ 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 1303 of file Server.php.

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

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

◆ http_MKCOL()

HTTP_WebDAV_Server::http_MKCOL ( )

MKCOL method handler.

Parameters
void
Returns
void

Definition at line 830 of file Server.php.

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

831  {
832  $options = Array();
833  $options["path"] = $this->path;
834 
835  $stat = $this->mkcol($options);
836 
837  $this->http_status($stat);
838  }
http_status($status)
set HTTP return status and mirror it in a private header
Definition: Server.php:1920
if(!is_array($argv)) $options
+ 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 1280 of file Server.php.

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

1281  {
1282  //$this->writelog('MOVE()');
1283  if ($this->_check_lock_status($this->path)) {
1284  // destination lock status is always checked by the helper method
1285  $this->_copymove("move");
1286  } else {
1287  //$this->writelog('MOVE():423 Locked');
1288  $this->http_status("423 Locked");
1289  }
1290  }
http_status($status)
set HTTP return status and mirror it in a private header
Definition: Server.php:1920
_check_lock_status($path, $exclusive_only=false)
Definition: Server.php:1843
+ 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 478 of file Server.php.

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

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

◆ http_PROPFIND()

HTTP_WebDAV_Server::http_PROPFIND ( )

PROPFIND method handler.

Parameters
void
Returns
void

Definition at line 512 of file Server.php.

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

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

◆ http_PROPPATCH()

HTTP_WebDAV_Server::http_PROPPATCH ( )

PROPPATCH method handler.

Parameters
void
Returns
void

Definition at line 773 of file Server.php.

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

774  {
775  if($this->_check_lock_status($this->path)) {
776  $options = Array();
777  $options["path"] = $this->path;
778 
779  $propinfo = new _parse_proppatch("php://input");
780 
781  if (!$propinfo->success) {
782  $this->http_status("400 Error");
783  return;
784  }
785 
786  $options['props'] = $propinfo->props;
787 
788  $responsedescr = $this->proppatch($options);
789 
790  $this->http_status("207 Multi-Status");
791  header('Content-Type: text/xml; charset="utf-8"');
792 
793  echo "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n";
794 
795  echo "<D:multistatus xmlns:D=\"DAV:\">\n";
796  echo " <D:response>\n";
797  echo " <D:href>".$this->_urlencode($_SERVER["SCRIPT_NAME"].$this->path)."</D:href>\n";
798 
799  foreach($options["props"] as $prop) {
800  echo " <D:propstat>\n";
801  echo " <D:prop><$prop[name] xmlns=\"$prop[ns]\"/></D:prop>\n";
802  echo " <D:status>HTTP/1.1 $prop[status]</D:status>\n";
803  echo " </D:propstat>\n";
804  }
805 
806  if ($responsedescr) {
807  echo " <D:responsedescription>".
808  $this->_prop_encode(htmlspecialchars($responsedescr)).
809  "</D:responsedescription>\n";
810  }
811 
812  echo " </D:response>\n";
813  echo "</D:multistatus>\n";
814  } else {
815  $this->http_status("423 Locked");
816  }
817  }
http_status($status)
set HTTP return status and mirror it in a private header
Definition: Server.php:1920
_check_lock_status($path, $exclusive_only=false)
Definition: Server.php:1843
if(!is_array($argv)) $options
_prop_encode($text)
UTF-8 encode property values if not already done so.
Definition: Server.php:1980
+ Here is the call graph for this function:

◆ http_PUT()

HTTP_WebDAV_Server::http_PUT ( )

PUT method handler.

Parameters
void
Returns
void

Definition at line 1089 of file Server.php.

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

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

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().

1921  {
1922  // simplified success case
1923  if($status === true) {
1924  $status = "200 OK";
1925  }
1926  //$this->writelog('http_status('.$status.')');
1927 
1928  // remember status
1929  $this->_http_status = $status;
1930 
1931  // generate HTTP status response
1932  header("HTTP/1.1 $status");
1933  header("X-WebDAV-Status: $status", true);
1934  }
+ 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 1418 of file Server.php.

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

1419  {
1420  $options = Array();
1421  $options["path"] = $this->path;
1422 
1423  if (isset($_SERVER['HTTP_DEPTH'])) {
1424  $options["depth"] = $_SERVER["HTTP_DEPTH"];
1425  } else {
1426  $options["depth"] = "infinity";
1427  }
1428 
1429  // strip surrounding <>
1430  $options["token"] = substr(trim($_SERVER["HTTP_LOCK_TOKEN"]), 1, -1);
1431 //$this->writelog('http_UNLOCK HTTP_LOCK_TOKEN='.$_SERVER["HTTP_LOCK_TOKEN"]);
1432  // call user method
1433  $stat = $this->unlock($options);
1434 
1435  $this->http_status($stat);
1436  }
http_status($status)
set HTTP return status and mirror it in a private header
Definition: Server.php:1920
if(!is_array($argv)) $options
+ Here is the call graph for this function:

◆ HTTP_WebDAV_Server()

HTTP_WebDAV_Server::HTTP_WebDAV_Server ( )

Constructor.

Parameters
void

Definition at line 108 of file Server.php.

Referenced by ilDAVServer\ilDAVServer().

109  {
110  // PHP messages destroy XML output -> switch them off
111  //ini_set("display_errors", 0);
112  }
+ Here is the caller graph for this function:

◆ lockdiscovery()

HTTP_WebDAV_Server::lockdiscovery (   $path)

Generate lockdiscovery reply from checklock() result.

Parameters
stringresource path to check
Returns
string lockdiscovery response

Definition at line 1872 of file Server.php.

Referenced by http_PROPFIND().

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

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

1548  {
1549  $args = func_get_args();
1550  if (count($args) == 3) {
1551  return array("ns" => $args[0],
1552  "name" => $args[1],
1553  "val" => $args[2]);
1554  } else {
1555  return array("ns" => "DAV:",
1556  "name" => $args[0],
1557  "val" => $args[1]);
1558  }
1559  }
+ 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 $uri, _allow(), _check_auth(), _check_if_header_conditions(), _urldecode(), 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  {
192  $method = "get";
193  $this->writelog(__METHOD__.': Using head emulation by get.');
194  }
195 
196  if (method_exists($this, $wrapper) && ($method == "options" || method_exists($this, $method)))
197  {
198  $this->writelog(__METHOD__.': Calling wrapper: '.$wrapper);
199  $this->$wrapper(); // call method by name
200  }
201  else
202  { // method not found/implemented
203  if ($_SERVER["REQUEST_METHOD"] == "LOCK")
204  {
205  $this->writelog(__METHOD__.': Method not found/implemented. Sending 412');
206  $this->http_status("412 Precondition failed");
207  }
208  else
209  {
210  $this->writelog(__METHOD__.': Method not found/implemented. Sending allowd methods');
211  $this->http_status("405 Method not allowed");
212  header("Allow: ".join(", ", $this->_allow())); // tell client what's allowed
213  }
214  }
215  }
_allow()
check for implemented HTTP methods
Definition: Server.php:1507
_check_if_header_conditions()
check if conditions from "If:" headers are meat
Definition: Server.php:1782
_urldecode($path)
private version of PHP urldecode
Definition: Server.php:1962
http_status($status)
set HTTP return status and mirror it in a private header
Definition: Server.php:1920
_check_auth()
check authentication if check is implemented
Definition: Server.php:1569
writelog($message)
Writes a message to the logfile.,.
Definition: Server.php:2012
+ 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 2012 of file Server.php.

References $ilUser, and $log.

Referenced by http_OPTIONS(), and serveRequest().

2013  {
2014  global $log, $ilUser;
2015 
2016  $log->write(
2017  $ilUser->getLogin()
2018  .' DAV Server.'.str_replace("\n",";",$message)
2019  );
2020  /*
2021  if ($this->logFile)
2022  {
2023  $fh = fopen($this->logFile, 'a');
2024  fwrite($fh, date('Y-m-d h:i:s '));
2025  fwrite($fh, str_replace("\n",";",$message));
2026  fwrite($fh, "\n\n");
2027  fclose($fh);
2028  }*/
2029  }
global $ilUser
Definition: imgupload.php:15
+ 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: