From a5f1249e642618b44aa611f46e7bd317c53fdfc6 Mon Sep 17 00:00:00 2001 From: Elizabeth Danzberger Date: Tue, 14 Jul 2026 15:28:27 -0400 Subject: [PATCH] fix(wopi): use fresh storage mtime for conflict detection and responses Assisted-by: ClaudeCode:claude-sonnet-4-6 Signed-off-by: Elizabeth Danzberger --- lib/Controller/WopiController.php | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/lib/Controller/WopiController.php b/lib/Controller/WopiController.php index 77cb84e517..29823da9ea 100644 --- a/lib/Controller/WopiController.php +++ b/lib/Controller/WopiController.php @@ -641,14 +641,18 @@ public function putFile( try { $file = $this->getFileForWopiToken($wopi); $wopiHeaderTime = $this->request->getHeader('X-COOL-WOPI-Timestamp'); + $storageMtime = $file->getStorage()->filemtime($file->getInternalPath()); - if (!empty($wopiHeaderTime) && $wopiHeaderTime !== Helper::toISO8601($file->getMTime() ?? 0)) { + if (!empty($wopiHeaderTime) && $wopiHeaderTime !== Helper::toISO8601($storageMtime ?: 0)) { $this->logger->debug('Document timestamp mismatch ! WOPI client says mtime {headerTime} but storage says {storageTime}', [ 'headerTime' => $wopiHeaderTime, - 'storageTime' => Helper::toISO8601($file->getMTime() ?? 0) + 'storageTime' => Helper::toISO8601($storageMtime ?: 0) ]); // Tell WOPI client about this conflict. - return new JSONResponse(['COOLStatusCode' => self::COOL_STATUS_DOC_CHANGED], Http::STATUS_CONFLICT); + return new JSONResponse([ + 'COOLStatusCode' => self::COOL_STATUS_DOC_CHANGED, + 'LastModifiedTime' => Helper::toISO8601($storageMtime ?: 0), + ], Http::STATUS_CONFLICT); } $content = fopen('php://input', 'rb'); @@ -670,7 +674,8 @@ public function putFile( $wopi->setTemplateId(null); $this->wopiMapper->update($wopi); } - return new JSONResponse(['LastModifiedTime' => Helper::toISO8601($file->getMTime())]); + $storageMtime = $file->getStorage()->filemtime($file->getInternalPath()); + return new JSONResponse(['LastModifiedTime' => Helper::toISO8601($storageMtime ?: $file->getMTime())]); } catch (NotFoundException $e) { $this->logger->warning($e->getMessage(), ['exception' => $e]); return new JSONResponse([], Http::STATUS_NOT_FOUND);