Skip to content

Instantly share code, notes, and snippets.

@rikmeijer
Created June 13, 2025 11:24
Show Gist options
  • Select an option

  • Save rikmeijer/fc9b7341731806c93b05fd361666fb7c to your computer and use it in GitHub Desktop.

Select an option

Save rikmeijer/fc9b7341731806c93b05fd361666fb7c to your computer and use it in GitHub Desktop.
Trigger checksum generator in Nextcloud, remotely
<?php
/**
* This script uses "sabre/dav" Client to make webdav requests to a Nextcloud instance.
* The "nextcloud-checksum-update" option is a, somewhat, hidden feature in the Sabre Connector (Checksum Update Plugin)
* https://github.com/nextcloud/server/blob/master/apps/dav/lib/Connector/Sabre/ChecksumUpdatePlugin.php
*
* The basic flow is:
* - PROPFIND on /remote.php/dav/Photos (explicitly asking for '{http://owncloud.org/ns}checksums' property)
* - use the proper hash from the response
* - OR do a PATCH request, with the X-Recalculate-Hash header, to trigger the recalculation
* - FOLLOWED BY a HEAD, with the X-Hash header, request on $file_path
* - use the hash from that response (in the oc-checksum response-header)
**/
define('USED_ALGORITHM', 'md5');
define('WORKING_PATH', '/Photos');
$client = new Sabre\DAV\Client([
'baseUri' => 'https://nextcloud.example.org/remote.php/dav',
'userName' => 'john',
'password' => 's3cr3t'
]);
$options = $client->options();
if (in_array("nextcloud-checksum-update", $options) === false) {
exit('Cannot update checksum, so media comparison is impossible');
}
$available_media_files = $client->propFind(WORKING_PATH, ['{http://owncloud.org/ns}checksums'], 1);
foreach ($available_media_files as $file_path => $available_media_file) {
$hash = null;
if (array_key_exists('{http://owncloud.org/ns}checksums', $available_media_file)) {
foreach ($available_media_file['{http://owncloud.org/ns}checksums'] as $checksum) {
list($algo, $possible_hash) = explode(':', $checksum['value'], 2);
if (strcasecmp($algo, USED_ALGORITHM) === 0) {
$hash = $possible_hash;
break;
}
}
}
if (isset($hash) === false) {
$client->request('PATCH', $file_path, headers: [
'X-Recalculate-Hash' => USED_ALGORITHM
]);
$file = $attempt('request', 'HEAD', $file_path, headers: [
'X-Hash' => USED_ALGORITHM
]);
foreach ($file['headers']['oc-checksum'] as $checksum) {
list($algo, $hash) = explode(':', $checksum, 2);
if (strcasecmp($algo, USED_ALGORITHM) === 0) {
break;
}
}
}
print 'Found '.USED_ALGORITHM.' hash ' . $hash . ' for file ' . $file_id;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment