Example #1
0
 /**
  * PROPFIND method handler
  *
  * @param  void
  * @return void
  */
 function http_PROPFIND()
 {
     $options = array();
     $options["path"] = $this->path;
     // search depth from header (default is "infinity)
     if (isset($_SERVER['HTTP_DEPTH'])) {
         $options["depth"] = $_SERVER["HTTP_DEPTH"];
     } else {
         $options["depth"] = "infinity";
     }
     // analyze request payload
     $propinfo = new _parse_propfind("php://input");
     if (!$propinfo->success) {
         $this->http_status("400 Error");
         return;
     }
     $options['props'] = $propinfo->props;
     // call user handler
     if (!$this->propfind($options, $files)) {
         $this->http_status("404 Not Found");
         return;
     }
     // collect namespaces here
     $ns_hash = array();
     // Microsoft Clients need this special namespace for date and time values
     $ns_defs = "xmlns:ns0=\"urn:uuid:c2f41010-65b3-11d1-a29f-00aa00c14882/\"";
     // now we loop over all returned file entries
     foreach ($files["files"] as $filekey => $file) {
         // nothing to do if no properties were returend for a file
         if (!isset($file["props"]) || !is_array($file["props"])) {
             continue;
         }
         // now loop over all returned properties
         foreach ($file["props"] as $key => $prop) {
             // as a convenience feature we do not require that user handlers
             // restrict returned properties to the requested ones
             // here we strip all unrequested entries out of the response
             switch ($options['props']) {
                 case "all":
                     // nothing to remove
                     break;
                 case "names":
                     // only the names of all existing properties were requested
                     // so we remove all values
                     unset($files["files"][$filekey]["props"][$key]["val"]);
                     break;
                 default:
                     $found = false;
                     // search property name in requested properties
                     foreach ((array) $options["props"] as $reqprop) {
                         if ($reqprop["name"] == $prop["name"] && $reqprop["xmlns"] == $prop["ns"]) {
                             $found = true;
                             break;
                         }
                     }
                     // unset property and continue with next one if not found/requested
                     if (!$found) {
                         $files["files"][$filekey]["props"][$key] = "";
                         continue 2;
                     }
                     break;
             }
             // namespace handling
             if (empty($prop["ns"])) {
                 continue;
             }
             // no namespace
             $ns = $prop["ns"];
             if ($ns == "DAV:") {
                 continue;
             }
             // default namespace
             if (isset($ns_hash[$ns])) {
                 continue;
             }
             // already known
             // register namespace
             $ns_name = "ns" . (count($ns_hash) + 1);
             $ns_hash[$ns] = $ns_name;
             $ns_defs .= " xmlns:{$ns_name}=\"{$ns}\"";
         }
         // we also need to add empty entries for properties that were requested
         // but for which no values where returned by the user handler
         if (is_array($options['props'])) {
             foreach ($options["props"] as $reqprop) {
                 if ($reqprop['name'] == "") {
                     continue;
                 }
                 // skip empty entries
                 $found = false;
                 // check if property exists in result
                 foreach ($file["props"] as $prop) {
                     if ($reqprop["name"] == $prop["name"] && $reqprop["xmlns"] == $prop["ns"]) {
                         $found = true;
                         break;
                     }
                 }
                 if (!$found) {
                     if ($reqprop["xmlns"] === "DAV:" && $reqprop["name"] === "lockdiscovery") {
                         // lockdiscovery is handled by the base class
                         $files["files"][$filekey]["props"][] = $this->mkprop("DAV:", "lockdiscovery", $this->lockdiscovery($files["files"][$filekey]['path']));
                     } else {
                         // add empty value for this property
                         $files["files"][$filekey]["noprops"][] = $this->mkprop($reqprop["xmlns"], $reqprop["name"], "");
                         // register property namespace if not known yet
                         if ($reqprop["xmlns"] != "DAV:" && !isset($ns_hash[$reqprop["xmlns"]])) {
                             $ns_name = "ns" . (count($ns_hash) + 1);
                             $ns_hash[$reqprop["xmlns"]] = $ns_name;
                             $ns_defs .= " xmlns:{$ns_name}=\"{$reqprop['xmlns']}\"";
                         }
                     }
                 }
             }
         }
     }
     // now we generate the reply header ...
     $this->http_status("207 Multi-Status");
     header('Content-Type: text/xml; charset="utf-8"');
     // ... and payload
     echo "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n";
     echo "<D:multistatus xmlns:D=\"DAV:\">\n";
     foreach ($files["files"] as $file) {
         // ignore empty or incomplete entries
         if (!is_array($file) || empty($file) || !isset($file["path"])) {
             continue;
         }
         $path = $file['path'];
         if (!is_string($path) || $path === "") {
             continue;
         }
         echo " <D:response {$ns_defs}>\n";
         $href = @$_SERVER["HTTPS"] === "on" ? "https:" : "http:";
         $href .= "//" . $_SERVER['HTTP_HOST'] . $_SERVER['SCRIPT_NAME'];
         $href .= $path;
         //TODO make sure collection resource pathes end in a trailing slash
         echo "  <D:href>{$href}</D:href>\n";
         // report all found properties and their values (if any)
         if (isset($file["props"]) && is_array($file["props"])) {
             echo "   <D:propstat>\n";
             echo "    <D:prop>\n";
             foreach ($file["props"] as $key => $prop) {
                 if (!is_array($prop)) {
                     continue;
                 }
                 if (!isset($prop["name"])) {
                     continue;
                 }
                 if (!isset($prop["val"]) || $prop["val"] === "" || $prop["val"] === false) {
                     // empty properties (cannot use empty() for check as "0" is a legal value here)
                     if ($prop["ns"] == "DAV:") {
                         echo "     <D:{$prop['name']}/>\n";
                     } else {
                         if (!empty($prop["ns"])) {
                             echo "     <" . $ns_hash[$prop["ns"]] . ":{$prop['name']}/>\n";
                         } else {
                             echo "     <{$prop['name']} xmlns=\"\"/>";
                         }
                     }
                 } else {
                     if ($prop["ns"] == "DAV:") {
                         // some WebDAV properties need special treatment
                         switch ($prop["name"]) {
                             case "creationdate":
                                 echo "     <D:creationdate ns0:dt=\"dateTime.tz\">" . gmdate("Y-m-d\\TH:i:s\\Z", $prop['val']) . "</D:creationdate>\n";
                                 break;
                             case "getlastmodified":
                                 echo "     <D:getlastmodified ns0:dt=\"dateTime.rfc1123\">" . TimeDate::httptime($prop['val']) . "</D:getlastmodified>\n";
                                 break;
                             case "resourcetype":
                                 echo "     <D:resourcetype><D:{$prop['val']}/></D:resourcetype>\n";
                                 break;
                             case "supportedlock":
                                 echo "     <D:supportedlock>{$prop['val']}</D:supportedlock>\n";
                                 break;
                             case "lockdiscovery":
                                 echo "     <D:lockdiscovery>\n";
                                 echo $prop["val"];
                                 echo "     </D:lockdiscovery>\n";
                                 break;
                             default:
                                 echo "     <D:{$prop['name']}>" . $this->_prop_encode(htmlspecialchars($prop['val'])) . "</D:{$prop['name']}>\n";
                                 break;
                         }
                     } else {
                         // properties from namespaces != "DAV:" or without any namespace
                         if ($prop["ns"]) {
                             echo "     <" . $ns_hash[$prop["ns"]] . ":{$prop['name']}>" . $this->_prop_encode(htmlspecialchars($prop['val'])) . "</" . $ns_hash[$prop["ns"]] . ":{$prop['name']}>\n";
                         } else {
                             echo "     <{$prop['name']} xmlns=\"\">" . $this->_prop_encode(htmlspecialchars($prop['val'])) . "</{$prop['name']}>\n";
                         }
                     }
                 }
             }
             echo "   </D:prop>\n";
             echo "   <D:status>HTTP/1.1 200 OK</D:status>\n";
             echo "  </D:propstat>\n";
         }
         // now report all properties requested bot not found
         if (isset($file["noprops"])) {
             echo "   <D:propstat>\n";
             echo "    <D:prop>\n";
             foreach ($file["noprops"] as $key => $prop) {
                 if ($prop["ns"] == "DAV:") {
                     echo "     <D:{$prop['name']}/>\n";
                 } else {
                     if ($prop["ns"] == "") {
                         echo "     <{$prop['name']} xmlns=\"\"/>\n";
                     } else {
                         echo "     <" . $ns_hash[$prop["ns"]] . ":{$prop['name']}/>\n";
                     }
                 }
             }
             echo "   </D:prop>\n";
             echo "   <D:status>HTTP/1.1 404 Not Found</D:status>\n";
             echo "  </D:propstat>\n";
         }
         echo " </D:response>\n";
     }
     echo "</D:multistatus>\n";
 }