How to make the webdav api work?

Hi All,

With reference to this post from me a few days ago, I am trying to write a simple php page to take a URL, username and password and to then load a list of all files that could be restored with tick boxes and a “select all” button (maybe also some date to / from options as well later).

I’ve got the code working to pull the “capabilities” from the server and that seem to be working well but I’m not currently managing to get the dav trash-bin stuff working. Code is below, could someone take a quick look and point me to where I am going wrong?

$apiUrl = ‘https://’ . $fqdn . ‘remote.php/dav/trash-bin/’ . $username;
// also tried
// $apiUrl = ‘https://$username:$password@$fqdn/remote.php/dav/trash-bin/$username’;
$apiCurl = curl_init();
curl_setopt($apiCurl, CURLOPT_USERPWD, $userUsername . “:” . $userPassword);
curl_setopt($apiCurl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($apiCurl, CURLOPT_URL, $apiUrl);
curl_setopt($apiCurl, CURLOPT_HTTPHEADER, array(’
Depth: 1;
Content-Type: application/xml;
charset=UTF-8’));
curl_setopt($apiCurl, CURLOPT_CUSTOMREQUEST, ‘PROPFIND’);
curl_setopt($apiCurl, CURLOPT_POSTFIELDS,’
<d:propfind xmlns:d=“DAV:” xmlns:oc=“http://owncloud.org/ns”>
<d:prop>
<oc:trashbin-original-filename />
<oc:trashbin-original-location />
<oc:trashbin-delete-datetime />
<d:getcontentlength />
<d:resourcetype />
</d:prop>
</d:propfind>
');

$curlResult = curl_exec($apiCurl);
$deletedFiles = json_decode($curlResult, true);

var_dump ($deletedFiles);

Any help would be appreciated, fairly sure I’m just not getting something quite right in the curl options / headers / post settings.

1 Like

For the record I have just tried the code from the docs in an ssh session and it returns

<?xml version="1.0" encoding="utf-8"?>

<d:error xmlns:d=“DAV:” xmlns:s=“http://sabredav.org/ns”>
<s:exception>Sabre\DAV\Exception\NotFound</s:exception>
<s:message>File not found: trash-bin in ‘root’</s:message>
</d:error>

So it looks like something isn’t working right anyway.
(there are definitely files that have been deleted for the user I am testing with and the Web interface shows them correctly.)

Also…

Tried this with an LDAP synced user and a local user, same result.

curl -u <user>:<password> -X PROPFIND --data-binary @/tmp/d.xml -k https://<server>/remote.php/dav/trash-bin/<user>/ | xmllint --format -
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  1249  100   990  100   259    322     84  0:00:03  0:00:03 --:--:--   407
<?xml version="1.0"?>
<d:multistatus xmlns:d="DAV:" xmlns:s="http://sabredav.org/ns" xmlns:oc="http://owncloud.org/ns">
  <d:response>
    <d:href>/remote.php/dav/trash-bin/admin/</d:href>
    <d:propstat>
      <d:prop>
        <d:resourcetype>
          <d:collection/>
        </d:resourcetype>
      </d:prop>
      <d:status>HTTP/1.1 200 OK</d:status>
    </d:propstat>
    <d:propstat>
      <d:prop>
        <oc:trashbin-original-filename/>
        <oc:trashbin-original-location/>
        <oc:trashbin-delete-datetime/>
        <d:getcontentlength/>
      </d:prop>
      <d:status>HTTP/1.1 404 Not Found</d:status>
    </d:propstat>
  </d:response>
  <d:response>
    <d:href>/remote.php/dav/trash-bin/admin/801</d:href>
    <d:propstat>
      <d:prop>
        <oc:trashbin-original-filename>157265.jpg</oc:trashbin-original-filename>
        <oc:trashbin-original-location>157265.jpg</oc:trashbin-original-location>
        <oc:trashbin-delete-datetime>Mon, 09 Nov 2020 08:33:50 GMT</oc:trashbin-delete-datetime>
        <d:getcontentlength>3412815</d:getcontentlength>
        <d:resourcetype/>
      </d:prop>
      <d:status>HTTP/1.1 200 OK</d:status>
    </d:propstat>
  </d:response>
</d:multistatus>

where the /tmp/d.xml file contains the following:

<?xml version="1.0"?>
<d:propfind xmlns:d="DAV:" xmlns:oc="http://owncloud.org/ns">
<d:prop>
<oc:trashbin-original-filename />
<oc:trashbin-original-location />
<oc:trashbin-delete-datetime />
<d:getcontentlength />
<d:resourcetype />
</d:prop>
</d:propfind>

Note that the response is xml, not json.

3 Likes

Thanks for your reply @jvillafanez,

I will give that a go and see if that works from the command line. Other than the json/xml confusion do you have any idea where I am going wrong with the PHP?

Same response when using the above format.

Tried with the wrong username and password just to confirm and that returns a different error so I can be sure the un/pw combo is being authenticated correctly.

It looks like the request is just not able to see /dav/trash-bin.

Another option here I guess might be to enumerate what is under /dav maybe?

Check you’re using a recent version. It should work with 10.5
It might work with versions from 10.3 but there are some fixes on top, so better use a newer version.
Versions prior 10.3 don’t have this feature.

2 Likes

10.0.10, that’ll be the issue. Will update and see how I go.

Thanks for your help

1 Like

Well that was a bit of an epic. Ubuntu from 14 to 16, php from 5 to 7, owncloud 10.0 to 10.3

tested, still not working

ubuntu from 16 to 18 via a lot of messing around and snapshotting, php to 7.2, owncloud to 10.5 and we now have the command line curl command working. I’ll go through and try to get the PHP working again but does anyone have a working example of using php + curl to talk to the API?

Hi again everyone. For the record (and for future googlers looking for answers).

$owncloudUrl = "https://owncloud.yourdomain.com/";
$apiUrl = $owncloudUrl . 'remote.php/dav/trash-bin/' . $userUsername;
$apiCurl = curl_init();
  curl_setopt($apiCurl, CURLOPT_RETURNTRANSFER, true);
  curl_setopt($apiCurl, CURLOPT_URL, $apiUrl);
  curl_setopt($apiCurl, CURLOPT_USERPWD, $userUsername . ":" . $userPassword); 
  curl_setopt($apiCurl, CURLOPT_CUSTOMREQUEST, 'PROPFIND');
  curl_setopt($apiCurl, CURLOPT_HEADER, 'true');
  curl_setopt($apiCurl, CURLOPT_HTTPHEADER, array('Depth: 30; Content-Type: application/xml; charset=UTF-8'));
  curl_setopt($apiCurl, CURLOPT_POSTFIELDS,'
    <d:propfind xmlns:d="DAV:" xmlns:oc="http://owncloud.org/ns">
      <d:prop>
        <oc:trashbin-original-filename />
        <oc:trashbin-original-location />
        <oc:trashbin-delete-datetime />
        <d:getcontentlength />
        <d:resourcetype />
      </d:prop>
    </d:propfind>
');
$curlResult = curl_exec($apiCurl);
$xmlResults = new SimpleXMLElement($curlResult);
$xmlNameSpaces = $xmlResults->getNameSpaces(true);

You also need to know to use the right format for simpleXML to get nodes that use a name space prefix (d: or oc: for example in the XML reply) as below for example;

$count= 0;
// Each file is contained within a response
foreach ($xmlResults->children($xmlNameSpaces['d'])->response as $theResponse){
  $count++;
  echo "response #: $count";
  // Each response seems to have 1 propstat for files and 2 propstats fo directories
  foreach ($theResponse->children($xmlNameSpaces['d'])->propstat as $thePropStat){
    $numPropStat++;
    // Get the file name from the XML
    $thisFile = trim($thePropStat->children($xmlNameSpaces['d'])->prop->children($xmlNameSpaces['oc'])->$xmlOcTbOrigFile->__toString());
    // Get the deleted date from the XML
    $thisDate = new dateTime(trim($thePropStat->children($xmlNameSpaces['d'])->prop->children($xmlNameSpaces['oc'])->$xmlOcTbDeleted));
    }
}

Now I’m off to work out how to tell if it’s safe to restore the file (does the restore path exist as OC seems to just dump it in the root if not) and how to actually restore the files.

On a side note, I came up with this bit of code that counts the number of deletions on a given day, I figured it might be helpful to keep an eye out for anomalous activity. The initial array is $arrFileList and has string OC reference, string file type, string filename, datetime deleted date. I set it to bold any days with more than 10 deletions (seems about right for this particular site).

// Create date compare function to be used later
  function formatDate($d) {
  return $d[3]->format('Y-m-d');
}

// Build new array with dates as strings to allow the array_count_values function to work
$results = array_map("formatDate", $arrFileList);

// count the values and dump results to another array
$results2 = array_count_values($results);

// Sort the results into date order
ksort($results2);

// Spit them all out in a more readable format than var_dump
foreach($results2 as $key => $value) {
  if ($value > 10){
    echo "\<b>$key - $value\</b>\<br>";    
  } else {
    echo "$key - $value\<br>";
  }
}

Hopefully this will help someone at some point in the future.
(If anyone has any suggested improvements to the above please feel free to let me know)

3 Likes