Deprecating/removing backup.php as a feature in OpenEMR

We are planning on deprecating and removing the backup.php script in OpenEMR. We’d like to know if anyone is utilizing this feature and if there is anyone in the community that would be interested in taking over the maintenance of this file and moving it into a module if the community is still wanting this feature.

We encourage people to use tools like mysqldump and backing up their sites directory using tools like rsync as that is a safer more secure way of handling file backups instead of the backup.php.

Re: Deprecating and removing backup.php

Thanks to Jerry Padgett, we have telemetry that speaks to the “is anyone using this” question directly. I want to put numbers on the table before the decision gets made.

Yes, people are using it

From the opt-in telemetry through June 2026:

  • 125 distinct sites have opened /interface/main/backup.php, out of 1,333 sites reporting any menu activity — about 9%.
  • 417 total page opens.
  • Month to month it runs steady at 5–13% of active sites, with no downward trend across the fifteen months of data.

For a single administrative page, one in ten sites is not a rounding error.

It isn’t just old installs

The argument that anyone still depending on this is too far out of date to upgrade doesn’t hold up. Version spread across those 125 sites:

  • 7.0.3 — 50 sites
  • 8.0.0 — 50 sites
  • 7.0.4 — 30 sites

Half are on the current major line. These are people who do upgrade, and who are still using the feature after upgrading.

The users hitting it look like exactly the group we’d strand

The same URL shows up under four different menu labels — English, Greek, Spanish, and Vietnamese. Whatever else is true about this population, a meaningful slice of it is non-English-speaking, and the proposed replacement is an English-language wiki page describing two command-line tools.

The stated alternative — mysqldump plus rsync — is the right answer for anyone who has shell access and knows how to use it. The people clicking a Backup menu item in Vietnamese are, almost by definition, not that person. The realistic outcome for that segment isn’t that they switch to mysqldump. It’s that they stop backing up.

For comparison: the fax/SMS module

Since we’re weighing what’s worth keeping and maintaining, here’s the same measurement applied to oe-module-faxsms:

  • 21 distinct sites have ever touched it — about 1.6% of reporting sites.
  • Usage is extremely concentrated: of 265 RingCentral FAX page opens, 254 come from a single site. A second site accounts for 10. A third clicked once, in November, and never returned.
  • The most widely configured backend is Clinic Email (14 sites), with 41 total opens across all of them.

backup.php reaches roughly six times as many sites as the fax/SMS module, and its usage is spread across the community rather than concentrated in one practice. I raise this not to argue against fax — it’s plainly essential to the practices that rely on it — but because if 21 sites is enough to justify carrying a subsystem, 125 should clear the same bar.

Caveats, stated plainly

I don’t want to oversell this data:

  • These are menu clicks, not completed backups. The telemetry records that someone opened the page. It can’t tell us whether a backup ran or succeeded.
  • The usage is shallow. Median is 1 open per site; 98 of the 125 sites appear in only one reporting period. You can read that as weak attachment — or as backups being an occasional, deliberate act (before an upgrade, before a migration) rather than a daily one. I lean toward the second reading, but the data doesn’t settle it.
  • Telemetry is opt-in and covers ~1,300 sites against a far larger installed base, and opt-in populations skew toward engaged, recently-upgraded administrators. Percentages should be treated as indicative.
  • In fairness to the security case: the telemetry also shows automated scanners probing for /backup, /backups, /backup-db, /backup_migrate and similar paths across multiple sites. Attackers actively hunt for exposed backup endpoints. That’s a real argument, and it deserves a real answer rather than dismissal.

What removal actually takes with it

Worth being explicit that this page carries more than one feature. Log table truncation lives on it, and that’s a genuinely useful operational tool that has nothing to do with bulk data export. Layout and form export/import is also there. Whatever happens to the backup function, those shouldn’t disappear as collateral.

Re: backup.php — a possible root-cause fix

I understand the removal has already landed on master, and I’m not trying to relitigate it. But I spent some time reading source with the assistance of AI. I think that the recurring vulnerability class here is fixable at the root rather than patched again. Before anyone invests effort, I want to find out whether a PR along these lines would even be considered.

What I think the actual problem is

The file splits into two halves, and only one of them is generating the issues.

The backup half looks clean already. The database dump wraps every value in escapeshellarg(), and none of those values come from user input — they’re all from $sqlconf (login, password, host, port, database). The site-directory archiving uses create_tar_archive() and ZipArchive, which are PHP, not shell. There’s very little injection surface in the part that actually performs backups.

The configuration export/import half is where it all lives — roughly lines 671–1000. What that code is doing is building shell command strings to accomplish things PHP can do directly:

  • A long chain of echo "..." >> file redirections whose only purpose is writing SQL text into a file.
  • A pipe through perl to strip DEFAULT CHARSET= and collate clauses with a regex.
  • mysqldump --where= clauses with user-selected list and layout IDs interpolated in.
  • Every one of the above written twice, once for cmd.exe and once for sh.

That last point is where the three-layer escaping comes from — SQL escaping inside shell escaping inside platform-specific quoting, maintained in two parallel code paths. I think that’s the “whack-a-mole” mechanism: fixing a quoting bug on one platform can open an injection path on the other.

The proposed fix

Remove the shell from that half of the file entirely, rather than adding another escaping layer:

  • The echo >> file chains become fwrite().
  • The perl pipe becomes preg_replace() in PHP (and perl stops being a dependency).
  • The --where dumps become parameterized sqlStatement(... WHERE list_id = ?, [$listid]) queries with the INSERT statements generated in PHP. This pattern already exists in the same file — the CSV export path at lines ~193 and ~255 does exactly this. The export path just never adopted it.
  • The full database dump keeps mysqldump, but invoked via Symfony\Component\Process\Process with an argument array rather than a concatenated command string.

If that’s done, both shell-escaping helper closures get deleted and the IS_WINDOWS branching in the export path collapses to a single code path. The escaping problem doesn’t get safer — it stops existing, because there’s no shell left for anything to be escaped for.

What this doesn’t fix

Being honest about the limits:

  • It doesn’t address the concern that a one-click backup lets someone drop an unencrypted database into a downloads folder. That needs the artifact encrypted and served through an expiring link, which is separate work.
  • The size limitation remains — the feature stops working above a certain database size regardless.

Who this helps, and how I’d like us to support them

I want to be clear about who I think is affected, because it shapes what a good outcome looks like.

The people who use this aren’t the ones with shell access. mysqldump and rsync are the right answer for anyone who can use them, and I’m not arguing otherwise. But the same menu entry shows up in the wild under English, Greek, Spanish, and Vietnamese labels, on current releases — small practices, often non-English-speaking, frequently without a technical administrator. For that group the realistic outcome of removal isn’t that they switch to command-line tools. It’s that they quietly stop backing up, and nobody finds out until the day it matters. I don’t think a wiki page closes that gap — the operators most affected are the ones least able to act on it. That’s why I’d rather see the underlying problem fixed than the feature documented away.

Two questions

  1. Would a PR along these lines be considered at all, or is the decision to remove settled regardless of whether the root cause is addressed?
  2. Would anyone be willing to review it and own it going forward? I’ll be straightforward: I’m not able to maintain this myself, and I know that’s the deciding question. But I think “review a complete PR” is a much smaller ask than “write and maintain a module,” and I’d like to know if it’s findable.

I should also say plainly that I’d be using AI assistance to produce the code, with the diagnosis above coming from reading the source rather than from the advisories.

Given what this file is and the current advisory backlog, that should be on the table up front rather than discovered later — and it’s exactly why I’m asking about a reviewer before writing anything.

“if you build it, they will come” :smiley:
(ie. definitely feel free to post a PR on this; if it is deemed safe, then I would definitely consider it)