I tested it on both, an XAMPP Installation on Windows (for dev) and the same web/apache server where the PHPMaker 2024 version was running (for prod).
The server account is the owner of uploads folder and only the owner has write privilege which means, that it can add files and replace files. But why not delete files? I can’t see that privileges on the storage system are the problem.
interesting…
sorry as well… i’m still on v2024, so all of this may be inapplicable to v2025
is the actual record in the table removed?
we have a similar issue, haven’t resolved it yet When deleting a record… the file is deleted, but the record is not, even though it said it was… this is happening with any tables that have “attachments”.
while debugging, we added this to the delete page:
which resolved the issue. but turned off transactions… thing is the table has no other tables or processing that would use transactions.
give it a try, just to rule out…
and in your modules main file:
routine:
// Delete uploaded files
public function deleteUploadedFiles($row)
{
$this->loadDbValues($row);
$this->DocumentAttachments->OldUploadPath = $this->DocumentAttachments->getUploadPath(); // PHP
$oldFiles = EmptyValue($row['DocumentAttachments']) ? [] : [$row['DocumentAttachments']];
foreach ($oldFiles as $oldFile) {
if (file_exists($this->DocumentAttachments->oldPhysicalUploadPath() . $oldFile)) {
@unlink($this->DocumentAttachments->oldPhysicalUploadPath() . $oldFile);
}
}
}
try to step through this and see if the function has the correct file path and filename to be removed and if there are any errors at the unlink function (remove the @, see if it throws an error).
I will definitely dive into this topic. Meanwhile I found out that in 2025 @unlink has been replaced by DeleteFile() which probably comes from one of the libraries, maybe FlySystem?
Here’s the new code:
// Delete uploaded files
public function deleteUploadedFiles(array $row)
{
$this->loadDbValues($row);
$this->Dokument->OldUploadPath = $this->Dokument->getUploadPath(); // PHP
$oldFiles = IsEmpty($row['Dokument']) ? [] : [$row['Dokument']];
foreach ($oldFiles as $oldFile) {
if (FileExists($this->Dokument->uploadPath() . $oldFile)) {
DeleteFile($this->Dokument->uploadPath() . $oldFile);
}
}
}
Maybe somebody already knows something about this. The trick with "UseTransaction = false" points to the problem of deleting a file while there is still a handle to the file open.
What is “subdir”? Did you try to use a dynamic subfolder by code? Or are you using a local file system root which is not "."? (If it is ".", uploadPath() should return same value as getUploadPath().)
uploadPath() returns the value in the project setting.
getUploadPath() returns the string in field setting.
So the code wants do delete the file in the wrong directory (files/ instead of files/subdir).
As for the root question, I don’t understand what you mean by system root. Anyway I did not change anything on the system level and the problem occurs on both XAMPP for Windows (see the log) and an Ubuntu installation as well.
With XAMPP the project does not execute in the root directory but in a subdirectory. So the physical path to the file is
If I add a record uploadPath() is called in total 11 times. 8 times it returns the global config ‘/files’ and 3 times it returns the field setting ‘files/subdir’.
If I delete a record uploadPath() is called 10 times and returns 10 times the global ‘config /files’.
If I replace the file in an existing record uploadPath() is called 17 times. 12 times it returns the global config ‘/files’ and 5 times it returns the field setting ‘files/subdir’.
this seems to be a more complex mechanism. not sure what to do with this without tracking even deeper. Maybe there are some ideas around.
It is not related to number of times it is called. It depends on whether or not the UploadPath property of the field is set in the context. You better click Tools → Update Template as Webmaster suggested to update the latest template and try again.
What I did (before asking for support). I removed the content of the accept property (.pdf) in the field setup. And everything went well. I then added the same property (.pdf) again and it still worked well.
The origin of the problem was probably in the project file.